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, []];
});