Advent of code 2023/8
Ajax Direct

Answer 20ms

Part 1 : 11309 Part 2 : 13740108158591
$dirs = $input->lines[0]->chars();
$paths = $input->lines->slice(2)->mapAssoc(function ($i, $line) {
    [$k, $l, $r] = $line->matchAll("/[1-9A-Z]+/")[0];
    return [$k => ["L" => $l, "R" => $r]];
});

// ==================================================
// > PART 1
// ==================================================
$pos = "AAA";
$solution_1 = 0;
while ($pos != "ZZZ") {
    $dir = $dirs[$solution_1++ % count($dirs)];
    $pos = $paths[$pos][$dir];
}

// ==================================================
// > PART 2
// ==================================================
$solution_2 = $paths->keys()
    ->filter(fn ($k) => $k[2] == "A")
    ->map(function ($pos) use ($dirs, $paths) {
        $i = 0;
        while ($pos[2] != "Z") {
            $dir = $dirs[$i++ % count($dirs)];
            $pos = $paths[$pos][$dir];
        }
        return $i;
    })
    ->reduce(fn ($carry, $i) => Math::lcm($carry, $i), 1);