From 64b82dd76fc325e76859438d0f1c8ba874153682 Mon Sep 17 00:00:00 2001 From: iMoHax Date: Tue, 21 Jul 2015 15:34:15 +0300 Subject: [PATCH] change predicate to route specification for depending targets --- .../ru/trader/analysis/RouteSearcher.java | 19 +++---- .../trader/analysis/RouteSpecification.java | 21 ++++++++ .../analysis/RouteSpecificationByTarget.java | 17 ++++++ .../analysis/RouteSpecificationByTargets.java | 52 +++++++++++++++++++ .../java/ru/trader/analysis/VendorsGraph.java | 24 ++++----- .../ru/trader/analysis/graph/CCrawler.java | 5 +- .../ru/trader/analysis/graph/Crawler.java | 35 ++++++------- .../ru/trader/analysis/graph/Traversal.java | 25 +++++++++ 8 files changed, 152 insertions(+), 46 deletions(-) create mode 100644 core/src/main/java/ru/trader/analysis/RouteSpecification.java create mode 100644 core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java create mode 100644 core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index 754160d..5c22784 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -9,7 +9,6 @@ import ru.trader.core.Profile; import ru.trader.core.Vendor; import java.util.*; -import java.util.function.Predicate; public class RouteSearcher { private final static Logger LOG = LoggerFactory.getLogger(RouteSearcher.class); @@ -25,15 +24,14 @@ public class RouteSearcher { } public List>> getPaths(Place from, Collection places){ - Predicate> isFoundFunc = e -> places.parallelStream().filter(e::isConnect).findFirst().isPresent(); - return search(from, from, places, scorer.getProfile().getRoutesCount(), isFoundFunc); + return search(from, from, places, scorer.getProfile().getRoutesCount(), RouteSpecificationByTargets.any(places)); } public List>> getPaths(Place from, Place to, Collection places){ return search(from, to, places, scorer.getProfile().getRoutesCount(), null); } - private List>> search(Place source, Place target, Collection places, int count, Predicate> isFoundFunc){ + private List>> search(Place source, Place target, Collection places, int count, RouteSpecification specification){ Profile profile = scorer.getProfile(); LOG.trace("Start search path from {} to {} ", source, target); ConnectibleGraph graph = new ConnectibleGraph<>(profile); @@ -41,7 +39,7 @@ public class RouteSearcher { graph.build(source, places); LOG.trace("Graph is builds"); List>> paths = new ArrayList<>(); - Crawler crawler = isFoundFunc != null ? new CCrawler<>(graph, isFoundFunc, paths::add) : new CCrawler<>(graph, paths::add); + Crawler crawler = specification != null ? new CCrawler<>(graph, specification, paths::add) : new CCrawler<>(graph, paths::add); crawler.setMaxSize(profile.getJumps()); if (profile.getPathPriority() == Profile.PATH_PRIORITY.FAST){ crawler.findFast(target, count); @@ -58,18 +56,17 @@ public class RouteSearcher { public List getRoutes(Collection fVendors, Collection toVendors, Collection vendors){ List res = new LimitedQueue<>(scorer.getProfile().getRoutesCount()); int count = (int) Math.ceil(scorer.getProfile().getRoutesCount() / fVendors.size()); - Predicate> isFoundFunc = e -> toVendors.parallelStream().filter(e::isConnect).findFirst().isPresent(); + RouteSpecification specification = RouteSpecificationByTargets.any(toVendors); for (Vendor fromVendor : fVendors) { count = count / toVendors.size(); - Collection routes = search(fromVendor, fromVendor, vendors, count, isFoundFunc); + Collection routes = search(fromVendor, fromVendor, vendors, count, specification); res.addAll(routes); } return res; } public List getRoutes(Vendor from, Collection vendors){ - Predicate> isFoundFunc = e -> vendors.parallelStream().filter(e::isConnect).findFirst().isPresent(); - return search(from, from, vendors, scorer.getProfile().getRoutesCount(), isFoundFunc); + return search(from, from, vendors, scorer.getProfile().getRoutesCount(), RouteSpecificationByTargets.any(vendors)); } public List getRoutes(Vendor from, Vendor to, Collection vendors){ @@ -80,14 +77,14 @@ public class RouteSearcher { return search(source, target, vendors, count, null); } - private List search(Vendor source, Vendor target, Collection vendors, int count, Predicate> isFoundFunc){ + private List search(Vendor source, Vendor target, Collection vendors, int count, RouteSpecification specification){ LOG.trace("Start search route from {} to {}", source, target); VendorsGraph vGraph = new VendorsGraph(scorer); LOG.trace("Build vendors graph"); vGraph.build(source, vendors); LOG.trace("Graph is builds"); RouteCollector collector = new RouteCollector(); - Crawler crawler = isFoundFunc != null ? vGraph.crawler(isFoundFunc, collector::add) : vGraph.crawler(collector::add); + Crawler crawler = specification != null ? vGraph.crawler(specification, collector::add) : vGraph.crawler(collector::add); crawler.setMaxSize(scorer.getProfile().getLands()); crawler.findMin(target, count); return collector.get(); diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecification.java b/core/src/main/java/ru/trader/analysis/RouteSpecification.java new file mode 100644 index 0000000..ca6fb7c --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/RouteSpecification.java @@ -0,0 +1,21 @@ +package ru.trader.analysis; + +import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.Traversal; + +public interface RouteSpecification { + + public boolean specified(Edge edge, Traversal entry); + + default RouteSpecification and(final RouteSpecification other){ + return (edge, entry) -> RouteSpecification.this.specified(edge, entry) && other.specified(edge, entry); + } + + default RouteSpecification or(final RouteSpecification other){ + return (edge, entry) -> RouteSpecification.this.specified(edge, entry) || other.specified(edge, entry); + } + + default RouteSpecification negate(){ + return (edge, entry) -> !specified(edge, entry); + } +} diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java new file mode 100644 index 0000000..ceb3370 --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTarget.java @@ -0,0 +1,17 @@ +package ru.trader.analysis; + +import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.Traversal; + +public class RouteSpecificationByTarget implements RouteSpecification { + protected final T target; + + public RouteSpecificationByTarget(T target) { + this.target = target; + } + + @Override + public boolean specified(Edge edge, Traversal entry) { + return edge.isConnect(target); + } +} diff --git a/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java new file mode 100644 index 0000000..f55009f --- /dev/null +++ b/core/src/main/java/ru/trader/analysis/RouteSpecificationByTargets.java @@ -0,0 +1,52 @@ +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 RouteSpecificationByTargets implements RouteSpecification { + protected final Collection targets; + protected final boolean all; + + private RouteSpecificationByTargets(Collection targets, boolean all) { + this.all = all; + this.targets = new ArrayList<>(targets); + } + + @Override + public boolean specified(Edge edge, Traversal entry) { + return all ? containsAll(edge, entry) : containsAny(edge, entry); + } + + private boolean containsAll(Edge edge, Traversal entry) { + T obj = edge.getTarget().getEntry(); + Collection set = new ArrayList<>(targets.size()); + set.add(obj); + entry.routeIterator().forEachRemaining(e -> set.add(e.getTarget().getEntry())); + return targets.containsAll(set); + } + + private boolean containsAny(Edge edge, Traversal entry) { + T obj = edge.getTarget().getEntry(); + if (targets.contains(obj)) return true; + Iterator> iterator = entry.routeIterator(); + while (iterator.hasNext()){ + if (targets.contains(iterator.next().getTarget().getEntry())){ + return true; + } + } + return false; + } + + public static RouteSpecificationByTargets all(Collection targets){ + return new RouteSpecificationByTargets<>(targets, true); + } + + public static RouteSpecificationByTargets any(Collection targets){ + return new RouteSpecificationByTargets<>(targets, false); + } + +} diff --git a/core/src/main/java/ru/trader/analysis/VendorsGraph.java b/core/src/main/java/ru/trader/analysis/VendorsGraph.java index 28a1084..cbca98b 100644 --- a/core/src/main/java/ru/trader/analysis/VendorsGraph.java +++ b/core/src/main/java/ru/trader/analysis/VendorsGraph.java @@ -34,8 +34,8 @@ public class VendorsGraph extends ConnectibleGraph { return new VendorsCrawler(onFoundFunc); } - public VendorsCrawler crawler(Predicate> isFoundFunc,Predicate>> onFoundFunc){ - return new VendorsCrawler(isFoundFunc, onFoundFunc); + public VendorsCrawler crawler(RouteSpecification specification, Predicate>> onFoundFunc){ + return new VendorsCrawler(specification, onFoundFunc); } @Override @@ -514,8 +514,8 @@ public class VendorsGraph extends ConnectibleGraph { startBalance = getProfile().getBalance(); } - protected VendorsCrawler(Predicate> isFoundFunc, Predicate>> onFoundFunc) { - super(VendorsGraph.this, isFoundFunc, onFoundFunc); + protected VendorsCrawler(RouteSpecification specification, Predicate>> onFoundFunc) { + super(VendorsGraph.this, specification, onFoundFunc); startFuel = getShip().getTank(); startBalance = getProfile().getBalance(); } @@ -563,7 +563,8 @@ public class VendorsGraph extends ConnectibleGraph { protected boolean check(Edge e){ VendorsBuildEdge edge = (VendorsBuildEdge) e; - return fuel <= edge.getMaxFuel() && (fuel >= edge.getMinFuel() || edge.getSource().getEntry().canRefill()) && (edge.getProfit() > 0 || isFound(edge)); + return fuel <= edge.getMaxFuel() && (fuel >= edge.getMinFuel() || edge.getSource().getEntry().canRefill()) + && (edge.getProfit() > 0 || isFound(edge, this)); } protected VendorsEdge wrap(Edge e) { @@ -574,21 +575,14 @@ public class VendorsGraph extends ConnectibleGraph { @Override public double getWeight() { if (weight == null){ - VendorsEdge edge = (VendorsEdge) getEdge(); - Optional> head = getHead(); double profit = 0; double time = 0; - if (edge != null){ - profit = edge.getProfitByTonne(); - time = edge.getTime(); - } - while (head.isPresent()){ - VendorsTraversalEntry hEntry = (VendorsTraversalEntry) head.get(); - edge = (VendorsEdge) hEntry.getEdge(); + Iterator> iterator = routeIterator(); + while (iterator.hasNext()){ + VendorsEdge edge = (VendorsEdge)iterator.next(); if (edge != null){ profit += edge.getProfitByTonne(); time += edge.getTime(); } - head = hEntry.getHead(); } weight = profit > 1 ? time / profit : time; } diff --git a/core/src/main/java/ru/trader/analysis/graph/CCrawler.java b/core/src/main/java/ru/trader/analysis/graph/CCrawler.java index dc9e94f..3bb2b44 100644 --- a/core/src/main/java/ru/trader/analysis/graph/CCrawler.java +++ b/core/src/main/java/ru/trader/analysis/graph/CCrawler.java @@ -2,6 +2,7 @@ package ru.trader.analysis.graph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ru.trader.analysis.RouteSpecification; import ru.trader.core.Profile; import ru.trader.core.Ship; import ru.trader.graph.Connectable; @@ -20,8 +21,8 @@ public class CCrawler> extends Crawler { startFuel = getShip().getTank(); } - public CCrawler(ConnectibleGraph graph, Predicate> isFoundFunc, Predicate>> onFoundFunc) { - super(graph, isFoundFunc, onFoundFunc); + public CCrawler(ConnectibleGraph graph, RouteSpecification specification, Predicate>> onFoundFunc) { + super(graph, specification, onFoundFunc); startFuel = getShip().getTank(); } diff --git a/core/src/main/java/ru/trader/analysis/graph/Crawler.java b/core/src/main/java/ru/trader/analysis/graph/Crawler.java index 53cdef9..3227273 100644 --- a/core/src/main/java/ru/trader/analysis/graph/Crawler.java +++ b/core/src/main/java/ru/trader/analysis/graph/Crawler.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.trader.analysis.LimitedQueue; +import ru.trader.analysis.RouteSpecification; import java.util.*; import java.util.concurrent.ForkJoinPool; @@ -18,7 +19,7 @@ public class Crawler { protected final Graph graph; private final Predicate>> onFoundFunc; - private final Predicate> isFound; + private final RouteSpecification specification; private T target; private int maxSize; @@ -26,14 +27,14 @@ public class Crawler { this.graph = graph; maxSize = graph.getRoot().getLevel(); this.onFoundFunc = onFoundFunc; - this.isFound = this::isTarget; + this.specification = (edge, entry) -> isTarget(edge); } - public Crawler(Graph graph, Predicate> isFoundFunc, Predicate>> onFoundFunc) { + public Crawler(Graph graph, RouteSpecification specification, Predicate>> onFoundFunc) { this.graph = graph; maxSize = graph.getRoot().getLevel(); this.onFoundFunc = onFoundFunc; - this.isFound = isFoundFunc; + this.specification = specification; } protected List> getCopyList(Traversal head, Edge tail){ @@ -58,8 +59,8 @@ public class Crawler { return edge.isConnect(this.target); } - protected boolean isFound(Edge edge){ - return isFound.test(edge); + protected boolean isFound(Edge edge, Traversal head){ + return specification.specified(edge, head); } public int getMaxSize() { @@ -157,7 +158,7 @@ public class Crawler { boolean stop = false; if (deep == source.getLevel()){ for (Edge next : entry.getEdges()) { - if (isFound(next)){ + if (isFound(next, entry)){ List> res = getCopyList(entry, next); LOG.debug("Last edge found, path {}", res); found++; @@ -198,7 +199,7 @@ public class Crawler { Iterator> iterator = entry.iterator(); while (iterator.hasNext()){ Edge edge = iterator.next(); - if (isFound(edge)){ + if (isFound(edge, entry)){ List> res = getCopyList(entry, edge); LOG.debug("Last edge found, path {}", res); found++; @@ -228,7 +229,7 @@ public class Crawler { LOG.trace("Check path entry {}, weight {}", entry, entry.weight); Edge edge = entry.getEdge(); if (edge != null) { - if (isFound(edge)) { + if (isFound(edge, entry)) { List> res = entry.toEdges(); LOG.debug("Path found {}", res); found++; @@ -249,7 +250,7 @@ public class Crawler { while (iterator.hasNext()){ edge = iterator.next(); boolean canDeep = !entry.getTarget().isSingle() && deep < entry.getTarget().getLevel(); - if (canDeep || isFound(edge)){ + if (canDeep || isFound(edge, entry)){ LOG.trace("Add edge {} to queue", edge); queue.add(travers(entry, edge)); } @@ -334,15 +335,13 @@ public class Crawler { if (cmp != 0) return cmp; cmp = Integer.compare(entry.size(), o.entry.size()); if (cmp != 0) return cmp; - CostTraversal cur = entry; - CostTraversal oCur = o.entry; - while (!cur.isRoot()){ - Edge edge = cur.getEdge(); - Edge oEdge = oCur.getEdge(); + Iterator> iter1 = entry.routeIterator(); + Iterator> iter2 = o.entry.routeIterator(); + while (iter1.hasNext()){ + Edge edge = iter1.next(); + Edge oEdge = iter2.next(); cmp = oEdge.compareTo(edge); if (cmp != 0) return cmp; - cur = (CostTraversal) cur.getHead().get(); - oCur = (CostTraversal) oCur.getHead().get(); } return 0; } @@ -419,7 +418,7 @@ public class Crawler { Edge edge = curr.next(); CostTraversalEntry entry = curr.entry; LOG.trace("Check edge {}, entry {}, weight {}", edge, entry, entry.weight); - boolean isTarget = isFound(edge); + boolean isTarget = isFound(edge, entry); boolean canDeep = !entry.getTarget().isSingle() && deep < entry.getTarget().getLevel() && entry.size() < maxSize-1; if (canDeep || isTarget){ CostTraversalEntry nextEntry = travers(entry, edge); diff --git a/core/src/main/java/ru/trader/analysis/graph/Traversal.java b/core/src/main/java/ru/trader/analysis/graph/Traversal.java index 9512aca..4ce0f47 100644 --- a/core/src/main/java/ru/trader/analysis/graph/Traversal.java +++ b/core/src/main/java/ru/trader/analysis/graph/Traversal.java @@ -44,4 +44,29 @@ public interface Traversal { } return Arrays.asList(res); } + + default Iterator> routeIterator(){ + return new Iterator>() { + private Edge next = getEdge(); + private Traversal entry = Traversal.this; + + @Override + public boolean hasNext() { + return next != null; + } + + @Override + public Edge next() { + Edge res = next; + Optional> head = entry.getHead(); + if (head.isPresent()){ + entry = head.get(); + next = entry.getEdge(); + } else { + next = null; + } + return res; + } + }; + } }