$graph = new Graph(function ($graph) {
[$x, $y, $path] = explode(";", $graph->current);
$doors = array_combine(
["U", "D", "L", "R"],
array_map(fn ($chr) => $chr >= "b", str_split(substr(md5($graph->passcode . $path), 0, 4)))
);
$ways = [
"U" => $y ? [$x, $y - 1] : false,
"D" => $y < 3 ? [$x, $y + 1] : false,
"L" => $x ? [$x - 1, $y] : false,
"R" => $x < 3 ? [$x + 1, $y] : false,
];
$states = [];
foreach ($ways as $dir => $way) {
if ($way && $doors[$dir]) {
$states[implode(";", [...$way, $path . $dir])] = 1;
}
}
return $states;
});
$graph->defineEnd(function ($graph) {
[$x, $y, $path] = explode(";", $graph->current);
return $x == 3 && $y == 3;
});
$graph->onEnd(fn ($graph) => set(explode(";", $graph->current))->last());
// ==================================================
// > PART 1
// ==================================================
$graph->passcode = $input;
$solution_1 = $graph->explore("0;0;");
// ==================================================
// > PART 2
// ==================================================
$graph->setTarget("highest");
// If reached the vault : stop there and register path
$graph->addPruning(function ($states, $graph) {
[$x, $y, $path] = explode(";", $graph->current);
if ($x == 3 && $y == 3) {
$graph->ends[$graph->current] = $graph->values[$graph->current];
return [];
};
return $states;
});
// When every possible state was explored, return the end state with the maximum value
$graph->onCompletion(function ($graph) {
return set($graph->ends)->max();
});
$solution_2 = $graph->explore("0;0;");