Archived
0

- update paths layout

- add top routers
- add orders button
This commit is contained in:
iMoHax
2014-08-19 17:20:30 +04:00
parent 2604939f96
commit 14c2021e0c
16 changed files with 419 additions and 133 deletions

View File

@@ -4,16 +4,11 @@ import javafx.collections.FXCollections;
import javafx.event.ActionEvent; import javafx.event.ActionEvent;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.Parent; import javafx.scene.Parent;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.LongStringConverter;
import org.controlsfx.control.ButtonBar; import org.controlsfx.control.ButtonBar;
import org.controlsfx.control.action.AbstractAction; import org.controlsfx.control.action.AbstractAction;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.controlsfx.dialog.Dialog; import org.controlsfx.dialog.Dialog;
import ru.trader.graph.PathRoute;
import ru.trader.model.OrderModel;
import ru.trader.model.PathRouteModel; import ru.trader.model.PathRouteModel;
import java.util.Collection; import java.util.Collection;
@@ -42,7 +37,7 @@ public class PathsController {
} }
public void showDialog(Parent parent, Parent content, Collection<PathRouteModel> paths) { public PathRouteModel showDialog(Parent parent, Parent content, Collection<PathRouteModel> paths) {
init(paths); init(paths);
@@ -50,9 +45,12 @@ public class PathsController {
dlg.setContent(content); dlg.setContent(content);
dlg.getActions().addAll(OK, Dialog.Actions.CANCEL); dlg.getActions().addAll(OK, Dialog.Actions.CANCEL);
dlg.setResizable(false); dlg.setResizable(false);
dlg.show(); return dlg.show() == OK ? getPath() : null;
} }
public PathRouteModel getPath(){
return tblPaths.getSelectionModel().getSelectedItem();
}
private void init(Collection<PathRouteModel> paths) { private void init(Collection<PathRouteModel> paths) {
tblPaths.getSelectionModel().clearSelection(); tblPaths.getSelectionModel().clearSelection();

View File

@@ -6,12 +6,11 @@ import javafx.collections.ListChangeListener;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.ComboBox; import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TableView; import javafx.scene.control.TableView;
import ru.trader.model.MarketModel; import ru.trader.model.*;
import ru.trader.model.OfferDescModel;
import ru.trader.model.OrderModel;
import ru.trader.model.VendorModel;
import ru.trader.view.support.NumberField; import ru.trader.view.support.NumberField;
import ru.trader.view.support.RouteNode;
import java.util.Collection; import java.util.Collection;
@@ -30,6 +29,9 @@ public class RoutersController {
@FXML @FXML
private NumberField jumps; private NumberField jumps;
@FXML
private ScrollPane path;
@FXML @FXML
private Button add; private Button add;
@@ -60,9 +62,9 @@ public class RoutersController {
balance.setValue(1000); balance.setValue(1000);
cargo.setValue(4); cargo.setValue(4);
tank.setValue(30); tank.setValue(20);
distance.setValue(7); distance.setValue(7);
jumps.setValue(4); jumps.setValue(3);
add.disableProperty().bind(this.balance.wrongProperty().or(this.cargo.wrongProperty())); add.disableProperty().bind(this.balance.wrongProperty().or(this.cargo.wrongProperty()));
tblOrders.setItems(FXCollections.observableArrayList()); tblOrders.setItems(FXCollections.observableArrayList());
@@ -87,7 +89,8 @@ public class RoutersController {
market = MainController.getMarket(); market = MainController.getMarket();
source.setItems(market.vendorsProperty()); source.setItems(market.vendorsProperty());
source.getSelectionModel().selectFirst(); source.getSelectionModel().selectFirst();
target.setItems(market.vendorsProperty()); target.setItems(FXCollections.observableArrayList(market.vendorsProperty()));
target.getItems().add(0, null);
tblOrders.getItems().clear(); tblOrders.getItems().clear();
totalBalance.setValue(balance.getValue()); totalBalance.setValue(balance.getValue());
totalProfit.setValue(0); totalProfit.setValue(0);
@@ -129,6 +132,7 @@ public class RoutersController {
tblOrders.getItems().clear(); tblOrders.getItems().clear();
totalBalance.setValue(balance.getValue()); totalBalance.setValue(balance.getValue());
totalProfit.setValue(0); totalProfit.setValue(0);
path.setContent(null);
} }
@@ -139,14 +143,45 @@ public class RoutersController {
} }
} }
public void showOrders(){
VendorModel s = source.getSelectionModel().getSelectedItem();
VendorModel t = target.getSelectionModel().getSelectedItem();
OrderModel order;
if (t==null){
order = Screeners.showTopOrders(market.getOrders(s, totalBalance.getValue().doubleValue()));
} else {
order = Screeners.showTopOrders(market.getOrders(t, s, totalBalance.getValue().doubleValue()));
}
if (order!=null){
tblOrders.getItems().add(order);
}
}
public void showRoutes(){ public void showRoutes(){
VendorModel s = source.getSelectionModel().getSelectedItem(); VendorModel s = source.getSelectionModel().getSelectedItem();
VendorModel t = target.getSelectionModel().getSelectedItem(); VendorModel t = target.getSelectionModel().getSelectedItem();
if (t==null) return; PathRouteModel path;
if (t==null){
MarketModel market = MainController.getMarket(); path = Screeners.showRouters(market.getRoutes(s, totalBalance.getValue().doubleValue()));
Screeners.showRouters(market.getRouters(s, t, totalBalance.getValue().doubleValue())); } else {
path = Screeners.showRouters(market.getRoutes(s, t, totalBalance.getValue().doubleValue()));
}
if (path!=null){
tblOrders.getItems().addAll(path.getOrders());
setPath(path);
}
} }
public void showTopRoutes(){
PathRouteModel path = Screeners.showRouters(market.getTopRoutes(totalBalance.getValue().doubleValue()));
if (path!=null){
tblOrders.getItems().addAll(path.getOrders());
setPath(path);
}
}
private void setPath(PathRouteModel route){
path.setContent(new RouteNode(route).getNode());
}
} }

