From 40b0f66d8da5f127d5b03e7a14a82657a94b2dbe Mon Sep 17 00:00:00 2001 From: iMoHax Date: Thu, 30 Jul 2015 12:00:06 +0300 Subject: [PATCH] implement loop route specification --- .../ru/trader/services/RoutesSearchTask.java | 2 +- .../analysis/LoopRouteSpecification.java | 62 ++++++ .../ru/trader/analysis/RouteSearcher.java | 4 + .../java/ru/trader/core/MarketAnalyzer.java | 4 + .../ru/trader/analysis/VendorsGraphTest.java | 177 +++++++++++++++++- 5 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 core/src/main/java/ru/trader/analysis/LoopRouteSpecification.java diff --git a/client/src/main/java/ru/trader/services/RoutesSearchTask.java b/client/src/main/java/ru/trader/services/RoutesSearchTask.java index 7375007..bd849ae 100644 --- a/client/src/main/java/ru/trader/services/RoutesSearchTask.java +++ b/client/src/main/java/ru/trader/services/RoutesSearchTask.java @@ -33,7 +33,7 @@ public class RoutesSearchTask extends AnalyzerTask>{ if (to != null) { routes = analyzer.getRoutes(stationFrom, to); } else { - routes = analyzer.getRoutes(stationFrom); + routes = analyzer.getLoops(stationFrom, 100); } } } else { diff --git a/core/src/main/java/ru/trader/analysis/LoopRouteSpecification.java b/core/src/main/java/ru/trader/analysis/LoopRouteSpecification.java new file mode 100644 index 0000000..ed51506 --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/LoopRouteSpecification.java @@ -0,0 +1,62 @@ +package ru.trader.analysis; + +import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.Traversal; + +import java.util.Optional; + +public class LoopRouteSpecification implements RouteSpecification { + private final boolean unique; + + public LoopRouteSpecification(boolean unique) { + this.unique = unique; + } + + private Traversal getStart(Traversal entry){ + Traversal res = null; + Traversal last = entry; + Optional> head = entry.getHead(); + while (head.isPresent()) { + Traversal e = head.get(); + res = last; + last = e; + head = e.getHead(); + } + return res; + } + + @Override + public boolean specified(Edge edge, Traversal entry) { + return check(edge, entry, false); + } + + @Override + public boolean updateSpecified(Edge edge, Traversal entry) { + return check(edge, entry, true); + } + + private boolean check(Edge edge, Traversal entry, boolean update) { + Optional> head = entry.getHead(); + if (!head.isPresent() || head.get().getEdge() == null) return false; + Traversal start = getStart(head.get()); + boolean found = edge.isConnect(start.getTarget().getEntry()); + if (found && unique){ + found = !start.isSkipped(); + if (update){ + start.setSkipped(true); + setSkip(entry); + } + } + return found; + } + + private void setSkip(Traversal entry) { + Traversal curr = entry; + Optional> head = entry.getHead(); + while (head.isPresent()) { + curr.setSkipped(true); + curr = head.get(); + head = curr.getHead(); + } + } +} diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index 07bfee1..be648a2 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -89,6 +89,10 @@ public class RouteSearcher { return collector.get(); } + public List getLoops(Vendor source, Collection vendors, int count){ + return search(source, source, vendors, count, new LoopRouteSpecification(true)); + } + private class RouteCollector { private List routes = new ArrayList<>(); diff --git a/core/src/main/java/ru/trader/core/MarketAnalyzer.java b/core/src/main/java/ru/trader/core/MarketAnalyzer.java index 5dba6bb..fc5d1c7 100644 --- a/core/src/main/java/ru/trader/core/MarketAnalyzer.java +++ b/core/src/main/java/ru/trader/core/MarketAnalyzer.java @@ -202,6 +202,10 @@ public class MarketAnalyzer { return top; } + public Collection getLoops(Vendor vendor, int limit){ + return searcher.getLoops(vendor, getVendors(), limit); + } + public Collection getRoutes(Place from){ return searcher.getRoutes(getVendors(from), getVendors()); } diff --git a/core/src/test/java/ru/trader/analysis/VendorsGraphTest.java b/core/src/test/java/ru/trader/analysis/VendorsGraphTest.java index d9cf7ef..4838380 100644 --- a/core/src/test/java/ru/trader/analysis/VendorsGraphTest.java +++ b/core/src/test/java/ru/trader/analysis/VendorsGraphTest.java @@ -6,14 +6,15 @@ import org.junit.Before; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.trader.analysis.graph.ConnectibleGraph; -import ru.trader.analysis.graph.Crawler; -import ru.trader.analysis.graph.SimpleCollector; -import ru.trader.analysis.graph.Vertex; +import ru.trader.analysis.graph.*; import ru.trader.core.*; import ru.trader.store.simple.Store; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Collectors; @@ -71,6 +72,174 @@ public class VendorsGraphTest extends Assert { assertNotNull(x); } + private final static Map edgesStat = new HashMap<>(); + static { + Object[][] arrays = { + {"Cabrera Dock",16}, + {"Transit LHS 1507",18}, + {"Transit Bao Yan Luo",12}, + {"Behnken Terminal",12}, + {"Transit LHS 1483",16}, + {"Transit Bhadaba",36}, + {"Transit BD+24 543",23}, + {"Proteus Orbital",23}, + {"Katzenstein Settlement",23}, + {"Ayerohal City",36}, + {"Derleth Orbital",36}, + {"Maire Gateway",36}, + {"Roberts Hub",36}, + {"Dedman Gateway",36}, + {"Bailey Ring",36}, + {"Humphreys Enterprise",36}, + {"Kandel Ring",36}, + {"Polya Enterprise",36}, + {"Transit Kp Tauri",32}, + {"Spedding Orbital",32}, + {"Anders Orbital",32}, + {"Mohmand Dock",32}, + {"Bykovsky Ring",16}, + {"Vaucanson Settlement",16}, + {"Nicollier Ring",16}, + {"Transit LHS 1516",29}, + {"Transit LHS 1573",28}, + {"DG-1 Refinery",28}, + {"Blackman Terminal",28}, + {"Transit LHS 21",21}, + {"Quimper Ring",21}, + {"Crook Orbital",21}, + {"Transit LP 356-106",28}, + {"Carrier Dock",28}, + {"Transit Marduk",30}, + {"Port Sippar",30}, + {"Amar Station",30}, + {"Transit Wolf 1278",29}, + {"Maller Hub",29}, + {"Scott Settlement",29}, + {"Transit Wolf 1325",36}, + {"Gibson Settlement",18}, + {"Euler Port",18}, + {"Transit LHS 1541",16}, + {"Henney City",16}, + {"Haller Port",16}, + {"Pennington City",16}, + {"Foda Station",16}, + {"Stebler City",16}, + {"Transit Wolf 1323",19}, + {"Denis Filippov",19}, + {"Rattus High",19}, + {"Transit Apollo",19}, + {"Reisman Station",19}, + {"Fultion Landing",19}, + {"Transit Meri",19}, + {"Tyurin Port",19}, + {"Transit Bonde",17}, + {"Aksyonov Platform",17}, + {"Transit LHS 1667",10}, + {"Transit Ndozins",19}, + {"Coney Arena",19}, + {"Transit Tascheter Sector CL-Y D99",17}, + {"Transit V491 Persei",25}, + {"Rand City",25}, + {"Transit 39 Tauri",24}, + {"Porta",24}, + {"Transit Lowne 1",7}, + {"Sarich Port",7}, + {"Transit Geras",8}, + {"Transit Herishep",15}, + {"Harris Platform",15}, + {"Transit Ross 592",26}, + {"Transit Sui Xing",24}, + {"Morgan Terminal",24}, + {"Oswald Platform",24}, + {"Transit LTT 11503",19}, + {"Fung Outpost",19}, + {"Transit Ashandras",13}, + {"Bolger Vision",13}, + {"Alpers Refinery",13}, + {"Transit Itza",10}, + {"Ellision Station",10}, + {"Hennepin Enterprise",10}, + {"Luiken Port",10}, + {"Ore Terminal",10}, + {"McDaniel Station",10}, + {"Cochrane Terminal",10}, + {"McDonald Port",10}, + {"Transit G 85-36",3}, + {"Transit Al-Qaum",14}, + {"Duke Hub",14}, + {"Shepard Ring",14}, + {"Cormack Orbital",14}, + {"Transit LTT 11455",15}, + {"Gdeschke Station",15}, + {"Stebler Mines",15}, + {"Transit Tao Ti",0} + }; + for (Object[] entry : arrays) { + edgesStat.put((String)entry[0], (Integer)entry[1]); + } + + } + + @Test + public void testBuild2() throws Exception { + Vendor cabreraDock = lhs1541.get("Cabrera Dock"); + Ship ship = new Ship(); + ship.setCargo(24); ship.setEngine(2,'A'); + Profile profile = new Profile(ship); + LOG.info("Start build test"); + profile.setBalance(100000); profile.setJumps(6); + LOG.info("Build connectible graph"); + ConnectibleGraph vGraph = new ConnectibleGraph<>(profile); + vGraph.build(cabreraDock, fWorld.getMarkets(true).collect(Collectors.toList())); + for (Vertex vertex : vGraph.vertexes()) { + assertEquals(edgesStat.get(vertex.getEntry().toString()).intValue(), vertex.getEdges().size()); + } + + LOG.info("Build vendors graph"); + Scorer scorer = new Scorer(fWorld, profile); + vGraph = new VendorsGraph(scorer); + vGraph.build(cabreraDock, fWorld.getMarkets(true).collect(Collectors.toList())); + for (Vertex vertex : vGraph.vertexes()) { + switch (vertex.getEntry().getName()){ + case "Shepard Ring": + case "Cormack Orbital": + case "Duke Hub": assertEquals(8, vertex.getEdges().size()); + break; + case "Stebler Mines": + case "Gdeschke Station": assertEquals(9, vertex.getEdges().size()); + break; + default: + assertEquals(62, vertex.getEdges().size()); + } + } + } + + @Test + public void testLoop() throws Exception { + Vendor cabreraDock = lhs1541.get("Cabrera Dock"); + Ship ship = new Ship(); + ship.setCargo(24); ship.setEngine(2,'A'); + Profile profile = new Profile(ship); + LOG.info("Start build test"); + profile.setBalance(100000); profile.setJumps(6); + Scorer scorer = new Scorer(fWorld, profile); + LOG.info("Build vendors graph"); + VendorsGraph vGraph = new VendorsGraph(scorer); + vGraph.build(cabreraDock, fWorld.getMarkets(true).collect(Collectors.toList())); + LOG.info("Search"); + SimpleCollector paths = new SimpleCollector<>(); + Crawler crawler = vGraph.crawler(new LoopRouteSpecification<>(true), paths::add); + crawler.findMin(cabreraDock, 100); + assertEquals(60, paths.get().size()); + Collection vendors = new ArrayList<>(60); + paths.get().forEach(edges -> { + Vendor v = edges.get(0).getTarget().getEntry(); + assertFalse(vendors.contains(v)); + vendors.add(v); + }); + + } + @After public void tearDown() throws Exception { world = null;