You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.0 KiB

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
}
}
}