Files
AdventOfCode/2022/Day11CSharp/Program.cs
2025-11-30 20:28:10 -05:00

320 lines
8.7 KiB
C#

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<Monkey> Monkeys { get; set; }
private bool AutoDropWorry { get; set; }
public Simulation(List<Monkey> monkeys)
{
Monkeys = monkeys;
}
public BigInteger MonkeyBusiness
{
get
{
var list = new List<Monkey>(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<BigInteger>();
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<BigInteger> Items { get; set; } = new List<BigInteger>();
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<Monkey> LoadMonkeys(string filename)
{
List<Monkey> monkeys = new List<Monkey>();
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;
}
}