From f04c05084322e92ffe80779b149a2e05262b575d Mon Sep 17 00:00:00 2001 From: iMoHax Date: Mon, 10 Aug 2015 16:18:45 +0300 Subject: [PATCH] add time and profit to route entry --- .../main/java/ru/trader/analysis/Route.java | 27 +++++++++--- .../java/ru/trader/analysis/RouteEntry.java | 37 ++++++++++++---- .../java/ru/trader/analysis/RouteFiller.java | 11 ++++- .../ru/trader/analysis/RouteSearcher.java | 44 +++++++++++++++---- .../main/java/ru/trader/analysis/Scorer.java | 39 +++++++++++----- .../java/ru/trader/analysis/VendorsGraph.java | 15 ++++--- .../java/ru/trader/core/MarketAnalyzer.java | 4 +- .../ru/trader/analysis/RouteSearcherTest.java | 4 +- .../ru/trader/core/MarketAnalyzerTest2.java | 4 +- 9 files changed, 135 insertions(+), 50 deletions(-) diff --git a/core/src/main/java/ru/trader/analysis/Route.java b/core/src/main/java/ru/trader/analysis/Route.java index 3c8eba3..bedbfee 100644 --- a/core/src/main/java/ru/trader/analysis/Route.java +++ b/core/src/main/java/ru/trader/analysis/Route.java @@ -13,8 +13,8 @@ public class Route implements Comparable { private double profit = 0; private double balance = 0; private double distance = 0; - private double score = 0; private double fuel = 0; + private double time = 0; private int lands = 0; private int refills = 0; @@ -64,6 +64,18 @@ public class Route implements Comparable { return refills; } + public double getTime() { + return time; + } + + public double getFuel() { + return fuel; + } + + public double getScore() { + return profit / time; + } + public void add(RouteEntry entry){ LOG.trace("Add entry {} to route {}", entry, this); entries.add(entry); @@ -120,7 +132,7 @@ public class Route implements Comparable { } void updateStats(){ - LOG.trace("Update stats, old: profit={}, distance={}, lands={}, fuel={}, refills={}, score={}", profit, distance, lands, fuel, refills, score); + LOG.trace("Update stats, old: profit={}, distance={}, lands={}, fuel={}, refills={}, time={}", profit, distance, lands, fuel, refills, time); profit = 0; distance = 0; lands = 0; fuel = 0; refills = 0; if (entries.isEmpty()) return; RouteEntry entry = entries.get(0); @@ -128,7 +140,7 @@ public class Route implements Comparable { RouteEntry next = entries.get(i); distance += entry.getVendor().getDistance(next.getVendor()); profit += entry.getProfit(); - score += entry.getScore(); + time += entry.getFullTime(); fuel += entry.getFuel(); if (entry.isLand()){ lands++; @@ -138,12 +150,12 @@ public class Route implements Comparable { } entry = next; } - LOG.trace("new stats profit={}, distance={}, lands={}, fuel={}, score={}", profit, distance, lands, fuel, score); + LOG.trace("new stats profit={}, distance={}, lands={}, fuel={}, time={}", profit, distance, lands, fuel, time); } @Override public int compareTo(Route o) { - return Double.compare(score, o.score); + return Double.compare(getScore(), o.getScore()); } @Override @@ -151,7 +163,7 @@ public class Route implements Comparable { if (this == o) return true; if (!(o instanceof Route)) return false; Route route = (Route) o; - return Double.compare(route.profit, profit) == 0 && entries.equals(route.entries); + return (Double.compare(route.profit, profit) == 0 || Math.abs(profit - route.profit) < 0.1)&& entries.equals(route.entries); } @Override @@ -166,7 +178,8 @@ public class Route implements Comparable { ", profit=" + profit + ", balance=" + balance + ", distance=" + distance + - ", score=" + score + + ", time=" + time + + ", score=" + getScore() + ", fuel=" + fuel + ", lands=" + lands + '}'; diff --git a/core/src/main/java/ru/trader/analysis/RouteEntry.java b/core/src/main/java/ru/trader/analysis/RouteEntry.java index 3d72a5c..38eb994 100644 --- a/core/src/main/java/ru/trader/analysis/RouteEntry.java +++ b/core/src/main/java/ru/trader/analysis/RouteEntry.java @@ -13,14 +13,16 @@ public class RouteEntry { private final List orders; private boolean land; private double refill; - private double score; + private double profit; + private double time; + private double fulltime; - public RouteEntry(Vendor vendor, double refill, double fuel, double score) { + public RouteEntry(Vendor vendor, double refill, double fuel, double profit) { orders = new ArrayList<>(); this.vendor = vendor; this.refill = refill; this.fuel = fuel; - this.score = score; + this.profit = profit; } public Vendor getVendor() { @@ -47,12 +49,28 @@ public class RouteEntry { return fuel; } - public double getScore() { - return score; + public double getProfit() { + return profit; } - void setScore(double score) { - this.score = score; + void setProfit(double profit) { + this.profit = profit; + } + + public double getTime() { + return time; + } + + void setTime(double time) { + this.time = time; + } + + public double getFullTime() { + return fulltime; + } + + void setFullTime(double fullTime) { + this.fulltime = fullTime; } void add(Order order){ @@ -71,7 +89,7 @@ public class RouteEntry { orders.clear(); } - public double getProfit(){ + public double getProfitByOrders(){ return orders.stream().mapToDouble(Order::getProfit).sum(); } @@ -97,6 +115,7 @@ public class RouteEntry { if (refill != that.refill) return false; if (Double.compare(that.fuel, fuel) != 0) return false; if (orders.size() != that.orders.size()) return false; + if (time != that.time) return false; return vendor.equals(that.vendor); } @@ -109,7 +128,7 @@ public class RouteEntry { result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (land ? 1 : 0); result = 31 * result + (isRefill() ? 1 : 0); - temp = Double.doubleToLongBits(score); + temp = Double.doubleToLongBits(profit); result = 31 * result + (int) (temp ^ (temp >>> 32)); return result; } diff --git a/core/src/main/java/ru/trader/analysis/RouteFiller.java b/core/src/main/java/ru/trader/analysis/RouteFiller.java index 6b98ae4..cfa0172 100644 --- a/core/src/main/java/ru/trader/analysis/RouteFiller.java +++ b/core/src/main/java/ru/trader/analysis/RouteFiller.java @@ -176,8 +176,15 @@ public class RouteFiller { if (best != TRANSIT) entry.addAll(best.bestOrders); } - int jumps = i==0 || entries.get(i-1).getVendor().getPlace().equals(entry.getVendor().getPlace())? 0 : 1; - entry.setScore(i==0 ? 0 : scorer.getScore(entry, jumps)); + RouteEntry prev = i != 0 ? entries.get(i-1) : null; + if (prev != null){ + prev.setProfit(scorer.getProfit(prev.getProfitByOrders(), prev.getFuel())); + prev.setTime(scorer.getTime(entry, prev)); + prev.setFullTime(prev.getTime()); + } else { + entry.setProfit(0); + entry.setTime(0); + } } } diff --git a/core/src/main/java/ru/trader/analysis/RouteSearcher.java b/core/src/main/java/ru/trader/analysis/RouteSearcher.java index cbe2114..36493d8 100644 --- a/core/src/main/java/ru/trader/analysis/RouteSearcher.java +++ b/core/src/main/java/ru/trader/analysis/RouteSearcher.java @@ -24,6 +24,10 @@ public class RouteSearcher { this.callback = callback; } + public Scorer getScorer() { + return scorer; + } + public List> getPath(Place from, Place to, Collection places){ List>> res = search(from, to, places, 1, null); return res.isEmpty() ? null : res.get(0); @@ -103,8 +107,7 @@ public class RouteSearcher { private List routes = new ArrayList<>(); public void add(List> edges){ - Route route = toRoute(edges); - route.setBalance(scorer.getProfile().getBalance()); + Route route = toRoute(edges, scorer); routes.add(route); } @@ -113,10 +116,11 @@ public class RouteSearcher { } } - public static Route toRoute(List> edges){ + public static Route toRoute(List> edges, final Scorer scorer){ List entries = new ArrayList<>(edges.size()+1); Vendor buyer = null; VendorsGraph.VendorsEdge vEdge = null; + RouteEntry prev = null; for (Edge e : edges) { vEdge = (VendorsGraph.VendorsEdge) e; List> transitEdges = vEdge.getPath().getEntries(); @@ -129,45 +133,67 @@ public class RouteSearcher { buyer = null; } if (k == 0) { - entry.setScore(vEdge.getWeight()); + entry.setProfit(scorer.getProfit(vEdge.getProfit(), vEdge.getFuelCost())); + entry.setFullTime(vEdge.getTime()); List orders = vEdge.getOrders(); if (!orders.isEmpty()) { buyer = orders.get(0).getBuyer(); entry.addAll(orders); } } + if (prev != null){ + prev.setTime(scorer.getTime(entry, prev)); + } entries.add(entry); + prev = entry; } } if (vEdge != null) { RouteEntry entry = new RouteEntry(vEdge.getTarget().getEntry(), 0, 0, 0); if (buyer != null) entry.setLand(true); + if (prev != null){ + prev.setTime(scorer.getTime(entry, prev)); + } entries.add(entry); } - return new Route(entries); + Route route = new Route(entries); + route.setBalance(scorer.getProfile().getBalance()); + return route; } - public static Route toRoute(Order order, List> edges){ - Route route = toRoute(order.getSeller(), order.getBuyer(), edges); + public static Route toRoute(Order order, List> edges, final Scorer scorer){ + Route route = toRoute(order.getSeller(), order.getBuyer(), edges, scorer); if (route.isEmpty()) return route; route.get(0).add(order); route.updateStats(); return route; } - public static Route toRoute(Vendor from, Vendor to, List> edges){ + public static Route toRoute(Vendor from, Vendor to, List> edges, final Scorer scorer){ List entries = new ArrayList<>(edges.size()+1); + RouteEntry prev = null; for (int i = 0; i < edges.size(); i++) { ConnectibleEdge edge = (ConnectibleEdge) edges.get(i); Vendor vendor = i == 0 ? from : edge.getSource().getEntry().asTransit(); RouteEntry entry = new RouteEntry(vendor, edge.getRefill(), edge.getFuelCost(), 0); + if (prev != null){ + prev.setTime(scorer.getTime(entry, prev)); + prev.setFullTime(prev.getTime()); + } entries.add(entry); if (i == edges.size()-1){ entry = new RouteEntry(to, 0, 0, 0); entry.setLand(true); + if (prev != null){ + prev.setTime(scorer.getTime(entry, prev)); + prev.setFullTime(prev.getTime()); + } entries.add(entry); } + prev = entry; } - return new Route(entries); + Route route = new Route(entries); + route.setBalance(scorer.getProfile().getBalance()); + return route; } } diff --git a/core/src/main/java/ru/trader/analysis/Scorer.java b/core/src/main/java/ru/trader/analysis/Scorer.java index 0e293dc..a50cc17 100644 --- a/core/src/main/java/ru/trader/analysis/Scorer.java +++ b/core/src/main/java/ru/trader/analysis/Scorer.java @@ -95,15 +95,6 @@ public class Scorer { return avgDistance; } - public double getScore(RouteEntry entry, int jumps) { - int lands = entry.isLand() ? 1 : 0; - return getScore(entry.getVendor(), entry.getProfit(), jumps, lands, entry.getFuel()); - } - - public double getScore(Vendor vendor, double profit, int jumps, int lands, double fuel) { - return getScore(vendor.getDistance(), profit, jumps, lands, fuel); - } - private double getTime(double distance){ double a = 6000; double b = 673; @@ -111,26 +102,50 @@ public class Scorer { return Math.log(distance + a)*b*profile.getDistanceTime() - c; } + public double getProfitByTonne(double profit, double fuel){ + return getProfit(profit, fuel) / profile.getShip().getCargo(); + } + public double getProfit(double profit, double fuel){ profit -= profile.getFuelPrice() * fuel; - profit = profit / profile.getShip().getCargo(); return profit; } + public double getTime(RouteEntry entry, RouteEntry prev) { + if (prev == null) return 0; + int lands = entry.isLand() ? 1 : 0; + int jumps = prev.getVendor().getPlace().equals(entry.getVendor().getPlace()) ? 0 : 1; + double time = getTime(entry.getVendor().getDistance(), jumps, lands); + if (!prev.isLand()){ + time = time - profile.getTakeoffTime() + profile.getRechargeTime(); + } + return time; + } + public double getTime(double distance, int jumps, int lands){ double time = profile.getTakeoffTime(); if (jumps > 0){ time += profile.getJumpTime() + (jumps-1) * (profile.getRechargeTime() + profile.getJumpTime()); } - if (profile.getLandingTime() > 0){ + if (profile.getLandingTime() > 0 & lands > 0){ time += (lands-1)*(getTime(avgDistance) + profile.getLandingTime() + profile.getTakeoffTime()) + getTime(distance) + profile.getLandingTime(); } return time; } + public double getScore(RouteEntry entry, RouteEntry prev) { + int lands = prev.isLand() ? 1 : 0; + int jumps = prev.getVendor().getPlace().equals(entry.getVendor().getPlace())? 0 : 1; + return getScore(prev.getVendor(), prev.getProfit(), jumps, lands, prev.getFuel()); + } + + public double getScore(Vendor vendor, double profit, int jumps, int lands, double fuel) { + return getScore(vendor.getDistance(), profit, jumps, lands, fuel); + } + public double getScore(double distance, double profit, int jumps, int lands, double fuel){ LOG.trace("Compute score distance={}, profit={}, jumps={}, lands={}, fuel={}", distance, profit, jumps, lands, fuel); - double score = getProfit(profit, fuel)/getTime(distance, jumps, lands); + double score = getProfitByTonne(profit, fuel)/getTime(distance, jumps, lands); LOG.trace("score={}", score); return score; } diff --git a/core/src/main/java/ru/trader/analysis/VendorsGraph.java b/core/src/main/java/ru/trader/analysis/VendorsGraph.java index 82ef30b..74e3dfd 100644 --- a/core/src/main/java/ru/trader/analysis/VendorsGraph.java +++ b/core/src/main/java/ru/trader/analysis/VendorsGraph.java @@ -383,10 +383,19 @@ public class VendorsGraph extends ConnectibleGraph { return path.getRemain(); } + @Override public boolean isRefill() { return path.isRefill(); } + @Override + public double getFuelCost() { + if (path != null){ + return path.getFuelCost(); + } + return super.getFuelCost(); + } + public TransitPath getPath() { return path; } @@ -415,11 +424,7 @@ public class VendorsGraph extends ConnectibleGraph { } protected double computeProfit(){ - double fuel = fuelCost; - if (path != null){ - fuel = path.getFuelCost(); - } - return scorer.getProfit(getProfit(), fuel); + return scorer.getProfitByTonne(getProfit(), getFuelCost()); } protected double computeTime(){ diff --git a/core/src/main/java/ru/trader/core/MarketAnalyzer.java b/core/src/main/java/ru/trader/core/MarketAnalyzer.java index de2479b..dac6e31 100644 --- a/core/src/main/java/ru/trader/core/MarketAnalyzer.java +++ b/core/src/main/java/ru/trader/core/MarketAnalyzer.java @@ -176,11 +176,11 @@ public class MarketAnalyzer { } public Route getPath(Vendor from, Vendor to){ - return RouteSearcher.toRoute(from, to, searcher.getPath(from.getPlace(), to.getPlace(), getPlaces())); + return RouteSearcher.toRoute(from, to, searcher.getPath(from.getPlace(), to.getPlace(), getPlaces()), searcher.getScorer()); } public Route getPath(Order order){ - return RouteSearcher.toRoute(order, searcher.getPath(order.getSeller().getPlace(), order.getBuyer().getPlace(), getPlaces())); + return RouteSearcher.toRoute(order, searcher.getPath(order.getSeller().getPlace(), order.getBuyer().getPlace(), getPlaces()), searcher.getScorer()); } public Collection getTopRoutes(int limit){ diff --git a/core/src/test/java/ru/trader/analysis/RouteSearcherTest.java b/core/src/test/java/ru/trader/analysis/RouteSearcherTest.java index 4165fcd..1c68a47 100644 --- a/core/src/test/java/ru/trader/analysis/RouteSearcherTest.java +++ b/core/src/test/java/ru/trader/analysis/RouteSearcherTest.java @@ -74,7 +74,7 @@ public class RouteSearcherTest extends Assert{ RouteFiller filler = new RouteFiller(scorer); filler.fill(route); - assertEquals(981200, route.getProfit(), 0); + assertEquals(978883.1, route.getProfit(), 0.1); assertEquals(2, route.getLands()); assertEquals(72.42, route.getDistance(), 0.01); @@ -102,7 +102,7 @@ public class RouteSearcherTest extends Assert{ filler = new RouteFiller(scorer); filler.fill(route); - assertEquals(1971200, route.getProfit(), 0); + assertEquals(1967873.6, route.getProfit(), 0.1); assertEquals(4, route.getLands()); assertEquals(109.51, route.getDistance(), 0.01); diff --git a/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java b/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java index 0fcfaa9..9f329b6 100644 --- a/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java +++ b/core/src/test/java/ru/trader/core/MarketAnalyzerTest2.java @@ -45,7 +45,7 @@ public class MarketAnalyzerTest2 extends Assert { assertTrue(path.isPresent()); Route actual = path.get(); assertEquals(expect, actual); - assertEquals(981200, actual.getProfit(), 0.00001); + assertEquals(978883.1, actual.getProfit(), 0.1); assertEquals(72.42, actual.getDistance(), 0.01); assertEquals(2, actual.getLands()); } @@ -78,7 +78,7 @@ public class MarketAnalyzerTest2 extends Assert { assertTrue(path.isPresent()); Route actual = path.get(); - assertEquals(199056, actual.getProfit(), 0.00001); + assertEquals(198127.6, actual.getProfit(), 0.1); assertEquals(28.72, actual.getDistance(), 0.01); assertEquals(2, actual.getLands());