private long produce(Chemical chemical, long amount) { if (chemical.Name == "FUEL") { foreach (Chemical chemicalClean in chemicals) { chemicalClean.AmountAvailable = 0; } } long oreAmount = 0; if (chemical.AmountAvailable >= amount) { chemical.AmountAvailable -= amount; return(oreAmount); } if (chemical.AmountAvailable > 0) { amount -= chemical.AmountAvailable; chemical.AmountAvailable = 0; } long amountOfReactions; if (amount <= chemical.ReactionToProduce.Output.Item2) { amountOfReactions = 1; } else { amountOfReactions = amount / chemical.ReactionToProduce.Output.Item2; if (amount % chemical.ReactionToProduce.Output.Item2 != 0) { amountOfReactions += 1; } } foreach (var input in chemical.ReactionToProduce.Inputs) { long amountNeeded = input.Value * amountOfReactions; if (input.Key.Name == "ORE") { oreAmount += amountNeeded; } else { oreAmount += this.produce(input.Key, amountNeeded); } } chemical.AmountAvailable += amountOfReactions * chemical.ReactionToProduce.Output.Item2; chemical.AmountAvailable -= amount; return(oreAmount); }
public Chemical getChemical(string name) { Chemical chemical = chemicals.FirstOrDefault(x => x.Name == name); if (chemical == null) { chemical = new Chemical() { Name = name }; chemicals.Add(chemical); } return(chemical); }
public string ComputePartTwo(string[] input) { surplus = new ChemicalsStore(); reactions = input.Select(i => Reaction.Parse(i)).ToList(); var fuel = new Chemical { Name = "FUEL", Quantity = 1 }; var oreGoal = 1000000000000; var orePerFuel = CalculateOreNeeded(fuel); var fuelGuess = oreGoal / orePerFuel; var mostValidGuess = fuelGuess; var fuelGuessFactor = fuelGuess / 2; long result; while ((result = CalculateOreNeeded(fuel * fuelGuess)) < oreGoal) { mostValidGuess = fuelGuess; if (result == oreGoal) { return($"{result}"); } Console.WriteLine($"Failed with guess {fuelGuess} - {fuelGuessFactor} and result {result}/{oreGoal}"); while (CalculateOreNeeded(fuel * (fuelGuessFactor + fuelGuess)) > oreGoal) { fuelGuessFactor /= 2; } if (fuelGuessFactor == 0) { fuelGuessFactor = 1; } fuelGuess += fuelGuessFactor; } return($"{mostValidGuess}"); }
public long CalculateOreNeeded(Chemical product) { var reaction = reactions.First(r => r.CanReverseReact(product)); var availableProduct = surplus.Withdraw(product.Name, product.Quantity); var productNeeded = product.Quantity - availableProduct; var wishFactor = (long)Math.Ceiling((double)Math.Max(productNeeded, 0) / (double)reaction.OutputQuantity); var bonusProduct = (long)(reaction.OutputQuantity * wishFactor - productNeeded); if (!product.IsOre()) { surplus.Deposit(product.Name, bonusProduct); } var requiredOre = 0L; foreach (var reactant in reaction.Input) { requiredOre += reactant.IsOre() ? wishFactor * reactant.Quantity : CalculateOreNeeded(reactant * wishFactor); } return(requiredOre); }
public override async Task Run() { string[] lines = File.ReadAllLines("Data/Day14.txt"); //lines = File.ReadAllLines("Data/Day14Part1Example1.txt"); //lines = File.ReadAllLines("Data/Day14Part1Example2.txt"); //lines = File.ReadAllLines("Data/Day14Part1Example3.txt"); //lines = File.ReadAllLines("Data/Day14Part1Example4.txt"); //lines = File.ReadAllLines("Data/Day14Part1Example5.txt"); foreach (string line in lines) { string[] lineSplitted = line.Split("=>"); Dictionary <Chemical, long> inputs = lineSplitted[0].Trim().Split(",").Select(x => { string[] inputSplitted = x.Trim().Split(" ", StringSplitOptions.RemoveEmptyEntries); Chemical chemical = this.getChemical(inputSplitted[1].Trim()); return(new Tuple <Chemical, long>(chemical, long.Parse(inputSplitted[0]))); }).ToDictionary(x => x.Item1, x => x.Item2); string[] outputSplitted = lineSplitted[1].Trim().Split(" ", StringSplitOptions.RemoveEmptyEntries); Tuple <Chemical, long> output = new Tuple <Chemical, long>(this.getChemical(outputSplitted[1].Trim()), long.Parse(outputSplitted[0])); Reaction reaction = new Reaction() { Inputs = inputs, Output = output }; if (reaction.Inputs.Count == 1 && reaction.Inputs.First().Key.Name == "ORE") { reaction.IsOre = true; } output.Item1.ReactionToProduce = reaction; this.reactions.Add(reaction); } //foreach (var reaction in reactions) //{ // Console.WriteLine(reaction.ToString()); //} Tuple <Chemical, long> chemicalFuel = reactions.First(x => x.Output.Item1.Name == "FUEL").Output; long oreAmount = this.produce(chemicalFuel.Item1, chemicalFuel.Item2); Console.WriteLine("Part 1: " + oreAmount); long oreAmountTotal = 1000000000000; long bsMax = 1; long bsMin = 0; long bsMid; while (true) { long oreAmountCurrent = this.produce(chemicalFuel.Item1, bsMax); if (oreAmountCurrent < oreAmountTotal) { bsMax *= 2; } else { break; } } while (bsMin < bsMax) { bsMid = (bsMin + bsMax) / 2; if (this.produce(chemicalFuel.Item1, bsMid) <= oreAmountTotal) { bsMin = bsMid + 1; } else { bsMax = bsMid; } } Console.WriteLine("Part 2: " + (bsMin - 1)); }
public static Reaction Parse(string data) { var membersData = data.Split("=>"); return(new Reaction(membersData[0].Split(',').Select(m => Chemical.Parse(m)).ToArray(), Chemical.Parse(membersData[1]))); }
public bool CanReverseReact(Chemical chemical) { return(output.Name.Equals(chemical.Name)); }
public Reaction(Chemical[] input, Chemical output) { this.input = input; this.output = output; }