Compare commits

..

No commits in common. "ea30ec2b6bf4c91962669cfe527d8f953faaa6a5" and "261ab9c4f4d6ee7e34078c455af5e593be59e3ea" have entirely different histories.

22 changed files with 284 additions and 285 deletions

View File

@ -10,13 +10,13 @@ repositories {
}
dependencies {
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'
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'
implementation 'org.jgrapht:jgrapht-io:1.5.1'
implementation 'guru.nidi:graphviz-java:0.18.1'
implementation 'org.graalvm.js:js:22.1.0.1'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.17.2'
implementation 'org.graalvm.js:js:20.0.0'
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.0'
}
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,6 +3,8 @@ 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;
@ -139,7 +141,9 @@ 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,6 +5,7 @@ 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;
@ -14,9 +15,11 @@ 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;
@ -26,7 +29,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).toList()) {
for (Item item : totals.keySet().stream().filter(Item::isRaw).collect(Collectors.toList())) {
raws.put(item, totals.get(item));
}
return raws;
@ -49,7 +52,7 @@ public class Utils {
EdgeReversedGraph<Item, DefaultWeightedEdge> inverse = new EdgeReversedGraph<>(graph);
GraphIterator<Item, DefaultWeightedEdge> iterator = new DepthFirstIterator<>(inverse, target);
iterator.addTraversalListener(new TraversalListener<>() {
iterator.addTraversalListener(new TraversalListener<Item, DefaultWeightedEdge>() {
@Override
public void connectedComponentFinished(ConnectedComponentTraversalEvent e) {
System.out.println("\tconnectedComponentFinished: " + e);
@ -102,7 +105,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 final String name;
private final Set<Recipe> recipes;
private String name;
private Set<Recipe> recipes;
private Recipe preference = null;
public int sum = 0;

View File

@ -5,6 +5,7 @@ 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;
@ -123,19 +124,18 @@ 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, prodPerMinute);
map.put(target, (double) 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,7 +237,9 @@ 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<>();
map.putAll(this.map);
other.map.forEach((item, aDouble) -> map.merge(item, aDouble, Double::sum));
this.map.forEach(map::put);
other.map.forEach((item, aDouble) -> map.merge(item,aDouble,Double::sum));
return new SumResult(merge(production, other.getProduction()), map);
}
@ -58,7 +58,8 @@ public class SumResult {
graph1.vertexSet().forEach(result::addVertex);
graph1.edgeSet().forEach(productionEdge -> {
List<ProductionEdge> collect = result.edgeSet().stream()
.filter(productionEdge1 -> productionEdge1.hasSource(productionEdge.getSource())).toList();
.filter(productionEdge1 -> productionEdge1.hasSource(productionEdge.getSource()))
.collect(Collectors.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 final Item item;
private Item item;
public RateAccumulator(Recipe recipe, Item item) {
super(new HashMap<>());
inputs.putAll(recipe.getInputs());
recipe.getInputs().forEach((item1, integer) -> inputs.put(item1, integer));
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,7 +2,6 @@ package satisfactory.items;
import org.junit.jupiter.api.Test;
import satisfactory.Database;
import static org.junit.jupiter.api.Assertions.*;
public class DatabaseTest {
@ -10,7 +9,7 @@ public class DatabaseTest {
void testWaterPreference() {
Item i = Database.Water;
assertSame(i.getPreference(), i.getRecipe());
assertSame(i.getPreference(), i.getRecipe());
assertTrue(i.getPreference() == i.getRecipe());
assertTrue(i.getRecipe().toString().contains("water pump thingy"));
}
}

View File

@ -1,10 +1,11 @@
package satisfactory.items;
import org.jgrapht.Graph;
import org.junit.jupiter.api.Test;
import satisfactory.Database;
import satisfactory.Utils;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@ -13,28 +14,36 @@ class ItemTest {
@Test
void productionScrews() {
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);
/*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");
}
@Test
void productionReinforcedIronPlates() {
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);
/*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();
}
@Test
@ -46,84 +55,65 @@ class ItemTest {
@Test
void testPhase3_ME_ACU() {
// references
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)
);
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);
// calculate
SumResult sum = SumResult.sum(new Production(Database.ModularEngine, 5), new Production(Database.AdaptiveControlUnit, 1));
Map<Item, Double> calculations = SumResult.sum(new Production(Database.ModularEngine, 5), new Production(Database.AdaptiveControlUnit, 1)).getMap();
// assert
compareProductions(sum, ref);
fail("Something heavy oil residue");
ref.forEach((item, amount) -> {
assertTrue(calculations.containsKey(item), "exists? " + item.getName());
assertEquals(amount, calculations.get(item), 0.01, item.getName());
});
}
@Test
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);
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);
}
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);
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));
});
}
}
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();
}
}