Wolfe_Alt6767 plays Champions VGC Reg M-C doubles: Bo1 ladder with closed team sheets, plus open-team-sheet formats. It’s a transformer of about 7.5M parameters, trained mostly by self-play reinforcement learning, with a one-turn simultaneous-move search on top at play time. It briefly reached #1 on the M-C ladder; its sustained level is a performance rating of around 1800. Hardware: a 1070 at home for development, and a rented 5090 for the big training runs.
The simulator. Everything starts with a purpose-built battle engine in Rust, written specifically for Champions (stat points, the new Megas, the Champions move and status changes). Pokemon Showdown is used only as the reference:
- Exact copy. I first ported Showdown’s simulator bit for bit (its random number generator, event system and call order). It matches Showdown exactly on every one of 8,400 test battles, but it’s slow, so it serves only as a checker.
- Fast engine. The engine actually used for training is a simplified one. It agrees with the exact copy on about 99.8% of turns, and its damage calculation is 100% exact against Showdown on 30,000+ random cases.
- Fixing the gaps. A diff tool plays the same turn many times in both engines, flags positions where the outcome distributions differ, and ranks the moves, abilities and items involved by how often they show up. That told me which mechanics to fix first.
- Speed. About 38,000 random battles per second on one CPU thread, roughly 250,000 on 12 threads, a few hundred times faster than running Showdown. A self-play harness runs thousands of games in parallel and writes observations straight into preallocated numpy buffers, so the GPU never waits on the simulator.
The network. A transformer, width 256, 8 layers, over 17 tokens: 8 Pokemon, 8 tokens for our active Pokemon’s moves, and a field token.
- Inputs: besides embeddings for species, abilities, items and moves, each position includes precomputed damage numbers. For each of our moves against each foe, and theirs against us, it gets the expected damage and KO chance from the real damage formula, plus speed order and the last few moves each Pokemon used. The net doesn’t have to learn the damage formula; it gets the arithmetic for free and spends its capacity on strategy.
- Moves: chosen by pairing a move token with a target token, so targeting is part of the structure.
- Other heads:
- a value head;
- a team-preview head choosing among all 90 plans (15 ways to pick four × 6 lead pairs);
- a head that predicts the opponent’s next action from our point of view;
- a KO-prediction head as an auxiliary target.
Training.
- Imitation first. I ported my earlier heuristic bot (damage-calc scoring + a one-turn search) to Rust and recorded a million games of it playing itself. The net learned to imitate it, which gave it a sensible starting point instead of random play.
- Then PPO self-playon a pool of about 5,600 real tournament teams (VGC Pastes + Limitless) and some synthetic ones. Details that mattered:
- Who it plays: about half its games are against itself, the rest against frozen past versions plus a “hall of fame” of the best checkpoints, to avoid forgetting and to cut down on strategy cycling.
- Holding it near its start: a KL penalty first pulls it towards the imitation net, then towards a slow moving average of its own weights. Letting it drift freely made it collapse into overconfident play.
- Team preview is learned too, and ended up several points better than the hand-written preview.
- Open and closed information: half the games are played with closed team sheets, where unrevealed moves, items and abilities are hidden from the net, so it plays both formats.
- Validation teams: about 1 team in 15 is never trained on, so I can tell real improvement from memorising teams.
- Learning-rate plateaus: twice, an apparent plateau turned out to be the learning rate. Halving it gave 5–9 point jumps within hours. Training now checks every 2 hours against the net from 2 hours earlier, and halves the rate automatically when progress stalls.
- Search targets: later runs also mix in improved targets from the search.
Search. Each turn is treated as the simultaneous-move game it is:
- Candidates: the net proposes its best joint actions for us, and the opponent-prediction head proposes theirs.
- Values: each (our action × their action) cell is played out in the engine across several sampled “worlds”, and the value net scores the resulting positions. With closed sheets, each world fills in the opponent’s unrevealed sets from a library of real tournament sets that match what has been revealed so far.
- Budget: sequential halving spends the budget on the actions that are still contenders.
- Choice: the matrix is solved with regret matching. The final pick blends the net’s own preference with the search’s value advantage. That blend beat trusting the search’s raw maximum, which tends to chase lucky estimates.
The search adds a lot: in engine tests, the same net went from 44% to 62% against my heuristic bot with search turned on. I’m now replacing the sampled dice in the search with chance nodes (enumerating KO rolls, crits and secondary effects with their probabilities), after reading the Nessie thread.
Playing on Showdown. The hardest engineering problem was rebuilding Showdown’s position inside my engine. I built an audit mode: Showdown’s true internal state is attached to every decision and compared with my reconstruction. That found bugs no strength test would have shown, such as weather and terrain timers, Mega forms, entry hazards, and Fake Out eligibility being one turn stale. On the ladder it also keeps light scouting notes on opponents’ habits and plays with some randomness, because regular opponents (including other bots) started to read a deterministic bot.
Tools. The project’s real payoff for people is:
- A game-review tool, like a lichess analysis: calibrated win chances, a win-chance graph, move ratings from “best” to “blunder”, team-preview analysis, and a browser extension that reviews a finished Showdown game in one click.
- A “Matchup Lab”: paste two teams, and it plays tens of thousands of games to find each side’s best four and leads (an equilibrium over the preview choices), the hardest lead matchups, and the best turn-1 plays. You can then take over any of those positions and play the rest against the bot.
Happy to answer questions!