An atomic theory of the Pokémon TCG
A model that sees cards as compositions of recurring elements, continuously learning and adapting in an ever-changing game.
Thesis
The Pokémon Trading Card Game is constantly changing. New cards are regularly released and the oldest are rotated out of format. The best players keep winning because they excel at adapting to the opportunities and constraints of each new format. Our approach is a system that can understand the game the same way.
Goals
We entered the competition with three goals:
- Generality: a single model that plays any deck.
- Scalability: performance that improves predictably with more compute.
- Adaptability: support for new cards without major redesign or retraining.
Model
We determined that rules-based agents would not achieve our goals, as there are too many situations to enumerate across deck archetypes. This led us to deep learning. We chose a transformer to let cards, game context, and legal actions interact through attention across the entire position. Attention excels at understanding “global context,” which we hypothesized would be useful for generalization over many cards. Pokémon’s board also lacks the spatial structure that motivates convolutions in games such as Go.
Encoder
When designing our encoder, we prioritized a dense representation of the board without compressing useful information. We decompose the game state and set of legal actions into an unordered set of rows: one for each card (agent and opponent), one for each action, and a few for global attributes. The transformer reads the whole set and returns a policy score for each action row and a value score estimating win probability, which we call the “judge.”
Card Effect Decomposition
Card rows are constructed from mechanical primitives of the game, so learning transfers across common card effects. Each holds three distinct segments:
- Printed: 194 features derived from card text.
- Instance: current state of the card.
- Learned: a vector tuned per card.
Encoding cards this way means what the model learns about one card generalizes to similar ones.
Actions are built the same way: each row is composed of an action type, its mechanical features, and pointers to relevant card rows. Thus, the model generalizes across the combinatorial space of actions, allowing it to reason about any action composition, even ones it was not directly trained on.
Pre-Training
We trained the base model on highly-rated public ladder games using imitation learning. Each gameplay action is packaged as a “decision”: the acting agent’s board view plus the action taken. We used a desktop PC with an NVIDIA RTX 3090.
Hyperparameters
We tested model sizes, training settings, data selection, and deck-specific training. Our submissions run a search system within Kaggle’s ten-minute limit, so we chose the following hyperparameters to balance cost and performance:
Search
A Pokémon turn contains many actions and imperfect information, so choosing the right action sequence is critical. We present two search systems, designed for planning multi-action turns and adapting to new information throughout a turn.
VCGS Search
We developed Variance-Controlled Gate Search (VCGS) for CPU-only Kaggle containers under a ten-minute limit. It explores promising routes proposed by the policy, then has the judge compare the positions they produce at a stable boundary, typically the end of a turn. VCGS takes the following inputs:
- B (beam width): how many policy-proposed routes we retain per root action.
- ρ (policy mass): how much cumulative policy probability we cover when choosing root actions.
- δ (override margin): how much better an action must score before replacing policy.
- K: how many outcomes to sample at an “information gate,” where hidden information resolves, such as a draw.
VCGS retains the highest-probability actions until their combined policy probability reaches ρ. For each, it follows policy-proposed continuations, keeping up to B routes, which can differ in the sequence and number of actions.
When a route reaches an information gate, VCGS samples K possible outcomes and plays each to the end of the turn, where the judge evaluates the resulting position. The route’s value is the average across those K continuations, which controls variance: a route is scored on its expected outcome, not on a single draw. VCGS then selects the route with the highest value.
Our submissions used K=4, B=2, ρ=0.90, and δ=0 for efficiency within container limitations. VCGS achieved modest performance gains over raw policy.
BC-PUCT Search
We developed Belief-Conditioned PUCT (BC-PUCT) for larger search budgets, offline training, and GPU-assisted evaluation. It uses policy priors, estimated values, and an exploration bonus to allocate effort among possible continuations.
At each position, we use the Search API to fork the game into states representing different chosen actions, continuing until search reaches an information gate. There, it samples K possible outcomes by manipulating the random seed before the gate, then continues through each, with a global budget capping total branches at N. Each branch is conditioned on a single belief about how the hidden information resolved, so search below the gate proceeds deterministically.
We evaluate newly reached positions in GPU batches and propagate their values back through the explored paths. Chance outcomes contribute probability-weighted averages, while decision points compare available continuations. Promising branches grow deeper until the search budget is exhausted or the visit leader cannot be overtaken, and visit counts guide the final action choice.
This lets us exploit Pokémon’s inherent variance. Where random MCTS would break up action chains, playing the policy through many sampled beliefs gives a stable average value for high-variance actions such as shuffle-draw Supporters and chained draw Abilities.
Unlike VCGS, where the policy alone constructs routes for the judge to compare, BC-PUCT uses the judge’s feedback to decide what to explore next. Search improved winrate across nearly every deck pair we tested, by a median of about 9.3 percentage points.
These results span a 12-deck matchup matrix, with 2000 games per matchup. The experiment used a maximum search budget of 1000 routes per decision (B1000), with an average tree depth of 6 decisions.
BC-PUCT scales significantly beyond this. We saw further improvements at B3000, B5000, and B10000 budgets, but gameplay is too slow for a 144,000 game experiment. We tested search budgets up to 100,000 on NVIDIA RTX 3090, pushing our agent to spend nearly thirty minutes thinking about each game.
Performance Optimizations
Search produces many positions that need the same neural evaluation, so we batch them into a single GPU call. We benchmarked up to 4,096 positions per batch on an NVIDIA RTX 3090, achieving up to 42.4x the throughput of CPU inference.
We also cache model outputs, avoiding 68% of requested neural evaluations over a 10,000 game sample, and retain explored branches after a move, cutting whole-game time by 11.5%. GPU evaluation is fast enough that our search is now CPU-bound.
Self-Play
If search plays better than policy, we can use it to generate high-quality games to train our model, starting the “flywheel” of self-improvement. We present two systems for this: one that trains on searched games, and one that trains the judge directly.
Direct Gameplay Training
We generated ~10,000 searched games across a 24-deck matrix on an NVIDIA RTX 3090, repacked them into decisions, and fine-tuned our existing model.
Early on we patched weaknesses by pruning and suggesting specific lines, shaping what search considered without overriding evaluation. As training data accumulated, the model learned these behaviors and we removed the rules with no loss in performance.
Winrate improvements were modest, but suggest this strategy may compound over generations. We only had the resources for two fine-tunes, but plan to scale and continue the method in the coming weeks.
Winrate Approximation Training
Since our search leans heavily on the judge, we sought a more direct path to improving its accuracy. Inspired by the MCTS methods behind AlphaGo and AlphaZero, we trained the judge against measured winrates:
- Select many positions from policy-only self-play.
- From each position, fork the game 1,000 times by manipulating the random seed.
- Play each fork to the end using policy and save the winrate.
- Use the winrate as a training target for the judge at that position.
GPU batching makes this far cheaper than mining searched games. We labeled over 37.8 million positions, improving the judge’s accuracy by ~2%.
We observed no clear strength gain in searched gameplay. We hypothesize this is due to insufficient scale. Even with 37.8 million positions, they originated from only 37,800 roots. That is likely not enough data to avoid overfitting, so we plan to continue experimentation.
With sufficient compute, labeling millions or billions more positions should improve judge accuracy further, and with it search quality. Whether this method is more efficient than mining search gameplay remains to be seen.
Deck
A decklist is the product of two decisions, made under uncertainty: which archetype the format rewards, and which sixty cards best express it. We made both empirically, from real-world data and controlled testing.
Kaggle Metagame
The meta kept shifting, so a general model paid off: early training data was valuable even for archetypes we did not ultimately choose, and our model reached a high level across several of them. When the field settled, we could pick from an informed position.
Dragapult
Most archetypes have a linear strategy: each turn, attack with the best option available. Dragapult instead spends turns setting up, disrupting the opponent, and spreading damage. We chose Dragapult because its demands match what our system does well:
- Information gate sampling: Drakloak’s Ability, the main draw engine, reveals cards and asks which to keep; our search samples at the gate and evaluates each choice at the turn boundary.
- Multi-action planning: three energy types, flexible damage placement, and an arsenal of varied attacks create many interacting choices and competing lines each turn; our search plans and sequences them together.
- Turn-level evaluation: a setup turn’s value is in the threats it builds for later turns; our judge scores the full position, which is where that value lives.
Decklist Construction
We built a library of archetype decklists from ladder and over-the-board data, giving us the share of lists in each archetype that play a given card. This informs our own builds and feeds search, where our model can roll out the opponent’s turn from a predicted list.
Dragapult’s “skeleton,” the cards appearing in 95% or more of lists, already fixed 54 of 60 slots. We built two lists from there: Control, which maximized consistency, and Meta-predict, which anticipated what the field would bring.
Control played Dudunsparce, one of the most common cards in our training data, for draw consistency. Meta-predict played Chi-Yu, which knocks out Crustle in one hit, a difficult matchup we expected to resurge as Dragapult became popular. It also played Watchtower, which disrupted archetypes relying on Dudunsparce and Mega Kangaskhan ex, both common in the top meta. Holding the pilot and seeds constant with seats swapped, we tested variations of both builds to isolate the contribution of specific cards and card combinations.
Results
We won 57.4% of 1,999 games and peaked at a rating of 1124, inside the top twenty. Meta-predict outperformed Control against Crustle and archetypes utilizing Dudunsparce, consistent with its Chi-Yu and Watchtower card choices.
We built an internal ladder to measure progress, pairing model versions, search configurations, and decks against a field resembling the real Kaggle metagame.
We ranked the ladder with OpenSkill, normalized to our final Kaggle score. Our top internal ladder player is currently rated about 1165, peaking at 1221. We expect further gains with more self-play and higher search budgets.
Like the Kaggle leaderboard, our internal ladder exhibits cyclical and inconsistent behavior based on player luck. This makes any specific “snapshot” of the leaderboard unreliable, but still sufficiently shows that our top models are much stronger than our Kaggle submission.
Outlook
The Pokémon Trading Card Game is constantly evolving, and we believe the best models, like the best players, carry knowledge from format to format. We have seen early signs of this: tested on archetypes from past and future formats, our model competently played cards it had never seen.
We now have the systems in place to build on this atomic theory of the game: a model that adapts, predicts, and innovates over and over again.