using System; using System.Numerics; Part01(); Console.WriteLine(); Part02(); void Part01() { Console.WriteLine("!! === Part 1 === !!"); var exampleMonkeys = Monkey.LoadMonkeys("example-input.txt"); var puzzleMonkeys = Monkey.LoadMonkeys("puzzle-input.txt"); Simulation exampleSim = new Simulation(exampleMonkeys); Simulation puzzleSim = new Simulation(puzzleMonkeys); Console.WriteLine(" === Example ==="); exampleSim.ProcessRound(20); exampleSim.PrintMonkeys(); Console.WriteLine("Monkey business: " + exampleSim.MonkeyBusiness); Console.WriteLine(); Console.WriteLine(" === Puzzle ==="); puzzleSim.ProcessRound(20); puzzleSim.PrintMonkeys(); Console.WriteLine("Monkey business: " + puzzleSim.MonkeyBusiness); } void Part02() { Console.WriteLine("!! === Part 2 === !!"); var exampleMonkeys = Monkey.LoadMonkeys("example-input.txt"); var puzzleMonkeys = Monkey.LoadMonkeys("puzzle-input.txt"); Simulation exampleSim = new Simulation(exampleMonkeys); Simulation puzzleSim = new Simulation(puzzleMonkeys); Console.WriteLine(" === Example ==="); exampleSim.ProcessRound(10000, false, true); exampleSim.PrintMonkeys(); Console.WriteLine("Monkey business: " + exampleSim.MonkeyBusiness); Console.WriteLine(); Console.WriteLine(" === Puzzle ==="); puzzleSim.ProcessRound(10000, false, true); puzzleSim.PrintMonkeys(); Console.WriteLine("Monkey business: " + puzzleSim.MonkeyBusiness); } class Simulation { private List Monkeys { get; set; } private bool AutoDropWorry { get; set; } public Simulation(List monkeys) { Monkeys = monkeys; } public BigInteger MonkeyBusiness { get { var list = new List(Monkeys); list.Sort(); BigInteger left = list[list.Count - 1].InspectedCount; BigInteger right = list[list.Count - 2].InspectedCount; return left * right; } } public void ProcessRound(int rounds = 1, bool part01 = true, bool printProgress = false) { int mod = Monkeys[0].Test.divisibility; for (int i = 1 ; i < Monkeys.Count; i++) { mod *= Monkeys[i].Test.divisibility; } if (printProgress) { Console.Write("Processing: "); Console.Out.Flush(); } for (int round = 0; round < rounds; round++) { if (printProgress && round % 100 == 0) { Console.Write(String.Format("{0}%..", (float)round / rounds * 100)); Console.Out.Flush(); } foreach (Monkey m in Monkeys) { var oldItemList = m.Items; m.Items = new List(); m.InspectedCount += oldItemList.Count; foreach (var item in oldItemList) { var i = item; // Worry operation i = m.Operation.GetNewValue(i); // Bored if (part01) i /= 3; else i = i % mod; // Test int dest = m.Test.DoTest(i); Monkeys[dest].Items.Add(i); } } } if (printProgress) Console.WriteLine("..Done!"); } public void PrintMonkeys() { for (int i = 0; i < Monkeys.Count; i++) { Console.Write(String.Format("Monkey {0} Inspected({1}), Items: ", i, Monkeys[i].InspectedCount)); bool first = true; foreach (var item in Monkeys[i].Items) { if (!first) { Console.Write(", "); } first = false; Console.Write(item); } Console.WriteLine(); } } } class Operation { public Operation(char op, string value) { this.op = op; this.value = value; } public BigInteger GetNewValue(BigInteger worryLevel) { BigInteger realVal; if (!BigInteger.TryParse(value, out realVal)) { realVal = worryLevel; } switch (op) { case '+': return worryLevel + realVal; case '-': return worryLevel - realVal; case '*': return worryLevel * realVal; case '/': return worryLevel / realVal; default: throw new InvalidDataException(); } } public static Operation Parse(string line) { if (!line.Trim().StartsWith("Operation:")) throw new InvalidDataException(); var split = line.Split('=')[1].Split(' ', StringSplitOptions.RemoveEmptyEntries); char op = split[1][0]; string value = split[2]; return new Operation(op, value); } private char op; private string value; } class Test { public Test(string[] line) { if (line.Length != 3) { throw new InvalidDataException(); } string[] split; // Get the divis by val split = line[0].Split(' '); divisibility = Int32.Parse(split[split.Length - 1]); // True split = line[1].Split(' '); trueMonkeyTarget = Int32.Parse(split[split.Length - 1]); // False split = line[2].Split(' '); falseMonkeyTarget = Int32.Parse(split[split.Length - 1]); } public int divisibility { get; set; } private int trueMonkeyTarget { get; set; } private int falseMonkeyTarget { get; set; } public int DoTest(BigInteger worryLevel) { if (worryLevel % divisibility == 0) { return trueMonkeyTarget; } else { return falseMonkeyTarget; } } } class Monkey : IComparable { public List Items { get; set; } = new List(); public Operation Operation { get; set; } public Test Test { get; set; } public int InspectedCount { get; set; } = 0; public Monkey(string[] lines) { for (int i = 0; i < lines.Length; i++) { string line = lines[i]; if (line.Trim().StartsWith("Operation:")) { Operation = Operation.Parse(line); } else if (line.Trim().StartsWith("Starting items:")) { var entries = line.Split(':')[1].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); foreach (var entry in entries) { int val = int.Parse(entry); Items.Add(val); } } else if (line.Trim().StartsWith("Test:")) { string[] testLines = new string[3]; testLines[0] = line; testLines[1] = lines[i+1]; testLines[2] = lines[i+2]; Test = new Test(testLines); } } if (Operation == null || Test == null) throw new InvalidDataException(); } public static List LoadMonkeys(string filename) { List monkeys = new List(); using (StreamReader reader = System.IO.File.OpenText(filename)) { while (!reader.EndOfStream) { string? line = reader.ReadLine(); if (line == null) throw new InvalidDataException(); if (line.StartsWith("Monkey")) { string[] lines = new string[5]; for (int i = 0; i < lines.Length; i++) { string? newLine = reader.ReadLine(); if (newLine == null) throw new InvalidDataException(); lines[i] = newLine; } monkeys.Add(new Monkey(lines)); } } } return monkeys; } public int CompareTo(object? obj) { if (obj == null) throw new InvalidDataException(); Monkey Temp = (Monkey)obj; if (this.InspectedCount < Temp.InspectedCount) return -1; if (this.InspectedCount > Temp.InspectedCount) return 1; else return 0; } }