refactoring vendor crawler
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
|
||||||
|
import ru.trader.analysis.graph.Edge;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public abstract class AbstractCrawlerSpecification implements CrawlerSpecification {
|
||||||
|
private final RouteSpecification<Vendor> routeSpecification;
|
||||||
|
private final Consumer<List<Edge<Vendor>>> onFoundFunc;
|
||||||
|
|
||||||
|
protected AbstractCrawlerSpecification(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||||
|
this.routeSpecification = routeSpecification;
|
||||||
|
this.onFoundFunc = onFoundFunc;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouteSpecification<Vendor> routeSpecification() {
|
||||||
|
return routeSpecification;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Consumer<List<Edge<Vendor>>> onFoundFunc() {
|
||||||
|
return onFoundFunc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.analysis.graph.Edge;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public interface CrawlerSpecification {
|
||||||
|
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsEdge edge);
|
||||||
|
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry);
|
||||||
|
|
||||||
|
public RouteSpecification<Vendor> routeSpecification();
|
||||||
|
|
||||||
|
public Consumer<List<Edge<Vendor>>> onFoundFunc();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.analysis.graph.Edge;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CrawlerSpecificationByProfit extends AbstractCrawlerSpecification {
|
||||||
|
|
||||||
|
public CrawlerSpecificationByProfit(Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||||
|
super(null, onFoundFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrawlerSpecificationByProfit(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||||
|
super(routeSpecification, onFoundFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsEdge edge) {
|
||||||
|
return edge.getTime()/edge.getProfitByTonne();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) {
|
||||||
|
double profit = 0; double time = 0;
|
||||||
|
Iterator<Edge<Vendor>> iterator = entry.routeIterator();
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next();
|
||||||
|
if (edge != null){
|
||||||
|
profit += edge.getProfitByTonne();
|
||||||
|
time += edge.getTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return profit > 1 ? time / profit : time;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.analysis.graph.Edge;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class CrawlerSpecificationByTime extends AbstractCrawlerSpecification {
|
||||||
|
public CrawlerSpecificationByTime(Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||||
|
super(null, onFoundFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrawlerSpecificationByTime(RouteSpecification<Vendor> routeSpecification, Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||||
|
super(routeSpecification, onFoundFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsEdge edge) {
|
||||||
|
return edge.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double computeWeight(VendorsCrawler.VendorsTraversalEntry entry) {
|
||||||
|
double time = 0;
|
||||||
|
Iterator<Edge<Vendor>> iterator = entry.routeIterator();
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
VendorsCrawler.VendorsEdge edge = (VendorsCrawler.VendorsEdge)iterator.next();
|
||||||
|
if (edge != null){
|
||||||
|
time += edge.getTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -119,10 +119,10 @@ public class RouteSearcher {
|
|||||||
public static Route toRoute(List<Edge<Vendor>> edges, final Scorer scorer){
|
public static Route toRoute(List<Edge<Vendor>> edges, final Scorer scorer){
|
||||||
List<RouteEntry> entries = new ArrayList<>(edges.size()+1);
|
List<RouteEntry> entries = new ArrayList<>(edges.size()+1);
|
||||||
Vendor buyer = null;
|
Vendor buyer = null;
|
||||||
VendorsGraph.VendorsEdge vEdge = null;
|
VendorsCrawler.VendorsEdge vEdge = null;
|
||||||
RouteEntry prev = null;
|
RouteEntry prev = null;
|
||||||
for (Edge<Vendor> e : edges) {
|
for (Edge<Vendor> e : edges) {
|
||||||
vEdge = (VendorsGraph.VendorsEdge) e;
|
vEdge = (VendorsCrawler.VendorsEdge) e;
|
||||||
List<ConnectibleEdge<Vendor>> transitEdges = vEdge.getPath().getEntries();
|
List<ConnectibleEdge<Vendor>> transitEdges = vEdge.getPath().getEntries();
|
||||||
for (int k = 0; k < transitEdges.size(); k++) {
|
for (int k = 0; k < transitEdges.size(); k++) {
|
||||||
ConnectibleEdge<Vendor> edge = transitEdges.get(k);
|
ConnectibleEdge<Vendor> edge = transitEdges.get(k);
|
||||||
|
|||||||
214
core/src/main/java/ru/trader/analysis/VendorsCrawler.java
Normal file
214
core/src/main/java/ru/trader/analysis/VendorsCrawler.java
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.trader.analysis.graph.*;
|
||||||
|
import ru.trader.core.Order;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class VendorsCrawler extends Crawler<Vendor> {
|
||||||
|
private double startFuel;
|
||||||
|
private double startBalance;
|
||||||
|
|
||||||
|
public VendorsCrawler(VendorsGraph graph, CrawlerSpecification specification, AnalysisCallBack callback) {
|
||||||
|
super(graph, specification.routeSpecification(), specification.onFoundFunc(), callback);
|
||||||
|
startFuel = graph.getProfile().getShip().getTank();
|
||||||
|
startBalance = graph.getProfile().getBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Scorer getScorer(){
|
||||||
|
return ((VendorsGraph)graph).getScorer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartFuel(double startFuel) {
|
||||||
|
this.startFuel = startFuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartBalance(double startBalance) {
|
||||||
|
this.startBalance = startBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VendorsTraversalEntry start(Vertex<Vendor> vertex) {
|
||||||
|
return new VendorsTraversalEntry(super.start(vertex), startFuel, startBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VendorsTraversalEntry travers(final CostTraversalEntry entry, final Edge<Vendor> edge) {
|
||||||
|
VendorsTraversalEntry vEntry = (VendorsTraversalEntry)entry;
|
||||||
|
VendorsEdge vEdge = (VendorsEdge) edge;
|
||||||
|
return new VendorsTraversalEntry(vEntry, vEdge);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class VendorsTraversalEntry extends CostTraversalEntry {
|
||||||
|
private final double fuel;
|
||||||
|
private final double balance;
|
||||||
|
|
||||||
|
protected VendorsTraversalEntry(CostTraversalEntry entry, double fuel, double balance) {
|
||||||
|
super(entry.getTarget());
|
||||||
|
this.fuel = fuel;
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected VendorsTraversalEntry(VendorsTraversalEntry head, VendorsEdge edge) {
|
||||||
|
super(head, edge);
|
||||||
|
this.balance = head.balance + edge.getProfit();
|
||||||
|
this.fuel = edge.getRemain();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Edge<Vendor>> collect(Collection<Edge<Vendor>> src) {
|
||||||
|
return src.stream().filter(this::check).map(this::wrap).filter(e -> e != null).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean check(Edge<Vendor> e){
|
||||||
|
VendorsGraph.VendorsBuildEdge edge = (VendorsGraph.VendorsBuildEdge) e;
|
||||||
|
return fuel <= edge.getMaxFuel() && (fuel >= edge.getMinFuel() || edge.getSource().getEntry().canRefill())
|
||||||
|
&& (edge.getProfit() > 0 || VendorsCrawler.this.isFound(edge, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected VendorsEdge wrap(Edge<Vendor> e) {
|
||||||
|
VendorsGraph.VendorsBuildEdge edge = (VendorsGraph.VendorsBuildEdge) e;
|
||||||
|
Path<Vendor> path = edge.getPath(fuel);
|
||||||
|
if (path == null) return null;
|
||||||
|
VendorsEdge res = new VendorsEdge(edge.getSource(), edge.getTarget(), new TransitPath(path, fuel));
|
||||||
|
res.setOrders(MarketUtils.getStack(edge.getOrders(), balance, getScorer().getProfile().getShip().getCargo()));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getWeight() {
|
||||||
|
if (weight == null){
|
||||||
|
double profit = 0; double time = 0;
|
||||||
|
Iterator<Edge<Vendor>> iterator = routeIterator();
|
||||||
|
while (iterator.hasNext()){
|
||||||
|
VendorsEdge edge = (VendorsEdge)iterator.next();
|
||||||
|
if (edge != null){
|
||||||
|
profit += edge.getProfitByTonne();
|
||||||
|
time += edge.getTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weight = profit > 1 ? time / profit : time;
|
||||||
|
}
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VendorsEdge extends ConnectibleEdge<Vendor> {
|
||||||
|
private TransitPath path;
|
||||||
|
private List<Order> orders;
|
||||||
|
private Double profitByTonne;
|
||||||
|
private Long time;
|
||||||
|
|
||||||
|
protected VendorsEdge(Vertex<Vendor> source, Vertex<Vendor> target, TransitPath path) {
|
||||||
|
super(source, target);
|
||||||
|
if (path == null) throw new IllegalArgumentException("Path must be no-null");
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setOrders(List<Order> orders){
|
||||||
|
this.orders = orders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfit(){
|
||||||
|
return getOrders().stream().mapToDouble(Order::getProfit).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Order> getOrders(){
|
||||||
|
if (orders == null){
|
||||||
|
Vendor seller = source.getEntry();
|
||||||
|
Vendor buyer = target.getEntry();
|
||||||
|
orders = MarketUtils.getOrders(seller, buyer);
|
||||||
|
}
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRemain() {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfitByTonne() {
|
||||||
|
if (profitByTonne == null){
|
||||||
|
profitByTonne = computeProfit();
|
||||||
|
}
|
||||||
|
return profitByTonne;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getTime() {
|
||||||
|
if (time == null){
|
||||||
|
time = computeTime();
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(@NotNull Edge other) {
|
||||||
|
double w = getWeight();
|
||||||
|
double ow = other.getWeight();
|
||||||
|
if (ow >= 0 && w >= 0) return super.compareTo(other);
|
||||||
|
if (w < 0 && ow < 0) return Double.compare(Math.abs(w), Math.abs(ow));
|
||||||
|
return w < 0 ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected double computeProfit(){
|
||||||
|
return getScorer().getProfitByTonne(getProfit(), getFuelCost());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long computeTime(){
|
||||||
|
int jumps = source.getEntry().getPlace().equals(target.getEntry().getPlace())? 0 : 1;
|
||||||
|
int lands = 1;
|
||||||
|
if (path != null){
|
||||||
|
jumps = path.size();
|
||||||
|
lands += path.getRefillCount();
|
||||||
|
//not lands if refuel on this station
|
||||||
|
if (path.isRefill()) lands--;
|
||||||
|
} else {
|
||||||
|
lands += isRefill() ? 1 :0;
|
||||||
|
}
|
||||||
|
return getScorer().getTime(target.getEntry().getDistance(), jumps, lands);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double computeWeight() {
|
||||||
|
return getTime()/getProfitByTonne();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof VendorsEdge)) return false;
|
||||||
|
if (!super.equals(o)) return false;
|
||||||
|
VendorsEdge edge = (VendorsEdge) o;
|
||||||
|
return !(path != null ? !path.equals(edge.path) : edge.path != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + (path != null ? path.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package ru.trader.analysis;
|
package ru.trader.analysis;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import ru.trader.analysis.graph.*;
|
import ru.trader.analysis.graph.*;
|
||||||
@@ -8,7 +7,6 @@ import ru.trader.core.*;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
|
||||||
public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
||||||
@@ -22,12 +20,28 @@ public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
|||||||
this.scorer = scorer;
|
this.scorer = scorer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Scorer getScorer() {
|
||||||
|
return scorer;
|
||||||
|
}
|
||||||
|
|
||||||
public VendorsCrawler crawler(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
public VendorsCrawler crawler(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
||||||
return new VendorsCrawler(onFoundFunc, callback);
|
return new VendorsCrawler(this, new CrawlerSpecificationByProfit(onFoundFunc), callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VendorsCrawler crawler(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
public VendorsCrawler crawler(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
||||||
return new VendorsCrawler(specification, onFoundFunc, callback);
|
return new VendorsCrawler(this, new CrawlerSpecificationByProfit(specification, onFoundFunc), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VendorsCrawler crawlerByTime(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
||||||
|
return new VendorsCrawler(this, new CrawlerSpecificationByTime(onFoundFunc), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VendorsCrawler crawlerByTime(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback){
|
||||||
|
return new VendorsCrawler(this, new CrawlerSpecificationByTime(specification, onFoundFunc), callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VendorsCrawler crawler(CrawlerSpecification specification, AnalysisCallBack callback){
|
||||||
|
return new VendorsCrawler(this, specification, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -298,7 +312,7 @@ public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path<Vendor> getPath(double fuel){
|
public Path<Vendor> getPath(double fuel){
|
||||||
Path<Vendor> res = null;
|
Path<Vendor> res = null;
|
||||||
for (Path<Vendor> p : paths) {
|
for (Path<Vendor> p : paths) {
|
||||||
if (fuel >= p.getMinFuel() && fuel <= p.getMaxFuel() || getSource().getEntry().canRefill()) {
|
if (fuel >= p.getMinFuel() && fuel <= p.getMaxFuel() || getSource().getEntry().canRefill()) {
|
||||||
@@ -340,216 +354,6 @@ public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
|||||||
update(path);
|
update(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public VendorsEdge getInstance(double fuel, double balance){
|
|
||||||
Path<Vendor> path = getPath(fuel);
|
|
||||||
if (path == null) return null;
|
|
||||||
VendorsEdge res = new VendorsEdge(source, target, new TransitPath(path,fuel));
|
|
||||||
res.setOrders(MarketUtils.getStack(getOrders(), balance, getShip().getCargo()));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VendorsEdge extends ConnectibleEdge<Vendor> {
|
|
||||||
private TransitPath path;
|
|
||||||
private List<Order> orders;
|
|
||||||
private Double profitByTonne;
|
|
||||||
private Long time;
|
|
||||||
|
|
||||||
protected VendorsEdge(Vertex<Vendor> source, Vertex<Vendor> target, TransitPath path) {
|
|
||||||
super(source, target);
|
|
||||||
if (path == null) throw new IllegalArgumentException("Path must be no-null");
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setOrders(List<Order> orders){
|
|
||||||
this.orders = orders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getProfit(){
|
|
||||||
return getOrders().stream().mapToDouble(Order::getProfit).sum();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Order> getOrders(){
|
|
||||||
if (orders == null){
|
|
||||||
Vendor seller = source.getEntry();
|
|
||||||
Vendor buyer = target.getEntry();
|
|
||||||
orders = MarketUtils.getOrders(seller, buyer);
|
|
||||||
}
|
|
||||||
return orders;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getRemain() {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getProfitByTonne() {
|
|
||||||
if (profitByTonne == null){
|
|
||||||
profitByTonne = computeProfit();
|
|
||||||
}
|
|
||||||
return profitByTonne;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTime() {
|
|
||||||
if (time == null){
|
|
||||||
time = computeTime();
|
|
||||||
}
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(@NotNull Edge other) {
|
|
||||||
double w = getWeight();
|
|
||||||
double ow = other.getWeight();
|
|
||||||
if (ow >= 0 && w >= 0) return super.compareTo(other);
|
|
||||||
if (w < 0 && ow < 0) return Double.compare(Math.abs(w), Math.abs(ow));
|
|
||||||
return w < 0 ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double computeProfit(){
|
|
||||||
return scorer.getProfitByTonne(getProfit(), getFuelCost());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected long computeTime(){
|
|
||||||
int jumps = source.getEntry().getPlace().equals(target.getEntry().getPlace())? 0 : 1;
|
|
||||||
int lands = 1;
|
|
||||||
if (path != null){
|
|
||||||
jumps = path.size();
|
|
||||||
lands += path.getRefillCount();
|
|
||||||
//not lands if refuel on this station
|
|
||||||
if (path.isRefill()) lands--;
|
|
||||||
} else {
|
|
||||||
lands += isRefill() ? 1 :0;
|
|
||||||
}
|
|
||||||
return scorer.getTime(target.getEntry().getDistance(), jumps, lands);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected double computeWeight() {
|
|
||||||
return getTime()/getProfitByTonne();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) return true;
|
|
||||||
if (!(o instanceof VendorsEdge)) return false;
|
|
||||||
if (!super.equals(o)) return false;
|
|
||||||
VendorsEdge edge = (VendorsEdge) o;
|
|
||||||
return !(path != null ? !path.equals(edge.path) : edge.path != null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = super.hashCode();
|
|
||||||
result = 31 * result + (path != null ? path.hashCode() : 0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class VendorsCrawler extends Crawler<Vendor> {
|
|
||||||
private double startFuel;
|
|
||||||
private double startBalance;
|
|
||||||
|
|
||||||
protected VendorsCrawler(Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback) {
|
|
||||||
super(VendorsGraph.this, onFoundFunc, callback);
|
|
||||||
startFuel = getShip().getTank();
|
|
||||||
startBalance = getProfile().getBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected VendorsCrawler(RouteSpecification<Vendor> specification, Consumer<List<Edge<Vendor>>> onFoundFunc, AnalysisCallBack callback) {
|
|
||||||
super(VendorsGraph.this, specification, onFoundFunc, callback);
|
|
||||||
startFuel = getShip().getTank();
|
|
||||||
startBalance = getProfile().getBalance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartFuel(double startFuel) {
|
|
||||||
this.startFuel = startFuel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStartBalance(double startBalance) {
|
|
||||||
this.startBalance = startBalance;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected VendorsTraversalEntry start(Vertex<Vendor> vertex) {
|
|
||||||
return new VendorsTraversalEntry(super.start(vertex), startFuel, startBalance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected VendorsTraversalEntry travers(final CostTraversalEntry entry, final Edge<Vendor> edge) {
|
|
||||||
VendorsTraversalEntry vEntry = (VendorsTraversalEntry)entry;
|
|
||||||
VendorsEdge vEdge = (VendorsEdge) edge;
|
|
||||||
return new VendorsTraversalEntry(vEntry, vEdge);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected class VendorsTraversalEntry extends CostTraversalEntry {
|
|
||||||
private final double fuel;
|
|
||||||
private final double balance;
|
|
||||||
|
|
||||||
protected VendorsTraversalEntry(CostTraversalEntry entry, double fuel, double balance) {
|
|
||||||
super(entry.getTarget());
|
|
||||||
this.fuel = fuel;
|
|
||||||
this.balance = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected VendorsTraversalEntry(VendorsTraversalEntry head, VendorsEdge edge) {
|
|
||||||
super(head, edge);
|
|
||||||
this.balance = head.balance + edge.getProfit();
|
|
||||||
this.fuel = edge.getRemain();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Edge<Vendor>> collect(Collection<Edge<Vendor>> src) {
|
|
||||||
return src.stream().filter(this::check).map(this::wrap).filter(e -> e != null).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean check(Edge<Vendor> e){
|
|
||||||
VendorsBuildEdge edge = (VendorsBuildEdge) e;
|
|
||||||
return fuel <= edge.getMaxFuel() && (fuel >= edge.getMinFuel() || edge.getSource().getEntry().canRefill())
|
|
||||||
&& (edge.getProfit() > 0 || VendorsCrawler.this.isFound(edge, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected VendorsEdge wrap(Edge<Vendor> e) {
|
|
||||||
VendorsBuildEdge edge = (VendorsBuildEdge) e;
|
|
||||||
return edge.getInstance(fuel, balance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double getWeight() {
|
|
||||||
if (weight == null){
|
|
||||||
double profit = 0; double time = 0;
|
|
||||||
Iterator<Edge<Vendor>> iterator = routeIterator();
|
|
||||||
while (iterator.hasNext()){
|
|
||||||
VendorsEdge edge = (VendorsEdge)iterator.next();
|
|
||||||
if (edge != null){
|
|
||||||
profit += edge.getProfitByTonne();
|
|
||||||
time += edge.getTime();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
weight = profit > 1 ? time / profit : time;
|
|
||||||
}
|
|
||||||
return weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ public class Crawler<T> {
|
|||||||
private int maxSize;
|
private int maxSize;
|
||||||
|
|
||||||
public Crawler(Graph<T> graph, Consumer<List<Edge<T>>> onFoundFunc, AnalysisCallBack callback) {
|
public Crawler(Graph<T> graph, Consumer<List<Edge<T>>> onFoundFunc, AnalysisCallBack callback) {
|
||||||
this.graph = graph;
|
this(graph, null, onFoundFunc, callback);
|
||||||
this.callback = new CrawlerCallBack(callback);
|
|
||||||
maxSize = graph.getRoot().getLevel();
|
|
||||||
this.onFoundFunc = onFoundFunc;
|
|
||||||
this.specification = (edge, entry) -> isTarget(edge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Crawler(Graph<T> graph, RouteSpecification<T> specification, Consumer<List<Edge<T>>> onFoundFunc, AnalysisCallBack callback) {
|
public Crawler(Graph<T> graph, RouteSpecification<T> specification, Consumer<List<Edge<T>>> onFoundFunc, AnalysisCallBack callback) {
|
||||||
@@ -38,7 +34,11 @@ public class Crawler<T> {
|
|||||||
this.callback = new CrawlerCallBack(callback);
|
this.callback = new CrawlerCallBack(callback);
|
||||||
maxSize = graph.getRoot().getLevel();
|
maxSize = graph.getRoot().getLevel();
|
||||||
this.onFoundFunc = onFoundFunc;
|
this.onFoundFunc = onFoundFunc;
|
||||||
this.specification = specification;
|
if (specification != null){
|
||||||
|
this.specification = specification;
|
||||||
|
} else {
|
||||||
|
this.specification = (edge, entry) -> isTarget(edge);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Edge<T>> getCopyList(Traversal<T> head, Edge<T> tail){
|
protected List<Edge<T>> getCopyList(Traversal<T> head, Edge<T> tail){
|
||||||
|
|||||||
Reference in New Issue
Block a user