diff --git a/inputs/day5/part2/0 b/inputs/day5/part2/0 new file mode 100644 index 0000000..2626616 --- /dev/null +++ b/inputs/day5/part2/0 @@ -0,0 +1 @@ +3,9,8,9,10,9,4,9,99,-1,8 diff --git a/inputs/day5/part2/1 b/inputs/day5/part2/1 new file mode 100644 index 0000000..2626616 --- /dev/null +++ b/inputs/day5/part2/1 @@ -0,0 +1 @@ +3,9,8,9,10,9,4,9,99,-1,8 diff --git a/inputs/day5/part2/10 b/inputs/day5/part2/10 new file mode 100644 index 0000000..62b0c3f --- /dev/null +++ b/inputs/day5/part2/10 @@ -0,0 +1 @@ +3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99 diff --git a/inputs/day5/part2/11 b/inputs/day5/part2/11 new file mode 100644 index 0000000..62b0c3f --- /dev/null +++ b/inputs/day5/part2/11 @@ -0,0 +1 @@ +3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99 diff --git a/inputs/day5/part2/2 b/inputs/day5/part2/2 new file mode 100644 index 0000000..2626616 --- /dev/null +++ b/inputs/day5/part2/2 @@ -0,0 +1 @@ +3,9,8,9,10,9,4,9,99,-1,8 diff --git a/inputs/day5/part2/3 b/inputs/day5/part2/3 new file mode 100644 index 0000000..124bbb7 --- /dev/null +++ b/inputs/day5/part2/3 @@ -0,0 +1 @@ +3,9,7,9,10,9,4,9,99,-1,8 diff --git a/inputs/day5/part2/4 b/inputs/day5/part2/4 new file mode 100644 index 0000000..124bbb7 --- /dev/null +++ b/inputs/day5/part2/4 @@ -0,0 +1 @@ +3,9,7,9,10,9,4,9,99,-1,8 diff --git a/inputs/day5/part2/5 b/inputs/day5/part2/5 new file mode 100644 index 0000000..1a710f8 --- /dev/null +++ b/inputs/day5/part2/5 @@ -0,0 +1 @@ +3,3,1108,-1,8,3,4,3,99 diff --git a/inputs/day5/part2/6 b/inputs/day5/part2/6 new file mode 100644 index 0000000..1a710f8 --- /dev/null +++ b/inputs/day5/part2/6 @@ -0,0 +1 @@ +3,3,1108,-1,8,3,4,3,99 diff --git a/inputs/day5/part2/7 b/inputs/day5/part2/7 new file mode 100644 index 0000000..1c96db8 --- /dev/null +++ b/inputs/day5/part2/7 @@ -0,0 +1 @@ +3,3,1107,-1,8,3,4,3,99 diff --git a/inputs/day5/part2/8 b/inputs/day5/part2/8 new file mode 100644 index 0000000..1c96db8 --- /dev/null +++ b/inputs/day5/part2/8 @@ -0,0 +1 @@ +3,3,1107,-1,8,3,4,3,99 diff --git a/inputs/day5/part2/9 b/inputs/day5/part2/9 new file mode 100644 index 0000000..62b0c3f --- /dev/null +++ b/inputs/day5/part2/9 @@ -0,0 +1 @@ +3,21,1008,21,8,20,1005,20,22,107,8,21,20,1006,20,31,1106,0,36,98,0,0,1002,21,125,20,4,20,1105,1,46,104,999,1105,1,46,1101,1000,1,20,4,20,1105,1,46,98,99 diff --git a/src/day5/ElfComputer3.php b/src/day5/ElfComputer3.php new file mode 100644 index 0000000..a1581ab --- /dev/null +++ b/src/day5/ElfComputer3.php @@ -0,0 +1,178 @@ +position = 0; + $this->program = array_map('intval', explode(',', $this->inputs[0])); + $this->outputs = []; + } + + public function run() + { + while ($this->position < $this->getProgramSize()) { + $instruction = $this->parseInstruction($this->readMemory()); + $this->execute($instruction); + } + + $this->output = implode(',', $this->program); + } + + public function parseInstruction($instruction) + { + $parsedInstuction = []; + $parsedInstuction['opcode'] = (int) substr($instruction, -2, 2); + $parsedInstuction['mode1'] = (strlen($instruction) > 2) ? (int) substr($instruction, -3, 1) : 0; + $parsedInstuction['mode2'] = (strlen($instruction) > 3) ? (int) substr($instruction, -4, 1) : 0; + $parsedInstuction['mode3'] = (strlen($instruction) > 4) ? (int) substr($instruction, -5, 1) : 0; + + return $parsedInstuction; + } + + public function getParameter(int $offset, int $mode) + { + $parameter = $this->readMemoryOffset($offset); + if ($mode == 0) { + $parameter = $this->readMemory($parameter); + } + + return $parameter; + } + + public function execute($instruction) + { + $opcode = $instruction['opcode']; + + if ($opcode === 1) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + $parameter3 = $this->readMemoryOffset(3); + $value = $parameter1 + $parameter2; + $this->writeMemory($value, $parameter3); + $this->position += 4; + } + + else if ($opcode === 2) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + $parameter3 = $this->readMemoryOffset(3); + $value = $parameter1 * $parameter2; + $this->writeMemory($value, $parameter3); + $this->position += 4; + } + + else if ($opcode == 3) { + $this->writeMemory($this->input, $this->readMemoryOffset(1)); + $this->position += 2; + } + + else if ($opcode == 4) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $this->outputs[] = $parameter1; + $this->position += 2; + } + + else if ($opcode == 5) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + if ($parameter1 != 0) { + $this->position = $parameter2; + } else { + $this->position += 3; + } + } + + else if ($opcode == 6) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + if ($parameter1 == 0) { + $this->position = $parameter2; + } else { + $this->position += 3; + } + } + + else if ($opcode == 7) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + $parameter3 = $this->readMemoryOffset(3); + $value = ($parameter1 < $parameter2) ? 1 : 0; + $this->writeMemory($value, $parameter3); + $this->position += 4; + } + + else if ($opcode == 8) { + $parameter1 = $this->getParameter(1, $instruction['mode1']); + $parameter2 = $this->getParameter(2, $instruction['mode2']); + $parameter3 = $this->readMemoryOffset(3); + $value = ($parameter1 == $parameter2) ? 1 : 0; + $this->writeMemory($value, $parameter3); + $this->position += 4; + } + + else if ($opcode === 99) { + $this->position = $this->getProgramSize(); + } else { + $this->position += 1; + } + } + + public function getProgramSize(): int + { + return count($this->program); + } + + public function readMemory($position = null) + { + if (is_null($position)) { + $position = $this->position; + } + + return $this->program[$position]; + } + + public function readMemoryOffset($offset = 0) + { + return $this->program[$this->position + $offset]; + } + + public function writeMemoryOffset(int $value, $offset = 0) + { + $this->program[$this->position + $offset] = $value; + } + + public function writeMemory(int $value, $position = null) + { + if (is_null($position)) { + $position = $this->position; + } + $this->program[$position] = $value; + } + + public function getProgram(): array + { + return $this->program ?: []; + } + + public function getPosition(): int + { + return $this->position ?: 0; + } + + public function setPosition(int $position): void + { + $this->position = $position; + } +} diff --git a/src/day5/solve.php b/src/day5/solve.php index 0e775d5..6214bb2 100644 --- a/src/day5/solve.php +++ b/src/day5/solve.php @@ -3,6 +3,7 @@ require_once __DIR__ . '/../../vendor/autoload.php'; use PuzzleSolvers\Day5\ElfComputer2; +use PuzzleSolvers\Day5\ElfComputer3; $elfComputer = new ElfComputer2('day5/part1/input'); $elfComputer->initialise(); @@ -11,3 +12,11 @@ $outputs = $elfComputer->outputs; echo "Day 5 Part 1 answer: " . end($outputs) . "\n"; + +$elfComputer = new ElfComputer3('day5/part1/input'); +$elfComputer->initialise(); +$elfComputer->input = 5; +$elfComputer->run(); +$outputs = $elfComputer->outputs; + +echo "Day 5 Part 2 answer: " . end($outputs) . "\n"; diff --git a/tests/Day5Part2Test.php b/tests/Day5Part2Test.php new file mode 100644 index 0000000..55f70b8 --- /dev/null +++ b/tests/Day5Part2Test.php @@ -0,0 +1,166 @@ + $output) { + $puzzleSolver = new ElfComputer3('day2/part1/' . $inputFileNumber); + $puzzleSolver->initialise(); + $puzzleSolver->run(); + $this->assertSame($output, $puzzleSolver->getOutput()); + } + } + + public function testInitialiseLoadsInputToProgramAndSetsPositionTo0(): void + { + $elfComputer = new ElfComputer3('day2/part1/0'); + + $elfComputer->initialise(); + + $this->assertSame([1, 9, 10, 3, 2, 3, 11, 0, 99, 30, 40, 50], $elfComputer->getProgram()); + $this->assertSame(0, $elfComputer->getPosition()); + } + + public function testPart1EndToEnd() + { + $outputs = [ + [42, 0, 4, 0, 99], + [1002, 4, 3, 4, 99], + [1101, 100, -1, 4, 99], + ]; + $programOutput = [ + [42], + [], + [], + ]; + foreach ($outputs as $inputFileNumber => $output) { + $elfComputer = new ElfComputer3('day5/part1/' . $inputFileNumber); + $elfComputer->initialise(); + $elfComputer->input = 42; + $elfComputer->run(); + + $this->assertSame($programOutput[$inputFileNumber], $elfComputer->outputs); + $this->assertSame($outputs[$inputFileNumber], $elfComputer->program); + } + } + + public function testEndToEnd() + { + $outputs = [ + [0], + [1], + [0], + [0], + [1], + [0], + [1], + [0], + [1], + [999], + [1000], + [1001], + ]; + $inputs = [ + 7, + 8, + 9, + 8, + 7, + 55, + 8, + 8, + 7, + 7, + 8, + 9, + ]; + foreach ($outputs as $inputFileNumber => $output) { + \PuzzleDebugger::print('TESTING FILE: ' . $inputFileNumber); + $elfComputer = new ElfComputer3('day5/part2/' . $inputFileNumber); + $elfComputer->initialise(); + $elfComputer->input = $inputs[$inputFileNumber]; + $elfComputer->run(); + + $this->assertSame($outputs[$inputFileNumber], $elfComputer->outputs); + } + } + + public function testReadMemory(): void + { + $elfComputer = new ElfComputer3('day2/part1/0'); + $elfComputer->initialise(); + $elfComputer->setPosition(1); + + $value0 = $elfComputer->readMemory(0); + $this->assertSame(1, $value0); + + $value1 = $elfComputer->readMemory(); + $this->assertSame(9, $value1); + + $value2 = $elfComputer->readMemory(2); + $this->assertSame(10, $value2); + } + + public function testReadMemoryOffset(): void + { + $elfComputer = new ElfComputer3('day2/part1/0'); + $elfComputer->initialise(); + $elfComputer->setPosition(1); + + $value1 = $elfComputer->readMemoryOffset(0); + $this->assertSame(9, $value1); + + $value3 = $elfComputer->readMemoryOffset(2); + $this->assertSame(3, $value3); + } + + public function testWriteMemory(): void + { + $elfComputer = new ElfComputer3('day2/part1/0'); + $elfComputer->initialise(); + $elfComputer->setPosition(1); + + $elfComputer->writeMemory(5, 0); + $elfComputer->writeMemory(42); + + $program = $elfComputer->getProgram(); + $this->assertSame(5, $program[0]); + $this->assertSame(42, $program[1]); + } + + public function testWriteMemoryOffset(): void + { + $elfComputer = new ElfComputer3('day2/part1/0'); + $elfComputer->initialise(); + $elfComputer->setPosition(1); + + $elfComputer->writeMemoryOffset(5, 2); + $elfComputer->writeMemoryOffset(42); + + $program = $elfComputer->getProgram(); + $this->assertSame(5, $program[3]); + $this->assertSame(42, $program[1]); + } + + public function testParseInstruction() + { + $elfComputer = new ElfComputer3('day5/part1/0'); + $parsedInstruction = $elfComputer->parseInstruction('1002'); + + $this->assertSame(2, $parsedInstruction['opcode']); + $this->assertSame(0, $parsedInstruction['mode1']); + $this->assertSame(1, $parsedInstruction['mode2']); + $this->assertSame(0, $parsedInstruction['mode3']); + } +}