fix graph merge loss of rates

master
agp8x 2021-05-15 23:40:52 +02:00
parent e1f442308e
commit b0f49eb814
8 changed files with 896 additions and 756 deletions

View File

@ -7,396 +7,397 @@ import satisfactory.items.type.*;
import java.util.*; import java.util.*;
public class Database { public class Database {
// dirty!
private static final Collection<Item> items = new HashSet<>(); private static final Collection<Item> items = new HashSet<>();
public static final Map<Item, Recipe> preferences = new HashMap<>(); public static final Map<Item, Recipe> preferences = new HashMap<>();
// Items & recipes // Items & recipes
public static final Item IronOre = new Ore("Iron Ore"); public static final Item IronOre = new Ore("Iron Ore");
public static final Item IronIngot = new Ingot("Iron Ingot", new Recipe(2, IronOre, 1)); public static final Item IronIngot = new Ingot("Iron Ingot", new Recipe(2, IronOre, 1));
public static final Item CopperOre = new Ore("Copper Ore"); public static final Item CopperOre = new Ore("Copper Ore");
public static final Item CopperIngot = new Ingot("Copper Ingot", new Recipe(2, CopperOre, 1)); public static final Item CopperIngot = new Ingot("Copper Ingot", new Recipe(2, CopperOre, 1));
public static final Item Coal = new Ore("Coal"); public static final Item Coal = new Ore("Coal");
public static final Item SteelIngot = new Ingot("Steel Ingot"); public static final Item SteelIngot = new Ingot("Steel Ingot");
public static final Item CateriumOre = new Ore("Caterium Ore"); public static final Item CateriumOre = new Ore("Caterium Ore");
public static final Item CateriumIngot = new Ingot("Caterium Ingot", new Recipe(4, CateriumOre, 3)); public static final Item CateriumIngot = new Ingot("Caterium Ingot", new Recipe(4, CateriumOre, 3));
public static final Item IronPlate = new Part("Iron Plate"); public static final Item IronPlate = new Part("Iron Plate");
public static final Item IronRod = new Part("IronRod", new Recipe(4, IronIngot, 1)); public static final Item IronRod = new Part("Iron Rod", new Recipe(4, IronIngot, 1));
public static final Item Screw = new Part("Screw"); public static final Item Screw = new Part("Screw");
public static final Item ReinforcedIronPlate = new Part("Reinforced Iron Plate"); public static final Item ReinforcedIronPlate = new Part("Reinforced Iron Plate");
public static final Item ModularFrame = new Part("Modular Frame"); public static final Item ModularFrame = new Part("Modular Frame");
public static final Item SteelBeam = new Part("Steel Beam", new Recipe(4, SteelIngot, 4)); public static final Item SteelBeam = new Part("Steel Beam", new Recipe(4, SteelIngot, 4));
public static final Item SteelPipe = new Part("Steel Pipe"); public static final Item SteelPipe = new Part("Steel Pipe");
public static final Item Limestone = new Ore("Limestone"); public static final Item Limestone = new Ore("Limestone");
public static final Item Concrete = new Part("Concrete", new Recipe(4, Limestone, 3)); public static final Item Concrete = new Part("Concrete", new Recipe(4, Limestone, 3));
public static final Item EncasedIndustrialBeam = new Part("Encased Industrial Beam"); public static final Item EncasedIndustrialBeam = new Part("Encased Industrial Beam");
public static final Item HeavyModularFrame = new Part("HeavyModularFrame"); public static final Item HeavyModularFrame = new Part("Heavy Modular Frame");
public static final Item CopperSheet = new Part("CopperSheet", new Recipe(6, CopperIngot, 2)); public static final Item CopperSheet = new Part("Copper Sheet", new Recipe(6, CopperIngot, 2));
public static final Item Wire = new Part("Wire"); public static final Item Wire = new Part("Wire");
public static final Item Cable = new Part("Cable", new Recipe(2, Wire, 2)); public static final Item Cable = new Part("Cable", new Recipe(2, Wire, 2));
public static final Item Quickwire = new Part("Quickwire"); public static final Item Quickwire = new Part("Quickwire");
public static final Item CircuitBoard = new Part("CircuitBoard"); public static final Item CircuitBoard = new Part("Circuit Board");
public static final Item AILimiter = new Part("A.I. Limiter"); public static final Item AILimiter = new Part("A.I. Limiter");
public static final Item HighSpeedConnector = new Part("High-Speed Connector"); public static final Item HighSpeedConnector = new Part("High-Speed Connector");
public static final Item Biomass = new Part("Biomass"); public static final Item Biomass = new Part("Biomass");
public static final Item SolidBiofuel = new Part("Solid Biofuel"); public static final Item SolidBiofuel = new Part("Solid Biofuel");
public static final Item Mycelia = new Pickup("Mycelia"); public static final Item Mycelia = new Pickup("Mycelia");
public static final Item Leaves = new Pickup("Leaves"); public static final Item Leaves = new Pickup("Leaves");
public static final Item Wood = new Pickup("Wood"); public static final Item Wood = new Pickup("Wood");
public static final Item AlienCarapace = new Pickup("Alien Carapace"); public static final Item AlienCarapace = new Pickup("Alien Carapace");
public static final Item AlienOrgans = new Pickup("Alien Organs"); public static final Item AlienOrgans = new Pickup("Alien Organs");
public static final Item Fabric = new Part("Fabric"); public static final Item Fabric = new Part("Fabric");
public static final Item Rotor = new Part("Rotor"); public static final Item Rotor = new Part("Rotor");
public static final Item Stator = new Part("Stator"); public static final Item Stator = new Part("Stator");
public static final Item Motor = new Part("Motor"); public static final Item Motor = new Part("Motor");
public static final Item GreenPowerSlug = new Pickup("Green Power Slug"); public static final Item GreenPowerSlug = new Pickup("Green Power Slug");
public static final Item YellowPowerSlug = new Pickup("Yellow Power Slug"); public static final Item YellowPowerSlug = new Pickup("Yellow Power Slug");
public static final Item PurplePowerSlug = new Pickup("Purple Power Slug"); public static final Item PurplePowerSlug = new Pickup("Purple Power Slug");
public static final Item PowerShard = new Pickup("PowerShard"); public static final Item PowerShard = new Pickup("PowerShard");
public static final Item Sulfur = new Ore("Sulfur"); public static final Item Sulfur = new Ore("Sulfur");
public static final Item BlackPowder = new Part("Black powder"); public static final Item BlackPowder = new Part("Black powder");
public static final Item SpikedRebar = new Part("SpikedRebar", new Recipe(4, IronRod, 1)); public static final Item SpikedRebar = new Part("Spiked Rebar", new Recipe(4, IronRod, 1));
public static final Item FlowerPetals = new Pickup("Flower Petals"); public static final Item FlowerPetals = new Pickup("Flower Petals");
public static final Item ColorCatridge = new Part("Color Catridge"); public static final Item ColorCatridge = new Part("Color Catridge");
public static final Item Beacon = new Tool("Beacon"); public static final Item Beacon = new Tool("Beacon");
public static final Item Rubber = new Part("Rubber"); public static final Item Rubber = new Part("Rubber");
public static final Item RifleCatridge = new Part("RifleCatridge"); public static final Item RifleCatridge = new Part("Rifle Catridge");
public static final Item GasFilter = new Tool("Gas Filter"); public static final Item GasFilter = new Tool("Gas Filter");
public static final Item Plastic = new Part("Plastic"); public static final Item Plastic = new Part("Plastic");
public static final Item Computer = new Part("Computer"); public static final Item Computer = new Part("Computer");
public static final Item SuperComputer = new Part("SuperComputer"); public static final Item SuperComputer = new Part("Super Computer");
public static final Item EmptyCanister = new Part("Empty Canister"); public static final Item EmptyCanister = new Part("Empty Canister");
public static final Item ModularEngine = new Part("Modular Engine"); public static final Item ModularEngine = new Part("Modular Engine");
public static final Item AdaptiveControlUnit = new Part("Adaptive Control Unit"); public static final Item AdaptiveControlUnit = new Part("Adaptive Control Unit");
public static final Item SmartPlating = new Part("Smart Plating"); public static final Item SmartPlating = new Part("Smart Plating");
public static final Item AutomatedWiring = new Part("Automated Wiring"); public static final Item AutomatedWiring = new Part("Automated Wiring");
public static final Item VersatileFrameWork = new Part("Versatile Framework"); public static final Item VersatileFrameWork = new Part("Versatile Framework");
public static final Item Nobelisk = new Part("Nobelisk"); public static final Item Nobelisk = new Part("Nobelisk");
public static final Item Water = new RawFluid("Water"); public static final Item Water = new RawFluid("Water");
public static final Item CrudeOil = new RawFluid("Crude Oil"); public static final Item CrudeOil = new RawFluid("Crude Oil");
public static final Item HeavyOilResidue = new ProcessedFluid("Heavy Oil Residue"); public static final Item HeavyOilResidue = new ProcessedFluid("Heavy Oil Residue");
public static final Item Fuel = new ProcessedFluid("Fuel"); public static final Item Fuel = new ProcessedFluid("Fuel");
public static final Item LiquidBiofuel = new ProcessedFluid("Liquid Biofuel"); public static final Item LiquidBiofuel = new ProcessedFluid("Liquid Biofuel");
public static final Item PetroleumCoke = new Part("Petroleum Coke"); public static final Item PetroleumCoke = new Part("Petroleum Coke");
public static final Item PolymerResin = new Part("Polymer Resin"); public static final Item PolymerResin = new Part("Polymer Resin");
static { static {
{ {
Set<Item> ores = new HashSet<>(Arrays.asList(IronOre, Coal, Limestone, CopperOre, CateriumOre, Sulfur)); Set<Item> ores = new HashSet<>(Arrays.asList(IronOre, Coal, Limestone, CopperOre, CateriumOre, Sulfur));
for (Item ore : ores) { for (Item ore : ores) {
Recipe mk1 = new Recipe(1, "Miner MK 1", false); Recipe mk1 = new Recipe(1, "Miner MK 1", false);
ore.add(mk1, 1); ore.add(mk1, 1);
Recipe mk2 = new Recipe(1, "Miner MK2", false); Recipe mk2 = new Recipe(1, "Miner MK2", false);
ore.add(mk2, 2); ore.add(mk2, 2);
} ore.setPreference(mk2);
}
Set<Item> rawFluids = new HashSet<>(Arrays.asList(CrudeOil, Water)); Set<Item> rawFluids = new HashSet<>(Arrays.asList(CrudeOil, Water));
// no common well yet // no common well yet
CrudeOil.add(new Recipe(1, "Oil extracting thingy", false), 2); CrudeOil.add(new Recipe(1, "Oil extracting thingy", false), 2);
Water.add(new Recipe(1, "water pump thingy", false), 2); Water.add(new Recipe(1, "water pump thingy", false), 2);
} }
{ {
// Steel Ingot // Steel Ingot
Recipe recipe = new Recipe(4); Recipe recipe = new Recipe(4);
recipe.addInput(IronOre, 3); recipe.addInput(IronOre, 3);
recipe.addInput(Coal, 3); recipe.addInput(Coal, 3);
SteelIngot.add(recipe, 3); SteelIngot.add(recipe, 3);
} }
{ {
// Iron Plate // Iron Plate
Recipe recipe = new Recipe(6, IronIngot, 3); Recipe recipe = new Recipe(6, IronIngot, 3);
IronPlate.add(recipe, 2); IronPlate.add(recipe, 2);
} }
{ {
// Screw // Screw
Screw.add(new Recipe(6, IronRod, 1), 4); Screw.add(new Recipe(6, IronRod, 1), 4);
} }
{ {
// Reinforced Iron Plate // Reinforced Iron Plate
Recipe recipe = new Recipe(12); Recipe recipe = new Recipe(12);
recipe.addInput(IronPlate, 6); recipe.addInput(IronPlate, 6);
recipe.addInput(Screw, 12); recipe.addInput(Screw, 12);
ReinforcedIronPlate.add(recipe); ReinforcedIronPlate.add(recipe);
Recipe bolted = new Recipe(12, "Bolted Iron Plate", false); Recipe bolted = new Recipe(12, "Bolted Iron Plate", false);
bolted.addInput(IronPlate, 18); bolted.addInput(IronPlate, 18);
bolted.addInput(Screw, 50); bolted.addInput(Screw, 50);
ReinforcedIronPlate.add(bolted, 3); ReinforcedIronPlate.add(bolted, 3);
ReinforcedIronPlate.setPreference(recipe); ReinforcedIronPlate.setPreference(recipe);
} }
{ {
// Modular Frame // Modular Frame
Recipe recipe = new Recipe(60); Recipe recipe = new Recipe(60);
recipe.addInput(ReinforcedIronPlate, 3); recipe.addInput(ReinforcedIronPlate, 3);
recipe.addInput(IronRod, 12); recipe.addInput(IronRod, 12);
ModularFrame.add(recipe, 2); ModularFrame.add(recipe, 2);
} }
{ {
// Steel Pipe // Steel Pipe
Recipe recipe = new Recipe(6); Recipe recipe = new Recipe(6);
recipe.addInput(SteelIngot, 3); recipe.addInput(SteelIngot, 3);
SteelPipe.add(recipe, 2); SteelPipe.add(recipe, 2);
} }
{ {
// Encased Industrial Beam // Encased Industrial Beam
Recipe recipe = new Recipe(10); Recipe recipe = new Recipe(10);
recipe.addInput(SteelBeam, 4); recipe.addInput(SteelBeam, 4);
recipe.addInput(Concrete, 5); recipe.addInput(Concrete, 5);
EncasedIndustrialBeam.add(recipe); EncasedIndustrialBeam.add(recipe);
} }
{ {
// Heavy Modular Frame // Heavy Modular Frame
Recipe recipe = new Recipe(30); Recipe recipe = new Recipe(30);
recipe.addInput(ModularFrame, 5); recipe.addInput(ModularFrame, 5);
recipe.addInput(SteelPipe, 15); recipe.addInput(SteelPipe, 15);
recipe.addInput(EncasedIndustrialBeam, 5); recipe.addInput(EncasedIndustrialBeam, 5);
recipe.addInput(Screw, 100); recipe.addInput(Screw, 100);
HeavyModularFrame.add(recipe); HeavyModularFrame.add(recipe);
} }
{ {
// Wire // Wire
Wire.add(new Recipe(4, CopperIngot, 1), 2); Wire.add(new Recipe(4, CopperIngot, 1), 2);
} }
{ {
// Quickwire // Quickwire
Quickwire.add(new Recipe(5, CateriumIngot, 1), 5); Quickwire.add(new Recipe(5, CateriumIngot, 1), 5);
} }
{ {
// Circuit Board // Circuit Board
Recipe recipe = new Recipe(8); Recipe recipe = new Recipe(8);
recipe.addInput(CopperSheet, 2); recipe.addInput(CopperSheet, 2);
recipe.addInput(Plastic, 4); recipe.addInput(Plastic, 4);
CircuitBoard.add(recipe); CircuitBoard.add(recipe);
} // TODO: alternative
{ }
// A.I. Limiter {
Recipe recipe = new Recipe(12); // A.I. Limiter
recipe.addInput(CopperSheet, 5); Recipe recipe = new Recipe(12);
recipe.addInput(Quickwire, 20); recipe.addInput(CopperSheet, 5);
AILimiter.add(recipe); recipe.addInput(Quickwire, 20);
} AILimiter.add(recipe);
{ }
// High Speed Connector {
Recipe recipe = new Recipe(16); // High Speed Connector
recipe.addInput(Quickwire, 56); Recipe recipe = new Recipe(16);
recipe.addInput(Cable, 10); recipe.addInput(Quickwire, 56);
recipe.addInput(CircuitBoard, 1); recipe.addInput(Cable, 10);
HighSpeedConnector.add(recipe); recipe.addInput(CircuitBoard, 1);
} HighSpeedConnector.add(recipe);
{ }
// Biomass {
Biomass.add(new Recipe(5, Leaves, 10), 5); // Biomass
Biomass.add(new Recipe(4, Wood, 4), 20); Biomass.add(new Recipe(5, Leaves, 10), 5);
Biomass.add(new Recipe(4, Mycelia, 10), 10); Biomass.add(new Recipe(4, Wood, 4), 20);
Biomass.add(new Recipe(4, AlienCarapace, 1), 100); Biomass.add(new Recipe(4, Mycelia, 10), 10);
Biomass.add(new Recipe(8, AlienOrgans, 1), 200); Biomass.add(new Recipe(4, AlienCarapace, 1), 100);
} Biomass.add(new Recipe(8, AlienOrgans, 1), 200);
{ }
// Fabric {
Recipe recipe = new Recipe(4); // Fabric
recipe.addInput(Mycelia); Recipe recipe = new Recipe(4);
recipe.addInput(Biomass, 5); recipe.addInput(Mycelia);
Fabric.add(recipe); recipe.addInput(Biomass, 5);
} Fabric.add(recipe);
{ }
// Solid Biofuel {
SolidBiofuel.add(new Recipe(4, Biomass, 8), 4); // Solid Biofuel
} SolidBiofuel.add(new Recipe(4, Biomass, 8), 4);
{ }
// Rotator {
Recipe recipe = new Recipe(15); // Rotator
recipe.addInput(IronRod, 5); Recipe recipe = new Recipe(15);
recipe.addInput(Screw, 25); recipe.addInput(IronRod, 5);
Rotor.add(recipe); recipe.addInput(Screw, 25);
} Rotor.add(recipe);
{ }
// Stator {
Recipe recipe = new Recipe(12); // Stator
recipe.addInput(SteelPipe, 3); Recipe recipe = new Recipe(12);
recipe.addInput(Wire, 8); recipe.addInput(SteelPipe, 3);
Stator.add(recipe); recipe.addInput(Wire, 8);
} Stator.add(recipe);
{ }
// Motor {
Recipe recipe = new Recipe(12); // Motor
recipe.addInput(Rotor, 2); Recipe recipe = new Recipe(12);
recipe.addInput(Stator, 2); recipe.addInput(Rotor, 2);
Motor.add(recipe); recipe.addInput(Stator, 2);
} Motor.add(recipe);
{ }
// Power Shard {
PowerShard.add(new Recipe(8, GreenPowerSlug, 1)); // Power Shard
PowerShard.add(new Recipe(12, YellowPowerSlug, 1), 2); PowerShard.add(new Recipe(8, GreenPowerSlug, 1));
PowerShard.add(new Recipe(24, PurplePowerSlug, 1), 5); PowerShard.add(new Recipe(12, YellowPowerSlug, 1), 2);
} PowerShard.add(new Recipe(24, PurplePowerSlug, 1), 5);
{ }
// Black Powder {
Recipe recipe = new Recipe(8); // Black Powder
recipe.addInput(Coal); Recipe recipe = new Recipe(8);
recipe.addInput(Sulfur, 2); recipe.addInput(Coal);
BlackPowder.add(recipe); recipe.addInput(Sulfur, 2);
} BlackPowder.add(recipe);
{ }
// Color Catridge {
ColorCatridge.add(new Recipe(8, FlowerPetals, 5), 10); // Color Catridge
} ColorCatridge.add(new Recipe(8, FlowerPetals, 5), 10);
{ }
// Rifle Catridge {
Recipe recipe = new Recipe(20); // Rifle Catridge
recipe.addInput(Beacon, 1); Recipe recipe = new Recipe(20);
recipe.addInput(SteelPipe, 10); recipe.addInput(Beacon, 1);
recipe.addInput(BlackPowder, 10); recipe.addInput(SteelPipe, 10);
recipe.addInput(Rubber, 10); recipe.addInput(BlackPowder, 10);
RifleCatridge.add(recipe, 5); recipe.addInput(Rubber, 10);
} RifleCatridge.add(recipe, 5);
{ }
// Gas Filter {
Recipe recipe = new Recipe(8); // Gas Filter
recipe.addInput(Coal, 5); Recipe recipe = new Recipe(8);
recipe.addInput(Rubber, 2); recipe.addInput(Coal, 5);
recipe.addInput(Fabric, 2); recipe.addInput(Rubber, 2);
GasFilter.add(recipe); recipe.addInput(Fabric, 2);
} GasFilter.add(recipe);
{ }
// Computer {
Recipe recipe = new Recipe(24); // Computer
recipe.addInput(CircuitBoard, 10); Recipe recipe = new Recipe(24);
recipe.addInput(Cable, 9); recipe.addInput(CircuitBoard, 10);
recipe.addInput(Plastic, 18); recipe.addInput(Cable, 9);
recipe.addInput(Screw, 52); recipe.addInput(Plastic, 18);
Computer.add(recipe); recipe.addInput(Screw, 52);
Recipe alternative = new Recipe(16, "Caterium Computer", false); Computer.add(recipe);
alternative.addInput(CircuitBoard, 7); Recipe alternative = new Recipe(16, "Caterium Computer", false);
alternative.addInput(Quickwire, 28); alternative.addInput(CircuitBoard, 7);
alternative.addInput(Rubber, 12); alternative.addInput(Quickwire, 28);
Computer.add(alternative); alternative.addInput(Rubber, 12);
Computer.add(alternative);
Computer.setPreference(recipe); Computer.setPreference(recipe);
} }
{ {
// Super Computer // Super Computer
Recipe recipe = new Recipe(32); Recipe recipe = new Recipe(32);
recipe.addInput(Computer, 2); recipe.addInput(Computer, 2);
recipe.addInput(AILimiter, 2); recipe.addInput(AILimiter, 2);
recipe.addInput(HighSpeedConnector, 3); recipe.addInput(HighSpeedConnector, 3);
recipe.addInput(Plastic, 28); recipe.addInput(Plastic, 28);
SuperComputer.add(recipe); SuperComputer.add(recipe);
} }
{ {
// Empty Canister // Empty Canister
EmptyCanister.add(new Recipe(4, Plastic, 2), 4); EmptyCanister.add(new Recipe(4, Plastic, 2), 4);
} }
{ {
// Beacon // Beacon
Recipe recipe = new Recipe(8); Recipe recipe = new Recipe(8);
recipe.addInput(IronPlate, 3); recipe.addInput(IronPlate, 3);
recipe.addInput(IronRod); recipe.addInput(IronRod);
recipe.addInput(Wire, 15); recipe.addInput(Wire, 15);
recipe.addInput(Cable, 2); recipe.addInput(Cable, 2);
Beacon.add(recipe); Beacon.add(recipe);
} }
{ {
// Modular Engine // Modular Engine
Recipe recipe = new Recipe(60, false); Recipe recipe = new Recipe(60, false);
recipe.addInput(Motor, 2); recipe.addInput(Motor, 2);
recipe.addInput(Rubber, 15); recipe.addInput(Rubber, 15);
recipe.addInput(SmartPlating, 2); recipe.addInput(SmartPlating, 2);
ModularEngine.add(recipe); ModularEngine.add(recipe);
} }
{ {
// Adaptive Control Unit // Adaptive Control Unit
Recipe recipe = new Recipe(120, false); Recipe recipe = new Recipe(120, false);
recipe.addInput(AutomatedWiring, 15); recipe.addInput(AutomatedWiring, 15);
recipe.addInput(CircuitBoard, 10); recipe.addInput(CircuitBoard, 10);
recipe.addInput(HeavyModularFrame, 2); recipe.addInput(HeavyModularFrame, 2);
recipe.addInput(Computer, 2); recipe.addInput(Computer, 2);
AdaptiveControlUnit.add(recipe, 2); AdaptiveControlUnit.add(recipe, 2);
} }
{ {
// Nobelisk // Nobelisk
Recipe recipe = new Recipe(20, false); Recipe recipe = new Recipe(20, false);
recipe.addInput(BlackPowder, 5); recipe.addInput(BlackPowder, 5);
recipe.addInput(SteelPipe, 10); recipe.addInput(SteelPipe, 10);
Nobelisk.add(recipe); Nobelisk.add(recipe);
} }
{ {
// Smart Plating // Smart Plating
Recipe recipe = new Recipe(30, false); Recipe recipe = new Recipe(30, false);
recipe.addInput(ReinforcedIronPlate); recipe.addInput(ReinforcedIronPlate);
recipe.addInput(Rotor); recipe.addInput(Rotor);
SmartPlating.add(recipe); SmartPlating.add(recipe);
} }
{ {
// Automated Wiring // Automated Wiring
Recipe recipe = new Recipe(24, false); Recipe recipe = new Recipe(24, false);
recipe.addInput(Stator); recipe.addInput(Stator);
recipe.addInput(Cable, 20); recipe.addInput(Cable, 20);
AutomatedWiring.add(recipe); AutomatedWiring.add(recipe);
} }
{ {
// Versatile Framework // Versatile Framework
Recipe recipe = new Recipe(24, false); Recipe recipe = new Recipe(24, false);
recipe.addInput(ModularFrame); recipe.addInput(ModularFrame);
recipe.addInput(SteelBeam, 12); recipe.addInput(SteelBeam, 12);
VersatileFrameWork.add(recipe, 2); VersatileFrameWork.add(recipe, 2);
} }
{ {
// Fuel // Fuel
Recipe residualFuel = new Recipe(6, "Residual Fuel", false); Recipe residualFuel = new Recipe(6, "Residual Fuel", false);
residualFuel.addInput(HeavyOilResidue, 6); residualFuel.addInput(HeavyOilResidue, 6);
Fuel.add(residualFuel, 4); Fuel.add(residualFuel, 4);
Recipe recipe = new Recipe(6, false); Recipe recipe = new Recipe(6, false);
recipe.addInput(CrudeOil, 6); recipe.addInput(CrudeOil, 6);
recipe.addOutput(PolymerResin, 3); recipe.addOutput(PolymerResin, 3);
Fuel.add(recipe, 4); Fuel.add(recipe, 4);
Fuel.setPreference(recipe); Fuel.setPreference(recipe);
} }
{ {
// Liquid Biofuel // Liquid Biofuel
Recipe recipe = new Recipe(4, false); Recipe recipe = new Recipe(4, false);
recipe.addInput(SolidBiofuel, 6); recipe.addInput(SolidBiofuel, 6);
recipe.addInput(Water, 3); recipe.addInput(Water, 3);
LiquidBiofuel.add(recipe, 4); LiquidBiofuel.add(recipe, 4);
} }
{ {
// Plastic // Plastic
Recipe recipe = new Recipe(6, false); Recipe recipe = new Recipe(6, false);
recipe.addInput(CrudeOil, 3); recipe.addInput(CrudeOil, 3);
recipe.addOutput(HeavyOilResidue, 1); recipe.addOutput(HeavyOilResidue, 1);
Plastic.add(recipe, 2); Plastic.add(recipe, 2);
Recipe residualPlastic = new Recipe(6, "Residual Plastic", false); Recipe residualPlastic = new Recipe(6, "Residual Plastic", false);
residualPlastic.addInput(PolymerResin, 6); residualPlastic.addInput(PolymerResin, 6);
residualPlastic.addInput(Water, 2); residualPlastic.addInput(Water, 2);
Plastic.add(residualPlastic, 2); Plastic.add(residualPlastic, 2);
Plastic.setPreference(recipe); Plastic.setPreference(recipe);
HeavyOilResidue.add(recipe); HeavyOilResidue.add(recipe);
HeavyOilResidue.setPreference(recipe); HeavyOilResidue.setPreference(recipe);
} }
{ {
// Rubber // Rubber
Recipe recipe = new Recipe(6, false); Recipe recipe = new Recipe(6, false);
recipe.addInput(CrudeOil, 3); recipe.addInput(CrudeOil, 3);
recipe.addOutput(HeavyOilResidue, 2); recipe.addOutput(HeavyOilResidue, 2);
Rubber.add(recipe, 2); Rubber.add(recipe, 2);
Recipe residualRubber = new Recipe(6, "Residual Rubber", false); Recipe residualRubber = new Recipe(6, "Residual Rubber", false);
residualRubber.addInput(PolymerResin, 6); residualRubber.addInput(PolymerResin, 6);
residualRubber.addInput(Water, 4); residualRubber.addInput(Water, 4);
Rubber.add(residualRubber, 2); Rubber.add(residualRubber, 2);
Rubber.setPreference(recipe); Rubber.setPreference(recipe);
HeavyOilResidue.add(recipe); HeavyOilResidue.add(recipe);
} }
{ {
// Petroleum Coke // Petroleum Coke
Recipe recipe = new Recipe(6, false); Recipe recipe = new Recipe(6, false);
recipe.addInput(HeavyOilResidue, 4); recipe.addInput(HeavyOilResidue, 4);
PetroleumCoke.add(recipe, 12); PetroleumCoke.add(recipe, 12);
} }
} }
public static void add(Item i) { public static void add(Item i) {
items.add(i); items.add(i);

View File

@ -67,28 +67,30 @@ public class Test {
System.out.println("\nSUM_reif"); System.out.println("\nSUM_reif");
Database.ReinforcedIronPlate.getRecipe().sum(Database.ReinforcedIronPlate, 100); Database.ReinforcedIronPlate.getRecipe().sum(Database.ReinforcedIronPlate, 100);
System.out.println("\nSUM_screw"); System.out.println("\nSUM_screw");
Graph<Item, ProductionEdge> screws100 = Database.Screw.getRecipe().sum(Database.Screw, 100); Graph<Item, ProductionEdge> screws100 = Database.Screw.getRecipe().sum(Database.Screw, 100).getProduction();
Graph<Item, ProductionEdge> computers100 = Database.Computer.getRecipe().sum(Database.Computer, 100); Graph<Item, ProductionEdge> computers100 = Database.Computer.getRecipe().sum(Database.Computer, 100).getProduction();
plot2(screws100, "screw_sum"); plot2(screws100, "screw_sum");
System.out.println("\nSUM_ACU"); System.out.println("\nSUM_ACU");
plot2(Database.AdaptiveControlUnit.getRecipe().sum(Database.AdaptiveControlUnit, 1), "acu4"); plot2(Database.AdaptiveControlUnit.getRecipe().sum(Database.AdaptiveControlUnit, 1).getProduction(), "acu4");
plot2(Utils.merge(screws100, computers100), "merged"); //plot2(SumResult.merge(screws100, computers100), "merged");
System.out.println("\n\nPHASE 3"); System.out.println("\n\nPHASE 3");
Graph<Item, ProductionEdge> phase3; Graph<Item, ProductionEdge> phase3;
//phase3 = Utils.sum(Database.VersatileFrameWork, 2500); //phase3 = Utils.sum(Database.VersatileFrameWork, 2500);
//phase3 = Utils.merge(phase3, Utils.sum(Database.ModularEngine,500)); //phase3 = Utils.merge(phase3, Utils.sum(Database.ModularEngine,500));
phase3 = Utils.sum(Database.ModularEngine,5); //phase3 = SumResult.sum(Database.ModularEngine,5);
phase3 = Utils.merge(phase3, Utils.sum(Database.AdaptiveControlUnit, 1)); //phase3 = SumResult.merge(phase3, SumResult.sum(Database.AdaptiveControlUnit, 1));
phase3 = SumResult.sum(new Production(Database.ModularEngine,5), new Production(Database.AdaptiveControlUnit,1)).getProduction();
plot2(phase3, "phase3"); plot2(phase3, "phase3");
System.out.println("\nrubber"); System.out.println("\nrubber");
plot2(Utils.sum(Database.Rubber, 75),"rubber"); plot2(SumResult.sum(Database.Rubber, 75),"rubber");
System.out.println("\ntest"); System.out.println("\ntest");
Utils.sum(Database.Plastic, 4); SumResult.sum(Database.Plastic, 4);
} }

View File

@ -15,6 +15,7 @@ import org.jgrapht.traverse.DepthFirstIterator;
import org.jgrapht.traverse.GraphIterator; import org.jgrapht.traverse.GraphIterator;
import satisfactory.items.Item; import satisfactory.items.Item;
import satisfactory.items.ProductionEdge; import satisfactory.items.ProductionEdge;
import satisfactory.items.SumResult;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
@ -23,112 +24,83 @@ import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Utils { public class Utils {
public static Map<Item, Integer> getRawOnly(Map<Item, Integer> totals) { public static Map<Item, Integer> getRawOnly(Map<Item, Integer> totals) {
Map<Item, Integer> raws = new HashMap<>(); 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).collect(Collectors.toList())) {
raws.put(item, totals.get(item)); raws.put(item, totals.get(item));
} }
return raws; return raws;
} }
public static <E extends Number> Map<String, E> shorten(Map<Item, E> totals) { public static <E extends Number> Map<String, E> shorten(Map<Item, E> totals) {
Map<String, E> shortend = new HashMap<>(); Map<String, E> shortend = new HashMap<>();
totals.forEach((item, e) -> shortend.put(item.getName(), e)); totals.forEach((item, e) -> shortend.put(item.getName(), e));
return shortend; return shortend;
} }
public static String dotID(Item item) { public static String dotID(Item item) {
String name = item.getName() + "_" + item.sum + "__" + (String.valueOf(item.getProductionRate()).replace(".", "_")); String name = item.getName() + "_" + item.sum + "__" + (String.valueOf(item.getProductionRate()).replace(".", "_"));
name = name.replace(" ", "").replace(".", ""); name = name.replace(" ", "").replace(".", "");
return name; return name;
} }
public static void fixSums(Item target, Graph<Item, DefaultWeightedEdge> graph) { public static void fixSums(Item target, Graph<Item, DefaultWeightedEdge> graph) {
System.err.println(target); System.err.println(target);
EdgeReversedGraph<Item, DefaultWeightedEdge> inverse = new EdgeReversedGraph<>(graph); EdgeReversedGraph<Item, DefaultWeightedEdge> inverse = new EdgeReversedGraph<>(graph);
GraphIterator<Item, DefaultWeightedEdge> iterator = new DepthFirstIterator<>(inverse, target); GraphIterator<Item, DefaultWeightedEdge> iterator = new DepthFirstIterator<>(inverse, target);
iterator.addTraversalListener(new TraversalListener<Item, DefaultWeightedEdge>() { iterator.addTraversalListener(new TraversalListener<Item, DefaultWeightedEdge>() {
@Override @Override
public void connectedComponentFinished(ConnectedComponentTraversalEvent e) { public void connectedComponentFinished(ConnectedComponentTraversalEvent e) {
System.out.println("\tconnectedComponentFinished: " + e); System.out.println("\tconnectedComponentFinished: " + e);
} }
@Override @Override
public void connectedComponentStarted(ConnectedComponentTraversalEvent e) { public void connectedComponentStarted(ConnectedComponentTraversalEvent e) {
System.out.println("\tconnectedComponentStarted: " + e); System.out.println("\tconnectedComponentStarted: " + e);
} }
@Override @Override
public void edgeTraversed(EdgeTraversalEvent<DefaultWeightedEdge> e) { public void edgeTraversed(EdgeTraversalEvent<DefaultWeightedEdge> e) {
System.out.println("\tedgeTraversed: " + e + "---> " + e.getEdge()); System.out.println("\tedgeTraversed: " + e + "---> " + e.getEdge());
} }
@Override @Override
public void vertexTraversed(VertexTraversalEvent<Item> e) { public void vertexTraversed(VertexTraversalEvent<Item> e) {
System.out.println("\tvertexTraversed: " + e + "---> " + e.getVertex().getName()); System.out.println("\tvertexTraversed: " + e + "---> " + e.getVertex().getName());
} }
@Override @Override
public void vertexFinished(VertexTraversalEvent<Item> e) { public void vertexFinished(VertexTraversalEvent<Item> e) {
System.out.println("\tvertexFinished: " + e); System.out.println("\tvertexFinished: " + e);
} }
}); });
while (iterator.hasNext()) { while (iterator.hasNext()) {
Item i = iterator.next(); Item i = iterator.next();
System.out.println(i.getName()); System.out.println(i.getName());
} }
} }
public static Graph<Item, ProductionEdge> merge(Graph<Item, ProductionEdge> graph0, Graph<Item, ProductionEdge> graph1) { public static void plot2(Graph<Item, ProductionEdge> sum, String filename) {
Graph<Item, ProductionEdge> result = new DefaultDirectedWeightedGraph<>(ProductionEdge.class); DOTExporter<Item, ProductionEdge> de = new DOTExporter<>(Item::ID);
de.setEdgeAttributeProvider(productionEdge -> {
Map<String, Attribute> m = new HashMap<>();
m.put("label", DefaultAttribute.createAttribute(productionEdge.label()));
return m;
});
de.setVertexAttributeProvider(item -> {
Map<String, Attribute> m = new HashMap<>();
if (item.isRaw()) {
m.put("peripheries", DefaultAttribute.createAttribute(2));
}
m.put("label", DefaultAttribute.createAttribute(item.getName()));
return m;
});
de.exportGraph(sum, new File(filename + ".dot"));
}
graph0.vertexSet().forEach(result::addVertex);
graph0.edgeSet().forEach(productionEdge -> result.addEdge(graph0.getEdgeSource(productionEdge), graph0.getEdgeTarget(productionEdge), productionEdge));
graph1.vertexSet().forEach(result::addVertex);
graph1.edgeSet().forEach(productionEdge -> {
List<ProductionEdge> collect = result.edgeSet().stream().filter(productionEdge1 -> productionEdge1.hasTarget(productionEdge.getTarget())).collect(Collectors.toList());
collect.forEach(edge -> {
Item src = result.getEdgeSource(edge);
Item target = result.getEdgeTarget(edge);
Item target2 = graph1.getEdgeTarget(productionEdge);
if (target != target2) {
result.addEdge(src, target2, productionEdge);
} else {
result.removeEdge(edge);
result.addEdge(src, target, edge);
}
});
if (collect.isEmpty()) {
result.addEdge(graph1.getEdgeSource(productionEdge), graph1.getEdgeTarget(productionEdge), productionEdge);
}
});
return result;
}
public static Graph<Item, ProductionEdge> sum(Item item, int amount) {
return item.getRecipe().sum(item,amount);
}
public static void plot2(Graph<Item, ProductionEdge> sum, String filename) {
DOTExporter<Item,ProductionEdge> de = new DOTExporter<>(Item::ID);
de.setEdgeAttributeProvider(productionEdge -> {
Map<String, Attribute> m = new HashMap<>();
m.put("label", DefaultAttribute.createAttribute(productionEdge.label()));
return m;
});
de.setVertexAttributeProvider(item -> {
Map<String,Attribute> m = new HashMap<>();
if (item.isRaw()) {
m.put("peripheries", DefaultAttribute.createAttribute(2));
}
return m;
});
de.exportGraph(sum, new File(filename+".dot"));
}
} }

