Archived
0

implement add offer to route

This commit is contained in:
iMoHax
2015-09-09 15:27:02 +03:00
parent ce6f6bf8d8
commit 8536e78458
7 changed files with 499 additions and 9 deletions

View File

@@ -80,6 +80,10 @@ public class Route implements Comparable<Route> {
return entries.size();
}
public boolean isLoop(){
return !isEmpty() && entries.get(0).is(entries.get(entries.size()-1).getVendor());
}
public void add(RouteEntry entry){
LOG.trace("Add entry {} to route {}", entry, this);
entries.add(entry);

View File

@@ -3,14 +3,13 @@ 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;
import java.util.*;
import java.util.stream.Collectors;
public class RouteEntry {
private final Vendor vendor;
private final double fuel;
private final List<Order> orders;
private final List<OrderWrapper> orders;
private boolean land;
private double refill;
private double profit;
@@ -74,15 +73,77 @@ public class RouteEntry {
}
void add(Order order){
orders.add(order);
orders.add(fixedWrap(order));
}
void addAll(Collection<Order> orders){
this.orders.addAll(orders);
orders.forEach(this::add);
}
void addOrder(Order order){
orders.add(wrap(order));
}
void removeOrder(Order order){
assert order instanceof OrderWrapper;
orders.remove(order);
}
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() {
return orders;
return new AbstractList<Order>() {
@Override
public Order get(int index) {
return orders.get(index);
}
@Override
public int size() {
return orders.size();
}
};
}
public List<Order> getFixedOrders(){
return orders.stream().filter(o -> o.fixed).collect(Collectors.toList());
}
void reserve(long count){
List<Order> fixedOrders = getFixedOrders();
fixedOrders.sort((o1, o2) -> Double.compare(o1.getProfitByTonne(), o2.getProfitByTonne()));
for (Order order : fixedOrders) {
long newCount = order.getCount() - count;
if (newCount < 0){
newCount = 0;
}
count -= order.getCount() - newCount;
order.setCount(newCount);
if (count <= 0) break;
}
}
void fill(long count){
List<Order> fixedOrders = getFixedOrders();
fixedOrders.sort((o1, o2) -> Double.compare(o2.getProfitByTonne(), o1.getProfitByTonne()));
for (Order order : fixedOrders) {
long newCount = Math.min(((OrderWrapper)order).max, order.getCount() + count);
count -= order.getCount() - newCount;
order.setCount(newCount);
if (count <= 0) break;
}
}
public long getCargo(){
return orders.stream().mapToLong(Order::getCount).sum();
}
void clearOrders(){
@@ -137,4 +198,27 @@ public class RouteEntry {
public String toString() {
return vendor + (isRefill() ? " (R)":"");
}
private OrderWrapper wrap(Order order){
return new OrderWrapper(order, false);
}
private OrderWrapper fixedWrap(Order order){
return new OrderWrapper(order, true);
}
private class OrderWrapper extends Order {
private final boolean fixed;
private final long max;
private OrderWrapper(Order order, boolean fixed) {
super(order.getSell(), order.getBuy(), order.getCount());
this.fixed = fixed;
this.max = order.getCount();
}
public void reset(){
setCount(max);
}
}
}

View File

@@ -357,4 +357,135 @@ public class RouteFiller {
return "{" + bestOrders + "}";
}
}
public static double[] getLostProfits(Route route, int offset, Vendor target, long count, long cargo){
List<RouteEntry> entries = route.getEntries();
int size = entries.size() - (route.isLoop() ? 1 : 0);
double[] res = new double[size];
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;
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++) {
index = i - j + offset;
if (index >= size) index -= size;
if (index < 0) index += size;
entry = entries.get(index);
if (!entry.isTransit() && entry.is(target)) {
break;
}
res[index] += profit;
}
}
return res;
}
public static void reservedCargo(final Route route, final int offset, Vendor target, long count, long cargo){
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 (entry.is(target)) {
break;
}
long empty = cargo - entry.getCargo();
long need = count - empty;
if (need > 0){
entry.reserve(need);
}
}
}
public static void fillCargo(final Route route, final int offset, Vendor target, long count){
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 (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++) {
RouteEntry entry = entries.get(i);
if (entry.isTransit()) continue;
Optional<Order> order = entry.getOrders().stream().filter(o -> o.getBuy().equals(buyOffer)).findAny();
if (order.isPresent()){
fillCargo(route, i, buyOffer.getVendor(), order.get().getCount());
entry.removeOrder(order.get());
}
}
}
public static void addOrders(final Route route, final int startEntry, final Offer buyOffer, final long cargo){
final double[] profits = getLostProfits(route, startEntry, buyOffer.getVendor(), buyOffer.getCount(), cargo);
class SortHelper {
RouteEntry entry;
int index;
Order sell;
SortHelper(RouteEntry entry, int index) {
this.entry = entry;
this.index = index;
Offer sell = entry.getVendor().getSell(buyOffer.getItem());
if (sell != null){
this.sell = new Order(sell, buyOffer, route.getBalance(), buyOffer.getCount());
}
}
private double getProfit(){
return sell != null ? profits[index] - sell.getProfit() : profits[index];
}
}
List<RouteEntry> entries = route.getEntries();
int size = entries.size()-1;
List<SortHelper> sortedEntries = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
RouteEntry entry = entries.get(i);
sortedEntries.add(new SortHelper(entry, i));
}
sortedEntries.sort((e1, e2) -> Double.compare(e1.getProfit(), e2.getProfit()));
long need = buyOffer.getCount();
double balance = route.getBalance();
for (SortHelper helper : sortedEntries) {
RouteEntry entry = helper.entry;
if (helper.sell != null){
Order order = new Order(helper.sell.getSell(), buyOffer, balance, need);
reservedCargo(route, helper.index, buyOffer.getVendor(), order.getCount(), cargo);
entry.addOrder(order);
need -= order.getCount();
if (need <= 0) break;
}
balance += entry.getProfit();
}
}
}

