Skip to content

Commit

Permalink
Merge branch 'bfs'
Browse files Browse the repository at this point in the history
  • Loading branch information
xdnw committed May 25, 2024
2 parents 717e7b4 + 6ac4f53 commit 84f7a0e
Show file tree
Hide file tree
Showing 19 changed files with 905 additions and 397 deletions.
33 changes: 33 additions & 0 deletions src/main/java/link/locutus/discord/apiv1/enums/city/ICity.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import link.locutus.discord.apiv1.enums.city.project.Project;
import link.locutus.discord.apiv1.enums.city.project.Projects;
import link.locutus.discord.commands.manager.v2.binding.annotation.Command;
import link.locutus.discord.util.PW;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Predicate;

public interface ICity {
Expand All @@ -20,6 +22,37 @@ public interface ICity {

double getInfra();

default double getFreeInfra() {
return getInfra() - getNumBuildings() * 50;
}

default double caclulateBuildingCostConverted(JavaCity from) {
double total = 0;
for (Building building : Buildings.values()) {
int amtA = getBuilding(building);
int amtB = from.getBuilding(building);
if (amtA != amtB) {
if (amtB > amtA) {
total += building.getNMarketCost((amtB - amtA) * 0.5);
} else {
total += building.getNMarketCost(amtB - amtA);
}
}
}
return total;
}

default double calculateCostConverted(JavaCity from) {
double total = caclulateBuildingCostConverted(from);
if (this.getInfra() > from.getInfra()) {
total += PW.City.Infra.calculateInfra(from.getInfra(), getInfra());
}
if (!Objects.equals(getLand(), from.getLand())) {
total += PW.City.Land.calculateLand(from.getLand(), getLand());
}
return total;
}

double getLand();

int getBuilding(Building building);
Expand Down
210 changes: 85 additions & 125 deletions src/main/java/link/locutus/discord/apiv1/enums/city/JavaCity.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import link.locutus.discord.apiv1.enums.city.building.*;
import link.locutus.discord.commands.info.optimal.CityBranch;
import link.locutus.discord.config.Settings;
import link.locutus.discord.db.entities.CityNode;
import link.locutus.discord.db.entities.DBCity;
import link.locutus.discord.db.entities.DBNation;
import link.locutus.discord.db.entities.MMRInt;
Expand Down Expand Up @@ -72,21 +73,13 @@ public void clear() {
Arrays.fill(buildings, (byte) 0);
}

public void set(JavaCity other, int maxBuildingIndex) {
// if (this.metrics != null) {
// if (other.metrics != null) {
// this.metrics.profit = other.metrics.profit;
// this.metrics.population = other.metrics.population;
// this.metrics.disease = other.metrics.disease;
// this.metrics.crime = other.metrics.crime;
// this.metrics.pollution = other.metrics.pollution;
// this.metrics.commerce = other.metrics.commerce;
// } else {
// clearMetrics();
// }
// }
// maxBuildingIndex = Math.min(buildings.length, maxBuildingIndex);
// for (int i = 0; i <= maxBuildingIndex; i++) {
public void setBuildings(ICity other) {
for (Building building : Buildings.values()) {
set(building, other.getBuilding(building));
}
}

public void set(JavaCity other) {
for (int i = 0; i < buildings.length; i++) {
buildings[i] = other.buildings[i];
}
Expand All @@ -104,10 +97,14 @@ public void clearMetrics() {
}
}

public long getNukeTurn() {
public int getNukeTurn() {
return nuke_turn;
}

public void setNuke_turn(int nuke_turn) {
this.nuke_turn = nuke_turn;
}

public int[] getMMRArray() {
return new int[]{getBuilding(Buildings.BARRACKS), getBuilding(Buildings.FACTORY), getBuilding(Buildings.HANGAR), getBuilding(Buildings.DRYDOCK)};
}
Expand Down Expand Up @@ -136,15 +133,7 @@ public void recalculate(JavaCity city, Predicate<Project> hasProject) {
pollution = 0;
commerce = 0;

double pollutionMax = 400d;
int turnsMax = 11 * 12;
long turns = TimeUtil.getTurn() - city.nuke_turn;
if (turns < turnsMax) {
double nukePollution = (turnsMax - turns) * pollutionMax / (turnsMax);
if (nukePollution > 0) {
pollution += (int) nukePollution;
}
}
this.pollution = PW.City.getNukePollution(city.nuke_turn);

for (Building building : Buildings.POLLUTION_BUILDINGS) {
int amt = city.buildings[building.ordinal()];
Expand Down Expand Up @@ -207,6 +196,20 @@ public void recalculate(JavaCity city, Predicate<Project> hasProject) {
}
}

public int getMaxCommerce(Predicate<Project> hasProject) {
int maxCommerce;
if (hasProject.test(Projects.INTERNATIONAL_TRADE_CENTER)) {
if (hasProject.test(Projects.TELECOMMUNICATIONS_SATELLITE)) {
maxCommerce = 125;
} else {
maxCommerce = 115;
}
} else {
maxCommerce = 100;
}
return maxCommerce;
}

public Metrics getCachedMetrics() {
return metrics;
}
Expand All @@ -216,7 +219,6 @@ public Metrics getMetrics(Predicate<Project> hasProject) {
metrics = new Metrics();
}
if (metrics.commerce == null) {

metrics.recalculate(this, hasProject);
}
return metrics;
Expand Down Expand Up @@ -467,30 +469,43 @@ public JavaCity zeroNonMilitary() {
return this;
}

public JavaCity optimalBuild(DBNation nation, long timeout) {
return optimalBuild(nation.getContinent(), nation.getRads(), nation.getCities(), nation::hasProject, nation.getGrossModifier(), timeout);
}

public JavaCity optimalBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, long timeout) {
return optimalBuild(continent, rads, numCities, hasProject, grossModifier, timeout, f -> f, null);
}

public JavaCity optimalBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, long timeout,
Function<Function<JavaCity, Double>, Function<JavaCity, Double>> modifyValueFunc, Function<JavaCity, Boolean> goal) {
Predicate<Project> finalHasProject = Projects.hasProjectCached(hasProject);
Function<JavaCity, Double> valueFunction = javaCity -> {
return javaCity.profitConvertedCached(continent, rads, finalHasProject, numCities, grossModifier) / javaCity.getNumBuildings();
};
valueFunction = modifyValueFunc.apply(valueFunction);

return optimalBuild(continent, valueFunction, goal, finalHasProject, timeout, rads);
}

public JavaCity roiBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, int days, long timeout) {
return roiBuild(continent, rads, numCities, hasProject, grossModifier, days, timeout, f -> f, null);
}

public JavaCity roiBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, int days, long timeout, Function<Function<JavaCity, Double>, Function<JavaCity, Double>> modifyValueFunc, Function<JavaCity, Boolean> goal) {
public JavaCity optimalBuild(DBNation nation, long timeout, boolean selfSufficient, Double infraLow) {
// Continent continent,
// int numCities,
// Function<CityNode, Double> valueFunction,
// Function<CityNode, Boolean> goal,
// Predicate<Project> hasProject,
// long timeout, double rads,
// boolean selfSufficient,
// double grossModifier,
// Double infraLow
return optimalBuild(nation.getContinent(),
nation.getCities(),
CityNode::getRevenueConverted,
null,
nation::hasProject,
timeout,
nation.getRads(),
selfSufficient,
nation.getGrossModifier(),
infraLow);
}

// public JavaCity optimalBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, long timeout, boolean selfSufficient,
// Function<Function<JavaCity, Double>, Function<JavaCity, Double>> modifyValueFunc, Function<JavaCity, Boolean> goal) {
// Predicate<Project> finalHasProject = Projects.optimize(hasProject);
// Function<JavaCity, Double> valueFunction = javaCity -> {
// return javaCity.profitConvertedCached(continent, rads, finalHasProject, numCities, grossModifier) / javaCity.getNumBuildings();
// };
// valueFunction = modifyValueFunc.apply(valueFunction);
// return optimalBuild(continent, valueFunction, goal, finalHasProject, timeout, rads, selfSufficient);
// }

public JavaCity roiBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, int days, long timeout, boolean selfSufficient, Double infraLow) {
return roiBuild(continent, rads, numCities, hasProject, grossModifier, days, timeout, selfSufficient, infraLow, f -> f, null);
}

public JavaCity roiBuild(Continent continent, double rads, int numCities, Predicate<Project> hasProject, double grossModifier, int days, long timeout, boolean selfSufficient, Double infraLow, Function<Function<CityNode, Double>, Function<CityNode, Double>> modifyValueFunc, Function<CityNode, Boolean> goal) {
JavaCity origin = new JavaCity(this);
origin.setAge(this.getAgeDays() + days / 2);

Expand All @@ -508,27 +523,17 @@ public JavaCity roiBuild(Continent continent, double rads, int numCities, Predic
double baseProfitNonTax = (baseProfit - zeroedProfit);
double profitPerImp = baseProfitNonTax / impOverZero;

Predicate<Project> finalHasProject = Projects.hasProjectCached(hasProject);
Function<JavaCity, Double> valueFunction = javaCity -> {
double newProfit = javaCity.profitConvertedCached(continent, rads, finalHasProject, numCities, grossModifier);

Predicate<Project> finalHasProject = Projects.optimize(hasProject);
Function<CityNode, Double> valueFunction = javaCity -> {
double newProfit = javaCity.getRevenueConverted();
double cost = javaCity.calculateCostConverted(origin);

// int imp = javaCity.getImpTotal() - baseImp;
// double expectedProfit = profitPerImp * imp;
return (newProfit * days - cost) / javaCity.getNumBuildings();
};

valueFunction = modifyValueFunc.apply(valueFunction);

JavaCity optimal = zeroed.optimalBuild(continent, valueFunction, goal, finalHasProject, timeout, rads);
JavaCity optimal = zeroed.optimalBuild(continent, numCities, valueFunction, goal, finalHasProject, timeout, rads, selfSufficient, grossModifier, infraLow);
return optimal;
}

public JavaCity optimalBuild(Continent continent, Function<JavaCity, Double> valueFunction, Predicate<Project> hasProject, long timeout, double rads) {
return optimalBuild(continent, valueFunction, null, hasProject, timeout, rads);
}

public JavaCity zeroPower() {
for (int i = 0; i < buildings.length; i++) {
if (!(Buildings.get(i) instanceof PowerBuilding)) continue;
Expand Down Expand Up @@ -570,44 +575,14 @@ public JavaCity setOptimalPower(Continent continent) {
return this;
}

public JavaCity optimalBuild(Continent continent, Function<JavaCity, Double> valueFunction, Function<JavaCity, Boolean> goal, Predicate<Project> hasProject, long timeout, double rads) {
if (goal == null) {
goal = javaCity -> javaCity.getFreeInfra() < 50;
}
CityBranch searchServices = new CityBranch(this, continent, false, rads, hasProject);

Function<Map.Entry<JavaCity, Integer>, Double> valueFunction2 = e -> valueFunction.apply(e.getKey());
Function<JavaCity, Boolean> finalGoal = goal;
Function<Map.Entry<JavaCity, Integer>, Boolean> goal2 = e -> finalGoal.apply(e.getKey());

PriorityQueue<Map.Entry<JavaCity, Integer>> queue = new ObjectHeapPriorityQueue<Map.Entry<JavaCity, Integer>>(500000,
(o1, o2) -> Double.compare(valueFunction2.apply(o2), valueFunction2.apply(o1)));

JavaCity origin = new JavaCity(this);

Function<Double, Function<Map.Entry<JavaCity, Integer>, Double>> valueCompletionFunction;

valueCompletionFunction = factor -> (Function<Map.Entry<JavaCity, Integer>, Double>) entry -> {
Double parentValue = valueFunction2.apply(entry);
int imps = entry.getKey().getNumBuildings();

if (factor <= 1) {
parentValue = (parentValue * imps) * factor + (parentValue * (1 - factor));
} else {
double factor2 = factor - 1;
parentValue = imps * factor2 + (parentValue * imps) * (1 - factor2);
}
return parentValue;
};

if (origin.getRequiredInfra() > origin.getInfra()) {
throw new IllegalArgumentException("The city infrastructure (" + MathMan.format(origin.getInfra()) + ") is too low for the required buildings (required infra: " + MathMan.format(origin.getRequiredInfra()) + ", mmr: " + origin.getMMR() + ")");
}

Map.Entry<JavaCity, Integer> optimized = BFSUtil.search(goal2, valueFunction2, valueCompletionFunction, searchServices, searchServices, new AbstractMap.SimpleEntry<>(origin, 0), queue, timeout);

System.out.println("Buildings " + optimized.getKey().getNumBuildings());
return optimized == null ? null : optimized.getKey();
public JavaCity optimalBuild(Continent continent, int numCities, Function<CityNode, Double> valueFunction, Function<CityNode, Boolean> goal, Predicate<Project> hasProject, long timeout, double rads, boolean selfSufficient, double grossModifier, Double infraLow) {
JavaCity copy = new JavaCity(this);
CityNode.CachedCity cached = new CityNode.CachedCity(this, continent, selfSufficient, hasProject, numCities, grossModifier, rads, infraLow);
CityBranch searchServices = new CityBranch(cached);
CityNode optimized = searchServices.toOptimal(valueFunction, goal, timeout);
System.out.println("Buildings " + (optimized == null ? "null" : optimized.getNumBuildings()));
if (optimized != null) copy.setBuildings(optimized);
return optimized == null ? null : copy;
}

public double profitConvertedCached(Continent continent, double rads, Predicate<Project> hasProject, int numCities, double grossModifier) {
Expand Down Expand Up @@ -695,29 +670,6 @@ public double[] calculateCost(JavaCity from) {
return calculateCost(from, new double[ResourceType.values.length]);
}

public double calculateCostConverted(JavaCity from) {
double total = 0;
for (int i = 0; i < buildings.length; i++) {
int amtOther = from.buildings[i];
int amt = buildings[i];
if (amt != amtOther) {
if (amtOther > amt) {
total += Buildings.get(i).getNMarketCost((amt - amtOther) * 0.5);
} else {
total += Buildings.get(i).getNMarketCost(amt - amtOther);
}
}
}

if (this.getInfra() > from.getInfra()) {
total += PW.City.Infra.calculateInfra(from.getInfra(), getInfra());
}
if (!Objects.equals(getLand(), from.getLand())) {
total += PW.City.Land.calculateLand(from.getLand(), getLand());
}
return total;
}

public double[] calculateCost(JavaCity from, double[] buffer) {
return calculateCost(from, buffer, true, true);
}
Expand Down Expand Up @@ -817,6 +769,14 @@ public JavaCity setAge(Integer age) {
return this;
}

public void setDateCreated(long dateCreated) {
this.dateCreated = dateCreated;
}

public long getDateCreated() {
return dateCreated;
}

public JavaCity setLand(Double land) {
this.land_ = land;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ default boolean canBuild(Continent continent) {

double profitConverted(Continent continent, double rads, Predicate<Project> hasProject, ICity city, int amt);

double[] profit(Continent continent, double rads, long date, Predicate<Project> hasProject, ICity city, double[] profitBuffer, int turns);
double[] profit(Continent continent, double rads, long date, Predicate<Project> hasProject, ICity city, double[] profitBuffer, int turns, int amt);

@Command(desc = "Get the continents this building can be built on")
default Set<Continent> getContinents() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ default boolean canBuild(Continent continent) {
ResourceBuilding continents(Continent... continents);

int getBaseProduction();

int getBaseInput();
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ public double profitConverted(Continent continent, double rads, Predicate<Projec
}

@Override
public double[] profit(Continent continent, double rads, long date, Predicate<Project> hasProject, ICity city, double[] profitBuffer, int turns) {
int amt = city.getBuilding(this);
public double[] profit(Continent continent, double rads, long date, Predicate<Project> hasProject, ICity city, double[] profitBuffer, int turns, int amt) {
if (amt > 0) {
for (ResourceType type : ResourceType.values) {
profitBuffer[type.ordinal()] -= upkeep(type, hasProject) * amt * turns / 12;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public double consumptionConverted(int infra) {
} else {
amt = (Math.min(infra, this.infra) + infraLevels - 1) / infraLevels;
}
return -(amt * resourceValue);
return -(amt * resourceValue * inputArr[resource.ordinal()]);
}

@Override
Expand All @@ -75,7 +75,7 @@ public double[] consumption(int infra, double[] profitBuffer, int turns) {
@Override
public double getPowerResourceConsumed(int infra) {
if (resource != null) {
return (Math.min(infra, this.infra) + infraLevels - 1d) / infraLevels;
return (Math.min(infra, this.infra) + infraLevels - 1) / infraLevels;
}
return 0;
}
Expand Down
Loading

0 comments on commit 84f7a0e

Please sign in to comment.