using System.Collections.Generic;
public static void Main()
var stock = new Dictionary<Product, int> {
RunAdvFab(Battery, stock, 1000);
static void RunAdvFab(Product order, Dictionary<Product, int> stock, double time)
Dump("In stock:", stock);
var tempStock = new Dictionary<Product, int>(stock);
var inputs = new Dictionary<Product, int>(order.OreCost);
var savedTime = CalcJob(order, null, tempStock, inputs);
var timeCost = order.OreBuildTime - savedTime;
var repetitions = inputs.Where(req => req.Value > 0).Min(req => stock[req.Key] / req.Value);
repetitions = Math.Min(repetitions, (int)(time / timeCost));
Console.WriteLine("Making " + order.Name + " x" + repetitions + " for " + (timeCost * repetitions) + "s total");
time -= timeCost * repetitions;
Console.WriteLine("Time left: " + time);
canBuild = repetitions > 0;
AddItems(stock, order, repetitions);
foreach(var item in inputs)
stock[item.Key] -= item.Value * repetitions;
static double CalcJob(Product order, int? amount, Dictionary<Product, int> stock, Dictionary<Product, int> inputs)
var subAmount = amount.HasValue ? amount.Value : 1;
foreach(var req in order.Requirements)
var available = stock.ContainsKey(req.Key) ? stock[req.Key] : 0;
var needed = req.Value * subAmount;
var used = Math.Min(available, needed);
Console.WriteLine("Using " + used + " " + req.Key.Name + ", saved " + (req.Key.OreBuildTime * used) + "s");
foreach(var ore in req.Key.OreCost)
if (inputs.ContainsKey(ore.Key))
inputs[ore.Key] -= ore.Value * used;
Dump("Missing " + ore.Key.Name, inputs);
savedTime += req.Key.OreBuildTime * used;
AddItems(inputs, req.Key, used);
savedTime += CalcJob(req.Key, needed - used, stock, inputs);
Console.WriteLine("Making " + subAmount + " " + order.Name);
static void AddItems(Dictionary<Product, int> stock, Product item, int amount)
if (!stock.ContainsKey(item))
static void Dump(string title, Dictionary<Product, int> stock)
Console.WriteLine(title);
foreach(var item in stock)
Console.WriteLine(item.Value + " " + item.Key.Name);
public readonly string Name;
public readonly Dictionary<Product, int> Requirements;
public readonly double BuildTime;
public readonly Dictionary<Product, int> OreCost;
public readonly double OreBuildTime;
get { return this.Requirements == null; }
public Product(string name, double buildTime, Dictionary<Product, int> requirements) {
this.BuildTime = buildTime;
this.Requirements = requirements;
this.OreCost = new Dictionary<Product, int>();
foreach(var req in requirements)
AddItems(OreCost, req.Key, req.Value);
foreach(var subOre in req.Key.OreCost)
AddItems(OreCost, subOre.Key, req.Value * subOre.Value);
time += req.Key.OreBuildTime * req.Value;
this.OreBuildTime = time;
static Product IronOre = new Product("iron ore", 0, null);
static Product CopperOre = new Product("copper ore", 0, null);
static Product IronIngot = new Product("iron ingot", 15, new Dictionary<Product, int> {
static Product CopperIngot = new Product("copper ingot", 15, new Dictionary<Product, int> {
static Product CopperWire = new Product("copper wire", 15, new Dictionary<Product, int> {
static Product Battery = new Product("battery", 30, new Dictionary<Product, int> {