improve reserving for missions
This commit is contained in:
@@ -6,7 +6,7 @@ import javafx.beans.property.SimpleDoubleProperty;
|
|||||||
import ru.trader.analysis.Route;
|
import ru.trader.analysis.Route;
|
||||||
import ru.trader.analysis.RouteEntry;
|
import ru.trader.analysis.RouteEntry;
|
||||||
import ru.trader.analysis.RouteFiller;
|
import ru.trader.analysis.RouteFiller;
|
||||||
import ru.trader.controllers.MainController;
|
import ru.trader.analysis.RouteReserve;
|
||||||
import ru.trader.core.Offer;
|
import ru.trader.core.Offer;
|
||||||
import ru.trader.core.Order;
|
import ru.trader.core.Order;
|
||||||
import ru.trader.model.support.BindingsHelper;
|
import ru.trader.model.support.BindingsHelper;
|
||||||
@@ -123,24 +123,31 @@ public class RouteModel {
|
|||||||
|
|
||||||
public void add(int offset, MissionModel mission){
|
public void add(int offset, MissionModel mission){
|
||||||
int completeIndex = -1;
|
int completeIndex = -1;
|
||||||
long cargo = MainController.getProfile().getShipCargo();
|
|
||||||
Offer offer = mission.getOffer();
|
Offer offer = mission.getOffer();
|
||||||
if (offer != null){
|
if (offer != null){
|
||||||
completeIndex = RouteFiller.addOrders(_route, offset, offer, cargo);
|
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
||||||
for (RouteEntryModel entry : entries) {
|
if (!reserves.isEmpty()) {
|
||||||
entry.sellOrders().clear();
|
_route.reserve(reserves);
|
||||||
entry.refresh(market);
|
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
||||||
|
for (RouteEntryModel entry : entries) {
|
||||||
|
entry.sellOrders().clear();
|
||||||
|
entry.refresh(market);
|
||||||
|
}
|
||||||
|
fillSellOrders();
|
||||||
}
|
}
|
||||||
fillSellOrders();
|
|
||||||
} else
|
} else
|
||||||
if (mission.isDelivery()){
|
if (mission.isDelivery()){
|
||||||
completeIndex = RouteFiller.reservedCargo(_route, offset, mission.getTarget().getStation(), mission.getCount(), cargo);
|
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
||||||
for (RouteEntryModel entry : entries) {
|
if (reserve != null) {
|
||||||
entry.refresh(market);
|
_route.reserve(reserve);
|
||||||
|
completeIndex = reserve.getToIndex();
|
||||||
|
for (RouteEntryModel entry : entries) {
|
||||||
|
entry.refresh(market);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
if (mission.isCourier()){
|
if (mission.isCourier()){
|
||||||
completeIndex = _route.find(mission.getTarget().getStation(), offset);
|
completeIndex = _route.find(mission.getTarget().getStation(), offset+1);
|
||||||
}
|
}
|
||||||
if (completeIndex != -1){
|
if (completeIndex != -1){
|
||||||
entries.get(completeIndex).add(mission);
|
entries.get(completeIndex).add(mission);
|
||||||
@@ -148,20 +155,28 @@ public class RouteModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(int offset, Collection<MissionModel> missions){
|
public void addAll(int offset, Collection<MissionModel> missions){
|
||||||
long cargo = MainController.getProfile().getShipCargo();
|
|
||||||
for (MissionModel mission : missions) {
|
for (MissionModel mission : missions) {
|
||||||
Offer offer = mission.getOffer();
|
Offer offer = mission.getOffer();
|
||||||
int completeIndex = -1;
|
int completeIndex = -1;
|
||||||
if (offer != null){
|
if (offer != null){
|
||||||
completeIndex = RouteFiller.addOrders(_route, offset, offer, cargo);
|
Collection<RouteReserve> reserves = RouteFiller.getReserves(_route, offset, offer);
|
||||||
|
if (!reserves.isEmpty()) {
|
||||||
|
_route.reserve(reserves);
|
||||||
|
completeIndex = RouteReserve.getCompleteIndex(reserves, offset);
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
if (mission.isDelivery()){
|
if (mission.isDelivery()){
|
||||||
completeIndex = RouteFiller.reservedCargo(_route, offset, mission.getTarget().getStation(), mission.getCount(), cargo);
|
RouteReserve reserve = RouteFiller.getReserves(_route, offset, mission.getTarget().getStation(), mission.getCount());
|
||||||
|
if (reserve != null) {
|
||||||
|
_route.reserve(reserve);
|
||||||
|
completeIndex = reserve.getToIndex();
|
||||||
|
}
|
||||||
} else
|
} else
|
||||||
if (mission.isCourier()){
|
if (mission.isCourier()){
|
||||||
completeIndex = _route.find(mission.getTarget().getStation(), offset);
|
completeIndex = _route.find(mission.getTarget().getStation(), offset+1);
|
||||||
}
|
}
|
||||||
if (completeIndex != -1){
|
if (completeIndex != -1){
|
||||||
|
if (completeIndex == 0 && _route.isLoop()) completeIndex = _route.getJumps()-1;
|
||||||
entries.get(completeIndex).add(mission);
|
entries.get(completeIndex).add(mission);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.trader.analysis;
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import ru.trader.core.Vendor;
|
import ru.trader.core.Vendor;
|
||||||
@@ -17,6 +18,7 @@ public class Route implements Comparable<Route> {
|
|||||||
private long time = 0;
|
private long time = 0;
|
||||||
private int lands = 0;
|
private int lands = 0;
|
||||||
private int refills = 0;
|
private int refills = 0;
|
||||||
|
private long cargo=0;
|
||||||
|
|
||||||
public Route(RouteEntry root) {
|
public Route(RouteEntry root) {
|
||||||
entries = new ArrayList<>();
|
entries = new ArrayList<>();
|
||||||
@@ -48,6 +50,14 @@ public class Route implements Comparable<Route> {
|
|||||||
return balance;
|
return balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getCargo() {
|
||||||
|
return cargo;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCargo(long cargo) {
|
||||||
|
this.cargo = cargo;
|
||||||
|
}
|
||||||
|
|
||||||
public double getProfit() {
|
public double getProfit() {
|
||||||
return profit;
|
return profit;
|
||||||
}
|
}
|
||||||
@@ -92,7 +102,7 @@ public class Route implements Comparable<Route> {
|
|||||||
|
|
||||||
public void addAll(Collection<RouteEntry> entries){
|
public void addAll(Collection<RouteEntry> entries){
|
||||||
LOG.trace("Add {} entries {} to route {}", entries, this);
|
LOG.trace("Add {} entries {} to route {}", entries, this);
|
||||||
entries.addAll(entries);
|
this.entries.addAll(entries);
|
||||||
updateStats();
|
updateStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,22 +120,52 @@ public class Route implements Comparable<Route> {
|
|||||||
return vendors;
|
return vendors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int find(Vendor vendor, int offset){
|
public int find(Vendor vendor, int fromIndex){
|
||||||
int size = entries.size();
|
for (Route.LoopIterator iterator = loopIterator(fromIndex); iterator.hasNext(); ) {
|
||||||
for (int i = 0; i < size; i++) {
|
RouteEntry entry = iterator.next();
|
||||||
int index = i + offset;
|
if (entry.is(vendor)) {
|
||||||
if (index >= size){
|
return iterator.getRealIndex();
|
||||||
if (isLoop()) index -= size;
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
RouteEntry entry = entries.get(index);
|
|
||||||
if (entry.is(vendor)){
|
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reserve(final RouteReserve reserve){
|
||||||
|
for (Route.LoopIterator iterator = loopIterator(reserve.getFromIndex()); iterator.hasNext(); ) {
|
||||||
|
RouteEntry entry = iterator.next();
|
||||||
|
if (entry.isTransit()) continue;
|
||||||
|
if (iterator.getRealIndex() == reserve.getToIndex() && (reserve.getFromIndex() != reserve.getToIndex() || iterator.getIndex() > 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry.reserve(reserve.getCount(), cargo);
|
||||||
|
}
|
||||||
|
if (reserve.getOrder() != null) {
|
||||||
|
entries.get(reserve.getFromIndex()).addOrder(reserve.getOrder());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reserve(Collection<RouteReserve> reserves){
|
||||||
|
reserves.forEach(this::reserve);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unreserve(final RouteReserve reserve){
|
||||||
|
for (Route.LoopIterator iterator = loopIterator(reserve.getFromIndex()); iterator.hasNext(); ) {
|
||||||
|
RouteEntry entry = iterator.next();
|
||||||
|
if (entry.isTransit()) continue;
|
||||||
|
if (iterator.getRealIndex() == reserve.getToIndex() && (reserve.getFromIndex() != reserve.getToIndex() || iterator.getIndex() > 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry.fill(reserve.getCount());
|
||||||
|
}
|
||||||
|
if (reserve.getOrder() != null) {
|
||||||
|
entries.get(reserve.getFromIndex()).removeOrder(reserve.getOrder());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unreserve(Collection<RouteReserve> reserves){
|
||||||
|
reserves.forEach(this::unreserve);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean contains(Collection<Vendor> vendors){
|
public boolean contains(Collection<Vendor> vendors){
|
||||||
return vendors.isEmpty()
|
return vendors.isEmpty()
|
||||||
|| vendors.size() <= entries.size()
|
|| vendors.size() <= entries.size()
|
||||||
@@ -178,7 +218,7 @@ public class Route implements Comparable<Route> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Route o) {
|
public int compareTo(@NotNull Route o) {
|
||||||
return Double.compare(getScore(), o.getScore());
|
return Double.compare(getScore(), o.getScore());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,4 +248,39 @@ public class Route implements Comparable<Route> {
|
|||||||
", lands=" + lands +
|
", lands=" + lands +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface LoopIterator extends Iterator<RouteEntry>{
|
||||||
|
int getIndex();
|
||||||
|
int getRealIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
public LoopIterator loopIterator(int from){
|
||||||
|
return new LoopIterator() {
|
||||||
|
private final int size = entries.size() - (isLoop() ? 1 : from);
|
||||||
|
private int i = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIndex(){
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRealIndex(){
|
||||||
|
int index = i + from;
|
||||||
|
if (index >= size) index -= size;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return i < size-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RouteEntry next() {
|
||||||
|
i++;
|
||||||
|
return entries.get(getRealIndex());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package ru.trader.analysis;
|
|||||||
import ru.trader.core.Order;
|
import ru.trader.core.Order;
|
||||||
import ru.trader.core.Vendor;
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.AbstractList;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class RouteEntry {
|
public class RouteEntry {
|
||||||
@@ -15,6 +18,7 @@ public class RouteEntry {
|
|||||||
private double profit;
|
private double profit;
|
||||||
private long time;
|
private long time;
|
||||||
private long fulltime;
|
private long fulltime;
|
||||||
|
private long reserved;
|
||||||
|
|
||||||
public RouteEntry(Vendor vendor, double refill, double fuel, double profit) {
|
public RouteEntry(Vendor vendor, double refill, double fuel, double profit) {
|
||||||
orders = new ArrayList<>();
|
orders = new ArrayList<>();
|
||||||
@@ -22,6 +26,7 @@ public class RouteEntry {
|
|||||||
this.refill = refill;
|
this.refill = refill;
|
||||||
this.fuel = fuel;
|
this.fuel = fuel;
|
||||||
this.profit = profit;
|
this.profit = profit;
|
||||||
|
reserved = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vendor getVendor() {
|
public Vendor getVendor() {
|
||||||
@@ -85,18 +90,11 @@ public class RouteEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void removeOrder(Order order){
|
void removeOrder(Order order){
|
||||||
assert order instanceof OrderWrapper;
|
if (order instanceof OrderWrapper) {
|
||||||
orders.remove(order);
|
orders.remove(order);
|
||||||
}
|
} else {
|
||||||
|
orders.removeIf(order::equals);
|
||||||
void clearTemporal(){
|
|
||||||
for (Iterator<OrderWrapper> iterator = orders.iterator(); iterator.hasNext(); ) {
|
|
||||||
OrderWrapper order = iterator.next();
|
|
||||||
if (!order.fixed){
|
|
||||||
iterator.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
orders.forEach(OrderWrapper::reset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Order> getOrders() {
|
public List<Order> getOrders() {
|
||||||
@@ -117,18 +115,23 @@ public class RouteEntry {
|
|||||||
return orders.stream().filter(o -> o.fixed).collect(Collectors.toList());
|
return orders.stream().filter(o -> o.fixed).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(long count){
|
void reserve(final long count, final long cargo){
|
||||||
List<Order> fixedOrders = getFixedOrders();
|
long empty = cargo - getCargo();
|
||||||
fixedOrders.sort((o1, o2) -> Double.compare(o1.getProfitByTonne(), o2.getProfitByTonne()));
|
long need = count - empty;
|
||||||
for (Order order : fixedOrders) {
|
if (need > 0){
|
||||||
long newCount = order.getCount() - count;
|
List<Order> fixedOrders = getFixedOrders();
|
||||||
if (newCount < 0){
|
fixedOrders.sort((o1, o2) -> Double.compare(o1.getProfitByTonne(), o2.getProfitByTonne()));
|
||||||
newCount = 0;
|
for (Order order : fixedOrders) {
|
||||||
|
long newCount = order.getCount() - need;
|
||||||
|
if (newCount < 0){
|
||||||
|
newCount = 0;
|
||||||
|
}
|
||||||
|
need -= order.getCount() - newCount;
|
||||||
|
order.setCount(newCount);
|
||||||
|
if (need <= 0) break;
|
||||||
}
|
}
|
||||||
count -= order.getCount() - newCount;
|
|
||||||
order.setCount(newCount);
|
|
||||||
if (count <= 0) break;
|
|
||||||
}
|
}
|
||||||
|
reserved += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill(long count){
|
void fill(long count){
|
||||||
@@ -140,10 +143,14 @@ public class RouteEntry {
|
|||||||
order.setCount(newCount);
|
order.setCount(newCount);
|
||||||
if (count <= 0) break;
|
if (count <= 0) break;
|
||||||
}
|
}
|
||||||
|
reserved -= count;
|
||||||
|
if (reserved < 0){
|
||||||
|
reserved = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getCargo(){
|
public long getCargo(){
|
||||||
return orders.stream().mapToLong(Order::getCount).sum();
|
return orders.stream().filter(o -> o.fixed).mapToLong(Order::getCount).sum() + reserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearOrders(){
|
void clearOrders(){
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ public class RouteFiller {
|
|||||||
public void fill(Route route){
|
public void fill(Route route){
|
||||||
this.route = route;
|
this.route = route;
|
||||||
route.setBalance(balance);
|
route.setBalance(balance);
|
||||||
|
route.setCargo(cargo);
|
||||||
fillOrders();
|
fillOrders();
|
||||||
updateEntries();
|
updateEntries();
|
||||||
route.updateStats();
|
route.updateStats();
|
||||||
@@ -358,34 +359,19 @@ public class RouteFiller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double[] getLostProfits(Route route, int offset, Vendor target, long count, long cargo){
|
public static double[] getLostProfits(Route route, int fromIndex, Vendor target, long count) {
|
||||||
List<RouteEntry> entries = route.getEntries();
|
final double[] profits = getLostProfits(route, count);
|
||||||
int size = entries.size() - (route.isLoop() ? 1 : 0);
|
int size = route.isLoop() ? route.getJumps()-1: route.getJumps();
|
||||||
double[] res = new double[size];
|
double[] res = new double[size];
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int index = i + offset;
|
int index = i + fromIndex;
|
||||||
if (index >= size) index -= size;
|
if (index >= size) index -= size;
|
||||||
RouteEntry entry = entries.get(index);
|
double profit = profits[index];
|
||||||
if (entry.isTransit()) continue;
|
|
||||||
List<Order> orders = new ArrayList<>(entry.getFixedOrders());
|
|
||||||
orders.sort((o1, o2) -> Double.compare(o1.getProfitByTonne(), o2.getProfitByTonne()));
|
|
||||||
long empty = cargo - orders.stream().mapToLong(Order::getCount).sum();
|
|
||||||
long need = count - empty;
|
|
||||||
double profit = 0;
|
|
||||||
for (Order order : orders) {
|
|
||||||
if (need > 0){
|
|
||||||
long reserved = Math.min(order.getCount(), need);
|
|
||||||
profit += reserved * order.getProfitByTonne();
|
|
||||||
need -= reserved;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int j = 0; j < size; j++) {
|
for (int j = 0; j < size; j++) {
|
||||||
index = i - j + offset;
|
index = i - j + fromIndex;
|
||||||
if (index >= size) index -= size;
|
if (index >= size) index -= size;
|
||||||
if (index < 0) index += size;
|
if (index < 0) index += size;
|
||||||
entry = entries.get(index);
|
RouteEntry entry = route.get(index);
|
||||||
if (!entry.isTransit() && entry.is(target)) {
|
if (!entry.isTransit() && entry.is(target)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -395,83 +381,114 @@ public class RouteFiller {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int reservedCargo(final Route route, final int offset, Vendor target, long count, long cargo){
|
|
||||||
//TODO: compute current cargo if already reserved
|
|
||||||
int lastIndex = -1;
|
|
||||||
List<RouteEntry> entries = route.getEntries();
|
|
||||||
int size = entries.size() - (route.isLoop() ? 1 : 0);
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
int index = i + offset;
|
|
||||||
if (index >= size) index -= size;
|
|
||||||
RouteEntry entry = entries.get(index);
|
|
||||||
if (entry.isTransit()) continue;
|
|
||||||
if (i > 0 && entry.is(target)) {
|
|
||||||
lastIndex = index;
|
|
||||||
if (index == 0 && route.isLoop()) lastIndex = size;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
long empty = cargo - entry.getCargo();
|
|
||||||
long need = count - empty;
|
|
||||||
if (need > 0){
|
|
||||||
entry.reserve(need);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lastIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void fillCargo(final Route route, final int offset, Vendor target, long count){
|
public static double[] getLostProfits(Route route, long count){
|
||||||
List<RouteEntry> entries = route.getEntries();
|
List<RouteEntry> entries = route.getEntries();
|
||||||
int size = entries.size() - (route.isLoop() ? 1 : 0);
|
int size = entries.size();
|
||||||
for (int i = 0; i < size; i++) {
|
double[] res = new double[size];
|
||||||
int index = i + offset;
|
|
||||||
if (index >= size) index -= size;
|
|
||||||
RouteEntry entry = entries.get(index);
|
|
||||||
if (entry.isTransit()) continue;
|
|
||||||
if (entry.is(target)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
entry.fill(count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void removeOrders(final Route route, final Offer buyOffer){
|
|
||||||
List<RouteEntry> entries = route.getEntries();
|
|
||||||
int size = entries.size() - (route.isLoop() ? 1 : 0);
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
RouteEntry entry = entries.get(i);
|
RouteEntry entry = entries.get(i);
|
||||||
if (entry.isTransit()) continue;
|
if (entry.isTransit()) continue;
|
||||||
Optional<Order> order = entry.getOrders().stream().filter(o -> o.getBuy().equals(buyOffer)).findAny();
|
List<Order> orders = new ArrayList<>(entry.getFixedOrders());
|
||||||
if (order.isPresent()){
|
orders.sort((o1, o2) -> Double.compare(o1.getProfitByTonne(), o2.getProfitByTonne()));
|
||||||
fillCargo(route, i, buyOffer.getVendor(), order.get().getCount());
|
long empty = route.getCargo() - entry.getCargo();
|
||||||
entry.removeOrder(order.get());
|
long need = count - empty;
|
||||||
|
double profit = 0;
|
||||||
|
for (Order order : orders) {
|
||||||
|
if (need > 0) {
|
||||||
|
long reserved = Math.min(order.getCount(), need);
|
||||||
|
profit += reserved * order.getProfitByTonne();
|
||||||
|
need -= reserved;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
res[i] += profit;
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int addOrders(final Route route, final int startEntry, final Offer buyOffer, final long cargo){
|
private static double getLostProfit(int fromIndex, int toIndex, double[] lostProfits) {
|
||||||
final double[] profits = getLostProfits(route, startEntry, buyOffer.getVendor(), buyOffer.getCount(), cargo);
|
double res = 0;
|
||||||
|
for (int i = 0; i < lostProfits.length; i++) {
|
||||||
|
int index = i + fromIndex;
|
||||||
|
if (index >= lostProfits.length) index -= lostProfits.length;
|
||||||
|
if (index == toIndex && (i > 0 || fromIndex != toIndex)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res += lostProfits[index];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getLastIndex(final int fromIndex, final Offer buyOffer, final Order[] sells){
|
||||||
|
long need = buyOffer.getCount();
|
||||||
|
for (int i = 0; i < sells.length; i++) {
|
||||||
|
int index = i + fromIndex;
|
||||||
|
if (index >= sells.length) index -= sells.length;
|
||||||
|
Order sell = sells[index];
|
||||||
|
if (sell == null) continue;
|
||||||
|
if (sell.getCount() >= need) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
need -= sell.getCount();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RouteReserve getReserves(final Route route, final int fromIndex, final Vendor target, long count){
|
||||||
|
int toIndex = route.find(target, fromIndex+1);
|
||||||
|
return toIndex != -1 ? new RouteReserve(fromIndex, toIndex, count) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<RouteReserve> getReserves(final Route route, final int fromIndex, final Offer buyOffer){
|
||||||
|
List<RouteEntry> entries = route.getEntries();
|
||||||
|
int size = entries.size()-1;
|
||||||
|
final double[] profits = getLostProfits(route, buyOffer.getCount());
|
||||||
|
final Order[] orders = new Order[size];
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
RouteEntry entry = entries.get(i);
|
||||||
|
Offer sell = entry.getVendor().getSell(buyOffer.getItem());
|
||||||
|
if (sell != null) {
|
||||||
|
orders[i] = new Order(sell, buyOffer, route.getBalance(), buyOffer.getCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class SortHelper {
|
class SortHelper {
|
||||||
RouteEntry entry;
|
final RouteEntry entry;
|
||||||
int index;
|
final int index;
|
||||||
Order sell;
|
final int endIndex;
|
||||||
|
final Order sell;
|
||||||
|
final double profit;
|
||||||
|
|
||||||
SortHelper(RouteEntry entry, int index) {
|
SortHelper(RouteEntry entry, int index) {
|
||||||
this.entry = entry;
|
this.entry = entry;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
Offer sell = entry.getVendor().getSell(buyOffer.getItem());
|
this.sell = orders[index];
|
||||||
if (sell != null){
|
int lastIndex = getLastIndex(index, buyOffer, orders);
|
||||||
this.sell = new Order(sell, buyOffer, route.getBalance(), buyOffer.getCount());
|
if (lastIndex != -1) {
|
||||||
|
endIndex = route.find(buyOffer.getVendor(), lastIndex+1);
|
||||||
|
if (endIndex != -1) {
|
||||||
|
double lost = getLostProfit(index, endIndex, profits);
|
||||||
|
profit = sell != null ? lost - sell.getProfit() : lost;
|
||||||
|
} else {
|
||||||
|
profit = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
endIndex = -1;
|
||||||
|
profit = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSeller(){
|
||||||
|
return sell != null && endIndex != -1;
|
||||||
|
}
|
||||||
|
|
||||||
private double getProfit(){
|
private double getProfit(){
|
||||||
return sell != null ? profits[index] - sell.getProfit() : profits[index];
|
return profit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RouteEntry> entries = route.getEntries();
|
|
||||||
int size = entries.size()-1;
|
|
||||||
List<SortHelper> sortedEntries = new ArrayList<>(size);
|
List<SortHelper> sortedEntries = new ArrayList<>(size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
RouteEntry entry = entries.get(i);
|
RouteEntry entry = entries.get(i);
|
||||||
@@ -479,23 +496,22 @@ public class RouteFiller {
|
|||||||
}
|
}
|
||||||
sortedEntries.sort((e1, e2) -> Double.compare(e1.getProfit(), e2.getProfit()));
|
sortedEntries.sort((e1, e2) -> Double.compare(e1.getProfit(), e2.getProfit()));
|
||||||
|
|
||||||
int completeIndex = -1;
|
|
||||||
long need = buyOffer.getCount();
|
long need = buyOffer.getCount();
|
||||||
double balance = route.getBalance();
|
double balance = route.getBalance();
|
||||||
|
boolean checkIndex = !route.isLoop();
|
||||||
|
Collection<RouteReserve> reserves = new ArrayList<>();
|
||||||
for (SortHelper helper : sortedEntries) {
|
for (SortHelper helper : sortedEntries) {
|
||||||
|
if (checkIndex && fromIndex > helper.index) continue;
|
||||||
RouteEntry entry = helper.entry;
|
RouteEntry entry = helper.entry;
|
||||||
if (helper.sell != null){
|
if (helper.isSeller()){
|
||||||
Order order = new Order(helper.sell.getSell(), buyOffer, balance, need);
|
Order order = new Order(helper.sell.getSell(), buyOffer, balance, need);
|
||||||
int lastIndex = reservedCargo(route, helper.index, buyOffer.getVendor(), order.getCount(), cargo);
|
RouteReserve reserve = new RouteReserve(order, helper.index, helper.endIndex);
|
||||||
if (completeIndex == -1 || completeIndex+startEntry < completeIndex + startEntry){
|
reserves.add(reserve);
|
||||||
completeIndex = lastIndex;
|
|
||||||
}
|
|
||||||
entry.addOrder(order);
|
|
||||||
need -= order.getCount();
|
need -= order.getCount();
|
||||||
if (need <= 0) break;
|
if (need <= 0) break;
|
||||||
}
|
}
|
||||||
balance += entry.getProfit();
|
balance += entry.getProfit();
|
||||||
}
|
}
|
||||||
return completeIndex;
|
return reserves;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
core/src/main/java/ru/trader/analysis/RouteReserve.java
Normal file
52
core/src/main/java/ru/trader/analysis/RouteReserve.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.core.Order;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class RouteReserve {
|
||||||
|
private final Order order;
|
||||||
|
private final int fromIndex;
|
||||||
|
private final int toIndex;
|
||||||
|
private final long count;
|
||||||
|
|
||||||
|
public RouteReserve(int fromIndex, int toIndex, long count) {
|
||||||
|
order = null;
|
||||||
|
this.fromIndex = fromIndex;
|
||||||
|
this.toIndex = toIndex;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteReserve(Order order, int fromIndex, int toIndex) {
|
||||||
|
this.order = order;
|
||||||
|
this.fromIndex = fromIndex;
|
||||||
|
this.toIndex = toIndex;
|
||||||
|
count = order.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Order getOrder() {
|
||||||
|
return order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getFromIndex() {
|
||||||
|
return fromIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getToIndex() {
|
||||||
|
return toIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCompleteIndex(Collection<RouteReserve> reserves, int fromIndex){
|
||||||
|
int completeIndex = -1;
|
||||||
|
for (RouteReserve reserve : reserves) {
|
||||||
|
if (completeIndex == -1 || completeIndex + fromIndex < reserve.getToIndex() + fromIndex){
|
||||||
|
completeIndex = reserve.getToIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return completeIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,9 @@ import ru.trader.core.Place;
|
|||||||
import ru.trader.core.Profile;
|
import ru.trader.core.Profile;
|
||||||
import ru.trader.core.Vendor;
|
import ru.trader.core.Vendor;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class RouteSearcher {
|
public class RouteSearcher {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(RouteSearcher.class);
|
private final static Logger LOG = LoggerFactory.getLogger(RouteSearcher.class);
|
||||||
@@ -152,6 +154,7 @@ public class RouteSearcher {
|
|||||||
}
|
}
|
||||||
Route route = new Route(entries);
|
Route route = new Route(entries);
|
||||||
route.setBalance(scorer.getProfile().getBalance());
|
route.setBalance(scorer.getProfile().getBalance());
|
||||||
|
route.setCargo(scorer.getProfile().getShip().getCargo());
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +191,7 @@ public class RouteSearcher {
|
|||||||
}
|
}
|
||||||
Route route = new Route(entries);
|
Route route = new Route(entries);
|
||||||
route.setBalance(scorer.getProfile().getBalance());
|
route.setBalance(scorer.getProfile().getBalance());
|
||||||
|
route.setCargo(scorer.getProfile().getShip().getCargo());
|
||||||
return route;
|
return route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import ru.trader.core.*;
|
|||||||
import ru.trader.store.simple.SimpleMarket;
|
import ru.trader.store.simple.SimpleMarket;
|
||||||
import ru.trader.store.simple.SimpleOffer;
|
import ru.trader.store.simple.SimpleOffer;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class RouteFillerTest extends Assert {
|
public class RouteFillerTest extends Assert {
|
||||||
@@ -484,30 +485,30 @@ public class RouteFillerTest extends Assert {
|
|||||||
assertEquals(3, route.getLands());
|
assertEquals(3, route.getLands());
|
||||||
|
|
||||||
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 */
|
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 */
|
||||||
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo, cargo);
|
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo);
|
||||||
assertArrayEquals(new double[]{750, 430, 180, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{750, 430, 180, 0}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, cargo);
|
||||||
assertArrayEquals(new double[]{0, 430, 180, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 430, 180, 0}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 1, v2, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 1, v2, cargo);
|
||||||
assertArrayEquals(new double[]{320, 0, 500, 320}, profits, 0.001);
|
assertArrayEquals(new double[]{320, 0, 500, 320}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 2, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 2, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 570}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 570}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 570}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 570}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, 2, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, 2);
|
||||||
assertArrayEquals(new double[]{0, 0, 0, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 0, 0, 0}, profits, 0.001);
|
||||||
|
|
||||||
/* v1 -2x20 -> v2 -2x50 -> v3 -> v4 */
|
/* v1 -2x20 -> v2 -2x50 -> v3 -> v4 */
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v4, 4, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v4, 4);
|
||||||
assertArrayEquals(new double[]{120, 100, 0, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{120, 100, 0, 0}, profits, 0.001);
|
||||||
|
|
||||||
/* v1 -1x100 - 2x20 -> v2 -3x50 -> v3 -1x60 -> v4 */
|
/* v1 -1x100 - 2x20 -> v2 -3x50 -> v3 -1x60 -> v4 */
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v4, 5, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v4, 5);
|
||||||
assertArrayEquals(new double[]{330, 210, 60, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{330, 210, 60, 0}, profits, 0.001);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,22 +560,22 @@ public class RouteFillerTest extends Assert {
|
|||||||
assertEquals(4, route.getLands());
|
assertEquals(4, route.getLands());
|
||||||
|
|
||||||
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x50 -> v3 transit -> v1 */
|
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x50 -> v3 transit -> v1 */
|
||||||
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo, cargo);
|
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo);
|
||||||
assertArrayEquals(new double[]{750, 430, 180, 0, 750}, profits, 0.001);
|
assertArrayEquals(new double[]{750, 430, 180, 0, 750}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, cargo);
|
||||||
assertArrayEquals(new double[]{0, 680, 430, 250, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 680, 430, 250, 0}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 1, v2, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 1, v2, cargo);
|
||||||
assertArrayEquals(new double[]{320, 0, 750, 570, 320}, profits, 0.001);
|
assertArrayEquals(new double[]{320, 0, 750, 570, 320}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 2, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 2, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 820, 570}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 820, 570}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 820, 570}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 820, 570}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, 2, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, 2);
|
||||||
assertArrayEquals(new double[]{0, 0, 0, 0, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 0, 0, 0, 0}, profits, 0.001);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -627,22 +628,22 @@ public class RouteFillerTest extends Assert {
|
|||||||
assertEquals(5, route.getLands());
|
assertEquals(5, route.getLands());
|
||||||
|
|
||||||
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x20 -> v3 3x10 -> v1 */
|
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x20 -> v3 3x10 -> v1 */
|
||||||
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo, cargo);
|
double[] profits = RouteFiller.getLostProfits(route, 0, v4, cargo);
|
||||||
assertArrayEquals(new double[]{750, 430, 180, 0, 780}, profits, 0.001);
|
assertArrayEquals(new double[]{750, 430, 180, 0, 780}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, cargo);
|
||||||
assertArrayEquals(new double[]{0, 560, 310, 130, 30}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 560, 310, 130, 30}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 1, v2, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 1, v2, cargo);
|
||||||
assertArrayEquals(new double[]{320, 0, 630, 450, 350}, profits, 0.001);
|
assertArrayEquals(new double[]{320, 0, 630, 450, 350}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 2, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 2, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 100, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 100, 0}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v3, cargo, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v3, cargo);
|
||||||
assertArrayEquals(new double[]{570, 250, 0, 100, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{570, 250, 0, 100, 0}, profits, 0.001);
|
||||||
|
|
||||||
profits = RouteFiller.getLostProfits(route, 0, v1, 2, cargo);
|
profits = RouteFiller.getLostProfits(route, 0, v1, 2);
|
||||||
assertArrayEquals(new double[]{0, 0, 0, 0, 0}, profits, 0.001);
|
assertArrayEquals(new double[]{0, 0, 0, 0, 0}, profits, 0.001);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -660,9 +661,13 @@ public class RouteFillerTest extends Assert {
|
|||||||
|
|
||||||
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x20 -> v3 3x10 -> v1 */
|
/* v1 3x100 + 2x20 -> v2 5x50 -> v3 3x60 -> v4 5x20 -> v3 3x10 -> v1 */
|
||||||
Offer offer = SimpleOffer.fakeBuy(v2, ITEM3, 210, 3);
|
Offer offer = SimpleOffer.fakeBuy(v2, ITEM3, 210, 3);
|
||||||
int completeIndex = RouteFiller.addOrders(route, 1, offer, cargo);
|
Collection<RouteReserve> reserves = RouteFiller.getReserves(route, 1, offer);
|
||||||
|
assertEquals(2, reserves.size());
|
||||||
|
int completeIndex = RouteReserve.getCompleteIndex(reserves, 1);
|
||||||
assertEquals(1, completeIndex);
|
assertEquals(1, completeIndex);
|
||||||
|
|
||||||
|
route.reserve(reserves);
|
||||||
|
|
||||||
Order order1 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 3);
|
Order order1 = new Order(v1.getSell(ITEM2), v2.getBuy(ITEM2), 3);
|
||||||
Order order2 = new Order(v1.getSell(ITEM4), v2.getBuy(ITEM4), 1);
|
Order order2 = new Order(v1.getSell(ITEM4), v2.getBuy(ITEM4), 1);
|
||||||
Order order3 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
Order order3 = new Order(v2.getSell(ITEM1), v3.getBuy(ITEM1), 5);
|
||||||
@@ -680,7 +685,7 @@ public class RouteFillerTest extends Assert {
|
|||||||
|
|
||||||
order2 = new Order(v1.getSell(ITEM4), v2.getBuy(ITEM4), 2);
|
order2 = new Order(v1.getSell(ITEM4), v2.getBuy(ITEM4), 2);
|
||||||
|
|
||||||
RouteFiller.removeOrders(route, offer);
|
route.unreserve(reserves);
|
||||||
TestUtil.assertCollectionEquals(route.get(0).getOrders(), order1, order2);
|
TestUtil.assertCollectionEquals(route.get(0).getOrders(), order1, order2);
|
||||||
TestUtil.assertCollectionEquals(route.get(1).getOrders(), order3);
|
TestUtil.assertCollectionEquals(route.get(1).getOrders(), order3);
|
||||||
TestUtil.assertCollectionEquals(route.get(2).getOrders(), order4);
|
TestUtil.assertCollectionEquals(route.get(2).getOrders(), order4);
|
||||||
|
|||||||
Reference in New Issue
Block a user