Improved segment search
This commit is contained in:
@@ -12,8 +12,8 @@ public class MarketAnalyzer {
|
|||||||
private Market market;
|
private Market market;
|
||||||
private double tank;
|
private double tank;
|
||||||
private double maxDistance;
|
private double maxDistance;
|
||||||
private double segment = 50;
|
private int segmentSize;
|
||||||
private int count = 100;
|
private int limit;
|
||||||
private int jumps;
|
private int jumps;
|
||||||
private int cargo;
|
private int cargo;
|
||||||
|
|
||||||
@@ -21,16 +21,18 @@ public class MarketAnalyzer {
|
|||||||
|
|
||||||
public MarketAnalyzer(Market market) {
|
public MarketAnalyzer(Market market) {
|
||||||
this.market = market;
|
this.market = market;
|
||||||
|
this.limit = 100;
|
||||||
|
this.segmentSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Order> getTop(double balance){
|
public Collection<Order> getTop(double balance){
|
||||||
LOG.debug("Get top {}", count);
|
LOG.debug("Get top {}", limit);
|
||||||
Collection<Vendor> vendors = market.get();
|
Collection<Vendor> vendors = market.get();
|
||||||
List<Order> top = new ArrayList<>(count);
|
List<Order> top = new ArrayList<>(limit);
|
||||||
for (Vendor vendor : vendors) {
|
for (Vendor vendor : vendors) {
|
||||||
LOG.trace("Check vendor {}", vendor);
|
LOG.trace("Check vendor {}", vendor);
|
||||||
Collection<Order> orders = getOrders(vendor, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit());
|
Collection<Order> orders = getOrders(vendor, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit());
|
||||||
RouteGraph.addAllToTop(top, orders, count, orderComparator);
|
TopList.addAllToTop(top, orders, limit, orderComparator);
|
||||||
}
|
}
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
@@ -101,22 +103,22 @@ public class MarketAnalyzer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Vendor from, double balance){
|
public Collection<PathRoute> getPaths(Vendor from, double balance){
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segment);
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
return searcher.getPaths(from, market.get(), jumps, balance, cargo, count);
|
return searcher.getPaths(from, market.get(), jumps, balance, cargo, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
|
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segment);
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
return searcher.getPaths(from, to, market.get(), jumps, balance, cargo, count);
|
return searcher.getPaths(from, to, market.get(), jumps, balance, cargo, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<PathRoute> getTopPaths(double balance){
|
public Collection<PathRoute> getTopPaths(double balance){
|
||||||
List<PathRoute> top = new ArrayList<>(count);
|
List<PathRoute> top = new ArrayList<>(limit);
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segment);
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
Collection<Vendor> vendors = market.get();
|
Collection<Vendor> vendors = market.get();
|
||||||
for (Vendor vendor : vendors) {
|
for (Vendor vendor : vendors) {
|
||||||
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
|
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
|
||||||
RouteGraph.addAllToTop(top, paths, count, RouteGraph.comparator);
|
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||||
}
|
}
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
@@ -138,5 +140,11 @@ public class MarketAnalyzer {
|
|||||||
this.cargo = cargo;
|
this.cargo = cargo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setSegmentSize(int segmentSize) {
|
||||||
|
this.segmentSize = segmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPathsCount(int count) {
|
||||||
|
this.limit = count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.util.function.Predicate;
|
|||||||
public class Graph<T extends Connectable<T>> {
|
public class Graph<T extends Connectable<T>> {
|
||||||
private final static ForkJoinPool POOL = new ForkJoinPool();
|
private final static ForkJoinPool POOL = new ForkJoinPool();
|
||||||
private final static int THRESHOLD = 4;
|
private final static int THRESHOLD = 4;
|
||||||
|
private final static int DEFAULT_COUNT = 200;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface PathConstructor<E extends Connectable<E>> {
|
public interface PathConstructor<E extends Connectable<E>> {
|
||||||
@@ -20,14 +21,14 @@ public class Graph<T extends Connectable<T>> {
|
|||||||
|
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(Graph.class);
|
private final static Logger LOG = LoggerFactory.getLogger(Graph.class);
|
||||||
|
|
||||||
private final Vertex<T> root;
|
protected final Vertex<T> root;
|
||||||
private final Map<T,Vertex<T>> vertexes;
|
protected final Map<T,Vertex<T>> vertexes;
|
||||||
|
|
||||||
private final double stock;
|
protected final double stock;
|
||||||
private final double maxDistance;
|
protected final double maxDistance;
|
||||||
private final boolean withRefill;
|
protected final boolean withRefill;
|
||||||
private final PathConstructor<T> pathFabric;
|
private final PathConstructor<T> pathFabric;
|
||||||
private int minJumps;
|
protected int minJumps;
|
||||||
|
|
||||||
|
|
||||||
public Graph(T start, Collection<T> set, double stock, int maxDeep) {
|
public Graph(T start, Collection<T> set, double stock, int maxDeep) {
|
||||||
@@ -79,42 +80,45 @@ public class Graph<T extends Connectable<T>> {
|
|||||||
return vertexes.get(entry);
|
return vertexes.get(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void findPathsTo(Vertex<T> target, int max, List<Path<T>> res){
|
private void findPathsTo(Vertex<T> target, TopList<Path<T>> res, int deep){
|
||||||
POOL.invoke(new PathFinder(res, max, pathFabric.build(root), target, root.getLevel() - 1, stock));
|
POOL.invoke(new PathFinder(res, pathFabric.build(root), target, deep-1, stock));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Path<T>> getPathsTo(T entry){
|
public List<Path<T>> getPathsTo(T entry){
|
||||||
return getPathsTo(entry, 200);
|
return getPathsTo(entry, DEFAULT_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Path<T>> getPathsTo(T entry, int max){
|
public List<Path<T>> getPathsTo(T entry, int max){
|
||||||
|
return getPathsTo(entry, max, root.getLevel()).getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopList<Path<T>> getPathsTo(T entry, int max, int deep){
|
||||||
Vertex<T> target = getVertex(entry);
|
Vertex<T> target = getVertex(entry);
|
||||||
ArrayList<Path<T>> paths = new ArrayList<>(max);
|
TopList<Path<T>> paths = newTopList(max);
|
||||||
findPathsTo(target, max, paths);
|
findPathsTo(target, paths, deep);
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Path<T>> getPaths(int count){
|
public List<Path<T>> getPaths(int count){
|
||||||
ArrayList<Path<T>> paths = new ArrayList<>(vertexes.size()*count);
|
return getPaths(count, root.getLevel()).getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TopList<Path<T>> getPaths(int count, int deep){
|
||||||
|
TopList<Path<T>> paths = newTopList(count);
|
||||||
for (Vertex<T> target : vertexes.values()) {
|
for (Vertex<T> target : vertexes.values()) {
|
||||||
ArrayList<Path<T>> p = new ArrayList<>(count);
|
TopList<Path<T>> p = newTopList(minJumps);
|
||||||
findPathsTo(target, count, p);
|
findPathsTo(target, p, deep);
|
||||||
for (Path<T> path : p) {
|
for (Path<T> path : p.getList()) {
|
||||||
paths.add(path);
|
paths.add(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TopList<Path<T>> newTopList(int count){
|
||||||
// if is true, then break search
|
return new TopList<>(count);
|
||||||
protected boolean onFindPath(List<Path<T>> paths, int max, Path<T> path){
|
|
||||||
if (paths.size() >= max) return true;
|
|
||||||
paths.add(path);
|
|
||||||
return paths.size() >= max;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Path<T> getFastPathTo(T entry){
|
public Path<T> getFastPathTo(T entry){
|
||||||
Vertex<T> target = getVertex(entry);
|
Vertex<T> target = getVertex(entry);
|
||||||
if (target == null) return null;
|
if (target == null) return null;
|
||||||
@@ -246,17 +250,15 @@ public class Graph<T extends Connectable<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class PathFinder extends RecursiveAction {
|
private class PathFinder extends RecursiveAction {
|
||||||
private final List<Path<T>> paths;
|
private final TopList<Path<T>> paths;
|
||||||
private final int max;
|
|
||||||
private final Path<T> head;
|
private final Path<T> head;
|
||||||
private final Vertex<T> target;
|
private final Vertex<T> target;
|
||||||
private final int deep;
|
private final int deep;
|
||||||
private final double limit;
|
private final double limit;
|
||||||
private final DistanceFilter distanceFilter;
|
private final DistanceFilter distanceFilter;
|
||||||
|
|
||||||
private PathFinder(List<Path<T>> paths, int max, Path<T> head, Vertex<T> target, int deep, double limit) {
|
private PathFinder(TopList<Path<T>> paths, Path<T> head, Vertex<T> target, int deep, double limit) {
|
||||||
this.paths = paths;
|
this.paths = paths;
|
||||||
this.max = max;
|
|
||||||
this.head = head;
|
this.head = head;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.deep = deep;
|
this.deep = deep;
|
||||||
@@ -276,7 +278,7 @@ public class Graph<T extends Connectable<T>> {
|
|||||||
path.finish();
|
path.finish();
|
||||||
LOG.trace("Last edge find, add path {}", path);
|
LOG.trace("Last edge find, add path {}", path);
|
||||||
synchronized (paths){
|
synchronized (paths){
|
||||||
if (onFindPath(paths, max, path)) complete(null);
|
if (!paths.add(path)) complete(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +298,7 @@ public class Graph<T extends Connectable<T>> {
|
|||||||
// refill
|
// refill
|
||||||
if (nextLimit < 0) nextLimit = stock - next.getLength();
|
if (nextLimit < 0) nextLimit = stock - next.getLength();
|
||||||
//Recursive search
|
//Recursive search
|
||||||
PathFinder task = new PathFinder(paths, max, path, target, deep - 1, nextLimit);
|
PathFinder task = new PathFinder(paths, path, target, deep - 1, nextLimit);
|
||||||
task.fork();
|
task.fork();
|
||||||
subTasks.add(task);
|
subTasks.add(task);
|
||||||
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
||||||
|
|||||||
@@ -106,5 +106,9 @@ public class Path<T extends Connectable<T>> {
|
|||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLength(){
|
||||||
|
return isRoot() ? 0 : 1 + getPrevious().getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,19 +12,33 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
private final static Logger LOG = LoggerFactory.getLogger(PathRoute.class);
|
private final static Logger LOG = LoggerFactory.getLogger(PathRoute.class);
|
||||||
|
|
||||||
private final ArrayList<Order> orders = new ArrayList<>();
|
private final ArrayList<Order> orders = new ArrayList<>();
|
||||||
|
private final boolean byAvg;
|
||||||
private double profit = 0;
|
private double profit = 0;
|
||||||
private double balance = 0;
|
private double balance = 0;
|
||||||
|
private double distance = 0;
|
||||||
|
private int landsCount = 0;
|
||||||
private PathRoute tail;
|
private PathRoute tail;
|
||||||
public final static Order TRANSIT = null;
|
public final static Order TRANSIT = null;
|
||||||
|
|
||||||
public PathRoute(Vertex<Vendor> source) {
|
public PathRoute(Vertex<Vendor> source) {
|
||||||
super(source);
|
this(source, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PathRoute buildAvg(Vertex<Vendor> source){
|
||||||
|
return new PathRoute(source, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PathRoute(Vertex<Vendor> source, boolean byAvg) {
|
||||||
|
super(source);
|
||||||
|
this.byAvg = byAvg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private PathRoute(PathRoute head, Vertex<Vendor> vertex, boolean refill) {
|
private PathRoute(PathRoute head, Vertex<Vendor> vertex, boolean refill) {
|
||||||
super(head, vertex, refill);
|
super(head, vertex, refill);
|
||||||
assert head.tail == null;
|
assert head.tail == null;
|
||||||
head.tail = this;
|
head.tail = this;
|
||||||
|
byAvg = head.byAvg;
|
||||||
//transit
|
//transit
|
||||||
orders.add(TRANSIT);
|
orders.add(TRANSIT);
|
||||||
}
|
}
|
||||||
@@ -90,6 +104,22 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
fillOrders();
|
fillOrders();
|
||||||
getPrevious().finish();
|
getPrevious().finish();
|
||||||
}
|
}
|
||||||
|
updateDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(){
|
||||||
|
PathRoute p = this;
|
||||||
|
p.updateBalance();
|
||||||
|
while (p.hasNext()){
|
||||||
|
p = p.getNext();
|
||||||
|
p.updateBalance();
|
||||||
|
}
|
||||||
|
while (p != this){
|
||||||
|
p.updateProfit();
|
||||||
|
p.updateLandsCount();
|
||||||
|
p = p.getPrevious();
|
||||||
|
}
|
||||||
|
getRoot().updateDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillOrders(){
|
private void fillOrders(){
|
||||||
@@ -128,38 +158,26 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
return tail != null;
|
return tail != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void update(){
|
public void sort(double balance, long cargo){
|
||||||
PathRoute p = this;
|
|
||||||
p.updateBalance();
|
|
||||||
while (p.hasNext()){
|
|
||||||
p = p.getNext();
|
|
||||||
p.updateBalance();
|
|
||||||
}
|
|
||||||
while (p != this){
|
|
||||||
p.updateProfit();
|
|
||||||
p = p.getPrevious();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sort(double balance, long limit){
|
|
||||||
// start on root only
|
// start on root only
|
||||||
if (isRoot()){
|
if (isRoot()){
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
if (hasNext())
|
if (hasNext()){
|
||||||
getNext().forwardSort(limit);
|
getNext().forwardSort(cargo);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
getPrevious().sort(balance, limit);
|
getPrevious().sort(balance, cargo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void forwardSort(long limit){
|
private void forwardSort(long cargo){
|
||||||
updateBalance();
|
updateBalance();
|
||||||
boolean needSort = false;
|
boolean needSort = false;
|
||||||
for (Order order : orders) {
|
for (Order order : orders) {
|
||||||
if (order == TRANSIT) continue;
|
if (order == TRANSIT) continue;
|
||||||
if (order.getCount() < limit){
|
if (order.getCount() < cargo){
|
||||||
needSort = true;
|
needSort = true;
|
||||||
order.setMax(balance, limit);
|
order.setMax(balance, cargo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needSort){
|
if (needSort){
|
||||||
@@ -168,20 +186,22 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
LOG.trace("New order of orders {}", orders);
|
LOG.trace("New order of orders {}", orders);
|
||||||
}
|
}
|
||||||
if (hasNext()){
|
if (hasNext()){
|
||||||
getNext().forwardSort(limit);
|
getNext().forwardSort(cargo);
|
||||||
} else {
|
} else {
|
||||||
LOG.trace("Start back sort");
|
LOG.trace("Start back sort");
|
||||||
Order best = orders.get(0);
|
Order best = orders.get(0);
|
||||||
profit = best == TRANSIT ? 0 : best.getProfit();
|
profit = best == TRANSIT ? 0 : best.getProfit();
|
||||||
LOG.trace("Max profit from {} = {}", getPrevious().get(), profit);
|
LOG.trace("Max profit from {} = {}", getPrevious().get(), profit);
|
||||||
|
updateLandsCount();
|
||||||
getPrevious().backwardSort();
|
getPrevious().backwardSort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void backwardSort(){
|
private void backwardSort(){
|
||||||
orders.sort(this::compareOrders);
|
orders.sort(byAvg ? this::compareByAvgProfit : this::compareOrders);
|
||||||
LOG.trace("New order of orders {}", orders);
|
LOG.trace("New order of orders {}", orders);
|
||||||
updateProfit();
|
updateProfit();
|
||||||
|
updateLandsCount();
|
||||||
if (!isRoot())
|
if (!isRoot())
|
||||||
getPrevious().backwardSort();
|
getPrevious().backwardSort();
|
||||||
}
|
}
|
||||||
@@ -222,6 +242,10 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
return profit;
|
return profit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getAvgProfit(){
|
||||||
|
return isRoot()? profit/landsCount : getPrevious().getAvgProfit();
|
||||||
|
}
|
||||||
|
|
||||||
public double getBalance() {
|
public double getBalance() {
|
||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
@@ -249,6 +273,17 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
return Double.compare(profit2, profit1);
|
return Double.compare(profit2, profit1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int compareByAvgProfit(Order o1, Order o2){
|
||||||
|
if (o1 != TRANSIT && o2 != TRANSIT){
|
||||||
|
if (!hasNext() || o1.isBuyer(o2.getBuyer()))
|
||||||
|
return o2.compareTo(o1);
|
||||||
|
}
|
||||||
|
double profit1 = getProfit(o1)/computeLandsCount(o1);
|
||||||
|
double profit2 = getProfit(o2)/computeLandsCount(o2);
|
||||||
|
return Double.compare(profit2, profit1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PathRoute getRoot() {
|
public PathRoute getRoot() {
|
||||||
return (PathRoute) super.getRoot();
|
return (PathRoute) super.getRoot();
|
||||||
@@ -263,19 +298,67 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
return orders.get(0);
|
return orders.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getDistance(){
|
private double computeDistance(){
|
||||||
if (isRoot()){
|
if (isRoot()){
|
||||||
double res = 0;
|
double res = 0;
|
||||||
PathRoute p = this;
|
PathRoute p = this;
|
||||||
while (p.hasNext()){
|
while (p.hasNext()){
|
||||||
p = p.getNext();
|
p = p.getNext();
|
||||||
res += p.getDistance();
|
res += p.computeDistance();
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
else return getPrevious().get().getDistance(get());
|
else return getPrevious().get().getDistance(get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateDistance(){
|
||||||
|
this.distance = computeDistance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance(){
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int computeLandsCount(Order order){
|
||||||
|
int res = 0;
|
||||||
|
PathRoute p = isRoot()? getNext() : this;
|
||||||
|
while (p.hasNext()){
|
||||||
|
p = p.getNext();
|
||||||
|
// lands for sell
|
||||||
|
if (order != null && p.isPathFrom(order.getBuyer())){
|
||||||
|
LOG.trace("{} is lands for sell by order {}", p, order);
|
||||||
|
return res + p.getLandsCount() + 1;
|
||||||
|
} else {
|
||||||
|
if (order == null){
|
||||||
|
order = p.getBest();
|
||||||
|
if (order != null){
|
||||||
|
LOG.trace("{} is lands for buy by order {}", p, order);
|
||||||
|
return res + p.getLandsCount() + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (p.isRefill()){
|
||||||
|
LOG.trace("{} is lands for refill", p);
|
||||||
|
res++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
LOG.trace("{} is end, landing", p);
|
||||||
|
res++;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateLandsCount(){
|
||||||
|
Order best = isRoot() ? getNext().getBest() : getBest();
|
||||||
|
landsCount = computeLandsCount(best);
|
||||||
|
LOG.trace("Lands count from {} = {}", isRoot() ? get() : getPrevious().get(), landsCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLandsCount() {
|
||||||
|
return landsCount;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
@@ -303,38 +386,6 @@ public class PathRoute extends Path<Vendor> {
|
|||||||
orders.set(0, order);
|
orders.set(0, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLandsCount(){
|
|
||||||
int res = 0;
|
|
||||||
PathRoute p = this.isRoot() ? getNext() : this;
|
|
||||||
Order o = p.getBest();
|
|
||||||
while (p.hasNext()){
|
|
||||||
p = p.getNext();
|
|
||||||
// lands for sell
|
|
||||||
if (o != null && p.isPathFrom(o.getBuyer())){
|
|
||||||
LOG.trace("{} is lands for sell by order {}", p, o);
|
|
||||||
o = p.getBest();
|
|
||||||
res++;
|
|
||||||
} else {
|
|
||||||
if (o == null){
|
|
||||||
o = p.getBest();
|
|
||||||
if (o!= null){
|
|
||||||
LOG.trace("{} is lands for buy by order {}", p, o);
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (p.isRefill()){
|
|
||||||
LOG.trace("{} is lands for refill", p);
|
|
||||||
res++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
LOG.trace("{} is end, landing", p);
|
|
||||||
res++;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PathRoute dropTo(Vendor vendor){
|
public PathRoute dropTo(Vendor vendor){
|
||||||
PathRoute p = getCopy(true).getEnd();
|
PathRoute p = getCopy(true).getEnd();
|
||||||
while (!p.isRoot() && !p.get().equals(vendor)){
|
while (!p.isRoot() && !p.get().equals(vendor)){
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ import java.util.*;
|
|||||||
public class RouteGraph extends Graph<Vendor> {
|
public class RouteGraph extends Graph<Vendor> {
|
||||||
|
|
||||||
private double balance;
|
private double balance;
|
||||||
private int limit;
|
private int cargo;
|
||||||
|
private boolean groupRes;
|
||||||
|
|
||||||
public static Comparator<PathRoute> comparator = (p1, p2) -> {
|
public static Comparator<PathRoute> byProfitComparator = (p1, p2) -> {
|
||||||
PathRoute r1 = p1.getRoot();
|
PathRoute r1 = p1.getRoot();
|
||||||
PathRoute r2 = p2.getRoot();
|
PathRoute r2 = p2.getRoot();
|
||||||
int cmp = Double.compare(r2.getProfit()/r2.getLandsCount(), r1.getProfit()/r1.getLandsCount());
|
int cmp = Double.compare(r2.getAvgProfit(), r1.getAvgProfit());
|
||||||
if (cmp != 0 ) return cmp;
|
if (cmp != 0 ) return cmp;
|
||||||
cmp = Double.compare(r1.getDistance(), r2.getDistance());
|
cmp = Double.compare(r1.getDistance(), r2.getDistance());
|
||||||
if (cmp != 0) return cmp;
|
if (cmp != 0) return cmp;
|
||||||
@@ -21,61 +22,65 @@ public class RouteGraph extends Graph<Vendor> {
|
|||||||
return cmp;
|
return cmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static Comparator<PathRoute> groupByLengthComparator = (p1, p2) -> {
|
||||||
|
int cmp = Integer.compare(p1.getLength(), p2.getLength());
|
||||||
|
if (cmp != 0 ) return cmp;
|
||||||
|
return byProfitComparator.compare(p1, p2);
|
||||||
|
};
|
||||||
|
|
||||||
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep) {
|
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep) {
|
||||||
super(start, set, stock, maxDistance, withRefill, maxDeep, PathRoute::new);
|
this(start, set, stock, maxDistance, withRefill, maxDeep, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep, boolean groupRes) {
|
||||||
|
super(start, set, stock, maxDistance, withRefill, maxDeep, groupRes ? PathRoute::buildAvg : PathRoute::new);
|
||||||
|
if (groupRes){
|
||||||
|
this.groupRes = maxDeep > minJumps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBalance(double balance) {
|
public void setBalance(double balance) {
|
||||||
this.balance = balance;
|
this.balance = balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setLimit(int limit) {
|
public void setCargo(int cargo) {
|
||||||
this.limit = limit;
|
this.cargo = cargo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean onFindPath(List<Path<Vendor>> paths, int max, Path<Vendor> path) {
|
protected TopList<Path<Vendor>> newTopList(int count) {
|
||||||
PathRoute route = (PathRoute) path;
|
int groupSize = 0;
|
||||||
route.sort(balance, limit);
|
if (groupRes && getMinJumps() > 1){
|
||||||
addToTop(paths, route, max, (r1, r2) -> comparator.compare((PathRoute)r1, (PathRoute)r2));
|
groupSize = Math.floorDiv(count, root.getLevel());
|
||||||
return false;
|
}
|
||||||
|
return new TopRoutes(count, groupSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> void addToTop(List<T> list, T entry, int limit, Comparator<T> comparator){
|
private class TopRoutes extends TopList<Path<Vendor>> {
|
||||||
if (list.size() == limit){
|
private final int groupSize;
|
||||||
int index = Collections.binarySearch(list, entry, comparator);
|
|
||||||
if (index < 0) index = -1 - index;
|
|
||||||
if (index == limit) return;
|
|
||||||
list.add(index, entry);
|
|
||||||
list.remove(limit);
|
|
||||||
|
|
||||||
} else {
|
public TopRoutes(int limit, int groupSize) {
|
||||||
if (list.size() < limit-1){
|
super(limit, (p1, p2) -> groupSize > 0 ? groupByLengthComparator.compare((PathRoute)p1, (PathRoute)p2) : RouteGraph.byProfitComparator.compare((PathRoute)p1, (PathRoute)p2));
|
||||||
list.add(entry);
|
this.groupSize = groupSize;
|
||||||
} else {
|
|
||||||
list.add(entry);
|
|
||||||
list.sort(comparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> void addAllToTop(List<T> list, Collection<T> sortEntries, int limit, Comparator<T> comparator){
|
@Override
|
||||||
for (T entry : sortEntries) {
|
public boolean add(Path<Vendor> entry) {
|
||||||
if (list.size() == limit){
|
if (comparator != null){
|
||||||
int index = Collections.binarySearch(list, entry, comparator);
|
((PathRoute)entry).sort(balance, cargo);
|
||||||
if (index < 0) index = -1 - index;
|
}
|
||||||
if (index == limit) return;
|
if (groupSize>0){
|
||||||
list.add(index, entry);
|
addToGroupTop(list, entry, limit, comparator, (e) -> e.getLength()-1, groupSize);
|
||||||
list.remove(limit);
|
|
||||||
} else {
|
} else {
|
||||||
if (list.size() < limit-1){
|
if (comparator != null){
|
||||||
list.add(entry);
|
addToTop(list, entry, limit, comparator);
|
||||||
} else {
|
} else {
|
||||||
|
if (list.size() >= limit) return false;
|
||||||
list.add(entry);
|
list.add(entry);
|
||||||
list.sort(comparator);
|
if (list.size() >= limit) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,40 +16,35 @@ public class RouteSearcher {
|
|||||||
private final static ForkJoinPool POOL = new ForkJoinPool();
|
private final static ForkJoinPool POOL = new ForkJoinPool();
|
||||||
private final static int THRESHOLD = (int) Math.ceil(Runtime.getRuntime().availableProcessors()/2.0);
|
private final static int THRESHOLD = (int) Math.ceil(Runtime.getRuntime().availableProcessors()/2.0);
|
||||||
|
|
||||||
private double maxDistance;
|
private final double maxDistance;
|
||||||
private double stock;
|
private final double stock;
|
||||||
private int segmentJump;
|
private final int segmentSize;
|
||||||
|
|
||||||
public RouteSearcher(double maxDistance, double stock, double segment) {
|
public RouteSearcher(double maxDistance, double stock) {
|
||||||
|
this(maxDistance, stock, 0);
|
||||||
|
}
|
||||||
|
public RouteSearcher(double maxDistance, double stock, int segmentSize) {
|
||||||
this.maxDistance = maxDistance;
|
this.maxDistance = maxDistance;
|
||||||
this.stock = stock;
|
this.stock = stock;
|
||||||
this.segmentJump = (int) Math.floor(segment/maxDistance);
|
this.segmentSize = segmentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PathRoute> getPaths(Vendor from, Vendor to, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
|
public List<PathRoute> getPaths(Vendor from, Vendor to, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
|
||||||
if (segmentJump == 0){
|
|
||||||
RouteGraph sGraph = new RouteGraph(from, vendors, stock, maxDistance, true, jumps);
|
|
||||||
segmentJump = sGraph.getMinJumps() > 1 ? sGraph.getMinJumps()-1 : sGraph.getMinJumps();
|
|
||||||
}
|
|
||||||
return POOL.invoke(new SegmentSearcher(from, to, vendors, jumps, balance, cargo, limit));
|
return POOL.invoke(new SegmentSearcher(from, to, vendors, jumps, balance, cargo, limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PathRoute> getPaths(Vendor from, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
|
public List<PathRoute> getPaths(Vendor from, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
|
||||||
if (segmentJump == 0){
|
|
||||||
RouteGraph sGraph = new RouteGraph(from, vendors, stock, maxDistance, true, jumps);
|
|
||||||
segmentJump = sGraph.getMinJumps() > 1 ? sGraph.getMinJumps()-1 : sGraph.getMinJumps();
|
|
||||||
}
|
|
||||||
return POOL.invoke(new SegmentSearcher(from, null, vendors, jumps, balance, cargo, limit));
|
return POOL.invoke(new SegmentSearcher(from, null, vendors, jumps, balance, cargo, limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SegmentSearcher extends RecursiveTask<List<PathRoute>> {
|
public class SegmentSearcher extends RecursiveTask<List<PathRoute>> {
|
||||||
private final Vendor source;
|
protected final Vendor source;
|
||||||
private final Vendor target;
|
protected final Vendor target;
|
||||||
private final Collection<Vendor> vendors;
|
protected final Collection<Vendor> vendors;
|
||||||
private final int jumps;
|
protected final int jumps;
|
||||||
private final double balance;
|
protected final double balance;
|
||||||
private final int cargo;
|
protected final int cargo;
|
||||||
private int limit;
|
protected int limit;
|
||||||
|
|
||||||
public SegmentSearcher(Vendor source, Vendor target, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit) {
|
public SegmentSearcher(Vendor source, Vendor target, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
@@ -64,15 +59,17 @@ public class RouteSearcher {
|
|||||||
@Override
|
@Override
|
||||||
protected List<PathRoute> compute() {
|
protected List<PathRoute> compute() {
|
||||||
LOG.trace("Start search route to {} from {}, jumps {}", source, target, jumps);
|
LOG.trace("Start search route to {} from {}, jumps {}", source, target, jumps);
|
||||||
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, Math.min(jumps, segmentJump));
|
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, jumps, true);
|
||||||
sGraph.setLimit(cargo);
|
int jumpsToAll = sGraph.getMinJumps();
|
||||||
|
LOG.trace("Segment jumps {}", jumpsToAll);
|
||||||
|
sGraph.setCargo(cargo);
|
||||||
sGraph.setBalance(balance);
|
sGraph.setBalance(balance);
|
||||||
List<PathRoute> res = new ArrayList<>(limit);
|
List<PathRoute> res = new ArrayList<>(limit);
|
||||||
if (jumps <= segmentJump){
|
if (jumps <= jumpsToAll){
|
||||||
LOG.trace("Is last segment");
|
LOG.trace("Is last segment");
|
||||||
List<Path<Vendor>> paths;
|
List<Path<Vendor>> paths;
|
||||||
if (target == null){
|
if (target == null){
|
||||||
paths = sGraph.getPaths(10);
|
paths = sGraph.getPaths(limit);
|
||||||
} else {
|
} else {
|
||||||
paths = sGraph.getPathsTo(target, limit);
|
paths = sGraph.getPathsTo(target, limit);
|
||||||
}
|
}
|
||||||
@@ -81,7 +78,7 @@ public class RouteSearcher {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG.trace("Split to segments");
|
LOG.trace("Split to segments");
|
||||||
List<Path<Vendor>> paths = sGraph.getPaths(1);
|
List<Path<Vendor>> paths = sGraph.getPaths(getPathsOnSegmentCount(sGraph), jumpsToAll-1).getList();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
ArrayList<SegmentSearcher> subTasks = new ArrayList<>(THRESHOLD);
|
ArrayList<SegmentSearcher> subTasks = new ArrayList<>(THRESHOLD);
|
||||||
while (i < paths.size()) {
|
while (i < paths.size()) {
|
||||||
@@ -89,7 +86,7 @@ public class RouteSearcher {
|
|||||||
for (int taskIndex = 0; taskIndex < THRESHOLD && i+taskIndex < paths.size(); taskIndex++) {
|
for (int taskIndex = 0; taskIndex < THRESHOLD && i+taskIndex < paths.size(); taskIndex++) {
|
||||||
PathRoute path = (PathRoute) paths.get(i+taskIndex);
|
PathRoute path = (PathRoute) paths.get(i+taskIndex);
|
||||||
double newBalance = balance + path.getRoot().getProfit();
|
double newBalance = balance + path.getRoot().getProfit();
|
||||||
SegmentSearcher task = new SegmentSearcher(path.get(), target, vendors, jumps - segmentJump, newBalance, cargo, (int) Math.ceil(limit / 2.0));
|
SegmentSearcher task = new SegmentSearcher(path.get(), target, vendors, jumps - path.getLength(), newBalance, cargo, 1);
|
||||||
task.fork();
|
task.fork();
|
||||||
subTasks.add(task);
|
subTasks.add(task);
|
||||||
}
|
}
|
||||||
@@ -100,9 +97,18 @@ public class RouteSearcher {
|
|||||||
i+=subTasks.size();
|
i+=subTasks.size();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finish(res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getPathsOnSegmentCount(RouteGraph graph){
|
||||||
|
if (segmentSize ==0){
|
||||||
|
return graph.vertexes.size()*graph.minJumps;
|
||||||
|
} else {
|
||||||
|
return segmentSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void add(SegmentSearcher task, PathRoute path, List<PathRoute> res){
|
private void add(SegmentSearcher task, PathRoute path, List<PathRoute> res){
|
||||||
List<PathRoute> tail = task.join();
|
List<PathRoute> tail = task.join();
|
||||||
@@ -111,10 +117,15 @@ public class RouteSearcher {
|
|||||||
} else {
|
} else {
|
||||||
path.add(tail.get(0), false);
|
path.add(tail.get(0), false);
|
||||||
path.sort(balance, cargo);
|
path.sort(balance, cargo);
|
||||||
RouteGraph.addToTop(res, path.getEnd(), limit, RouteGraph.comparator);
|
TopList.addToTop(res, path.getEnd(), limit, RouteGraph.byProfitComparator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void finish(List<PathRoute> res){
|
||||||
|
if (res.size() < limit)
|
||||||
|
res.sort(RouteGraph.byProfitComparator);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
91
core/src/main/java/ru/trader/graph/TopList.java
Normal file
91
core/src/main/java/ru/trader/graph/TopList.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package ru.trader.graph;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class TopList<T> {
|
||||||
|
protected final List<T> list;
|
||||||
|
protected final int limit;
|
||||||
|
protected final Comparator<T> comparator;
|
||||||
|
|
||||||
|
public TopList(int limit) {
|
||||||
|
this(limit, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public TopList(int limit, Comparator<T> comparator) {
|
||||||
|
this.list = new ArrayList<>(limit);
|
||||||
|
this.limit = limit;
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
//return true if is last entry or list is full
|
||||||
|
public boolean add(T entry){
|
||||||
|
if (comparator != null){
|
||||||
|
addToTop(list, entry, limit, comparator);
|
||||||
|
} else {
|
||||||
|
if (list.size() >= limit) return false;
|
||||||
|
list.add(entry);
|
||||||
|
if (list.size() >= limit) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> getList() {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void addToGroupTop(List<T> list, T entry, int limit, Comparator<T> comparator, Function<T, Integer> getGroup, int groupSize) {
|
||||||
|
boolean isFull = list.size() >= limit;
|
||||||
|
int group = getGroup.apply(entry);
|
||||||
|
int groupStart = groupSize * group;
|
||||||
|
int groupEnd = groupSize * (group + 1);
|
||||||
|
if (!isFull){
|
||||||
|
if (groupStart >= list.size()) groupStart = list.size();
|
||||||
|
if (groupEnd >= list.size()) groupEnd = list.size();
|
||||||
|
}
|
||||||
|
List<T> groupList = list.subList(groupStart, groupEnd);
|
||||||
|
T removeEntry = addToTop(groupList, entry, groupSize, comparator);
|
||||||
|
if (!isFull && removeEntry != null && group != getGroup.apply(removeEntry)){
|
||||||
|
addToGroupTop(list, removeEntry, limit, comparator, getGroup, groupSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T addToTop(List<T> list, T entry, int limit, Comparator<T> comparator) {
|
||||||
|
if (list.size() == limit) {
|
||||||
|
int index = Collections.binarySearch(list, entry, comparator);
|
||||||
|
if (index < 0) index = -1 - index;
|
||||||
|
if (index == limit) return null;
|
||||||
|
list.add(index, entry);
|
||||||
|
return list.remove(limit);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (list.size() < limit - 1) {
|
||||||
|
list.add(entry);
|
||||||
|
} else {
|
||||||
|
list.add(entry);
|
||||||
|
list.sort(comparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void addAllToTop(List<T> list, Collection<T> sortEntries, int limit, Comparator<T> comparator) {
|
||||||
|
for (T entry : sortEntries) {
|
||||||
|
if (list.size() == limit) {
|
||||||
|
int index = Collections.binarySearch(list, entry, comparator);
|
||||||
|
if (index < 0) index = -1 - index;
|
||||||
|
if (index == limit) return;
|
||||||
|
list.add(index, entry);
|
||||||
|
list.remove(limit);
|
||||||
|
} else {
|
||||||
|
if (list.size() < limit - 1) {
|
||||||
|
list.add(entry);
|
||||||
|
} else {
|
||||||
|
list.add(entry);
|
||||||
|
list.sort(comparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import ru.trader.graph.PathRoute;
|
|||||||
import ru.trader.store.Store;
|
import ru.trader.store.Store;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public class MarketAnalyzerTest2 extends Assert {
|
public class MarketAnalyzerTest2 extends Assert {
|
||||||
private static MarketAnalyzer analyzer;
|
private static MarketAnalyzer analyzer;
|
||||||
@@ -32,11 +33,13 @@ public class MarketAnalyzerTest2 extends Assert {
|
|||||||
analyzer.setCargo(440);analyzer.setTank(40);analyzer.setMaxDistance(13.4);analyzer.setJumps(6);
|
analyzer.setCargo(440);analyzer.setTank(40);analyzer.setMaxDistance(13.4);analyzer.setJumps(6);
|
||||||
Collection<PathRoute> paths = analyzer.getPaths(ithaca, ithaca, 6000000);
|
Collection<PathRoute> paths = analyzer.getPaths(ithaca, ithaca, 6000000);
|
||||||
PathRoute expect = PathRoute.toPathRoute(ithaca, morgor, lhs3006, lhs3262, lhs3006, morgor, ithaca);
|
PathRoute expect = PathRoute.toPathRoute(ithaca, morgor, lhs3006, lhs3262, lhs3006, morgor, ithaca);
|
||||||
PathRoute actual = paths.stream().filter((p)->p.equals(expect)).findFirst().get().getRoot();
|
Optional<PathRoute> path = paths.stream().filter((p)->p.equals(expect)).findFirst();
|
||||||
|
assertTrue(path.isPresent());
|
||||||
|
PathRoute actual = path.get().getRoot();
|
||||||
TestUtil.assertCollectionContain(paths, expect);
|
TestUtil.assertCollectionContain(paths, expect);
|
||||||
assertEquals(981200, actual.getProfit(), 0.00001);
|
assertEquals(981200, actual.getProfit(), 0.00001);
|
||||||
assertEquals(72.42, actual.getDistance(), 0.01);
|
assertEquals(72.42, actual.getDistance(), 0.01);
|
||||||
assertEquals(2, actual.getLandsCount());
|
assertEquals(2, actual.getLandsCount());
|
||||||
assertEquals(490600, actual.getProfit()/actual.getLandsCount() , 0.00001);
|
assertEquals(490600, actual.getAvgProfit() , 0.00001);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class RouteGraphTest extends Assert {
|
|||||||
public void testRoutes() throws Exception {
|
public void testRoutes() throws Exception {
|
||||||
RouteGraph graph = new RouteGraph(v1, market.get(), 1, 1, true, 4);
|
RouteGraph graph = new RouteGraph(v1, market.get(), 1, 1, true, 4);
|
||||||
graph.setBalance(500);
|
graph.setBalance(500);
|
||||||
graph.setLimit(5);
|
graph.setCargo(5);
|
||||||
//Profit: 150 180 200 230 670 620 950 890 620 950 1015 1180 890 950 930
|
//Profit: 150 180 200 230 670 620 950 890 620 950 1015 1180 890 950 930
|
||||||
//Landings: 1 2 3 4 4 2 3 3 2 3 4 4 3 3 4
|
//Landings: 1 2 3 4 4 2 3 3 2 3 4 4 3 3 4
|
||||||
//Prof: 150 90 66.66 57.5 167.5 310 316.66 296.66 310 316.66 253.75 295 296.66 316.66 232.5
|
//Prof: 150 90 66.66 57.5 167.5 310 316.66 296.66 310 316.66 253.75 295 296.66 316.66 232.5
|
||||||
|
|||||||
@@ -25,11 +25,10 @@ public class RouteSearcherTest extends Assert {
|
|||||||
// Ithaca (Palladium to LHS 3262) -> Morgor -> LHS 3006 -> LHS 3262 (Consumer Technology to Ithaca) -> LHS 3006 -> Morgor -> Ithaca
|
// 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
|
// Profit: 981200, avg: 490600, distance: 67.5, lands: 2
|
||||||
Vendor ithaca = market.get().stream().filter((v)->v.getName().equals("Ithaca")).findFirst().get();
|
Vendor ithaca = market.get().stream().filter((v)->v.getName().equals("Ithaca")).findFirst().get();
|
||||||
Vendor lhs3262 = market.get().stream().filter((v)->v.getName().equals("LHS 3262")).findFirst().get();
|
|
||||||
|
|
||||||
RouteSearcher searcher = new RouteSearcher(13.4, 40, 50);
|
RouteSearcher searcher = new RouteSearcher(13.4, 40);
|
||||||
RouteGraph graph = new RouteGraph(ithaca, market.get(), 40, 13.4, true, 6);
|
RouteGraph graph = new RouteGraph(ithaca, market.get(), 40, 13.4, true, 6);
|
||||||
graph.setLimit(440);
|
graph.setCargo(440);
|
||||||
graph.setBalance(6000000);
|
graph.setBalance(6000000);
|
||||||
|
|
||||||
|
|
||||||
@@ -40,13 +39,38 @@ public class RouteSearcherTest extends Assert {
|
|||||||
PathRoute actual = apaths.stream().findFirst().get();
|
PathRoute actual = apaths.stream().findFirst().get();
|
||||||
assertTrue("Routes is different",expect.isRoute(actual));
|
assertTrue("Routes is different",expect.isRoute(actual));
|
||||||
|
|
||||||
graph = new RouteGraph(lhs3262, market.get(), 40, 13.4, true, 6);
|
}
|
||||||
graph.setLimit(440);
|
|
||||||
|
@Test
|
||||||
|
public void testRoutes2() throws Exception {
|
||||||
|
// Balance: 6000000, cargo: 440, tank: 40, distance: 13.6, 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();
|
||||||
|
Vendor lhs3262 = market.get().stream().filter((v)->v.getName().equals("LHS 3262")).findFirst().get();
|
||||||
|
|
||||||
|
RouteSearcher searcher = new RouteSearcher(13.6, 40);
|
||||||
|
RouteGraph graph = new RouteGraph(ithaca, market.get(), 40, 13.6, true, 6);
|
||||||
|
graph.setCargo(440);
|
||||||
|
graph.setBalance(6000000);
|
||||||
|
|
||||||
|
List<Path<Vendor>> epaths = graph.getPathsTo(ithaca, 10);
|
||||||
|
PathRoute expect = epaths.stream().map(p -> (PathRoute) p).findFirst().get();
|
||||||
|
|
||||||
|
List<PathRoute> apaths = searcher.getPaths(ithaca, ithaca, market.get(), 6, 6000000, 440, 10);
|
||||||
|
PathRoute actual = apaths.stream().findFirst().get();
|
||||||
|
assertTrue("Routes is different",expect.isRoute(actual));
|
||||||
|
|
||||||
|
graph = new RouteGraph(lhs3262, market.get(), 40, 13.6, true, 6);
|
||||||
|
graph.setCargo(440);
|
||||||
graph.setBalance(6000000);
|
graph.setBalance(6000000);
|
||||||
|
|
||||||
expect = graph.getPathsTo(lhs3262, 10).stream().map(p -> (PathRoute)p).findFirst().get();
|
expect = graph.getPathsTo(lhs3262, 10).stream().map(p -> (PathRoute)p).findFirst().get();
|
||||||
actual = searcher.getPaths(lhs3262, lhs3262, market.get(), 6, 6000000, 440, 10).stream().findFirst().get();
|
apaths = searcher.getPaths(lhs3262, lhs3262, market.get(), 6, 6000000, 440, 10);
|
||||||
assertTrue("Routes is different",expect.isRoute(actual));
|
actual = apaths.stream().findFirst().get();
|
||||||
|
assertEquals("Routes is different",expect.getAvgProfit(), actual.getAvgProfit(), 0.00001);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
87
core/src/test/java/ru/trader/graph/TopListTest.java
Normal file
87
core/src/test/java/ru/trader/graph/TopListTest.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package ru.trader.graph;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class TopListTest extends Assert {
|
||||||
|
|
||||||
|
private static final Function<Integer, Integer> getGroup = (o1) -> Math.floorDiv(o1, 10);
|
||||||
|
|
||||||
|
private static final Comparator<Integer> groupcomp = (o1, o2) -> {
|
||||||
|
int cmp = Integer.compare(getGroup.apply(o1), getGroup.apply(o2));
|
||||||
|
if (cmp !=0 ) return cmp;
|
||||||
|
return o1.compareTo(o2);
|
||||||
|
};
|
||||||
|
|
||||||
|
private void add(List<Integer> list, Integer entry){
|
||||||
|
TopList.addToGroupTop(list, entry, 10, groupcomp, getGroup, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToGroup() throws Exception {
|
||||||
|
ArrayList<Integer> top = new ArrayList<>(10);
|
||||||
|
add(top, 5);
|
||||||
|
add(top, 15);
|
||||||
|
add(top, 22);
|
||||||
|
add(top, 34);
|
||||||
|
add(top, 36);
|
||||||
|
add(top, 21);
|
||||||
|
add(top, 7);
|
||||||
|
add(top, 6);
|
||||||
|
add(top, 3);
|
||||||
|
|
||||||
|
assertEquals(4, top.size());
|
||||||
|
assertEquals(3, top.get(0).intValue());
|
||||||
|
assertEquals(15, top.get(1).intValue());
|
||||||
|
assertEquals(21, top.get(2).intValue());
|
||||||
|
assertEquals(34, top.get(3).intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToGroup2() throws Exception {
|
||||||
|
ArrayList<Integer> top = new ArrayList<>(10);
|
||||||
|
add(top, 36);
|
||||||
|
add(top, 15);
|
||||||
|
add(top, 22);
|
||||||
|
add(top, 6);
|
||||||
|
add(top, 34);
|
||||||
|
add(top, 5);
|
||||||
|
add(top, 21);
|
||||||
|
add(top, 7);
|
||||||
|
add(top, 3);
|
||||||
|
|
||||||
|
assertEquals(4, top.size());
|
||||||
|
assertEquals(3, top.get(0).intValue());
|
||||||
|
assertEquals(15, top.get(1).intValue());
|
||||||
|
assertEquals(21, top.get(2).intValue());
|
||||||
|
assertEquals(34, top.get(3).intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddToGroup3() throws Exception {
|
||||||
|
ArrayList<Integer> top = new ArrayList<>(10);
|
||||||
|
add(top, 21);
|
||||||
|
add(top, 34);
|
||||||
|
add(top, 36);
|
||||||
|
add(top, 3);
|
||||||
|
add(top, 15);
|
||||||
|
add(top, 22);
|
||||||
|
add(top, 6);
|
||||||
|
add(top, 34);
|
||||||
|
add(top, 5);
|
||||||
|
add(top, 7);
|
||||||
|
|
||||||
|
assertEquals(4, top.size());
|
||||||
|
assertEquals(3, top.get(0).intValue());
|
||||||
|
assertEquals(15, top.get(1).intValue());
|
||||||
|
assertEquals(21, top.get(2).intValue());
|
||||||
|
assertEquals(34, top.get(3).intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user