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);