Increase search speed, add minimum vendor rating parameter for skip low profitable vendors
This commit is contained in:
@@ -36,6 +36,8 @@ public class SettingsController {
|
|||||||
@FXML
|
@FXML
|
||||||
private NumberField routesCount;
|
private NumberField routesCount;
|
||||||
@FXML
|
@FXML
|
||||||
|
private NumberField minVendorRating;
|
||||||
|
@FXML
|
||||||
private NumberField fuelPrice;
|
private NumberField fuelPrice;
|
||||||
@FXML
|
@FXML
|
||||||
private ComboBox<Profile.PATH_PRIORITY> pathPriority;
|
private ComboBox<Profile.PATH_PRIORITY> pathPriority;
|
||||||
@@ -93,6 +95,7 @@ public class SettingsController {
|
|||||||
jumps.setValue(profile.getJumps());
|
jumps.setValue(profile.getJumps());
|
||||||
lands.setValue(profile.getLands());
|
lands.setValue(profile.getLands());
|
||||||
routesCount.setValue(profile.getRoutesCount());
|
routesCount.setValue(profile.getRoutesCount());
|
||||||
|
minVendorRating.setValue(profile.getMinVendorRating());
|
||||||
fuelPrice.setValue(profile.getFuelPrice());
|
fuelPrice.setValue(profile.getFuelPrice());
|
||||||
pathPriority.setValue(profile.getPathPriority());
|
pathPriority.setValue(profile.getPathPriority());
|
||||||
jumpTime.setValue(profile.getJumpTime());
|
jumpTime.setValue(profile.getJumpTime());
|
||||||
@@ -134,6 +137,7 @@ public class SettingsController {
|
|||||||
profile.setJumps(jumps.getValue().intValue());
|
profile.setJumps(jumps.getValue().intValue());
|
||||||
profile.setLands(lands.getValue().intValue());
|
profile.setLands(lands.getValue().intValue());
|
||||||
profile.setRoutesCount(routesCount.getValue().intValue());
|
profile.setRoutesCount(routesCount.getValue().intValue());
|
||||||
|
profile.setMinVendorRating(minVendorRating.getValue().doubleValue());
|
||||||
profile.setFuelPrice(fuelPrice.getValue().intValue());
|
profile.setFuelPrice(fuelPrice.getValue().intValue());
|
||||||
profile.setPathPriority(pathPriority.getValue());
|
profile.setPathPriority(pathPriority.getValue());
|
||||||
profile.setJumpTime(jumpTime.getValue().intValue());
|
profile.setJumpTime(jumpTime.getValue().intValue());
|
||||||
|
|||||||
@@ -184,13 +184,14 @@ settings.emdn.on=Active
|
|||||||
settings.emdn.sub=Server SUB:
|
settings.emdn.sub=Server SUB:
|
||||||
settings.emdn.updateOnly=Update price only:
|
settings.emdn.updateOnly=Update price only:
|
||||||
settings.emdn.auto=Auto update (sec.):
|
settings.emdn.auto=Auto update (sec.):
|
||||||
|
settings.edce.on=Active
|
||||||
|
settings.edce.interval=Update interval, sec.
|
||||||
settings.performance=Performance
|
settings.performance=Performance
|
||||||
settings.performance.segmentSize=Segment size (0 - auto):
|
settings.performance.segmentSize=Segment size (0 - auto):
|
||||||
settings.performance.limit=Routes count:
|
settings.performance.limit=Routes count:
|
||||||
settings.edce.on=Active
|
|
||||||
settings.edce.interval=Update interval, sec.
|
|
||||||
settings.performance.jumps=Jumps:
|
settings.performance.jumps=Jumps:
|
||||||
settings.performance.landings=Landings:
|
settings.performance.landings=Landings:
|
||||||
|
settings.performance.minVendorRating=Minimal station rating (0-10):
|
||||||
settings.search=Search options
|
settings.search=Search options
|
||||||
settings.search.fuelPrice=1t fuel price:
|
settings.search.fuelPrice=1t fuel price:
|
||||||
settings.search.pathType=Path priority:
|
settings.search.pathType=Path priority:
|
||||||
|
|||||||
@@ -183,13 +183,14 @@ settings.emdn.on=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C
|
|||||||
settings.emdn.sub=\u0421\u0435\u0440\u0432\u0435\u0440 SUB:
|
settings.emdn.sub=\u0421\u0435\u0440\u0432\u0435\u0440 SUB:
|
||||||
settings.emdn.updateOnly=\u0422\u043E\u043B\u044C\u043A\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0446\u0435\u043D\u044B:
|
settings.emdn.updateOnly=\u0422\u043E\u043B\u044C\u043A\u043E \u043E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0446\u0435\u043D\u044B:
|
||||||
settings.emdn.auto=\u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0430\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0447\u0435\u0440\u0435\u0437 (\u0441\u0435\u043A.):
|
settings.emdn.auto=\u041E\u0431\u043D\u043E\u0432\u043B\u044F\u0442\u044C \u0430\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0447\u0435\u0440\u0435\u0437 (\u0441\u0435\u043A.):
|
||||||
|
settings.edce.on=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C
|
||||||
|
settings.edce.interval=\u0418\u043D\u0442\u0435\u0440\u0432\u0430\u043B, \u0441\u0435\u043A.
|
||||||
settings.performance=\u041F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C
|
settings.performance=\u041F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u044C
|
||||||
settings.performance.segmentSize=\u041C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432 \u0432 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u0435 (0 - \u0430\u0432\u0442\u043E):
|
settings.performance.segmentSize=\u041C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432 \u0432 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u0435 (0 - \u0430\u0432\u0442\u043E):
|
||||||
settings.performance.limit=\u041A\u043E\u043B-\u0432\u043E \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432 \u043D\u0430 \u0432\u044B\u0432\u043E\u0434:
|
settings.performance.limit=\u041A\u043E\u043B-\u0432\u043E \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432 \u043D\u0430 \u0432\u044B\u0432\u043E\u0434:
|
||||||
settings.edce.on=\u0412\u043A\u043B\u044E\u0447\u0438\u0442\u044C
|
|
||||||
settings.edce.interval=\u0418\u043D\u0442\u0435\u0440\u0432\u0430\u043B, \u0441\u0435\u043A.
|
|
||||||
settings.performance.jumps=\u041F\u0440\u044B\u0436\u043A\u043E\u0432:
|
settings.performance.jumps=\u041F\u0440\u044B\u0436\u043A\u043E\u0432:
|
||||||
settings.performance.landings=\u041F\u043E\u0441\u0430\u0434\u043E\u043A:
|
settings.performance.landings=\u041F\u043E\u0441\u0430\u0434\u043E\u043A:
|
||||||
|
settings.performance.minVendorRating=\u041C\u0438\u043D\u0438\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u0440\u0435\u0439\u0442\u0438\u043D\u0433 \u0441\u0442\u0430\u043D\u0446\u0438\u0438 (0-10):
|
||||||
settings.search=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u043F\u043E\u0438\u0441\u043A\u0430
|
settings.search=\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u043F\u043E\u0438\u0441\u043A\u0430
|
||||||
settings.search.fuelPrice=\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C 1\u0442 \u0442\u043E\u043F\u043B\u0438\u0432\u0430:
|
settings.search.fuelPrice=\u0421\u0442\u043E\u0438\u043C\u043E\u0441\u0442\u044C 1\u0442 \u0442\u043E\u043F\u043B\u0438\u0432\u0430:
|
||||||
settings.search.pathType=\u0422\u0438\u043F \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432:
|
settings.search.pathType=\u0422\u0438\u043F \u043C\u0430\u0440\u0448\u0440\u0443\u0442\u043E\u0432:
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
<?import javafx.scene.layout.*?>
|
<?import javafx.scene.layout.*?>
|
||||||
<?import ru.trader.view.support.*?>
|
<?import ru.trader.view.support.*?>
|
||||||
<?import org.controlsfx.glyphfont.Glyph?>
|
<?import org.controlsfx.glyphfont.Glyph?>
|
||||||
<GridPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ru.trader.controllers.SettingsController"
|
<ScrollPane xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ru.trader.controllers.SettingsController"
|
||||||
styleClass="dialog" vgap="4" hgap="8">
|
styleClass="dialog">
|
||||||
|
<GridPane vgap="4" hgap="8">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
<ColumnConstraints />
|
<ColumnConstraints />
|
||||||
<ColumnConstraints minWidth="260" maxWidth="260"/>
|
<ColumnConstraints minWidth="260" maxWidth="260"/>
|
||||||
@@ -26,38 +27,40 @@
|
|||||||
<NumberField fx:id="lands" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
<NumberField fx:id="lands" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="5" />
|
||||||
<Label text="%settings.performance.limit" GridPane.rowIndex="6" />
|
<Label text="%settings.performance.limit" GridPane.rowIndex="6" />
|
||||||
<NumberField fx:id="routesCount" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="6" />
|
<NumberField fx:id="routesCount" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="6" />
|
||||||
<Label text="%settings.search" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="7"/>
|
<Label text="%settings.performance.minVendorRating" GridPane.rowIndex="7" />
|
||||||
<Label text="%settings.search.fuelPrice" GridPane.rowIndex="8" />
|
<NumberField fx:id="minVendorRating" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="7" />
|
||||||
<NumberField fx:id="fuelPrice" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="8" />
|
<Label text="%settings.search" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="8"/>
|
||||||
<Label text="%settings.search.pathType" GridPane.rowIndex="9" />
|
<Label text="%settings.search.fuelPrice" GridPane.rowIndex="9" />
|
||||||
<ComboBox fx:id="pathPriority" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="9" />
|
<NumberField fx:id="fuelPrice" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="9" />
|
||||||
<Label text="%settings.search.times.jump" GridPane.rowIndex="10" />
|
<Label text="%settings.search.pathType" GridPane.rowIndex="10" />
|
||||||
<NumberField fx:id="jumpTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="10" />
|
<ComboBox fx:id="pathPriority" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="10" />
|
||||||
<Label text="%settings.search.times.landing" GridPane.rowIndex="11" />
|
<Label text="%settings.search.times.jump" GridPane.rowIndex="11" />
|
||||||
<NumberField fx:id="landingTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="11" />
|
<NumberField fx:id="jumpTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="11" />
|
||||||
<Label text="%settings.search.times.orbital" GridPane.rowIndex="12" />
|
<Label text="%settings.search.times.landing" GridPane.rowIndex="12" />
|
||||||
<NumberField fx:id="orbitalTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="12" />
|
<NumberField fx:id="landingTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="12" />
|
||||||
<Label text="%settings.search.times.takeoff" GridPane.rowIndex="13" />
|
<Label text="%settings.search.times.orbital" GridPane.rowIndex="13" />
|
||||||
<NumberField fx:id="takeoffTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="13" />
|
<NumberField fx:id="orbitalTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="13" />
|
||||||
<Label text="%settings.search.times.recharge" GridPane.rowIndex="14" />
|
<Label text="%settings.search.times.takeoff" GridPane.rowIndex="14" />
|
||||||
<NumberField fx:id="rechargeTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="14" />
|
<NumberField fx:id="takeoffTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="14" />
|
||||||
<Label text="%settings.hotkeys" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="15"/>
|
<Label text="%settings.search.times.recharge" GridPane.rowIndex="15" />
|
||||||
<Label text="%settings.hotkeys.complete" GridPane.rowIndex="16" />
|
<NumberField fx:id="rechargeTime" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="15" />
|
||||||
<TextField fx:id="completeKeyText" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="16" />
|
<Label text="%settings.hotkeys" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="16"/>
|
||||||
<Label text="ED Log Watcher" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="17"/>
|
<Label text="%settings.hotkeys.complete" GridPane.rowIndex="17" />
|
||||||
<Label text="%settings.edlog.on" GridPane.rowIndex="18"/>
|
<TextField fx:id="completeKeyText" maxWidth="100" GridPane.columnIndex="1" GridPane.rowIndex="17" />
|
||||||
<CheckBox fx:id="edLogActive" GridPane.columnIndex="1" GridPane.rowIndex="18"/>
|
<Label text="ED Log Watcher" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="18"/>
|
||||||
<Label text="%settings.edlog.dir" GridPane.rowIndex="19" />
|
<Label text="%settings.edlog.on" GridPane.rowIndex="19"/>
|
||||||
<HBox maxWidth="260" GridPane.columnIndex="1" GridPane.rowIndex="19">
|
<CheckBox fx:id="edLogActive" GridPane.columnIndex="1" GridPane.rowIndex="19"/>
|
||||||
|
<Label text="%settings.edlog.dir" GridPane.rowIndex="20" />
|
||||||
|
<HBox maxWidth="260" GridPane.columnIndex="1" GridPane.rowIndex="20">
|
||||||
<TextField fx:id="edLogDir" />
|
<TextField fx:id="edLogDir" />
|
||||||
<Button minWidth="30" minHeight="25" onAction="#selectLogDir"><graphic><Glyph text="FontAwesome|FOLDER_OPEN"/></graphic></Button>
|
<Button minWidth="30" minHeight="25" onAction="#selectLogDir"><graphic><Glyph text="FontAwesome|FOLDER_OPEN"/></graphic></Button>
|
||||||
|
|
||||||
</HBox>
|
</HBox>
|
||||||
<Label text="%settings.emdn" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="20"/>
|
<Label text="%settings.emdn" styleClass="settings-group" GridPane.halignment="CENTER" GridPane.columnSpan="2" GridPane.rowIndex="21"/>
|
||||||
<Label text="%settings.emdn.on" GridPane.rowIndex="21"/>
|
<Label text="%settings.emdn.on" GridPane.rowIndex="22"/>
|
||||||
<CheckBox fx:id="emdnOn" GridPane.columnIndex="1" GridPane.rowIndex="21"/>
|
<CheckBox fx:id="emdnOn" GridPane.columnIndex="1" GridPane.rowIndex="22"/>
|
||||||
<Label text="%settings.emdn.sub" GridPane.rowIndex="22" />
|
<Label text="%settings.emdn.sub" GridPane.rowIndex="23" />
|
||||||
<TextField fx:id="emdnSubServ" GridPane.columnIndex="1" GridPane.rowIndex="22" />
|
<TextField fx:id="emdnSubServ" GridPane.columnIndex="1" GridPane.rowIndex="23" />
|
||||||
|
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
</ScrollPane>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.trader.analysis;
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import ru.trader.analysis.graph.Edge;
|
import ru.trader.analysis.graph.Edge;
|
||||||
import ru.trader.core.Offer;
|
import ru.trader.core.Offer;
|
||||||
import ru.trader.core.Vendor;
|
import ru.trader.core.Vendor;
|
||||||
@@ -165,6 +166,7 @@ public class CrawlerSpecificator {
|
|||||||
if (res) return true;
|
if (res) return true;
|
||||||
for (TimeEntry<Offer> entry : offers){
|
for (TimeEntry<Offer> entry : offers){
|
||||||
Offer offer = entry.obj;
|
Offer offer = entry.obj;
|
||||||
|
if (offer.getVendor().equals(vendor)) return true;
|
||||||
Offer sell = vendor.getSell(offer.getItem());
|
Offer sell = vendor.getSell(offer.getItem());
|
||||||
res = sell != null && sell.getCount() >= offer.getCount();
|
res = sell != null && sell.getCount() >= offer.getCount();
|
||||||
if (res) return true;
|
if (res) return true;
|
||||||
@@ -172,12 +174,23 @@ public class CrawlerSpecificator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Vendor> getVendors(Collection<Vendor> vendors){
|
public Set<Vendor> getVendors(Collection<Scorer.Rating> vendors){
|
||||||
Set<Vendor> v = containsAny.stream().map(e -> e.obj).collect(Collectors.toSet());
|
Set<Vendor> v = all.stream().map(e -> e.obj).collect(Collectors.toSet());
|
||||||
any.stream().map(e -> e.obj).forEach(v::add);
|
if (containsAny.size() > 0){
|
||||||
all.stream().map(e -> e.obj).forEach(v::add);
|
vendors.stream().filter(r -> contains(containsAny, r.getVendor())).sorted().limit(5).forEach(r -> v.add(r.getVendor()));
|
||||||
offers.stream().map(e -> e.obj.getVendor()).forEach(v::add);
|
}
|
||||||
v.addAll(vendors);
|
if (any.size() > 0){
|
||||||
|
vendors.stream().filter(r -> contains(any, r.getVendor())).sorted().limit(5).forEach(r -> v.add(r.getVendor()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TimeEntry<Offer> entry : offers) {
|
||||||
|
vendors.stream().filter(r -> {
|
||||||
|
Offer offer = entry.obj;
|
||||||
|
if (offer.getVendor().equals(r.getVendor())) return true;
|
||||||
|
Offer sell = r.getVendor().getSell(offer.getItem());
|
||||||
|
return sell != null && sell.getCount() >= offer.getCount();
|
||||||
|
}).sorted().limit(5).forEach(r -> v.add(r.getVendor()));
|
||||||
|
}
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,70 +27,26 @@ import java.util.stream.Stream;
|
|||||||
public class Scorer {
|
public class Scorer {
|
||||||
private final static Logger LOG = LoggerFactory.getLogger(Scorer.class);
|
private final static Logger LOG = LoggerFactory.getLogger(Scorer.class);
|
||||||
|
|
||||||
private final Map<Item, Offer> sellOffers;
|
|
||||||
private final Map<Item, Offer> buyOffers;
|
|
||||||
private final FilteredMarket market;
|
private final FilteredMarket market;
|
||||||
private final Profile profile;
|
private final Profile profile;
|
||||||
|
|
||||||
private final double avgProfit;
|
|
||||||
private final double minProfit;
|
|
||||||
private final double maxProfit;
|
|
||||||
private final double maxScore;
|
|
||||||
private final double avgDistance;
|
private final double avgDistance;
|
||||||
|
|
||||||
public Scorer(FilteredMarket market, Profile profile) {
|
public Scorer(FilteredMarket market, Profile profile) {
|
||||||
this.market = market;
|
this.market = market;
|
||||||
this.profile = profile;
|
this.profile = profile;
|
||||||
sellOffers = new HashMap<>(100, 0.9f);
|
|
||||||
buyOffers = new HashMap<>(100, 0.9f);
|
|
||||||
market.getItems().forEach(this::fillOffers);
|
|
||||||
DoubleSummaryStatistics statProfit = computeProfit();
|
|
||||||
minProfit = statProfit.getMin() / profile.getShip().getCargo();
|
|
||||||
avgProfit = statProfit.getAverage() / profile.getShip().getCargo();
|
|
||||||
maxProfit = statProfit.getMax() / profile.getShip().getCargo();
|
|
||||||
|
|
||||||
avgDistance = computeAvgDistance();
|
avgDistance = computeAvgDistance();
|
||||||
maxScore = getScore(1, statProfit.getMax(), 0, 1, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Profile getProfile() {
|
public Profile getProfile() {
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillOffers(Item item){
|
|
||||||
Optional<Offer> offer = market.getSell(item).findFirst();
|
|
||||||
if (offer.isPresent()){
|
|
||||||
sellOffers.put(item, offer.get());
|
|
||||||
}
|
|
||||||
offer = market.getBuy(item).findFirst();
|
|
||||||
if (offer.isPresent()){
|
|
||||||
buyOffers.put(item, offer.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DoubleSummaryStatistics computeProfit(){
|
|
||||||
return sellOffers.values().stream()
|
|
||||||
.flatMap(this::mapToOrder)
|
|
||||||
.collect(Collectors.summarizingDouble(Order::getProfit));
|
|
||||||
}
|
|
||||||
|
|
||||||
private double computeAvgDistance(){
|
private double computeAvgDistance(){
|
||||||
OptionalDouble res = market.getVendors().mapToDouble(Vendor::getDistance).average();
|
OptionalDouble res = market.getVendors().mapToDouble(Vendor::getDistance).average();
|
||||||
return res.orElse(0);
|
return res.orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getAvgProfit() {
|
|
||||||
return avgProfit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getMaxProfit() {
|
|
||||||
return maxProfit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getMaxScore() {
|
|
||||||
return maxScore;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getAvgDistance() {
|
public double getAvgDistance() {
|
||||||
return avgDistance;
|
return avgDistance;
|
||||||
}
|
}
|
||||||
@@ -157,25 +113,113 @@ public class Scorer {
|
|||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<Order> mapToOrder(Offer offer) {
|
|
||||||
Offer sell;
|
|
||||||
Offer buy;
|
|
||||||
if (offer.getType() == OFFER_TYPE.SELL){
|
|
||||||
sell = offer;
|
|
||||||
buy = buyOffers.get(offer.getItem());
|
|
||||||
} else {
|
|
||||||
sell = sellOffers.get(offer.getItem());
|
|
||||||
buy = offer;
|
|
||||||
}
|
|
||||||
if (sell == null || buy == null) return Stream.empty();
|
|
||||||
Order order = new Order(sell, buy, profile.getBalance(), profile.getShip().getCargo());
|
|
||||||
if (order.getProfit() <= 0) return Stream.empty();
|
|
||||||
return Stream.of(order);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Order> getOrders(Vendor seller, Vendor buyer){
|
public List<Order> getOrders(Vendor seller, Vendor buyer){
|
||||||
FilteredVendor fSeller = market.getFiltered(seller);
|
FilteredVendor fSeller = market.getFiltered(seller);
|
||||||
FilteredVendor fBuyer = market.getFiltered(buyer);
|
FilteredVendor fBuyer = market.getFiltered(buyer);
|
||||||
return MarketUtils.getOrders(fSeller, fBuyer);
|
return MarketUtils.getOrders(fSeller, fBuyer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RatingComputer getRatingComputer(final Set<Vendor> vendors){
|
||||||
|
return new RatingComputer(vendors);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RatingComputer {
|
||||||
|
private final Map<Item, Offer> sellOffers;
|
||||||
|
private final Map<Item, Offer> buyOffers;
|
||||||
|
|
||||||
|
private final DoubleSummaryStatistics globalStat;
|
||||||
|
private final double avgDistance;
|
||||||
|
|
||||||
|
private RatingComputer(final Set<Vendor> vendors) {
|
||||||
|
sellOffers = new HashMap<>(100, 0.9f);
|
||||||
|
buyOffers = new HashMap<>(100, 0.9f);
|
||||||
|
market.getItems().forEach(i -> fillOffers(i, vendors));
|
||||||
|
globalStat = computeProfit();
|
||||||
|
avgDistance = vendors.stream().mapToDouble(Vendor::getDistance).average().orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillOffers(Item item, Set<Vendor> vendors){
|
||||||
|
Optional<Offer> offer = market.getSell(item).filter(o -> vendors.contains(o.getVendor())).findFirst();
|
||||||
|
if (offer.isPresent()){
|
||||||
|
sellOffers.put(item, offer.get());
|
||||||
|
}
|
||||||
|
offer = market.getBuy(item).filter(o -> vendors.contains(o.getVendor())).findFirst();
|
||||||
|
if (offer.isPresent()){
|
||||||
|
buyOffers.put(item, offer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<Order> mapToOrder(Offer offer) {
|
||||||
|
Offer sell;
|
||||||
|
Offer buy;
|
||||||
|
if (offer.getType() == OFFER_TYPE.SELL){
|
||||||
|
sell = offer;
|
||||||
|
buy = buyOffers.get(offer.getItem());
|
||||||
|
} else {
|
||||||
|
sell = sellOffers.get(offer.getItem());
|
||||||
|
buy = offer;
|
||||||
|
}
|
||||||
|
if (sell == null || buy == null) return Stream.empty();
|
||||||
|
Order order = new Order(sell, buy, profile.getBalance(), profile.getShip().getCargo());
|
||||||
|
if (order.getProfit() <= 0) return Stream.empty();
|
||||||
|
return Stream.of(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DoubleSummaryStatistics computeProfit(){
|
||||||
|
return sellOffers.values().stream()
|
||||||
|
.flatMap(this::mapToOrder)
|
||||||
|
.collect(Collectors.summarizingDouble(Order::getProfit));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DoubleSummaryStatistics computeProfits(Stream<Order> orders) {
|
||||||
|
return orders.sorted(Comparator.<Order>reverseOrder())
|
||||||
|
.limit(4)
|
||||||
|
.filter(o -> o.getProfit() > 0)
|
||||||
|
.collect(Collectors.summarizingDouble(Order::getProfit));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rating getRating(Vendor vendor){
|
||||||
|
Stream<Order> sell = vendor.getAllSellOffers().stream().flatMap(this::mapToOrder);
|
||||||
|
Stream<Order> buy = vendor.getAllBuyOffers().stream().flatMap(this::mapToOrder);
|
||||||
|
|
||||||
|
DoubleSummaryStatistics sellStat = computeProfits(sell);
|
||||||
|
DoubleSummaryStatistics buyStat = computeProfits(buy);
|
||||||
|
|
||||||
|
double sellRate = 0.5 * sellStat.getMax() / globalStat.getMax() + 2.5 * sellStat.getAverage() / globalStat.getAverage();
|
||||||
|
double buyRate = 0.5 * buyStat.getMax() / globalStat.getMax() + 2 * buyStat.getAverage() / globalStat.getAverage();
|
||||||
|
double distRate = 0.5 * (vendor.getDistance() > 0 ? (vendor.getDistance() < avgDistance ? 1-vendor.getDistance()/avgDistance : -1+avgDistance/vendor.getDistance()) : 0.0);
|
||||||
|
|
||||||
|
LOG.trace("Computed rate for {} = {}", vendor.getFullName(), sellRate + buyRate + distRate);
|
||||||
|
LOG.trace("global - max: {} avg: {} min: {}", globalStat.getMax(), globalStat.getAverage(), globalStat.getMin());
|
||||||
|
LOG.trace("sell - max: {} avg: {} min: {} rate: {}", sellStat.getMax(), sellStat.getAverage(), sellStat.getMin(), sellRate);
|
||||||
|
LOG.trace("buy - max: {} avg: {} min: {} rate: {}", buyStat.getMax(), buyStat.getAverage(), buyStat.getMin(), buyRate);
|
||||||
|
LOG.trace("distance: {} avg: {} rate: {}", vendor.getDistance(), avgDistance, distRate);
|
||||||
|
|
||||||
|
return new Rating(vendor, sellRate + buyRate + distRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Rating implements Comparable<Rating> {
|
||||||
|
private final Vendor vendor;
|
||||||
|
private final double rate;
|
||||||
|
|
||||||
|
public Rating(Vendor vendor, double rate) {
|
||||||
|
this.vendor = vendor;
|
||||||
|
this.rate = rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vendor getVendor() {
|
||||||
|
return vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getRate() {
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Rating o) {
|
||||||
|
return Double.compare(rate, o.rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -296,13 +296,26 @@ public class MarketAnalyzer {
|
|||||||
|
|
||||||
private Collection<Vendor> getVendors(CrawlerSpecificator specificator, boolean withTransit){
|
private Collection<Vendor> getVendors(CrawlerSpecificator specificator, boolean withTransit){
|
||||||
List<Vendor> transits = withTransit ? market.get().map(Place::asTransit).collect(Collectors.toList()) : new ArrayList<>();
|
List<Vendor> transits = withTransit ? market.get().map(Place::asTransit).collect(Collectors.toList()) : new ArrayList<>();
|
||||||
Collection<Vendor> vendors;
|
Set<Vendor> vendors;
|
||||||
if (!specificator.isFullScan() || specificator.getMinHop() >= profile.getLands()){
|
if (!specificator.isFullScan() || specificator.getMinHop() >= profile.getLands()){
|
||||||
vendors = market.getMarkets().filter(specificator::contains).collect(Collectors.toList());
|
vendors = market.getMarkets().filter(specificator::contains).collect(Collectors.toSet());
|
||||||
} else {
|
} else {
|
||||||
vendors = market.getMarkets().collect(Collectors.toList());
|
vendors = market.getMarkets().collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
vendors = specificator.getVendors(vendors);
|
Scorer.RatingComputer ratings = searcher.getScorer().getRatingComputer(vendors);
|
||||||
|
Collection<Scorer.Rating> removes = new ArrayList<>(500);
|
||||||
|
vendors.removeIf(v -> {
|
||||||
|
Scorer.Rating rating = ratings.getRating(v);
|
||||||
|
if (rating.getRate() <= profile.getMinVendorRating()){
|
||||||
|
if (specificator.contains(v)){
|
||||||
|
removes.add(rating);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
vendors.addAll(specificator.getVendors(removes));
|
||||||
vendors.addAll(transits);
|
vendors.addAll(transits);
|
||||||
return vendors;
|
return vendors;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public class Profile {
|
|||||||
private int lands;
|
private int lands;
|
||||||
private boolean refill;
|
private boolean refill;
|
||||||
private int routesCount;
|
private int routesCount;
|
||||||
|
private double minVendorRating;
|
||||||
//Scorer multipliers
|
//Scorer multipliers
|
||||||
private double distanceTime;
|
private double distanceTime;
|
||||||
private double jumpTime;
|
private double jumpTime;
|
||||||
@@ -31,6 +32,7 @@ public class Profile {
|
|||||||
jumps = 3;
|
jumps = 3;
|
||||||
lands = 4;
|
lands = 4;
|
||||||
routesCount = 30;
|
routesCount = 30;
|
||||||
|
minVendorRating = 7;
|
||||||
distanceTime = 0.3;
|
distanceTime = 0.3;
|
||||||
fuelPrice = 100;
|
fuelPrice = 100;
|
||||||
landingTime = 80;
|
landingTime = 80;
|
||||||
@@ -49,6 +51,7 @@ public class Profile {
|
|||||||
this.lands = profile.lands;
|
this.lands = profile.lands;
|
||||||
this.refill = profile.refill;
|
this.refill = profile.refill;
|
||||||
this.routesCount = profile.routesCount;
|
this.routesCount = profile.routesCount;
|
||||||
|
this.minVendorRating = profile.minVendorRating;
|
||||||
this.distanceTime = profile.distanceTime;
|
this.distanceTime = profile.distanceTime;
|
||||||
this.jumpTime = profile.jumpTime;
|
this.jumpTime = profile.jumpTime;
|
||||||
this.landingTime = profile.landingTime;
|
this.landingTime = profile.landingTime;
|
||||||
@@ -142,6 +145,14 @@ public class Profile {
|
|||||||
this.routesCount = routesCount;
|
this.routesCount = routesCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getMinVendorRating() {
|
||||||
|
return minVendorRating;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinVendorRating(double minVendorRating) {
|
||||||
|
this.minVendorRating = minVendorRating;
|
||||||
|
}
|
||||||
|
|
||||||
public double getDistanceTime() {
|
public double getDistanceTime() {
|
||||||
return distanceTime;
|
return distanceTime;
|
||||||
}
|
}
|
||||||
@@ -230,6 +241,7 @@ public class Profile {
|
|||||||
profile.setLands(Integer.valueOf(values.getProperty("profile.lands", "4")));
|
profile.setLands(Integer.valueOf(values.getProperty("profile.lands", "4")));
|
||||||
profile.setPathPriority(PATH_PRIORITY.valueOf(values.getProperty("profile.search.priority", "FAST")));
|
profile.setPathPriority(PATH_PRIORITY.valueOf(values.getProperty("profile.search.priority", "FAST")));
|
||||||
profile.setRoutesCount(Integer.valueOf(values.getProperty("profile.search.routes", "30")));
|
profile.setRoutesCount(Integer.valueOf(values.getProperty("profile.search.routes", "30")));
|
||||||
|
profile.setMinVendorRating(Double.valueOf(values.getProperty("profile.search.minRating", "7")));
|
||||||
profile.setFuelPrice(Double.valueOf(values.getProperty("profile.search.fuel.price", "100")));
|
profile.setFuelPrice(Double.valueOf(values.getProperty("profile.search.fuel.price", "100")));
|
||||||
profile.setDistanceTime(Double.valueOf(values.getProperty("profile.search.times.distance", "0.3")));
|
profile.setDistanceTime(Double.valueOf(values.getProperty("profile.search.times.distance", "0.3")));
|
||||||
profile.setLandingTime(Double.valueOf(values.getProperty("profile.search.times.landing", "80")));
|
profile.setLandingTime(Double.valueOf(values.getProperty("profile.search.times.landing", "80")));
|
||||||
@@ -250,6 +262,7 @@ public class Profile {
|
|||||||
values.setProperty("profile.lands", String.valueOf(lands));
|
values.setProperty("profile.lands", String.valueOf(lands));
|
||||||
values.setProperty("profile.search.priority", String.valueOf(pathPriority));
|
values.setProperty("profile.search.priority", String.valueOf(pathPriority));
|
||||||
values.setProperty("profile.search.routes", String.valueOf(routesCount));
|
values.setProperty("profile.search.routes", String.valueOf(routesCount));
|
||||||
|
values.setProperty("profile.search.minRating", String.valueOf(minVendorRating));
|
||||||
values.setProperty("profile.search.fuel.price", String.valueOf(fuelPrice));
|
values.setProperty("profile.search.fuel.price", String.valueOf(fuelPrice));
|
||||||
values.setProperty("profile.search.times.distance", String.valueOf(distanceTime));
|
values.setProperty("profile.search.times.distance", String.valueOf(distanceTime));
|
||||||
values.setProperty("profile.search.times.landing", String.valueOf(landingTime));
|
values.setProperty("profile.search.times.landing", String.valueOf(landingTime));
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class ScorerTest extends Assert {
|
|||||||
profile.setBalance(1000000);
|
profile.setBalance(1000000);
|
||||||
Scorer scorer = new Scorer(fWorld, profile);
|
Scorer scorer = new Scorer(fWorld, profile);
|
||||||
|
|
||||||
double avgProfit = scorer.getAvgProfit() * profile.getShip().getCargo();
|
double avgProfit = 750 * profile.getShip().getCargo();
|
||||||
|
|
||||||
double score = scorer.getScore(scorer.getAvgDistance(), 0, 1, 1, 0, 4);
|
double score = scorer.getScore(scorer.getAvgDistance(), 0, 1, 1, 0, 4);
|
||||||
double score1 = scorer.getScore(scorer.getAvgDistance(), avgProfit/2, 1, 1, 0, 4);
|
double score1 = scorer.getScore(scorer.getAvgDistance(), avgProfit/2, 1, 1, 0, 4);
|
||||||
|
|||||||
Reference in New Issue
Block a user