implement route searcher
This commit is contained in:
@@ -25,6 +25,15 @@ public class FilteredMarket {
|
||||
.filter(v -> !filter.isFiltered(v));
|
||||
}
|
||||
|
||||
public Stream<Vendor> getMarkets(boolean withTransit){
|
||||
return get().flatMap(p -> p.get(true).stream())
|
||||
.filter(v -> {
|
||||
if (withTransit && v instanceof TransitVendor) return true;
|
||||
if (!v.has(SERVICE_TYPE.MARKET) && !v.has(SERVICE_TYPE.BLACK_MARKET)) return false;
|
||||
return !filter.isFiltered(v);
|
||||
});
|
||||
}
|
||||
|
||||
public Collection<Item> getItems(){
|
||||
return market.getItems();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ public class Route {
|
||||
private double profit = 0;
|
||||
private double balance = 0;
|
||||
private double distance = 0;
|
||||
private double score = 0;
|
||||
private double fuel = 0;
|
||||
private int lands = 0;
|
||||
|
||||
public Route(RouteEntry root) {
|
||||
@@ -20,14 +22,9 @@ public class Route {
|
||||
entries.add(root);
|
||||
}
|
||||
|
||||
public Route(List<VendorsGraph.VendorsEdge> edges) {
|
||||
//TODO: move to RouteCrawler
|
||||
entries = new ArrayList<>(edges.size()+1);
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
VendorsGraph.VendorsEdge edge = edges.get(i);
|
||||
if (i==0) entries.add(new RouteEntry(edge.getSource().getEntry(), false, 0));
|
||||
entries.add(new RouteEntry(edge.getTarget().getEntry(), edge.isRefill(), edge.getFuel()));
|
||||
}
|
||||
public Route(List<RouteEntry> entries) {
|
||||
this.entries = new ArrayList<>(entries);
|
||||
updateStats();
|
||||
}
|
||||
|
||||
public List<RouteEntry> getEntries() {
|
||||
@@ -100,7 +97,7 @@ public class Route {
|
||||
}
|
||||
|
||||
void updateStats(){
|
||||
LOG.trace("Update stats, old: profit={}, distance={}, lands={}", profit, distance, lands);
|
||||
LOG.trace("Update stats, old: profit={}, distance={}, lands={}, fuel={}, score={}", profit, distance, lands, fuel, score);
|
||||
profit = 0; distance = 0; lands = 0;
|
||||
if (entries.isEmpty()) return;
|
||||
RouteEntry entry = entries.get(0);
|
||||
@@ -108,13 +105,26 @@ public class Route {
|
||||
RouteEntry next = entries.get(i);
|
||||
distance += entry.getVendor().getDistance(next.getVendor());
|
||||
profit += entry.getProfit();
|
||||
score += entry.getScore();
|
||||
fuel += entry.getFuel();
|
||||
if (entry.isLand()){
|
||||
lands++;
|
||||
}
|
||||
entry = next;
|
||||
}
|
||||
LOG.trace("new stats profit={}, distance={}, lands={}", profit, distance, lands);
|
||||
LOG.trace("new stats profit={}, distance={}, lands={}, fuel={}, score={}", profit, distance, lands, fuel, score);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Route{" +
|
||||
"entries=" + entries +
|
||||
", profit=" + profit +
|
||||
", balance=" + balance +
|
||||
", distance=" + distance +
|
||||
", score=" + score +
|
||||
", fuel=" + fuel +
|
||||
", lands=" + lands +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,18 @@ import java.util.List;
|
||||
public class RouteEntry {
|
||||
private final Vendor vendor;
|
||||
private final double fuel;
|
||||
private final double score;
|
||||
private final List<Order> orders;
|
||||
private boolean land;
|
||||
private boolean refill;
|
||||
|
||||
|
||||
public RouteEntry(Vendor vendor, boolean refill, double fuel) {
|
||||
public RouteEntry(Vendor vendor, boolean refill, double fuel, double score) {
|
||||
orders = new ArrayList<>();
|
||||
this.vendor = vendor;
|
||||
this.refill = refill;
|
||||
this.fuel = fuel;
|
||||
this.score = score;
|
||||
}
|
||||
|
||||
public Vendor getVendor() {
|
||||
@@ -42,6 +44,10 @@ public class RouteEntry {
|
||||
return fuel;
|
||||
}
|
||||
|
||||
public double getScore() {
|
||||
return score;
|
||||
}
|
||||
|
||||
public void add(Order order){
|
||||
orders.add(order);
|
||||
}
|
||||
@@ -74,4 +80,8 @@ public class RouteEntry {
|
||||
return !isLand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return vendor + (isRefill() ? " (R)":"");
|
||||
}
|
||||
}
|
||||
|
||||
104
core/src/main/java/ru/trader/analysis/RouteSearcher.java
Normal file
104
core/src/main/java/ru/trader/analysis/RouteSearcher.java
Normal file
@@ -0,0 +1,104 @@
|
||||
package ru.trader.analysis;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.trader.analysis.graph.Crawler;
|
||||
import ru.trader.analysis.graph.Edge;
|
||||
import ru.trader.core.Order;
|
||||
import ru.trader.core.TransitVendor;
|
||||
import ru.trader.core.Vendor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class RouteSearcher {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(RouteSearcher.class);
|
||||
private final VendorsGraph vGraph;
|
||||
|
||||
public RouteSearcher(Scorer scorer) {
|
||||
vGraph = new VendorsGraph(scorer);
|
||||
}
|
||||
|
||||
public List<Route> getRoutes(Vendor from, Vendor to, Collection<Vendor> vendors){
|
||||
return search(from, to, vendors);
|
||||
}
|
||||
|
||||
public List<Route> getRoutes(Vendor from, Collection<Vendor> vendors){
|
||||
return search(from, null, vendors);
|
||||
}
|
||||
|
||||
private List<Route> search(Vendor source, Vendor target, Collection<Vendor> vendors){
|
||||
LOG.trace("Start search route to {} from {}", source, target);
|
||||
vGraph.build(source, vendors);
|
||||
|
||||
RouteCollector collector = new RouteCollector();
|
||||
Crawler<Vendor> crawler = vGraph.crawler(collector::add);
|
||||
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());
|
||||
}
|
||||
return collector.get();
|
||||
|
||||
}
|
||||
|
||||
private class RouteCollector {
|
||||
private List<Route> routes = new ArrayList<>();
|
||||
|
||||
public void add(List<Edge<Vendor>> edges){
|
||||
Route route = toRoute(edges);
|
||||
if (route.getProfit() > 0) {
|
||||
routes.add(route);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Route> get() {
|
||||
return routes;
|
||||
}
|
||||
|
||||
private Route toRoute(List<Edge<Vendor>> edges){
|
||||
List<RouteEntry> entries = new ArrayList<>(edges.size()+1);
|
||||
Vendor buyer = null;
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
VendorsGraph.VendorsEdge edge = (VendorsGraph.VendorsEdge) edges.get(i);
|
||||
if (i==0){
|
||||
RouteEntry entry = new RouteEntry(edge.getSource().getEntry(), false, 0, 0);
|
||||
List<Order> orders = edge.getOrders();
|
||||
if (!orders.isEmpty()){
|
||||
buyer = orders.get(0).getBuyer();
|
||||
}
|
||||
entry.addAll(orders);
|
||||
entries.add(entry);
|
||||
}
|
||||
Vendor vendor = edge.getTarget().getEntry();
|
||||
RouteEntry entry = new RouteEntry(vendor, edge.isRefill(), edge.getFuel(), edge.getWeight());
|
||||
if (buyer != null && vendor.equals(buyer)){
|
||||
entry.setLand(true);
|
||||
}
|
||||
List<Order> orders = edge.getOrders();
|
||||
if (!orders.isEmpty()){
|
||||
buyer = orders.get(0).getBuyer();
|
||||
if (vendor instanceof TransitVendor){
|
||||
Vendor seller = orders.get(0).getSell().getVendor();
|
||||
for (int j = i-1; j <= 0; j--) {
|
||||
RouteEntry sEntry = entries.get(j);
|
||||
if (sEntry.is(seller)){
|
||||
sEntry.addAll(orders);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
entry.addAll(orders);
|
||||
}
|
||||
}
|
||||
entries.add(entry);
|
||||
}
|
||||
return new Route(entries);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ public class Scorer {
|
||||
buyOffers = new HashMap<>(100, 0.9f);
|
||||
market.getItems().parallelStream().forEach(this::fillOffers);
|
||||
DoubleSummaryStatistics statProfit = computeProfit();
|
||||
avgProfit = statProfit.getAverage()/profile.getShip().getCargo();
|
||||
avgProfit = statProfit.getAverage();
|
||||
avgDistance = computeAvgDistance();
|
||||
maxScore = getScore(0, statProfit.getMax()*2, 0,0,0);
|
||||
}
|
||||
@@ -77,8 +77,8 @@ public class Scorer {
|
||||
|
||||
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 = profit/profile.getShip().getCargo();
|
||||
if (avgDistance > 0) {
|
||||
double score = profit;
|
||||
if (avgDistance > 0 && profit > 0) {
|
||||
score -= profile.getDistanceMult() * getAvgProfit() * (distance - avgDistance) / avgDistance;
|
||||
}
|
||||
score -= profile.getLandMult() * lands * getAvgProfit();
|
||||
|
||||
146
core/src/main/java/ru/trader/analysis/VendorsGraph.java
Normal file
146
core/src/main/java/ru/trader/analysis/VendorsGraph.java
Normal file
@@ -0,0 +1,146 @@
|
||||
package ru.trader.analysis;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.trader.analysis.graph.*;
|
||||
import ru.trader.core.Order;
|
||||
import ru.trader.core.TransitVendor;
|
||||
import ru.trader.core.Vendor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
public class VendorsGraph extends ConnectibleGraph<Vendor> {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(VendorsGraph.class);
|
||||
|
||||
private final Scorer scorer;
|
||||
|
||||
public VendorsGraph(Scorer scorer) {
|
||||
super(scorer.getProfile());
|
||||
this.scorer = scorer;
|
||||
}
|
||||
|
||||
public VendorsGraph(Scorer scorer, AnalysisCallBack callback) {
|
||||
super(scorer.getProfile(), callback);
|
||||
this.scorer = scorer;
|
||||
}
|
||||
|
||||
public VendorsCrawler crawler(Consumer<List<Edge<Vendor>>> onFoundFunc){
|
||||
return new VendorsCrawler(onFoundFunc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphBuilder createGraphBuilder(Vertex<Vendor> vertex, Collection<Vendor> set, int deep, double limit) {
|
||||
return new VendorsGraphBuilder(vertex, set, deep, limit);
|
||||
}
|
||||
|
||||
protected class VendorsGraphBuilder extends ConnectibleGraphBuilder {
|
||||
protected VendorsGraphBuilder(Vertex<Vendor> vertex, Collection<Vendor> set, int deep, double limit) {
|
||||
super(vertex, set, deep, limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double onConnect(Vendor entry) {
|
||||
double nextlimit = super.onConnect(entry);
|
||||
if (entry instanceof TransitVendor && vertex.getEntry().getPlace().equals(entry.getPlace())) nextlimit = -1;
|
||||
return nextlimit;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ConnectibleEdge<Vendor> createEdge(Vertex<Vendor> target) {
|
||||
return new VendorsEdge(vertex, target, refill, fuelCost, false);
|
||||
}
|
||||
}
|
||||
|
||||
public class VendorsEdge extends ConnectibleEdge<Vendor> {
|
||||
private List<Order> orders;
|
||||
private boolean isTarget;
|
||||
|
||||
protected VendorsEdge(Vertex<Vendor> source, Vertex<Vendor> target, boolean refill, double fuel, boolean isTarget) {
|
||||
super(source, target, refill, fuel);
|
||||
this.isTarget = isTarget;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double computeWeight() {
|
||||
int jumps = source.getEntry().getPlace().equals(target.getEntry().getPlace())? 0 : 1;
|
||||
int lands = refill && orders.isEmpty() || isTarget ? 1 : 0;
|
||||
double score = scorer.getScore(target.getEntry(), getProfit(), jumps, lands, fuel);
|
||||
return scorer.getMaxScore() - score;
|
||||
}
|
||||
}
|
||||
|
||||
public class VendorsCrawler extends CCrawler<Vendor> {
|
||||
protected VendorsCrawler(Consumer<List<Edge<Vendor>>> onFoundFunc) {
|
||||
super(VendorsGraph.this, onFoundFunc);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CostTraversalEntry start(Vertex<Vendor> vertex) {
|
||||
double balance = scorer.getProfile().getBalance();
|
||||
return new VendorsTraversalEntry((CCostTraversalEntry) super.start(vertex), balance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CostTraversalEntry travers(CostTraversalEntry entry, List<Edge<Vendor>> head, Edge<Vendor> edge, Vendor target) {
|
||||
VendorsTraversalEntry ve = (VendorsTraversalEntry)entry;
|
||||
double balance = ve.balance;
|
||||
Vendor buyer = edge.getTarget().getEntry();
|
||||
List<Order> orders = ((VendorsEdge) edge).getOrders();
|
||||
if (edge.getSource().getEntry() instanceof TransitVendor &&
|
||||
!(buyer instanceof TransitVendor)){
|
||||
LOG.trace("{} is transit, search seller", edge.getSource().getEntry());
|
||||
for (int i = head.size() - 1; i >= 0; i--) {
|
||||
Vendor seller = head.get(i).getSource().getEntry();
|
||||
if (!(seller instanceof TransitVendor)){
|
||||
orders = MarketUtils.getOrders(seller, buyer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
orders = MarketUtils.getStack(orders, balance, scorer.getProfile().getShip().getCargo());
|
||||
|
||||
CCostTraversalEntry ce = (CCostTraversalEntry) super.travers(entry, head, edge, target);
|
||||
ConnectibleEdge<Vendor> cedge = (ConnectibleEdge<Vendor>) ce.getEdge();
|
||||
VendorsEdge addingEdge = new VendorsEdge(cedge.getSource(), cedge.getTarget(), cedge.isRefill(), cedge.getFuel(), target.equals(buyer));
|
||||
addingEdge.setOrders(orders);
|
||||
return new VendorsTraversalEntry(ce, head, addingEdge, balance+addingEdge.getProfit());
|
||||
}
|
||||
|
||||
protected class VendorsTraversalEntry extends CCostTraversalEntry {
|
||||
private final double balance;
|
||||
|
||||
protected VendorsTraversalEntry(CCostTraversalEntry entry, double balance) {
|
||||
super(entry.getHead(), entry.getVertex(), entry.getFuel());
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
protected VendorsTraversalEntry(CCostTraversalEntry entry, List<Edge<Vendor>> head, Edge<Vendor> edge, double balance) {
|
||||
super(head, edge, entry.getWeight(), entry.getFuel());
|
||||
this.balance = balance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -27,35 +27,13 @@ public class CCrawler<T extends Connectable<T>> extends Crawler<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Crawler<T>.TraversalEntry start(Vertex<T> vertex) {
|
||||
double fuel = getShip().getTank();
|
||||
return new CTraversalEntry(new ArrayList<>(), vertex, fuel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Crawler<T>.CostTraversalEntry costStart(Vertex<T> vertex) {
|
||||
protected CostTraversalEntry start(Vertex<T> vertex) {
|
||||
double fuel = getShip().getTank();
|
||||
return new CCostTraversalEntry(new ArrayList<>(), vertex, fuel);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Crawler<T>.TraversalEntry travers(TraversalEntry entry, Edge<T> edge) {
|
||||
T source = entry.vertex.getEntry();
|
||||
double distance = source.getDistance(edge.target.getEntry());
|
||||
double fuelCost = getShip().getFuelCost(((CTraversalEntry)entry).fuel, distance);
|
||||
double nextLimit = getProfile().withRefill() ? ((CTraversalEntry)entry).fuel - fuelCost : getShip().getTank();
|
||||
boolean refill = nextLimit < 0 && source.canRefill();
|
||||
if (refill) {
|
||||
LOG.trace("Refill");
|
||||
refill = true;
|
||||
nextLimit = getShip().getTank() - getShip().getFuelCost(distance);
|
||||
}
|
||||
edge = new ConnectibleEdge<>(edge.getSource(), edge.getTarget(), refill, fuelCost);
|
||||
return new CTraversalEntry(getCopyList(entry.head, edge), edge.getTarget(), nextLimit);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Crawler<T>.CostTraversalEntry costTravers(Crawler<T>.CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge) {
|
||||
protected CostTraversalEntry travers(CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge, T target) {
|
||||
T source = entry.vertex.getEntry();
|
||||
double distance = source.getDistance(edge.target.getEntry());
|
||||
double fuelCost = getShip().getFuelCost(((CCostTraversalEntry)entry).fuel, distance);
|
||||
@@ -71,23 +49,6 @@ public class CCrawler<T extends Connectable<T>> extends Crawler<T> {
|
||||
return new CCostTraversalEntry(head, edge, entry.getWeight(), nextLimit);
|
||||
}
|
||||
|
||||
protected class CTraversalEntry extends TraversalEntry {
|
||||
private final double fuel;
|
||||
|
||||
protected CTraversalEntry(List<Edge<T>> head, Vertex<T> vertex, double fuel) {
|
||||
super(head, vertex);
|
||||
this.fuel = fuel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<Edge<T>> getIteratorInstance() {
|
||||
return vertex.getEdges().stream().filter(e -> {
|
||||
ConnectibleEdge<T> edge = (ConnectibleEdge<T>) e;
|
||||
return edge.getFuel() <= fuel || e.getSource().getEntry().canRefill();
|
||||
}).iterator();
|
||||
}
|
||||
}
|
||||
|
||||
protected class CCostTraversalEntry extends CostTraversalEntry {
|
||||
private final double fuel;
|
||||
|
||||
@@ -101,6 +62,10 @@ public class CCrawler<T extends Connectable<T>> extends Crawler<T> {
|
||||
this.fuel = fuel;
|
||||
}
|
||||
|
||||
public double getFuel() {
|
||||
return fuel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<Edge<T>> getIteratorInstance() {
|
||||
return vertex.getEdges().stream().filter(e -> {
|
||||
|
||||
@@ -5,12 +5,9 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Crawler<T> {
|
||||
private final static ForkJoinPool POOL = new ForkJoinPool();
|
||||
private final static int THRESHOLD = 4;
|
||||
private final static Logger LOG = LoggerFactory.getLogger(Crawler.class);
|
||||
|
||||
protected final Graph<T> graph;
|
||||
@@ -61,32 +58,20 @@ public class Crawler<T> {
|
||||
Vertex<T> t = graph.getVertex(target);
|
||||
int found = 0;
|
||||
if (t != null) {
|
||||
found = ucs(costStart(graph.getRoot()), target, 0, count);
|
||||
found = ucs(start(graph.getRoot()), target, 0, count);
|
||||
}
|
||||
LOG.debug("Found {} paths", found);
|
||||
}
|
||||
|
||||
protected TraversalEntry start(Vertex<T> vertex){
|
||||
return new TraversalEntry(new ArrayList<>(), vertex);
|
||||
}
|
||||
|
||||
protected CostTraversalEntry costStart(Vertex<T> vertex){
|
||||
protected CostTraversalEntry start(Vertex<T> vertex){
|
||||
return new CostTraversalEntry(new ArrayList<>(), vertex);
|
||||
}
|
||||
|
||||
protected TraversalEntry travers(TraversalEntry entry, Edge<T> edge){
|
||||
return new TraversalEntry(getCopyList(entry.head, edge), edge.getTarget());
|
||||
}
|
||||
|
||||
private CostTraversalEntry costTravers(CostTraversalEntry entry, Edge<T> edge){
|
||||
return costTravers(entry, getCopyList(entry.head, edge), edge);
|
||||
}
|
||||
|
||||
protected CostTraversalEntry costTravers(CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge){
|
||||
protected CostTraversalEntry travers(CostTraversalEntry entry, List<Edge<T>> head, Edge<T> edge, T target){
|
||||
return new CostTraversalEntry(head, edge, entry.getWeight());
|
||||
}
|
||||
|
||||
private int dfs(TraversalEntry entry, T target, int deep, int count) {
|
||||
private int dfs(CostTraversalEntry entry, T target, int deep, int count) {
|
||||
int found = 0;
|
||||
List<Edge<T>> head = entry.head;
|
||||
Vertex<T> source = entry.vertex;
|
||||
@@ -107,7 +92,7 @@ public class Crawler<T> {
|
||||
LOG.trace("Search around");
|
||||
for (Edge<T> edge : entry.getEdges()) {
|
||||
if (edge.getTarget().isSingle()) continue;
|
||||
found += dfs(travers(entry, edge), target, deep, count-found);
|
||||
found += dfs(travers(entry, getCopyList(head, edge), edge, target), target, deep, count-found);
|
||||
if (found >= count) break;
|
||||
}
|
||||
}
|
||||
@@ -115,13 +100,13 @@ public class Crawler<T> {
|
||||
return found;
|
||||
}
|
||||
|
||||
private int bfs(TraversalEntry root, T target, int deep, int count) {
|
||||
private int bfs(CostTraversalEntry root, T target, int deep, int count) {
|
||||
LOG.trace("BFS from {} to {}, deep {}, count {}", root.vertex, target, deep, count);
|
||||
int found = 0;
|
||||
LinkedList<TraversalEntry> queue = new LinkedList<>();
|
||||
LinkedList<CostTraversalEntry> queue = new LinkedList<>();
|
||||
queue.add(root);
|
||||
while (!queue.isEmpty() && count > found){
|
||||
TraversalEntry entry = queue.poll();
|
||||
CostTraversalEntry entry = queue.poll();
|
||||
List<Edge<T>> head = entry.head;
|
||||
Vertex<T> source = entry.vertex;
|
||||
if (head.size() >= maxSize){
|
||||
@@ -142,7 +127,7 @@ public class Crawler<T> {
|
||||
if (edge.getTarget().isSingle()) continue;
|
||||
if (deep < source.getLevel()) {
|
||||
edge.getTarget().sortEdges();
|
||||
queue.add(travers(entry, edge));
|
||||
queue.add(travers(entry, getCopyList(head, edge), edge, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,7 +168,7 @@ public class Crawler<T> {
|
||||
edge = iterator.next();
|
||||
if (deep < source.getLevel() && !edge.getTarget().isSingle() || edge.isConnect(target)) {
|
||||
LOG.trace("Add edge {} to queue", edge);
|
||||
queue.add(costTravers(entry, head, edge));
|
||||
queue.add(travers(entry, head, edge, target));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,7 +202,7 @@ public class Crawler<T> {
|
||||
if (edge.getTarget().isSingle()) continue;
|
||||
if (deep < source.getLevel() && head.size() < maxSize-1) {
|
||||
edge.getTarget().sortEdges();
|
||||
queue.add(costTravers(entry, head, edge));
|
||||
queue.add(travers(entry, head, edge, target));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -236,6 +221,14 @@ public class Crawler<T> {
|
||||
this.vertex = vertex;
|
||||
}
|
||||
|
||||
public List<Edge<T>> getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public Vertex<T> getVertex() {
|
||||
return vertex;
|
||||
}
|
||||
|
||||
public Iterator<Edge<T>> iterator(){
|
||||
if (iterator == null){
|
||||
iterator = getIteratorInstance();
|
||||
@@ -247,7 +240,7 @@ public class Crawler<T> {
|
||||
return vertex.getEdges().iterator();
|
||||
}
|
||||
|
||||
private Iterable<Edge<T>> getEdges(){
|
||||
protected Iterable<Edge<T>> getEdges(){
|
||||
return this::iterator;
|
||||
}
|
||||
}
|
||||
@@ -269,13 +262,17 @@ public class Crawler<T> {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
protected double getWeight(){
|
||||
public double getWeight(){
|
||||
if (weight == null){
|
||||
weight = cost + (edge !=null ? edge.getWeight() : 0);
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
|
||||
public Edge<T> getEdge() {
|
||||
return edge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull CostTraversalEntry other) {
|
||||
int cmp = Double.compare(getWeight(), other.getWeight());
|
||||
@@ -283,69 +280,4 @@ public class Crawler<T> {
|
||||
return Integer.compare(head.size(), other.head.size());
|
||||
}
|
||||
}
|
||||
/*
|
||||
private class PathFinder extends RecursiveAction {
|
||||
private final TopList<Path<T>> paths;
|
||||
private final Path<T> head;
|
||||
private final Vertex<T> target;
|
||||
|
||||
private PathFinder(TopList<Path<T>> paths, Path<T> head, Vertex<T> target) {
|
||||
this.paths = paths;
|
||||
this.head = head;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void compute() {
|
||||
if (target == null || isCancelled()) return;
|
||||
Vertex<T> source = head.getTarget();
|
||||
LOG.trace("Find path to deep from {} to {}, head {}", source, target, head);
|
||||
Edge<T> edge = source.getEdge(target);
|
||||
if (edge != null){
|
||||
Path<T> path = head.connectTo(edge.getTarget(), limit < edge.getLength());
|
||||
path.finish();
|
||||
LOG.trace("Last edge find, add path {}", path);
|
||||
synchronized (paths){
|
||||
if (!paths.add(path)) complete(null);
|
||||
}
|
||||
callback.onFound();
|
||||
}
|
||||
if (!source.isSingle()){
|
||||
LOG.trace("Search around");
|
||||
ArrayList<PathFinder> subTasks = new ArrayList<>(source.getEdges().size());
|
||||
Iterator<Edge<T>> iterator = source.getEdges().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Edge<T> next = iterator.next();
|
||||
if (isDone() || callback.isCancel()) break;
|
||||
// target already added if source consist edge
|
||||
if (next.isConnect(target)) continue;
|
||||
Path<T> path = head.connectTo(next.getTarget(), limit < next.getLength());
|
||||
//Recursive search
|
||||
PathFinder task = new PathFinder(paths, path, target);
|
||||
task.fork();
|
||||
subTasks.add(task);
|
||||
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
||||
for (PathFinder subTask : subTasks) {
|
||||
if (isDone() || callback.isCancel()) {
|
||||
subTask.cancel(callback.isCancel());
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
}
|
||||
subTasks.clear();
|
||||
}
|
||||
}
|
||||
if (!subTasks.isEmpty()){
|
||||
for (PathFinder subTask : subTasks) {
|
||||
if (isDone() || callback.isCancel()) {
|
||||
subTask.cancel(callback.isCancel());
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
}
|
||||
subTasks.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
24
core/src/main/java/ru/trader/analysis/graph/Path.java
Normal file
24
core/src/main/java/ru/trader/analysis/graph/Path.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package ru.trader.analysis.graph;
|
||||
|
||||
import ru.trader.graph.Connectable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Path<T extends Connectable<T>> {
|
||||
private final List<PathEntry<T>> entries;
|
||||
|
||||
public Path(List<ConnectibleEdge<T>> edges) {
|
||||
entries = new ArrayList<>(edges.size());
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
ConnectibleEdge<T> edge = edges.get(i);
|
||||
if (i==0) entries.add(new PathEntry<>(edge.getSource().getEntry(), false));
|
||||
entries.add(new PathEntry<>(edge.getTarget().getEntry(), edge.isRefill()));
|
||||
}
|
||||
}
|
||||
|
||||
public PathEntry<T> get(int index){
|
||||
return entries.get(index);
|
||||
}
|
||||
|
||||
}
|
||||
19
core/src/main/java/ru/trader/analysis/graph/PathEntry.java
Normal file
19
core/src/main/java/ru/trader/analysis/graph/PathEntry.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package ru.trader.analysis.graph;
|
||||
|
||||
public class PathEntry<T> {
|
||||
private final T entry;
|
||||
private boolean refill;
|
||||
|
||||
public PathEntry(T entry, boolean refill) {
|
||||
this.entry = entry;
|
||||
this.refill = refill;
|
||||
}
|
||||
|
||||
public T getEntry() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
public boolean isRefill() {
|
||||
return refill;
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,9 @@ public class Vertex<T> {
|
||||
public void connect(Edge<T> edge){
|
||||
assert this == edge.getSource();
|
||||
synchronized (edges){
|
||||
edges.add(edge);
|
||||
if (!edges.contains(edge)){
|
||||
edges.add(edge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,17 @@ public interface Place extends Connectable<Place> {
|
||||
void setPosition(double x, double y, double z);
|
||||
|
||||
Collection<Vendor> get();
|
||||
default Collection<Vendor> get(boolean withTransit){
|
||||
if (withTransit){
|
||||
Collection<Vendor> vendors = new ArrayList<>();
|
||||
vendors.add(new TransitVendor(this));
|
||||
vendors.addAll(get());
|
||||
return vendors;
|
||||
} else {
|
||||
return get();
|
||||
}
|
||||
}
|
||||
|
||||
default Vendor get(String name){
|
||||
Optional<Vendor> vendor = get().stream().filter(p -> name.equalsIgnoreCase(p.getName())).findFirst();
|
||||
return vendor.isPresent() ? vendor.get() : null;
|
||||
|
||||
@@ -6,6 +6,7 @@ public class Profile {
|
||||
private int jumps;
|
||||
private Ship ship;
|
||||
private boolean refill;
|
||||
private int routesCount;
|
||||
//Scorer multipliers
|
||||
private int scoreOrdersCount;
|
||||
private double distanceMult;
|
||||
@@ -55,6 +56,14 @@ public class Profile {
|
||||
this.refill = refill;
|
||||
}
|
||||
|
||||
public int getRoutesCount() {
|
||||
return routesCount;
|
||||
}
|
||||
|
||||
public void setRoutesCount(int routesCount) {
|
||||
this.routesCount = routesCount;
|
||||
}
|
||||
|
||||
public int getScoreOrdersCount() {
|
||||
return scoreOrdersCount;
|
||||
}
|
||||
|
||||
@@ -122,8 +122,8 @@ public class Ship {
|
||||
{90.0, 75.0, 60.0, 54.0, 48.0},
|
||||
{150.0, 125.0, 100.0, 90.0, 80.0},
|
||||
{525.0, 438.0, 350.0, 315.0, 280.0},
|
||||
{1,050.0, 875.0, 700.0, 630.0, 560.0},
|
||||
{1,800.0, 1,500.0, 1,200.0, 1,080.0, 960.0}
|
||||
{1050.0, 875.0, 700.0, 630.0, 560.0},
|
||||
{1800.0, 1500.0, 1200.0, 1080.0, 960.0}
|
||||
};
|
||||
//FSD Max fuel per jump [class][rating]
|
||||
private final static double[][] FSD_MAX_FUEL= {
|
||||
|
||||
113
core/src/main/java/ru/trader/core/TransitVendor.java
Normal file
113
core/src/main/java/ru/trader/core/TransitVendor.java
Normal file
@@ -0,0 +1,113 @@
|
||||
package ru.trader.core;
|
||||
|
||||
import ru.trader.graph.Connectable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class TransitVendor implements Vendor {
|
||||
protected Place place;
|
||||
|
||||
public TransitVendor(Place place) {
|
||||
this.place = place;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Place getPlace() {
|
||||
return place;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDistance(double distance) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(SERVICE_TYPE service) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SERVICE_TYPE service) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(SERVICE_TYPE service) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SERVICE_TYPE> getServices() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Offer addOffer(OFFER_TYPE type, Item item, double price, long count) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Offer offer) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Offer offer) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Offer> get(OFFER_TYPE type) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Offer get(OFFER_TYPE type, Item item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(OFFER_TYPE type, Item item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Connectable<Vendor> o) {
|
||||
double d = getDistance((Vendor)o);
|
||||
return d == 0 ? 0 : d > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TransitVendor)) return false;
|
||||
TransitVendor that = (TransitVendor) o;
|
||||
return place.equals(that.place);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return place.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Transit - "+place;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package ru.trader.core;
|
||||
|
||||
import ru.trader.graph.Connectable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class VendorsIterator implements Iterator<Vendor> {
|
||||
@@ -65,114 +62,4 @@ public class VendorsIterator implements Iterator<Vendor> {
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
private class TransitVendor implements Vendor {
|
||||
|
||||
private Place place;
|
||||
|
||||
private TransitVendor(Place place) {
|
||||
this.place = place;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Place getPlace() {
|
||||
return place;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDistance() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDistance(double distance) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(SERVICE_TYPE service) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(SERVICE_TYPE service) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(SERVICE_TYPE service) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<SERVICE_TYPE> getServices() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Offer addOffer(OFFER_TYPE type, Item item, double price, long count) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Offer offer) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Offer offer) {
|
||||
throw new UnsupportedOperationException("Is fake vendor, change unsupported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Offer> get(OFFER_TYPE type) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Offer get(OFFER_TYPE type, Item item) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean has(OFFER_TYPE type, Item item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Connectable<Vendor> o) {
|
||||
double d = getDistance((Vendor)o);
|
||||
return d == 0 ? 0 : d > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TransitVendor)) return false;
|
||||
TransitVendor that = (TransitVendor) o;
|
||||
return place.equals(that.place);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return place.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Transit";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user