Advent of code 2021/21
Ajax Direct

Answer 1160ms

Part 1 : 995904 Part 2 : 193753136998081
$num = $input->numbers;

// ==================================================
// > PART 1
// ==================================================
$pos   = [$num[1] - 1, $num[3] - 1];
$score = [0, 0];
$turn  = 0;

for ($d = 1;; $d += 3) {
    $t = $turn++ % 2;
    $pos[$t] = ($pos[$t] + ($d * 3) + 3) % 10;
    $score[$t] += $pos[$t] + 1;
    if ($score[$t] >= 1000) break;
}

$solution_1 = $score[($t + 1) % 2]  * $turn * 3;

// ==================================================
// > PART 2
// ==================================================
$winrates = [];
$rolls = [];
foreach ([1,2,3] as $d1) foreach ([1,2,3] as $d2) foreach ([1,2,3] as $d3)
    $rolls["$d1$d2$d3"] = $d1+$d2+$d3;

$get_winrate = function ($state) use (&$get_winrate, &$winrates, $rolls) {
    $key = implode(",", $state);
    if (isset($winrates[$key])) return $winrates[$key];

    [$p1, $p2, $s1, $s2, $t] = $state;
    if ($s1 >= 21) return [1, 0];
    if ($s2 >= 21) return [0, 1];

    $winrate = [0, 0];
    $nt = $t ? 0 : 1;
    foreach ($rolls as $roll) {
        if ($t) {
            $pn = ($p2 + $roll) % 10;
            $next = [$p1, $pn, $s1, $s2 + $pn + 1, $nt];
        } else {
            $pn = ($p1 + $roll) % 10;
            $next = [$pn, $p2, $s1 + $pn + 1, $s2, $nt];
        }

        $next_winrate = $get_winrate($next);
        $winrate[0] += $next_winrate[0];
        $winrate[1] += $next_winrate[1];
    }

    $winrates[$key] = $winrate;
    return $winrate;
};

$solution_2 = max($get_winrate([$num[1] - 1, $num[3] - 1, 0, 0, 0]));