fix gradle structure, add aluminium stuff. Cycles still broken!

master
agp8x 2021-07-19 15:21:10 +02:00
parent b0f49eb814
commit 5d57f9dd1d
42 changed files with 258 additions and 222 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
out/
build/
.gradle/
plots/

View File

@ -1,27 +1,22 @@
plugins {
id 'java'
}
group 'de.clkl.satisfactory'
version '1.0-snapshot'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
sourceSets {
main {
java {
srcDirs = ['src']
}
}
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-core:2.12.2'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.2'
implementation 'org.jgrapht:jgrapht-io:1.5.1'
}
test {
useJUnitPlatform()
}
dependencies{
implementation 'org.junit.jupiter:junit-jupiter:5.7.0'
compile 'com.fasterxml.jackson.core:jackson-core:2.12.2'
compile 'com.fasterxml.jackson.core:jackson-databind:2.12.2'
compile 'org.jgrapht:jgrapht-io:1.5.1'
}

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

0
plots/.gitkeep Normal file
View File

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="satisfactory" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4" />

2
settings.gradle Normal file
View File

@ -0,0 +1,2 @@
rootProject.name = 'satisfactory'

View File

@ -7,8 +7,8 @@ import satisfactory.items.type.*;
import java.util.*;
public class Database {
private static final Collection<Item> items = new HashSet<>();
public static final Map<Item, Recipe> preferences = new HashMap<>();
private static final Collection<Item> items = new HashSet<>();
public static final Map<Item, Recipe> preferences = new HashMap<>();
// Items & recipes
public static final Item IronOre = new Ore("Iron Ore");
@ -78,10 +78,23 @@ public class Database {
public static final Item LiquidBiofuel = new ProcessedFluid("Liquid Biofuel");
public static final Item PetroleumCoke = new Part("Petroleum Coke");
public static final Item PolymerResin = new Part("Polymer Resin");
// TODO: verify below!
public static final Item AluminumIngot = new Part("Aluminum Ingot");
public static final Item AlcladAluminumSheet = new Part("Alclad Aluminum Sheet");
public static final Item AluminumCasing = new Part("Aluminum Casing");
public static final Item RawQuartz = new Ore("Raw Quartz");
public static final Item QuartzCristal = new Part("Quartz Cristal");
public static final Item CrystalOscillator = new Part("Crystal Oscillator");
public static final Item RadioControlUnit = new Part("Radio Control Unit");
public static final Item AluminumScrap = new Part("Aluminum Scrap");
public static final Item Silica = new Part("Silica");
public static final Item Bauxite = new Ore("Bauxite");
public static final Item AluminaSolution = new ProcessedFluid("Alumina Solution");
static {
{
Set<Item> ores = new HashSet<>(Arrays.asList(IronOre, Coal, Limestone, CopperOre, CateriumOre, Sulfur));
ores.addAll(Arrays.asList(Bauxite, RawQuartz));// TODO: rly?
for (Item ore : ores) {
Recipe mk1 = new Recipe(1, "Miner MK 1", false);
ore.add(mk1, 1);
@ -93,7 +106,10 @@ public class Database {
Set<Item> rawFluids = new HashSet<>(Arrays.asList(CrudeOil, Water));
// no common well yet
CrudeOil.add(new Recipe(1, "Oil extracting thingy", false), 2);
Water.add(new Recipe(1, "water pump thingy", false), 2);
//CrudeOil.setPreference();
Recipe water = new Recipe(1, "water pump thingy", false);
Water.add(water, 2);
Water.setPreference(water);
}
{
// Steel Ingot
@ -372,9 +388,6 @@ public class Database {
Plastic.add(residualPlastic, 2);
Plastic.setPreference(recipe);
HeavyOilResidue.add(recipe);
HeavyOilResidue.setPreference(recipe);
}
{
// Rubber
@ -388,8 +401,6 @@ public class Database {
Rubber.add(residualRubber, 2);
Rubber.setPreference(recipe);
HeavyOilResidue.add(recipe);
}
{
// Petroleum Coke
@ -397,13 +408,60 @@ public class Database {
recipe.addInput(HeavyOilResidue, 4);
PetroleumCoke.add(recipe, 12);
}
// TODO: verify below!
{
Recipe recipe = new Recipe(6, AluminumIngot, 3);
recipe.addInput(CopperIngot, 1);
AlcladAluminumSheet.add(recipe, 3);
}
{
Recipe recipe = new Recipe(120, QuartzCristal, 36);
recipe.addInput(Cable, 28);
recipe.addInput(ReinforcedIronPlate, 5);
CrystalOscillator.add(recipe, 2);
}
{
Recipe recipe = new Recipe(48, AluminumCasing, 32);
recipe.addInput(CrystalOscillator, 1);
recipe.addInput(Computer, 1);
RadioControlUnit.add(recipe, 2);
}
{
Recipe recipe = new Recipe(2, AluminumIngot, 3);
AluminumCasing.add(recipe, 2);
}
{
Recipe recipe = new Recipe(8, RawQuartz, 5);
QuartzCristal.add(recipe, 3);
}
{
Recipe recipe = new Recipe(4, AluminumScrap, 6);
recipe.addInput(Silica, 5);
recipe.addOutput(AluminumIngot, 4);
}
{
Recipe recipe = new Recipe(6);
recipe.addInput(Bauxite, 12);
recipe.addInput(Water, 18);
recipe.addOutput(Silica, 5);
recipe.addOutput(AluminaSolution, 12);
}
{
Recipe recipe = new Recipe(1);
recipe.addInput(AluminaSolution, 4);
recipe.addInput(Coal, 2);
recipe.addOutput(AluminumScrap,6);
recipe.addOutput(Water,2);
}
}
public static void add(Item i) {
items.add(i);
}
public static void add(Item i) {
items.add(i);
}
public static Collection<Item> getItems() {
return new HashSet<>(items);
}
public static Collection<Item> getItems() {
return new HashSet<>(items);
}
}

View File

@ -1,25 +1,26 @@
package satisfactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import satisfactory.items.*;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import org.jgrapht.graph.EdgeReversedGraph;
import org.jgrapht.nio.Attribute;
import org.jgrapht.nio.DefaultAttribute;
import org.jgrapht.nio.dot.DOTExporter;
import satisfactory.items.Item;
import satisfactory.items.Production;
import satisfactory.items.Recipe;
import satisfactory.items.SumResult;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import static satisfactory.Utils.PLOTS;
import static satisfactory.Utils.plot2;
public class Test {
public static void main(String[] args) throws JsonProcessingException {
//System.out.println(satisfactory.items.Database.AdaptiveControlUnit);
public static void main(String[] args) throws JsonProcessingException {
/* //System.out.println(satisfactory.items.Database.AdaptiveControlUnit);
Map<Item, Integer> totalRequirements = Database.HeavyModularFrame.getRecipe().getTotalRequirements();
System.out.println(totalRequirements);
@ -91,15 +92,33 @@ public class Test {
plot2(SumResult.sum(Database.Rubber, 75),"rubber");
System.out.println("\ntest");
SumResult.sum(Database.Plastic, 4);
*/
Item a = Database.HeavyOilResidue;
Item b = Database.Water;
Map<Item, Recipe> preferences = Database.preferences;
Recipe recipe = b.getRecipe();
System.out.println(recipe);
//plot(Database.GasFilter, "rubber",1);
plot(Database.RadioControlUnit, "alu", 1);
Item i = Database.AluminumIngot;
//plot2(SumResult.sum(i, 1),"rubber_");
//plot(i, "rcu_hierarchy",1);
SumResult s = SumResult.sum(new Production(Database.RadioControlUnit, 2));
plot2(s.getProduction(), "rcu");
}
}
private static void plot(Item target, String name, int amount, DOTExporter<Item, DefaultWeightedEdge> de) {
Graph<Item, DefaultWeightedEdge> screws = target.productionHierarchy(amount);
de.exportGraph(screws, new File(name + ".dot"));
System.out.println(name);
Item.production(screws).forEach((item, rate) -> {
System.out.println("\t" + item.getName() + "\t" + rate);
});
}
private static void plot(Item target, String name, int amount) {
Graph<Item, DefaultWeightedEdge> screws = target.hierarchy();
DOTExporter<Item, DefaultWeightedEdge> de = new DOTExporter<>(Utils::dotID);
de.setEdgeAttributeProvider(defaultWeightedEdge -> {
Map<String, Attribute> m = new HashMap<>();
m.put("label", DefaultAttribute.createAttribute(screws.getEdgeWeight(defaultWeightedEdge)));
return m;
});
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);
});
}
}

View File

@ -24,6 +24,9 @@ import java.util.Map;
import java.util.stream.Collectors;
public class Utils {
public static final String PLOTS = "plots/";
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())) {
@ -100,7 +103,7 @@ public class Utils {
m.put("label", DefaultAttribute.createAttribute(item.getName()));
return m;
});
de.exportGraph(sum, new File(filename + ".dot"));
de.exportGraph(sum, new File(PLOTS +filename + ".dot"));
}
}

