Advent of code 2022/9
Ajax Direct

Answer

Part 1 :
Part 2 :
function get_solution($input, $rope_size)
{
    // Create a rope of XY pointers
    $rope = set()->fill(0, $rope_size, fn () => xy([0, 0]));

    // Apply each movement
    foreach ($input->lines as $line) {

        [$direction, $count] = $line->split(" ");

        // Apply movement X times
        for ($count = $count->int; $count; $count--) {

            // Move first pointer in a direction (L/R/U/D)
            $rope->first()->direction(direction($direction));

            // Move the following parts of the rope if necessary
            for ($part = 1; $part < $rope_size; $part++) {
                $distance = xy($rope[$part]->getDistanceTo($rope[$part - 1]));

                // Not more that 2 units away in any direction from parent, stay in place
                if (set($distance->xy)->map("abs")->searchNumberOver(2) === false) continue;

                // Move towards the parent, but no more than one step in each direction
                $rope[$part]->move(set($distance->xy)->map(fn ($dir) => $dir / (abs($dir) ?: 1)));
            }
        }
    }

    return $rope->last()->getVisitedCount();
}

// ==================================================
// > SOLUTIONS
// ==================================================
$solution_1 = get_solution($input, 2);
$solution_2 = get_solution($input, 10);