public static int[] Run(IEnumerable <int> program, InputHandler input = null, OutputHandler output = null, Logger logger = null) { if (input == null) { input = () => int.Parse(Console.ReadLine()); } if (output == null) { output = (val) => Console.WriteLine(val); } var memory = program.ToArray(); var pctr = 0; bool running = true; while (running) { var instr = memory[pctr]; void log(string message) => logger?.Invoke($"{instr}: {message}"); switch (instr % 100) { case 1: { var x1 = resolveParam(0, pctr, memory); var x2 = resolveParam(1, pctr, memory); var pout = memory[pctr + 3]; var result = x1 + x2; memory[pout] = result; pctr += 4; log($"Set {pout} to {x1}+{x2}={result}"); break; } case 2: { var x1 = resolveParam(0, pctr, memory); var x2 = resolveParam(1, pctr, memory); var pout = memory[pctr + 3]; var result = x1 * x2; memory[pout] = result; pctr += 4; log($"Set {pout} to {x1}*{x2}={result}"); break; } case 3: { var pout = memory[pctr + 1]; var val = input(); memory[pout] = val; pctr += 2; log($"Set {pout} to (input) {val}"); break; } case 4: { var x = resolveParam(0, pctr, memory); output(x); pctr += 2; log($"Output {x}"); break; } case 5: { var x = resolveParam(0, pctr, memory); if (x != 0) { pctr = resolveParam(1, pctr, memory); log($"{x} != 0; jumping to {pctr}"); } else { log($"{x} == 0; noop"); pctr += 3; } break; } case 6: { var x = resolveParam(0, pctr, memory); if (x == 0) { pctr = resolveParam(1, pctr, memory); log($"{x} == 0; jumping to {pctr}"); } else { log($"{x} != 0; noop"); pctr += 3; } break; } case 7: { var x1 = resolveParam(0, pctr, memory); var x2 = resolveParam(1, pctr, memory); var pOut = memory[pctr + 3]; var result = (x1 < x2) ? 1 : 0; memory[pOut] = result; log($"Set {pOut} to {result} ({x1} < {x2}?)"); pctr += 4; break; } case 8: { var x1 = resolveParam(0, pctr, memory); var x2 = resolveParam(1, pctr, memory); var pOut = memory[pctr + 3]; var result = (x1 == x2) ? 1 : 0; memory[pOut] = result; log($"Set {pOut} to {result} ({x1} = {x2}?)"); pctr += 4; break; } case 99: { running = false; log($"Stopping"); break; } default: throw new Exception($"Unknown instr {instr}"); } } return(memory); }