def test_reset(self): """ Tests for CPU reset """ e = ElfCPU() e.load_string('1,0,0,0,99') e.execute() e.reset() # Halted gets cleared self.assertFalse(e.is_halted) # Program counter goes to 0 self.assertEqual(e.pc, 0) # Memory gets wiped so address 1 becomes invalid with self.assertRaises(ValueError): e.peek(1)
def test_halt(self): """ Tests for the halt op code """ e = ElfCPU() e.load_string('1,0,0,0,99') e.step() self.assertFalse(e.is_halted) e.step() self.assertTrue(e.is_halted)
def test_invalid_instr(self): """ Tests for invalid op code """ e = ElfCPU() e.load_string('123456789') with self.assertRaises(InvalidInstructionError): e.execute()
def test_gpf(self): """ Tests for a general protection fault by allowing the program counter to go past the end of the memory """ e = ElfCPU() e.load_string('1,0,0,0') with self.assertRaises(ProtectionFaultError): e.execute()
def test_load_string_types(self): """ Checks for TypeError """ e = ElfCPU() with self.assertRaises(TypeError): # noinspection PyTypeChecker e.load_string(0) e.load_string('1,2,3,4')
def test_op_add(self): """ Tests ADD op code [dst]:=[a]+[b] """ e = ElfCPU() # Invalid address 44 for a e.load_string('1,44,0,0') with self.assertRaises(ProtectionFaultError): e.step() # Invalid address 44 for b e.load_string('1,0,44,0') with self.assertRaises(ProtectionFaultError): e.step() # Invalid address 44 for dst e.load_string('1,0,0,44') with self.assertRaises(ProtectionFaultError): e.step() # 1 + 1 = 2 @ address 0 e.load_string('1,0,0,0,99') e.step() self.assertEqual(e.peek(0), 2) # 2**64 + 1 = 1 @ address 0 (overflow and wrap) #e.load_string('1,5,6,0,99,'+str(2**64)+',1') #e.step() #self.assertEqual(e.peek(0), 1) # dst:=a+[b] e.load_string('101,44,5,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 46) # dst:=[a]+b e.load_string('1001,5,50,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 52) # dst:=a+b e.load_string('1101,5,5,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 10)
def test_poke(self): """ Tests address range and data for poke """ e = ElfCPU() e.load_string('0,1,2,3,4,5,6,7,8,9') # Address with self.assertRaises(TypeError): # noinspection PyTypeChecker e.poke('x', 2) with self.assertRaises(ValueError): e.poke(20, 2) with self.assertRaises(ValueError): e.poke(-1, 2) # Value with self.assertRaises(ValueError): e.poke(0, 2**64 + 1) self.assertEqual(e.poke(0, 99), 99) self.assertEqual(e.poke(9, 88), 88) self.assertEqual(e.peek(0), 99) self.assertEqual(e.peek(9), 88)
def test_peek(self): """ Tests address range for peek """ e = ElfCPU() e.load_string('0,1,2,3,4,5,6,7,8,9') with self.assertRaises(TypeError): # noinspection PyTypeChecker e.peek('x') with self.assertRaises(ValueError): e.peek(20) with self.assertRaises(ValueError): e.peek(-1) self.assertEqual(e.peek(0), 0) self.assertEqual(e.peek(9), 9)
def test_op_eq(self): """ Tests equals op code """ e = ElfCPU() """ Tests if value of address 5 (10) is equal to value of address 6 (10). Since this is true, write 1 to address 7. """ e.load_string('8,5,6,7,99,10,10,-1') e.execute() self.assertEqual(e.peek(7), 1) """ Tests if value of address 5 (10) is equal to value of address 6 (0). Since this is false, write 0 to address 7. """ e.load_string('8,5,6,7,99,10,0,-1') e.execute() self.assertEqual(e.peek(7), 0) """ Tests if immediate value 10 is equal to immediate value 10. Since this is true, write 1 to address 7. """ e.load_string('1108,10,10,7,99,2,3,-1') e.execute() self.assertEqual(e.peek(7), 1) """ Tests if immediate value of 0 is equal to immediate value 10. Since this is false, write 0 to address 7. """ e.load_string('1108,0,10,7,99,2,3,-1') e.execute() self.assertEqual(e.peek(7), 0)
def test_op_cmp_lessthan(self): """ Tests compare less than op code """ e = ElfCPU() """ Tests if value of address 5 (5) is less than value of address 6 (10). Since this is true write 1 to address 7. """ e.load_string('7,5,6,7,99,5,10,-1') e.execute() self.assertEqual(e.peek(7), 1) """ Tests if value of address 5 (10) is less than value of address 6 (5). Since this is false write 0 to address 7. """ e.load_string('7,5,6,7,99,10,5,-1') e.execute() self.assertEqual(e.peek(7), 0) """ Tests if immediate value of 5 is less than immediate value of 10. Since this is true write 1 to address 7. """ e.load_string('1107,5,10,7,99,0,0,-1') e.execute() self.assertEqual(e.peek(7), 1) """ Tests if immediate value of 10 is less than immediate value of 5. Since this is false write 0 to address 7. """ e.load_string('1107,10,5,7,99,0,0,-1') e.execute() self.assertEqual(e.peek(7), 0)
def test_op_jmp_true(self): """ Tests jump if true op code """ e = ElfCPU() """ Tests address 8 (which is 1) if it is non-zero. Since this is true, it jumps to the value of address 9 (which is 7). This terminates the program. """ e.load_string('5,8,9,1101,1,1,8,99,1,7') e.execute() self.assertEqual(e.peek(8), 1) """ Tests immediate value 8 if it is non-zero. Since it is true, jump to immediate address 7 which terminates. """ e.load_string('1105,8,7,1101,1,1,8,99,1,7') e.execute() self.assertEqual(e.peek(8), 1) """ Tests address 8 (which is 0) if it is non-zero. Since this is false it does not jump and instead adds 1+1 to address 8. """ e.load_string('5,8,9999,1101,1,1,8,99,0,7') e.execute() self.assertEqual(e.peek(8), 2) """ Tests immediate value 0 if it is non-zero. Since it is false it does not jump and instead adds 1+1 to address 8. """ e.load_string('1105,0,9999,1101,1,1,8,99,0,7') e.execute() self.assertEqual(e.peek(8), 2)
def test_op_output(self): """ Tests output op code Use io.StringIO() to capture the output """ e = ElfCPU() # Interrupts off e.load_string('4,5,104,66,99,55') e.interrupts = False result = None with patch('sys.stdout', new=io.StringIO()) as output: e.execute() result = output.getvalue() result = result.splitlines() # First is a reference to memory address 5 self.assertEqual(result[0].strip(), '55') # Second is an immediate value self.assertEqual(result[1].strip(), '66') # Interrupts on e.load_string('4,5,104,66,99,55') e.interrupts = True with self.assertRaises(OutputInterrupt): e.execute() self.assertEqual(e.output_buffer, 55) # Don't clear buffer with self.assertRaises(OutputOverflow): e.execute() # Restart test e.reset() e.load_string('4,5,104,66,99,55') e.interrupts = True with self.assertRaises(OutputInterrupt): e.execute() self.assertEqual(e.output_buffer, 55) # Clear buffer del e.output_buffer with self.assertRaises(OutputInterrupt): e.execute() self.assertEqual(e.output_buffer, 66)
def test_op_input(self): """ Tests input op code Use unittest.mock.patch to fake the input value """ e = ElfCPU() # Interrupts off e.load_string('3,3,99,-1') e.interrupts = False with patch('builtins.input', return_value='1234'): e.execute() self.assertEqual(e.peek(3), 1234) # Interrupts on e.load_string('3,5,3,5,99,-1') e.interrupts = True with self.assertRaises(InputInterrupt): e.step() # Should be back at pc = 0 self.assertEqual(e.pc, 0) # Load input e.input_buffer = 567 # Loading again overflows with self.assertRaises(InputOverflow): e.input_buffer = 123 # Execute the input instruction e.step() self.assertEqual(e.peek(5), 567) # Exec next input instruction with self.assertRaises(InputInterrupt): e.step() e.input_buffer = 987 # Execute until end e.execute() self.assertEqual(e.peek(5), 987)
def test_op_mul(self): """ Tests MUL op code [dst]:=[a]*[b] """ e = ElfCPU() # Invalid address 44 for a e.load_string('2,44,0,0') with self.assertRaises(ProtectionFaultError): e.step() # Invalid address 44 for b e.load_string('2,0,44,0') with self.assertRaises(ProtectionFaultError): e.step() # Invalid address 44 for dst e.load_string('2,0,0,44') with self.assertRaises(ProtectionFaultError): e.step() # 2 * 2 = 4 @ address 0 e.load_string('2,0,0,0,99') e.step() self.assertEqual(e.peek(0), 4) # 2**63 * 3 = 9223372036854775808 @ address 0 (overflow and wrap) #e.load_string('2,5,6,0,99,' + str(2 ** 63) + ',3') #e.step() #self.assertEqual(e.peek(0), 9223372036854775808) # dst:=a*[b] e.load_string('102,44,5,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 88) # dst:=[a]*b e.load_string('1002,5,50,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 100) # dst:=a*b e.load_string('1102,5,5,6,99,2,-1') e.execute() self.assertEqual(e.peek(6), 25)
waived worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You may copy, modify, distribute, and perform the work, even for commercial purposes, all without asking permission. See the accompanying COPYRIGHT document. """ from day7 import ElfCPU, InputInterrupt, OutputInterrupt, SystemHaltError from itertools import permutations """ Part Two """ # Amps A through E amplifiers = [ElfCPU() for _ in range(5)] phases = permutations([5, 6, 7, 8, 9]) # Max thruster thruster = 0 with open('input.txt') as f: intcode = ''.join(f.readlines()) # Iterate through phases for phase in phases: # Prepare amps for amp in amplifiers: amp.reset() amp.load_string(intcode)
NO COPYRIGHT This work is dedicated to the public domain. All rights have been waived worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. You may copy, modify, distribute, and perform the work, even for commercial purposes, all without asking permission. See the accompanying COPYRIGHT document. """ from day7 import ElfCPU, InputInterrupt, OutputInterrupt from itertools import permutations """ Part One """ amp = ElfCPU() phases = permutations([0, 1, 2, 3, 4]) # Max thruster thruster = 0 with open('input.txt') as f: intcode = ''.join(f.readlines()) # Iterate through phases for phase in phases: input_signal = 0 # Iterate through amps for position in range(5): # Clear state