View File

@@ -160,7 +160,7 @@ public class Screeners {
return topOrdersController.showDialog(mainScreen, topOrdersScreen, top); return topOrdersController.showDialog(mainScreen, topOrdersScreen, top);
} }
public static void showRouters(ObservableList<PathRouteModel> routers) { public static PathRouteModel showRouters(ObservableList<PathRouteModel> routers) {
pathsController.showDialog(mainScreen, pathsScreen, routers); return pathsController.showDialog(mainScreen, pathsScreen, routers);
} }
} }

View File

@@ -3,11 +3,11 @@ package ru.trader.model;
import javafx.beans.property.ListProperty; import javafx.beans.property.ListProperty;
import javafx.beans.property.ReadOnlyListProperty; import javafx.beans.property.ReadOnlyListProperty;
import javafx.beans.property.SimpleListProperty; import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import ru.trader.core.*; import ru.trader.core.*;
import ru.trader.graph.PathRoute;
import ru.trader.model.support.BindingsHelper; import ru.trader.model.support.BindingsHelper;
import ru.trader.model.support.ChangeMarketListener; import ru.trader.model.support.ChangeMarketListener;
@@ -169,15 +169,15 @@ public class MarketModel {
return ModelFabrica.getModel(vendor, this); return ModelFabrica.getModel(vendor, this);
} }
public ObservableList<OrderModel> getTop(int limit, double balance){ public OrderModel asModel(Order order) {
return BindingsHelper.observableList(analyzer.getTop(limit, balance), (o) -> { return new OrderModel(asOfferDescModel(order.getSell()), asModel(order.getBuy()), order.getCount());
OrderModel model = new OrderModel(asOfferDescModel(o.getSell()), balance, analyzer.getCargo());
model.setBuyer(asModel(o.getBuy()));
model.setCount(model.getMax());
return model;
});
} }
public PathRouteModel asModel(PathRoute path) {
return new PathRouteModel(path, this);
}
public void setCargo(long cargo){ public void setCargo(long cargo){
analyzer.setCargo(cargo); analyzer.setCargo(cargo);
} }
@@ -194,7 +194,28 @@ public class MarketModel {
analyzer.setMaxDistance(distance); analyzer.setMaxDistance(distance);
} }
public ObservableList<PathRouteModel> getRouters(VendorModel from, VendorModel to, double balance){ public ObservableList<OrderModel> getOrders(VendorModel from, double balance) {
return BindingsHelper.observableList(analyzer.getPaths(from.getVendor(), to.getVendor(), balance), PathRouteModel::new); return BindingsHelper.observableList(analyzer.getOrders(from.getVendor(), balance), this::asModel);
} }
public ObservableList<OrderModel> getOrders(VendorModel from, VendorModel to, double balance) {
return BindingsHelper.observableList(analyzer.getOrders(from.getVendor(), to.getVendor(), balance), this::asModel);
}
public ObservableList<OrderModel> getTop(int limit, double balance){
return BindingsHelper.observableList(analyzer.getTop(limit, balance), this::asModel);
}
public ObservableList<PathRouteModel> getRoutes(VendorModel from, double balance){
return BindingsHelper.observableList(analyzer.getPaths(from.getVendor(), balance), this::asModel);
}
public ObservableList<PathRouteModel> getRoutes(VendorModel from, VendorModel to, double balance){
return BindingsHelper.observableList(analyzer.getPaths(from.getVendor(), to.getVendor(), balance), this::asModel);
}
public ObservableList<PathRouteModel> getTopRoutes(double balance){
return BindingsHelper.observableList(analyzer.getTopPaths(100, balance), this::asModel);
}
} }