View File

@ -0,0 +1,19 @@
package satisfactory.items;
public class Production {
private final Item item;
private final int amount;
public Production(Item item, int amount) {
this.item = item;
this.amount = amount;
}
public Item getItem() {
return item;
}
public int getAmount() {
return amount;
}
}

View File

@ -3,62 +3,77 @@ package satisfactory.items;
import java.util.Objects; import java.util.Objects;
public class ProductionEdge { public class ProductionEdge {
private Item source; private final Item source;
private double totalRequired; private final Item target;
private double instances; private double totalRequired;
private double instances;
public ProductionEdge(Item source,double totalRequired, double productionRate) { public ProductionEdge(Item source, Item target, double totalRequired, double productionRate) {
this.source=source; this.source = source;
this.totalRequired = totalRequired; this.target = target;
this.instances = productionRate; this.totalRequired = totalRequired;
} this.instances = productionRate;
public String label(){ }
//return "(" + totalRequired + "||" + instances + ")";
return "(%.2f||%.2f)".formatted(totalRequired,instances);
}
public double getTotalRequired() { public String label() {
return totalRequired; //return "(" + totalRequired + "||" + instances + ")";
} return "(%.2f||%.2f)".formatted(totalRequired, instances);
}
public void setTotalRequired(double totalRequired) { public void merge(ProductionEdge other) {
this.totalRequired = totalRequired; if (source.equals(other.getSource())) {
} totalRequired += other.getTotalRequired();
instances += other.getInstances();
}
}
public double getInstances() { public double getTotalRequired() {
return instances; return totalRequired;
} }
public void setInstances(double instances) { public void setTotalRequired(double totalRequired) {
this.instances = instances; this.totalRequired = totalRequired;
} }
public boolean hasTarget(Item t){ public double getInstances() {
return source.equals(t); return instances;
} }
@Override public void setInstances(double instances) {
public boolean equals(Object o) { this.instances = instances;
if (this == o) return true; }
if (o == null || getClass() != o.getClass()) return false;
ProductionEdge that = (ProductionEdge) o;
return Double.compare(that.totalRequired, totalRequired) == 0 && instances == that.instances && Objects.equals(source, that.source);
}
@Override public boolean hasSource(Item t) {
public int hashCode() { return source.equals(t);
return Objects.hash(source, totalRequired, instances); }
}
@Override @Override
public String toString() { public boolean equals(Object o) {
return "ProductionEdge{" + if (this == o) return true;
"totalRequired=" + totalRequired + if (o == null || getClass() != o.getClass()) return false;
", instances=" + instances + ProductionEdge that = (ProductionEdge) o;
'}'; return Objects.equals(source, that.source) && Objects.equals(target, that.target);
} }
public Item getTarget() { @Override
return source; public int hashCode() {
} return Objects.hash(source, target);
}
@Override
public String toString() {
return "ProductionEdge{" +
"source=" + source.getName() +
", totalRequired=" + totalRequired +
", instances=" + instances +
'}';
}
public Item getSource() {
return source;
}
public Item getTarget() {
return target;
}
} }

