using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace _2020 { class Q08 { static readonly List> instructions = new List>(); public static void Go() { MakeList(); Part1(); Part2(); } static void MakeList() { foreach (var line in File.ReadAllLines("08input.txt")) { var parts = line.Split(' '); if (parts.Length != 2) { throw new Exception("malformed input"); } instructions.Add(new Tuple(parts[0], Convert.ToInt32(parts[1]))); } } static void ProcessInstruction(List> inst, ref int i, ref int accum) { switch (inst[i].Item1) { case "acc": accum += inst[i].Item2; i++; break; case "jmp": i += inst[i].Item2; break; case "nop": i++; break; } } static Tuple RunProgram(List> program) { var accum = 0; var executed = new Dictionary(); for (var i = 0; ;) { if (program.Count <= i) { return new Tuple(accum, true); } if (executed.ContainsKey(i)) { break; } executed.Add(i, 1); ProcessInstruction(program, ref i, ref accum); } return new Tuple(accum, false); } static void Part1() { var result = RunProgram(instructions); if (result.Item2) { throw new Exception("Exited normally - shouldn't have"); } Util.Log($"Q08Part1: accum value={result.Item1}"); } static void Part2() { // should probably have used RunProgram here, but ended up replacing the first-encountered instruction instead of // moving through the program and changing the first unchanged instruction i came across. this seemed possibly // more efficient? i don't know. bool bExited = false; var instructionToChange = "jmp"; var instructionToReplace = "nop"; var replacedInstructions = new List(); var accum = 0; while (!bExited) { accum = 0; var copy = new List>(instructions); var executed = new Dictionary(); bool bChanged = false; for (var i = 0; ;) { if (copy.Count <= i) { bExited = true; break; } if (executed.ContainsKey(i)) { if (!bChanged) { // this whole section is hacky if (instructionToChange != "jmp") { throw new Exception("nothing worked"); } Util.Log($"changing {instructionToChange} to {instructionToReplace} didn't work - flipping"); var tmp = instructionToChange; instructionToChange = instructionToReplace; instructionToReplace = tmp; replacedInstructions = new List(); } break; } executed.Add(i, 1); if (copy[i].Item1 == instructionToChange && !bChanged && !replacedInstructions.Contains(i)) { replacedInstructions.Add(i); bChanged = true; copy[i] = new Tuple(instructionToReplace, copy[i].Item2); } ProcessInstruction(copy, ref i, ref accum); } } Util.Log($"Q08Part2: accum value={accum}"); } } }