Advent of code 2022/15
Ajax Direct

Answer

Part 1 :
Part 2 :
$grid    = grid();
$couples = [];

// Draw sources and beacons
foreach ($input->lines as $line) {
    preg_match_all('/[-0-9]+/', $line, $matches);
    $couple = [xy([$matches[0][0], $matches[0][1]]), xy([$matches[0][2], $matches[0][3]])];
    $couples[] = $couple;
    $grid->set($couple[0], "S");
    $grid->set($couple[1], "B");
}

// ==================================================
// > PART 1
// ==================================================
$search = 2000000;
$ranges = [];

foreach ($couples as $couple) {
    $radius = $couple[0]->manhattan($couple[1]);
    // If the beacon is too far, skip
    if ($couple[0][1] - $radius > $search || $couple[0][1] + $radius < $search) continue;
    // Get the x range at the search level
    $ranges[] = [$couple[0][0] - ($radius - abs($couple[0][1] - $search)), $couple[0][0] + ($radius - abs($couple[0][1] - $search))];
}

// Count the number of points in the merged ranges
$count = set($ranges)->mergeRanges()
    ->reduce(fn ($count, $range) => $count + $range[1] - $range[0] + 1, 0);

// All the coverd points minus the beacons
$solution_1 = $count - $grid[2000000]->keep("B")->count();

// ==================================================
// > PART 2
// ==================================================
$intersections = set();

// Find interections that are just outside of the known areas
for ($i = 0; $i < count($couples); $i++) {
    $area = new GridCircle($couples[$i][0], $couples[$i][0]->manhattan($couples[$i][1]) + 1);
    for ($j = $i + 1; $j < count($couples); $j++) {
        $intersections = $intersections->merge($area->getIntersections(
            new GridCircle($couples[$j][0], $couples[$j][0]->manhattan($couples[$j][1]) + 1)
        ));
    }
}

// Keep only the ones between 0 and 4000000
$intersections = $intersections->filter(fn ($xy) => $xy[0] >= 0 && $xy[1] >= 0 && $xy[0] <= 4000000 && $xy[1] <= 4000000);

foreach ($intersections as $intersection) {
    foreach ($couples as $couple) {
        $radius = $couple[0]->manhattan($couple[1]);
        $distance = $couple[0]->manhattan($intersection);
        if ($distance <= $radius) continue 2;
    }
    break;
}
$xy = xy($intersection);
$solution_2 = $xy[0] * 4000000 + $xy[1];