|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
|
|
|
namespace AdventOfCode
|
|
|
|
|
{
|
|
|
|
|
public static class IntcodeComputer
|
|
|
|
|
{
|
|
|
|
|
public static (int[] opcodes, List<int> output) Run(int[] opcodes, int? noun = null, int? verb = null, int[]? input = null)
|
|
|
|
|
{
|
|
|
|
|
opcodes[1] = noun ?? opcodes[1];
|
|
|
|
|
opcodes[2] = verb ?? opcodes[2];
|
|
|
|
|
|
|
|
|
|
List<int> output = new List<int>();
|
|
|
|
|
|
|
|
|
|
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<int, int> InstructionLength = new Dictionary<int, int>()
|
|
|
|
|
{
|
|
|
|
|
// 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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|