Archived
0

implement loop specificator

This commit is contained in:
iMoHax
2015-08-20 17:35:30 +03:00
parent 2d6c0f8f9e
commit 88fb2fcaf9
9 changed files with 131 additions and 44 deletions

View File

@@ -10,10 +10,16 @@ import java.util.function.Consumer;
public abstract class AbstractCrawlerSpecification implements CrawlerSpecification { public abstract class AbstractCrawlerSpecification implements CrawlerSpecification {
private final RouteSpecification<Vendor> routeSpecification; private final RouteSpecification<Vendor> routeSpecification;
private final Consumer<List<Edge<Vendor>>> onFoundFunc; private final Consumer<List<Edge<Vendor>>> onFoundFunc;
private final boolean loop;
protected AbstractCrawlerSpecification(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) { protected AbstractCrawlerSpecification(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc, boolean loop) {
this.routeSpecification = routeSpecification; this.routeSpecification = routeSpecification;
this.onFoundFunc = onFoundFunc; this.onFoundFunc = onFoundFunc;
this.loop = loop;
}
protected boolean isLoop() {
return loop;
} }
@Override @Override

View File

@@ -10,29 +10,34 @@ import java.util.function.Consumer;
public class CrawlerSpecificationByProfit extends AbstractCrawlerSpecification { public class CrawlerSpecificationByProfit extends AbstractCrawlerSpecification {
public CrawlerSpecificationByProfit(Consumer<List<Edge<Vendor>>> onFoundFunc) { public CrawlerSpecificationByProfit(Consumer<List<Edge<Vendor>>> onFoundFunc) {
super(null, onFoundFunc); super(null, onFoundFunc, false);
} }
public CrawlerSpecificationByProfit(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) { public CrawlerSpecificationByProfit(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc, boolean loop) {
super(routeSpecification, onFoundFunc); super(routeSpecification, onFoundFunc, loop);
} }
@Override @Override
public double computeWeight(VendorsCrawler.VendorsEdge edge) { public double computeWeight(VendorsCrawler.VendorsEdge edge) {
return edge.getTime()/edge.getProfitByTonne(); double profit = edge.getProfitByTonne();
return profit > 0 ? edge.getTime()/profit : edge.getTime();
} }
@Override @Override
public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) { public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) {
double profit = 0; double time = 0; double profit = 0; double time = 0;
Iterator<Edge<Vendor>> iterator = entry.routeIterator(); Iterator<Edge<Vendor>> iterator = entry.routeIterator();
boolean first = true;
while (iterator.hasNext()){ while (iterator.hasNext()){
VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next(); VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next();
if (edge != null){ if (edge != null){
if (!isLoop() || first || iterator.hasNext()){
profit += edge.getProfitByTonne(); profit += edge.getProfitByTonne();
time += edge.getTime(); time += edge.getTime();
} }
} }
first = false;
}
return profit > 1 ? time / profit : time; return profit > 1 ? time / profit : time;
} }

View File

@@ -9,29 +9,35 @@ import java.util.function.Consumer;
public class CrawlerSpecificationByTime extends AbstractCrawlerSpecification { public class CrawlerSpecificationByTime extends AbstractCrawlerSpecification {
public CrawlerSpecificationByTime(Consumer<List<Edge<Vendor>>> onFoundFunc) { public CrawlerSpecificationByTime(Consumer<List<Edge<Vendor>>> onFoundFunc) {
super(null, onFoundFunc); super(null, onFoundFunc, false);
} }
public CrawlerSpecificationByTime(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) { public CrawlerSpecificationByTime(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc, boolean loop) {
super(routeSpecification, onFoundFunc); super(routeSpecification, onFoundFunc, loop);
} }
@Override @Override
public double computeWeight(VendorsCrawler.VendorsEdge edge) { public double computeWeight(VendorsCrawler.VendorsEdge edge) {
return edge.getTime(); double profit = edge.getProfitByTonne();
return profit > 0 ? edge.getTime() + 1/profit : edge.getTime();
} }
@Override @Override
public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) { public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) {
double time = 0; double profit = 0; long time = 0;
Iterator<Edge<Vendor>> iterator = entry.routeIterator(); Iterator<Edge<Vendor>> iterator = entry.routeIterator();
boolean first = true;
while (iterator.hasNext()){ while (iterator.hasNext()){
VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next(); VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next();
if (edge != null){ if (edge != null){
if (!isLoop() || first || iterator.hasNext()){
profit += edge.getProfitByTonne();
time += edge.getTime(); time += edge.getTime();
} }
} }
return time; first = false;
}
return profit > 0 ? time + 1/profit : time + 0.999999999999999d;
} }
} }

