Archived
0

implement route filler, changes in scorer

This commit is contained in:
iMoHax
2015-05-20 16:07:10 +03:00
parent eaee1b190d
commit bf5f12e405
9 changed files with 1201 additions and 22 deletions

View 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;
}
}

View 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);
}
}

View 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();
}
}

View 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 + "}";
}
}
}

View File

@@ -1,6 +1,8 @@
package ru.trader.analysis;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.trader.core.*;
import java.util.*;
@@ -8,25 +10,31 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Scorer {
private final static Logger LOG = LoggerFactory.getLogger(Scorer.class);
private final Map<Item, Offer> sellOffers;
private final Map<Item, Offer> buyOffers;
private final FilteredMarket market;
private final Profile profile;
private final double avgProfit;
private final double maxScore;
private final double avgDistance;
private int ordersCount = 5;
private double distanceRate = 1;
public Scorer(FilteredMarket market, Profile profile) {
this.market = market;
this.profile = profile;
sellOffers = new HashMap<>(100, 0.9f);
buyOffers = new HashMap<>(100, 0.9f);
market.getItems().parallelStream().forEach(this::fillOffers);
avgProfit = computeAvgProfit();
DoubleSummaryStatistics statProfit = computeProfit();
avgProfit = statProfit.getAverage()/profile.getShip().getCargo();
avgDistance = computeAvgDistance();
maxScore = getScore(0, statProfit.getMax()*2, 0,0,0);
}
public Profile getProfile() {
return profile;
}
private void fillOffers(Item item){
@@ -40,12 +48,10 @@ public class Scorer {
}
}
private double computeAvgProfit(){
OptionalDouble avg = sellOffers.values().stream()
private DoubleSummaryStatistics computeProfit(){
return sellOffers.values().stream()
.flatMap(this::mapToOrder)
.mapToDouble(o -> o.getProfit() / profile.getShip().getCargo())
.average();
return avg.orElse(0);
.collect(Collectors.summarizingDouble(Order::getProfit));
}
private double computeAvgDistance(){
@@ -53,18 +59,35 @@ public class Scorer {
return res.orElse(0);
}
public void setOrdersCount(int ordersCount) {
this.ordersCount = ordersCount;
}
public void setDistanceRate(double distanceRate) {
this.distanceRate = distanceRate;
}
public double getAvgProfit() {
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){
return new Score(vendor);
}
@@ -116,13 +139,13 @@ public class Scorer {
private DoubleSummaryStatistics computeProfits(Stream<Order> orders) {
return orders.sorted(Comparator.<Order>reverseOrder())
.limit(ordersCount)
.collect(Collectors.summarizingDouble(o -> o.getProfit() / profile.getShip().getCargo()));
.limit(profile.getScoreOrdersCount())
.collect(Collectors.summarizingDouble(Order::getProfit));
}
private void computeScore(){
score = (getSellProfit() + getBuyProfit())/2;
score -= distanceRate * avgProfit * (vendor.getDistance() - avgDistance) / avgDistance;
score = Scorer.this.getScore(vendor, score, 0, 0, 0);
}
@Override

View File

@@ -41,5 +41,12 @@ public abstract class AbstractOffer implements Offer {
}
}
@Override
public String toString() {
return "{" + getVendor() +
","+ getType() +
"," + getCount()+
"," + getItem() +
"," +getPrice()+"}";
}
}

View File

@@ -35,6 +35,10 @@ public class Ship {
return engine;
}
public void setEngine(int clazz, char rating) {
this.engine = new Engine(clazz, rating);
}
public void setEngine(Engine engine) {
this.engine = engine;
}

View 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);
}
}

View 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));
}
}