View File

@ -1,239 +1,240 @@
package satisfactory.items; package satisfactory.items;
import satisfactory.items.requirements.RateAccumulator;
import satisfactory.items.requirements.TotalAccumulator;
import org.jgrapht.Graph; import org.jgrapht.Graph;
import org.jgrapht.Graphs; import org.jgrapht.Graphs;
import org.jgrapht.graph.DefaultDirectedWeightedGraph; import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.DefaultWeightedEdge;
import satisfactory.items.requirements.RateAccumulator;
import satisfactory.items.requirements.TotalAccumulator;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Recipe { public class Recipe {
private final Map<Item, Integer> inputs; private final Map<Item, Integer> inputs;
private final Map<Item, Integer> outputs; private final Map<Item, Integer> outputs;
private boolean isHandCraftable = true; private boolean isHandCraftable = true;
private String name; private String name;
private final int duration; private final int duration;
public Recipe(int duration) { public Recipe(int duration) {
inputs = new HashMap<>(); inputs = new HashMap<>();
outputs = new HashMap<>(); outputs = new HashMap<>();
this.duration = duration; this.duration = duration;
} }
public Recipe(int duration, boolean isHandCraftable) { public Recipe(int duration, boolean isHandCraftable) {
this(duration); this(duration);
this.isHandCraftable = isHandCraftable; this.isHandCraftable = isHandCraftable;
} }
public Recipe(int duration, Item item, int input) { public Recipe(int duration, Item item, int input) {
this(duration); this(duration);
addInput(item, input); addInput(item, input);
} }
public Recipe(int duration, Map<Item, Integer> inputs, Map<Item, Integer> outputs) { public Recipe(int duration, Map<Item, Integer> inputs, Map<Item, Integer> outputs) {
this.duration = duration; this.duration = duration;
this.inputs = inputs; this.inputs = inputs;
this.outputs = outputs; this.outputs = outputs;
} }
public Recipe(int duration, String name, boolean isHandCraftable) { public Recipe(int duration, String name, boolean isHandCraftable) {
this(duration); this(duration);
this.name = name; this.name = name;
this.isHandCraftable = isHandCraftable; this.isHandCraftable = isHandCraftable;
} }
public static Map<String, Integer> getInputs(Map<Item, Integer> values) { public static Map<String, Integer> getInputs(Map<Item, Integer> values) {
Map<String, Integer> names = new HashMap<>(); Map<String, Integer> names = new HashMap<>();
for (Item item : values.keySet()) { for (Item item : values.keySet()) {
names.put(item.getName(), values.get(item)); names.put(item.getName(), values.get(item));
} }
return names; return names;
} }
public void addInput(Item item, int amount) { public void addInput(Item item, int amount) {
inputs.put(item, amount); inputs.put(item, amount);
} }
@Override @Override
public String toString() { public String toString() {
return "Recipe{" + return "Recipe{" +
"inputs=" + inputs + "inputs=" + inputs +
", outputs=" + formatIO(outputs) + ", outputs=" + formatIO(outputs) +
", isHandCraftable=" + isHandCraftable + ", isHandCraftable=" + isHandCraftable +
", name='" + name + '\'' + ", name='" + name + '\'' +
", duration=" + duration + ", duration=" + duration +
'}'; '}';
} }
public void addInput(Item input) { public void addInput(Item input) {
addInput(input, 1); addInput(input, 1);
} }
public void addOutput(Item item, int amount) { public void addOutput(Item item, int amount) {
this.outputs.put(item, amount); this.outputs.put(item, amount);
} }
public void checkOutput(Item item, int amount) { public void checkOutput(Item item, int amount) {
if (!(outputs.containsKey(item) && outputs.get(item) == amount)) { if (!(outputs.containsKey(item) && outputs.get(item) == amount)) {
outputs.put(item, amount); outputs.put(item, amount);
} }
} }
private String formatIO(Map<Item, Integer> map) { private String formatIO(Map<Item, Integer> map) {
StringBuilder sb = new StringBuilder("{"); StringBuilder sb = new StringBuilder("{");
map.forEach((item, integer) -> sb.append(item.getName()).append(": ").append(integer).append(", ")); map.forEach((item, integer) -> sb.append(item.getName()).append(": ").append(integer).append(", "));
return sb.append("}").toString(); return sb.append("}").toString();
} }
public Map<Item, Integer> getTotalRequirements() { public Map<Item, Integer> getTotalRequirements() {
return new TotalAccumulator(inputs).accumulate(); return new TotalAccumulator(inputs).accumulate();
} }
public float getProductionRate(Item item) { public float getProductionRate(Item item) {
float production = outputs.get(item); float production = outputs.get(item);
return (float) (production / (duration / 60.0)); return (float) (production / (duration / 60.0));
} }
public Map<Item, Float> getRequirementRates(Item item) { public Map<Item, Float> getRequirementRates(Item item) {
float rate = getProductionRate(item); float rate = getProductionRate(item);
return new RateAccumulator(this, item).accumulate(); return new RateAccumulator(this, item).accumulate();
} }
public Map<Item, Integer> getInputs() { public Map<Item, Integer> getInputs() {
return inputs; return inputs;
} }
public Graph<Item, DefaultWeightedEdge> buildGraph(Item target) { public Graph<Item, DefaultWeightedEdge> buildGraph(Item target) {
Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class); Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex(target); graph.addVertex(target);
target.sum += 1; target.sum += 1;
Map<Item, Integer> output = outputs.entrySet().stream() Map<Item, Integer> output = outputs.entrySet().stream()
.filter(itemIntegerEntry -> itemIntegerEntry.getKey() != target) .filter(itemIntegerEntry -> itemIntegerEntry.getKey() != target)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
output.forEach((item, integer) -> { output.forEach((item, integer) -> {
graph.addVertex(item); graph.addVertex(item);
graph.addEdge(target, item); graph.addEdge(target, item);
graph.setEdgeWeight(target, item, integer); graph.setEdgeWeight(target, item, integer);
}); });
inputs.forEach((item, integer) -> { inputs.forEach((item, integer) -> {
graph.addVertex(item); graph.addVertex(item);
graph.addEdge(item, target); graph.addEdge(item, target);
graph.setEdgeWeight(item, target, integer); graph.setEdgeWeight(item, target, integer);
Recipe recipe = item.getRecipe(); Recipe recipe = item.getRecipe();
if (recipe != null) { if (recipe != null) {
Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item); Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item);
Graphs.addGraph(graph, g); Graphs.addGraph(graph, g);
} }
}); });
return graph; return graph;
} }
private float getLoad(Item target, float amount) { private float getLoad(Item target, float amount) {
return getUsage(target, amount) * duration; return getUsage(target, amount) * duration;
} }
private float getUsage(Item target, float amount) { private float getUsage(Item target, float amount) {
return amount / outputs.get(target); return amount / outputs.get(target);
} }
public Graph<Item, DefaultWeightedEdge> buildGraph(Item target, float amountPerSecond) { public Graph<Item, DefaultWeightedEdge> buildGraph(Item target, float amountPerSecond) {
Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class); Graph<Item, DefaultWeightedEdge> graph = new DefaultDirectedWeightedGraph<>(DefaultWeightedEdge.class);
graph.addVertex(target); graph.addVertex(target);
target.sum += 1; target.sum += 1;
float load = getLoad(target, amountPerSecond); float load = getLoad(target, amountPerSecond);
// byproducts // byproducts
Map<Item, Integer> output = outputs.entrySet().stream() Map<Item, Integer> output = outputs.entrySet().stream()
.filter(itemIntegerEntry -> itemIntegerEntry.getKey() != target) .filter(itemIntegerEntry -> itemIntegerEntry.getKey() != target)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
output.forEach((item, integer) -> { output.forEach((item, integer) -> {
graph.addVertex(item); graph.addVertex(item);
graph.addEdge(target, item); graph.addEdge(target, item);
graph.setEdgeWeight(target, item, integer * load); graph.setEdgeWeight(target, item, integer * load);
}); });
// inputs // inputs
inputs.forEach((item, integer) -> { inputs.forEach((item, integer) -> {
graph.addVertex(item); graph.addVertex(item);
graph.addEdge(item, target); graph.addEdge(item, target);
float rate = (amountPerSecond / outputs.get(target)) / integer; float rate = (amountPerSecond / outputs.get(target)) / integer;
graph.setEdgeWeight(item, target, rate); graph.setEdgeWeight(item, target, rate);
Recipe recipe = item.getRecipe(); Recipe recipe = item.getRecipe();
if (recipe != null) { if (recipe != null) {
Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item, rate); Graph<Item, DefaultWeightedEdge> g = recipe.buildGraph(item, rate);
Graphs.addGraph(graph, g); Graphs.addGraph(graph, g);
} }
}); });
return graph; return graph;
} }
private double processesNeeded(Item target, double n) { private double processesNeeded(Item target, double n) {
Recipe r = target.getRecipe(); Recipe r = target.getRecipe();
return n / r.getProductionRate(target); return n / r.getProductionRate(target);
} }
public Graph<Item, ProductionEdge> sum(Item target, int prodPerMinute) { public SumResult sum(Item target, int prodPerMinute) {
Graph<Item, DefaultWeightedEdge> buildGraph = buildGraph(target); Graph<Item, DefaultWeightedEdge> buildGraph = buildGraph(target);
Graph<Item, ProductionEdge> production = new DefaultDirectedWeightedGraph<>(ProductionEdge.class); Graph<Item, ProductionEdge> production = new DefaultDirectedWeightedGraph<>(ProductionEdge.class);
Map<Item, Double> map = new HashMap<>(); Map<Item, Double> map = new HashMap<>();
Queue<Item> queue = new LinkedList<>(); Queue<Item> queue = new LinkedList<>();
queue.add(target); queue.add(target);
map.put(target, (double) prodPerMinute); map.put(target, (double) prodPerMinute);
production.addVertex(target); production.addVertex(target);
production.addEdge(target, target, new ProductionEdge(target, prodPerMinute, processesNeeded(target, prodPerMinute))); production.addEdge(target, target, new ProductionEdge(target, target, prodPerMinute, processesNeeded(target, prodPerMinute)));
while (!queue.isEmpty()) { while (!queue.isEmpty()) {
Item item = queue.remove(); Item item = queue.remove();
// next satisfactory.items // next items
buildGraph.incomingEdgesOf(item) buildGraph.incomingEdgesOf(item)
.stream() .stream()
.map(buildGraph::getEdgeSource) .map(buildGraph::getEdgeSource)
.forEach(queue::add); .forEach(queue::add);
// *this* item // *this* item
double sum = 0; double sum = 0;
Set<Item> byProducts = new HashSet<>(); Set<Item> byProducts = new HashSet<>();
for (DefaultWeightedEdge edge : buildGraph.outgoingEdgesOf(item)) { for (DefaultWeightedEdge edge : buildGraph.outgoingEdgesOf(item)) {
Item product = buildGraph.getEdgeTarget(edge); Item product = buildGraph.getEdgeTarget(edge);
Double productWantedPerMinute = map.get(product); Double productWantedPerMinute = map.get(product);
if (item.getRecipe().outputs.containsKey(product)){ if (item.getRecipe().outputs.containsKey(product)) {
// product is by-product, no forward dependency // product is by-product, no forward dependency
byProducts.add(product); byProducts.add(product);
continue; continue;
} }
if (productWantedPerMinute == null) { if (productWantedPerMinute == null) {
sum = 0; sum = 0;
break; break;
} }
double amountNeeded = buildGraph.getEdgeWeight(edge); double amountNeeded = buildGraph.getEdgeWeight(edge);
int productPerProcess = product.getRecipe().outputs.get(product); int productPerProcess = product.getRecipe().outputs.get(product);
double requiredProcesRuns = productWantedPerMinute / productPerProcess; double requiredProcesRuns = productWantedPerMinute / productPerProcess;
double requiredInput = amountNeeded * requiredProcesRuns; double requiredInput = amountNeeded * requiredProcesRuns;
sum += requiredInput; sum += requiredInput;
production.addVertex(item);
production.addEdge(item, product, new ProductionEdge(item, product, requiredInput, processesNeeded(item, requiredInput)));
}
if (!map.containsKey(item) && sum > 0) {
map.put(item, sum);
}
if (!byProducts.isEmpty()) {
byProducts.forEach(item1 -> {
production.addVertex(item1);
// TODO: calculate produced amount
production.addEdge(item, item1, new ProductionEdge(item, item1, 0, 0));
});
}
}
map.forEach((item, aDouble) -> {
System.out.println(item.getName() + ": " + aDouble);
});
return new SumResult(production, map);
}
production.addVertex(item);
production.addEdge(item, product, new ProductionEdge(item, requiredInput, processesNeeded(item, requiredInput)));
}
if (!map.containsKey(item) && sum > 0) {
map.put(item, sum);
}
if (!byProducts.isEmpty()) {
byProducts.forEach(item1 -> {
production.addVertex(item1);
// TODO: calculate produced amount
production.addEdge(item, item1, new ProductionEdge(item, 0,0));
});
}
}
map.forEach((item, aDouble) -> {
System.out.println(item.getName() + ": " + aDouble);
});
return production;
}
} }