View File

@@ -64,7 +64,7 @@ public class CrawlerSpecificator {
this.offers.addAll(offers); this.offers.addAll(offers);
} }
public CrawlerSpecification build(Consumer<List<Edge<Vendor>>> onFoundFunc, RouteSpecification<Vendor> andSpec){ public CrawlerSpecification build(Consumer<List<Edge<Vendor>>> onFoundFunc, RouteSpecification<Vendor> andSpec, boolean loop){
RouteSpecification<Vendor> spec; RouteSpecification<Vendor> spec;
RouteSpecification<Vendor> res = null; RouteSpecification<Vendor> res = null;
if (!all.isEmpty()){ if (!all.isEmpty()){
@@ -95,13 +95,13 @@ public class CrawlerSpecificator {
} }
} }
if (byTime){ if (byTime){
return new CrawlerSpecificationByTime(res, onFoundFunc); return new CrawlerSpecificationByTime(res, onFoundFunc, loop);
} }
return new CrawlerSpecificationByProfit(res, onFoundFunc); return new CrawlerSpecificationByProfit(res, onFoundFunc, loop);
} }
public CrawlerSpecification build(Consumer<List<Edge<Vendor>>> onFoundFunc){ public CrawlerSpecification build(Consumer<List<Edge<Vendor>>> onFoundFunc){
return build(onFoundFunc, null); return build(onFoundFunc, null, false);
} }
} }

View File

