public void AddHaltingRule_GivenValidRule_HaltsInExpectedState( Func <IJumpmanCPU, bool> rule, IEnumerable <IOperation> program, int expectedProgramCounter, int expectedAccumulator, bool expectedHalt, IOperation expectedLastOperation, IEnumerable <ICPUState> expectedTrace, bool expectedTermination ) { var sut = new JumpmanCPU(program); Assert.Equal(program, sut.Program); sut.AddHaltingRule(rule); sut.RunProgram(); Assert.Equal(expectedProgramCounter, sut.ProgramCounter); Assert.Equal(expectedAccumulator, sut.Accumulator); Assert.Equal(expectedHalt, sut.Halt); Assert.Equal(expectedLastOperation, sut.LastOperation); Assert.Equal(expectedTermination, sut.TerminatedNormally); Assert.Equal(expectedTrace.Count(), sut.Trace.Count()); for (var i = 0; i < expectedTrace.Count(); i++) { Assert.Equal(expectedTrace.Skip(i).First(), sut.Trace.Skip(i).First()); } }
/// <summary> /// JumpMan.Cmd entry point /// </summary> /// <param name="args">Command line arguments (not used)</param> static void Main(string[] args) { var filePath = "./input"; var reader = new FileReader(); var program = reader .ReadFileByLines(filePath) .Select(operation => new Operation(operation)); var cpu = new JumpmanCPU(program); cpu.AddHaltingRule( (cpu) => cpu .Trace .Select(trace => trace.ProgramCounter) .Where(counter => counter == cpu.ProgramCounter) .Count() > 0 ); cpu.RunProgram(); Console.WriteLine(cpu.Accumulator); // We can patch the program by editing one instruction from a nop to a jump or vice versa. // The program ends normaly by having the ProgramCounter exceed the length of the program. // So detect when that happens. var arrayProgram = program.ToArray <IOperation>(); IOperation oldOperation; for (var i = 0; i < arrayProgram.Length; i++) { if (arrayProgram[i].OpCode == OpCode.jmp || arrayProgram[i].OpCode == OpCode.nop) { oldOperation = arrayProgram[i]; var sign = oldOperation.Argument >= 0 ? "+" : string.Empty; if (arrayProgram[i].OpCode == OpCode.jmp) { arrayProgram[i] = new Operation(string.Format("nop {0}{1}", sign, oldOperation.Argument)); } else { arrayProgram[i] = new Operation(string.Format("jmp {0}{1}", sign, oldOperation.Argument)); } cpu.LoadNewProgram(arrayProgram); cpu.RunProgram(); if (cpu.TerminatedNormally) { // we did it! break; } else { arrayProgram[i] = oldOperation; } } } Console.WriteLine(cpu.Accumulator); }
public void LoadNewProgram_GivenValidProgram_SetsProgramAsExpected(IEnumerable <IOperation> program) { var sut = new JumpmanCPU(new IOperation[] { }); sut.LoadNewProgram(program); Assert.Equal(program, sut.Program); }
public void Constructor_GivenValidProgram_SetsValuesAsExpected(IEnumerable <IOperation> program) { var sut = new JumpmanCPU(program); Assert.Equal(program, sut.Program); Assert.Equal(0, sut.ProgramCounter); Assert.Equal(0, sut.Accumulator); Assert.False(sut.Halt); Assert.Null(sut.LastOperation); Assert.Empty(sut.Trace); }
public void LoadNewProgram_GivenInvalidProgram_ThrowsException() { var sut = new JumpmanCPU(new IOperation[] { }); var program = new IOperation[] { OpCodeUtility.MockOperation(OpCode.debug, 0) }; var exception = Assert.Throws <ArgumentException>(() => sut.LoadNewProgram(program)); Assert.StartsWith("The Opcodes: \"debug\" are not supported.", exception.Message); }