Advent of code 2020/22
Ajax Direct

Answer

Part 1 :
Part 2 :
function new_game($stacks, $get_winner) {
    $seen = [[], []];

    while ($stacks[0] && $stacks[1]) {
        if (in_array($stacks[0], $seen[0]) || in_array($stacks[1], $seen[1])) {
            return [0, $stacks];
        }
        $seen[0][] = $stacks[0];
        $seen[1][] = $stacks[1];

        [$a, $b] = [array_shift($stacks[0]), array_shift($stacks[1])];
        $winner = (int) $get_winner($a, $b, $stacks, $get_winner);
        $stacks[$winner] = array_merge($stacks[$winner], $winner ? [$b, $a] : [$a, $b]);
    }
    return [$winner, $stacks];
}

function solve($stacks, $get_winner) {
    [$winner, $stacks] = new_game($stacks, $get_winner);

    return set($stacks[$winner])->reverse()
        ->reduce(fn ($total, $v, $k) =>  $total + (($k + 1) * $v), 0, true);
}

// ==================================================
// > SOLUTIONS
// ==================================================

// Parsing
$stacks = (array) $input->split("\n\n")->map(fn ($stack) => (array) $stack->lines->slice(1)->map("int"));

// Part 1
$solution_1 = solve($stacks, function ($a, $b) {
    return $b > $a;
});

// Part 2
$solution_2 = solve($stacks, function ($a, $b, $stacks, $get_winner) {
    if (count($stacks[0]) < $a || count($stacks[1]) < $b) return $b > $a;
    return new_game([array_slice($stacks[0], 0, $a), array_slice($stacks[1], 0, $b)], $get_winner)[0];
});