@@ -114,13 +114,19 @@ public class RouteSearcher {
vGraph.build(source, vendors); vGraph.build(source, vendors);
LOG.trace("Graph is builds"); LOG.trace("Graph is builds");
RouteCollector collector = new RouteCollector(); RouteCollector collector = new RouteCollector();
Crawler<Vendor> crawler = vGraph.crawler(specificator.build(collector::add, new LoopRouteSpecification<>(true)), callback); Crawler<Vendor> crawler = vGraph.crawler(specificator.build(collector::add, new LoopRouteSpecification<>(true), true), callback);
crawler.setMaxSize(scorer.getProfile().getLands()); crawler.setMaxSize(scorer.getProfile().getLands());
crawler.findMin(source, count); crawler.findMin(source, count);
crawler = vGraph.crawler(specificator.build(collector::add, new RouteSpecificationByTarget<>(source)), callback); crawler = vGraph.crawler(specificator.build(collector::add, new RouteSpecificationByTarget<>(source), false), callback);
crawler.setMaxSize(scorer.getProfile().getLands()); crawler.setMaxSize(scorer.getProfile().getLands());
crawler.findMin(source, 1); crawler.findMin(source, 1);
return collector.get(); List<Route> routes = collector.get();
routes.sort((r1, r2) -> {
double s1 = (r1.getProfit() - r1.getEntries().get(0).getProfit()) / r1.getTime();
double s2 = (r2.getProfit() - r2.getEntries().get(0).getProfit()) / r2.getTime();
return Double.compare(s2, s1);
});
return routes;
} }
private class RouteCollector { private class RouteCollector {

View File

@@ -6,16 +6,17 @@ import ru.trader.core.Order;
import ru.trader.core.Vendor; import ru.trader.core.Vendor;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class VendorsCrawler extends Crawler<Vendor> { public class VendorsCrawler extends Crawler<Vendor> {
private double startFuel; private double startFuel;
private double startBalance; private double startBalance;
private final CrawlerSpecification specification;
public VendorsCrawler(VendorsGraph graph, CrawlerSpecification specification, AnalysisCallBack callback) { public VendorsCrawler(VendorsGraph graph, CrawlerSpecification specification, AnalysisCallBack callback) {
super(graph, specification.routeSpecification(), specification.onFoundFunc(), callback); super(graph, specification.routeSpecification(), specification.onFoundFunc(), callback);
this.specification = specification;
startFuel = graph.getProfile().getShip().getTank(); startFuel = graph.getProfile().getShip().getTank();
startBalance = graph.getProfile().getBalance(); startBalance = graph.getProfile().getBalance();
} }
@@ -83,16 +84,7 @@ public class VendorsCrawler extends Crawler<Vendor> {
@Override @Override
public double getWeight() { public double getWeight() {
if (weight == null){ if (weight == null){
double profit = 0; double time = 0; weight = specification.computeWeight(this);
Iterator<Edge<Vendor>> iterator = routeIterator();
while (iterator.hasNext()){
VendorsEdge edge = (VendorsEdge)iterator.next();
if (edge != null){
profit += edge.getProfitByTonne();
time += edge.getTime();
}
}
weight = profit > 1 ? time / profit : time;
} }
return weight; return weight;
} }
@@ -191,7 +183,7 @@ public class VendorsCrawler extends Crawler<Vendor> {
@Override @Override
protected double computeWeight() { protected double computeWeight() {
return getTime()/getProfitByTonne(); return specification.computeWeight(this);
} }
@Override @Override

View File

@@ -28,18 +28,10 @@ public class VendorsGraph extends ConnectibleGraph<Vendor> {
return new VendorsCrawler(this, new CrawlerSpecificationByProfit(onFoundFunc), callback); return new VendorsCrawler(this, new CrawlerSpecificationByProfit(onFoundFunc), callback);
} }
public VendorsCrawler crawler(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
return new VendorsCrawler(this, new CrawlerSpecificationByProfit(specification, onFoundFunc), callback);
}
public VendorsCrawler crawlerByTime(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){ public VendorsCrawler crawlerByTime(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
return new VendorsCrawler(this, new CrawlerSpecificationByTime(onFoundFunc), callback); return new VendorsCrawler(this, new CrawlerSpecificationByTime(onFoundFunc), callback);
} }
public VendorsCrawler crawlerByTime(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
return new VendorsCrawler(this, new CrawlerSpecificationByTime(specification, onFoundFunc), callback);
}
public VendorsCrawler crawler(CrawlerSpecification specification, AnalysisCallBack callback){ public VendorsCrawler crawler(CrawlerSpecification specification, AnalysisCallBack callback){
return new VendorsCrawler(this, specification, callback); return new VendorsCrawler(this, specification, callback);
} }

View File

@@ -9,6 +9,8 @@ import ru.trader.core.*;
import ru.trader.store.simple.Store; import ru.trader.store.simple.Store;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -25,6 +27,7 @@ public class RouteSearcherTest extends Assert{
private Place dnDraconis; private Place dnDraconis;
private Place aulin; private Place aulin;
private Place cmDraco; private Place cmDraco;
private Place aulis;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@@ -37,6 +40,7 @@ public class RouteSearcherTest extends Assert{
dnDraconis = world.get("DN Draconis"); dnDraconis = world.get("DN Draconis");
aulin = world.get("Aulin"); aulin = world.get("Aulin");
cmDraco = world.get("CM Draco"); cmDraco = world.get("CM Draco");
aulis = world.get("Aulis");
MarketFilter filter = new MarketFilter(); MarketFilter filter = new MarketFilter();
fWorld = new FilteredMarket(world, filter); fWorld = new FilteredMarket(world, filter);
@@ -78,7 +82,8 @@ public class RouteSearcherTest extends Assert{
assertEquals(2, route.getLands()); assertEquals(2, route.getLands());
assertEquals(72.42, route.getDistance(), 0.01); assertEquals(72.42, route.getDistance(), 0.01);
List<Route> apaths = searcher.getRoutes(ithaca_st, ithaca_st, fWorld.getMarkets(true).collect(Collectors.toList())); Collection<Vendor> world = fWorld.getMarkets(true).collect(Collectors.toList());
List<Route> apaths = searcher.getRoutes(ithaca_st, ithaca_st, world);
/* List<Route> apaths = searcher.getRoutes(ithaca_st, ithaca_st, Arrays.asList(ithaca_st, lhs3262_st, /* List<Route> apaths = searcher.getRoutes(ithaca_st, ithaca_st, Arrays.asList(ithaca_st, lhs3262_st,
morgor_st, lhs3006_st, ithaca.asTransit(), lhs3262.asTransit(), morgor_st, lhs3006_st, ithaca.asTransit(), lhs3262.asTransit(),
morgor.asTransit(), lhs3006.asTransit())); morgor.asTransit(), lhs3006.asTransit()));
@@ -106,9 +111,84 @@ public class RouteSearcherTest extends Assert{
assertEquals(4, route.getLands()); assertEquals(4, route.getLands());
assertEquals(109.51, route.getDistance(), 0.01); assertEquals(109.51, route.getDistance(), 0.01);
apaths = searcher.getRoutes(ithaca_st, ithaca_st, fWorld.getMarkets(true).collect(Collectors.toList())); apaths = searcher.getRoutes(ithaca_st, ithaca_st, world);
actual = apaths.stream().findFirst().get(); actual = apaths.stream().findFirst().get();
assertEquals(route, actual); assertEquals(route, actual);
} }
@Test
public void testRoutesByTime() throws Exception {
// Balance: 6000000, cargo: 440, tank: 40, distance: 13.4, jumps: 6
// Ithaca (Palladium to Aulis) -> Aulis (Consumer Technology to Ithaca) -> Aulis
// Profit: 231093.9, time: 476, distance: 17.36, lands: 2
Vendor ithaca_st = ithaca.get().iterator().next();
Vendor aulis_st = aulis.get().iterator().next();
Ship ship = new Ship();
ship.setCargo(440); ship.setTank(15);
ship.setEngine(5, 'A'); ship.setMass(466);
Profile profile = new Profile(ship);
profile.setBalance(6000000); profile.setJumps(6);
profile.setRoutesCount(100); profile.setLands(3);
Scorer scorer = new Scorer(fWorld, profile);
LOG.info("Start search by times test");
RouteSearcher searcher = new RouteSearcher(scorer);
Route route = new Route(new RouteEntry(ithaca_st, 0, 1.73439683972718d, 0));
route.add(new RouteEntry(aulis_st, 0, 1.726405672421771d, 0));
route.add(new RouteEntry(ithaca_st, 0, 0, 0));
RouteFiller filler = new RouteFiller(scorer);
filler.fill(route);
assertEquals(231093.9, route.getProfit(), 0.1);
assertEquals(476, route.getTime(), 0.1);
assertEquals(2, route.getLands());
assertEquals(17.36, route.getDistance(), 0.01);
CrawlerSpecificator specificator = new CrawlerSpecificator();
specificator.setByTime(true);
Collection<Vendor> world = fWorld.getMarkets(true).collect(Collectors.toList());
List<Route> apaths = searcher.search(ithaca_st, ithaca_st, world, profile.getRoutesCount(), specificator);
Route actual = apaths.stream().findFirst().get();
assertEquals("Routes is different", route, actual);
}
@Test
public void testLoopRoutes() throws Exception {
// Balance: 6000000, cargo: 440, tank: 40, distance: 13.4, jumps: 6
Ship ship = new Ship();
ship.setCargo(440); ship.setTank(15);
ship.setEngine(5, 'A'); ship.setMass(466);
Profile profile = new Profile(ship);
profile.setBalance(6000000); profile.setJumps(6);
profile.setRoutesCount(100); profile.setLands(3);
Scorer scorer = new Scorer(fWorld, profile);
LOG.info("Start loop search ");
RouteSearcher searcher = new RouteSearcher(scorer);
Vendor ithaca_st = ithaca.get().iterator().next();
Collection<Vendor> world = fWorld.getMarkets(true).collect(Collectors.toList());
List<Route> apaths = searcher.getLoops(ithaca_st, world, profile.getRoutesCount());
assertEquals(39, apaths.size());
Collection<Vendor> vendors = new ArrayList<>(40);
apaths.forEach(route -> {
List<RouteEntry> entries = route.getEntries();
Vendor v = entries.get(entries.size()-1).getVendor();
assertFalse(vendors.contains(v));
vendors.add(v);
/* List<Route> p = searcher.getRoutes(v, v, world, 1);
double profit = route.getProfit() - route.get(0).getProfit();
long time = route.getTime() - route.get(0).getFullTime();
double score = profit/time;
Route oRoute = p.get(0);
LOG.info("{} - loop", v);
LOG.info("profit: {}, time: {}, score: {} ", profit, time, score);
LOG.info("profit: {}, time: {}, score: {} ", oRoute.getProfit(), oRoute.getTime(), oRoute.getScore());
assertTrue(score <= oRoute.getScore());*/
});
assertTrue(vendors.contains(ithaca_st));
}
} }

View File

@@ -228,7 +228,7 @@ public class VendorsGraphTest extends Assert {
vGraph.build(cabreraDock, fWorld.getMarkets(true).collect(Collectors.toList())); vGraph.build(cabreraDock, fWorld.getMarkets(true).collect(Collectors.toList()));
LOG.info("Search"); LOG.info("Search");
SimpleCollector<Vendor> paths = new SimpleCollector<>(); SimpleCollector<Vendor> paths = new SimpleCollector<>();
Crawler<Vendor> crawler = vGraph.crawler(new LoopRouteSpecification<>(true), paths::add, new AnalysisCallBack()); Crawler<Vendor> crawler = vGraph.crawler(new CrawlerSpecificationByProfit(new LoopRouteSpecification<>(true), paths::add, true), new AnalysisCallBack());
crawler.findMin(cabreraDock, 100); crawler.findMin(cabreraDock, 100);
assertEquals(60, paths.get().size()); assertEquals(60, paths.get().size());
Collection<Vendor> vendors = new ArrayList<>(60); Collection<Vendor> vendors = new ArrayList<>(60);