diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/IntCodeVM.cs | 132 |
1 files changed, 88 insertions, 44 deletions
diff --git a/lib/IntCodeVM.cs b/lib/IntCodeVM.cs index de2b98a..92cd539 100644 --- a/lib/IntCodeVM.cs +++ b/lib/IntCodeVM.cs @@ -1,22 +1,25 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; namespace aoc2019.lib { public class IntCodeVM { - private int i; - public List<int> v; - public Queue<int> input, output; - private readonly List<int> program; + private long i; + private long relbase; + public long[] memory; + private readonly long[] program; + public Queue<long> input, output; - public IntCodeVM(List<int> tape) + public IntCodeVM(List<long> tape) { i = 0; - program = tape; - v = tape; - input = new Queue<int>(); - output = new Queue<int>(); + relbase = 0; + program = tape.ToArray(); + memory = tape.ToArray(); + input = new Queue<long>(); + output = new Queue<long>(); } public enum HaltType @@ -25,66 +28,107 @@ namespace aoc2019.lib Waiting } - enum Op : int - { - ADD = 1, MUL = 2, INPUT = 3, OUTPUT = 4, JMP = 5, JNE = 6, LT = 7, EQ = 8, HALT = 99 - } - public void Reset() { i = 0; - v = program; + relbase = 0; + memory = program; input.Clear(); output.Clear(); } - public int Result => output.Dequeue(); + public long Result => output.Dequeue(); - public HaltType Run(params int[] additionalInput) + private long MemGet(long addr) { - foreach (var i in additionalInput) input.Enqueue(i); - return Run(); + return addr < memory.Length ? memory[addr] : 0; } - public HaltType Run() + + private void MemSet(long addr, long value) { - while (i < v.Count) + if (addr < 0) addr = 0; + if (addr >= memory.Length) + Array.Resize(ref memory, (int)addr + 1); + memory[addr] = value; + } + + private long Mode(long idx) + { + var mode = MemGet(i) / 100; + for (var s = 1; s < idx; s++) + mode /= 10; + return mode % 10; + } + + private long Get(long idx) + { + var param = MemGet(i + idx); + switch (Mode(idx)) { - int Val(int mode, int val) => - mode == 0 ? v[val] : val; + case 0: return MemGet(param); + case 1: return param; + case 2: return MemGet(relbase + param); + default: throw new Exception("invalid parameter mode"); + } + } - int Val1() => Val(v[i] / 100 % 10, v[i + 1]); - int Val2() => Val(v[i] / 1000, v[i + 2]); + private void Set(long idx, long val) + { + var param = MemGet(i + idx); + switch (Mode(idx)) + { + case 0: MemSet(param, val); break; + case 1: throw new Exception("cannot set in immediate mode"); + case 2: MemSet(relbase + param, val); break; + default: throw new Exception("invalid parameter mode"); + } + } - switch ((Op)(v[i] % 100)) + public HaltType Run(params long[] additionalInput) + { + foreach (var s in additionalInput) input.Enqueue(s); + return Run(); + } + public HaltType Run() + { + while (i < memory.Length) + { + var op = MemGet(i) % 100; + switch (op) { - case Op.ADD: - v[v[i + 3]] = Val1() + Val2(); + case 1: + Set(3, Get(1) + Get(2)); i += 4; break; - case Op.MUL: - v[v[i + 3]] = Val1() * Val2(); + case 2: + Set(3, Get(1) * Get(2)); i += 4; break; - case Op.INPUT: + case 3: if (!input.Any()) return HaltType.Waiting; - v[v[i + 1]] = input.Dequeue(); + Set(1, input.Dequeue()); i += 2; break; - case Op.OUTPUT: - output.Enqueue(Val1()); + case 4: + output.Enqueue(Get(1)); i += 2; break; - case Op.JMP: - i = Val1() == 0 ? i + 3 : Val2(); + case 5: + i = Get(1) == 0 ? i + 3 : Get(2); break; - case Op.JNE: - i = Val1() != 0 ? i + 3 : Val2(); + case 6: + i = Get(1) != 0 ? i + 3 : Get(2); break; - case Op.LT: - v[v[i + 3]] = Val1() < Val2() ? 1 : 0; + case 7: + Set(3, Get(1) < Get(2) ? 1 : 0); i += 4; break; - case Op.EQ: - v[v[i + 3]] = Val1() == Val2() ? 1 : 0; + case 8: + Set(3, Get(1) == Get(2) ? 1 : 0); i += 4; break; - case Op.HALT: + case 9: + relbase += Get(1); + i += 2; break; + case 99: return HaltType.Terminate; + default: + throw new Exception($"unknown op {op} at {i}"); } } |