View File

@ -0,0 +1,81 @@
package satisfactory.items;
import org.jgrapht.Graph;
import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SumResult {
private final Graph<Item, ProductionEdge> production;
private final Map<Item, Double> map;
public SumResult(Graph<Item, ProductionEdge> production, Map<Item, Double> map) {
this.production = production;
this.map = map;
}
public SumResult() {
production = new DefaultDirectedWeightedGraph<>(ProductionEdge.class);
map = new HashMap<>();
}
public Graph<Item, ProductionEdge> getProduction() {
return production;
}
public Map<Item, Double> getMap() {
return map;
}
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));
return new SumResult(merge(production, other.getProduction()), map);
}
public static Graph<Item, ProductionEdge> sum(Item item, int amount) {
return item.getRecipe().sum(item, amount).getProduction();
}
public static SumResult sum(Production... productions) {
return Arrays.stream(productions)
.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) {
// ToDo: test!
Graph<Item, ProductionEdge> result = new DefaultDirectedWeightedGraph<>(ProductionEdge.class);
graph0.vertexSet().forEach(result::addVertex);
graph0.edgeSet().forEach(productionEdge -> result.addEdge(graph0.getEdgeSource(productionEdge), graph0.getEdgeTarget(productionEdge), productionEdge));
graph1.vertexSet().forEach(result::addVertex);
graph1.edgeSet().forEach(productionEdge -> {
List<ProductionEdge> collect = result.edgeSet().stream()
.filter(productionEdge1 -> productionEdge1.hasSource(productionEdge.getSource()))
.collect(Collectors.toList());
collect.forEach(edge -> {
Item src = result.getEdgeSource(edge);
Item target = result.getEdgeTarget(edge);
Item target2 = graph1.getEdgeTarget(productionEdge);
if (target != target2) {
result.addEdge(src, target2, productionEdge);
} else {
/*result.removeEdge(edge);
result.addEdge(src, target, edge);*/
edge.merge(productionEdge);
}
});
if (collect.isEmpty()) {
result.addEdge(graph1.getEdgeSource(productionEdge), graph1.getEdgeTarget(productionEdge), productionEdge);
}
});
return result;
}
}

