From 380eeda47b9e560691c8af69332fae7498266de9 Mon Sep 17 00:00:00 2001 From: Eveldee Date: Fri, 24 Jan 2025 10:19:12 +0100 Subject: [PATCH] Add day 17 --- Days/Day17.cs | 247 +++++++++++++++++++++++++++++++++++++++++++++++ Inputs/Day17.txt | 5 + 2 files changed, 252 insertions(+) create mode 100644 Days/Day17.cs create mode 100644 Inputs/Day17.txt diff --git a/Days/Day17.cs b/Days/Day17.cs new file mode 100644 index 0000000..9ad405b --- /dev/null +++ b/Days/Day17.cs @@ -0,0 +1,247 @@ +using System.Numerics; +using Spectre.Console; + +namespace AdventOfCode.Days; + +public class Day17 : Day +{ + public override int Number => 17; + public override string Name => "Chronospatial Computer"; + + public override void RunPart1(bool display = true) + { + var (registerA, registerB, registerC, program) = ParseState(); + + var toOutput = new List(); + var instructionPointer = 0; + + while (instructionPointer < program.Length) + { + var opCode = program[instructionPointer]; + + var isComboOperand = opCode switch + { + 0 => true, + 1 => false, + 2 => true, + 3 => false, + 4 => false, + 5 => true, + 6 => true, + 7 => true, + _ => throw new ArgumentOutOfRangeException(nameof(opCode)) + }; + + var operand = (isComboOperand, program[instructionPointer + 1]) switch + { + (false, var literalValue) => literalValue, + (true, 0) => 0, + (true, 1) => 1, + (true, 2) => 2, + (true, 3) => 3, + (true, 4) => registerA, + (true, 5) => registerB, + (true, 6) => registerC, + _ => throw new ArgumentOutOfRangeException() + }; + + switch (opCode) + { + // adv + case 0: + registerA = (int)(registerA / Math.Pow(2, operand)); + break; + + // bxl + case 1: + registerB = registerB ^ operand; + break; + + // bst + case 2: + registerB = operand % 8; + break; + + // jnz + case 3: + if (registerA is not 0) + { + instructionPointer = operand - 2; + } + break; + + // bxc + case 4: + registerB = registerB ^ registerC; + break; + + // out + case 5: + toOutput.Add(operand % 8); + break; + + // bdv + case 6: + registerB = (int)(registerA / Math.Pow(2, operand)); + break; + + // cdv + case 7: + registerC = (int)(registerA / Math.Pow(2, operand)); + break; + } + + instructionPointer += 2; + } + + if (display) + { + AnsiConsole.MarkupLine($"[green]Output: [yellow]{string.Join(',', toOutput)}[/][/]"); + } + } + + public override void RunPart2(bool display = true) + { + var (_, originalRegisterB, originalRegisterC, program) = ParseState(); + var toOutput = new List(); + var instructionPointer = 0; + + var finalRegisterA = 0; + + AnsiConsole.Status().Start("Computing (0)...", ctx => + { + for (var initialRegisterA = 0; initialRegisterA < int.MaxValue; initialRegisterA++) + { + // Reset state + var registerA = initialRegisterA; + var registerB = originalRegisterB; + var registerC = originalRegisterC; + + toOutput.Clear(); + instructionPointer = 0; + + while (instructionPointer < program.Length) + { + var opCode = program[instructionPointer]; + + var isComboOperand = opCode switch + { + 0 => true, + 1 => false, + 2 => true, + 3 => false, + 4 => false, + 5 => true, + 6 => true, + 7 => true, + _ => throw new ArgumentOutOfRangeException(nameof(opCode)) + }; + + var operand = (isComboOperand, program[instructionPointer + 1]) switch + { + (false, var literalValue) => literalValue, + (true, 0) => 0, + (true, 1) => 1, + (true, 2) => 2, + (true, 3) => 3, + (true, 4) => registerA, + (true, 5) => registerB, + (true, 6) => registerC, + _ => throw new ArgumentOutOfRangeException() + }; + + switch (opCode) + { + // adv + case 0: + registerA = (int)(registerA / Math.Pow(2, operand)); + break; + + // bxl + case 1: + registerB = registerB ^ operand; + break; + + // bst + case 2: + registerB = operand % 8; + break; + + // jnz + case 3: + if (registerA is not 0) + { + instructionPointer = operand - 2; + } + break; + + // bxc + case 4: + registerB = registerB ^ registerC; + break; + + // out + case 5: + toOutput.Add(operand % 8); + break; + + // bdv + case 6: + registerB = (int)(registerA / Math.Pow(2, operand)); + break; + + // cdv + case 7: + registerC = (int)(registerA / Math.Pow(2, operand)); + break; + } + + instructionPointer += 2; + } + + if (initialRegisterA % 1000 == 0) + { + ctx.Status($"Computing ({initialRegisterA})..."); + } + + // Check if output is the program itself + if (toOutput.SequenceEqual(program)) + { + finalRegisterA = initialRegisterA; + + break; + } + } + }); + + if (display) + { + AnsiConsole.MarkupLine($"[green]Lowest possible value for register A to output itself: [yellow]{finalRegisterA}[/][/]"); + } + } + + private (int RegisterA, int RegisterN, int RegisterC, int[] Program) ParseState() + { + var lineIterator = Input.AsSpan().EnumerateLines(); + + lineIterator.MoveNext(); + var registerA = int.Parse(lineIterator.Current[(lineIterator.Current.IndexOf(':') + 2)..]); + + lineIterator.MoveNext(); + var registerB = int.Parse(lineIterator.Current[(lineIterator.Current.IndexOf(':') + 2)..]); + + lineIterator.MoveNext(); + var registerC = int.Parse(lineIterator.Current[(lineIterator.Current.IndexOf(':') + 2)..]); + + lineIterator.MoveNext(); + lineIterator.MoveNext(); + + var program = lineIterator.Current[(lineIterator.Current.IndexOf(':') + 2)..] + .ToString() + .Split(',') + .Select(int.Parse) + .ToArray(); + + return (registerA, registerB, registerC, program); + } +} \ No newline at end of file diff --git a/Inputs/Day17.txt b/Inputs/Day17.txt new file mode 100644 index 0000000..31bb2d3 --- /dev/null +++ b/Inputs/Day17.txt @@ -0,0 +1,5 @@ +Register A: 44348299 +Register B: 0 +Register C: 0 + +Program: 2,4,1,5,7,5,1,6,0,3,4,2,5,5,3,0 \ No newline at end of file