View File

@ -0,0 +1,108 @@
package satisfactory.items;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import satisfactory.Database;
import java.util.*;
public abstract class Item {
protected boolean isRaw = false;
private String name;
private Set<Recipe> recipes;
private Recipe preference = null;
public int sum = 0;
protected Item(String name, Set<Recipe> recipes) {
this.name = name;
this.recipes = recipes;
Database.add(this);
for (Recipe recipe : recipes) {
add(recipe);
}
}
public Item(String name, Recipe... recipes) {
this(name, new HashSet<>(Arrays.asList(recipes)));
}
public Item(String name) {
this(name, new HashSet<>());
}
public void add(Recipe recipe) {
add(recipe, 1);
}
public void add(Recipe recipe, int output) {
recipes.add(recipe);
recipe.checkOutput(this, output);
}
public String getName() {
return name;
}
public Set<Recipe> getRecipes() {
return recipes;
}
public boolean isRaw() {
return isRaw;
}
public float getProductionRate() {
Recipe recipe = getRecipe();
if (recipe == null) {
return 0;
}
return recipe.getProductionRate(this);
}
public Recipe getRecipe() {
Recipe recipe = Database.preferences.getOrDefault(this, preference);
if (recipe == null) {
recipe = recipes.stream().findFirst().orElse(null);
}
return recipe;
}
protected void setIsRaw() {
isRaw = true;
}
@Override
public String toString() {
return "Item{" +
"name='" + name + '\'' +
", #recipes=" + recipes.size() +
'}';
}
public void setPreference(Recipe preference) {
this.preference = preference;
}
public static Map<Item, Double> production(Graph<Item, DefaultWeightedEdge> graph) {
Map<Item, Double> map = new HashMap<>();
graph.vertexSet().forEach(item -> {
double rate = graph.outgoingEdgesOf(item).stream().mapToDouble(graph::getEdgeWeight).sum();
map.put(item, rate);
});
return map;
}
public Graph<Item, DefaultWeightedEdge> hierarchy() {
System.out.println(getRecipe() + " == " + this.preference);
return getRecipe().buildGraph(this);
}
public String ID() {
return getName().replace(" ", "");
}
public Recipe getPreference() {
return preference;
}
}