View File

@@ -31,6 +31,13 @@ public class OrderModel {
}; };
} }
public OrderModel(OfferDescModel sellOffer, OfferModel buyOffer, long max) {
this(sellOffer);
this.max = max;
setBuyer(buyOffer);
setCount(max);
}
public OrderModel(OfferDescModel offer, double balance, long limit) { public OrderModel(OfferDescModel offer, double balance, long limit) {
this(offer); this(offer);
this.max = Math.min(limit, (long) Math.floor(balance / offer.getPrice())); this.max = Math.min(limit, (long) Math.floor(balance / offer.getPrice()));

View File

@@ -1,28 +1,35 @@
package ru.trader.model; package ru.trader.model;
import ru.trader.core.Vendor; import ru.trader.core.Order;
import ru.trader.graph.PathRoute; import ru.trader.graph.PathRoute;
import java.util.ArrayList;
import java.util.Collection;
public class PathRouteModel { public class PathRouteModel {
private final MarketModel market;
private final double distance; private final double distance;
private final double totalProfit; private final double totalProfit;
private final int jumps; private final int jumps;
private final int refuels; private final int refuels;
private final int lands;
private final PathRoute path; private final PathRoute path;
public PathRouteModel(PathRoute path) { PathRouteModel(PathRoute path, MarketModel market) {
this.market = market;
this.path = path; this.path = path;
PathRoute p = path.getRoot(); PathRoute p = path.getRoot();
double pr =0, d = 0; int j = 0, r = 0; totalProfit = p.getProfit();
double d = 0; int j = 0, r = 0, l = 0;
while (p.hasNext()){ while (p.hasNext()){
p = p.getNext(); p = p.getNext();
d += path.getDistance(); d += p.getDistance();
pr += p.getMaxProfit();
j++; j++;
if (p.isRefill()) r++; if (p.isRefill()) r++;
if (p.getBest() != null || p.isRefill()) l++;
} }
totalProfit = pr; lands = l;
distance = d; distance = d;
jumps = j; jumps = j;
refuels = r; refuels = r;
@@ -47,4 +54,29 @@ public class PathRouteModel {
public PathRoute getPath() { public PathRoute getPath() {
return path; return path;
} }
public int getLands() {
return lands;
}
public double getAvgProfit(){
return totalProfit/lands;
}
public Collection<OrderModel> getOrders(){
Collection<OrderModel> res = new ArrayList<>(lands);
PathRoute p = path.getRoot();
Order cargo = null;
while (p.hasNext()){
p = p.getNext();
if (cargo == null && p.getBest()!=null){
cargo = p.getBest();
res.add(market.asModel(cargo));
}
if (cargo!=null && cargo.isBuyer(p.get())){
cargo = null;
}
}
return res;
}
} }

View File

@@ -0,0 +1,86 @@
package ru.trader.view.support;
import javafx.scene.Node;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import org.controlsfx.glyphfont.GlyphFontRegistry;
import ru.trader.core.Order;
import ru.trader.graph.PathRoute;
import ru.trader.model.PathRouteModel;
public class RouteNode {
private final static String CSS_PATH = "path";
private final static String CSS_ICONS = "path-icons";
private final static String CSS_TRACK = "path-track";
private final static String CSS_TRACK_TEXT = "path-track-text";
private final static String CSS_VENDOR = "path-vendor";
private final PathRoute path;
private final HBox node = new HBox();
public RouteNode(PathRouteModel path) {
this.path = path.getPath();
node.getStyleClass().add(CSS_PATH);
build();
}
private void build(){
HBox v = new HBox();
VBox icons = new VBox();
VBox track = new VBox();
VBox.setVgrow(track, Priority.ALWAYS);
VBox.setVgrow(icons, Priority.ALWAYS);
v.getStyleClass().add(CSS_VENDOR);
icons.getStyleClass().add(CSS_ICONS);
track.getStyleClass().add(CSS_TRACK);
PathRoute p = path.getRoot();
v.getChildren().add(new Text(p.get().getName()));
Order cargo = null;
while (p.hasNext()){
p = p.getNext();
if (cargo == null && p.getBest() != null){
cargo = p.getBest();
icons.getChildren().add(GlyphFontRegistry.glyph("FontAwesome|UPLOAD_ALT"));
}
if (p.isRefill()) icons.getChildren().add(GlyphFontRegistry.glyph("FontAwesome|REFRESH"));
node.getChildren().addAll(v, icons);
Text t = new Text(String.format("(%.2f LY)", p.getDistance()));
t.getStyleClass().add(CSS_TRACK_TEXT);
track.getChildren().addAll(t, GlyphFontRegistry.glyph("FontAwesome|LONG_ARROW_RIGHT"));
node.getChildren().addAll(track);
v = new HBox();
icons = new VBox();
track = new VBox(0);
VBox.setVgrow(track, Priority.ALWAYS);
VBox.setVgrow(icons, Priority.ALWAYS);
v.getStyleClass().add(CSS_VENDOR);
icons.getStyleClass().add(CSS_ICONS);
track.getStyleClass().add(CSS_TRACK);
v.getChildren().add(new Text(p.get().getName()));
v.getChildren().add(icons);
if (cargo != null && cargo.isBuyer(p.get())){
v.getChildren().add(new Text(String.format(" (%+.0f) ", cargo.getProfit())));
cargo = null;
icons.getChildren().add(GlyphFontRegistry.glyph("FontAwesome|DOWNLOAD_ALT"));
}
}
node.getChildren().addAll(v, icons);
}
public Node getNode() {
return node;
}
}

View File

@@ -1,49 +1,25 @@
package ru.trader.view.support.cells; package ru.trader.view.support.cells;
import javafx.geometry.Pos;
import javafx.scene.control.TableCell; import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn; import javafx.scene.control.TableColumn;
import javafx.scene.layout.HBox; import javafx.scene.control.TableRow;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.util.Callback; import javafx.util.Callback;
import org.controlsfx.glyphfont.GlyphFontRegistry;
import ru.trader.core.Order;
import ru.trader.graph.PathRoute;
import ru.trader.model.PathRouteModel; import ru.trader.model.PathRouteModel;
import ru.trader.view.support.RouteNode;
public class PathRouteCell<T> implements Callback<TableColumn<PathRouteModel, T>, TableCell<PathRouteModel, T>> { public class PathRouteCell<T> implements Callback<TableColumn<PathRouteModel, T>, TableCell<PathRouteModel, T>> {
@Override @Override
public TableCell<PathRouteModel, T> call(TableColumn<PathRouteModel, T> param) { public TableCell<PathRouteModel, T> call(TableColumn<PathRouteModel, T> param) {
return new TableCell<PathRouteModel, T>(){ return new TableCell<PathRouteModel, T>(){
@Override @Override
public void updateItem(T value, boolean empty) { public void updateItem(T value, boolean empty) {
super.updateItem(value, empty); super.updateItem(value, empty);
if (!empty){ TableRow row = getTableRow();
PathRoute p = ((PathRouteModel) getTableRow().getItem()).getPath().getRoot(); if (!empty && row !=null && row.getItem() != null){
HBox hBox = new HBox(); RouteNode route = new RouteNode((PathRouteModel) row.getItem());
HBox v = new HBox();
v.setAlignment(Pos.BOTTOM_CENTER);
v.getChildren().add(new Text(p.get().getName()));
while (p.hasNext()){
p = p.getNext();
if (p.isRefill()) v.getChildren().add(GlyphFontRegistry.glyph("FontAwesome|REFRESH"));
hBox.getChildren().add(v);
VBox dist = new VBox(new Text(String.format("(%+.0f LY)", p.getDistance())));
dist.setAlignment(Pos.BASELINE_CENTER);
dist.getChildren().add(GlyphFontRegistry.glyph("FontAwesome|LONG_ARROW_RIGHT"));
hBox.getChildren().addAll(dist);
v = new HBox();
v.setAlignment(Pos.BOTTOM_CENTER);
v.getChildren().add(new Text(p.get().getName()));
v.getChildren().add(new Text(String.format(" (%+.0f) ", p.getMaxProfit())));
}
hBox.getChildren().add(v);
setText(null); setText(null);
setGraphic(hBox); setGraphic(route.getNode());
} else { } else {
setText(null); setText(null);
setGraphic(null); setGraphic(null);

View File

@@ -11,7 +11,7 @@
<?import ru.trader.view.support.cells.DoubleCell?> <?import ru.trader.view.support.cells.DoubleCell?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" <HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ru.trader.controllers.OffersController"> fx:controller="ru.trader.controllers.OffersController">
<TitledPane text="Станции" minWidth="260" prefHeight="500" collapsible="false"> <TitledPane text="Станции" minWidth="250" prefHeight="510" collapsible="false">
<ListView fx:id="vendors" /> <ListView fx:id="vendors" />
</TitledPane> </TitledPane>

View File

@@ -12,34 +12,38 @@
<?import ru.trader.view.support.cells.PathRouteCell?> <?import ru.trader.view.support.cells.PathRouteCell?>
<HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" <HBox xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="ru.trader.controllers.PathsController" styleClass="dialog" fx:controller="ru.trader.controllers.PathsController" styleClass="dialog"
prefWidth="900"> prefWidth="1050">
<TableView fx:id="tblPaths" editable="true"> <TableView fx:id="tblPaths" editable="true">
<columns> <columns>
<TableColumn minWidth="640.0" text="Путь"> <TableColumn minWidth="600.0" text="Путь">
<cellFactory><PathRouteCell /></cellFactory> <cellFactory><PathRouteCell /></cellFactory>
</TableColumn> </TableColumn>
<TableColumn minWidth="70.0" text="Прыжков">
<TableColumn minWidth="60.0" text="Заправок">
<cellValueFactory><PropertyValueFactory property="refuels"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="60.0" text="Прыжков">
<cellValueFactory><PropertyValueFactory property="jumps"/></cellValueFactory> <cellValueFactory><PropertyValueFactory property="jumps"/></cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn minWidth="70.0" text="Заправок">
<TableColumn minWidth="60.0" text="Дистанция"> <cellValueFactory><PropertyValueFactory property="refuels"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="70.0" text="Посадок">
<cellValueFactory><PropertyValueFactory property="lands"/></cellValueFactory>
</TableColumn>
<TableColumn minWidth="80.0" text="Дистанция">
<cellFactory><DoubleCell format="\%.2f LY"/></cellFactory> <cellFactory><DoubleCell format="\%.2f LY"/></cellFactory>
<cellValueFactory><PropertyValueFactory property="distance"/></cellValueFactory> <cellValueFactory><PropertyValueFactory property="distance"/></cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn fx:id="profit" minWidth="80.0" text="Прибыль" sortType="DESCENDING"> <TableColumn minWidth="70.0" text="Прибыль">
<cellValueFactory><PropertyValueFactory property="totalProfit"/></cellValueFactory> <cellValueFactory><PropertyValueFactory property="totalProfit"/></cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn fx:id="avgProfit" minWidth="70.0" text="Ср." sortType="DESCENDING">
<cellFactory><DoubleCell format="\%.0f"/></cellFactory>
<cellValueFactory><PropertyValueFactory property="avgProfit"/></cellValueFactory>
</TableColumn>
</columns> </columns>
<columnResizePolicy> <columnResizePolicy>
<TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/> <TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy> </columnResizePolicy>
<sortOrder> <sortOrder>
<fx:reference source="profit"/> <fx:reference source="avgProfit"/>
</sortOrder> </sortOrder>
</TableView> </TableView>
</HBox> </HBox>

View File

@@ -22,13 +22,13 @@
<ColumnConstraints minWidth="90" maxWidth="90"/> <ColumnConstraints minWidth="90" maxWidth="90"/>
</columnConstraints> </columnConstraints>
<Label text="Баланс:"/> <Label text="Баланс:"/>
<NumberField fx:id="balance" value="1000" GridPane.columnIndex="1" /> <NumberField fx:id="balance" GridPane.columnIndex="1" />
<Label text="Трюм:" GridPane.rowIndex="1" /> <Label text="Трюм:" GridPane.rowIndex="1" />
<NumberField fx:id="cargo" value="4" GridPane.columnIndex="1" GridPane.rowIndex="1" /> <NumberField fx:id="cargo" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Label text="Запас топлива(LY):" GridPane.rowIndex="2" /> <Label text="Запас топлива(LY):" GridPane.rowIndex="2" />
<NumberField fx:id="tank" value="30" GridPane.columnIndex="1" GridPane.rowIndex="2" /> <NumberField fx:id="tank" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Label text="Дистанция прыжка(LY):" GridPane.rowIndex="3" /> <Label text="Дистанция прыжка(LY):" GridPane.rowIndex="3" />
<NumberField fx:id="distance" value="7" GridPane.columnIndex="1" GridPane.rowIndex="3" /> <NumberField fx:id="distance" GridPane.columnIndex="1" GridPane.rowIndex="3" />
</GridPane> </GridPane>
</TitledPane> </TitledPane>
<TitledPane text="Параметры маршрута" minHeight="250" collapsible="false"> <TitledPane text="Параметры маршрута" minHeight="250" collapsible="false">
@@ -42,18 +42,22 @@
<Label text="До:" GridPane.rowIndex="1"/> <Label text="До:" GridPane.rowIndex="1"/>
<ComboBox fx:id="target" prefWidth="160" GridPane.columnIndex="1" GridPane.rowIndex="1"/> <ComboBox fx:id="target" prefWidth="160" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="Прыжков:" GridPane.rowIndex="2" /> <Label text="Прыжков:" GridPane.rowIndex="2" />
<NumberField fx:id="jumps" value="4" GridPane.columnIndex="1" GridPane.rowIndex="2" /> <NumberField fx:id="jumps" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Separator GridPane.columnSpan="2" GridPane.rowIndex="3" GridPane.margin="$separator_margin"/> <Separator GridPane.columnSpan="2" GridPane.rowIndex="3" GridPane.margin="$separator_margin"/>
<VBox GridPane.columnSpan="2" GridPane.rowIndex="4" spacing="20"> <VBox GridPane.columnSpan="2" GridPane.rowIndex="4" spacing="5">
<HBox alignment="CENTER" spacing="5"> <HBox alignment="CENTER" spacing="5">
<Button fx:id="add" text="Добавить" onAction="#addOrders"/> <Button fx:id="add" text="Добавить" onAction="#addOrders"/>
<Button text="Удалить" onAction="#removeSelected"/> <Button text="Удалить" onAction="#removeSelected"/>
<Button text="Очистить" onAction="#removeAll" /> <Button text="Очистить" onAction="#removeAll" />
</HBox> </HBox>
<HBox alignment="CENTER" spacing="5"> <HBox alignment="CENTER" spacing="5">
<Button prefWidth="80" text="Заказы" onAction="#showOrders" />
<Button text="TOP 100" onAction="#showTopOrders" /> <Button text="TOP 100" onAction="#showTopOrders" />
<Button text="Маршруты" onAction="#showRoutes" /> </HBox>
<HBox alignment="CENTER" spacing="5">
<Button prefWidth="80" text="Маршруты" onAction="#showRoutes" />
<Button text="TOP 100" onAction="#showTopRoutes" />
</HBox> </HBox>
</VBox> </VBox>
</GridPane> </GridPane>
@@ -72,7 +76,8 @@
</GridPane> </GridPane>
</TitledPane> </TitledPane>
</VBox> </VBox>
<TableView fx:id="tblOrders" HBox.hgrow="ALWAYS"> <VBox HBox.hgrow="ALWAYS">
<TableView fx:id="tblOrders" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn minWidth="210.0" text="Продавец"> <TableColumn minWidth="210.0" text="Продавец">
<cellValueFactory><PropertyValueFactory property="vendor"/></cellValueFactory> <cellValueFactory><PropertyValueFactory property="vendor"/></cellValueFactory>
@@ -103,4 +108,6 @@
<TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/> <TableView fx:constant="UNCONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy> </columnResizePolicy>
</TableView> </TableView>
<ScrollPane fx:id="path" styleClass="path-pane" minHeight="100" fitToHeight="true"/>
</VBox>
</HBox> </HBox>

View File

@@ -48,3 +48,39 @@ HBox.fields-group hbox-margin{
.center { .center {
-fx-alignment: center; -fx-alignment: center;
} }
/* Path */
.path {
-fx-alignment: center-left;
-fx-spacing: 5px;
-fx-fill-height: true;
}
.path-vendor {
-fx-alignment: center-left;
-fx-text-alignment: left;
}
.path-icons {
-fx-alignment: center;
}
.path-track {
-fx-padding: 0 8;
-fx-alignment: center;
}
.path-track .text {
-fx-font-size: 16pt;
}
.path-track-text {
-fx-font-size: 7pt;
}
.path-pane {
-fx-padding: 10;
-fx-alignment: center-left;
}

View File

@@ -60,6 +60,42 @@ public class MarketAnalyzer {
return top; return top;
} }
public Collection<Order> getOrders(Vendor vendor, double balance) {
Collection<Order> res = new ArrayList<>();
for (Offer sell : vendor.getAllSellOffers()) {
long count = Math.min(cargo, (long) Math.floor(balance / sell.getPrice()));
LOG.trace("Sell offer {}, count = {}", sell, count);
if (count == 0) continue;
Iterator<Offer> buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator();
while (buyers.hasNext()){
Offer buy = buyers.next();
Order order = new Order(sell, buy, count);
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
res.add(order);
}
}
return res;
}
public Collection<Order> getOrders(Vendor from, Vendor to, double balance) {
Collection<Order> res = new ArrayList<>();
for (Offer sell : from.getAllSellOffers()) {
long count = Math.min(cargo, (long) Math.floor(balance / sell.getPrice()));
LOG.trace("Sell offer {}, count = {}", sell, count);
if (count == 0) continue;
Offer buy = to.getBuy(sell.getItem());
if (buy != null){
Order order = new Order(sell, buy, count);
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
res.add(order);
}
}
return res;
}
private void rebuild(Vendor source){ private void rebuild(Vendor source){
graph = new Graph<>(source, market.get(), tank, maxDistance, true, jumps, PathRoute::new); graph = new Graph<>(source, market.get(), tank, maxDistance, true, jumps, PathRoute::new);
} }
@@ -74,6 +110,22 @@ public class MarketAnalyzer {
return graph.getPathsTo(to, true); return graph.getPathsTo(to, true);
} }
public Path<Vendor> getPath(Vendor from, Vendor to){
setSource(from);
return graph.getFastPathTo(to);
}
public Collection<PathRoute> getPaths(Vendor from, double balance){
Collection<PathRoute> res = new ArrayList<>();
for (Vendor vendor : market.get()) {
PathRoute path = (PathRoute) getPath(from, vendor);
if (path == null) continue;
path.sort(balance, cargo);
res.add(path);
}
return res;
}
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){ public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
Collection<Path<Vendor>> paths = getPaths(from, to); Collection<Path<Vendor>> paths = getPaths(from, to);
Collection<PathRoute> res = new ArrayList<>(paths.size()); Collection<PathRoute> res = new ArrayList<>(paths.size());
@@ -85,6 +137,21 @@ public class MarketAnalyzer {
return res; return res;
} }
public Collection<PathRoute> getTopPaths(int limit, double balance){
TreeSet<PathRoute> top = new TreeSet<>((p1, p2) -> Double.compare(p2.getProfit(), p1.getProfit()));
for (Vendor vendor : market.get()) {
Collection<PathRoute> paths = getPaths(vendor, vendor, balance);
for (PathRoute path : paths) {
top.add(path);
if (top.size() > limit) {
top.pollLast();
}
}
}
return top;
}
public void setTank(double tank) { public void setTank(double tank) {
this.tank = tank; this.tank = tank;
this.graph = null; this.graph = null;
@@ -107,4 +174,5 @@ public class MarketAnalyzer {
public long getCargo() { public long getCargo() {
return cargo; return cargo;
} }
} }

View File

@@ -142,6 +142,7 @@ public class Graph<T extends Connectable<T>> {
public Path<T> getFastPathTo(T entry){ public Path<T> getFastPathTo(T entry){
Vertex<T> target = getVertex(entry); Vertex<T> target = getVertex(entry);
if (target == null) return null;
return findFastPath(pathFabric.build(root), target, target.getLevel()+1, stock); return findFastPath(pathFabric.build(root), target, target.getLevel()+1, stock);
} }

View File

@@ -49,7 +49,7 @@ public class PathRoute extends Path<Vendor> {
} }
public PathRoute getCopy(){ public PathRoute getCopy(){
PathRoute path = (PathRoute) getRoot(); PathRoute path = getRoot();
PathRoute res = new PathRoute(path.getTarget()); PathRoute res = new PathRoute(path.getTarget());
while (path.hasNext()){ while (path.hasNext()){
path = path.getNext(); path = path.getNext();
@@ -180,10 +180,10 @@ public class PathRoute extends Path<Vendor> {
} }
private void backwardSort(){ private void backwardSort(){
if (isRoot()) return;
orders.sort(this::compareOrders); orders.sort(this::compareOrders);
LOG.trace("New order of orders {}", orders); LOG.trace("New order of orders {}", orders);
updateProfit(); updateProfit();
if (!isRoot())
getPrevious().backwardSort(); getPrevious().backwardSort();
} }
@@ -209,10 +209,10 @@ public class PathRoute extends Path<Vendor> {
private void updateProfit() { private void updateProfit() {
Order best = orders.get(0); Order best = orders.isEmpty()? TRANSIT : orders.get(0);
if (best == TRANSIT) profit = getTransitProfit(); if (best == TRANSIT) profit = getTransitProfit();
else profit = getProfit(best); else profit = getProfit(best);
LOG.trace("Max profit from {} = {}", getPrevious().get(), profit); LOG.trace("Max profit from {} = {}", isRoot() ? get() : getPrevious().get(), profit);
} }
private double getTransitProfit(){ private double getTransitProfit(){

View File

@@ -37,14 +37,17 @@ public class PathRouteTest extends Assert {
res = (PathRoute) res.connectTo(new Vertex<>(v2), false); res = (PathRoute) res.connectTo(new Vertex<>(v2), false);
res.finish(); res.finish();
res.sort(10000, 5); res.sort(10000, 5);
return (PathRoute) res.getRoot(); return res.getRoot();
} }
@Test @Test
public void testPathRoute1() throws Exception { public void testPathRoute1() throws Exception {
LOG.info("Start path route test 1"); LOG.info("Start path route test 1");
PathRoute path = initTest1().getNext(); PathRoute path = initTest1();
assertEquals(1000, path.getProfit(), 0.0001);
path = path.getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
@@ -74,13 +77,16 @@ public class PathRouteTest extends Assert {
res = (PathRoute) res.connectTo(new Vertex<>(v3), false); res = (PathRoute) res.connectTo(new Vertex<>(v3), false);
res.finish(); res.finish();
res.sort(10000, 5); res.sort(10000, 5);
return (PathRoute) res.getRoot(); return res.getRoot();
} }
@Test @Test
public void testPathRoute2() throws Exception { public void testPathRoute2() throws Exception {
LOG.info("Start path route test 2"); LOG.info("Start path route test 2");
PathRoute path = initTest2().getNext(); PathRoute path = initTest2();
assertEquals(1000, path.getProfit(), 0.0001);
path = path.getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
@@ -123,13 +129,16 @@ public class PathRouteTest extends Assert {
res = (PathRoute) res.connectTo(new Vertex<>(v4), false); res = (PathRoute) res.connectTo(new Vertex<>(v4), false);
res.finish(); res.finish();
res.sort(10000, 5); res.sort(10000, 5);
return (PathRoute) res.getRoot(); return res.getRoot();
} }
@Test @Test
public void testPathRoute3() throws Exception { public void testPathRoute3() throws Exception {
LOG.info("Start path route test 3"); LOG.info("Start path route test 3");
PathRoute path = initTest3().getNext(); PathRoute path = initTest3();
assertEquals(800, path.getProfit(), 0.0001);
path = path.getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);
@@ -184,13 +193,16 @@ public class PathRouteTest extends Assert {
res = (PathRoute) res.connectTo(new Vertex<>(v5), false); res = (PathRoute) res.connectTo(new Vertex<>(v5), false);
res.finish(); res.finish();
res.sort(10000, 5); res.sort(10000, 5);
return (PathRoute) res.getRoot(); return res.getRoot();
} }
@Test @Test
public void testPathRoute4() throws Exception { public void testPathRoute4() throws Exception {
LOG.info("Start path route test 4"); LOG.info("Start path route test 4");
PathRoute path = initTest4().getNext(); PathRoute path = initTest4();
assertEquals(1000, path.getProfit(), 0.0001);
path = path.getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v2.getBuy(ITEM1), 5);
@@ -251,13 +263,16 @@ public class PathRouteTest extends Assert {
res = (PathRoute) res.connectTo(new Vertex<>(v4), false); res = (PathRoute) res.connectTo(new Vertex<>(v4), false);
res.finish(); res.finish();
res.sort(500, 5); res.sort(500, 5);
return (PathRoute) res.getRoot(); return res.getRoot();
} }
@Test @Test
public void testPathRoute5() throws Exception { public void testPathRoute5() throws Exception {
LOG.info("Start path route test 5"); LOG.info("Start path route test 5");
PathRoute path = initTest5().getNext(); PathRoute path = initTest5();
assertEquals(620, path.getProfit(), 0.0001);
path = path.getNext();
Collection<Order> orders = path.getOrders(); Collection<Order> orders = path.getOrders();
Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5); Order order1 = new Order(v1.getSell(ITEM1), v3.getBuy(ITEM1), 5);