implement route filler, changes in scorer
This commit is contained in:
57
core/src/main/java/ru/trader/analysis/MarketUtils.java
Normal file
57
core/src/main/java/ru/trader/analysis/MarketUtils.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.Offer;
|
||||||
|
import ru.trader.core.Order;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MarketUtils {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(MarketUtils.class);
|
||||||
|
|
||||||
|
public static List<Order> getStack(List<Order> orders, double balance, long cargo){
|
||||||
|
LOG.trace("Fill stack orders {}, balance {}", orders, balance);
|
||||||
|
orders.forEach(o -> o.setMax(balance, cargo));
|
||||||
|
LOG.trace("Simple sort");
|
||||||
|
orders.sort(Comparator.<Order>reverseOrder());
|
||||||
|
LOG.trace("New order of orders {}", orders);
|
||||||
|
List<Order> stack = new ArrayList<>();
|
||||||
|
long count = cargo;
|
||||||
|
double remain = balance;
|
||||||
|
for (Order order : orders) {
|
||||||
|
order = new Order(order.getSell(), order.getBuy(), remain, count);
|
||||||
|
LOG.trace("Next best order {}", order);
|
||||||
|
if (order.getProfit() > 0) {
|
||||||
|
stack.add(order);
|
||||||
|
remain -= order.getCount() * order.getSell().getPrice();
|
||||||
|
count -= order.getCount();
|
||||||
|
LOG.trace("Remain cargo {}, remain balance {}", count, remain);
|
||||||
|
} else {
|
||||||
|
LOG.trace("Low profit, stopped");
|
||||||
|
remain = 0;
|
||||||
|
}
|
||||||
|
if (count <= 0 || remain <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.trace("Stack: {}", stack);
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Order> getOrders(Vendor seller, Vendor buyer){
|
||||||
|
LOG.trace("Get orders from {}, to {}", seller, buyer);
|
||||||
|
List<Order> orders = new ArrayList<>();
|
||||||
|
for (Offer sell : seller.getAllSellOffers()) {
|
||||||
|
Offer buy = buyer.getBuy(sell.getItem());
|
||||||
|
if (buy != null) {
|
||||||
|
Order order = new Order(sell, buy, 1);
|
||||||
|
orders.add(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
}
|
||||||
120
core/src/main/java/ru/trader/analysis/Route.java
Normal file
120
core/src/main/java/ru/trader/analysis/Route.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Route {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(Route.class);
|
||||||
|
|
||||||
|
private final List<RouteEntry> entries;
|
||||||
|
private double profit = 0;
|
||||||
|
private double balance = 0;
|
||||||
|
private double distance = 0;
|
||||||
|
private int lands = 0;
|
||||||
|
|
||||||
|
public Route(RouteEntry root) {
|
||||||
|
entries = new ArrayList<>();
|
||||||
|
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 List<RouteEntry> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBalance(double balance){
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfit() {
|
||||||
|
return profit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLands() {
|
||||||
|
return lands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(RouteEntry entry){
|
||||||
|
LOG.trace("Add entry {} to route {}", entry, this);
|
||||||
|
entries.add(entry);
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAll(Collection<RouteEntry> entries){
|
||||||
|
LOG.trace("Add {} entries {} to route {}", entries, this);
|
||||||
|
entries.addAll(entries);
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Vendor> getVendors() {
|
||||||
|
return getVendors(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Vendor> getVendors(int index){
|
||||||
|
if (index < 0 || index >= entries.size()) return Collections.emptyList();
|
||||||
|
Collection<Vendor> vendors = new HashSet<>();
|
||||||
|
for (int i = index; i < entries.size(); i++) {
|
||||||
|
RouteEntry entry = entries.get(i);
|
||||||
|
vendors.add(entry.getVendor());
|
||||||
|
}
|
||||||
|
return vendors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Collection<Vendor> vendors){
|
||||||
|
return vendors.isEmpty()
|
||||||
|
|| vendors.size() <= entries.size()
|
||||||
|
&& vendors.stream().allMatch(v -> entries.stream().anyMatch(e -> v.equals(e.getVendor())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void join(Route route){
|
||||||
|
LOG.trace("Join route {}", route);
|
||||||
|
RouteEntry end = entries.get(entries.size()-1);
|
||||||
|
if (route.entries.get(0).is(end.getVendor())){
|
||||||
|
entries.remove(entries.size()-1);
|
||||||
|
} else {
|
||||||
|
LOG.trace("Is not connected route, set refill");
|
||||||
|
end.setRefill(true);
|
||||||
|
}
|
||||||
|
entries.addAll(route.entries);
|
||||||
|
updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateStats(){
|
||||||
|
LOG.trace("Update stats, old: profit={}, distance={}, lands={}", profit, distance, lands);
|
||||||
|
profit = 0; distance = 0; lands = 0;
|
||||||
|
if (entries.isEmpty()) return;
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
for (int i = 1; i < entries.size(); i++) {
|
||||||
|
RouteEntry next = entries.get(i);
|
||||||
|
distance += entry.getVendor().getDistance(next.getVendor());
|
||||||
|
profit += entry.getProfit();
|
||||||
|
if (entry.isLand()){
|
||||||
|
lands++;
|
||||||
|
}
|
||||||
|
entry = next;
|
||||||
|
}
|
||||||
|
LOG.trace("new stats profit={}, distance={}, lands={}", profit, distance, lands);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
77
core/src/main/java/ru/trader/analysis/RouteEntry.java
Normal file
77
core/src/main/java/ru/trader/analysis/RouteEntry.java
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.core.Order;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RouteEntry {
|
||||||
|
private final Vendor vendor;
|
||||||
|
private final double fuel;
|
||||||
|
private final List<Order> orders;
|
||||||
|
private boolean land;
|
||||||
|
private boolean refill;
|
||||||
|
|
||||||
|
|
||||||
|
public RouteEntry(Vendor vendor, boolean refill, double fuel) {
|
||||||
|
orders = new ArrayList<>();
|
||||||
|
this.vendor = vendor;
|
||||||
|
this.refill = refill;
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vendor getVendor() {
|
||||||
|
return vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Vendor vendor){
|
||||||
|
return vendor.equals(this.vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRefill() {
|
||||||
|
return refill;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRefill(boolean refill) {
|
||||||
|
this.refill = refill;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getFuel() {
|
||||||
|
return fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Order order){
|
||||||
|
orders.add(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAll(Collection<Order> orders){
|
||||||
|
this.orders.addAll(orders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Order> getOrders() {
|
||||||
|
return orders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearOrders(){
|
||||||
|
orders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfit(){
|
||||||
|
return orders.stream().mapToDouble(Order::getProfit).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLand(){
|
||||||
|
return land || refill || !orders.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLand(boolean land) {
|
||||||
|
this.land = land;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTransit(){
|
||||||
|
return !isLand();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
353
core/src/main/java/ru/trader/analysis/RouteFiller.java
Normal file
353
core/src/main/java/ru/trader/analysis/RouteFiller.java
Normal file
@@ -0,0 +1,353 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.Offer;
|
||||||
|
import ru.trader.core.Order;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class RouteFiller {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(Route.class);
|
||||||
|
private final static OrderStack TRANSIT = null;
|
||||||
|
|
||||||
|
private final double balance;
|
||||||
|
private final long cargo;
|
||||||
|
private final Scorer scorer;
|
||||||
|
private Route route;
|
||||||
|
private List<OEntry> oList;
|
||||||
|
|
||||||
|
public RouteFiller(Scorer scorer) {
|
||||||
|
this.scorer = scorer;
|
||||||
|
this.balance = scorer.getProfile().getBalance();
|
||||||
|
this.cargo = scorer.getProfile().getShip().getCargo();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fill(Route route){
|
||||||
|
this.route = route;
|
||||||
|
route.setBalance(balance);
|
||||||
|
fillOrders();
|
||||||
|
updateEntries();
|
||||||
|
route.updateStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillOrders(){
|
||||||
|
fillOrdersList();
|
||||||
|
sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillOrdersList(){
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
oList = new ArrayList<>(entries.size());
|
||||||
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
|
RouteEntry rEntry = entries.get(i);
|
||||||
|
OEntry entry = new OEntry(rEntry.getVendor(), rEntry.isRefill(), rEntry.getFuel());
|
||||||
|
oList.add(entry);
|
||||||
|
Vendor seller = entries.get(i).getVendor();
|
||||||
|
LOG.trace("Fill orders for {}", seller);
|
||||||
|
final int nextIndex = i+1;
|
||||||
|
Collection<Vendor> vendors = route.getVendors(nextIndex);
|
||||||
|
for (Offer sell : seller.getAllSellOffers()) {
|
||||||
|
for (Vendor buyer : vendors) {
|
||||||
|
Offer buy = buyer.getBuy(sell.getItem());
|
||||||
|
if (buy != null) {
|
||||||
|
Order order = new Order(sell, buy, 1);
|
||||||
|
if (order.getProfit() <= 0) {
|
||||||
|
LOG.trace("{} - is no profit, skip", order);
|
||||||
|
} else {
|
||||||
|
entry.add(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sort() {
|
||||||
|
LOG.trace("Start forward sort");
|
||||||
|
for (int i = 0; i < oList.size(); i++) {
|
||||||
|
OEntry entry = oList.get(i);
|
||||||
|
entry.setBalance(getBalance(entry.vendor, i - 1));
|
||||||
|
entry.fillToMax(i+1);
|
||||||
|
}
|
||||||
|
LOG.trace("Start backward sort");
|
||||||
|
for (int i = oList.size() - 1; i >= 0; i--) {
|
||||||
|
OEntry entry = oList.get(i);
|
||||||
|
OrderStack best = entry.getBest();
|
||||||
|
final int nextIndex = i+1;
|
||||||
|
entry.setLands(getLands(best, nextIndex) + (best != TRANSIT || entry.refill ? 1 : 0));
|
||||||
|
BackwardComparator comparator = new BackwardComparator(nextIndex);
|
||||||
|
entry.sort(comparator);
|
||||||
|
best = entry.getBest();
|
||||||
|
entry.setFullScore(comparator.getScore(best));
|
||||||
|
entry.setLands(getLands(best, nextIndex) + (best != TRANSIT || entry.refill ? 1 : 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getIndex(Vendor vendor, int startIndex){
|
||||||
|
for (int i = startIndex; i < oList.size(); i++) {
|
||||||
|
if (oList.get(i).vendor.equals(vendor)) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getBalance(Vendor vendor, int startIndex){
|
||||||
|
double res = 0;
|
||||||
|
double score = 0;
|
||||||
|
double fuel = 0;
|
||||||
|
int refills = 0;
|
||||||
|
int jumps = 0;
|
||||||
|
for (int i = startIndex; i >= 0; i--) {
|
||||||
|
OEntry entry = oList.get(i);
|
||||||
|
fuel += entry.fuel;
|
||||||
|
if (entry.fuel > 0) jumps++;
|
||||||
|
OrderStack best = entry.getStack(vendor);
|
||||||
|
if (best == null) continue;
|
||||||
|
double profit = best.getProfit();
|
||||||
|
if (res < profit){
|
||||||
|
double newScore = scorer.getScore(entry.vendor, profit, jumps, refills, fuel);
|
||||||
|
if (newScore > score) {
|
||||||
|
score = newScore;
|
||||||
|
res = profit;
|
||||||
|
LOG.trace("Orders {} is best to {}, score {}, profit {}", best, vendor, score, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry.refill){
|
||||||
|
refills++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.trace("Max score on {} = {}, profit {}", vendor, score, res);
|
||||||
|
return balance + res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private double getScore(OrderStack order, int startIndex){
|
||||||
|
double fuel = 0;
|
||||||
|
int refills = 0;
|
||||||
|
int jumps = 0;
|
||||||
|
Vendor buyer = order.getBuyer();
|
||||||
|
for (int i = startIndex; i < oList.size(); i++) {
|
||||||
|
OEntry entry = oList.get(i);
|
||||||
|
fuel += entry.fuel;
|
||||||
|
if (entry.fuel > 0) jumps++;
|
||||||
|
if (entry.vendor.equals(buyer)){
|
||||||
|
return scorer.getScore(order.getBuyer(), order.getProfit(), jumps, refills + entry.lands, fuel);
|
||||||
|
}
|
||||||
|
if (entry.refill){
|
||||||
|
refills++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private double getFullScore(OrderStack order, int startIndex){
|
||||||
|
if (startIndex >= oList.size()) return 0;
|
||||||
|
if (order == TRANSIT) return oList.get(startIndex).score;
|
||||||
|
int index = getIndex(order.getBuyer(), startIndex);
|
||||||
|
if (index > 0) {
|
||||||
|
return oList.get(index).score + getScore(order, index);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getLands(OrderStack order, int startIndex) {
|
||||||
|
if (startIndex >= oList.size()) return 1;
|
||||||
|
if (order == TRANSIT) return oList.get(startIndex).lands;
|
||||||
|
int index = getIndex(order.getBuyer(), startIndex);
|
||||||
|
if (index > 0) {
|
||||||
|
return oList.get(index).lands;
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(String.format("Not found buyer for order %s", order));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateEntries(){
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
OrderStack best = TRANSIT;
|
||||||
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
|
RouteEntry entry = entries.get(i);
|
||||||
|
entry.clearOrders();
|
||||||
|
entry.setLand(false);
|
||||||
|
OEntry o = oList.get(i);
|
||||||
|
if (best == TRANSIT || o.vendor.equals(best.getBuyer())){
|
||||||
|
if (best != TRANSIT)
|
||||||
|
entry.setLand(true);
|
||||||
|
best = o.getBest();
|
||||||
|
if (best != TRANSIT)
|
||||||
|
entry.addAll(best.bestOrders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ForwardComparator implements Comparator<OrderStack> {
|
||||||
|
private final HashMap<OrderStack, Double> cache = new HashMap<>(10);
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private ForwardComparator(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(OrderStack o1, OrderStack o2) {
|
||||||
|
if (o1 != TRANSIT && o2 != TRANSIT){
|
||||||
|
double score1 = getScore(o1);
|
||||||
|
double score2 = getScore(o2);
|
||||||
|
return Double.compare(score2, score1);
|
||||||
|
}
|
||||||
|
return o1 == TRANSIT ? o2 == TRANSIT ? 0 : Double.compare(o2.getProfit(), 0) : Double.compare(0, o1.getProfit());
|
||||||
|
}
|
||||||
|
|
||||||
|
private double getScore(OrderStack stack){
|
||||||
|
Double score = cache.get(stack);
|
||||||
|
if (score == null){
|
||||||
|
score = RouteFiller.this.getScore(stack, index);
|
||||||
|
cache.put(stack, score);
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class BackwardComparator implements Comparator<OrderStack> {
|
||||||
|
private final HashMap<OrderStack, Double> cache = new HashMap<>(10);
|
||||||
|
private final int index;
|
||||||
|
|
||||||
|
private BackwardComparator(int index) {
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(OrderStack o1, OrderStack o2) {
|
||||||
|
double score1 = getScore(o1);
|
||||||
|
double score2 = getScore(o2);
|
||||||
|
return Double.compare(score2, score1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScore(OrderStack stack){
|
||||||
|
Double score = cache.get(stack);
|
||||||
|
if (score == null){
|
||||||
|
score = RouteFiller.this.getFullScore(stack, index);
|
||||||
|
cache.put(stack, score);
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OEntry {
|
||||||
|
private final List<OrderStack> orders;
|
||||||
|
|
||||||
|
private final Vendor vendor;
|
||||||
|
private final boolean refill;
|
||||||
|
private final double fuel;
|
||||||
|
private double balance;
|
||||||
|
private double score;
|
||||||
|
private int lands;
|
||||||
|
|
||||||
|
|
||||||
|
private OEntry(Vendor vendor, boolean refill, double fuel){
|
||||||
|
this.vendor = vendor;
|
||||||
|
orders = new ArrayList<>();
|
||||||
|
orders.add(TRANSIT);
|
||||||
|
this.refill = refill;
|
||||||
|
this.fuel = fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Order order){
|
||||||
|
LOG.trace("Add order {}", order);
|
||||||
|
OrderStack stack = getStack(order.getBuyer());
|
||||||
|
if (stack == null){
|
||||||
|
stack = new OrderStack();
|
||||||
|
orders.add(stack);
|
||||||
|
}
|
||||||
|
stack.add(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrderStack getStack(Vendor vendor){
|
||||||
|
OrderStack stack = null;
|
||||||
|
for (OrderStack s : orders) {
|
||||||
|
if (s == TRANSIT) continue;
|
||||||
|
if (s.is(vendor)){
|
||||||
|
stack = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalance(double balance){
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillToMax(int nextIndex){
|
||||||
|
orders.forEach(o -> {
|
||||||
|
if (o != TRANSIT)
|
||||||
|
o.fillBest(balance);
|
||||||
|
});
|
||||||
|
sort(new ForwardComparator(nextIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfit(){
|
||||||
|
OrderStack best = orders.get(0);
|
||||||
|
return best.getProfit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFullScore(double score) {
|
||||||
|
LOG.trace("New full score {}", score);
|
||||||
|
this.score = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLands(int lands) {
|
||||||
|
LOG.trace("New lands count {}", lands);
|
||||||
|
this.lands = lands;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OrderStack getBest(){
|
||||||
|
return orders.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sort(Comparator<OrderStack> comparator) {
|
||||||
|
LOG.trace("Sort");
|
||||||
|
orders.sort(comparator);
|
||||||
|
LOG.trace("New order of orders {}", orders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class OrderStack {
|
||||||
|
private final List<Order> orders;
|
||||||
|
private final List<Order> bestOrders;
|
||||||
|
|
||||||
|
private OrderStack() {
|
||||||
|
orders = new ArrayList<>();
|
||||||
|
bestOrders = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Order order){
|
||||||
|
orders.add(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vendor getBuyer(){
|
||||||
|
return orders.isEmpty() ? null : orders.get(0).getBuyer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Vendor buyer){
|
||||||
|
return orders.isEmpty() || orders.get(0).isBuyer(buyer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillBest(double balance){
|
||||||
|
bestOrders.clear();
|
||||||
|
bestOrders.addAll(MarketUtils.getStack(orders, balance, cargo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getProfit(){
|
||||||
|
return bestOrders.stream().mapToDouble(Order::getProfit).sum();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + bestOrders + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package ru.trader.analysis;
|
package ru.trader.analysis;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import ru.trader.core.*;
|
import ru.trader.core.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@@ -8,25 +10,31 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class Scorer {
|
public class Scorer {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(Scorer.class);
|
||||||
|
|
||||||
private final Map<Item, Offer> sellOffers;
|
private final Map<Item, Offer> sellOffers;
|
||||||
private final Map<Item, Offer> buyOffers;
|
private final Map<Item, Offer> buyOffers;
|
||||||
private final FilteredMarket market;
|
private final FilteredMarket market;
|
||||||
private final Profile profile;
|
private final Profile profile;
|
||||||
|
|
||||||
private final double avgProfit;
|
private final double avgProfit;
|
||||||
|
private final double maxScore;
|
||||||
private final double avgDistance;
|
private final double avgDistance;
|
||||||
|
|
||||||
private int ordersCount = 5;
|
|
||||||
private double distanceRate = 1;
|
|
||||||
|
|
||||||
public Scorer(FilteredMarket market, Profile profile) {
|
public Scorer(FilteredMarket market, Profile profile) {
|
||||||
this.market = market;
|
this.market = market;
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
sellOffers = new HashMap<>(100, 0.9f);
|
sellOffers = new HashMap<>(100, 0.9f);
|
||||||
buyOffers = new HashMap<>(100, 0.9f);
|
buyOffers = new HashMap<>(100, 0.9f);
|
||||||
market.getItems().parallelStream().forEach(this::fillOffers);
|
market.getItems().parallelStream().forEach(this::fillOffers);
|
||||||
avgProfit = computeAvgProfit();
|
DoubleSummaryStatistics statProfit = computeProfit();
|
||||||
|
avgProfit = statProfit.getAverage()/profile.getShip().getCargo();
|
||||||
avgDistance = computeAvgDistance();
|
avgDistance = computeAvgDistance();
|
||||||
|
maxScore = getScore(0, statProfit.getMax()*2, 0,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Profile getProfile() {
|
||||||
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillOffers(Item item){
|
private void fillOffers(Item item){
|
||||||
@@ -40,12 +48,10 @@ public class Scorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeAvgProfit(){
|
private DoubleSummaryStatistics computeProfit(){
|
||||||
OptionalDouble avg = sellOffers.values().stream()
|
return sellOffers.values().stream()
|
||||||
.flatMap(this::mapToOrder)
|
.flatMap(this::mapToOrder)
|
||||||
.mapToDouble(o -> o.getProfit() / profile.getShip().getCargo())
|
.collect(Collectors.summarizingDouble(Order::getProfit));
|
||||||
.average();
|
|
||||||
return avg.orElse(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeAvgDistance(){
|
private double computeAvgDistance(){
|
||||||
@@ -53,18 +59,35 @@ public class Scorer {
|
|||||||
return res.orElse(0);
|
return res.orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOrdersCount(int ordersCount) {
|
|
||||||
this.ordersCount = ordersCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDistanceRate(double distanceRate) {
|
|
||||||
this.distanceRate = distanceRate;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getAvgProfit() {
|
public double getAvgProfit() {
|
||||||
return avgProfit;
|
return avgProfit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getMaxScore() {
|
||||||
|
return maxScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getFuel(double distance){
|
||||||
|
return profile.getShip().getFuelCost(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScore(Vendor vendor, double profit, int jumps, int lands, double fuel) {
|
||||||
|
return getScore(vendor.getDistance(), profit, jumps, lands, fuel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getScore(double distance, double profit, int jumps, int lands, double fuel){
|
||||||
|
LOG.trace("Compute score distance={}, profit={}, jumps={}, lands={}, fuel={}", distance, profit, jumps, lands, fuel);
|
||||||
|
double score = profit/profile.getShip().getCargo();
|
||||||
|
if (avgDistance > 0) {
|
||||||
|
score -= profile.getDistanceMult() * getAvgProfit() * (distance - avgDistance) / avgDistance;
|
||||||
|
}
|
||||||
|
score -= profile.getLandMult() * lands * getAvgProfit();
|
||||||
|
score -= profile.getFuelPrice() * fuel;
|
||||||
|
score -= profile.getJumpMult() * jumps * getAvgProfit();
|
||||||
|
LOG.trace("score={}", score);
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
public Score getScore(Vendor vendor){
|
public Score getScore(Vendor vendor){
|
||||||
return new Score(vendor);
|
return new Score(vendor);
|
||||||
}
|
}
|
||||||
@@ -116,13 +139,13 @@ public class Scorer {
|
|||||||
|
|
||||||
private DoubleSummaryStatistics computeProfits(Stream<Order> orders) {
|
private DoubleSummaryStatistics computeProfits(Stream<Order> orders) {
|
||||||
return orders.sorted(Comparator.<Order>reverseOrder())
|
return orders.sorted(Comparator.<Order>reverseOrder())
|
||||||
.limit(ordersCount)
|
.limit(profile.getScoreOrdersCount())
|
||||||
.collect(Collectors.summarizingDouble(o -> o.getProfit() / profile.getShip().getCargo()));
|
.collect(Collectors.summarizingDouble(Order::getProfit));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void computeScore(){
|
private void computeScore(){
|
||||||
score = (getSellProfit() + getBuyProfit())/2;
|
score = (getSellProfit() + getBuyProfit())/2;
|
||||||
score -= distanceRate * avgProfit * (vendor.getDistance() - avgDistance) / avgDistance;
|
score = Scorer.this.getScore(vendor, score, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -41,5 +41,12 @@ public abstract class AbstractOffer implements Offer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" + getVendor() +
|
||||||
|
","+ getType() +
|
||||||
|
"," + getCount()+
|
||||||
|
"," + getItem() +
|
||||||
|
"," +getPrice()+"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ public class Ship {
|
|||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setEngine(int clazz, char rating) {
|
||||||
|
this.engine = new Engine(clazz, rating);
|
||||||
|
}
|
||||||
|
|
||||||
public void setEngine(Engine engine) {
|
public void setEngine(Engine engine) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
}
|
}
|
||||||
|
|||||||
472
core/src/test/java/ru/trader/analysis/RouteFillerTest.java
Normal file
472
core/src/test/java/ru/trader/analysis/RouteFillerTest.java
Normal file
@@ -0,0 +1,472 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.TestUtil;
|
||||||
|
import ru.trader.core.*;
|
||||||
|
import ru.trader.store.simple.SimpleMarket;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RouteFillerTest extends Assert {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(RouteFillerTest.class);
|
||||||
|
|
||||||
|
private Market market;
|
||||||
|
private Item ITEM1;
|
||||||
|
private Item ITEM2;
|
||||||
|
private Item ITEM3;
|
||||||
|
private Item ITEM4;
|
||||||
|
private Vendor v1;
|
||||||
|
private Vendor v2;
|
||||||
|
private Vendor v3;
|
||||||
|
private Vendor v4;
|
||||||
|
private Vendor v5;
|
||||||
|
|
||||||
|
private RouteFiller getFillerInstance(double balance, int cargo, double landsMult, Market market){
|
||||||
|
Ship ship = new Ship();
|
||||||
|
ship.setCargo(cargo);
|
||||||
|
Profile profile = new Profile(ship);
|
||||||
|
profile.setBalance(balance);
|
||||||
|
profile.setLandMult(landsMult);
|
||||||
|
Scorer scorer = new Scorer(new FilteredMarket(market, new MarketFilter()), profile);
|
||||||
|
return new RouteFiller(scorer);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest1(){
|
||||||
|
LOG.info("Init test 1");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,0,0).addVendor("v2");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 100, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM2, 200, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM1, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM2, 350, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM3, 400, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRoute1() throws Exception {
|
||||||
|
LOG.info("Start route test 1");
|
||||||
|
Route route = initTest1();
|
||||||
|
RouteFiller filler = getFillerInstance(10000, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(10000, route.getBalance(), 0.0001);
|
||||||
|
assertEquals(1000, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(1, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
|
||||||
|
assertEquals(1000, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest2(){
|
||||||
|
LOG.info("Init test 2");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,0,0).addVendor("v2");
|
||||||
|
v3 = market.addPlace("p3",0,0,0).addVendor("v3");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 100, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM2, 200, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM1, 300, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM2, 350, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM3, 400, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
route.add(new RouteEntry(v3, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute2() throws Exception {
|
||||||
|
LOG.info("Start route test 2");
|
||||||
|
Route route = initTest2();
|
||||||
|
RouteFiller filler = getFillerInstance(10000, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(1000, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(1, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(1000, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order1);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest3(){
|
||||||
|
LOG.info("Init test 3");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,0,0).addVendor("v2");
|
||||||
|
v3 = market.addPlace("p3",0,0,0).addVendor("v3");
|
||||||
|
v4 = market.addPlace("p4",0,0,0).addVendor("v4");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 100, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM2, 200, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM1, 150, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM3, 320, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.SELL, ITEM3, 390, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM2, 225, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM1, 200, -1);
|
||||||
|
v4.addOffer(OFFER_TYPE.BUY, ITEM3, 450, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
route.add(new RouteEntry(v3, false, 0));
|
||||||
|
route.add(new RouteEntry(v4, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute3() throws Exception {
|
||||||
|
LOG.info("Start route test 3");
|
||||||
|
Route route = initTest3();
|
||||||
|
RouteFiller filler = getFillerInstance(10000, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(800, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(2, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 5);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(500, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order1);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(300, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order7);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute3byLands() throws Exception {
|
||||||
|
LOG.info("Start route test 3 by lands");
|
||||||
|
Route route = initTest3();
|
||||||
|
RouteFiller filler = getFillerInstance(10000, 5, 1, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(750, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(1, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order3 = new Order(v1.getSell(ITEM3), v4.getBuy(ITEM3), 5);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(750, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order3);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest4(){
|
||||||
|
LOG.info("Init test 4");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,0,0).addVendor("v2");
|
||||||
|
v3 = market.addPlace("p3",0,0,0).addVendor("v3");
|
||||||
|
v4 = market.addPlace("p4",0,0,0).addVendor("v4");
|
||||||
|
v5 = market.addPlace("p5",0,0,0).addVendor("v5");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 410, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM2, 200, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM2, 270, -1);
|
||||||
|
v4.addOffer(OFFER_TYPE.SELL, ITEM1, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM1, 470, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM2, 300, -1);
|
||||||
|
v4.addOffer(OFFER_TYPE.BUY, ITEM3, 370, -1);
|
||||||
|
v5.addOffer(OFFER_TYPE.BUY, ITEM1, 400, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
route.add(new RouteEntry(v3, false, 0));
|
||||||
|
route.add(new RouteEntry(v4, false, 0));
|
||||||
|
route.add(new RouteEntry(v5, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute4() throws Exception {
|
||||||
|
LOG.info("Start route test 4");
|
||||||
|
Route route = initTest4();
|
||||||
|
RouteFiller filler = getFillerInstance(10000, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(1000, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(3, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order3 = new Order(v1.getSell(ITEM2), v3.getBuy(ITEM2), 5);
|
||||||
|
Order order6 = new Order(v4.getSell(ITEM1), v5.getBuy(ITEM1), 5);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(500, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order3);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(3);
|
||||||
|
assertEquals(500, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order6);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest5(){
|
||||||
|
LOG.info("Init test 5");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
ITEM4 = market.addItem("ITEM4", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,0,0).addVendor("v2");
|
||||||
|
v3 = market.addPlace("p3",0,0,0).addVendor("v3");
|
||||||
|
v4 = market.addPlace("p4",0,0,0).addVendor("v4");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 100, 5);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM2, 200, 5);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, 5);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM4, 40, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM1, 150, 5);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM3, 320, 5);
|
||||||
|
v3.addOffer(OFFER_TYPE.SELL, ITEM3, 390, 5);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM2, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM4, 50, -1);
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM1, 200, -1);
|
||||||
|
v4.addOffer(OFFER_TYPE.BUY, ITEM3, 450, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
route.add(new RouteEntry(v3, false, 0));
|
||||||
|
route.add(new RouteEntry(v4, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute5() throws Exception {
|
||||||
|
LOG.info("Start route test 5");
|
||||||
|
Route route = initTest5();
|
||||||
|
RouteFiller filler = getFillerInstance(500, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(620, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(2, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 2);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(500, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order1);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(120, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order7);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPathRoute5B() throws Exception {
|
||||||
|
LOG.info("Start route test 5B");
|
||||||
|
Route route = initTest5();
|
||||||
|
RouteFiller filler = getFillerInstance(700, 7, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(750, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(3, route.getLands());
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order2 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 3);
|
||||||
|
Order order3 = new Order(v1.getSell(ITEM4), v2.getBuy(ITEM4), 2);
|
||||||
|
Order order4 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 3);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(320, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order2, order3);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(250, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order4);
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(180, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order7);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest6A(){
|
||||||
|
LOG.info("Init test 5");
|
||||||
|
market = new SimpleMarket();
|
||||||
|
ITEM1 = market.addItem("ITEM1", null);
|
||||||
|
ITEM2 = market.addItem("ITEM2", null);
|
||||||
|
ITEM3 = market.addItem("ITEM3", null);
|
||||||
|
ITEM4 = market.addItem("ITEM4", null);
|
||||||
|
v1 = market.addPlace("p1",0,0,0).addVendor("v1");
|
||||||
|
v2 = market.addPlace("p2",0,1,0).addVendor("v2");
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM1, 100, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM2, 200, -1);
|
||||||
|
v1.addOffer(OFFER_TYPE.SELL, ITEM3, 300, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM1, 150, -1);
|
||||||
|
v2.addOffer(OFFER_TYPE.SELL, ITEM3, 320, -1);
|
||||||
|
|
||||||
|
v2.addOffer(OFFER_TYPE.BUY, ITEM2, 225, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
route.add(new RouteEntry(v2, false, 0));
|
||||||
|
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Route initTest6B(){
|
||||||
|
LOG.info("Init test 6B");
|
||||||
|
v3 = market.addPlace("p3",0,1,1).addVendor("v3");
|
||||||
|
v4 = market.addPlace("p4",1,1,1).addVendor("v4");
|
||||||
|
|
||||||
|
v3.addOffer(OFFER_TYPE.SELL, ITEM3, 390, -1);
|
||||||
|
|
||||||
|
v3.addOffer(OFFER_TYPE.BUY, ITEM1, 200, -1);
|
||||||
|
v4.addOffer(OFFER_TYPE.BUY, ITEM3, 450, -1);
|
||||||
|
|
||||||
|
Route route = new Route(new RouteEntry(v2, false, 0));
|
||||||
|
route.add(new RouteEntry(v3, false, 0));
|
||||||
|
route.add(new RouteEntry(v4, false, 0));
|
||||||
|
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinRoute() throws Exception {
|
||||||
|
LOG.info("Start join route test");
|
||||||
|
Route route = initTest6A();
|
||||||
|
Route routeB = initTest6B();
|
||||||
|
RouteFiller filler = getFillerInstance(500, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
filler.fill(routeB);
|
||||||
|
|
||||||
|
route.join(routeB);
|
||||||
|
filler.fill(route);
|
||||||
|
|
||||||
|
assertEquals(620, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(2, route.getLands());
|
||||||
|
assertEquals(3, route.getDistance(), 0.0001);
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
Order order2 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 2);
|
||||||
|
Order order3 = new Order(v1.getSell(ITEM3), v4.getBuy(ITEM3), 1);
|
||||||
|
Order order4 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 3);
|
||||||
|
Order order5 = new Order(v2.getSell(ITEM3), v4.getBuy(ITEM3), 1);
|
||||||
|
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 2);
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(500, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order1);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(0, entry.getProfit(), 0.0001);
|
||||||
|
assertTrue(entry.getOrders().isEmpty());
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(120, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order7);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJoinRouteNoSort() throws Exception {
|
||||||
|
LOG.info("Start join route test");
|
||||||
|
Route route = initTest6A();
|
||||||
|
Route routeB = initTest6B();
|
||||||
|
RouteFiller filler = getFillerInstance(500, 5, 0, market);
|
||||||
|
filler.fill(route);
|
||||||
|
filler = getFillerInstance(550, 5, 0, market);
|
||||||
|
filler.fill(routeB);
|
||||||
|
|
||||||
|
route.join(routeB);
|
||||||
|
|
||||||
|
assertEquals(260, route.getProfit(), 0.0001);
|
||||||
|
assertEquals(3, route.getLands());
|
||||||
|
assertEquals(3, route.getDistance(), 0.0001);
|
||||||
|
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
|
Order order2 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 2);
|
||||||
|
Order order3 = new Order(v1.getSell(ITEM3), v4.getBuy(ITEM3), 1);
|
||||||
|
Order order4 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 3);
|
||||||
|
Order order5 = new Order(v2.getSell(ITEM3), v4.getBuy(ITEM3), 1);
|
||||||
|
Order order7 = new Order(v3.getSell(ITEM3), v4.getBuy(ITEM3), 1);
|
||||||
|
|
||||||
|
|
||||||
|
RouteEntry entry = entries.get(0);
|
||||||
|
assertEquals(50, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order2);
|
||||||
|
|
||||||
|
entry = entries.get(1);
|
||||||
|
assertEquals(150, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order4);
|
||||||
|
|
||||||
|
entry = entries.get(2);
|
||||||
|
assertEquals(60, entry.getProfit(), 0.0001);
|
||||||
|
TestUtil.assertCollectionEquals(entry.getOrders(), order7);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
66
core/src/test/java/ru/trader/analysis/RouteTest.java
Normal file
66
core/src/test/java/ru/trader/analysis/RouteTest.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.TestUtil;
|
||||||
|
import ru.trader.core.Vendor;
|
||||||
|
import ru.trader.store.simple.SimpleVendor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class RouteTest extends Assert {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(RouteTest.class);
|
||||||
|
|
||||||
|
private Vendor v1;
|
||||||
|
private Vendor v2;
|
||||||
|
private Vendor v3;
|
||||||
|
private Vendor v4;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendors() throws Exception {
|
||||||
|
LOG.info("Start test get vendors");
|
||||||
|
v1 = new SimpleVendor("v1",0,0,0);
|
||||||
|
v2 = new SimpleVendor("v2",0,0,0);
|
||||||
|
v3 = new SimpleVendor("v3",0,0,0);
|
||||||
|
v4 = new SimpleVendor("v4",0,0,0);
|
||||||
|
|
||||||
|
Route path = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
path.add(new RouteEntry(v2, false, 0));
|
||||||
|
path.add(new RouteEntry(v3, false, 0));
|
||||||
|
TestUtil.assertCollectionContainAll(path.getVendors(), v1, v2, v3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testContains() throws Exception {
|
||||||
|
LOG.info("Start test get entries");
|
||||||
|
v1 = new SimpleVendor("v1",0,0,0);
|
||||||
|
v2 = new SimpleVendor("v2",0,0,0);
|
||||||
|
v3 = new SimpleVendor("v3",0,0,0);
|
||||||
|
v4 = new SimpleVendor("v4",0,0,0);
|
||||||
|
|
||||||
|
Route path = new Route(new RouteEntry(v1, false, 0));
|
||||||
|
path.add(new RouteEntry(v2, false, 0));
|
||||||
|
path.add(new RouteEntry(v3, false, 0));
|
||||||
|
Collection<Vendor> vendors = new ArrayList<>();
|
||||||
|
Collections.addAll(vendors, v1, v2, v3);
|
||||||
|
assertTrue(path.contains(vendors));
|
||||||
|
vendors.clear();
|
||||||
|
Collections.addAll(vendors, v2);
|
||||||
|
assertTrue(path.contains(vendors));
|
||||||
|
vendors.clear();
|
||||||
|
Collections.addAll(vendors, v4);
|
||||||
|
assertFalse(path.contains(vendors));
|
||||||
|
vendors.clear();
|
||||||
|
Collections.addAll(vendors, v3, v2, v4, v1);
|
||||||
|
assertFalse(path.contains(vendors));
|
||||||
|
vendors.clear();
|
||||||
|
Collections.addAll(vendors, v1, v2, v3, v4);
|
||||||
|
assertFalse(path.contains(vendors));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user