implement filter for market analyzer
This commit is contained in:
@@ -93,6 +93,7 @@ public class Main extends Application {
|
|||||||
Screeners.loadPathsStage(getUrl(("paths.fxml")));
|
Screeners.loadPathsStage(getUrl(("paths.fxml")));
|
||||||
Screeners.loadSettingsStage(getUrl(("settings.fxml")));
|
Screeners.loadSettingsStage(getUrl(("settings.fxml")));
|
||||||
Screeners.loadSEditorStage(getUrl(("sEditor.fxml")));
|
Screeners.loadSEditorStage(getUrl(("sEditor.fxml")));
|
||||||
|
Screeners.loadFilterStage(getUrl(("filter.fxml")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static URL getUrl(String filename) throws MalformedURLException {
|
private static URL getUrl(String filename) throws MalformedURLException {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ru.trader;
|
|||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
@@ -125,4 +126,12 @@ public class Settings {
|
|||||||
public int getPathsCount(){
|
public int getPathsCount(){
|
||||||
return Integer.valueOf(values.getProperty("performance.limit","100"));
|
return Integer.valueOf(values.getProperty("performance.limit","100"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MarketFilter getFilter(Market market){
|
||||||
|
return MarketFilter.buildFilter(values, market);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilter(MarketFilter filter){
|
||||||
|
filter.writeTo(values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package ru.trader;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import ru.trader.core.Market;
|
import ru.trader.core.Market;
|
||||||
import ru.trader.core.MarketAnalyzer;
|
import ru.trader.core.MarketAnalyzer;
|
||||||
import ru.trader.model.ModelFabric;
|
|
||||||
import ru.trader.store.simple.SimpleMarket;
|
import ru.trader.store.simple.SimpleMarket;
|
||||||
import ru.trader.store.simple.Store;
|
import ru.trader.store.simple.Store;
|
||||||
import ru.trader.store.XSSFImporter;
|
import ru.trader.store.XSSFImporter;
|
||||||
@@ -47,6 +46,7 @@ public class World {
|
|||||||
MarketAnalyzer analyzer = new MarketAnalyzer(market);
|
MarketAnalyzer analyzer = new MarketAnalyzer(market);
|
||||||
analyzer.setSegmentSize(Main.SETTINGS.getSegmentSize());
|
analyzer.setSegmentSize(Main.SETTINGS.getSegmentSize());
|
||||||
analyzer.setPathsCount(Main.SETTINGS.getPathsCount());
|
analyzer.setPathsCount(Main.SETTINGS.getPathsCount());
|
||||||
|
analyzer.setFilter(Main.SETTINGS.getFilter(market));
|
||||||
return analyzer;
|
return analyzer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
151
client/src/main/java/ru/trader/controllers/FilterController.java
Normal file
151
client/src/main/java/ru/trader/controllers/FilterController.java
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
package ru.trader.controllers;
|
||||||
|
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
|
import javafx.fxml.FXML;
|
||||||
|
import javafx.scene.Parent;
|
||||||
|
import javafx.scene.control.CheckBox;
|
||||||
|
import javafx.scene.control.ComboBox;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import org.controlsfx.control.ButtonBar;
|
||||||
|
import org.controlsfx.control.action.Action;
|
||||||
|
import org.controlsfx.dialog.Dialog;
|
||||||
|
import org.controlsfx.dialog.DialogAction;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.MarketFilter;
|
||||||
|
import ru.trader.core.SERVICE_TYPE;
|
||||||
|
import ru.trader.model.MarketModel;
|
||||||
|
import ru.trader.model.ModelFabric;
|
||||||
|
import ru.trader.model.StationModel;
|
||||||
|
import ru.trader.model.SystemModel;
|
||||||
|
import ru.trader.model.support.BindingsHelper;
|
||||||
|
import ru.trader.view.support.Localization;
|
||||||
|
import ru.trader.view.support.NumberField;
|
||||||
|
import ru.trader.view.support.cells.CustomListCell;
|
||||||
|
|
||||||
|
|
||||||
|
public class FilterController {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(FilterController.class);
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private ComboBox<SystemModel> center;
|
||||||
|
@FXML
|
||||||
|
private NumberField radius;
|
||||||
|
@FXML
|
||||||
|
private NumberField distance;
|
||||||
|
@FXML
|
||||||
|
private ComboBox<SystemModel> system;
|
||||||
|
@FXML
|
||||||
|
private ComboBox<StationModel> station;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbMarket;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbBlackMarket;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbRepair;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbMunition;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbOutfit;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbShipyard;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbMediumLandpad;
|
||||||
|
@FXML
|
||||||
|
private CheckBox cbLargeLandpad;
|
||||||
|
@FXML
|
||||||
|
private ListView<StationModel> excludes;
|
||||||
|
|
||||||
|
public final Action actSave = new DialogAction(Localization.getString("dialog.button.save"), ButtonBar.ButtonType.OK_DONE, false, true, false, (e) -> save());
|
||||||
|
|
||||||
|
private MarketModel market;
|
||||||
|
private MarketFilter filter;
|
||||||
|
|
||||||
|
@FXML
|
||||||
|
private void initialize(){
|
||||||
|
system.valueProperty().addListener((ov, o, n) -> station.setItems(n.getStationsList()));
|
||||||
|
excludes.setCellFactory(new CustomListCell<>(s -> String.format("%s (%s)", s.getSystem().getName(), s.getName())));
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(){
|
||||||
|
market = MainController.getMarket();
|
||||||
|
center.setItems(market.systemsListProperty());
|
||||||
|
system.setItems(market.systemsProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fill(MarketFilter filter){
|
||||||
|
this.filter = filter;
|
||||||
|
center.setValue(market.getModeler().get(filter.getCenter()));
|
||||||
|
radius.setValue(filter.getRadius());
|
||||||
|
distance.setValue(filter.getDistance());
|
||||||
|
cbMarket.setSelected(filter.has(SERVICE_TYPE.MARKET));
|
||||||
|
cbBlackMarket.setSelected(filter.has(SERVICE_TYPE.BLACK_MARKET));
|
||||||
|
cbMunition.setSelected(filter.has(SERVICE_TYPE.MUNITION));
|
||||||
|
cbRepair.setSelected(filter.has(SERVICE_TYPE.REPAIR));
|
||||||
|
cbOutfit.setSelected(filter.has(SERVICE_TYPE.OUTFIT));
|
||||||
|
cbShipyard.setSelected(filter.has(SERVICE_TYPE.SHIPYARD));
|
||||||
|
cbMediumLandpad.setSelected(filter.has(SERVICE_TYPE.MEDIUM_LANDPAD));
|
||||||
|
cbLargeLandpad.setSelected(filter.has(SERVICE_TYPE.LARGE_LANDPAD));
|
||||||
|
excludes.setItems(BindingsHelper.observableList(filter.getExcludes(), market.getModeler()::get));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void save() {
|
||||||
|
SystemModel s = center.getValue();
|
||||||
|
LOG.trace("Old filter", filter);
|
||||||
|
filter.setCenter(s == ModelFabric.NONE_SYSTEM ? null : market.getModeler().get(s));
|
||||||
|
filter.setRadius(radius.getValue().doubleValue());
|
||||||
|
filter.setDistance(distance.getValue().doubleValue());
|
||||||
|
if (cbMarket.isSelected()) filter.add(SERVICE_TYPE.MARKET); else filter.remove(SERVICE_TYPE.MARKET);
|
||||||
|
if (cbBlackMarket.isSelected()) filter.add(SERVICE_TYPE.BLACK_MARKET); else filter.remove(SERVICE_TYPE.BLACK_MARKET);
|
||||||
|
if (cbMunition.isSelected()) filter.add(SERVICE_TYPE.MUNITION); else filter.remove(SERVICE_TYPE.MUNITION);
|
||||||
|
if (cbRepair.isSelected()) filter.add(SERVICE_TYPE.REPAIR); else filter.remove(SERVICE_TYPE.REPAIR);
|
||||||
|
if (cbOutfit.isSelected()) filter.add(SERVICE_TYPE.OUTFIT); else filter.remove(SERVICE_TYPE.OUTFIT);
|
||||||
|
if (cbShipyard.isSelected()) filter.add(SERVICE_TYPE.SHIPYARD); else filter.remove(SERVICE_TYPE.SHIPYARD);
|
||||||
|
if (cbMediumLandpad.isSelected()) filter.add(SERVICE_TYPE.MEDIUM_LANDPAD); else filter.remove(SERVICE_TYPE.MEDIUM_LANDPAD);
|
||||||
|
if (cbLargeLandpad.isSelected()) filter.add(SERVICE_TYPE.LARGE_LANDPAD); else filter.remove(SERVICE_TYPE.LARGE_LANDPAD);
|
||||||
|
filter.clearExcludes();
|
||||||
|
excludes.getItems().forEach(st -> filter.addExclude(market.getModeler().get(st)));
|
||||||
|
LOG.trace("New filter", filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action showDialog(Parent parent, Parent content){
|
||||||
|
return showDialog(parent, content, new MarketFilter());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action showDialog(Parent parent, Parent content, MarketFilter filter){
|
||||||
|
Dialog dlg = new Dialog(parent, Localization.getString("filter.title"));
|
||||||
|
dlg.setContent(content);
|
||||||
|
dlg.getActions().addAll(actSave, Dialog.ACTION_CANCEL);
|
||||||
|
dlg.setResizable(false);
|
||||||
|
fill(filter);
|
||||||
|
return dlg.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(ActionEvent actionEvent) {
|
||||||
|
SystemModel s = system.getValue();
|
||||||
|
if (s != null){
|
||||||
|
StationModel st = station.getValue();
|
||||||
|
if (st != null && st != ModelFabric.NONE_STATION){
|
||||||
|
excludes.getItems().add(st);
|
||||||
|
} else {
|
||||||
|
excludes.getItems().addAll(s.getStations());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(ActionEvent actionEvent) {
|
||||||
|
int index = excludes.getSelectionModel().getSelectedIndex();
|
||||||
|
if (index >= 0){
|
||||||
|
excludes.getItems().remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clean(ActionEvent actionEvent) {
|
||||||
|
excludes.getItems().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarketFilter getFilter(){
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -177,6 +177,10 @@ public class MainController {
|
|||||||
Screeners.showSettings();
|
Screeners.showSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void editFilter(){
|
||||||
|
Screeners.showFilter(market.getAnalyzer().getFilter());
|
||||||
|
}
|
||||||
|
|
||||||
private void reload(){
|
private void reload(){
|
||||||
world = new MarketModel(World.getMarket());
|
world = new MarketModel(World.getMarket());
|
||||||
market = world;
|
market = world;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import javafx.stage.Stage;
|
|||||||
import org.controlsfx.control.action.Action;
|
import org.controlsfx.control.action.Action;
|
||||||
import org.controlsfx.dialog.Dialogs;
|
import org.controlsfx.dialog.Dialogs;
|
||||||
import ru.trader.EMDNUpdater;
|
import ru.trader.EMDNUpdater;
|
||||||
|
import ru.trader.Main;
|
||||||
|
import ru.trader.core.MarketFilter;
|
||||||
import ru.trader.model.*;
|
import ru.trader.model.*;
|
||||||
import ru.trader.view.support.CustomBuilderFactory;
|
import ru.trader.view.support.CustomBuilderFactory;
|
||||||
import ru.trader.view.support.Localization;
|
import ru.trader.view.support.Localization;
|
||||||
@@ -29,6 +31,7 @@ public class Screeners {
|
|||||||
private static Parent pathsScreen;
|
private static Parent pathsScreen;
|
||||||
private static Parent settingsScreen;
|
private static Parent settingsScreen;
|
||||||
private static Parent sEditorScreen;
|
private static Parent sEditorScreen;
|
||||||
|
private static Parent filterScreen;
|
||||||
|
|
||||||
private static MainController mainController;
|
private static MainController mainController;
|
||||||
private static ItemDescController itemDescController;
|
private static ItemDescController itemDescController;
|
||||||
@@ -39,6 +42,7 @@ public class Screeners {
|
|||||||
private static PathsController pathsController;
|
private static PathsController pathsController;
|
||||||
private static SettingsController settingsController;
|
private static SettingsController settingsController;
|
||||||
private static SystemsEditorController systemsEditorController;
|
private static SystemsEditorController systemsEditorController;
|
||||||
|
private static FilterController filterController;
|
||||||
|
|
||||||
private static FXMLLoader initLoader(URL url){
|
private static FXMLLoader initLoader(URL url){
|
||||||
FXMLLoader loader = new FXMLLoader(url, Localization.getResources());
|
FXMLLoader loader = new FXMLLoader(url, Localization.getResources());
|
||||||
@@ -127,6 +131,12 @@ public class Screeners {
|
|||||||
systemsEditorController = loader.getController();
|
systemsEditorController = loader.getController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void loadFilterStage(URL fxml) throws IOException {
|
||||||
|
FXMLLoader loader = initLoader(fxml);
|
||||||
|
filterScreen = loader.load();
|
||||||
|
addStylesheet(filterScreen);
|
||||||
|
filterController = loader.getController();
|
||||||
|
}
|
||||||
|
|
||||||
public static void show(Node node){
|
public static void show(Node node){
|
||||||
mainController.getMainPane().setCenter(node);
|
mainController.getMainPane().setCenter(node);
|
||||||
@@ -195,8 +205,21 @@ public class Screeners {
|
|||||||
settingsController.showDialog(mainScreen, settingsScreen);
|
settingsController.showDialog(mainScreen, settingsScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MarketFilter showFilter() {
|
||||||
|
Action res = filterController.showDialog(mainScreen, filterScreen);
|
||||||
|
return res == filterController.actSave ? filterController.getFilter() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showFilter(MarketFilter filter) {
|
||||||
|
Action res = filterController.showDialog(mainScreen, filterScreen, filter);
|
||||||
|
if (res == filterController.actSave){
|
||||||
|
Main.SETTINGS.setFilter(filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void reinitAll() {
|
public static void reinitAll() {
|
||||||
mainController.init();
|
mainController.init();
|
||||||
|
filterController.init();
|
||||||
EMDNUpdater.setMarket(MainController.getMarket());
|
EMDNUpdater.setMarket(MainController.getMarket());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public class ModelFabric {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Place get(SystemModel model){
|
||||||
|
return model.getSystem();
|
||||||
|
}
|
||||||
|
|
||||||
public StationModel get(Vendor station){
|
public StationModel get(Vendor station){
|
||||||
if (station == null) return NONE_STATION;
|
if (station == null) return NONE_STATION;
|
||||||
@@ -60,6 +63,9 @@ public class ModelFabric {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vendor get(StationModel model){
|
||||||
|
return model.getStation();
|
||||||
|
}
|
||||||
|
|
||||||
public ItemModel get(Item item){
|
public ItemModel get(Item item){
|
||||||
if (item == null) return null;
|
if (item == null) return null;
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package ru.trader.view.support.cells;
|
||||||
|
|
||||||
|
import javafx.scene.control.ListCell;
|
||||||
|
import javafx.scene.control.ListView;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class CustomListCell<T> implements Callback<ListView<T>, ListCell<T>> {
|
||||||
|
|
||||||
|
private final Function<T, String> toString;
|
||||||
|
|
||||||
|
public CustomListCell(Function<T, String> toString) {
|
||||||
|
this.toString = toString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ListCell<T> call(ListView<T> param){
|
||||||
|
return new ListCell<T>(){
|
||||||
|
@Override
|
||||||
|
public void updateItem(T item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
if (item != null && !empty){
|
||||||
|
setText(toString.apply(item));
|
||||||
|
setGraphic(null);
|
||||||
|
} else {
|
||||||
|
setText(null);
|
||||||
|
setGraphic(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,6 +57,7 @@ main.menu.settings=Settings
|
|||||||
main.menu.settings.language=Language
|
main.menu.settings.language=Language
|
||||||
main.menu.settings.language.item=English
|
main.menu.settings.language.item=English
|
||||||
main.menu.settings.parameters=Preferences
|
main.menu.settings.parameters=Preferences
|
||||||
|
main.menu.settings.filter=Filter
|
||||||
|
|
||||||
# add item dialog
|
# add item dialog
|
||||||
dialog.addItem.title=Adding new commodity
|
dialog.addItem.title=Adding new commodity
|
||||||
@@ -123,3 +124,11 @@ settings.performance.limit=Routes count:
|
|||||||
sEditor.title=Star systems editor
|
sEditor.title=Star systems editor
|
||||||
sEditor.text.orientates=Landmarks:
|
sEditor.text.orientates=Landmarks:
|
||||||
sEditor.table.distance=Distance (LY)
|
sEditor.table.distance=Distance (LY)
|
||||||
|
|
||||||
|
# filter.fxml
|
||||||
|
filter.title=Edit Filter
|
||||||
|
filter.center=Center:
|
||||||
|
filter.radius=Rsdius(LY):
|
||||||
|
filter.distance=Distance to station(Ls):
|
||||||
|
filter.services=Services:
|
||||||
|
filter.excludes=Excludes stations:
|
||||||
@@ -58,7 +58,7 @@ main.menu.settings=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
|
|||||||
main.menu.settings.language=\u042F\u0437\u044B\u043A
|
main.menu.settings.language=\u042F\u0437\u044B\u043A
|
||||||
main.menu.settings.language.item=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
|
main.menu.settings.language.item=\u0420\u0443\u0441\u0441\u043A\u0438\u0439
|
||||||
main.menu.settings.parameters=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B
|
main.menu.settings.parameters=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B
|
||||||
|
main.menu.settings.filter=\u0424\u0438\u043B\u044C\u0442\u0440
|
||||||
|
|
||||||
# add item dialog
|
# add item dialog
|
||||||
dialog.addItem.title=\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0433\u043E \u0442\u043E\u0432\u0430\u0440\u0430
|
dialog.addItem.title=\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u043E\u0432\u043E\u0433\u043E \u0442\u043E\u0432\u0430\u0440\u0430
|
||||||
@@ -124,3 +124,11 @@ settings.performance.limit=\u041A\u043E\u043B-\u0432\u043E \u043C\u0430\u0440\u0
|
|||||||
sEditor.title=\u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440 \u0437\u0432\u0435\u0437\u0434\u043D\u044B\u0445 \u0441\u0438\u0441\u0442\u0435\u043C
|
sEditor.title=\u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440 \u0437\u0432\u0435\u0437\u0434\u043D\u044B\u0445 \u0441\u0438\u0441\u0442\u0435\u043C
|
||||||
sEditor.text.orientates=\u041E\u0440\u0438\u0435\u043D\u0442\u0438\u0440\u044B:
|
sEditor.text.orientates=\u041E\u0440\u0438\u0435\u043D\u0442\u0438\u0440\u044B:
|
||||||
sEditor.table.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F (LY)
|
sEditor.table.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F (LY)
|
||||||
|
|
||||||
|
# filter.fxml
|
||||||
|
filter.title=\u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 \u0444\u0438\u043B\u044C\u0442\u0440\u0430
|
||||||
|
filter.center=\u0426\u0435\u043D\u0442\u0440:
|
||||||
|
filter.radius=\u0420\u0430\u0434\u0438\u0443\u0441(LY):
|
||||||
|
filter.distance=\u0414\u0438\u0441\u0442\u0430\u043D\u0446\u0438\u044F \u0434\u043E \u0441\u0442\u0430\u043D\u0446\u0438\u0438(Ls):
|
||||||
|
filter.services=\u0421\u0435\u0440\u0432\u0438\u0441\u044B:
|
||||||
|
filter.excludes=\u0418\u0441\u043A\u043B\u044E\u0447\u0430\u0435\u043C\u044B\u0435 \u0441\u0442\u0430\u043D\u0446\u0438\u0438:
|
||||||
52
client/src/main/resources/view/filter.fxml
Normal file
52
client/src/main/resources/view/filter.fxml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?import javafx.scene.layout.GridPane?>
|
||||||
|
<?import javafx.scene.layout.ColumnConstraints?>
|
||||||
|
<?import javafx.scene.control.Label?>
|
||||||
|
<?import ru.trader.view.support.NumberField?>
|
||||||
|
|
||||||
|
|
||||||
|
<?import javafx.scene.control.CheckBox?>
|
||||||
|
<?import javafx.scene.control.ComboBox?>
|
||||||
|
<?import javafx.scene.layout.TilePane?>
|
||||||
|
<?import javafx.scene.layout.VBox?>
|
||||||
|
<?import javafx.scene.layout.HBox?>
|
||||||
|
<?import org.controlsfx.glyphfont.Glyph?>
|
||||||
|
<?import javafx.scene.control.Button?>
|
||||||
|
<?import javafx.scene.control.ListView?>
|
||||||
|
<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ru.trader.controllers.FilterController"
|
||||||
|
styleClass="dialog" vgap="4" hgap="8">
|
||||||
|
<columnConstraints>
|
||||||
|
<ColumnConstraints minWidth="180" maxWidth="180"/>
|
||||||
|
<ColumnConstraints minWidth="220" maxWidth="220"/>
|
||||||
|
</columnConstraints>
|
||||||
|
<Label text="%filter.title" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2"/>
|
||||||
|
<Label text="%filter.center" GridPane.rowIndex="1"/>
|
||||||
|
<ComboBox fx:id="center" GridPane.columnIndex="1" GridPane.rowIndex="1" minWidth="220"/>
|
||||||
|
<Label text="%filter.radius" GridPane.rowIndex="2" />
|
||||||
|
<NumberField fx:id="radius" GridPane.columnIndex="1" GridPane.rowIndex="2" />
|
||||||
|
<Label text="%filter.distance" GridPane.rowIndex="3" />
|
||||||
|
<NumberField fx:id="distance" GridPane.columnIndex="1" GridPane.rowIndex="3" />
|
||||||
|
<Label text="%filter.services" GridPane.rowIndex="4" />
|
||||||
|
<TilePane hgap="5" vgap="5" tileAlignment="BASELINE_LEFT" GridPane.columnIndex="1" GridPane.rowIndex="4" >
|
||||||
|
<CheckBox fx:id="cbMarket" text="%services.MARKET"/>
|
||||||
|
<CheckBox fx:id="cbBlackMarket" text="%services.BLACK_MARKET"/>
|
||||||
|
<CheckBox fx:id="cbRepair" text="%services.REPAIR"/>
|
||||||
|
<CheckBox fx:id="cbMunition" text="%services.MUNITION"/>
|
||||||
|
<CheckBox fx:id="cbOutfit" text="%services.OUTFIT"/>
|
||||||
|
<CheckBox fx:id="cbShipyard" text="%services.SHIPYARD"/>
|
||||||
|
<CheckBox fx:id="cbMediumLandpad" text="%services.MEDIUM_LANDPAD"/>
|
||||||
|
<CheckBox fx:id="cbLargeLandpad" text="%services.LARGE_LANDPAD"/>
|
||||||
|
</TilePane>
|
||||||
|
<Label text="%filter.excludes" GridPane.rowIndex="5" />
|
||||||
|
<VBox GridPane.rowIndex="6" spacing="4">
|
||||||
|
<ComboBox fx:id="system" minWidth="180"/>
|
||||||
|
<ComboBox fx:id="station" minWidth="180"/>
|
||||||
|
<HBox spacing="2" alignment="BASELINE_RIGHT">
|
||||||
|
<Button prefWidth="30" onAction="#add"><graphic><Glyph text="FontAwesome|PLUS"/></graphic></Button>
|
||||||
|
<Button prefWidth="30" onAction="#remove"><graphic><Glyph text="FontAwesome|MINUS"/></graphic></Button>
|
||||||
|
<Button prefWidth="30" onAction="#clean"><graphic><Glyph text="FontAwesome|TRASH_ALT"/></graphic></Button>
|
||||||
|
</HBox>
|
||||||
|
</VBox>
|
||||||
|
<ListView fx:id="excludes" GridPane.rowIndex="6" GridPane.columnIndex="1" maxHeight="200"/>
|
||||||
|
|
||||||
|
</GridPane>
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<MenuItem text="%main.menu.edit.removeStation" onAction="#removeStation"/>
|
<MenuItem text="%main.menu.edit.removeStation" onAction="#removeStation"/>
|
||||||
</Menu>
|
</Menu>
|
||||||
<Menu text="%main.menu.settings">
|
<Menu text="%main.menu.settings">
|
||||||
|
<MenuItem text="%main.menu.settings.filter" onAction="#editFilter"/>
|
||||||
<MenuItem text="%main.menu.settings.parameters" onAction="#editSettings"/>
|
<MenuItem text="%main.menu.settings.parameters" onAction="#editSettings"/>
|
||||||
<Menu fx:id="langs" text="%main.menu.settings.language"/>
|
<Menu fx:id="langs" text="%main.menu.settings.language"/>
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|||||||
@@ -1,12 +1,17 @@
|
|||||||
package ru.trader.core;
|
package ru.trader.core;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface Market {
|
public interface Market {
|
||||||
|
|
||||||
void add(Place place);
|
void add(Place place);
|
||||||
Place addPlace(String name, double x, double y, double z);
|
Place addPlace(String name, double x, double y, double z);
|
||||||
void remove(Place place);
|
void remove(Place place);
|
||||||
|
default Place get(String name){
|
||||||
|
Optional<Place> place = get().stream().filter(p -> name.equals(p.getName())).findFirst();
|
||||||
|
return place.isPresent() ? place.get() : null;
|
||||||
|
}
|
||||||
|
|
||||||
void add(Group group);
|
void add(Group group);
|
||||||
Group addGroup(String name, GROUP_TYPE type);
|
Group addGroup(String name, GROUP_TYPE type);
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import java.util.*;
|
|||||||
public class MarketAnalyzer {
|
public class MarketAnalyzer {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class);
|
private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class);
|
||||||
|
|
||||||
private Market market;
|
private final Market market;
|
||||||
|
private MarketFilter filter;
|
||||||
private double tank;
|
private double tank;
|
||||||
private double maxDistance;
|
private double maxDistance;
|
||||||
private int segmentSize;
|
private int segmentSize;
|
||||||
@@ -25,221 +26,10 @@ public class MarketAnalyzer {
|
|||||||
this.segmentSize = 0;
|
this.segmentSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Order> getTop(double balance){
|
public void setFilter(MarketFilter filter) {
|
||||||
LOG.debug("Get top {}", limit);
|
this.filter = filter;
|
||||||
Iterable<Place> places = market.get();
|
|
||||||
List<Order> top = new ArrayList<>(limit);
|
|
||||||
for (Place place : places) {
|
|
||||||
LOG.trace("Check place {}", place);
|
|
||||||
Collection<Order> orders = getOrders(place, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit());
|
|
||||||
TopList.addAllToTop(top, orders, limit, orderComparator);
|
|
||||||
}
|
|
||||||
return top;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Order> getOrders(Vendor vendor, double balance) {
|
|
||||||
Collection<Place> places = market.get();
|
|
||||||
Graph<Place> graph = new Graph<Place>(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new);
|
|
||||||
return getOrders(graph, Collections.singleton(vendor), balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Order> getOrders(Place place, double balance) {
|
|
||||||
return getOrders(place, balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Order> getOrders(Place place, double balance, double lowProfit) {
|
|
||||||
Collection<Place> places = market.get();
|
|
||||||
Graph<Place> graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new);
|
|
||||||
return getOrders(graph, place.get(), balance, lowProfit);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Order> getOrders(Graph<Place> graph, Collection<Vendor> sellers, double balance, double lowProfit) {
|
|
||||||
List<Order> res = new ArrayList<>(20);
|
|
||||||
for (Vendor vendor : sellers) {
|
|
||||||
for (Offer sell : vendor.getAllSellOffers()) {
|
|
||||||
LOG.trace("Sell offer {}", sell);
|
|
||||||
if (sell.getCount() == 0) continue;
|
|
||||||
long count = Order.getMaxCount(sell, balance, cargo);
|
|
||||||
LOG.trace("count = {}", count);
|
|
||||||
if (count == 0) continue;
|
|
||||||
Iterator<Offer> buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator();
|
|
||||||
while (buyers.hasNext()){
|
|
||||||
Offer buy = buyers.next();
|
|
||||||
if (!graph.isAccessible(buy.getVendor().getPlace())){
|
|
||||||
LOG.trace("Is inaccessible buyer, skip");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Order order = new Order(sell, buy, count);
|
|
||||||
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
|
|
||||||
if (order.getProfit() <= 0 && order.getCount() > 0) break;
|
|
||||||
if (order.getProfit() < lowProfit && order.getCount() == count) {
|
|
||||||
LOG.trace("Is low profit, skip");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
res.add(order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.sort(orderComparator);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Order> getOrders(Collection<Vendor> sellers, Collection<Vendor> buyers, double balance, double lowProfit) {
|
|
||||||
List<Order> res = new ArrayList<>();
|
|
||||||
for (Vendor seller : sellers) {
|
|
||||||
for (Offer sell : seller.getAllSellOffers()) {
|
|
||||||
if (sell.getCount() == 0) continue;
|
|
||||||
long count = Order.getMaxCount(sell, balance, cargo);
|
|
||||||
LOG.trace("Sell offer {}, count = {}", sell, count);
|
|
||||||
if (count == 0) continue;
|
|
||||||
for (Vendor buyer : buyers) {
|
|
||||||
Offer buy = buyer.getBuy(sell.getItem());
|
|
||||||
if (buy != null){
|
|
||||||
Order order = new Order(sell, buy, count);
|
|
||||||
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
|
|
||||||
if (order.getProfit() < lowProfit) {
|
|
||||||
LOG.trace("Is low profit, skip");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
res.add(order);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.sort(orderComparator);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Order> getOrders(Vendor from, Vendor to, double balance) {
|
|
||||||
Graph<Place> graph = new Graph<Place>(from.getPlace(), market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
if (!graph.isAccessible(to.getPlace())){
|
|
||||||
LOG.trace("Is inaccessible buyer");
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return getOrders(Collections.singleton(from), Collections.singleton(to), balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Order> getOrders(Place from, Place to, double balance) {
|
|
||||||
Graph<Place> graph = new Graph<Place>(from, market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
if (!graph.isAccessible(to)){
|
|
||||||
LOG.trace("Is inaccessible buyer");
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return getOrders(from.get(), to.get(), balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Collection<Order> getOrders(Vendor from, Place to, double balance) {
|
|
||||||
Graph<Place> graph = new Graph<Place>(from.getPlace(), market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
if (!graph.isAccessible(to)){
|
|
||||||
LOG.trace("Is inaccessible buyer");
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return getOrders(Collections.singleton(from), to.get(), balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<Order> getOrders(Place from, Vendor to, double balance) {
|
|
||||||
Graph<Place> graph = new Graph<Place>(from, market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
if (!graph.isAccessible(to.getPlace())){
|
|
||||||
LOG.trace("Is inaccessible buyer");
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
return getOrders(from.get(), Collections.singleton(to), balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Collection<Path<Place>> getPaths(Place from, Place to){
|
|
||||||
Graph<Place> graph = new Graph<Place>(from, market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
return graph.getPathsTo(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path<Place> getPath(Place from, Place to){
|
|
||||||
Graph<Place> graph = new Graph<Place>(from, market.get(), tank, maxDistance, true, jumps, Path::new);
|
|
||||||
return graph.getFastPathTo(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PathRoute getPath(Vendor from, Vendor to){
|
|
||||||
RouteGraph graph = new RouteGraph(from, market.getVendors(), tank, maxDistance, true, jumps);
|
|
||||||
return (PathRoute)graph.getFastPathTo(to);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Vendor from, double balance){
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = market.getVendors();
|
|
||||||
return searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Place from, double balance){
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = market.getVendors();
|
|
||||||
for (Vendor vendor : from.get()) {
|
|
||||||
Collection<PathRoute> paths = searcher.getPaths(vendor, vendors, jumps, balance, cargo, limit);
|
|
||||||
if (paths.size()>0){
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
return searcher.getPaths(from, to, market.getVendors(), jumps, balance, cargo, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Place from, Place to, double balance){
|
|
||||||
List<PathRoute> top = new ArrayList<>(limit);
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = market.getVendors();
|
|
||||||
Collection<Vendor> fVendors = from.get();
|
|
||||||
Collection<Vendor> toVendors = to.get();
|
|
||||||
int count = (int) Math.ceil(limit / fVendors.size());
|
|
||||||
for (Vendor fromVendor : fVendors) {
|
|
||||||
for (Vendor toVendor : toVendors) {
|
|
||||||
Collection<PathRoute> paths = searcher.getPaths(fromVendor, toVendor, vendors, jumps, balance, cargo, count);
|
|
||||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Vendor from, Place to, double balance){
|
|
||||||
List<PathRoute> top = new ArrayList<>(limit);
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = market.getVendors();
|
|
||||||
Collection<Vendor> toVendors = to.get();
|
|
||||||
int count = (int) Math.ceil(limit / toVendors.size());
|
|
||||||
for (Vendor toVendor : toVendors) {
|
|
||||||
Collection<PathRoute> paths = searcher.getPaths(from, toVendor, vendors, jumps, balance, cargo, count);
|
|
||||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
|
||||||
}
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getPaths(Place from, Vendor to, double balance){
|
|
||||||
List<PathRoute> top = new ArrayList<>(limit);
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = market.getVendors();
|
|
||||||
Collection<Vendor> fVendors = from.get();
|
|
||||||
int count = (int) Math.ceil(limit / fVendors.size());
|
|
||||||
for (Vendor fromVendor : fVendors) {
|
|
||||||
Collection<PathRoute> paths = searcher.getPaths(fromVendor, to, vendors, jumps, balance, cargo, count);
|
|
||||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
|
||||||
}
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Collection<PathRoute> getTopPaths(double balance){
|
|
||||||
List<PathRoute> top = new ArrayList<>(limit);
|
|
||||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
|
||||||
Collection<Vendor> vendors = new PlacesWrapper(market.get());
|
|
||||||
for (Vendor vendor : vendors) {
|
|
||||||
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
|
|
||||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
|
||||||
}
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void setTank(double tank) {
|
public void setTank(double tank) {
|
||||||
this.tank = tank;
|
this.tank = tank;
|
||||||
}
|
}
|
||||||
@@ -263,4 +53,279 @@ public class MarketAnalyzer {
|
|||||||
public void setPathsCount(int count) {
|
public void setPathsCount(int count) {
|
||||||
this.limit = count;
|
this.limit = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getTop(double balance){
|
||||||
|
LOG.debug("Get top {}", limit);
|
||||||
|
Iterable<Place> places = getPlaces();
|
||||||
|
List<Order> top = new ArrayList<>(limit);
|
||||||
|
for (Place place : places) {
|
||||||
|
LOG.trace("Check place {}", place);
|
||||||
|
Collection<Order> orders = getOrders(place, balance, top.isEmpty() ? 0 : top.get(top.size()-1).getProfit());
|
||||||
|
TopList.addAllToTop(top, orders, limit, orderComparator);
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Vendor vendor, double balance) {
|
||||||
|
Collection<Place> places = getPlaces();
|
||||||
|
Graph<Place> graph = new Graph<Place>(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new);
|
||||||
|
return getOrders(graph, Collections.singleton(vendor), balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Place place, double balance) {
|
||||||
|
return getOrders(place, balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Order> getOrders(Place place, double balance, double lowProfit) {
|
||||||
|
Collection<Place> places = getPlaces();
|
||||||
|
Graph<Place> graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new);
|
||||||
|
return getOrders(graph, place.get(), balance, lowProfit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Order> getOrders(Graph<Place> graph, Collection<Vendor> sellers, double balance, double lowProfit) {
|
||||||
|
List<Order> res = new ArrayList<>(20);
|
||||||
|
for (Vendor vendor : sellers) {
|
||||||
|
if (isFiltered(vendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Offer sell : vendor.getAllSellOffers()) {
|
||||||
|
LOG.trace("Sell offer {}", sell);
|
||||||
|
if (sell.getCount() == 0) continue;
|
||||||
|
long count = Order.getMaxCount(sell, balance, cargo);
|
||||||
|
LOG.trace("count = {}", count);
|
||||||
|
if (count == 0) continue;
|
||||||
|
Iterator<Offer> buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator();
|
||||||
|
while (buyers.hasNext()){
|
||||||
|
Offer buy = buyers.next();
|
||||||
|
if (isFiltered(buy.getVendor())){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!graph.isAccessible(buy.getVendor().getPlace())){
|
||||||
|
LOG.trace("Is inaccessible buyer, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Order order = new Order(sell, buy, count);
|
||||||
|
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
|
||||||
|
if (order.getProfit() <= 0 && order.getCount() > 0) break;
|
||||||
|
if (order.getProfit() < lowProfit && order.getCount() == count) {
|
||||||
|
LOG.trace("Is low profit, skip");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
res.add(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.sort(orderComparator);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Order> getOrders(Collection<Vendor> sellers, Collection<Vendor> buyers, double balance, double lowProfit) {
|
||||||
|
List<Order> res = new ArrayList<>();
|
||||||
|
for (Vendor seller : sellers) {
|
||||||
|
if (isFiltered(seller)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Offer sell : seller.getAllSellOffers()) {
|
||||||
|
if (sell.getCount() == 0) continue;
|
||||||
|
long count = Order.getMaxCount(sell, balance, cargo);
|
||||||
|
LOG.trace("Sell offer {}, count = {}", sell, count);
|
||||||
|
if (count == 0) continue;
|
||||||
|
for (Vendor buyer : buyers) {
|
||||||
|
if (isFiltered(buyer)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Offer buy = buyer.getBuy(sell.getItem());
|
||||||
|
if (buy != null){
|
||||||
|
Order order = new Order(sell, buy, count);
|
||||||
|
LOG.trace("Buy offer {} profit = {}", buy, order.getProfit());
|
||||||
|
if (order.getProfit() < lowProfit) {
|
||||||
|
LOG.trace("Is low profit, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
res.add(order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.sort(orderComparator);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Vendor from, Vendor to, double balance) {
|
||||||
|
Graph<Place> graph = new Graph<Place>(from.getPlace(), getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
if (!graph.isAccessible(to.getPlace())){
|
||||||
|
LOG.trace("Is inaccessible buyer");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return getOrders(Collections.singleton(from), Collections.singleton(to), balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Place from, Place to, double balance) {
|
||||||
|
Graph<Place> graph = new Graph<Place>(from, getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
if (!graph.isAccessible(to)){
|
||||||
|
LOG.trace("Is inaccessible buyer");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return getOrders(from.get(), to.get(), balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Vendor from, Place to, double balance) {
|
||||||
|
Graph<Place> graph = new Graph<Place>(from.getPlace(), getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
if (!graph.isAccessible(to)){
|
||||||
|
LOG.trace("Is inaccessible buyer");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return getOrders(Collections.singleton(from), to.get(), balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Order> getOrders(Place from, Vendor to, double balance) {
|
||||||
|
Graph<Place> graph = new Graph<Place>(from, getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
if (!graph.isAccessible(to.getPlace())){
|
||||||
|
LOG.trace("Is inaccessible buyer");
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return getOrders(from.get(), Collections.singleton(to), balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Collection<Path<Place>> getPaths(Place from, Place to){
|
||||||
|
Graph<Place> graph = new Graph<Place>(from, getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
return graph.getPathsTo(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path<Place> getPath(Place from, Place to){
|
||||||
|
Graph<Place> graph = new Graph<Place>(from, getPlaces(), tank, maxDistance, true, jumps, Path::new);
|
||||||
|
return graph.getFastPathTo(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PathRoute getPath(Vendor from, Vendor to){
|
||||||
|
RouteGraph graph = new RouteGraph(from, getVendors(), tank, maxDistance, true, jumps);
|
||||||
|
return (PathRoute)graph.getFastPathTo(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Vendor from, double balance){
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
return searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Place from, double balance){
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
for (Vendor vendor : from.get()) {
|
||||||
|
if (isFiltered(vendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Collection<PathRoute> paths = searcher.getPaths(vendor, vendors, jumps, balance, cargo, limit);
|
||||||
|
if (paths.size()>0){
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Vendor from, Vendor to, double balance){
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
return searcher.getPaths(from, to, getVendors(), jumps, balance, cargo, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Place from, Place to, double balance){
|
||||||
|
List<PathRoute> top = new ArrayList<>(limit);
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
Collection<Vendor> fVendors = from.get();
|
||||||
|
Collection<Vendor> toVendors = to.get();
|
||||||
|
int count = (int) Math.ceil(limit / fVendors.size());
|
||||||
|
for (Vendor fromVendor : fVendors) {
|
||||||
|
if (isFiltered(fromVendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Vendor toVendor : toVendors) {
|
||||||
|
if (isFiltered(toVendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Collection<PathRoute> paths = searcher.getPaths(fromVendor, toVendor, vendors, jumps, balance, cargo, count);
|
||||||
|
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Vendor from, Place to, double balance){
|
||||||
|
List<PathRoute> top = new ArrayList<>(limit);
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
Collection<Vendor> toVendors = to.get();
|
||||||
|
int count = (int) Math.ceil(limit / toVendors.size());
|
||||||
|
for (Vendor toVendor : toVendors) {
|
||||||
|
if (isFiltered(toVendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Collection<PathRoute> paths = searcher.getPaths(from, toVendor, vendors, jumps, balance, cargo, count);
|
||||||
|
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getPaths(Place from, Vendor to, double balance){
|
||||||
|
List<PathRoute> top = new ArrayList<>(limit);
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
Collection<Vendor> fVendors = from.get();
|
||||||
|
int count = (int) Math.ceil(limit / fVendors.size());
|
||||||
|
for (Vendor fromVendor : fVendors) {
|
||||||
|
if (isFiltered(fromVendor)){
|
||||||
|
LOG.trace("Is filtered, skip");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Collection<PathRoute> paths = searcher.getPaths(fromVendor, to, vendors, jumps, balance, cargo, count);
|
||||||
|
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<PathRoute> getTopPaths(double balance){
|
||||||
|
List<PathRoute> top = new ArrayList<>(limit);
|
||||||
|
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||||
|
Collection<Vendor> vendors = getVendors();
|
||||||
|
for (Vendor vendor : vendors) {
|
||||||
|
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
|
||||||
|
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||||
|
}
|
||||||
|
return top;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Place> getPlaces(){
|
||||||
|
if (filter != null){
|
||||||
|
return filter.filtered(market.get());
|
||||||
|
} else {
|
||||||
|
return market.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Collection<Vendor> getVendors(){
|
||||||
|
if (filter != null){
|
||||||
|
Collection<Vendor> vendors = new PlacesWrapper(getPlaces());
|
||||||
|
return filter.filteredVendors(vendors);
|
||||||
|
} else {
|
||||||
|
return market.getVendors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MarketFilter getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFiltered(Vendor vendor){
|
||||||
|
return filter != null && (filter.isFiltered(vendor.getPlace()) || filter.isFiltered(vendor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
169
core/src/main/java/ru/trader/core/MarketFilter.java
Normal file
169
core/src/main/java/ru/trader/core/MarketFilter.java
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
package ru.trader.core;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class MarketFilter {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(MarketFilter.class);
|
||||||
|
|
||||||
|
private Place center;
|
||||||
|
private double radius;
|
||||||
|
private double distance;
|
||||||
|
private final EnumSet<SERVICE_TYPE> services;
|
||||||
|
private final Collection<Vendor> excludes;
|
||||||
|
|
||||||
|
public MarketFilter() {
|
||||||
|
services = EnumSet.noneOf(SERVICE_TYPE.class);
|
||||||
|
excludes = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Place getCenter() {
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCenter(Place center) {
|
||||||
|
this.center = center;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRadius() {
|
||||||
|
return radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRadius(double radius) {
|
||||||
|
this.radius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistance(double distance) {
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(SERVICE_TYPE service){
|
||||||
|
services.add(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAll(Collection<SERVICE_TYPE> service){
|
||||||
|
services.addAll(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(SERVICE_TYPE service){
|
||||||
|
services.remove(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(SERVICE_TYPE service){
|
||||||
|
return services.contains(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addExclude(Vendor vendor){
|
||||||
|
excludes.add(vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeExclude(Vendor vendor){
|
||||||
|
excludes.remove(vendor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearExcludes(){
|
||||||
|
excludes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Vendor> getExcludes(){
|
||||||
|
return excludes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFiltered(Place place){
|
||||||
|
return center != null && center.getDistance(place) > radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFiltered(Vendor vendor){
|
||||||
|
if (distance > 0 && vendor.getDistance() > distance) return true;
|
||||||
|
if (excludes.contains(vendor)) return true;
|
||||||
|
for (SERVICE_TYPE service : services) {
|
||||||
|
if (!vendor.has(service)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Place> filtered(Collection<Place> places){
|
||||||
|
return places.parallelStream().filter(p -> !isFiltered(p)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Vendor> filteredVendors(Collection<Vendor> vendors){
|
||||||
|
return vendors.parallelStream().filter(v -> !isFiltered(v)).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static MarketFilter buildFilter(Properties values, Market market){
|
||||||
|
MarketFilter filter = new MarketFilter();
|
||||||
|
String v = values.getProperty("filter.center", null);
|
||||||
|
if (v != null){
|
||||||
|
filter.setCenter(market.get(v));
|
||||||
|
}
|
||||||
|
filter.setRadius(Double.valueOf(values.getProperty("filter.radius","0")));
|
||||||
|
filter.setDistance(Double.valueOf(values.getProperty("filter.distance", "0")));
|
||||||
|
v = values.getProperty("filter.services", "");
|
||||||
|
if (v.length() > 0){
|
||||||
|
for (String s : v.split(",")) {
|
||||||
|
filter.add(SERVICE_TYPE.valueOf(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = values.getProperty("filter.excludes", "");
|
||||||
|
if (v.length() > 0){
|
||||||
|
for (String s : v.split(",")) {
|
||||||
|
String[] st = s.split("\\|");
|
||||||
|
Place place = market.get(st[0]);
|
||||||
|
if (place != null) {
|
||||||
|
Vendor vendor = place.get(st[1]);
|
||||||
|
if (vendor != null) {
|
||||||
|
filter.addExclude(vendor);
|
||||||
|
} else {
|
||||||
|
LOG.warn("Not found vendor {}", st[1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG.warn("Not found place {}", st[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeTo(Properties properties){
|
||||||
|
properties.setProperty("filter.center", center != null ? center.getName() : "");
|
||||||
|
properties.setProperty("filter.radius", String.valueOf(radius));
|
||||||
|
properties.setProperty("filter.distance", String.valueOf(distance));
|
||||||
|
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
for (SERVICE_TYPE service: services) {
|
||||||
|
if (s.length() > 0) s.append(",");
|
||||||
|
s.append(service);
|
||||||
|
}
|
||||||
|
properties.setProperty("filter.services", s.toString());
|
||||||
|
s = new StringBuilder();
|
||||||
|
for (Vendor vendor : excludes) {
|
||||||
|
if (s.length() > 0) s.append(",");
|
||||||
|
s.append(vendor.getPlace().getName());
|
||||||
|
s.append("|");
|
||||||
|
s.append(vendor.getName());
|
||||||
|
}
|
||||||
|
properties.setProperty("filter.excludes", s.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "{" +
|
||||||
|
"center=" + center +
|
||||||
|
", radius=" + radius +
|
||||||
|
", distance=" + distance +
|
||||||
|
", services=" + services +
|
||||||
|
", excludes=" + excludes +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package ru.trader.core;
|
|||||||
import ru.trader.graph.Connectable;
|
import ru.trader.graph.Connectable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public interface Place extends Connectable<Place> {
|
public interface Place extends Connectable<Place> {
|
||||||
|
|
||||||
@@ -15,6 +16,10 @@ public interface Place extends Connectable<Place> {
|
|||||||
void setPosition(double x, double y, double z);
|
void setPosition(double x, double y, double z);
|
||||||
|
|
||||||
Collection<Vendor> get();
|
Collection<Vendor> get();
|
||||||
|
default Vendor get(String name){
|
||||||
|
Optional<Vendor> vendor = get().stream().filter(p -> name.equals(p.getName())).findFirst();
|
||||||
|
return vendor.isPresent() ? vendor.get() : null;
|
||||||
|
}
|
||||||
void add(Vendor vendor);
|
void add(Vendor vendor);
|
||||||
Vendor addVendor(String name);
|
Vendor addVendor(String name);
|
||||||
void remove(Vendor vendor);
|
void remove(Vendor vendor);
|
||||||
|
|||||||
Reference in New Issue
Block a user