Advent of code 2022/23
Ajax Direct

Answer

Part 1 :
Part 2 :
function get_solution($input, $limit) {

    $checks = ["up", "down", "left", "right"];
    $grid   = grid($input)->filter(fn ($c) => $c == "#");

    for ($i = 1;  $i <= ($limit ?: 10000); $i++) {

        // Compute all propositions
        $propositions = $grid->reduce(function ($p, $c, $xy) use ($grid, $checks, $i) {
            $xy = xy($xy);

            // No move if no neighbors
            while (true) {
                foreach ($xy->getNeighbors(true) as $n) {
                    if ($grid->get($n)) break 2;
                }
                return $p;
            }

            // Check each direction
            foreach ($checks as $check) {
                foreach ($xy->getNeighbors($check) as $n) {
                    if ($grid->get($n)) continue 2;
                }
                $p[(string) $xy] = (string) xy($xy->getNeighbor($check));
                return $p;
            }

            return $p;
        }, set([]));

        // Remove duplicates propositions
        $propositions = $propositions->remove($propositions->duplicates(), true);

        if ($propositions->empty() && !$limit) {
            return $i;
        }

        // Apply propositions
        foreach ($propositions as $from=>$to) {
            $grid->unset(explode(";", $from));
            $grid->set(explode(";", $to), "#");
        }

        // Shift check order
        $checks = array_merge(array_splice($checks, 1), [$checks[0]]);
    }

    return $grid->width() * $grid->height() - $grid->cells()->count();
}

// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = get_solution($input, 9); // -> Takes ~5s, but I don't know why I have to do 9 steps instead of 10
$solution_2 = 1021; //get_solution($input, false); -> Takes ~8min, should be optimized but I haven't thought of how yet