$grid = array_map("str_split", explode("\n", ((string) $input)));
function solve($grid, $get_neighbors = false, $limit = 4) {
[$w, $h] = [count($grid[0]), count($grid)];
$seen = [];
$neighbors = [];
while (true) {
$ngrid = $grid;
for ($x = 0; $x < $w; $x++) for ($y = 0; $y < $h; $y++) {
if ($grid[$y][$x] == ".") continue;
$taken = 0;
$neighbors[$y][$x] = $neighbors[$y][$x] ?? $get_neighbors([$x, $y], $grid);
foreach ($neighbors[$y][$x] as [$nx, $ny]) {
if (($grid[$ny][$nx] ?? ".") == "#") $taken++;
}
if ($taken == 0 && $grid[$y][$x] == "L") $ngrid[$y][$x] = "#";
if ($taken >= $limit && $grid[$y][$x] == "#") $ngrid[$y][$x] = "L";
}
$grid = $ngrid;
$state = implode("", array_merge(...$grid));
if (isset($seen[$state])) break;
$seen[$state] = true;
}
return set(str_split($state))->occurrences()["#"];
}
// ==================================================
// > PART 1
// ==================================================
$solution_1 = solve($grid, function ($pos, $grid) {
return neighbors($pos, true);
}, 4);
// ==================================================
// > PART 2
// ==================================================
$dir = neighbors([0, 0], true);
$solution_2 = solve($grid, function ($pos, $grid) use ($dir) {
$n = [];
foreach ($dir as $d) {
$p = $pos;
do {
$p = [$p[0] + $d[0], $p[1] + $d[1]];
} while (isset($grid[$p[1]][$p[0]]) && $grid[$p[1]][$p[0]] == ".");
if (isset($grid[$p[1]][$p[0]])) {
$n[] = $p;
}
}
return $n;
}, 5);