320 lines
8.7 KiB
C#
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;
|
|
}
|
|
}
|