From d8b09cc8374a882e67f672b9bb3e5edfc0948ae2 Mon Sep 17 00:00:00 2001 From: iMoHax Date: Thu, 27 Aug 2015 17:12:18 +0300 Subject: [PATCH] implement offers crawler builder --- .../trader/analysis/CrawlerSpecificator.java | 39 +++- .../main/java/ru/trader/analysis/Route.java | 4 + .../ru/trader/analysis/RouteSearcher.java | 6 +- .../analysis/RouteSpecificationByTargets.java | 2 +- .../analysis/CrawlerSpecificatorTest.java | 216 ++++++++++++++++++ 5 files changed, 256 insertions(+), 11 deletions(-) create mode 100644 core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java diff --git a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java index b1a72c8..fbc8da6 100644 --- a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java +++ b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.function.Consumer; +import java.util.stream.Collectors; public class CrawlerSpecificator { private final List any; @@ -69,17 +70,33 @@ public class CrawlerSpecificator { this.groupCount = groupCount; } - public VendorsCrawlerSpecification build(Consumer>> onFoundFunc, RouteSpecification andSpec, boolean loop){ + private RouteSpecification buildOffersSpec(Collection vendors){ + RouteSpecification res = null; + for (Offer offer : offers) { + List sellers = vendors.stream().filter(v -> { + Offer sell = v.getSell(offer.getItem()); + return sell != null && sell.getCount() >= offer.getCount(); + }).collect(Collectors.toList()); + if (res != null){ + res = res.and(RouteSpecificationByTargets.containAny(sellers)); + } else { + res = RouteSpecificationByTargets.containAny(sellers); + } + } + return res; + } + + public VendorsCrawlerSpecification build(Collection vendors, Consumer>> onFoundFunc, RouteSpecification andSpec, boolean loop){ RouteSpecification spec; RouteSpecification res = null; if (!all.isEmpty()){ - spec = all.size() > 1 ? RouteSpecificationByTargets.all(all) : new RouteSpecificationByTarget<>(all.get(0)); + spec = RouteSpecificationByTargets.all(all); res = spec; } if (!any.isEmpty()){ spec = any.size() > 1 ? RouteSpecificationByTargets.any(any) : new RouteSpecificationByTarget<>(any.get(0)); if (res != null){ - res.and(spec); + res = res.and(spec); } else { res = spec; } @@ -87,14 +104,22 @@ public class CrawlerSpecificator { if (!containsAny.isEmpty()){ spec = RouteSpecificationByTargets.containAny(containsAny); if (res != null){ - res.and(spec); + res = res.and(spec); + } else { + res = spec; + } + } + if (!offers.isEmpty()){ + spec = buildOffersSpec(vendors); + if (res != null){ + res = res.and(spec); } else { res = spec; } } if (andSpec != null){ if (res != null){ - res.and(andSpec); + res = res.and(andSpec); } else { res = andSpec; } @@ -109,8 +134,8 @@ public class CrawlerSpecificator { return (VendorsCrawlerSpecification) crawlerSpecification; } - public VendorsCrawlerSpecification build(Consumer>> onFoundFunc){ - return build(onFoundFunc, null, false); + public VendorsCrawlerSpecification build(Collection vendors, Consumer>> onFoundFunc){ + return build(vendors, onFoundFunc, null, false); } } diff --git a/core/src/main/java/ru/trader/analysis/Route.java b/core/src/main/java/ru/trader/analysis/Route.java index 8dc704d..3ef09b1 100644 --- a/core/src/main/java/ru/trader/analysis/Route.java +++ b/core/src/main/java/ru/trader/analysis/Route.java @@ -76,6 +76,10 @@ public class Route implements Comparable { return profit / time; } + public int getJumps(){ + return entries.size(); + } + public void add(RouteEntry entry){ LOG.trace("Add entry {} to route {}", entry, this); entries.add(entry); diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index 8550238..fa52785 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -103,7 +103,7 @@ public class RouteSearcher { vGraph.build(source, vendors); LOG.trace("Graph is builds"); RouteCollector collector = new RouteCollector(); - Crawler crawler = vGraph.crawler(specificator.build(collector::add), callback); + Crawler crawler = vGraph.crawler(specificator.build(vendors, collector::add), callback); crawler.setMaxSize(scorer.getProfile().getLands()); crawler.findMin(target, count); return collector.get(); @@ -117,10 +117,10 @@ public class RouteSearcher { LOG.trace("Graph is builds"); RouteCollector collector = new RouteCollector(); specificator.setGroupCount(vendors.size()); - Crawler crawler = vGraph.crawler(specificator.build(collector::add, new LoopRouteSpecification<>(true), true), callback); + Crawler crawler = vGraph.crawler(specificator.build(vendors, collector::add, new LoopRouteSpecification<>(true), true), callback); crawler.setMaxSize(scorer.getProfile().getLands()); crawler.findMin(source, vendors.size()); - crawler = vGraph.crawler(specificator.build(collector::add, new RouteSpecificationByTarget<>(source), false), callback); + crawler = vGraph.crawler(specificator.build(vendors, collector::add, new RouteSpecificationByTarget<>(source), false), callback); crawler.setMaxSize(scorer.getProfile().getLands()); crawler.findMin(source, 1); List routes = collector.get(); diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java index 1da710a..389a7eb 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java @@ -28,7 +28,7 @@ public class RouteSpecificationByTargets implements RouteSpecification { Collection set = new ArrayList<>(targets.size()); set.add(obj); entry.routeIterator().forEachRemaining(e -> set.add(e.getTarget().getEntry())); - return targets.containsAll(set); + return set.containsAll(targets); } private boolean containsAny(Edge edge, Traversal entry) { diff --git a/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java new file mode 100644 index 0000000..3743290 --- /dev/null +++ b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java @@ -0,0 +1,216 @@ +package ru.trader.analysis; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.trader.analysis.graph.Crawler; +import ru.trader.core.*; +import ru.trader.store.simple.SimpleOffer; +import ru.trader.store.simple.Store; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class CrawlerSpecificatorTest extends Assert{ + private final static Logger LOG = LoggerFactory.getLogger(CrawlerSpecificatorTest.class); + + private VendorsGraph vGraph; + private List vendors; + + private Vendor ithaca_st; + private Vendor lhs3262_st; + private Vendor morgor_st; + private Vendor lhs3006_st; + private Vendor aulin_st; + private Vendor cmDraco_st; + private Vendor ovid_st; + private Vendor aulis_st; + + private Item gold; + private Item personalweapons; + + @Before + public void setUp() throws Exception { + InputStream is = getClass().getResourceAsStream("/world.xml"); + Market world = Store.loadFromFile(is); + gold = world.getItem("gold"); + personalweapons = world.getItem("personalweapons"); + Place ithaca = world.get("Ithaca"); + Place lhs3262 = world.get("LHS 3262"); + Place morgor = world.get("Morgor"); + Place lhs3006 = world.get("LHS 3006"); + Place ovid = world.get("Ovid"); + Place aulin = world.get("Aulin"); + Place cmDraco = world.get("CM Draco"); + Place aulis = world.get("Aulis"); + + ithaca_st = ithaca.get().iterator().next(); + lhs3262_st = lhs3262.get().iterator().next(); + morgor_st = morgor.get().iterator().next(); + lhs3006_st = lhs3006.get().iterator().next(); + aulin_st = aulin.get().iterator().next(); + cmDraco_st = cmDraco.get().iterator().next(); + ovid_st = ovid.get().iterator().next(); + aulis_st = aulis.get().iterator().next(); + + MarketFilter filter = new MarketFilter(); + FilteredMarket fWorld = new FilteredMarket(world, filter); + + 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("Build vendors graph"); + vGraph = new VendorsGraph(scorer, new AnalysisCallBack()); + vendors = fWorld.getMarkets(true).collect(Collectors.toList()); + Vendor ithaca_st = ithaca.get().iterator().next(); + vGraph.build(ithaca_st, vendors); + } + + + @Test + public void testContainAll() throws Exception { + LOG.info("Test contain all"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + specificator.add(cmDraco_st, true); + specificator.add(aulin_st, true); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(3); + crawler.findMin(lhs3262_st, 10); + assertEquals(10, paths.size()); + for (Route path : paths) { + assertTrue(path.contains(Arrays.asList(cmDraco_st, aulin_st))); + } + paths.clear(); + } + + @Test + public void testAny() throws Exception { + LOG.info("Test any"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + specificator.add(morgor_st, false); + specificator.add(lhs3006_st, false); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(3); + crawler.findMin(lhs3262_st, 10); + assertEquals(10, paths.size()); + for (Route path : paths) { + Vendor target = path.get(path.getJumps()-1).getVendor(); + assertTrue(target == morgor_st || target == lhs3006_st); + } + paths.clear(); + } + + @Test + public void testContainAny() throws Exception { + LOG.info("Test contain any"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + specificator.any(Arrays.asList(aulin_st, morgor_st, lhs3006_st)); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(3); + crawler.findMin(lhs3262_st, 10); + assertEquals(10, paths.size()); + for (Route path : paths) { + boolean contain = path.contains(Arrays.asList(aulin_st)) || + path.contains(Arrays.asList(morgor_st)) || + path.contains(Arrays.asList(lhs3006_st)); + + assertTrue(contain); + } + paths.clear(); + } + + @Test + public void testContainAllAny() throws Exception { + LOG.info("Test contain all and any target"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + specificator.add(cmDraco_st, true); + specificator.add(aulin_st, true); + specificator.add(morgor_st, false); + specificator.add(lhs3006_st, false); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(3); + crawler.findMin(lhs3262_st, 10); + assertEquals(4, paths.size()); + for (Route path : paths) { + assertTrue(path.contains(Arrays.asList(cmDraco_st, aulin_st))); + Vendor target = path.get(path.getJumps()-1).getVendor(); + assertTrue(target == morgor_st || target == lhs3006_st); + } + paths.clear(); + } + + @Test + public void testOffers() throws Exception { + LOG.info("Test offer"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + Offer goldOffer = new SimpleOffer(OFFER_TYPE.BUY, gold, 0, 30); + Offer weaponOffer = new SimpleOffer(OFFER_TYPE.BUY, personalweapons, 0, 100); + specificator.buy(Arrays.asList(goldOffer, weaponOffer)); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(3); + crawler.findMin(lhs3262_st, 10); + assertEquals(10, paths.size()); + for (Route path : paths) { + Collection vs = path.getVendors(); + assertTrue(vs.stream().anyMatch(v -> v.hasSell(gold)) || vs.stream().anyMatch(v -> v.hasSell(personalweapons))); + } + paths.clear(); + } + + @Test + public void testFull() throws Exception { + LOG.info("Test full"); + List paths = new ArrayList<>(); + CrawlerSpecificator specificator = new CrawlerSpecificator(); + specificator.add(cmDraco_st, true); + specificator.add(aulin_st, true); + specificator.add(lhs3262_st, false); + specificator.add(lhs3006_st, false); + specificator.any(Arrays.asList(ovid_st, aulis_st)); + Offer goldOffer = new SimpleOffer(OFFER_TYPE.BUY, gold, 0, 30); + Offer weaponOffer = new SimpleOffer(OFFER_TYPE.BUY, personalweapons, 0, 100); + specificator.buy(Arrays.asList(goldOffer, weaponOffer)); + VendorsCrawlerSpecification spec = specificator.build(vendors, edges -> {paths.add(RouteSearcher.toRoute(edges, vGraph.getScorer()));}); + + Crawler crawler = vGraph.crawler(spec, new AnalysisCallBack()); + crawler.setMaxSize(6); + crawler.findMin(ithaca_st, 10); + assertEquals(10, paths.size()); + for (Route path : paths) { + Vendor target = path.get(path.getJumps()-1).getVendor(); + assertTrue(target == lhs3262_st || target == lhs3006_st); + Collection vs = path.getVendors(); + assertTrue(vs.contains(aulis_st)||vs.contains(ovid_st)); + assertTrue(vs.containsAll(Arrays.asList(cmDraco_st, aulin_st))); + assertTrue(vs.stream().anyMatch(v -> v.hasSell(gold)) || vs.stream().anyMatch(v -> v.hasSell(personalweapons))); + } + paths.clear(); + } + +}