// Build the map
$grid = grid();
$grid->set([500, 0], "+");
foreach ($input->lines as $line) {
$corners = $line->numbers()->chunk(2);
$c[] = $corners;
for ($i = 0; $i < $corners->count() - 1; $i++) {
$grid->drawLine((array) $corners[$i], (array) $corners[$i + 1], "#");
}
}
function get_solution($grid, $with_floor = false)
{
$floor = $grid->rows()->keys()->max() + ($with_floor ? 2 : 0);
$rest = 0;
// Draw floor
if ($with_floor) foreach (xy([-1000, $floor])->pathTo(xy([1000, $floor])) as $cell) {
$grid->set($cell, "#");
}
// Start moving sand
while (true) {
// Source is covered in sand, stop
if ($with_floor && $grid->get([500, 0]) === "o") break;
// Emit a new sand and move it one step at a time
$sand = xy([500, 0]);
while (true) {
$sand->move([0, 1]);
// Reached the bottom and has no floor, stop there
if (!$with_floor && $sand[1] > $floor) break 2;
// Nothing, keep falling
if (!$grid->get($sand)) continue;
// Hit something, try to go left
$sand->move([-1, 0]);
if (!$grid->get($sand)) continue;
// Hit something, try to go right
$sand->move([2, 0]);
if (!$grid->get($sand)) continue;
// Nowhere to go, stack on top
$sand->move([-1, -1]);
$grid->set($sand, "o");
$rest++;
break;
}
}
return [$rest, $grid];
}
// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = get_solution(clone $grid)[0];
$solution_2 = get_solution($grid, true)[0];