View File

@ -74,6 +74,7 @@ public class Recipe {
public void addOutput(Item item, int amount) {
this.outputs.put(item, amount);
item.add(this, amount);
}
public void checkOutput(Item item, int amount) {
@ -107,6 +108,7 @@ public class Recipe {
}
public Graph<Item, DefaultWeightedEdge> buildGraph(Item target) {
System.out.println("buildGraph(" + target.getName() + ") @ "+ name);
Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex(target);
target.sum += 1;
@ -124,57 +126,14 @@ public class Recipe {
graph.setEdgeWeight(item, target, integer);
Recipe recipe = item.getRecipe();
if (recipe != null) {
if (recipe != null && item != target) {
Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item);
Graphs.addGraph(graph, g);
}
});
return graph;
}
private float getLoad(Item target, float amount) {
return getUsage(target, amount) * duration;
}
private float getUsage(Item target, float amount) {
return amount / outputs.get(target);
}
public Graph<Item, DefaultWeightedEdge> buildGraph(Item target, float amountPerSecond) {
Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex(target);
target.sum += 1;
float load = getLoad(target, amountPerSecond);
// byproducts
Map<Item, Integer> output = outputs.entrySet().stream()
.filter(itemIntegerEntry -> itemIntegerEntry.getKey() != target)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
output.forEach((item, integer) -> {
graph.addVertex(item);
graph.addEdge(target, item);
graph.setEdgeWeight(target, item, integer * load);
});
// inputs
inputs.forEach((item, integer) -> {
graph.addVertex(item);
graph.addEdge(item, target);
float rate = (amountPerSecond / outputs.get(target)) / integer;
graph.setEdgeWeight(item, target, rate);
Recipe recipe = item.getRecipe();
if (recipe != null) {
Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item, rate);
Graphs.addGraph(graph, g);
}
});
return graph;
}
private double processesNeeded(Item target, double n) {
Recipe r = target.getRecipe();
return n / r.getProductionRate(target);
@ -202,8 +161,10 @@ public class Recipe {
for (DefaultWeightedEdge edge : buildGraph.outgoingEdgesOf(item)) {
Item product = buildGraph.getEdgeTarget(edge);
Double productWantedPerMinute = map.get(product);
System.out.println(item.getName());
if (item.getRecipe().outputs.containsKey(product)) {
// product is by-product, no forward dependency
System.out.println("BY-PRODUCT " + item.getName() + " -> " + product.getName());
byProducts.add(product);
continue;
}

View File

@ -1,126 +0,0 @@
package satisfactory.items;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultWeightedEdge;
import satisfactory.Database;
import java.util.*;
public abstract class Item {
protected boolean isRaw = false;
private String name;
private Set<Recipe> recipes;
private Recipe preference = null;
public int sum = 0;
protected Item(String name, Set<Recipe> recipes) {
this.name = name;
this.recipes = recipes;
Database.add(this);
for (Recipe recipe : recipes) {
add(recipe);
}
}
public Item(String name, Recipe... recipes) {
this(name, new HashSet<>(Arrays.asList(recipes)));
}
public Item(String name) {
this(name, new HashSet<>());
}
public void add(Recipe recipe) {
add(recipe, 1);
}
public void add(Recipe recipe, int output) {
recipes.add(recipe);
recipe.checkOutput(this, output);
}
public String getName() {
return name;
}
public Set<Recipe> getRecipes() {
return recipes;
}
public boolean isRaw() {
return isRaw;
}
public float getProductionRate() {
Recipe recipe = getRecipe();
if (recipe == null) {
return 0;
}
return recipe.getProductionRate(this);
}
public Recipe getRecipe() {
Recipe recipe = preference;
if (recipe == null) {
if (Database.preferences.containsKey(this)) {
recipe = Database.preferences.get(this);
}
if (recipe == null) {
recipe = recipes.stream().findFirst().orElse(null);
}
}
return recipe;
}
protected void setIsRaw() {
isRaw = true;
}
@Override
public String toString() {
return "Item{" +
"name='" + name + '\'' +
", #recipes=" + recipes.size() +
'}';
}
public void setPreference(Recipe preference) {
this.preference = preference;
}
public Graph<Item, DefaultWeightedEdge> productionHierarchy() {
return productionHierarchy(1);
}
public Graph<Item, DefaultWeightedEdge> productionHierarchy(int amount) {
Graph<Item, DefaultWeightedEdge> graph = getRecipe().buildGraph(this, amount);
graph.addEdge(this,this);
graph.setEdgeWeight(this,this,amount);
return graph;
}
public Map<Item, Double> production(int amount){
Graph<Item, DefaultWeightedEdge> graph = productionHierarchy(amount);
return production(graph);
}
public static Map<Item, Double> production(Graph<Item, DefaultWeightedEdge> graph){
Map<Item,Double> map = new HashMap<>();
graph.vertexSet().forEach(item -> {
double rate = graph.outgoingEdgesOf(item).stream().mapToDouble(graph::getEdgeWeight).sum();
map.put(item, rate);
});
return map;
}
public Graph<Item, DefaultWeightedEdge> hierarchy(){
return getRecipe().buildGraph(this);
}
public String ID(){
return getName().replace(" ","");
}
}

View File

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

View File

@ -14,11 +14,12 @@ class ItemTest {
@Test
void productionScrews() {
Map<Item, Double> production = Database.Screw.production(100);
/*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");
assertEquals(25, production.get(Database.IronOre), "IronOre");*/
fail();
}
@Test
@ -35,13 +36,14 @@ class ItemTest {
@Test
void productionReinforcedIronPlates() {
Map<Item, Double> production = Database.ReinforcedIronPlate.production(100);
/*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");
assertEquals(600, production.get(Database.IronPlate), "IronPlate");*/
fail();
}
@Test