progress dialog prototype
This commit is contained in:
250
client/src/main/java/ru/trader/controllers/AnalyzerProgress.java
Normal file
250
client/src/main/java/ru/trader/controllers/AnalyzerProgress.java
Normal file
@@ -0,0 +1,250 @@
|
||||
package ru.trader.controllers;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.LongProperty;
|
||||
import javafx.beans.property.SimpleLongProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressBar;
|
||||
import javafx.scene.layout.HBox;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.stage.Stage;
|
||||
import ru.trader.core.MarketAnalyzer;
|
||||
import ru.trader.core.MarketAnalyzerCallBack;
|
||||
import ru.trader.core.Place;
|
||||
import ru.trader.core.Vendor;
|
||||
import ru.trader.graph.Connectable;
|
||||
import ru.trader.graph.GraphCallBack;
|
||||
import ru.trader.graph.RouteSearcherCallBack;
|
||||
import ru.trader.graph.Vertex;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
public class AnalyzerProgress {
|
||||
private VBox tasks;
|
||||
private TaskVisual task;
|
||||
|
||||
public void show(Parent main, String text, MarketAnalyzer analyzer){
|
||||
tasks = new VBox(5);
|
||||
task = new TaskVisual(text);
|
||||
Button button = new Button("Cancel");
|
||||
|
||||
Scene scene = new Scene(tasks, 200, 200);
|
||||
Stage stage = new Stage();
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
|
||||
MarketAnalyzerCallBack callBack = new AnalyzerCallBack(task);
|
||||
analyzer.setCallback(callBack);
|
||||
button.setOnAction(e -> callBack.cancel());
|
||||
createProgress(task);
|
||||
tasks.getChildren().add(button);
|
||||
|
||||
task.getSubTasks().addListener((ListChangeListener<TaskVisual>)l -> {
|
||||
while (l.next()) {
|
||||
if (l.wasRemoved()) {
|
||||
l.getRemoved().forEach(this::removeProgress);
|
||||
}
|
||||
if (l.wasAdded()) {
|
||||
l.getAddedSubList().forEach(this::createProgress);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createProgress(TaskVisual task){
|
||||
HBox hBox = new HBox(10);
|
||||
hBox.setUserData(task);
|
||||
Label txt = new Label("Процесс");
|
||||
ProgressBar bar = new ProgressBar();
|
||||
txt.textProperty().bind(task.messageProperty());
|
||||
bar.progressProperty().bind(task.countProperty().divide(task.maxProperty()));
|
||||
hBox.getChildren().addAll(txt, bar);
|
||||
tasks.getChildren().addAll(hBox);
|
||||
}
|
||||
|
||||
private void removeProgress(TaskVisual task){
|
||||
tasks.getChildren().removeIf(n -> task.equals(n.getUserData()));
|
||||
}
|
||||
|
||||
private class TaskVisual {
|
||||
private final StringProperty message;
|
||||
private final LongProperty count;
|
||||
private final LongProperty max;
|
||||
private final ObservableList<TaskVisual> subTasks;
|
||||
|
||||
private TaskVisual(String text) {
|
||||
message = new SimpleStringProperty(text);
|
||||
count = new SimpleLongProperty(0);
|
||||
max = new SimpleLongProperty(1);
|
||||
subTasks = FXCollections.observableArrayList();
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message.get();
|
||||
}
|
||||
|
||||
public StringProperty messageProperty() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
Platform.runLater(() -> this.message.set(message));
|
||||
}
|
||||
|
||||
public long getCount() {
|
||||
return count.get();
|
||||
}
|
||||
|
||||
public LongProperty countProperty() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(long count) {
|
||||
Platform.runLater(() -> this.count.set(count));
|
||||
}
|
||||
|
||||
public long getMax() {
|
||||
return max.get();
|
||||
}
|
||||
|
||||
public LongProperty maxProperty() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void setMax(long max) {
|
||||
Platform.runLater(() -> this.max.set(max));
|
||||
}
|
||||
|
||||
public ObservableList<TaskVisual> getSubTasks() {
|
||||
return subTasks;
|
||||
}
|
||||
|
||||
public void addSubTask(TaskVisual task){
|
||||
Platform.runLater(() -> {
|
||||
synchronized (subTasks) {
|
||||
subTasks.add(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void removeSubTask(TaskVisual task){
|
||||
Platform.runLater(() -> {
|
||||
synchronized (subTasks) {
|
||||
subTasks.remove(task);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class AnalyzerCallBack extends MarketAnalyzerCallBack {
|
||||
private final TaskVisual task;
|
||||
private final AtomicLong count = new AtomicLong();
|
||||
|
||||
private AnalyzerCallBack(TaskVisual task) {
|
||||
this.task = task;
|
||||
count.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RouteSearcherCallBack getRouteSearcherCallBackInstance() {
|
||||
return new RSCallBack(task);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected GraphCallBack<Place> getGraphCallBackInstance() {
|
||||
TaskVisual subtask = new TaskVisual("Build graph of system");
|
||||
task.addSubTask(subtask);
|
||||
return new GCallBack<Place>(subtask, task);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnd() {
|
||||
task.setMessage("Finish");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCount(long count) {
|
||||
task.setMax(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inc() {
|
||||
task.setCount(count.incrementAndGet());
|
||||
}
|
||||
}
|
||||
|
||||
private class RSCallBack extends RouteSearcherCallBack {
|
||||
private final TaskVisual task;
|
||||
|
||||
private RSCallBack(TaskVisual task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GraphCallBack<Vendor> getGraphCallBackInstance() {
|
||||
TaskVisual subtask = new TaskVisual("Build graph of stations");
|
||||
task.addSubTask(subtask);
|
||||
return new GCallBack<>(subtask, task);
|
||||
}
|
||||
}
|
||||
|
||||
private class GCallBack<T extends Connectable<T>> extends GraphCallBack<T> {
|
||||
private final TaskVisual task;
|
||||
private final TaskVisual owner;
|
||||
private final AtomicLong count = new AtomicLong();
|
||||
|
||||
private GCallBack(TaskVisual task, TaskVisual owner) {
|
||||
this.task = task;
|
||||
this.owner = owner;
|
||||
count.set(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartBuild(T from) {
|
||||
task.setMessage(String.format("Build graph from %s", from));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndBuild() {
|
||||
task.setMessage("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartFind(Vertex<T> from, Vertex<T> to) {
|
||||
if (to != null) {
|
||||
task.setMessage(String.format("Find path from %s graph to %s", from.getEntry(), to.getEntry()));
|
||||
} else {
|
||||
task.setMessage(String.format("Find path from %s graph", from.getEntry()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFound() {
|
||||
task.setMessage("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEndFind() {
|
||||
owner.removeSubTask(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCount(long count) {
|
||||
task.setMax(count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inc() {
|
||||
task.setCount(count.incrementAndGet());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package ru.trader.controllers;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.control.TableView;
|
||||
@@ -29,7 +31,7 @@ public class PathsController {
|
||||
}
|
||||
|
||||
|
||||
public PathRouteModel showDialog(Parent parent, Parent content, Collection<PathRouteModel> paths) {
|
||||
public PathRouteModel showDialog(Parent parent, Parent content, ObservableList<PathRouteModel> paths) {
|
||||
|
||||
init(paths);
|
||||
|
||||
@@ -46,10 +48,17 @@ public class PathsController {
|
||||
return tblPaths.getSelectionModel().getSelectedItem();
|
||||
}
|
||||
|
||||
private void init(Collection<PathRouteModel> paths) {
|
||||
private void init(ObservableList<PathRouteModel> paths) {
|
||||
tblPaths.getSelectionModel().clearSelection();
|
||||
this.paths.clear();
|
||||
this.paths.addAll(paths);
|
||||
paths.addListener((ListChangeListener<PathRouteModel>) l -> {
|
||||
while (l.next()) {
|
||||
if (l.wasAdded()) {
|
||||
this.paths.addAll(l.getAddedSubList());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.trader.controllers;
|
||||
|
||||
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
@@ -227,11 +228,12 @@ public class RouterController {
|
||||
SystemModel t = target.getValue();
|
||||
StationModel sS = sStation.getValue();
|
||||
StationModel tS = tStation.getValue();
|
||||
Platform.runLater(() -> {
|
||||
PathRouteModel path = Screeners.showRouters(market.getRoutes(s, sS, t, tS, totalBalance.getValue().doubleValue()));
|
||||
if (path!=null){
|
||||
orders.addAll(path.getOrders());
|
||||
addRouteToPath(path);
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
public void showTopRoutes(){
|
||||
|
||||
@@ -9,12 +9,17 @@ import javafx.collections.ObservableList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import ru.trader.World;
|
||||
import ru.trader.controllers.AnalyzerProgress;
|
||||
import ru.trader.controllers.Screeners;
|
||||
import ru.trader.core.*;
|
||||
import ru.trader.graph.PathRoute;
|
||||
import ru.trader.model.support.BindingsHelper;
|
||||
import ru.trader.model.support.Notificator;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
public class MarketModel {
|
||||
@@ -167,29 +172,37 @@ public class MarketModel {
|
||||
}
|
||||
|
||||
public ObservableList<PathRouteModel> getRoutes(SystemModel from, StationModel stationFrom, SystemModel to, StationModel stationTo, double balance) {
|
||||
Collection<PathRoute> routes;
|
||||
if (stationFrom != null && stationFrom != ModelFabric.NONE_STATION){
|
||||
if (stationTo != null && stationTo != ModelFabric.NONE_STATION){
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), stationTo.getStation(), balance);
|
||||
} else {
|
||||
if (to != null && to != ModelFabric.NONE_SYSTEM){
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), to.getSystem(), balance);
|
||||
AnalyzerProgress progress = new AnalyzerProgress();
|
||||
progress.show(Screeners.getMainScreen(), "Get routes", analyzer);
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
ObservableList<PathRouteModel> res = FXCollections.observableArrayList();
|
||||
executor.execute(() -> {
|
||||
Collection<PathRoute> routes;
|
||||
|
||||
if (stationFrom != null && stationFrom != ModelFabric.NONE_STATION) {
|
||||
if (stationTo != null && stationTo != ModelFabric.NONE_STATION) {
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), stationTo.getStation(), balance);
|
||||
} else {
|
||||
if (to != null && to != ModelFabric.NONE_SYSTEM) {
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), to.getSystem(), balance);
|
||||
} else {
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), balance);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
routes = analyzer.getPaths(stationFrom.getStation(), balance);
|
||||
if (stationTo != null && stationTo != ModelFabric.NONE_STATION) {
|
||||
routes = analyzer.getPaths(from.getSystem(), stationTo.getStation(), balance);
|
||||
} else {
|
||||
if (to != null && to != ModelFabric.NONE_SYSTEM) {
|
||||
routes = analyzer.getPaths(from.getSystem(), to.getSystem(), balance);
|
||||
} else {
|
||||
routes = analyzer.getPaths(from.getSystem(), balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (stationTo != null && stationTo != ModelFabric.NONE_STATION){
|
||||
routes = analyzer.getPaths(from.getSystem(), stationTo.getStation(), balance);
|
||||
} else {
|
||||
if (to != null && to != ModelFabric.NONE_SYSTEM){
|
||||
routes = analyzer.getPaths(from.getSystem(), to.getSystem(), balance);
|
||||
} else {
|
||||
routes = analyzer.getPaths(from.getSystem(), balance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return BindingsHelper.observableList(routes, modeler::get);
|
||||
routes.stream().map(modeler::get).forEach(res::add);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ public class MarketAnalyzer {
|
||||
private final static Logger LOG = LoggerFactory.getLogger(MarketAnalyzer.class);
|
||||
|
||||
private final Market market;
|
||||
private MarketAnalyzerCallBack callback;
|
||||
private MarketFilter filter;
|
||||
private double tank;
|
||||
private double maxDistance;
|
||||
@@ -21,11 +22,20 @@ public class MarketAnalyzer {
|
||||
private final static Comparator<Order> orderComparator = (o1, o2) -> o2.compareTo(o1);
|
||||
|
||||
public MarketAnalyzer(Market market) {
|
||||
this(market, new MarketAnalyzerCallBack());
|
||||
}
|
||||
|
||||
public MarketAnalyzer(Market market, MarketAnalyzerCallBack callback) {
|
||||
this.market = market;
|
||||
this.callback = callback;
|
||||
this.limit = 100;
|
||||
this.segmentSize = 0;
|
||||
}
|
||||
|
||||
public void setCallback(MarketAnalyzerCallBack callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void setFilter(MarketFilter filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
@@ -56,19 +66,23 @@ public class MarketAnalyzer {
|
||||
|
||||
public Collection<Order> getTop(double balance){
|
||||
LOG.debug("Get top {}", limit);
|
||||
Iterable<Place> places = getPlaces();
|
||||
Collection<Place> places = getPlaces();
|
||||
List<Order> top = new ArrayList<>(limit);
|
||||
callback.setCount(places.size());
|
||||
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);
|
||||
if (callback.isCancel()) break;
|
||||
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);
|
||||
callback.inc();
|
||||
}
|
||||
callback.onEnd();
|
||||
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);
|
||||
Graph<Place> graph = new Graph<Place>(vendor.getPlace(), places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph());
|
||||
return getOrders(graph, Collections.singleton(vendor), balance, 0);
|
||||
}
|
||||
|
||||
@@ -78,18 +92,22 @@ public class MarketAnalyzer {
|
||||
|
||||
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);
|
||||
Graph<Place> graph = new Graph<>(place, places, tank, maxDistance, true, jumps, Path::new, callback.onStartGraph());
|
||||
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);
|
||||
callback.setCount(sellers.size());
|
||||
for (Vendor vendor : sellers) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(vendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
for (Offer sell : vendor.getAllSellOffers()) {
|
||||
if (callback.isCancel()) break;
|
||||
LOG.trace("Sell offer {}", sell);
|
||||
if (sell.getCount() == 0) continue;
|
||||
long count = Order.getMaxCount(sell, balance, cargo);
|
||||
@@ -97,6 +115,7 @@ public class MarketAnalyzer {
|
||||
if (count == 0) continue;
|
||||
Iterator<Offer> buyers = market.getStatBuy(sell.getItem()).getOffers().descendingIterator();
|
||||
while (buyers.hasNext()){
|
||||
if (callback.isCancel()) break;
|
||||
Offer buy = buyers.next();
|
||||
if (isFiltered(buy.getVendor())){
|
||||
LOG.trace("Is filtered, skip");
|
||||
@@ -116,6 +135,7 @@ public class MarketAnalyzer {
|
||||
res.add(order);
|
||||
}
|
||||
}
|
||||
callback.inc();
|
||||
}
|
||||
res.sort(orderComparator);
|
||||
return res;
|
||||
@@ -123,17 +143,22 @@ public class MarketAnalyzer {
|
||||
|
||||
private Collection<Order> getOrders(Collection<Vendor> sellers, Collection<Vendor> buyers, double balance, double lowProfit) {
|
||||
List<Order> res = new ArrayList<>();
|
||||
callback.setCount(sellers.size());
|
||||
for (Vendor seller : sellers) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(seller)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
for (Offer sell : seller.getAllSellOffers()) {
|
||||
if (callback.isCancel()) break;
|
||||
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 (callback.isCancel()) break;
|
||||
if (isFiltered(buyer)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
continue;
|
||||
@@ -150,6 +175,7 @@ public class MarketAnalyzer {
|
||||
}
|
||||
}
|
||||
}
|
||||
callback.inc();
|
||||
}
|
||||
res.sort(orderComparator);
|
||||
return res;
|
||||
@@ -209,98 +235,131 @@ public class MarketAnalyzer {
|
||||
}
|
||||
|
||||
public Collection<PathRoute> getPaths(Vendor from, double balance){
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||
callback.setCount(1);
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
Collection<Vendor> vendors = getVendors();
|
||||
return searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
|
||||
Collection<PathRoute> res = searcher.getPaths(from, vendors, jumps, balance, cargo, limit);
|
||||
callback.inc();
|
||||
callback.onEndSearch();
|
||||
return res;
|
||||
}
|
||||
|
||||
public Collection<PathRoute> getPaths(Place from, double balance){
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize);
|
||||
List<PathRoute> top = new ArrayList<>(limit);
|
||||
Collection<Vendor> vendors = getVendors();
|
||||
callback.setCount(vendors.size());
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
for (Vendor vendor : from.get()) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(vendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
Collection<PathRoute> paths = searcher.getPaths(vendor, vendors, jumps, balance, cargo, limit);
|
||||
if (paths.size()>0){
|
||||
return paths;
|
||||
}
|
||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||
callback.inc();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
callback.onEndSearch();
|
||||
return top;
|
||||
}
|
||||
|
||||
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);
|
||||
callback.setCount(1);
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
Collection<PathRoute> res = searcher.getPaths(from, to, getVendors(), jumps, balance, cargo, limit);
|
||||
callback.inc();
|
||||
callback.onEndSearch();
|
||||
return res;
|
||||
}
|
||||
|
||||
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());
|
||||
callback.setCount(fVendors.size() * toVendors.size());
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
for (Vendor fromVendor : fVendors) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(fromVendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
for (Vendor toVendor : toVendors) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(toVendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
Collection<PathRoute> paths = searcher.getPaths(fromVendor, toVendor, vendors, jumps, balance, cargo, count);
|
||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||
callback.inc();
|
||||
}
|
||||
}
|
||||
callback.onEndSearch();
|
||||
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());
|
||||
callback.setCount(toVendors.size());
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
for (Vendor toVendor : toVendors) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(toVendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
Collection<PathRoute> paths = searcher.getPaths(from, toVendor, vendors, jumps, balance, cargo, count);
|
||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||
callback.inc();
|
||||
}
|
||||
callback.onEndSearch();
|
||||
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());
|
||||
callback.setCount(fVendors.size());
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
for (Vendor fromVendor : fVendors) {
|
||||
if (callback.isCancel()) break;
|
||||
if (isFiltered(fromVendor)){
|
||||
LOG.trace("Is filtered, skip");
|
||||
callback.inc();
|
||||
continue;
|
||||
}
|
||||
Collection<PathRoute> paths = searcher.getPaths(fromVendor, to, vendors, jumps, balance, cargo, count);
|
||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||
callback.inc();
|
||||
}
|
||||
callback.onEndSearch();
|
||||
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();
|
||||
callback.setCount(vendors.size());
|
||||
RouteSearcher searcher = new RouteSearcher(maxDistance, tank, segmentSize, callback.onStartSearch());
|
||||
for (Vendor vendor : vendors) {
|
||||
if (callback.isCancel()) break;
|
||||
Collection<PathRoute> paths = searcher.getPaths(vendor, vendor, vendors, jumps, balance, cargo, 3);
|
||||
TopList.addAllToTop(top, paths, limit, RouteGraph.byProfitComparator);
|
||||
callback.inc();
|
||||
}
|
||||
callback.onEndSearch();
|
||||
return top;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package ru.trader.core;
|
||||
|
||||
import ru.trader.graph.GraphCallBack;
|
||||
import ru.trader.graph.RouteSearcherCallBack;
|
||||
|
||||
public class MarketAnalyzerCallBack {
|
||||
private volatile boolean cancel = false;
|
||||
private RouteSearcherCallBack callbackRoute;
|
||||
private GraphCallBack<Place> callbackGraph;
|
||||
|
||||
|
||||
protected RouteSearcherCallBack getRouteSearcherCallBackInstance(){
|
||||
return new RouteSearcherCallBack();
|
||||
}
|
||||
|
||||
protected GraphCallBack<Place> getGraphCallBackInstance(){
|
||||
return new GraphCallBack<>();
|
||||
}
|
||||
|
||||
public final GraphCallBack<Place> onStartGraph(){
|
||||
callbackGraph = getGraphCallBackInstance();
|
||||
return callbackGraph;
|
||||
}
|
||||
|
||||
public final void onEndGraph(){
|
||||
callbackGraph = null;
|
||||
}
|
||||
|
||||
public final RouteSearcherCallBack onStartSearch(){
|
||||
callbackRoute = getRouteSearcherCallBackInstance();
|
||||
return callbackRoute;
|
||||
}
|
||||
|
||||
public final void onEndSearch(){
|
||||
callbackRoute = null;
|
||||
onEnd();
|
||||
}
|
||||
|
||||
protected void onEnd(){}
|
||||
|
||||
public void setCount(long count){}
|
||||
public void inc(){}
|
||||
|
||||
|
||||
public final boolean isCancel() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
public final void cancel(){
|
||||
if (cancel) return;
|
||||
this.cancel = true;
|
||||
if (callbackRoute != null){
|
||||
callbackRoute.cancel();
|
||||
callbackRoute = null;
|
||||
}
|
||||
if (callbackGraph != null){
|
||||
callbackGraph.cancel();
|
||||
callbackGraph = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
|
||||
protected final Vertex<T> root;
|
||||
protected final Map<T,Vertex<T>> vertexes;
|
||||
private final GraphCallBack<T> callback;
|
||||
|
||||
protected final double stock;
|
||||
protected final double maxDistance;
|
||||
@@ -48,15 +49,22 @@ public class Graph<T extends Connectable<T>> {
|
||||
}
|
||||
|
||||
public Graph(T start, Collection<T> set, double stock, double maxDistance, boolean withRefill, int maxDeep, PathConstructor<T> pathFabric) {
|
||||
this(start, set, stock, maxDistance, withRefill, maxDeep, pathFabric, new GraphCallBack<>());
|
||||
}
|
||||
|
||||
public Graph(T start, Collection<T> set, double stock, double maxDistance, boolean withRefill, int maxDeep, PathConstructor<T> pathFabric, GraphCallBack<T> callback) {
|
||||
this.maxDistance = maxDistance;
|
||||
this.stock = stock;
|
||||
this.withRefill = withRefill;
|
||||
this.pathFabric = pathFabric;
|
||||
this.callback = callback;
|
||||
root = new Vertex<>(start);
|
||||
root.setLevel(maxDeep);
|
||||
vertexes = new ConcurrentHashMap<>(50, 0.9f, THRESHOLD);
|
||||
vertexes.put(root.getEntry(), root);
|
||||
callback.onStartBuild(start);
|
||||
build(root, set, maxDeep, stock);
|
||||
callback.onEndBuild();
|
||||
}
|
||||
|
||||
private void build(Vertex<T> root, Collection<T> set, int maxDeep, double stock) {
|
||||
@@ -81,7 +89,9 @@ public class Graph<T extends Connectable<T>> {
|
||||
}
|
||||
|
||||
private void findPathsTo(Vertex<T> target, TopList<Path<T>> res, int deep){
|
||||
callback.onStartFind(root, target);
|
||||
POOL.invoke(new PathFinder(res, pathFabric.build(root), target, deep-1, stock));
|
||||
callback.onEndFind();
|
||||
}
|
||||
|
||||
public List<Path<T>> getPathsTo(T entry){
|
||||
@@ -95,7 +105,9 @@ public class Graph<T extends Connectable<T>> {
|
||||
public TopList<Path<T>> getPathsTo(T entry, int max, int deep){
|
||||
Vertex<T> target = getVertex(entry);
|
||||
TopList<Path<T>> paths = newTopList(max);
|
||||
callback.setCount(1);
|
||||
findPathsTo(target, paths, deep);
|
||||
callback.inc();
|
||||
paths.finish();
|
||||
return paths;
|
||||
}
|
||||
@@ -106,12 +118,15 @@ public class Graph<T extends Connectable<T>> {
|
||||
|
||||
public TopList<Path<T>> getPaths(int count, int deep){
|
||||
TopList<Path<T>> paths = newTopList(count);
|
||||
callback.setCount(vertexes.size());
|
||||
for (Vertex<T> target : vertexes.values()) {
|
||||
if (callback.isCancel()) break;
|
||||
TopList<Path<T>> p = newTopList(minJumps);
|
||||
findPathsTo(target, p, deep);
|
||||
for (Path<T> path : p.getList()) {
|
||||
paths.add(path);
|
||||
}
|
||||
callback.inc();
|
||||
}
|
||||
paths.finish();
|
||||
return paths;
|
||||
@@ -204,6 +219,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
ArrayList<GraphBuilder> subTasks = new ArrayList<>(set.size());
|
||||
Iterator<T> iterator = set.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (callback.isCancel()) break;
|
||||
T entry = iterator.next();
|
||||
if (entry == vertex.getEntry()) continue;
|
||||
double distance = vertex.getEntry().getDistance(entry);
|
||||
@@ -236,14 +252,22 @@ public class Graph<T extends Connectable<T>> {
|
||||
}
|
||||
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
||||
for (GraphBuilder subTask : subTasks) {
|
||||
subTask.join();
|
||||
if (callback.isCancel()){
|
||||
subTask.cancel(true);
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
}
|
||||
subTasks.clear();
|
||||
}
|
||||
}
|
||||
if (!subTasks.isEmpty()){
|
||||
for (GraphBuilder subTask : subTasks) {
|
||||
subTask.join();
|
||||
if (callback.isCancel()){
|
||||
subTask.cancel(true);
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
}
|
||||
subTasks.clear();
|
||||
}
|
||||
@@ -282,6 +306,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
synchronized (paths){
|
||||
if (!paths.add(path)) complete(null);
|
||||
}
|
||||
callback.onFound();
|
||||
}
|
||||
}
|
||||
if (deep > 0 ){
|
||||
@@ -291,7 +316,7 @@ public class Graph<T extends Connectable<T>> {
|
||||
Iterator<Edge<T>> iterator = source.getEdges().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Edge<T> next = iterator.next();
|
||||
if (isDone()) break;
|
||||
if (isDone() || callback.isCancel()) break;
|
||||
// target already added if source consist edge
|
||||
if (next.isConnect(target)) continue;
|
||||
if (!distanceFilter.test(next.getLength())) continue;
|
||||
@@ -305,8 +330,8 @@ public class Graph<T extends Connectable<T>> {
|
||||
subTasks.add(task);
|
||||
if (subTasks.size() == THRESHOLD || !iterator.hasNext()){
|
||||
for (PathFinder subTask : subTasks) {
|
||||
if (isDone()) {
|
||||
subTask.cancel(false);
|
||||
if (isDone() || callback.isCancel()) {
|
||||
subTask.cancel(callback.isCancel());
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
@@ -316,8 +341,8 @@ public class Graph<T extends Connectable<T>> {
|
||||
}
|
||||
if (!subTasks.isEmpty()){
|
||||
for (PathFinder subTask : subTasks) {
|
||||
if (isDone()) {
|
||||
subTask.cancel(false);
|
||||
if (isDone() || callback.isCancel()) {
|
||||
subTask.cancel(callback.isCancel());
|
||||
} else {
|
||||
subTask.join();
|
||||
}
|
||||
|
||||
27
core/src/main/java/ru/trader/graph/GraphCallBack.java
Normal file
27
core/src/main/java/ru/trader/graph/GraphCallBack.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package ru.trader.graph;
|
||||
|
||||
public class GraphCallBack<T extends Connectable<T>> {
|
||||
|
||||
private volatile boolean cancel = false;
|
||||
|
||||
public void onStartBuild(T from){}
|
||||
public void onEndBuild(){}
|
||||
|
||||
|
||||
public void onStartFind(Vertex<T> from, Vertex<T> to){}
|
||||
public void onFound(){}
|
||||
public void onEndFind(){}
|
||||
|
||||
|
||||
public void setCount(long count){}
|
||||
public void inc(){}
|
||||
|
||||
public final boolean isCancel() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
public final void cancel(){
|
||||
this.cancel = true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,9 +31,12 @@ public class RouteGraph extends Graph<Vendor> {
|
||||
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep) {
|
||||
this(start, set, stock, maxDistance, withRefill, maxDeep, false);
|
||||
}
|
||||
|
||||
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep, boolean groupRes) {
|
||||
super(start, set, stock, maxDistance, withRefill, maxDeep, groupRes ? PathRoute::buildAvg : PathRoute::new);
|
||||
this(start, set, stock, maxDistance, withRefill, maxDeep, groupRes, new GraphCallBack<>());
|
||||
}
|
||||
|
||||
public RouteGraph(Vendor start, Collection<Vendor> set, double stock, double maxDistance, boolean withRefill, int maxDeep, boolean groupRes, GraphCallBack<Vendor> callback) {
|
||||
super(start, set, stock, maxDistance, withRefill, maxDeep, groupRes ? PathRoute::buildAvg : PathRoute::new, callback);
|
||||
if (groupRes){
|
||||
this.groupRes = maxDeep > minJumps;
|
||||
}
|
||||
|
||||
@@ -14,17 +14,19 @@ public class RouteSearcher {
|
||||
private final static ForkJoinPool POOL = new ForkJoinPool();
|
||||
private final static int THRESHOLD = (int) Math.ceil(Runtime.getRuntime().availableProcessors()/2.0);
|
||||
|
||||
private final RouteSearcherCallBack callback;
|
||||
private final double maxDistance;
|
||||
private final double stock;
|
||||
private final int segmentSize;
|
||||
|
||||
public RouteSearcher(double maxDistance, double stock) {
|
||||
this(maxDistance, stock, 0);
|
||||
this(maxDistance, stock, 0, new RouteSearcherCallBack());
|
||||
}
|
||||
public RouteSearcher(double maxDistance, double stock, int segmentSize) {
|
||||
public RouteSearcher(double maxDistance, double stock, int segmentSize, RouteSearcherCallBack callback) {
|
||||
this.maxDistance = maxDistance;
|
||||
this.stock = stock;
|
||||
this.segmentSize = segmentSize;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public List<PathRoute> getPaths(Vendor from, Vendor to, Collection<Vendor> vendors, int jumps, double balance, int cargo, int limit){
|
||||
@@ -56,8 +58,10 @@ public class RouteSearcher {
|
||||
|
||||
@Override
|
||||
protected List<PathRoute> compute() {
|
||||
if (callback.isCancel()) return Collections.emptyList();
|
||||
LOG.trace("Start search route to {} from {}, jumps {}", source, target, jumps);
|
||||
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, jumps, true);
|
||||
GraphCallBack<Vendor> gCallBack = callback.onStart();
|
||||
RouteGraph sGraph = new RouteGraph(source, vendors, stock, maxDistance, true, jumps, true, gCallBack);
|
||||
int jumpsToAll = sGraph.getMinJumps();
|
||||
LOG.trace("Segment jumps {}", jumpsToAll);
|
||||
sGraph.setCargo(cargo);
|
||||
@@ -87,8 +91,10 @@ public class RouteSearcher {
|
||||
res.add(path);
|
||||
}
|
||||
}
|
||||
if (callback.isCancel()) break;
|
||||
subTasks.clear();
|
||||
for (int taskIndex = 0; taskIndex < THRESHOLD && i+taskIndex < paths.size(); taskIndex++) {
|
||||
if (callback.isCancel()) break;
|
||||
PathRoute path = (PathRoute) paths.get(i+taskIndex);
|
||||
double newBalance = balance + path.getRoot().getProfit();
|
||||
SegmentSearcher task = new SegmentSearcher(path.get(), target, vendors, jumps - path.getLength(), newBalance, cargo, 1);
|
||||
@@ -103,6 +109,7 @@ public class RouteSearcher {
|
||||
}
|
||||
}
|
||||
res.finish();
|
||||
callback.onEnd(gCallBack);
|
||||
return res.getList();
|
||||
}
|
||||
|
||||
@@ -116,6 +123,10 @@ public class RouteSearcher {
|
||||
|
||||
|
||||
private void add(SegmentSearcher task, PathRoute path, TopList<PathRoute> res){
|
||||
if (callback.isCancel()){
|
||||
task.cancel(true);
|
||||
return;
|
||||
}
|
||||
List<PathRoute> tail = task.join();
|
||||
if (tail.isEmpty()){
|
||||
LOG.trace("Not found route from {} to {}, jumps {}", task.source, task.target, task.jumps);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package ru.trader.graph;
|
||||
|
||||
import ru.trader.core.Vendor;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class RouteSearcherCallBack {
|
||||
|
||||
private volatile boolean cancel = false;
|
||||
private final List<GraphCallBack<Vendor>> callbacks = new LinkedList<>();
|
||||
|
||||
public final GraphCallBack<Vendor> onStart(){
|
||||
GraphCallBack<Vendor> callback = getGraphCallBackInstance();
|
||||
if (cancel) return callback;
|
||||
synchronized (callbacks) {
|
||||
callbacks.add(callback);
|
||||
}
|
||||
return callback;
|
||||
}
|
||||
|
||||
public final void onEnd( GraphCallBack<Vendor> callback){
|
||||
synchronized (callbacks) {
|
||||
callbacks.remove(callback);
|
||||
}
|
||||
}
|
||||
|
||||
protected GraphCallBack<Vendor> getGraphCallBackInstance(){
|
||||
return new GraphCallBack<>();
|
||||
}
|
||||
|
||||
public final boolean isCancel() {
|
||||
return cancel;
|
||||
}
|
||||
|
||||
public final void cancel(){
|
||||
if (cancel) return;
|
||||
this.cancel = true;
|
||||
synchronized (callbacks){
|
||||
callbacks.forEach(GraphCallBack::cancel);
|
||||
callbacks.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user