-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay5.php
130 lines (111 loc) · 4.47 KB
/
Day5.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php
declare(strict_types=1);
namespace App\Days;
use App\Contracts\Day;
use Illuminate\Support\Collection;
use RuntimeException;
class Day5 extends Day
{
public const EXAMPLE1 = <<<eof
[D]
[N] [C]
[Z] [M] [P]
1 2 3
move 1 from 2 to 1
move 3 from 1 to 3
move 2 from 2 to 1
move 1 from 1 to 2
eof;
/**
* After the rearrangement procedure completes, what crate ends up on top of each stack?
*/
public function solvePart1(mixed $input): int|string|null
{
$input = $this->parseInput($input);
/** @var Collection $diagram */
$diagram = $input->get('diagram');
/** @var Collection $instructions */
$instructions = $input->get('instructions');
while ($instructions->isNotEmpty()) {
$instruction = (string) $instructions->shift();
preg_match("/move (\d+) from (\d+) to (\d+)/", $instruction, $matches);
if (4 === count($matches)) {
[, $amount, $from, $to] = $matches;
$amount = (int) $amount;
// move the crates one at a time
while ($amount > 0) {
--$amount;
/** @var Collection $fromStack */
$fromStack = $diagram->get($from);
/** @var Collection $toStack */
$toStack = $diagram->get($to);
$crate = $fromStack->pop();
$toStack->push($crate);
}
}
}
return $diagram->map(fn ($stack) => $stack->pop())->implode('');
}
/**
* After the rearrangement procedure completes, what crate ends up on top of each stack?
*/
public function solvePart2(mixed $input): int|string|null
{
$input = $this->parseInput($input);
/** @var Collection $diagram */
$diagram = $input->get('diagram');
/** @var Collection $instructions */
$instructions = $input->get('instructions');
while ($instructions->isNotEmpty()) {
$instruction = (string) $instructions->shift();
preg_match("/move (\d+) from (\d+) to (\d+)/", $instruction, $matches);
if (4 === count($matches)) {
[, $amount, $from, $to] = $matches;
$amount = (int) $amount;
/** @var Collection $fromStack */
$fromStack = $diagram->get($from);
/** @var Collection $toStack */
$toStack = $diagram->get($to);
// move the crates in bulk preserving the original order
$fromStack->splice(-$amount)->each(fn ($item) => $toStack->push($item));
}
}
return $diagram->map(fn ($stack) => $stack->pop())->implode('');
}
protected function parseInput(mixed $input): Collection
{
$input = is_array($input) ? $input : explode("\n", $input);
return collect($input)
->chunkWhile(fn ($value) => '' !== $value)
->map(fn ($chunk) => $chunk->filter(fn ($value) => '' !== $value)->values())
->flatMap(fn ($chunk, $index) => 0 === $index
? ['diagram' => $this->setupDiagram($chunk)]
: ['instructions' => collect($chunk)]);
}
protected function setupDiagram(Collection $rawDiagram): Collection
{
$stackLine = $rawDiagram->pop(); // " 1 2 3 "
// create an empty array keyed by the stack columns 1,2,3 etc
$stackNumbers = preg_split("/\s+/", trim((string) $stackLine));
if (false === $stackNumbers) {
throw new RuntimeException('Failed to parse stack numbers');
}
/** @var array<string, array<int, string>> $stacks */
$stacks = array_map(fn () => [], array_flip($stackNumbers));
// loop over each remaining diagram line, adding the crates to the correct stack column
$rawDiagram->each(function ($line) use (&$stacks): void {
$crates = collect(mb_str_split($line, 4))
->map(fn ($char) => trim(str_replace(['[', ']'], '', $char)));
foreach ($stacks as &$stack) {
$crate = $crates->shift();
if ('' !== $crate) {
$stack[] = $crate;
}
}
});
foreach ($stacks as &$stack) {
$stack = collect(array_reverse($stack));
}
return collect($stacks);
}
}