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); } }