public async Task <IntcodeProgramResult> RunProgram(IntcodeProgramInput programInput) { CurrentMemory = new long[InitialMemory.Length * 100]; InitialMemory.CopyTo(CurrentMemory, 0); programInput.MemoryInitialisation(CurrentMemory); InstructionPointer = 0; RelativeBase = 0; Exited = false; Errored = false; Paused = false; Inputs.Clear(); programInput.Inputs.ForEach(AddInput); while (!Exited) { var operationCode = (int)(((CurrentMemory[InstructionPointer] / (decimal)100) - Math.Floor(CurrentMemory[InstructionPointer] / (decimal)100)) * (decimal)100); var matchedOperations = AvailableOperations.Where(op => op.Code == operationCode); if (matchedOperations.Count() == 0) { Exited = true; Errored = true; } else if (matchedOperations.Count() == 1) { try { var operationResult = await matchedOperations.Single().RunOperation(InstructionPointer, CurrentMemory, RelativeBase, GetNextInput); Exited |= operationResult.Exit; if (operationResult.Output.HasValue) { AddOutput(operationResult.Output.Value); } if (operationResult.JumpTo.HasValue) { InstructionPointer = operationResult.JumpTo.Value; } else { InstructionPointer += (1 + (ulong)matchedOperations.Single().ParameterCount); } if (operationResult.AdjustRelativeBase.HasValue) { RelativeBase = RelativeBase + operationResult.AdjustRelativeBase.Value; } } catch (IntcodeOperationException ex) { Exited = true; Errored = true; } } else { throw new Exception("Multiple operation definitions for operation code: " + CurrentMemory[InstructionPointer]); } } var finalMemState = new long[InitialMemory.Length * 100]; CurrentMemory.CopyTo(finalMemState, 0); List <long> finalOutputs; lock (OutputLock) { finalOutputs = Outputs.CloneAsList().ToList(); } return(new IntcodeProgramResult(!Errored, finalMemState, finalOutputs)); }