-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDay21.php
114 lines (93 loc) · 2.37 KB
/
Day21.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
<?php
declare(strict_types=1);
namespace Aoc2021\Day21;
use Aoc2021\Contracts\Runnable;
use Aoc2021\Day21\GameState;
use Aoc2021\Utils\Parser;
class Day21 implements Runnable
{
public function part1(string $input): string
{
[$p1p, $p2p] = Parser::getLines($input)->map(static fn ($l) => (int)\trim(\explode(':', $l)[1]));
$p1p -= 1;
$p2p -= 1;
$p1s = $p2s = 0;
$d = 2;
while (true) {
$p1p = ($p1p + $d * 3) % 10;
$p1s += $p1p + 1;
$d += 3;
if ($p1s >= 1000) {
break;
}
$p2p = ($p2p + $d * 3) % 10;
$p2s += $p2p + 1;
$d += 3;
if ($p2s >= 1000) {
break;
}
}
return (string)(\min($p1s, $p2s) * ($d - 2));
}
/**
* phpcs:disable SlevomatCodingStandard.Functions.FunctionLength
*/
public function part2(string $input): string
{
[$p1p, $p2p] = Parser::getLines($input)->map(static fn ($l) => (int)\trim(\explode(':', $l)[1]));
$s = new GameState($p1p - 1, 0, $p2p - 1, 0);
$rolls = [
3 => 1,
4 => 3,
5 => 6,
6 => 7,
7 => 6,
8 => 3,
9 => 1,
];
/** @var array<string, GameState> $states */
$states = [$s->ID() => $s];
/** @var array<string, int> $cache */
$cache = [$s->ID() => 1];
$finals = [1 => 0, 0];
while (\count($cache) > 0) {
// Iterate over for 2 players
for ($i = 1; $i <= 2; $i += 1) {
$toRemove = [];
$toAdd = [];
foreach ($cache as $stateKey => $size) {
$toRemove[] = $stateKey;
$s = $states[$stateKey];
foreach ($rolls as $diceSum => $rollSize) {
if ($i === 1) {
$newPos = ($s->p1Pos + $diceSum) % 10;
$rs = new GameState($newPos, $s->p1Score + $newPos + 1, $s->p2Pos, $s->p2Score);
if ($rs->p1Score >= 21) {
$finals[1] += $size * $rollSize;
continue;
}
} else {
$newPos = ($s->p2Pos + $diceSum) % 10;
$rs = new GameState($s->p1Pos, $s->p1Score, $newPos, $s->p2Score + $newPos + 1);
if ($rs->p2Score >= 21) {
$finals[2] += $size * $rollSize;
continue;
}
}
if (!isset($states[$rs->ID()])) {
$states[$rs->ID()] = $rs;
}
$toAdd[$rs->ID()] = ($toAdd[$rs->ID()] ?? 0) + $size * $rollSize;
}
}
foreach ($toRemove as $stateKey) {
unset($cache[$stateKey]);
}
foreach ($toAdd as $stateKey => $size) {
$cache[$stateKey] = ($cache[$stateKey] ?? 0) + $size;
}
}
}
return (string)\max($finals);
}
}