View File

@ -1,27 +1,28 @@
package satisfactory.items; package satisfactory.items;
import org.jgrapht.Graph;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import satisfactory.Database;
import satisfactory.Utils;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.fail;
import satisfactory.Database;
class ItemTest { class ItemTest {
@Test @Test
void productionScrews() { 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(100, production.get(Database.Screw), "Screws (output)");
assertEquals(25, production.get(Database.IronRod), "IronRod"); assertEquals(25, production.get(Database.IronRod), "IronRod");
assertEquals(25, production.get(Database.IronIngot), "IronIngot"); assertEquals(25, production.get(Database.IronIngot), "IronIngot");
assertEquals(25, production.get(Database.IronOre), "IronOre"); assertEquals(25, production.get(Database.IronOre), "IronOre");
} }
@Test @Test
void productionScrews2() { void productionScrews2() {
/*Map<Item, Double> production = Database.Screw.getRecipe().sum(Database.Screw, 100); /*Map<Item, Double> production = Database.Screw.getRecipe().sum(Database.Screw, 100);
assertEquals(100, production.get(Database.Screw), "Screws (output)"); assertEquals(100, production.get(Database.Screw), "Screws (output)");
assertEquals(25, production.get(Database.IronRod), "IronRod"); assertEquals(25, production.get(Database.IronRod), "IronRod");
@ -29,23 +30,71 @@ class ItemTest {
assertEquals(25, production.get(Database.IronOre), "IronOre"); assertEquals(25, production.get(Database.IronOre), "IronOre");
*/ */
fail("TODO: migrate"); fail("TODO: migrate");
} }
@Test @Test
void productionReinforcedIronPlates() { 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(100, production.get(Database.ReinforcedIronPlate), "output");
assertEquals(1200, production.get(Database.Screw), "Screws"); assertEquals(1200, production.get(Database.Screw), "Screws");
assertEquals(300, production.get(Database.IronRod), "IronRod"); assertEquals(300, production.get(Database.IronRod), "IronRod");
assertEquals(1200, production.get(Database.IronIngot), "IronIngot"); assertEquals(1200, production.get(Database.IronIngot), "IronIngot");
assertEquals(1200, production.get(Database.IronOre), "IronOre"); assertEquals(1200, production.get(Database.IronOre), "IronOre");
assertEquals(600, production.get(Database.IronPlate), "IronPlate"); assertEquals(600, production.get(Database.IronPlate), "IronPlate");
} }
@Test @Test
void testScrewProd(){ void testScrewProd() {
float productionRate = Database.Screw.getRecipe().getProductionRate(Database.Screw); float productionRate = Database.Screw.getRecipe().getProductionRate(Database.Screw);
assertEquals(40, productionRate); assertEquals(40, productionRate);
} }
@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);
// calculate
Map<Item, Double> calculations = SumResult.sum(new Production(Database.ModularEngine, 5), new Production(Database.AdaptiveControlUnit, 1)).getMap();
// assert
ref.forEach((item, amount) -> {
assertTrue(calculations.containsKey(item), "exists? " + item.getName());
assertEquals(amount, calculations.get(item), 0.01, item.getName());
});
}
} }