using System; using System.Collections.Generic; using System.Text; namespace AdventOfCode { public static class IntcodeComputer { public static (int[] opcodes, List output) Run(int[] opcodes, int? noun = null, int? verb = null, int[]? input = null) { opcodes[1] = noun ?? opcodes[1]; opcodes[2] = verb ?? opcodes[2]; List output = new List(); int ptr = 0; int inputPtr = 0; while (opcodes[ptr] != 99) { int GetOpcode(int opcode, Mode mode) => mode switch { Mode.Position => opcodes[opcode], Mode.Immediate => opcode, _ => throw new Exception() }; bool jumped = false; Mode paramOne = opcodes[ptr] / 100 % 10 == 0 ? Mode.Position : Mode.Immediate; Mode paramTwo = opcodes[ptr] / 1000 == 0 ? Mode.Position : Mode.Immediate; int code = opcodes[ptr] % 100; switch (code) { case 1: // Add { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); opcodes[opcodes[ptr + 3]] = x + y; break; } case 2: // Multiply { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); opcodes[opcodes[ptr + 3]] = x * y; break; } case 3: // Read input if (input != null) { opcodes[opcodes[ptr + 1]] = inputPtr < input.Length ? input[inputPtr] : int.Parse(Console.ReadLine()); inputPtr++; break; } opcodes[opcodes[ptr + 1]] = int.Parse(Console.ReadLine()); break; case 4: // Output { output.Add(GetOpcode(opcodes[ptr + 1], paramOne)); break; } case 5: // Jump if true { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); if (x != 0) { ptr = y; jumped = true; }; break; } case 6: // Jump if false { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); if (x == 0) { ptr = y; jumped = true; }; break; } case 7: // Less than { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); opcodes[opcodes[ptr + 3]] = x < y ? 1 : 0; break; } case 8: // Equal to { int x = GetOpcode(opcodes[ptr + 1], paramOne); int y = GetOpcode(opcodes[ptr + 2], paramTwo); opcodes[opcodes[ptr + 3]] = x == y ? 1 : 0; break; } case 99: throw new Exception("Skipped an exit code"); default: throw new Exception("Unknown opcode encountered"); } if (!jumped) { ptr += InstructionLength[code]; } } return (opcodes, output); } private static readonly Dictionary InstructionLength = new Dictionary() { // Instruction number, How far to move the ptr {1, 4 }, {2, 4 }, {3, 2 }, {4, 2 }, {5, 3 }, {6, 3 }, {7, 4 }, {8, 4 }, }; private enum Mode { Position = 0, Immediate = 1 } } }