fix #2: calculate exact values for byproducts and its parents
parent
f8bdb9902b
commit
0ab1f7b330
|
|
@ -110,7 +110,7 @@ public class Utils {
|
||||||
double instances = sum.outgoingEdgesOf(item).stream().map(ProductionEdge::getInstances).reduce(Double::sum).orElseGet(() -> Double.NaN);
|
double instances = sum.outgoingEdgesOf(item).stream().map(ProductionEdge::getInstances).reduce(Double::sum).orElseGet(() -> Double.NaN);
|
||||||
String buildingName = item.getRecipe().getBuilding().getName();
|
String buildingName = item.getRecipe().getBuilding().getName();
|
||||||
if (Double.isNaN(required) || Double.isNaN(instances)) {
|
if (Double.isNaN(required) || Double.isNaN(instances)) {
|
||||||
required = -sum.incomingEdgesOf(item).stream().map(ProductionEdge::getTotalRequired).reduce(Double::sum).orElseGet(() -> Double.NaN);
|
required = -sum.incomingEdgesOf(item).stream().map(ProductionEdge::getTotalProduced).reduce(Double::sum).orElseGet(() -> Double.NaN);
|
||||||
instances = 0;
|
instances = 0;
|
||||||
buildingName = "";
|
buildingName = "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,12 @@ public class ProductionEdge {
|
||||||
private final Item target;
|
private final Item target;
|
||||||
private double totalRequired;
|
private double totalRequired;
|
||||||
private double instances;
|
private double instances;
|
||||||
|
private boolean ignoreUpstream;
|
||||||
|
|
||||||
|
public ProductionEdge(Item source, Item target, double totalRequired, double productionRate, boolean ignoreUpstream) {
|
||||||
|
this(source, target, totalRequired, productionRate);
|
||||||
|
this.ignoreUpstream = ignoreUpstream;
|
||||||
|
}
|
||||||
|
|
||||||
public ProductionEdge(Item source, Item target, double totalRequired, double productionRate) {
|
public ProductionEdge(Item source, Item target, double totalRequired, double productionRate) {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
|
|
@ -28,6 +34,13 @@ public class ProductionEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getTotalRequired() {
|
public double getTotalRequired() {
|
||||||
|
if (ignoreUpstream){
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
return totalRequired;
|
||||||
|
}
|
||||||
|
public double getTotalProduced(){
|
||||||
|
// for byproducts
|
||||||
return totalRequired;
|
return totalRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,6 +49,9 @@ public class ProductionEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getInstances() {
|
public double getInstances() {
|
||||||
|
if (ignoreUpstream){
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
return instances;
|
return instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,11 @@ public class Recipe {
|
||||||
|
|
||||||
private double getByproductRate(Item main, Item product, double production) {
|
private double getByproductRate(Item main, Item product, double production) {
|
||||||
double runs = getRequiredProcessRuns(main, production);
|
double runs = getRequiredProcessRuns(main, production);
|
||||||
return product.getRecipe().outputs.get(product) * runs;
|
System.out.printf("BY-RATE: %s -> %s%n", main.getName(), product.getName());
|
||||||
|
if (!main.getRecipe().outputs.containsKey(product)){
|
||||||
|
return Double.NaN;
|
||||||
|
}
|
||||||
|
return main.getRecipe().outputs.get(product) * runs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SumResult sum(Item target, double prodPerMinute) {
|
public SumResult sum(Item target, double prodPerMinute) {
|
||||||
|
|
@ -192,6 +196,7 @@ public class Recipe {
|
||||||
production.addVertex(target);
|
production.addVertex(target);
|
||||||
production.addEdge(target, target, new ProductionEdge(target, target, prodPerMinute, processesNeeded(target, prodPerMinute)));
|
production.addEdge(target, target, new ProductionEdge(target, target, prodPerMinute, processesNeeded(target, prodPerMinute)));
|
||||||
Set<Item> visited = new HashSet<>(); // keep track of which items are already expanded fully into the graph
|
Set<Item> visited = new HashSet<>(); // keep track of which items are already expanded fully into the graph
|
||||||
|
Set<Item> by = new HashSet<>(); // keep track of which items are already expanded fully into the graph
|
||||||
while (!queue.isEmpty()) {
|
while (!queue.isEmpty()) {
|
||||||
Item item = queue.remove();
|
Item item = queue.remove();
|
||||||
if (!visited.contains(item)) {
|
if (!visited.contains(item)) {
|
||||||
|
|
@ -236,15 +241,22 @@ public class Recipe {
|
||||||
}
|
}
|
||||||
if (!byProducts.isEmpty()) {
|
if (!byProducts.isEmpty()) {
|
||||||
double finalSum = sum;
|
double finalSum = sum;
|
||||||
byProducts.forEach(item1 -> {
|
byProducts.forEach(byproduct -> {
|
||||||
production.addVertex(item1);
|
production.addVertex(byproduct);
|
||||||
// TODO: calculate produced amount
|
// TODO: calculate produced amount
|
||||||
double byproductRate = getByproductRate(item, item1, finalSum);
|
double byproductRate = getByproductRate(item, byproduct, finalSum);
|
||||||
production.addEdge(item, item1, new ProductionEdge(item, item1, byproductRate, processesNeeded(item, finalSum)));
|
production.addEdge(item, byproduct, new ProductionEdge(item, byproduct, byproductRate, processesNeeded(item, finalSum), true));
|
||||||
});
|
});
|
||||||
|
by.addAll(byProducts);
|
||||||
}
|
}
|
||||||
visited.add(item);
|
visited.add(item);
|
||||||
}
|
}
|
||||||
|
by.forEach(item -> {production.incomingEdgesOf(item).forEach(productionEdge -> {
|
||||||
|
Item source = productionEdge.getSource();
|
||||||
|
double sourceRate = map.get(source);
|
||||||
|
double byProductRate = getByproductRate(source, item, sourceRate);
|
||||||
|
map.put(item, byProductRate + map.getOrDefault(item,0.0));
|
||||||
|
});});
|
||||||
map.forEach((item, aDouble) -> System.out.println(item.getName() + ": " + aDouble));
|
map.forEach((item, aDouble) -> System.out.println(item.getName() + ": " + aDouble));
|
||||||
return new SumResult(production, map);
|
return new SumResult(production, map);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ public class SumResult {
|
||||||
.map(prod -> prod.getItem().getRecipe().sum(prod.getItem(), prod.getAmount()))
|
.map(prod -> prod.getItem().getRecipe().sum(prod.getItem(), prod.getAmount()))
|
||||||
.reduce(SumResult::merge).orElse(new SumResult());
|
.reduce(SumResult::merge).orElse(new SumResult());
|
||||||
}
|
}
|
||||||
|
public static SumResult sum(List<Production> productions) {
|
||||||
|
return productions.stream()
|
||||||
|
.map(prod -> prod.getItem().getRecipe().sum(prod.getItem(), prod.getAmount()))
|
||||||
|
.reduce(SumResult::merge).orElse(new SumResult());
|
||||||
|
}
|
||||||
|
|
||||||
public static Graph<Item, ProductionEdge> merge(Graph<Item, ProductionEdge> graph0, Graph<Item, ProductionEdge> graph1) {
|
public static Graph<Item, ProductionEdge> merge(Graph<Item, ProductionEdge> graph0, Graph<Item, ProductionEdge> graph1) {
|
||||||
// ToDo: test!
|
// ToDo: test!
|
||||||
|
|
@ -69,8 +74,7 @@ public class SumResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SumResult merge(SumResult other) {
|
public SumResult merge(SumResult other) {
|
||||||
HashMap<Item, Double> map = new HashMap<>();
|
HashMap<Item, Double> map = new HashMap<>(this.map);
|
||||||
map.putAll(this.map);
|
|
||||||
other.map.forEach((item, aDouble) -> map.merge(item, aDouble, Double::sum));
|
other.map.forEach((item, aDouble) -> map.merge(item, aDouble, Double::sum));
|
||||||
return new SumResult(merge(production, other.getProduction()), map);
|
return new SumResult(merge(production, other.getProduction()), map);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,4 +51,17 @@ class ItemTest {
|
||||||
fail();
|
fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void productionPlastic(){
|
||||||
|
test(Database.Plastic,"plastic");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void productionRubber(){
|
||||||
|
test(Database.Rubber,"rubber");
|
||||||
|
}
|
||||||
|
@Test
|
||||||
|
void productionRubberAndPlastic(){
|
||||||
|
test("rubberAndPlastic",Database.Rubber, Database.Plastic);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -3,23 +3,21 @@ package satisfactory.items;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import satisfactory.Database;
|
import satisfactory.Database;
|
||||||
|
|
||||||
import java.util.Map;
|
import static satisfactory.items.TestHelper.test;
|
||||||
|
|
||||||
import static satisfactory.items.TestHelper.*;
|
|
||||||
|
|
||||||
class Phase3Test {
|
class Phase3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ACU() {
|
void testPhase3_ACU() {
|
||||||
Item item = Database.AdaptiveControlUnit;
|
Item item = Database.AdaptiveControlUnit;
|
||||||
test(item);
|
test(item, "p3_acu");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ME() {
|
void testPhase3_ME() {
|
||||||
Item item = Database.ModularEngine;
|
Item item = Database.ModularEngine;
|
||||||
test(item);
|
test(item, "p3_me");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -31,70 +29,21 @@ class Phase3Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ME_ACU_VF() {
|
void testPhase3_ME_ACU_VF() {
|
||||||
// references
|
test(Database.ModularEngine, Database.AdaptiveControlUnit, Database.VersatileFrameWork);
|
||||||
Map<Item, Double> ref = merge(
|
|
||||||
ValidatedValues.get(Database.ModularEngine),
|
|
||||||
ValidatedValues.get(Database.AdaptiveControlUnit),
|
|
||||||
ValidatedValues.get(Database.VersatileFrameWork));
|
|
||||||
ref.forEach((item, aDouble) -> System.out.println(aDouble + "\t" + item.getName()));
|
|
||||||
|
|
||||||
// calculate
|
|
||||||
Map<Item, Double> calculations = SumResult.sum(
|
|
||||||
new Production(Database.ModularEngine, 1),
|
|
||||||
new Production(Database.AdaptiveControlUnit, 1),
|
|
||||||
new Production(Database.VersatileFrameWork, 1)
|
|
||||||
).getMap();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assertMap(ref, calculations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ME_ACU() {
|
void testPhase3_ME_ACU() {
|
||||||
// references
|
test(Database.ModularEngine, Database.AdaptiveControlUnit);
|
||||||
Map<Item, Double> ref1 = merge(
|
|
||||||
ValidatedValues.get(Database.ModularEngine),
|
|
||||||
ValidatedValues.get(Database.AdaptiveControlUnit)
|
|
||||||
);
|
|
||||||
|
|
||||||
// calculate
|
|
||||||
Map<Item, Double> calculations1 = SumResult.sum(
|
|
||||||
new Production(Database.ModularEngine, 1),
|
|
||||||
new Production(Database.AdaptiveControlUnit, 1)
|
|
||||||
).getMap();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assertMap(ref1, calculations1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ACU_VF() {
|
void testPhase3_ACU_VF() {
|
||||||
// references
|
test(Database.AdaptiveControlUnit, Database.VersatileFrameWork);
|
||||||
Map<Item, Double> ref1 = merge(
|
|
||||||
ValidatedValues.get(Database.AdaptiveControlUnit),
|
|
||||||
ValidatedValues.get(Database.VersatileFrameWork));
|
|
||||||
|
|
||||||
// calculate
|
|
||||||
Map<Item, Double> calculations1 = SumResult.sum(
|
|
||||||
new Production(Database.AdaptiveControlUnit, 1),
|
|
||||||
new Production(Database.VersatileFrameWork, 1)
|
|
||||||
).getMap();
|
|
||||||
|
|
||||||
// assert
|
|
||||||
assertMap(ref1, calculations1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testPhase3_ME_VF() {
|
void testPhase3_ME_VF() {
|
||||||
// references
|
test(Database.ModularEngine, Database.VersatileFrameWork);
|
||||||
Map<Item, Double> ref1 = merge(
|
|
||||||
ValidatedValues.get(Database.ModularEngine),
|
|
||||||
ValidatedValues.get(Database.VersatileFrameWork));
|
|
||||||
|
|
||||||
// calculate
|
|
||||||
Map<Item, Double> calculations1 = SumResult.sum(
|
|
||||||
new Production(Database.ModularEngine, 1),
|
|
||||||
new Production(Database.VersatileFrameWork, 1)
|
|
||||||
).getMap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,9 @@ package satisfactory.items;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -38,12 +40,37 @@ public class TestHelper {
|
||||||
assertMap(ref, calculations.getMap());
|
assertMap(ref, calculations.getMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void test(String name, Item... items) {
|
||||||
|
|
||||||
|
// references
|
||||||
|
Map<Item, Double> ref1 = merge(Arrays.stream(items).map(ValidatedValues::get).toList());
|
||||||
|
|
||||||
|
// calculate
|
||||||
|
SumResult sumResult = SumResult.sum(Arrays.stream(items).map(item -> new Production(item, 1.0)).toList());
|
||||||
|
Map<Item, Double> calculations = sumResult.getMap();
|
||||||
|
|
||||||
|
// plot
|
||||||
|
if (name != null) {
|
||||||
|
name = "test_" + name;
|
||||||
|
plot2(sumResult.getProduction(), name);
|
||||||
|
javaPlot(name);
|
||||||
|
list(sumResult, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert
|
||||||
|
assertMap(ref1, calculations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void test(Item... items) {
|
||||||
|
test(null, items);
|
||||||
|
}
|
||||||
|
|
||||||
private static SumResult calculate(Item item) {
|
private static SumResult calculate(Item item) {
|
||||||
// calculate
|
// calculate
|
||||||
return SumResult.sum(new Production(item, 1));
|
return SumResult.sum(new Production(item, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <K> Map<K, Double> merge(Map<K, Double>... single_refs) {
|
public static <K> Map<K, Double> merge(List<Map<K, Double>> single_refs) {
|
||||||
Map<K, Double> ref = new HashMap<>();
|
Map<K, Double> ref = new HashMap<>();
|
||||||
for (Map<K, Double> singleRef : single_refs) {
|
for (Map<K, Double> singleRef : single_refs) {
|
||||||
singleRef.forEach((singleItem, singleValue) -> ref.compute(singleItem, (refItem, refValue) -> singleValue + check(refValue)));
|
singleRef.forEach((singleItem, singleValue) -> ref.compute(singleItem, (refItem, refValue) -> singleValue + check(refValue)));
|
||||||
|
|
@ -77,7 +104,7 @@ public class TestHelper {
|
||||||
//c.put("b", 4.0);
|
//c.put("b", 4.0);
|
||||||
e.put("b", 3.);
|
e.put("b", 3.);
|
||||||
}
|
}
|
||||||
Map<String, Double> m = merge(a, b, c);
|
Map<String, Double> m = merge(Arrays.asList(a, b, c));
|
||||||
e.forEach((s, aDouble) -> {
|
e.forEach((s, aDouble) -> {
|
||||||
assertEquals(aDouble, m.get(s));
|
assertEquals(aDouble, m.get(s));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,22 @@ public class ValidatedValues {
|
||||||
ref.put(item, 1.);
|
ref.put(item, 1.);
|
||||||
values.put(item, ref);
|
values.put(item, ref);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
Item item = Database.Plastic;
|
||||||
|
Map<Item, Double> ref = new HashMap<>();
|
||||||
|
ref.put(Database.CrudeOil, 1.5);
|
||||||
|
ref.put(Database.Plastic, 1.);
|
||||||
|
ref.put(Database.HeavyOilResidue, 0.5);
|
||||||
|
values.put(item, ref);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Item item = Database.Rubber;
|
||||||
|
Map<Item, Double> ref = new HashMap<>();
|
||||||
|
ref.put(Database.CrudeOil, 1.5);
|
||||||
|
ref.put(Database.HeavyOilResidue, 1.);
|
||||||
|
ref.put(item, 1.);
|
||||||
|
values.put(item, ref);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Item, Double> get(Item item) {
|
public static Map<Item, Double> get(Item item) {
|
||||||
|
|
@ -113,7 +129,7 @@ public class ValidatedValues {
|
||||||
ref.put(Database.CopperIngot, 249.0);
|
ref.put(Database.CopperIngot, 249.0);
|
||||||
ref.put(Database.IronRod, 90.5);
|
ref.put(Database.IronRod, 90.5);
|
||||||
ref.put(Database.IronIngot, 158.0);
|
ref.put(Database.IronIngot, 158.0);
|
||||||
//ref.put(Database.HeavyOilResidue, 39.0); // FIXME byproduct
|
ref.put(Database.HeavyOilResidue, 39.0); // FIXME byproduct
|
||||||
ref.put(Database.CopperSheet, 30.0);
|
ref.put(Database.CopperSheet, 30.0);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +156,7 @@ public class ValidatedValues {
|
||||||
ref.put(Database.SmartPlating, 2.0);
|
ref.put(Database.SmartPlating, 2.0);
|
||||||
ref.put(Database.ReinforcedIronPlate, 2.0);
|
ref.put(Database.ReinforcedIronPlate, 2.0);
|
||||||
ref.put(Database.Rubber, 15.0);
|
ref.put(Database.Rubber, 15.0);
|
||||||
//ref.put(Database.HeavyOilResidue, 15.0); // FIXME byproduct
|
ref.put(Database.HeavyOilResidue, 15.0); // FIXME byproduct
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue