// ==================================================
// > PARSING
// ==================================================
$maps = $input->split("\n\n")->slice(1)->map(function ($map) {
$map = $map->lines->slice(1)->map(function ($line) {
[$ds, $ss, $rl] = $line->numbers();
return [$ss, $ss + $rl - 1, $ds - $ss];
})->sortBy(0)->values();
if ($map[0][0] != 0) {
$map = [[0, $map[0][0] - 1, 0], ...$map];
}
$map[] = [$map[count($map) - 1][1] + 1, INF, 0];
return set($map);
});
// ==================================================
// > PART 1
// ==================================================
$seeds = $input->lines[0]->numbers();
foreach ($maps as $map) {
$seeds = $seeds->map(function ($seed) use ($map) {
$rule = $map->filter(fn ($range) => $range[0] <= $seed && $seed <= $range[1])->first();
return $seed + ($rule[2] ?? 0);
});
}
$solution_1 = $seeds->min();
// ==================================================
// > PART 2
// ==================================================
$ranges = $input->lines[0]->numbers()->chunk(2)->map(fn ($range) => [$range[0], $range[0] + $range[1] - 1]);
foreach ($maps as $map) {
$nranges = set();
foreach ($ranges as $r) foreach ($map as $m) {
if ($r[1] < $m[0] || $r[0] > $m[1]) continue;
$nranges[] = [
max($r[0], $m[0]) + $m[2],
min($r[1], $m[1]) + $m[2]
];
}
$ranges = $nranges;
}
$solution_2 = $ranges->merge()->min();