View File

@@ -44,6 +44,10 @@ public class Order implements Comparable<Order> {
return profit;
}
public double getProfitByTonne(){
return count == 0 ? buy.getPrice() - sell.getPrice() : profit/count;
}
public long getCount() {
return count;
}
@@ -86,7 +90,7 @@ public class Order implements Comparable<Order> {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!(o instanceof Order)) return false;
Order order = (Order) o;

View File

@@ -226,5 +226,25 @@ public class Profile {
values.setProperty("profile.search.times.recharge", String.valueOf(rechargeTime));
ship.writeTo(values);
}
public Profile copy(){
Profile res = new Profile(ship);
res.name = this.name;
res.balance = this.balance;
res.system = this.system;
res.station = this.station;
res.docked = this.docked;
res.jumps = this.jumps;
res.lands = this.lands;
res.refill = this.refill;
res.routesCount = this.routesCount;
res.distanceTime = this.distanceTime;
res.jumpTime = this.jumpTime;
res.landingTime = this.landingTime;
res.takeoffTime = this.takeoffTime;
res.rechargeTime = this.rechargeTime;
res.fuelPrice = this.fuelPrice;
res.pathPriority = this.pathPriority;
return res;
}
}

View File

@@ -61,4 +61,35 @@ public class SimpleOffer extends AbstractOffer {
this.count = count;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SimpleOffer)) return false;
SimpleOffer that = (SimpleOffer) o;
if (count != that.count) return false;
if (Double.compare(that.price, price) != 0) return false;
if (!item.equals(that.item)) return false;
if (type != that.type) return false;
if (!vendor.equals(that.vendor)) return false;
return true;
}
@Override
public int hashCode() {
int result = vendor.hashCode();
result = 31 * result + item.hashCode();
result = 31 * result + type.hashCode();
return result;
}
public static Offer fakeBuy(Vendor buyer, Item item, double price, long count){
SimpleOffer res = new SimpleOffer(OFFER_TYPE.BUY, item, price, count);
res.setVendor(buyer);
return res;
}
}