implement import powerplay data
This commit is contained in:
@@ -6,7 +6,6 @@ import ru.trader.core.Market;
|
|||||||
import ru.trader.core.Place;
|
import ru.trader.core.Place;
|
||||||
import ru.trader.core.StarSystemFilter;
|
import ru.trader.core.StarSystemFilter;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -32,7 +31,27 @@ public class PowerPlayAnalyzator {
|
|||||||
this.starSystemFilter = starSystemFilter;
|
this.starSystemFilter = starSystemFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Place> getNear(Collection<Place> starSystems, Collection<Place> centers, double radius, double maxDistance){
|
public Collection<Place> getControlling(Place starSystem){
|
||||||
|
return getControlling(starSystem, market.get(), CONTROLLING_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Place> getIntersects(Collection<Place> starSystems){
|
||||||
|
return getIntersects(market.get(), starSystems, CONTROLLING_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Place> getIntersects(Place starSystem, Collection<Place> starSystems){
|
||||||
|
return getIntersects(starSystem, market.get(), starSystems, CONTROLLING_RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Collection<Place> getControlling(Place starSystem, Collection<Place> starSystems, double radius){
|
||||||
|
return starSystems.stream()
|
||||||
|
.filter(new Controlling(starSystem, radius))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Collection<Place> getNear(Collection<Place> starSystems, Collection<Place> centers, double radius, double maxDistance){
|
||||||
return starSystems.stream()
|
return starSystems.stream()
|
||||||
.filter(new FarDropper(centers, maxDistance))
|
.filter(new FarDropper(centers, maxDistance))
|
||||||
.filter(intersectsAnyPredicate(centers, radius).negate())
|
.filter(intersectsAnyPredicate(centers, radius).negate())
|
||||||
@@ -40,24 +59,21 @@ public class PowerPlayAnalyzator {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Collection<Place> getIntersects(Place checkedSystem, Collection<Place> starSystems, Collection<Place> centers, double radius){
|
||||||
|
|
||||||
|
|
||||||
public Collection<Place> getIntersects(Place checkedSystem, Collection<Place> starSystems, Collection<Place> centers, double radius){
|
|
||||||
return starSystems.stream()
|
return starSystems.stream()
|
||||||
.filter(new FarDropper(centers, radius))
|
.filter(new FarDropper(centers, radius))
|
||||||
.filter(intersectsPredicate(checkedSystem, centers, radius))
|
.filter(intersectsPredicate(checkedSystem, centers, radius))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Place> getIntersects(Collection<Place> starSystems, Collection<Place> centers, double radius){
|
public static Collection<Place> getIntersects(Collection<Place> starSystems, Collection<Place> centers, double radius){
|
||||||
return starSystems.stream()
|
return starSystems.stream()
|
||||||
.filter(new FarDropper(centers, radius))
|
.filter(new FarDropper(centers, radius))
|
||||||
.filter(intersectsPredicate(centers, radius))
|
.filter(intersectsPredicate(centers, radius))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<Place> intersectsAnyPredicate(Collection<Place> places, double radius){
|
private static Predicate<Place> intersectsAnyPredicate(Collection<Place> places, double radius){
|
||||||
Predicate<Place> intersects = null;
|
Predicate<Place> intersects = null;
|
||||||
for (Place place : places) {
|
for (Place place : places) {
|
||||||
if (intersects == null) intersects = new Controlling(place, radius);
|
if (intersects == null) intersects = new Controlling(place, radius);
|
||||||
@@ -67,7 +83,7 @@ public class PowerPlayAnalyzator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Predicate<Place> intersectsPredicate(Collection<Place> places, double radius){
|
private static Predicate<Place> intersectsPredicate(Collection<Place> places, double radius){
|
||||||
Predicate<Place> intersects = null;
|
Predicate<Place> intersects = null;
|
||||||
for (Place place : places) {
|
for (Place place : places) {
|
||||||
if (intersects == null) intersects = new Controlling(place, radius);
|
if (intersects == null) intersects = new Controlling(place, radius);
|
||||||
@@ -76,11 +92,11 @@ public class PowerPlayAnalyzator {
|
|||||||
return intersects;
|
return intersects;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<Place> intersectsPredicate(Place checkedPlace, Collection<Place> places, double radius){
|
private static Predicate<Place> intersectsPredicate(Place checkedPlace, Collection<Place> places, double radius){
|
||||||
return new Controlling(checkedPlace, radius).and(intersectsAnyPredicate(places, radius));
|
return new Controlling(checkedPlace, radius).and(intersectsAnyPredicate(places, radius));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Controlling implements Predicate<Place> {
|
private static class Controlling implements Predicate<Place> {
|
||||||
private final Place center;
|
private final Place center;
|
||||||
private final double radius;
|
private final double radius;
|
||||||
|
|
||||||
@@ -91,6 +107,7 @@ public class PowerPlayAnalyzator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean test(Place place) {
|
public boolean test(Place place) {
|
||||||
|
if (place == center) return false;
|
||||||
double distance = center.getDistance(place);
|
double distance = center.getDistance(place);
|
||||||
LOG.trace("Check {}, distance to {} = {}, radius = {}", place, center, distance, radius);
|
LOG.trace("Check {}, distance to {} = {}, radius = {}", place, center, distance, radius);
|
||||||
return distance <= radius;
|
return distance <= radius;
|
||||||
@@ -98,7 +115,7 @@ public class PowerPlayAnalyzator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class FarDropper implements Predicate<Place> {
|
private static class FarDropper implements Predicate<Place> {
|
||||||
private double minX;
|
private double minX;
|
||||||
private double maxX;
|
private double maxX;
|
||||||
private double minY;
|
private double minY;
|
||||||
@@ -148,7 +165,7 @@ public class PowerPlayAnalyzator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DistanceComparator implements Comparator<Place> {
|
private static class DistanceComparator implements Comparator<Place> {
|
||||||
private final Collection<Place> centers;
|
private final Collection<Place> centers;
|
||||||
private final HashMap<Place, Double> distances;
|
private final HashMap<Place, Double> distances;
|
||||||
|
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ public enum POWER {
|
|||||||
return super.isLegal(faction, item, state);
|
return super.isLegal(faction, item, state);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
GROM,
|
||||||
NONE;
|
NONE;
|
||||||
|
|
||||||
private final static String WEAPONS_GRP="weapons";
|
private final static String WEAPONS_GRP="weapons";
|
||||||
|
|||||||
184
utils/src/main/java/ru/trader/powerplay/PPParser.java
Normal file
184
utils/src/main/java/ru/trader/powerplay/PPParser.java
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package ru.trader.powerplay;
|
||||||
|
|
||||||
|
import au.com.bytecode.opencsv.CSVParser;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import ru.trader.core.*;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class PPParser {
|
||||||
|
private final static Logger LOG = LoggerFactory.getLogger(PPParser.class);
|
||||||
|
|
||||||
|
private final CSVParser parser;
|
||||||
|
private final Market market;
|
||||||
|
private boolean canceled;
|
||||||
|
private final Collection<PowerData> controllingSystems;
|
||||||
|
|
||||||
|
public PPParser(Market market) {
|
||||||
|
this.market = market;
|
||||||
|
parser = new CSVParser(',', '\"');
|
||||||
|
controllingSystems = new ArrayList<>(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel(){
|
||||||
|
this.canceled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseSystems(File file) throws IOException {
|
||||||
|
parseFile(file, 1, FILE_TYPE.SYSTEMS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFile(File file, int skip, FILE_TYPE type) throws IOException {
|
||||||
|
canceled = false;
|
||||||
|
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||||
|
int row = 0;
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
if (canceled) break;
|
||||||
|
row++;
|
||||||
|
if (row <= skip) continue;
|
||||||
|
String[] values = parser.parseLine(line);
|
||||||
|
switch (type) {
|
||||||
|
case SYSTEMS: parseSystemsFile(values);
|
||||||
|
break;
|
||||||
|
case PREPARE:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (type == FILE_TYPE.SYSTEMS){
|
||||||
|
updatePowerState();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (type == FILE_TYPE.SYSTEMS){
|
||||||
|
controllingSystems.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseSystemsFile(String[] values) {
|
||||||
|
// "Id","Power Id","Value","State","Upkeep Default","Upkeep Current","Income","Controlstarsystem Id","Qty For","Qty Against","Thr For","Thr Against","Prediction","В "
|
||||||
|
String starSystemName = getName(values[0]);
|
||||||
|
POWER power = getPower(values[1]);
|
||||||
|
POWER_STATE state = getState(values[3]);
|
||||||
|
if (starSystemName == null || power == null || state == null) return;
|
||||||
|
if (state == POWER_STATE.CONTROL || state == POWER_STATE.EXPANSION){
|
||||||
|
Place place = market.get(starSystemName);
|
||||||
|
if (place != null){
|
||||||
|
controllingSystems.add(new PowerData(place, power, state));
|
||||||
|
} else {
|
||||||
|
LOG.warn("Not found system {} for import powerplay data", starSystemName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private final static Pattern NAME_REGEXP = Pattern.compile("(.+)\\s+\\((\\d+)\\)");
|
||||||
|
@Nullable
|
||||||
|
private String getName(String value) {
|
||||||
|
Matcher matcher = NAME_REGEXP.matcher(value);
|
||||||
|
if (matcher.find()){
|
||||||
|
return matcher.group(1);
|
||||||
|
} else {
|
||||||
|
LOG.warn("Unknown format of name: {} ", value);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private POWER getPower(String value) {
|
||||||
|
String name = getName(value);
|
||||||
|
if (name == null) return null;
|
||||||
|
switch (name){
|
||||||
|
case "A. Lavigny-Duval": return POWER.LAVIGNY_DUVAL;
|
||||||
|
case "Aisling Duval": return POWER.DUVAL;
|
||||||
|
case "Archon Delaine": return POWER.DELAINE;
|
||||||
|
case "Denton Patreus": return POWER.PATREUS;
|
||||||
|
case "Edmund Mahon": return POWER.MAHON;
|
||||||
|
case "Felicia Winters": return POWER.WINTERS;
|
||||||
|
case "Li Yong-Rui": return POWER.YONG_RUI;
|
||||||
|
case "Pranav Antal": return POWER.ANTAL;
|
||||||
|
case "Yuri Grom": return POWER.GROM;
|
||||||
|
case "Zachary Hudson": return POWER.HUDSON;
|
||||||
|
case "Zemina Torval": return POWER.TORVAL;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unknown power name: {}", name);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private POWER_STATE getState(String value) {
|
||||||
|
if (value == null) return null;
|
||||||
|
switch (value){
|
||||||
|
case "blocked": return POWER_STATE.NONE;
|
||||||
|
case "control": return POWER_STATE.CONTROL;
|
||||||
|
case "contested": return POWER_STATE.CONTESTED;
|
||||||
|
case "takingControl": return POWER_STATE.EXPANSION;
|
||||||
|
case "turmoil": return POWER_STATE.NONE;
|
||||||
|
default:
|
||||||
|
LOG.warn("Unknown power state: {}", value);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static double CONTROLLING_RADIUS = 15;
|
||||||
|
private void updatePowerState(){
|
||||||
|
if (controllingSystems.isEmpty()) return;
|
||||||
|
for (Place starSystem : market.get()) {
|
||||||
|
if (starSystem.getFaction() == FACTION.NONE) continue;
|
||||||
|
if (starSystem.getPowerState() != POWER_STATE.HEADQUARTERS){
|
||||||
|
starSystem.setPower(POWER.NONE, POWER_STATE.NONE);
|
||||||
|
}
|
||||||
|
for (PowerData powerData : controllingSystems){
|
||||||
|
if (starSystem.equals(powerData.starSystem)){
|
||||||
|
if (starSystem.getPowerState() != POWER_STATE.HEADQUARTERS){
|
||||||
|
starSystem.setPower(powerData.power, powerData.state);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (powerData.state != POWER_STATE.CONTROL) continue;
|
||||||
|
if (starSystem.getDistance(powerData.starSystem) <= CONTROLLING_RADIUS){
|
||||||
|
if (starSystem.getPowerState() == POWER_STATE.EXPLOITED){
|
||||||
|
if (starSystem.getPower() != powerData.power){
|
||||||
|
starSystem.setPower(powerData.power, POWER_STATE.CONTESTED);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (starSystem.getPowerState() == POWER_STATE.NONE){
|
||||||
|
starSystem.setPower(powerData.power, POWER_STATE.EXPLOITED);
|
||||||
|
} else {
|
||||||
|
LOG.warn("Illegal power state: {}, star system: {}", starSystem.getPower(), starSystem.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum FILE_TYPE {
|
||||||
|
SYSTEMS, PREPARE
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PowerData {
|
||||||
|
private final Place starSystem;
|
||||||
|
private final POWER power;
|
||||||
|
private final POWER_STATE state;
|
||||||
|
|
||||||
|
private PowerData(Place starSystem, POWER power, POWER_STATE state) {
|
||||||
|
this.starSystem = starSystem;
|
||||||
|
this.power = power;
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
87
utils/src/test/java/ru/trader/powerplay/PPImportTest.java
Normal file
87
utils/src/test/java/ru/trader/powerplay/PPImportTest.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package ru.trader.powerplay;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import ru.trader.analysis.PowerPlayAnalyzator;
|
||||||
|
import ru.trader.core.Market;
|
||||||
|
import ru.trader.core.POWER;
|
||||||
|
import ru.trader.core.POWER_STATE;
|
||||||
|
import ru.trader.core.Place;
|
||||||
|
import ru.trader.store.simple.Store;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class PPImportTest extends Assert {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testImportSystems() throws Exception {
|
||||||
|
InputStream is = getClass().getResourceAsStream("/world.xml");
|
||||||
|
Market market = Store.loadFromFile(is);
|
||||||
|
Place opala = market.get("Opala");
|
||||||
|
Place aulin = market.get("Aulin");
|
||||||
|
Place draconis = market.get("26 Draconis");
|
||||||
|
Place bolg = market.get("Bolg");
|
||||||
|
Place aulis = market.get("Aulis");
|
||||||
|
Place lhs2887 = market.get("LHS 2887");
|
||||||
|
Place gd_319 = market.get("GD 319");
|
||||||
|
|
||||||
|
aulin.setPower(POWER.GROM, POWER_STATE.CONTROL);
|
||||||
|
draconis.setPower(POWER.PATREUS, POWER_STATE.EXPLOITED);
|
||||||
|
|
||||||
|
PPParser parser = new PPParser(market);
|
||||||
|
parser.parseSystems(new File(getClass().getResource("/pp.csv").getFile()));
|
||||||
|
|
||||||
|
assertEquals(POWER_STATE.CONTROL, opala.getPowerState());
|
||||||
|
assertEquals(POWER.MAHON, opala.getPower());
|
||||||
|
assertEquals(POWER_STATE.CONTROL, bolg.getPowerState());
|
||||||
|
assertEquals(POWER.DUVAL, bolg.getPower());
|
||||||
|
|
||||||
|
PowerPlayAnalyzator analyzator = new PowerPlayAnalyzator(market);
|
||||||
|
|
||||||
|
Collection<Place> intersectsMahon = analyzator.getIntersects(Arrays.asList(opala, gd_319));
|
||||||
|
Collection<Place> intersectsDuval = analyzator.getIntersects(bolg, Arrays.asList(opala, gd_319));
|
||||||
|
|
||||||
|
Collection<Place> exploitedOpala = analyzator.getControlling(opala);
|
||||||
|
Collection<Place> exploitedBolg = analyzator.getControlling(bolg);
|
||||||
|
|
||||||
|
for (Place place : intersectsMahon) {
|
||||||
|
assertEquals(POWER_STATE.EXPLOITED, place.getPowerState());
|
||||||
|
assertEquals(POWER.MAHON, place.getPower());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Place place : exploitedOpala) {
|
||||||
|
if (intersectsDuval.contains(place)){
|
||||||
|
assertEquals(POWER_STATE.CONTESTED, place.getPowerState());
|
||||||
|
} else {
|
||||||
|
assertEquals(POWER_STATE.EXPLOITED, place.getPowerState());
|
||||||
|
assertEquals(POWER.MAHON, place.getPower());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Place place : exploitedBolg) {
|
||||||
|
if (intersectsDuval.contains(place)){
|
||||||
|
assertEquals(POWER_STATE.CONTESTED, place.getPowerState());
|
||||||
|
} else {
|
||||||
|
assertEquals(POWER_STATE.EXPLOITED, place.getPowerState());
|
||||||
|
assertEquals(POWER.DUVAL, place.getPower());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(POWER_STATE.CONTESTED, aulin.getPowerState());
|
||||||
|
assertEquals(POWER.DUVAL, aulin.getPower());
|
||||||
|
|
||||||
|
assertEquals(POWER_STATE.EXPLOITED, aulis.getPowerState());
|
||||||
|
assertEquals(POWER.MAHON, aulis.getPower());
|
||||||
|
|
||||||
|
assertEquals(POWER_STATE.EXPLOITED, lhs2887.getPowerState());
|
||||||
|
assertEquals(POWER.DUVAL, lhs2887.getPower());
|
||||||
|
|
||||||
|
assertEquals(POWER_STATE.EXPANSION, draconis.getPowerState());
|
||||||
|
assertEquals(POWER.DELAINE, draconis.getPower());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
8
utils/src/test/resources/pp.csv
Normal file
8
utils/src/test/resources/pp.csv
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"Id","Power Id","Value","State","Upkeep Default","Upkeep Current","Income","Controlstarsystem Id","Qty For","Qty Against","Thr For","Thr Against","Prediction","В "
|
||||||
|
"Opala (78755)","Edmund Mahon (100010)","7","control","23","23","131","","2842","4650","2818","13778","FORTIFY",""
|
||||||
|
"Gui Xian (3932411564754)","A. Lavigny-Duval (100020)","10","control","22","0","99","","2760","0","2760","15031","FORTIFY",""
|
||||||
|
"Bolg (2871588038081)","Aisling Duval (100000)","8","control","24","24","65","","6413","0","6213","10701","FORTIFY",""
|
||||||
|
"26 Draconis (2869440619961)","Archon Delaine (100100)","6","takingControl","0","0","0","","3690","24830","6632","9652","FAIL",""
|
||||||
|
"Gyhldekala (2869977687521)","Yuri Grom (100120)","0","control","28","28","108","","4993","420","3725","8507","FORTIFY",""
|
||||||
|
"GD 319 (9467584587225)","Edmund Mahon (100010)","0","control","0","0","0","Lundji (11666876278233)","","","","","PASS",""
|
||||||
|
"Ithaca (77805)","Edmund Mahon (100010)","5","blocked","22","22","112","","1749","2070","5314","18818","PASS",""
|
||||||
|
2381
utils/src/test/resources/world.xml
Normal file
2381
utils/src/test/resources/world.xml
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user