using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; namespace AoC { internal class Day8 { private enum Instruction { ACC, JMP, NOP } private record Command(Instruction ins, int value); private ImmutableDictionary InstructionFromString = new Dictionary { { "acc", Instruction.ACC }, { "jmp", Instruction.JMP }, { "nop", Instruction.NOP } }.ToImmutableDictionary(); private Regex rx = new(@"^(?\w+) (?(\+|\-)\d+)"); private bool DoesItLoop(List commands, int index, ref int accumulator) { ISet commandIndices = new HashSet(); while (index >= 0 && index < commands.Count && !commandIndices.Contains(index)) { commandIndices.Add(index); var command = commands[index]; (accumulator, index) = command.ins switch { Instruction.ACC => (accumulator + command.value, index + 1), Instruction.JMP => (accumulator, index + command.value), Instruction.NOP => (accumulator, index + 1), _ => throw new ArgumentException("Du doofer Hund!") }; } return commandIndices.Contains(index); } internal void Solve() { var readLines = File.ReadAllText("day8/input").Split("\n", StringSplitOptions.RemoveEmptyEntries); Command LineToCommandSelector(string line) { var groups = rx.Match(line).Groups; return new Command(InstructionFromString[groups["ins"].Value], int.Parse(groups["value"].Value)); } var commands = readLines.Select(LineToCommandSelector).ToList(); SortedSet commandIndices = new SortedSet(); int index = 0; int accumulator = 0; while (!commandIndices.Contains(index)) { commandIndices.Add(index); var command = commands[index]; (accumulator, index) = command.ins switch { Instruction.ACC => (accumulator + command.value, index + 1), Instruction.JMP => (accumulator, index + command.value), Instruction.NOP => (accumulator, index + 1), _ => throw new ArgumentException("Du doofer Hund!") }; } Console.WriteLine(accumulator); foreach (var commandIndex in commandIndices.Reverse()) { index = 0; accumulator = 0; if (commands[commandIndex].ins == Instruction.ACC) { continue; } if (commands[commandIndex].ins == Instruction.JMP) { commands[commandIndex] = new Command(Instruction.NOP, commands[commandIndex].value); if (!DoesItLoop(commands, index, ref accumulator)) { break; } commands[commandIndex] = new Command(Instruction.JMP, commands[commandIndex].value); } else { commands[commandIndex] = new Command(Instruction.JMP, commands[commandIndex].value); if (!DoesItLoop(commands, index, ref accumulator)) { break; } commands[commandIndex] = new Command(Instruction.NOP, commands[commandIndex].value); } } Console.WriteLine(accumulator); } private record Info(int index, int accumulator); private static void ExecuteInstruction(List commands, ref int index, ref int accumulator) { var command = commands[index]; (accumulator, index) = command.ins switch { Instruction.ACC => (accumulator + command.value, index + 1), Instruction.JMP => (accumulator, index + command.value), Instruction.NOP => (accumulator, index + 1), _ => throw new ArgumentException("Du doofer Hund!") }; } private bool DoesItLoop(List commands, int index, ref int accumulator, ISet visitedInstructions) { while (index >= 0 && index < commands.Count && !visitedInstructions.Contains(index)) { visitedInstructions.Add(index); ExecuteInstruction(commands, ref index, ref accumulator); } return visitedInstructions.Contains(index); } internal void SolveOn() { var readLines = File.ReadAllText("day8/input").Split("\n", StringSplitOptions.RemoveEmptyEntries); Command LineToCommandSelector(string line) { var groups = rx.Match(line).Groups; return new Command(InstructionFromString[groups["ins"].Value], int.Parse(groups["value"].Value)); } var commands = readLines.Select(LineToCommandSelector).ToList(); ISet commandIndices = new HashSet(); Stack commandInfo = new Stack(); int index = 0; int accumulator = 0; while (!commandIndices.Contains(index)) { commandIndices.Add(index); commandInfo.Push(new Info(index, accumulator)); ExecuteInstruction(commands, ref index, ref accumulator); } Console.WriteLine(accumulator); Instruction switchInstruction(Instruction ins) => ins == Instruction.NOP ? Instruction.JMP : Instruction.NOP; int tempAccumulator = -1; while (commandInfo.Count > 0) { var current = commandInfo.Pop(); if (commands[current.index].ins == Instruction.ACC) { continue; } commands[current.index] = new Command(switchInstruction(commands[current.index].ins), commands[current.index].value); tempAccumulator = current.accumulator; commandIndices.Remove(current.index); if (!DoesItLoop(commands, current.index, ref tempAccumulator, commandIndices)) { break; } commands[current.index] = new Command(switchInstruction(commands[current.index].ins), commands[current.index].value); } Console.WriteLine(tempAccumulator); } } }