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