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());
            }
        }
Beispiel #2
0
        /// <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);
        }