function solve($grid, $guard, $dir, $history = [], $reccord_to_try = false) {
$dirs = [[0, -1], [1, 0], [0, 1], [-1, 0]];
$pos = [join(";", $guard)];
$to_try = [];
while (true) {
$next = [
$guard[0] + $dirs[$dir][0],
$guard[1] + $dirs[$dir][1]
];
switch ($grid->get($next)) {
case null:
return [false, array_unique($pos), $to_try];
case "#":
$dir = ($dir + 1) % 4;
break;
default:
if ($reccord_to_try) {
$to_try[] = [$guard, $next, $dir, $history];
}
$guard = $next;
$pos[] = join(";", $guard);
$state = join(";", $guard) . ";" . $dir;
if (isset($history[$state])) {
return [true, array_unique($pos)];
}
$history[$state] = true;
}
}
}
// ==================================================
// > PART 1
// ==================================================
$grid = $input->grid;
$guard = $grid->search("^");
[$looped, $pos, $to_try] = solve($grid, $guard, 0, [join(";", $guard).";0" => true], true);
$solution_1 = count($pos);
// ==================================================
// > PART 2
// ==================================================
$tries = [];
foreach ($to_try as $try) {
[$guard, $next, $dir, $history] = $try;
$ngrid = $grid->set($next, "#");
$b = join(";", $next);
if (!isset($tries[$b])) {
[$tries[$b], $_] = solve($ngrid, $guard, $dir, $history);
}
$grid->set($next, ".");
}
$solution_2 = count(array_filter($tries));