Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Hamish Wright
committed
Dec 21, 2019
1 parent
8de33ab
commit 5dbed61
Showing
15 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,9,8,9,10,9,4,9,99,-1,8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,9,8,9,10,9,4,9,99,-1,8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,9,8,9,10,9,4,9,99,-1,8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,9,7,9,10,9,4,9,99,-1,8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,9,7,9,10,9,4,9,99,-1,8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,3,1108,-1,8,3,4,3,99 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,3,1108,-1,8,3,4,3,99 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,3,1107,-1,8,3,4,3,99 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
3,3,1107,-1,8,3,4,3,99 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
<?php | ||
|
||
namespace PuzzleSolvers\Day5; | ||
|
||
use PuzzleSolvers\PuzzleSolver; | ||
|
||
class ElfComputer3 extends PuzzleSolver | ||
{ | ||
public $program; | ||
public $position; | ||
public $input; | ||
public $outputs; | ||
public $parameterMode; | ||
public $instructionLength = 4; | ||
|
||
public function initialise() | ||
{ | ||
$this->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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
<?php | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use PuzzleSolvers\Day5\ElfComputer3; | ||
|
||
final class Day5Part2Test extends TestCase | ||
{ | ||
public function testDay2EndToEnd(): void | ||
{ | ||
$outputs = [ | ||
'3500,9,10,70,2,3,11,0,99,30,40,50', | ||
'2,0,0,0,99', | ||
'2,3,0,6,99', | ||
'2,4,4,5,99,9801', | ||
'30,1,1,4,2,5,6,0,99', | ||
]; | ||
foreach ($outputs as $inputFileNumber => $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']); | ||
} | ||
} |