[$depth, $tx, $ty] = $input->numbers;
// ==================================================
// > PART 1 : BUILD THE CAVE
// ==================================================
$erosion = [];
$cave = [];
$solution_1 = 0;
for ($y = 0; $y <= $ty + 50; $y++) for ($x = 0; $x <= $tx + 50; $x++) {
$erosion[$y][$x] = match (true) {
($x == 0) => ($y * 48271 + $depth) % 20183,
($y == 0) => ($x * 16807 + $depth) % 20183,
($x == $tx && $y == $ty) => $depth % 20183,
default => (($erosion[$y][$x - 1] * $erosion[$y - 1][$x]) + $depth) % 20183
};
$cave[$y][$x] = $erosion[$y][$x] % 3;
if ($x <= $tx && $y <= $ty) {
$solution_1 += $cave[$y][$x];
}
}
// ==================================================
// > PART 2 : EXPLORE
// ==================================================
$graph = new Graph(function ($graph) use ($cave) {
[$x, $y, $object] = explode(";", $graph->current);
$states = [];
foreach (neighbors([$x, $y], false, 0, INF, 0, INF) as [$sx, $sy]) {
if (!isset($cave[$sy][$sx])) continue;
// Get object in common between current region and next one
// 0 nothing, 1 climbing gear, 2 torch
$picks = array_values(array_intersect(
[[1, 2], [0, 1], [0, 2]][$cave[$y][$x]],
[[1, 2], [0, 1], [0, 2]][$cave[$sy][$sx]]
));
// If we can keep the object, always choose to do so
if (in_array($object, $picks)) {
$states["$sx;$sy;$object"] = 1;
} else {
$states["$sx;$sy;$picks[0]"] = 8;
}
}
return $states;
});
$solution_2 = $graph->explore("0;0;2", "$tx;$ty;2")[1];