Advent of code 2023/22
Ajax Direct

Answer

Part 1 :
Part 2 :
function parse($input) {
    foreach ($input->lines as $i=>$l) {
        [$x1, $y1, $z1, $x2, $y2, $z2] = $l->numbers();
        foreach (range($x1, $x2) as $x) foreach (range($y1, $y2) as $y) foreach (range($z1, $z2) as $z) {
            $bricks[$i][] = [$x, $y, $z];
            $grid[$x][$y][$z] = $i;
        }
    }
    $order = array_keys($bricks);
    usort($order, fn($a, $b) => $bricks[$a][0][2] <=> $bricks[$b][0][2]);
    return [$bricks, $grid, $order];
}

function get_bricks_under($id, $bricks, $grid) {
    $under = [];
    foreach ($bricks[$id] as $cube) {
        [$x, $y, $z] = $cube;
        if ($z == 1) return ["floor"];
        if ($z != $bricks[$id][0][2]) break;
        if (isset($grid[$x][$y][$z-1])) $under[] = $grid[$x][$y][$z-1];
    }
    return array_unique($under);
}

function make_brick_fall($id, &$bricks, &$grid) {
    $cubes = &$bricks[$id];
    foreach ($cubes as &$cube) {
        [$x, $y, $z] = $cube;
        unset($grid[$x][$y][$z]);
        $cube[2] = $z - 1;
        $grid[$x][$y][$z - 1] = $id;
    }
}

// ==================================================
// > PART 1
// ==================================================
[$bricks, $grid, $order] = parse($input);

foreach ($order as $id) {
    while (!($under[$id] = get_bricks_under($id, $bricks, $grid))) make_brick_fall($id, $bricks, $grid);
    foreach ($under[$id] as $u) $over[$u][] = $id;
    if (count($under[$id]) == 1) $only_under = array_merge($only_under??[], $under[$id]);
}

$only_under = array_unique(array_diff($only_under, ["floor"]));
$solution_1 = count($bricks) - count($only_under);

// ==================================================
// > PART 2
// ==================================================
$solution_2 = 0;

foreach ($only_under as $id) {
    $queue = [$id];
    $felt = [];
    $u = $under;

    while ($queue) {
        $id = array_shift($queue);
        if (isset($felt[$id])) continue;
        $felt[$id] = true;
        foreach (($over[$id]??[]) as $i) {
            $u[$i] = array_diff($u[$i], [$id]);
            if (empty($u[$i])) $queue[] = $i;
        }
    }
    $solution_2 += count($felt) - 1;
}