Advent of code 2024/8
Ajax Direct

Answer

Part 1 :
Part 2 :
$w = strlen($input->lines[0]);
$h = $input->lines->count();

// Group coordonates
$groups = set($input->replace("\n", "")->matchAll("/[a-zA-Z0-9]/", true)[0])
->map(fn ($p) => [$p[0], [$p[1] % $w, intdiv($p[1], $w)]])
->groupBy(0, fn ($p) => $p[1]);


// ==================================================
// > SOLVE
// ==================================================
function solve($groups, $w, $h, $part_2 = false) {
    $map = [];

    foreach ($groups as $l=>$g) {
        for ($i = 0; $i < count($g) - 1; $i++) {
            for ($j = $i+1; $j < count($g); $j++) {
                [$ix, $iy] = $g[$i];
                [$jx, $jy] = $g[$j];

                // Find vectors from $i and $j
                [$nx, $ny] = [abs($ix - $jx), abs($iy - $jy)];
                $di = [$ix < $jx ? -$nx : $nx, -$ny];
                $dj = [$ix < $jx ? $nx : -$nx, $ny];

                // Multiply vector (0, ...) until OOB for $i and $j; or only once for part 1
                foreach ([[$di, $g[$i]], [$dj, $g[$j]]] as [[$dx, $dy], [$px, $py]]) {
                    for ($mult = $part_2 ? 0 : 1;; $mult++) {
                        [$x, $y] = [$px + ($dx * $mult), $py + ($dy * $mult)];
                        if (0 <= $x && $x < $w && 0 <= $y && $y < $h) {
                            $map["$x;$y"] = true;
                        } else {
                            break;
                        }
                        if (!$part_2) break;
                    }
                }
            }
        }
    }

    return count($map);
}

$solution_1 = solve($groups, $w, $h, false);
$solution_2 = solve($groups, $w, $h, true);