public IntcodeProgramStatus RunProgram() { IntcodeProgramStatus status = IntcodeProgramStatus.Running; while (true) { LogDebugMessage($"Pos: {_position.ToString("0000")}, Cmd: {_program[_position]}"); var parsedCommand = ParseCommand(_program[_position]); var opcode = parsedCommand[0]; if (opcode == 1) { // Add param1 + param2, store in address pointed to by param3 var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); var val3 = GetParameterWritePosition(_position + 3, 3, parsedCommand); SetMemoryValue(val3, val1 + val2); _position += 4; } else if (opcode == 2) { // Multiply param1 * param2, store in address pointed to by param3 var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); var val3 = GetParameterWritePosition(_position + 3, 3, parsedCommand); SetMemoryValue(val3, val1 * val2); _position += 4; } else if (opcode == 3) { // Take user input, and store in the parameter location // If the input provider doesn't have any input, // then pause the program and return awaiting input status if (!_inputProvider.HasInput()) { status = IntcodeProgramStatus.AwaitingInput; break; } BigInteger input = _inputProvider.GetInput(); var val1 = GetParameterWritePosition(_position + 1, 1, parsedCommand); SetMemoryValue(val1, input); _position += 2; } else if (opcode == 4) { // Output a value var val1 = GetParameterValue(_position + 1, 1, parsedCommand); _outputListener.SendOutput(val1); _position += 2; } else if (opcode == 5) { // Opcode 5 is jump-if-true: if the first parameter is // non-zero, it sets the instruction pointer to the value // from the second parameter. Otherwise, it does nothing. var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); if (val1 != 0) { _position = GetMemoryAddress(val2); } else { _position += 3; } } else if (opcode == 6) { // Opcode 6 is jump-if-false: if the first parameter is // zero, it sets the instruction pointer to the value from // the second parameter. Otherwise, it does nothing. var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); if (val1 == 0) { _position = GetMemoryAddress(val2); } else { _position += 3; } } else if (opcode == 7) { // Opcode 7 is less than: if the first parameter is less // than the second parameter, it stores 1 in the position // given by the third parameter. // Otherwise, it stores 0. var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); var val3 = GetParameterWritePosition(_position + 3, 3, parsedCommand); var valToStore = val1 < val2 ? 1 : 0; SetMemoryValue(val3, valToStore); _position += 4; } else if (opcode == 8) { // Opcode 8 is equals: if the first parameter is equal to // the second parameter, it stores 1 in the position given // by the third parameter. // Otherwise, it stores 0. var val1 = GetParameterValue(_position + 1, 1, parsedCommand); var val2 = GetParameterValue(_position + 2, 2, parsedCommand); var val3 = GetParameterWritePosition(_position + 3, 3, parsedCommand); var valToStore = val1 == val2 ? 1 : 0; SetMemoryValue(val3, valToStore); _position += 4; } else if (opcode == 9) { // Opcode 9 adjusts the relative base by the value of its // only parameter. The relative base increases (or // decreases, if the value is negative) by the value of the // parameter. // For example, if the relative base is 2000, then after // the instruction 109,19, the relative base would be 2019. // If the next instruction were 204,-34, then the value at // address 1985 would be output. var val1 = GetParameterValue(_position + 1, 1, parsedCommand); _relativeBase += GetMemoryAddress(val1); _position += 2; } else if (opcode == 99) { status = IntcodeProgramStatus.Completed; break; } else if (opcode != 99) { throw new Exception($"Invalid opcode {_program[_position]} at position {_position}"); } } return(status); }