Advent of code 2024/9
Ajax Direct

Answer

Part 1 :
Part 2 :
function solve($input, $process) {
    $filled = $empty = $placed = [];

    // Index filled spots and empty spots
    $id = $pos = 0;
    foreach ($input->chars as $i=>$c) {
        if ($i % 2) {
            if ((int) $c) $empty[] = [$pos, (int) $c];
        } else {
            $filled[] = [$pos, (int) $c, $id++];
        }
        $pos += (int) $c;
    }

    // Move things arround (part 1 or 2)
    [$filled, $placed] = $process($filled, $empty, $placed);

    // Generate checksum
    $c = 0;
    foreach (array_merge($filled, $placed) as [$p, $s, $id]) {
        for ($i = 0; $i < $s; $i++) $c += $id * ($p + $i);
    }
    return $c;
}

// ==================================================
// > PART 1
// ==================================================
$solution_1 = solve($input, function ($filled, $empty, $placed) {
    while (count($empty)) {
        [$pf, $sf, $id] = array_pop($filled);
        [$pe, $se] = $empty[0];

        if ($pe > $pf) {
            $filled[] = [$pf, $sf, $id];
            break;
        }

        $set = min($sf, $se);
        $placed[] = [$pe, $set, $id];

        if ($set == $se) {
            unset($empty[0]);
            $empty = array_values($empty);
        } else {
            $empty[0] = [$pe + $set, $se - $set];
        }

        if ($set < $sf) {
            $filled[] = [$pf, $sf - $set, $id];
        }
    }
    return [$filled, $placed];
});

// ==================================================
// > PART 2
// ==================================================
$solution_2 = solve($input, function ($filled, $empty, $placed) {
    for ($i = count($filled) - 1; $i >= 0; $i--) {
        [$pf, $sf, $id] = $filled[$i];

        foreach ($empty as $e=>[$pe, $se]) {
            if ($pe > $pf) break;
            if ($se >= $sf) {
                $filled[$i][0] = $pe;

                if ($se > $sf) {
                    $empty[$e] = [$pe + $sf, $se - $sf];
                } else {
                    unset($empty[$e]);
                }
                continue 2;
            }
        }
    }

    return [$filled, []];
});