Compare commits

...

2 Commits

Author SHA1 Message Date
clemens ea30ec2b6b reformat & code cleanup 2022-07-05 15:23:05 +02:00
clemens 6bb38066d6 add test helper 2022-07-05 15:15:58 +02:00
22 changed files with 285 additions and 284 deletions

View File

@ -10,13 +10,13 @@ repositories {
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.2'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.3'
implementation 'org.jgrapht:jgrapht-io:1.5.1'
implementation 'guru.nidi:graphviz-java:0.18.1'
implementation 'org.graalvm.js:js:20.0.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.0'
implementation 'org.graalvm.js:js:22.1.0.1'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.2'
}
test {

View File

@ -140,7 +140,7 @@ public class Database {
Water.setPreference(water);
// gases
NitrogenGas.add(new Recipe(1,"pressure thingy", false, ResourceWellExtractor.class));
NitrogenGas.add(new Recipe(1, "pressure thingy", false, ResourceWellExtractor.class));
}
{
// Steel Ingot
@ -496,72 +496,72 @@ public class Database {
}
{
Recipe recipe = new Recipe(6, Refinery.class);
recipe.addInput(Sulfur,5);
recipe.addInput(Water,5);
recipe.addInput(Sulfur, 5);
recipe.addInput(Water, 5);
recipe.addOutput(SulfuricAcid, 5);
}
{
Recipe recipe = new Recipe(150,Manufacturer.class);
Recipe recipe = new Recipe(150, Manufacturer.class);
recipe.addInput(EncasedUraniumCell, 50);
recipe.addInput(EncasedIndustrialBeam,3);
recipe.addInput(EncasedIndustrialBeam, 3);
recipe.addInput(ElectromagneticControlRod, 5);
recipe.addOutput(UraniumFuelRod,1);
recipe.addOutput(UraniumFuelRod, 1);
}
{
Recipe recipe = new Recipe(12, Blender.class);
recipe.addInput(Uranium, 10);
recipe.addInput(Concrete,3);
recipe.addInput(Concrete, 3);
recipe.addInput(SulfuricAcid, 8);
recipe.addOutput(EncasedUraniumCell, 5);
recipe.addOutput(SulfuricAcid, 2);
}
{
Recipe recipe = new Recipe(120,Manufacturer.class);
recipe.addInput(VersatileFrameWork,5);
Recipe recipe = new Recipe(120, Manufacturer.class);
recipe.addInput(VersatileFrameWork, 5);
recipe.addInput(ElectromagneticControlRod, 5);
recipe.addInput(Battery, 10);
recipe.addOutput(MagneticFieldGenerator,2);
recipe.addOutput(MagneticFieldGenerator, 2);
}
{
Recipe recipe = new Recipe(3, Blender.class);
recipe.addInput(SulfuricAcid,2.5);
recipe.addInput(AluminaSolution,2);
recipe.addInput(AluminumCasing,1);
recipe.addInput(SulfuricAcid, 2.5);
recipe.addInput(AluminaSolution, 2);
recipe.addInput(AluminumCasing, 1);
recipe.addOutput(Battery, 1);
recipe.addOutput(Water, 1.5);
}
{
Recipe recipe = new Recipe(8, Assembler.class);
recipe.addInput(AlcladAluminumSheet,5);
recipe.addInput(CopperSheet,3);
recipe.addInput(AlcladAluminumSheet, 5);
recipe.addInput(CopperSheet, 3);
recipe.addOutput(HeatSink, 1);
}
{
Recipe recipe = new Recipe(80, Assembler.class);
recipe.addInput(AdaptiveControlUnit,2);
recipe.addInput(SuperComputer,1);
recipe.addOutput(AssemblyDirectorSystem,1);
recipe.addInput(AdaptiveControlUnit, 2);
recipe.addInput(SuperComputer, 1);
recipe.addOutput(AssemblyDirectorSystem, 1);
}
{
Recipe recipe = new Recipe(30,Assembler.class);
recipe.addInput(Stator,3);
recipe.addInput(AILimiter,2);
recipe.addOutput(ElectromagneticControlRod,2);
Recipe recipe = new Recipe(30, Assembler.class);
recipe.addInput(Stator, 3);
recipe.addInput(AILimiter, 2);
recipe.addOutput(ElectromagneticControlRod, 2);
}
{
Recipe recipe = new Recipe(10, Blender.class);
recipe.addInput(HeatSink,2);
recipe.addInput(Rubber,2);
recipe.addInput(Water,5);
recipe.addInput(NitrogenGas,25);
recipe.addOutput(CoolingSystem,1);
recipe.addInput(HeatSink, 2);
recipe.addInput(Rubber, 2);
recipe.addInput(Water, 5);
recipe.addInput(NitrogenGas, 25);
recipe.addOutput(CoolingSystem, 1);
}
{
Recipe recipe = new Recipe(40, Blender.class);
recipe.addInput(HeavyModularFrame,1);
recipe.addInput(AluminumCasing,50);
recipe.addInput(NitrogenGas,25);
recipe.addOutput(FusedModularFrame,1);
recipe.addInput(HeavyModularFrame, 1);
recipe.addInput(AluminumCasing, 50);
recipe.addInput(NitrogenGas, 25);
recipe.addOutput(FusedModularFrame, 1);
}
}

View File

@ -3,8 +3,6 @@ package satisfactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import guru.nidi.graphviz.engine.Format;
import guru.nidi.graphviz.engine.Graphviz;
import guru.nidi.graphviz.engine.GraphvizCmdLineEngine;
import guru.nidi.graphviz.engine.GraphvizJdkEngine;
import guru.nidi.graphviz.model.MutableGraph;
import guru.nidi.graphviz.parse.Parser;
import org.jgrapht.Graph;
@ -141,9 +139,7 @@ public class Test {
});
de.exportGraph(screws, new File(PLOTS + name + ".dot"));
System.out.println(name);
Item.production(screws).forEach((item, rate) -> {
System.out.println("\t" + item.getName() + "\t" + rate);
});
Item.production(screws).forEach((item, rate) -> System.out.println("\t" + item.getName() + "\t" + rate));
}
private static void javaPlot(String name) {

View File

@ -5,7 +5,6 @@ import org.jgrapht.event.ConnectedComponentTraversalEvent;
import org.jgrapht.event.EdgeTraversalEvent;
import org.jgrapht.event.TraversalListener;
import org.jgrapht.event.VertexTraversalEvent;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.EdgeReversedGraph;
import org.jgrapht.nio.Attribute;
@ -15,11 +14,9 @@ import org.jgrapht.traverse.DepthFirstIterator;
import org.jgrapht.traverse.GraphIterator;
import satisfactory.items.Item;
import satisfactory.items.ProductionEdge;
import satisfactory.items.SumResult;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@ -29,7 +26,7 @@ public class Utils {
public static Map<Item, Integer> getRawOnly(Map<Item, Integer> totals) {
Map<Item, Integer> raws = new HashMap<>();
for (Item item : totals.keySet().stream().filter(Item::isRaw).collect(Collectors.toList())) {
for (Item item : totals.keySet().stream().filter(Item::isRaw).toList()) {
raws.put(item, totals.get(item));
}
return raws;
@ -52,7 +49,7 @@ public class Utils {
EdgeReversedGraph<Item, DefaultWeightedEdge> inverse = new EdgeReversedGraph<>(graph);
GraphIterator<Item, DefaultWeightedEdge> iterator = new DepthFirstIterator<>(inverse, target);
iterator.addTraversalListener(new TraversalListener<Item, DefaultWeightedEdge>() {
iterator.addTraversalListener(new TraversalListener<>() {
@Override
public void connectedComponentFinished(ConnectedComponentTraversalEvent e) {
System.out.println("\tconnectedComponentFinished: " + e);
@ -105,7 +102,7 @@ public class Utils {
m.put("label", DefaultAttribute.createAttribute(label));
return m;
});
de.exportGraph(sum, new File(PLOTS +filename + ".dot"));
de.exportGraph(sum, new File(PLOTS + filename + ".dot"));
}
}

View File

@ -9,8 +9,8 @@ import java.util.*;
public abstract class Item {
protected boolean isRaw = false;
private String name;
private Set<Recipe> recipes;
private final String name;
private final Set<Recipe> recipes;
private Recipe preference = null;
public int sum = 0;

View File

@ -5,7 +5,6 @@ import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;
import satisfactory.buildings.Building;
import satisfactory.buildings.production.Assembler;
import satisfactory.items.requirements.RateAccumulator;
import satisfactory.items.requirements.TotalAccumulator;
@ -124,18 +123,19 @@ public class Recipe {
return inputs;
}
public Map<Item,Double> getByProducts(Item reference){
if (!outputs.containsKey(reference)){
public Map<Item, Double> getByProducts(Item reference) {
if (!outputs.containsKey(reference)) {
return null;
}
return outputs.entrySet().stream().filter(itemIntegerEntry -> isByProduct(reference, itemIntegerEntry.getKey())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
public boolean isByProduct(Item reference, Item test){
public boolean isByProduct(Item reference, Item test) {
return !reference.equals(test) && outputs.containsKey(reference) && outputs.containsKey(test);
}
public Graph<Item, DefaultWeightedEdge> buildGraph(Item target) {
System.out.println("buildGraph(" + target.getName() + ") @ "+ name);
System.out.println("buildGraph(" + target.getName() + ") @ " + name);
Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex(target);
target.sum += 1;
@ -171,7 +171,7 @@ public class Recipe {
return productWantedPerMinute / productPerProcess;
}
private double getByproductRate(Item main, Item product, double production){
private double getByproductRate(Item main, Item product, double production) {
double runs = getRequiredProcessRuns(main, production);
return product.getRecipe().outputs.get(product) * runs;
}
@ -182,14 +182,14 @@ public class Recipe {
Map<Item, Double> map = new HashMap<>();
Queue<Item> queue = new LinkedList<>();
queue.add(target);
map.put(target, (double) prodPerMinute);
map.put(target, prodPerMinute);
production.addVertex(target);
production.addEdge(target, target, new ProductionEdge(target, target, prodPerMinute, processesNeeded(target, prodPerMinute)));
Set<Item> visited = new HashSet<>();
while (!queue.isEmpty()) {
Item item = queue.remove();
if (visited.contains(item)){
System.out.println("hint: already processed " + item.getName()+ "! Skip!");
if (visited.contains(item)) {
System.out.println("hint: already processed " + item.getName() + "! Skip!");
//continue;
} else {
// next items
@ -207,7 +207,7 @@ public class Recipe {
System.out.println(item.getName());
if (item.getRecipe().outputs.containsKey(product)) { // TODO: method isByProduct
// product is by-product, no forward dependency
System.out.println("BY-PRODUCT " + item.getName() + " -> " + product.getName() + "... "+ queue);
System.out.println("BY-PRODUCT " + item.getName() + " -> " + product.getName() + "... " + queue);
byProducts.add(product);
continue;
}
@ -237,9 +237,7 @@ public class Recipe {
}
visited.add(item);
}
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);
}

View File

@ -31,10 +31,10 @@ public class SumResult {
return map;
}
public SumResult merge(SumResult other){
public SumResult merge(SumResult other) {
HashMap<Item, Double> map = new HashMap<>();
this.map.forEach(map::put);
other.map.forEach((item, aDouble) -> map.merge(item,aDouble,Double::sum));
map.putAll(this.map);
other.map.forEach((item, aDouble) -> map.merge(item, aDouble, Double::sum));
return new SumResult(merge(production, other.getProduction()), map);
}
@ -58,8 +58,7 @@ public class SumResult {
graph1.vertexSet().forEach(result::addVertex);
graph1.edgeSet().forEach(productionEdge -> {
List<ProductionEdge> collect = result.edgeSet().stream()
.filter(productionEdge1 -> productionEdge1.hasSource(productionEdge.getSource()))
.collect(Collectors.toList());
.filter(productionEdge1 -> productionEdge1.hasSource(productionEdge.getSource())).toList();
collect.forEach(edge -> {
Item src = result.getEdgeSource(edge);
Item target = result.getEdgeTarget(edge);

View File

@ -6,7 +6,7 @@ import satisfactory.items.Recipe;
import java.util.HashMap;
import java.util.Map;
public abstract class Accumulator<E extends Number> implements RequirementAccumulator<E>{
public abstract class Accumulator<E extends Number> implements RequirementAccumulator<E> {
protected Map<Item, E> inputs;
public Accumulator(Map<Item, E> inputs) {
@ -28,7 +28,7 @@ public abstract class Accumulator<E extends Number> implements RequirementAccumu
Item i = queue.keySet().iterator().next();
E amount = queue.remove(i);
E newTotal = dequeue(i, amount, total);
total.put(i,newTotal);
total.put(i, newTotal);
if (i.getRecipes().isEmpty()) {
continue;
}
@ -43,6 +43,6 @@ public abstract class Accumulator<E extends Number> implements RequirementAccumu
return total;
}
protected abstract Map<Item,E> getRequirements(Recipe r, Item i);// r.getTotalRequirements()
protected abstract Map<Item, E> getRequirements(Recipe r, Item i);// r.getTotalRequirements()
}

View File

@ -7,11 +7,11 @@ import java.util.HashMap;
import java.util.Map;
public class RateAccumulator extends Accumulator<Double> {
private Item item;
private final Item item;
public RateAccumulator(Recipe recipe, Item item) {
super(new HashMap<>());
recipe.getInputs().forEach((item1, integer) -> inputs.put(item1, integer));
inputs.putAll(recipe.getInputs());
this.item = item;
}

View File

@ -5,7 +5,7 @@ import satisfactory.items.Recipe;
import java.util.Map;
public class TotalAccumulator extends Accumulator<Double>{
public class TotalAccumulator extends Accumulator<Double> {
public TotalAccumulator(Map<Item, Double> inputs) {
super(inputs);

View File

@ -2,6 +2,7 @@ package satisfactory.items;
import org.junit.jupiter.api.Test;
import satisfactory.Database;
import static org.junit.jupiter.api.Assertions.*;
public class DatabaseTest {
@ -9,7 +10,7 @@ public class DatabaseTest {
void testWaterPreference() {
Item i = Database.Water;
assertSame(i.getPreference(), i.getRecipe());
assertTrue(i.getPreference() == i.getRecipe());
assertSame(i.getPreference(), i.getRecipe());
assertTrue(i.getRecipe().toString().contains("water pump thingy"));
}
}

View File

@ -1,11 +1,10 @@
package satisfactory.items;
import org.jgrapht.Graph;
import org.junit.jupiter.api.Test;
import satisfactory.Database;
import satisfactory.Utils;
import java.util.HashMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@ -14,36 +13,28 @@ class ItemTest {
@Test
void productionScrews() {
/*Map<Item, Double> production = Database.Screw.production(100);
assertEquals(100, production.get(Database.Screw), "Screws (output)");
assertEquals(25, production.get(Database.IronRod), "IronRod");
assertEquals(25, production.get(Database.IronIngot), "IronIngot");
assertEquals(25, production.get(Database.IronOre), "IronOre");*/
fail();
}
@Test
void productionScrews2() {
/*Map<Item, Double> production = Database.Screw.getRecipe().sum(Database.Screw, 100);
assertEquals(100, production.get(Database.Screw), "Screws (output)");
assertEquals(25, production.get(Database.IronRod), "IronRod");
assertEquals(25, production.get(Database.IronIngot), "IronIngot");
assertEquals(25, production.get(Database.IronOre), "IronOre");
*/
fail("TODO: migrate");
Collection<Ref> ref = Arrays.asList(
new Ref(Database.Screw, 100.0),
new Ref(Database.IronRod, 25.0),
new Ref(Database.IronIngot, 25.0),
new Ref(Database.IronOre, 25.0)
);
SumResult sum = SumResult.sum(new Production(Database.Screw, 100.0));
compareProductions(sum, ref);
}
@Test
void productionReinforcedIronPlates() {
/*Map<Item, Double> production = Database.ReinforcedIronPlate.production(100);
assertEquals(100, production.get(Database.ReinforcedIronPlate), "output");
assertEquals(1200, production.get(Database.Screw), "Screws");
assertEquals(300, production.get(Database.IronRod), "IronRod");
assertEquals(1200, production.get(Database.IronIngot), "IronIngot");
assertEquals(1200, production.get(Database.IronOre), "IronOre");
assertEquals(600, production.get(Database.IronPlate), "IronPlate");*/
fail();
Collection<Ref> ref = Arrays.asList(
new Ref(Database.ReinforcedIronPlate, 100.0, "output"),
new Ref(Database.Screw, 1200.0),
new Ref(Database.IronRod, 300.0),
new Ref(Database.IronIngot, 1200.0),
new Ref(Database.IronOre, 1200.0),
new Ref(Database.IronPlate, 600.0)
);
SumResult sum = SumResult.sum(new Production(Database.ReinforcedIronPlate, 100.0));
compareProductions(sum, ref);
}
@Test
@ -55,65 +46,84 @@ class ItemTest {
@Test
void testPhase3_ME_ACU() {
// references
Map<Item, Double> ref = new HashMap<>();
ref.put(Database.CircuitBoard, 15.0);
ref.put(Database.Computer, 1.0);
ref.put(Database.Limestone,75.0);
ref.put(Database.Concrete,25.0);
ref.put(Database.SteelBeam,20.0);
ref.put(Database.EncasedIndustrialBeam, 5.0);
ref.put(Database.ModularFrame,5.0);
ref.put(Database.HeavyModularFrame,1.0);
ref.put(Database.Plastic, 78.0);
ref.put(Database.CopperSheet, 30.0);
ref.put(Database.Coal,226.25);
ref.put(Database.Cable,159.0);
ref.put(Database.CopperOre,329.0);
ref.put(Database.AutomatedWiring, 7.5);
ref.put(Database.AdaptiveControlUnit, 1.0);
ref.put(Database.CrudeOil, 229.5);
ref.put(Database.ReinforcedIronPlate, 17.5);
ref.put(Database.CopperIngot, 329.0);
ref.put(Database.SteelIngot, 226.25);
ref.put(Database.IronPlate, 105.0);
ref.put(Database.SmartPlating, 10.0);
//ref.put(Database.HeavyOilResidue, 114.0); // TODO: implement calculation
ref.put(Database.Rubber, 75.0);
ref.put(Database.Wire, 538.0);
ref.put(Database.SteelPipe, 97.5);
ref.put(Database.Stator, 27.5);
ref.put(Database.Screw, 1112.0);
ref.put(Database.IronOre, 841.75);
ref.put(Database.IronIngot, 615.5);
ref.put(Database.IronRod, 458.0);
ref.put(Database.Rotor, 30.0);
ref.put(Database.Motor, 10.0);
ref.put(Database.ModularEngine, 5.0);
Collection<Ref> ref = Arrays.asList(
new Ref(Database.CircuitBoard, 15.0),
new Ref(Database.Computer, 1.0),
new Ref(Database.Limestone, 75.0),
new Ref(Database.Concrete, 25.0),
new Ref(Database.SteelBeam, 20.0),
new Ref(Database.EncasedIndustrialBeam, 5.0),
new Ref(Database.ModularFrame, 5.0),
new Ref(Database.HeavyModularFrame, 1.0),
new Ref(Database.Plastic, 78.0),
new Ref(Database.CopperSheet, 30.0),
new Ref(Database.Coal, 226.25),
new Ref(Database.Cable, 159.0),
new Ref(Database.CopperOre, 329.0),
new Ref(Database.AutomatedWiring, 7.5),
new Ref(Database.AdaptiveControlUnit, 1.0),
new Ref(Database.CrudeOil, 229.5),
new Ref(Database.ReinforcedIronPlate, 17.5),
new Ref(Database.CopperIngot, 329.0),
new Ref(Database.SteelIngot, 226.25),
new Ref(Database.IronPlate, 105.0),
new Ref(Database.SmartPlating, 10.0),
//new Ref(Database.HeavyOilResidue, 114.0), // TODO: implement calculation
new Ref(Database.Rubber, 75.0),
new Ref(Database.Wire, 538.0),
new Ref(Database.SteelPipe, 97.5),
new Ref(Database.Stator, 27.5),
new Ref(Database.Screw, 1112.0),
new Ref(Database.IronOre, 841.75),
new Ref(Database.IronIngot, 615.5),
new Ref(Database.IronRod, 458.0),
new Ref(Database.Rotor, 30.0),
new Ref(Database.Motor, 10.0),
new Ref(Database.ModularEngine, 5.0)
);
// calculate
Map<Item, Double> calculations = SumResult.sum(new Production(Database.ModularEngine, 5), new Production(Database.AdaptiveControlUnit, 1)).getMap();
SumResult sum = SumResult.sum(new Production(Database.ModularEngine, 5), new Production(Database.AdaptiveControlUnit, 1));
// assert
ref.forEach((item, amount) -> {
assertTrue(calculations.containsKey(item), "exists? " + item.getName());
assertEquals(amount, calculations.get(item), 0.01, item.getName());
});
compareProductions(sum, ref);
fail("Something heavy oil residue");
}
@Test
void uraniumFuelRodWithSteelIngotParents(){
Map<Item, Double> ref = new HashMap<>();
ref.put(Database.SteelIngot, 81.75);
ref.put(Database.IronOre, 81.75);
ref.put(Database.Coal, 81.75);
compareProductions(Database.UraniumFuelRod, 1, ref);
void uraniumFuelRodWithSteelIngotParents() {
Collection<Ref> refs = Arrays.asList(
new Ref(Database.SteelIngot, 81.75),
new Ref(Database.IronOre, 81.75),
new Ref(Database.Coal, 81.75)
);
SumResult sums = SumResult.sum(new Production(Database.UraniumFuelRod, 1.0));
compareProductions(sums, refs);
}
private void compareProductions(Item targetItem, int amount, Map<Item, Double> ref) {
Map<Item, Double> sum = SumResult.sum(new Production(targetItem, amount)).getMap();
ref.forEach((item, aDouble) -> {
assertTrue(sum.containsKey(item));
assertEquals(aDouble, sum.get(item));
private void compareProductions(SumResult sum, Collection<Ref> references) {
Map<Item, Double> inputs = sum.getMap();
references.forEach(ref -> {
assertTrue(inputs.containsKey(ref.item), ref.note);
assertEquals(ref.amount, inputs.get(ref.item), ref.note);
});
}
}
class Ref {
Item item;
double amount;
String note;
public Ref(Item item, double amount, String note) {
this.item = item;
this.amount = amount;
this.note = note;
}
public Ref(Item item, double amount) {
this.item = item;
this.amount = amount;
note = item.getName();
}
}