diff --git a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java index 23ff359..1e25712 100644 --- a/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java +++ b/core/src/main/java/ru/trader/analysis/CrawlerSpecificator.java @@ -97,9 +97,9 @@ public class CrawlerSpecificator { return sell != null && sell.getCount() >= offer.getCount(); }).collect(Collectors.toList()); if (res != null){ - res = res.and(RouteSpecificationByTargets.containAny(sellers)); + res = res.and(new RouteSpecificationByPair<>(sellers, offer.getVendor())); } else { - res = RouteSpecificationByTargets.containAny(sellers); + res = new RouteSpecificationByPair<>(sellers, offer.getVendor()); } } return res; diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecification.java b/core/src/main/java/ru/trader/analysis/RouteSpecification.java index e4e9033..1c5f7c4 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecification.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecification.java @@ -13,8 +13,12 @@ public interface RouteSpecification { public default boolean updateMutated(){return false;} public default boolean mutable(){return false;} public default void update(Traversal entry){} + public default void onAnd(RouteSpecification other){} + public default void onOr(RouteSpecification other){} default RouteSpecification and(final RouteSpecification other){ + this.onAnd(other); + other.onAnd(this); return new RouteSpecification() { @Override public boolean specified(Edge edge, Traversal entry) { @@ -46,10 +50,23 @@ public interface RouteSpecification { RouteSpecification.this.update(entry); other.update(entry); } + + @Override + public void onAnd(RouteSpecification specification) { + RouteSpecification.this.onAnd(specification); + other.onAnd(specification); + } + + @Override + public void onOr(RouteSpecification specification) { + RouteSpecification.this.onOr(specification); + other.onOr(specification); + } }; } default RouteSpecification or(final RouteSpecification other){ + this.onOr(other); return new RouteSpecification() { @Override public boolean specified(Edge edge, Traversal entry) { @@ -80,10 +97,62 @@ public interface RouteSpecification { RouteSpecification.this.update(entry); other.update(entry); } + + @Override + public void onAnd(RouteSpecification specification) { + RouteSpecification.this.onAnd(specification); + other.onAnd(specification); + } + + @Override + public void onOr(RouteSpecification specification) { + RouteSpecification.this.onOr(specification); + other.onOr(specification); + } + }; } default RouteSpecification negate(){ - return (edge, entry) -> !specified(edge, entry); + return new RouteSpecification() { + @Override + public boolean specified(Edge edge, Traversal entry) { + return !RouteSpecification.this.specified(edge, entry); + } + + @Override + public int lastFound(Edge edge, Traversal entry) { + return RouteSpecification.this.lastFound(edge, entry); + } + + @Override + public int matchCount() { + return RouteSpecification.this.matchCount(); + } + + @Override + public boolean updateMutated() { + return RouteSpecification.this.updateMutated(); + } + @Override + public boolean mutable() { + return RouteSpecification.this.mutable(); + } + + @Override + public void update(Traversal entry) { + RouteSpecification.this.update(entry); + } + + @Override + public void onAnd(RouteSpecification specification) { + RouteSpecification.this.onAnd(specification); + } + + @Override + public void onOr(RouteSpecification specification) { + RouteSpecification.this.onOr(specification); + } + }; } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java new file mode 100644 index 0000000..d4aa160 --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByPair.java @@ -0,0 +1,81 @@ +package ru.trader.analysis; + +import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.Traversal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +public class RouteSpecificationByPair implements RouteSpecification { + protected final Collection first; + protected final T second; + private boolean checkSecond; + + public RouteSpecificationByPair(T first, T second) { + this.first = new ArrayList<>(); + this.first.add(first); + this.second = second; + } + + public RouteSpecificationByPair(Collection first, T second) { + this.first = new ArrayList<>(first); + this.second = second; + } + + @Override + public boolean specified(Edge edge, Traversal entry) { + return searchPair(edge, entry) == 0; + } + + @Override + public int lastFound(Edge edge, Traversal entry) { + return searchPair(edge, entry); + } + + @Override + public int matchCount() { + return checkSecond ? 2 : 1; + } + + private int searchPair(Edge edge, Traversal entry){ + T obj = edge.getTarget().getEntry(); + int fIndex = -1; + int sIndex = -1; + if (first.contains(obj)){ + fIndex = 0; + } + if (second.equals(obj)){ + sIndex = 0; + } + if (sIndex != -1 && fIndex >= sIndex) return 0; + + Iterator> iterator = entry.routeIterator(); + int i = 1; + while (iterator.hasNext()){ + obj = iterator.next().getTarget().getEntry(); + if (sIndex == -1 && second.equals(obj)){ + sIndex = i; + } + if (sIndex != -1 && fIndex >= sIndex){ + return 0; + } + if (first.contains(obj)){ + fIndex = i; + } + i++; + } + if (fIndex == -1) return checkSecond ? 2 : 1; + if (sIndex == -1) return 1; + return fIndex >= sIndex ? 0 : 1; + } + + + @Override + public void onAnd(RouteSpecification other) { + if (other instanceof RouteSpecificationByTarget){ + T otherTarget = ((RouteSpecificationByTarget)other).target; + checkSecond = checkSecond || !second.equals(otherTarget); + } + } +} diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java index 11b2a7d..b71a599 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java @@ -34,6 +34,25 @@ public class RouteSpecificationByTargets implements RouteSpecification { return all ? targets.size() : 1; } + @Override + public void onAnd(RouteSpecification other) { + if (other instanceof RouteSpecificationByTarget){ + T otherTarget = ((RouteSpecificationByTarget)other).target; + targets.remove(otherTarget); + } else + if (other instanceof RouteSpecificationByTargets){ + RouteSpecificationByTargets os = ((RouteSpecificationByTargets)other); + if (os.all){ + Collection otherTargets = ((RouteSpecificationByTargets)other).targets; + targets.removeAll(otherTargets); + } + } else + if (other instanceof RouteSpecificationByPair){ + T otherTarget = ((RouteSpecificationByPair)other).second; + targets.remove(otherTarget); + } + } + private int containsAll(Edge edge, Traversal entry) { T obj = edge.getTarget().getEntry(); Collection set = new ArrayList<>(targets.size()); diff --git a/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java index 3743290..c980a83 100644 --- a/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java +++ b/core/src/test/java/ru/trader/analysis/CrawlerSpecificatorTest.java @@ -167,13 +167,13 @@ public class CrawlerSpecificatorTest extends Assert{ 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); + Offer goldOffer = SimpleOffer.fakeBuy(lhs3262_st, gold, 0, 30); + Offer weaponOffer = SimpleOffer.fakeBuy(lhs3262_st, 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.setMaxSize(4); crawler.findMin(lhs3262_st, 10); assertEquals(10, paths.size()); for (Route path : paths) { @@ -193,13 +193,13 @@ public class CrawlerSpecificatorTest extends Assert{ 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); + Offer goldOffer = SimpleOffer.fakeBuy(aulin_st, gold, 0, 30); + Offer weaponOffer = SimpleOffer.fakeBuy(aulin_st, 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.setMaxSize(7); crawler.findMin(ithaca_st, 10); assertEquals(10, paths.size()); for (Route path : paths) {