diff --git a/core/src/main/java/ru/trader/analysis/Route.java b/core/src/main/java/ru/trader/analysis/Route.java index a75094f..e116558 100644 --- a/core/src/main/java/ru/trader/analysis/Route.java +++ b/core/src/main/java/ru/trader/analysis/Route.java @@ -6,7 +6,7 @@ import ru.trader.core.Vendor; import java.util.*; -public class Route { +public class Route implements Comparable { private final static Logger LOG = LoggerFactory.getLogger(Route.class); private final List entries; @@ -31,6 +31,10 @@ public class Route { return entries; } + public RouteEntry get(int index) { + return entries.get(index); + } + void setBalance(double balance){ this.balance = balance; } @@ -115,6 +119,11 @@ public class Route { LOG.trace("new stats profit={}, distance={}, lands={}, fuel={}, score={}", profit, distance, lands, fuel, score); } + @Override + public int compareTo(Route o) { + return Double.compare(score, o.score); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index e59c1ea..1acdbfe 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -2,13 +2,14 @@ package ru.trader.analysis; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.trader.analysis.graph.ConnectibleEdge; -import ru.trader.analysis.graph.Crawler; -import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.*; import ru.trader.core.Order; +import ru.trader.core.Place; +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); @@ -18,33 +19,78 @@ public class RouteSearcher { this.scorer = scorer; } - public List getRoutes(Vendor from, Vendor to, Collection vendors){ - return search(from, to, vendors); + public List> getPath(Place from, Place to, Collection places){ + List>> res = search(from, to, places, 1, null); + return res.isEmpty() ? null : res.get(0); + } + + 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); + } + + 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){ + Profile profile = scorer.getProfile(); + LOG.trace("Start search path from {} to {} ", source, target); + ConnectibleGraph graph = new ConnectibleGraph<>(profile); + LOG.trace("Build connectible graph"); + 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.setMaxSize(profile.getJumps()); + if (profile.getPathPriority() == Profile.PATH_PRIORITY.FAST){ + crawler.findFast(target, count); + } else { + crawler.findMin(target, count); + } + return paths; + } + + public List getRoutes(Collection fVendors, Collection vendors){ + return getRoutes(fVendors, vendors, vendors); + } + + 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(); + for (Vendor fromVendor : fVendors) { + count = count / toVendors.size(); + Collection routes = search(fromVendor, fromVendor, vendors, count, isFoundFunc); + res.addAll(routes); + } + return res; } public List getRoutes(Vendor from, Collection vendors){ - return search(from, null, vendors); + Predicate> isFoundFunc = e -> vendors.parallelStream().filter(e::isConnect).findFirst().isPresent(); + return search(from, from, vendors, scorer.getProfile().getRoutesCount(), isFoundFunc); } - private List search(Vendor source, Vendor target, Collection vendors){ - LOG.trace("Start search route to {} from {}", source, target); + public List getRoutes(Vendor from, Vendor to, Collection vendors){ + return getRoutes(from, to, vendors, scorer.getProfile().getRoutesCount()); + } + + public List getRoutes(Vendor source, Vendor target, Collection vendors, int count){ + return search(source, target, vendors, count, null); + } + + private List search(Vendor source, Vendor target, Collection vendors, int count, Predicate> isFoundFunc){ + 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 = vGraph.crawler(collector::add); + Crawler crawler = isFoundFunc != null ? vGraph.crawler(isFoundFunc, collector::add) : vGraph.crawler(collector::add); crawler.setMaxSize(scorer.getProfile().getLands()); - if (target == null){ - int count = vGraph.getProfile().getRoutesCount() / vendors.size(); - for (Vendor vendor : vendors) { - crawler.findMin(vendor, count); - } - } else { - crawler.findMin(target, vGraph.getProfile().getRoutesCount()); - } + crawler.findMin(target, count); return collector.get(); - } private class RouteCollector { diff --git a/core/src/main/java/ru/trader/core/MarketAnalyzer.java b/core/src/main/java/ru/trader/core/MarketAnalyzer.java index b2ea9b3..9afefba 100644 --- a/core/src/main/java/ru/trader/core/MarketAnalyzer.java +++ b/core/src/main/java/ru/trader/core/MarketAnalyzer.java @@ -2,161 +2,114 @@ package ru.trader.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ru.trader.graph.*; +import ru.trader.analysis.*; +import ru.trader.analysis.graph.ConnectibleGraph; +import ru.trader.analysis.graph.Edge; import java.util.*; +import java.util.stream.Collectors; public class MarketAnalyzer { private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class); - private final Market market; + private final FilteredMarket market; + private final Profile profile; + private final RouteSearcher searcher; private MarketAnalyzerCallBack callback; - private MarketFilter filter; - private double tank; - private double maxDistance; - private int segmentSize; - private int limit; - private int jumps; - private int cargo; + private final static Comparator orderComparator = (o1, o2) -> o2.compareTo(o1); - public MarketAnalyzer(Market market) { - this(market, new MarketAnalyzerCallBack()); + public MarketAnalyzer(FilteredMarket market, Profile profile) { + this(market, profile, new MarketAnalyzerCallBack()); } - public MarketAnalyzer(Market market, MarketAnalyzerCallBack callback) { + public MarketAnalyzer(FilteredMarket market, Profile profile, MarketAnalyzerCallBack callback) { this.market = market; this.callback = callback; - this.limit = 100; - this.segmentSize = 0; + this.profile = profile; + this.searcher = new RouteSearcher(new Scorer(market, profile)); } public void setCallback(MarketAnalyzerCallBack callback) { this.callback = callback; } - public void setFilter(MarketFilter filter) { - this.filter = filter; - } - - public void setTank(double tank) { - this.tank = tank; - } - - public void setMaxDistance(double maxDistance) { - this.maxDistance = maxDistance; - } - - public void setJumps(int jumps) { - this.jumps = jumps; - } - - public void setCargo(int cargo) { - this.cargo = cargo; - } - - public void setSegmentSize(int segmentSize) { - this.segmentSize = segmentSize; - } - - public void setPathsCount(int count) { - this.limit = count; - } - - public Collection getOffers(OFFER_TYPE offerType, Item item, MarketFilter filter){ - Collection offers = market.getOffers(offerType, item); - Collection res = new ArrayList<>(offers.size()); - callback.setMax(offers.size()); - for (Offer offer : offers) { - if (callback.isCancel()) break; - if (isFiltered(offer.getVendor()) || filter.isFiltered(offer.getVendor())){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - res.add(offer); - callback.inc(); - } - callback.onEnd(); - return res; - } - - public Collection getVendors(MarketFilter filter){ - Collection vendors = getVendors(); - Collection res = new ArrayList<>(vendors.size()); - callback.setMax(vendors.size()); - for (Vendor vendor : vendors) { - if (callback.isCancel()) break; - if (filter.isFiltered(vendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - res.add(vendor); - callback.inc(); - } - callback.onEnd(); - return res; - } - - public Collection getTop(double balance){ + public Collection getTop(int limit){ LOG.debug("Get top {}", limit); Collection places = getPlaces(); - List top = new ArrayList<>(limit); + LimitedQueue top = new LimitedQueue<>(limit, orderComparator); callback.setMax(places.size()); for (Place place : places) { if (callback.isCancel()) break; LOG.trace("Check place {}", place); - Collection orders = getOrders(place, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit()); - TopList.addAllToTop(top, orders, limit, orderComparator); + Collection orders = getOrders(place, top.isEmpty() ? 0 : top.last().getProfit()); + top.addAll(orders); callback.inc(); } callback.onEnd(); return top; } - public Collection getOrders(Vendor vendor, double balance) { - Collection places = getPlaces(); - Graph graph = new Graph(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph()); - return getOrders(graph, Collections.singleton(vendor), balance, 0); + public Collection getOrders(Place place) { + return getOrders(place, 0); } - public Collection getOrders(Place place, double balance) { - return getOrders(place, balance, 0); + public Collection getOrders(Place from, Place to) { + if (isInaccessible(from, to)){ + return Collections.emptyList(); + } + return getOrders(getVendors(from), getVendors(to), 0); } - private Collection getOrders(Place place, double balance, double lowProfit) { - Collection places = getPlaces(); - Graph graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph()); - return getOrders(graph, place.get(), balance, lowProfit); + public Collection getOrders(Place from, Vendor to) { + if (isInaccessible(from, to.getPlace())){ + return Collections.emptyList(); + } + return getOrders(getVendors(from), Collections.singleton(to), 0); } - private Collection getOrders(Graph graph, Collection sellers, double balance, double lowProfit) { + public Collection getOrders(Vendor vendor) { + return getOrders(vendor.getPlace(), Collections.singleton(vendor), 0); + } + + public Collection getOrders(Vendor from, Place to) { + if (isInaccessible(from.getPlace(), to)){ + return Collections.emptyList(); + } + return getOrders(Collections.singleton(from), to.get(), 0); + } + + public Collection getOrders(Vendor from, Vendor to) { + if (isInaccessible(from.getPlace(), to.getPlace())){ + return Collections.emptyList(); + } + return getOrders(Collections.singleton(from), Collections.singleton(to), 0); + } + + + private Collection getOrders(Place place, double lowProfit) { + return getOrders(place, getVendors(place), lowProfit); + } + + private Collection getOrders(Place place, Collection sellers, double lowProfit) { + ConnectibleGraph graph = new ConnectibleGraph<>(profile); + graph.build(place, getPlaces()); List res = new ArrayList<>(20); callback.setMax(sellers.size()); for (Vendor vendor : sellers) { if (callback.isCancel()) break; - if (isFiltered(vendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } for (Offer sell : vendor.getAllSellOffers()) { if (callback.isCancel()) break; LOG.trace("Sell offer {}", sell); if (sell.getCount() == 0) continue; - long count = Order.getMaxCount(sell, balance, cargo); + long count = Order.getMaxCount(sell, profile.getBalance(), profile.getShip().getCargo()); LOG.trace("count = {}", count); if (count == 0) continue; - Iterator buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator(); + Iterator buyers = market.getBuy(sell.getItem()).iterator(); while (buyers.hasNext()){ if (callback.isCancel()) break; Offer buy = buyers.next(); - if (isFiltered(buy.getVendor())){ - LOG.trace("Is filtered, skip"); - continue; - } if (!graph.isAccessible(buy.getVendor().getPlace())){ LOG.trace("Is inaccessible buyer, skip"); continue; @@ -177,28 +130,19 @@ public class MarketAnalyzer { return res; } - private Collection getOrders(Collection sellers, Collection buyers, double balance, double lowProfit) { + private Collection getOrders(Collection sellers, Collection buyers, double lowProfit) { List res = new ArrayList<>(); callback.setMax(sellers.size()); for (Vendor seller : sellers) { if (callback.isCancel()) break; - if (isFiltered(seller)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } for (Offer sell : seller.getAllSellOffers()) { if (callback.isCancel()) break; if (sell.getCount() == 0) continue; - long count = Order.getMaxCount(sell, balance, cargo); + long count = Order.getMaxCount(sell, profile.getBalance(), profile.getShip().getCargo()); LOG.trace("Sell offer {}, count = {}", sell, count); if (count == 0) continue; for (Vendor buyer : buyers) { if (callback.isCancel()) break; - if (isFiltered(buyer)){ - LOG.trace("Is filtered, skip"); - continue; - } Offer buy = buyer.getBuy(sell.getItem()); if (buy != null){ Order order = new Order(sell, buy, count); @@ -217,197 +161,62 @@ public class MarketAnalyzer { return res; } - public Collection getOrders(Vendor from, Vendor to, double balance) { - Graph graph = new Graph(from.getPlace(), getPlaces(), tank, maxDistance, true, jumps, Path::new); - if (!graph.isAccessible(to.getPlace())){ - LOG.trace("Is inaccessible buyer"); - return Collections.emptyList(); - } - return getOrders(Collections.singleton(from), Collections.singleton(to), balance, 0); + public Collection>> getPaths(Place from, Place to){ + return searcher.getPaths(from, to, getPlaces()); } - public Collection getOrders(Place from, Place to, double balance) { - Graph graph = new Graph(from, getPlaces(), tank, maxDistance, true, jumps, Path::new); - if (!graph.isAccessible(to)){ - LOG.trace("Is inaccessible buyer"); - return Collections.emptyList(); - } - return getOrders(from.get(), to.get(), balance, 0); + public List> getPath(Place from, Place to){ + return searcher.getPath(from, to, getPlaces()); } - - public Collection getOrders(Vendor from, Place to, double balance) { - Graph graph = new Graph(from.getPlace(), getPlaces(), tank, maxDistance, true, jumps, Path::new); - if (!graph.isAccessible(to)){ - LOG.trace("Is inaccessible buyer"); - return Collections.emptyList(); - } - return getOrders(Collections.singleton(from), to.get(), balance, 0); - } - - public Collection getOrders(Place from, Vendor to, double balance) { - Graph graph = new Graph(from, getPlaces(), tank, maxDistance, true, jumps, Path::new); - if (!graph.isAccessible(to.getPlace())){ - LOG.trace("Is inaccessible buyer"); - return Collections.emptyList(); - } - return getOrders(from.get(), Collections.singleton(to), balance, 0); - } - - - public Collection> getPaths(Place from, Place to){ - Graph graph = new Graph(from, getPlaces(), tank, maxDistance, true, jumps, Path::new); - return graph.getPathsTo(to); - } - - public Path getPath(Place from, Place to){ - Graph graph = new Graph(from, getPlaces(), tank, maxDistance, true, jumps, Path::new); - return graph.getFastPathTo(to); - } - - public PathRoute getPath(Vendor from, Vendor to){ - RouteGraph graph = new RouteGraph(from, getVendors(true), tank, maxDistance, true, jumps); - return (PathRoute)graph.getFastPathTo(to); - } - - public Collection getPaths(Vendor from, double balance){ - callback.setMax(1); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - Collection vendors = getVendors(true); - Collection res = searcher.getPaths(from, vendors, jumps, balance, cargo, limit); - callback.inc(); - callback.onEndSearch(); - return res; - } - - public Collection getPaths(Place from, double balance){ - List top = new ArrayList<>(limit); - Collection vendors = getVendors(true); + public Collection getTopRoutes(int limit){ + LOG.debug("Get top {}", limit); + LimitedQueue top = new LimitedQueue<>(limit); + Collection vendors = getVendors(); callback.setMax(vendors.size()); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - for (Vendor vendor : from.get()) { - if (callback.isCancel()) break; - if (isFiltered(vendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - Collection paths = searcher.getPaths(vendor, vendors, jumps, balance, cargo, limit); - TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator); - callback.inc(); - } - callback.onEndSearch(); - return top; - } - - public Collection getPaths(Vendor from, Vendor to, double balance){ - callback.setMax(1); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - Collection res = searcher.getPaths(from, to, getVendors(true), jumps, balance, cargo, limit); - callback.inc(); - callback.onEndSearch(); - return res; - } - - public Collection getPaths(Place from, Place to, double balance){ - List top = new ArrayList<>(limit); - Collection vendors = getVendors(true); - Collection fVendors = from.get(); - Collection toVendors = to.get(); - int count = (int) Math.ceil(limit / fVendors.size()); - callback.setMax(fVendors.size() * toVendors.size()); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - for (Vendor fromVendor : fVendors) { - if (callback.isCancel()) break; - if (isFiltered(fromVendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - for (Vendor toVendor : toVendors) { - if (callback.isCancel()) break; - if (isFiltered(toVendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - Collection paths = searcher.getPaths(fromVendor, toVendor, vendors, jumps, balance, cargo, count); - TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator); - callback.inc(); - } - } - callback.onEndSearch(); - return top; - } - - public Collection getPaths(Vendor from, Place to, double balance){ - List top = new ArrayList<>(limit); - Collection vendors = getVendors(true); - Collection toVendors = to.get(); - int count = (int) Math.ceil(limit / toVendors.size()); - callback.setMax(toVendors.size()); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - for (Vendor toVendor : toVendors) { - if (callback.isCancel()) break; - if (isFiltered(toVendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - Collection paths = searcher.getPaths(from, toVendor, vendors, jumps, balance, cargo, count); - TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator); - callback.inc(); - } - callback.onEndSearch(); - return top; - } - - public Collection getPaths(Place from, Vendor to, double balance){ - List top = new ArrayList<>(limit); - Collection vendors = getVendors(true); - Collection fVendors = from.get(); - int count = (int) Math.ceil(limit / fVendors.size()); - callback.setMax(fVendors.size()); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); - for (Vendor fromVendor : fVendors) { - if (callback.isCancel()) break; - if (isFiltered(fromVendor)){ - LOG.trace("Is filtered, skip"); - callback.inc(); - continue; - } - Collection paths = searcher.getPaths(fromVendor, to, vendors, jumps, balance, cargo, count); - TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator); - callback.inc(); - } - callback.onEndSearch(); - return top; - } - - public Collection getTopPaths(double balance){ - List top = new ArrayList<>(limit); - Collection vendors = getVendors(true); - callback.setMax(vendors.size()); - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); for (Vendor vendor : vendors) { if (callback.isCancel()) break; - Collection paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3); - TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator); + Collection paths = searcher.getRoutes(vendor, vendor, vendors, 3); + top.addAll(paths); callback.inc(); } callback.onEndSearch(); return top; } - public PathRoute getPath(Collection vendors, double balance) { - PathRoute res = null; + public Collection getRoutes(Place from){ + return searcher.getRoutes(getVendors(from), getVendors()); + } + + public Collection getRoutes(Place from, Place to){ + return searcher.getRoutes(getVendors(from), getVendors(to), getVendors()); + } + + public Collection getRoutes(Place from, Vendor to){ + return searcher.getRoutes(getVendors(from), Collections.singleton(to), getVendors()); + } + + public Collection getRoutes(Vendor from){ + return searcher.getRoutes(from, getVendors()); + } + + public Collection getRoutes(Vendor from, Place to){ + return searcher.getRoutes(Collections.singleton(from), getVendors(to), getVendors()); + } + + public Collection getRoutes(Vendor from, Vendor to){ + return searcher.getRoutes(from, to, getVendors()); + } + + + public Route getRoute(Collection vendors) { + Route res = null; callback.setMax(vendors.size()); for (Vendor from : vendors) { - RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch()); //TODO: implement search with constant length - Collection paths = searcher.getPaths(from, vendors, jumps, balance, cargo, limit); - Optional route = paths.stream().filter(p -> p.contains(vendors)).findFirst(); - if (route.isPresent() && (res == null || RouteGraph.byProfitComparator.compare(res, route.get()) > 0)){ + Collection paths = searcher.getRoutes(from, vendors); + Optional route = paths.stream().filter(p -> p.contains(vendors)).findFirst(); + if (route.isPresent() && (res == null || res.compareTo(route.get()) > 0)){ res = route.get(); } callback.inc(); @@ -416,32 +225,25 @@ public class MarketAnalyzer { return res; } - private Collection getPlaces(){ - if (filter != null){ - return filter.filtered(market.get()); - } else { - return market.get(); + private boolean isInaccessible(Place from, Place to){ + ConnectibleGraph graph = new ConnectibleGraph<>(profile); + graph.build(from, getPlaces()); + if (!graph.isAccessible(to)){ + LOG.trace("Is inaccessible buyer"); + return true; } + return false; } - private Collection getVendors(){ - return getVendors(false); + private List getPlaces(){ + return market.get().collect(Collectors.toList()); } - private Collection getVendors(boolean includeTransit){ - if (filter != null){ - Collection vendors = new PlacesWrapper(getPlaces(), includeTransit); - return filter.filteredVendors(vendors); - } else { - return market.getVendors(includeTransit); - } + private List getVendors(){ + return market.getMarkets(true).collect(Collectors.toList()); } - public MarketFilter getFilter() { - return filter; - } - - private boolean isFiltered(Vendor vendor){ - return filter != null && (filter.isFiltered(vendor.getPlace()) || filter.isFiltered(vendor)); + private List getVendors(Place place){ + return market.getVendors(place).collect(Collectors.toList()); } } diff --git a/core/src/main/java/ru/trader/core/MarketFilter.java b/core/src/main/java/ru/trader/core/MarketFilter.java index 378d670..70a1e80 100644 --- a/core/src/main/java/ru/trader/core/MarketFilter.java +++ b/core/src/main/java/ru/trader/core/MarketFilter.java @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; import java.util.Properties; -import java.util.stream.Collectors; public class MarketFilter { private final static Logger LOG = LoggerFactory.getLogger(MarketFilter.class); @@ -97,15 +96,6 @@ public class MarketFilter { return false; } - public Collection filtered(Collection places){ - return places.parallelStream().filter(p -> !isFiltered(p)).collect(Collectors.toList()); - } - - public Collection filteredVendors(Collection vendors){ - return vendors.parallelStream().filter(v -> !isFiltered(v)).collect(Collectors.toList()); - } - - public static MarketFilter buildFilter(Properties values, Market market){ MarketFilter filter = new MarketFilter(); String v = values.getProperty("filter.center", null); diff --git a/core/src/main/java/ru/trader/core/Profile.java b/core/src/main/java/ru/trader/core/Profile.java index 8cbd1db..8460b75 100644 --- a/core/src/main/java/ru/trader/core/Profile.java +++ b/core/src/main/java/ru/trader/core/Profile.java @@ -22,6 +22,7 @@ public class Profile { refill = true; jumps = 6; lands = 4; + routesCount = 30; scoreOrdersCount = 5; distanceMult = 0.8; landMult = 0.95; diff --git a/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java b/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java index 79d16f7..550c0f9 100644 --- a/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java +++ b/core/src/test/java/ru/trader/core/MarketAnalyzerTest.java @@ -7,29 +7,32 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ru.trader.TestUtil; -import ru.trader.graph.Path; +import ru.trader.analysis.FilteredMarket; +import ru.trader.analysis.graph.Edge; +import ru.trader.analysis.graph.PPath; import ru.trader.store.simple.*; import java.util.Collection; +import java.util.List; public class MarketAnalyzerTest extends Assert { private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzerTest.class); - private static Market market = new SimpleMarket(); - private static Place v1; - private static Place v2; - private static Place v3; - private static Place v4; - private static Place v5; - private static Place v6; - private static Place v7; - private static Place v8; - private static Place v9; - private static Place v10; - private static Place v11; - private static Item ITEM1 = new SimpleItem("ITEM1"); - private static Item ITEM2 = new SimpleItem("ITEM2"); - private static Item ITEM3 = new SimpleItem("ITEM3"); + private FilteredMarket market; + private Place v1; + private Place v2; + private Place v3; + private Place v4; + private Place v5; + private Place v6; + private Place v7; + private Place v8; + private Place v9; + private Place v10; + private Place v11; + private Item ITEM1 = new SimpleItem("ITEM1"); + private Item ITEM2 = new SimpleItem("ITEM2"); + private Item ITEM3 = new SimpleItem("ITEM3"); private void add(Place place, Offer offer){ if (place.isEmpty()){ @@ -41,6 +44,8 @@ public class MarketAnalyzerTest extends Assert { @Before public void setUp() throws Exception { + Market market = new SimpleMarket(); + v1 = new SimplePlace("v1_x0y0z0",0,0,0); v2 = new SimplePlace("v2_x1y0z0",1,0,0); v3 = new SimplePlace("v3_x0y1z0",0,1,0); @@ -80,29 +85,34 @@ public class MarketAnalyzerTest extends Assert { add(v10, new SimpleOffer(OFFER_TYPE.BUY, ITEM3, 140, 1)); add(v11, new SimpleOffer(OFFER_TYPE.BUY, ITEM3, 500, 1)); + MarketFilter filter = new MarketFilter(); + this.market = new FilteredMarket(market, filter); } - @Test public void testPaths() throws Exception { LOG.info("Start paths test"); - MarketAnalyzer analyzer = new MarketAnalyzer(market); - analyzer.setJumps(5);analyzer.setMaxDistance(1);analyzer.setTank(1); + // maxDist - 1, fulltank - 1 + Ship ship = new Ship(); + ship.setMass(340);ship.setTank(0.6); + Profile profile = new Profile(ship); + profile.setJumps(5); + MarketAnalyzer analyzer = new MarketAnalyzer(market, profile); - Collection> paths = analyzer.getPaths(v1, v2); - TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v2)); + Collection>> paths = analyzer.getPaths(v1, v2); + TestUtil.assertPaths(paths, PPath.of(v1, v2)); paths = analyzer.getPaths(v1, v3); - TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v3)); + TestUtil.assertPaths(paths, PPath.of(v1, v3)); paths = analyzer.getPaths(v1, v4); - TestUtil.assertCollectionEquals(paths, Path.toPath(v1, v4)); + TestUtil.assertPaths(paths, PPath.of(v1, v4)); paths = analyzer.getPaths(v1, v5); assertTrue(paths.isEmpty()); paths = analyzer.getPaths(v2, v5); - TestUtil.assertCollectionEquals(paths, Path.toPath(v2, v5)); + TestUtil.assertPaths(paths, PPath.of(v2, v5)); paths = analyzer.getPaths(v4, v3); assertTrue(paths.isEmpty()); @@ -111,80 +121,95 @@ public class MarketAnalyzerTest extends Assert { @Test public void testPathsWithStock() throws Exception { LOG.info("Start paths with stock test"); - MarketAnalyzer analyzer = new MarketAnalyzer(market); - analyzer.setJumps(5);analyzer.setMaxDistance(1);analyzer.setTank(2); + // jumpRange - 1, fulltank - 2 + Ship ship = new Ship(); + ship.setMass(340);ship.setTank(1.17); + Profile profile = new Profile(ship); + profile.setJumps(5); + MarketAnalyzer analyzer = new MarketAnalyzer(market, profile); - Collection> paths = analyzer.getPaths(v1, v2); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v2)); + Collection>> paths = analyzer.getPaths(v1, v2); + TestUtil.assertPaths(paths, PPath.of(v1, v2)); paths = analyzer.getPaths(v1, v3); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v3)); + TestUtil.assertPaths(paths, PPath.of(v1, v3)); paths = analyzer.getPaths(v1, v4); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v4)); + TestUtil.assertPaths(paths, PPath.of(v1, v4)); paths = analyzer.getPaths(v1, v5); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v2, v5), Path.toPath(v1, v3, v5)); + TestUtil.assertPaths(paths, PPath.of(v1, v2, v5), PPath.of(v1, v3, v5)); paths = analyzer.getPaths(v2, v5); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v2, v5)); + TestUtil.assertPaths(paths, PPath.of(v2, v5)); paths = analyzer.getPaths(v4, v3); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v4, v1, v3)); + TestUtil.assertPaths(paths, PPath.of(v4, v1, v3)); } @Test public void testPathsWithStockAndRefill() throws Exception { LOG.info("Start paths with stock and refill test"); - MarketAnalyzer analyzer = new MarketAnalyzer(market); - analyzer.setJumps(2);analyzer.setMaxDistance(10);analyzer.setTank(15); + // jumpRange - 10, fulltank - 15 + Ship ship = new Ship(); + ship.setMass(30);ship.setTank(0.7); + Profile profile = new Profile(ship); + profile.setJumps(2); + MarketAnalyzer analyzer = new MarketAnalyzer(market, profile); - Collection> paths = analyzer.getPaths(v10, v6); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6), Path.toPath(v10, v11, v6), - Path.toPath(v10, v8, v6)); + Collection>> paths = analyzer.getPaths(v10, v6); + TestUtil.assertPaths(paths, PPath.of(v10, v6), PPath.of(v10, v11, v6), + PPath.of(v10, v8, v6)); paths = analyzer.getPaths(v1, v3); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v1, v3), Path.toPath(v1, v2, v3), - Path.toPath(v1, v4, v3), Path.toPath(v1, v5, v3) + TestUtil.assertPaths(paths, PPath.of(v1, v3), PPath.of(v1, v2, v3), + PPath.of(v1, v4, v3), PPath.of(v1, v5, v3) ); } @Test public void testPathsWithStockAndRefill2() throws Exception { LOG.info("Start paths with stock and refill test 2"); - MarketAnalyzer analyzer = new MarketAnalyzer(market); - analyzer.setJumps(3);analyzer.setMaxDistance(10);analyzer.setTank(15); + // jumpRange - 10, fulltank - 15 + Ship ship = new Ship(); + ship.setMass(30);ship.setTank(0.7); + Profile profile = new Profile(ship); + profile.setJumps(3); + MarketAnalyzer analyzer = new MarketAnalyzer(market, profile); - Collection> paths = analyzer.getPaths(v10, v6); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6), Path.toPath(v10, v11, v6), Path.toPath(v10, v11, v10, v6), - Path.toPath(v10, v8, v6), Path.toPath(v10, v8, v10, v6), Path.toPath(v10, v8, v11, v6)); + Collection>> paths = analyzer.getPaths(v10, v6); + TestUtil.assertPaths(paths, PPath.of(v10, v6), PPath.of(v10, v8, v6), PPath.of(v10, v11, v6), + PPath.of(v10, v8, v11, v6), PPath.of(v10, v8, v10, v6), PPath.of(v10, v11, v10, v6), + PPath.of(v10, v6, v7, v6), PPath.of(v10, v6, v8, v6), PPath.of(v10, v6, v11, v6), + PPath.of(v10, v6, v10, v6)); paths = analyzer.getPaths(v10, v7); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v6, v7), Path.toPath(v10, v11, v6, v7), - Path.toPath(v10, v8, v6, v7) + TestUtil.assertPaths(paths, PPath.of(v10, v6, v7), PPath.of(v10, v11, v6, v7), + PPath.of(v10, v8, v6, v7) ); paths = analyzer.getPaths(v10, v8); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v8), Path.toPath(v10, v11, v8), - Path.toPath(v10, v11, v6, v8), Path.toPath(v10, v6, v8), Path.toPath(v10, v6, v11, v8), - Path.toPath(v10, v11, v10, v8), Path.toPath(v10, v6, v10, v8)); + TestUtil.assertPaths(paths, PPath.of(v10, v8), PPath.of(v10, v11, v8), PPath.of(v10, v6, v8), + PPath.of(v10, v8, v11, v8), PPath.of(v10, v8, v10, v8), PPath.of(v10, v8, v6, v8), + PPath.of(v10, v11, v10, v8), PPath.of(v10, v11, v6, v8), PPath.of(v10, v6, v11, v8), + PPath.of(v10, v6, v10, v8)); paths = analyzer.getPaths(v10, v9); assertTrue(paths.isEmpty()); paths = analyzer.getPaths(v10, v10); - TestUtil.assertCollectionContainAll(paths, Path.toPath(v10, v11, v10), Path.toPath(v10, v6, v10), - Path.toPath(v10, v11, v6, v10), Path.toPath(v10, v6, v11, v10), - Path.toPath(v10, v8, v10), Path.toPath(v10, v8, v11, v10), - Path.toPath(v10, v8, v6, v10), Path.toPath(v10, v8, v6, v10)); + TestUtil.assertPaths(paths, PPath.of(v10, v11, v10), PPath.of(v10, v6, v10), + PPath.of(v10, v11, v6, v10), PPath.of(v10, v6, v11, v10), + PPath.of(v10, v8, v10), PPath.of(v10, v8, v11, v10), + PPath.of(v10, v8, v6, v10), PPath.of(v10, v8, v6, v10)); } @After public void tearDown() throws Exception { - market = new SimpleMarket(); + market = null; } } diff --git a/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java b/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java index 12e1711..f0219ec 100644 --- a/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java +++ b/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java @@ -4,7 +4,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import ru.trader.TestUtil; -import ru.trader.graph.PathRoute; +import ru.trader.analysis.*; import ru.trader.store.simple.Store; import java.io.InputStream; import java.util.Collection; @@ -16,25 +16,40 @@ public class MarketAnalyzerTest2 extends Assert { public void testRoutes() throws Exception { InputStream is = getClass().getResourceAsStream("/world.xml"); Market market = Store.loadFromFile(is); - MarketAnalyzer analyzer = new MarketAnalyzer(market); + MarketFilter filter = new MarketFilter(); + FilteredMarket fWorld = new FilteredMarket(market, filter); // Balance: 6000000, cargo: 440, tank: 40, distance: 13.4, jumps: 6 // Ithaca (Palladium to LHS 3262) -> Morgor -> LHS 3006 -> LHS 3262 (Consumer Technology to Ithaca) -> LHS 3006 -> Morgor -> Ithaca // Profit: 981200, avg: 490600, distance: 67.5, lands: 2 - Vendor ithaca = market.get().stream().filter((v)->v.getName().equals("Ithaca")).findFirst().get().get().iterator().next(); - Vendor morgor = market.get().stream().filter((v)->v.getName().equals("Morgor")).findFirst().get().get().iterator().next(); - Vendor lhs3006 = market.get().stream().filter((v)->v.getName().equals("LHS 3006")).findFirst().get().get().iterator().next(); - Vendor lhs3262 = market.get().stream().filter((v)->v.getName().equals("LHS 3262")).findFirst().get().get().iterator().next(); - analyzer.setCargo(440);analyzer.setTank(40);analyzer.setMaxDistance(13.4);analyzer.setJumps(6); - Collection paths = analyzer.getPaths(ithaca, ithaca, 6000000); - PathRoute expect = PathRoute.toPathRoute(ithaca, morgor, lhs3006, lhs3262, lhs3006, morgor, ithaca); - Optional path = paths.stream().filter((p)->p.equals(expect)).findFirst(); + 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); + MarketAnalyzer analyzer = new MarketAnalyzer(fWorld, profile); + Vendor ithaca = market.get("Ithaca").get().iterator().next(); + Vendor morgor = market.get("Morgor").asTransit(); + Vendor lhs3006 = market.get("LHS 3006").asTransit(); + Vendor lhs3262 = market.get("LHS 3262").get().iterator().next(); + Collection paths = analyzer.getRoutes(ithaca, ithaca); + Route expect = new Route(new RouteEntry(ithaca, false, 3.3789702637348586d, 0)); + expect.add(new RouteEntry(morgor, false, 4.137765020523591d, 0)); + expect.add(new RouteEntry(lhs3006, false, 4.0674474942172765d, 0)); + expect.add(new RouteEntry(lhs3262, true, 4.149937831634785d, 0)); + expect.add(new RouteEntry(lhs3006, false, 4.1292528548103d, 0)); + expect.add(new RouteEntry(morgor, false, 3.3050364899848566, 0)); + expect.add(new RouteEntry(ithaca, false, 0, 0)); + RouteFiller filler = new RouteFiller(new Scorer(fWorld, profile)); + filler.fill(expect); + + Optional path = paths.stream().findFirst(); assertTrue(path.isPresent()); - PathRoute actual = path.get().getRoot(); - TestUtil.assertCollectionContain(paths, expect); + Route actual = path.get(); + assertEquals(expect, actual); assertEquals(981200, actual.getProfit(), 0.00001); assertEquals(72.42, actual.getDistance(), 0.01); - assertEquals(2, actual.getLandsCount()); - assertEquals(490600, actual.getAvgProfit() , 0.00001); + assertEquals(2, actual.getLands()); } //test best avg profit @@ -42,27 +57,51 @@ public class MarketAnalyzerTest2 extends Assert { public void testRoutes2() throws Exception { InputStream is = getClass().getResourceAsStream("/test2.xml"); Market market = Store.loadFromFile(is); - MarketAnalyzer analyzer = new MarketAnalyzer(market); + MarketFilter filter = new MarketFilter(); + FilteredMarket fWorld = new FilteredMarket(market, filter); // Balance: 6000000, cargo: 104 tank: 150, distance: 12.6, jumps: 4 - // LHS 21 (Resonatic Separator to Sui Xing) -> Bonde -> Sui Xing (Palladium to LHS 21) -> Bonde -> LHS 21 - // Profit: 981200, avg: 490600, distance: 67.5, lands: 2 - Place lhs21 = market.get().stream().filter((v)->v.getName().equals("LHS 21")).findFirst().get(); - Place suiXing = market.get().stream().filter((v)->v.getName().equals("Sui Xing")).findFirst().get(); - analyzer.setCargo(104);analyzer.setTank(150);analyzer.setMaxDistance(12.6);analyzer.setJumps(4);analyzer.setPathsCount(100); - Collection paths = analyzer.getPaths(lhs21, lhs21, 6000000); - Optional path = paths.stream().findFirst(); + // LHS 21 -> Bonde -> LHS 21 + // Profit: 114816, distance: 8.16, lands: 2 + Ship ship = new Ship(); + ship.setCargo(104); ship.setTank(150); + ship.setEngine(5, 'A'); ship.setMass(865); + Profile profile = new Profile(ship); + profile.setBalance(6000000); profile.setJumps(4); + profile.setRoutesCount(100); + MarketAnalyzer analyzer = new MarketAnalyzer(fWorld, profile); + Place lhs21 = market.get("LHS 21"); + Place bonde = market.get("Bonde"); + Place suiXing = market.get("Sui Xing"); + Collection paths = analyzer.getRoutes(lhs21, lhs21); + Optional path = paths.stream().findFirst(); assertTrue(path.isPresent()); - PathRoute actual = path.get().getRoot(); + Route actual = path.get(); + assertEquals(114816, actual.getProfit(), 0.00001); + assertEquals(8.16, actual.getDistance(), 0.01); + assertEquals(2, actual.getLands()); + + Place aPlace = actual.get(0).getVendor().getPlace(); + assertEquals(lhs21, aPlace); + aPlace = actual.get(1).getVendor().getPlace(); + assertEquals(bonde, aPlace); + + // If distance to station has small mult + // LHS 21 (Resonatic Separator to Sui Xing) -> Bonde -> Sui Xing (Palladium to LHS 21) -> Bonde -> LHS 21 + // Profit: 199056, distance: 28.72, lands: 2 + + profile.setDistanceMult(0.1); + paths = analyzer.getRoutes(lhs21, lhs21); + path = paths.stream().findFirst(); + assertTrue(path.isPresent()); + actual = path.get(); assertEquals(199056, actual.getProfit(), 0.00001); assertEquals(28.72, actual.getDistance(), 0.01); - assertEquals(2, actual.getLandsCount()); - assertEquals(99528, actual.getAvgProfit() , 0.00001); + assertEquals(2, actual.getLands()); - Place aPlace = actual.get().getPlace(); + aPlace = actual.get(0).getVendor().getPlace(); assertEquals(lhs21, aPlace); - actual = actual.getNext().getNext(); - aPlace = actual.get().getPlace(); + aPlace = actual.get(2).getVendor().getPlace(); assertEquals(suiXing, aPlace); }