A competitive Pokémon bot at the top of the human ladder and professional play.
Laplace plays Gen 9 Random Battle on Pokémon Showdown, where it peaked at 2137 Elo and rank 447 worldwide. It utilizes a Monte Carlo Tree Search algorithm alongside a value-net and slight randomization to win every game.
Overview
Laplace
Every turn Laplace rebuilds concrete versions of the board it cannot fully see, then plays each one forward with a real battle engine. A small trained value head sits on top as a tie-breaker and touches maybe one turn in ten.
The name comes from Lapras, whose Japanese name is ラプラス, and from Laplace's demon: the idea of something that could predict the future if it knew the complete state of the world.
Half the board is invisible
The opponent's moves, item, ability and Tera type stay hidden until they get used. You have to evaluate a position you have only partly seen.
Both players commit at once
There is no move order to exploit. Plain minimax would quietly let the opponent see your choice before answering it, and every value it returned would be wrong.
Damage rolls, crits, secondaries
Even a fully known position branches on chance, so the best reply is a distribution over outcomes rather than a single line.
What makes the guessing worth doing: Random Battle teams are not arbitrary. The format builds them from a public recipe, so the space of hidden sets is large but structured, and you can weight a guess by how the game actually assembles a team.
How it works
One turn, five steps.
Roughly one to two seconds of thinking per turn, well inside Showdown's move timer. Eight sampled worlds, 150 ms of search each, across eight threads.
Everything the server has revealed
poke-env keeps the observable half of the game: revealed moves, items, HP, boosts, hazards, weather and field conditions. Nothing in this step is guessed.
Sample opponent teams that are still possible
The bot draws eight complete opponent teams, with real items, abilities, moves and Tera types, from Random Battle usage counts. Each one has to survive a filter against everything seen so far. Some of what goes into that filter is not obvious: Random Battle speeds are fixed, so an opponent that outsped when it should not have is holding a Choice Scarf, and every sampled world has to give it one.
Monte-Carlo Tree Search, once per world
Each sampled team goes to poke-engine, a fast Rust Gen 9 engine that runs about 250,000 iterations in 120 ms. Damage, priority, hazards, residuals, abilities, turn order and Terastallization are all modelled exactly, and MCTS handles the simultaneous turn honestly.
Pool the votes, then veto the blunders
The eight rankings average into one candidate table. A handful of deterministic guards then refuse known mistakes outright: a move that provably does nothing, locking the last Pokémon into a status move, attacking into an ability that nullifies it. The value head re-ranks only the near-tied cases where the engine's evaluation is known to be weak, usually against an opponent quietly setting up.
guards absorb · futility · noop · deadlock · tiebreak · mix
Do not be predictable
Always clicking the single best move is exploitable. Humans learn fast, and they will start switching an immunity absorber into a deterministic click. So among near-tied candidates the final choice is sampled instead of fixed. Terastallization is the exception, since it happens once per game and is never spent on a coin flip.
mix_root on, window 0.9
vs Foul Play 57% (17-13) mixed, against
28.3% (17-43) for a fixed pick
Live analysis
What a turn actually looks like.
analyze_battle.py plays one ranked game with the shipped configuration
and narrates it. share is the pooled visit count across
worlds, worlds is how many of the eight picked that move
outright, and eval is the engine's own win estimate.
== Turn 2 ========================================================== us Iron Hands 82% ##########.. 6/6 quarkdrive · assaultvest opp Scrafty 100% ############ 6/6 intimidate · ?item search 8/8 worlds x 150ms x 8t · 2.43M visits · 1.8s candidate share worlds eval -> Heavy Slam ####.... 0.27 4/8 0.57 Close Combat ###..... 0.19 2/8 0.54 Volt Switch ###..... 0.19 1/8 0.53 value net agrees: Heavy Slam 0.53, Close Combat 0.50, Volt Switch 0.50 guessed item unknownitem x8 · ability intimidate x8 · tera poison x8 inferred used since switch-in: Drain Punch >> plays Heavy Slam [1.8s, eval 0.55] expects switch Misdreavus 10% T2 opp Scrafty used Drain Punch -> Iron Hands 82% -> 64% T2 us Iron Hands used Heavy Slam -> Scrafty 100% -> 69%
Engineering
Every change has to beat the old one.
Most of the work was deciding what to keep. New code plays the old code on a local server, 60 games minimum, and the result settles it. Ideas that lost are written down next to the ones that won.
Cluster the losses
Every game is saved with a per-turn trace of what the search considered.
mine_losses.py groups losses into recurring signatures, using wins as a
control so a signature has to actually separate the two.
One cause, one narrow change
Each signature gets reproduced and traced to a specific flaw. One example: the engine knew a full-HP recovery move would do nothing, but kept clicking it anyway, so a guard now demotes any move whose outcome equals doing nothing.
60 games or it does not count
New code plays old code on a local server, judged on a Wilson confidence interval. Feeding the search real item stats without Choice-lock modelling lost at 39%. More search time on the stock evaluation did nothing at all, twice.
Replays
Real games, real opponents.
Four rated wins against high-Elo humans, rebuilt from the archived Showdown logs. These are the actual turn-by-turn records, animated from the protocol. Open the full replay to step through any of them yourself.
Full Showdown replays: Laplace vs schleeby (2308 Elo), Laplace vs Elite 4 Anubis (2256 Elo), Laplace vs BCena (2171 Elo), Laplace vs aalmeida.aamanda (2176 Elo).
Record across the archived run: 396-332 over 728 rated games · 46% across 163 games against opponents rated 2000 and above · highest-rated opponent beaten: 2308
Play against the bot.
A hosted instance you can challenge straight from the browser, with no local setup and no Rust toolchain. Pick Gen 9 Random Battle, hit challenge, and play the same build that laddered to 2137 while it shows you its reasoning each turn.
Status
- ✓ Ladder client, shipped config
- ✓ Live per-turn analysis view
- ✓ Replay and trace archive
- · Persistent hosted instance
- · Browser challenge flow
FAQ
Common questions.
The things people ask most often about the bot, its rating, and what is actually doing the work underneath.
What is Laplace?
Laplace is an open-source AI that plays Gen 9 Random Battle on Pokémon Showdown. It reads the visible half of the board, samples complete opponent teams that are still possible, searches each of those worlds with a Rust battle engine, and plays a mixed strategy over the moves that survive. It peaked at 2137 Elo and rank 447 worldwide.
How strong is Laplace on the Pokémon Showdown ladder?
Laplace peaked at 2137 Elo with roughly 81 GXE on the live Gen 9 Random Battle ladder, reaching rank 447 worldwide. That is the top 1% of active rated players, where opponents are strong humans rather than other bots. Across the archived run it went 396-332 over 728 rated games, and 46% across 163 games against opponents rated 2000 and above.
Can an AI beat human players at competitive Pokémon?
At the top of the ladder, yes. Laplace's opponents above 2000 Elo are strong humans, and it wins 46% of those games while sitting in the top 1% of rated players overall. The hard parts are not tactical: the board is half hidden, both players commit at the same time, and damage rolls make even a known position branch on chance.
How does Laplace handle hidden information?
It determinizes. Each turn it samples eight complete opponent teams, covering item, ability, moves and Tera type, drawn from real Random Battle usage counts and filtered against everything revealed so far. That filter includes Choice locks inferred from move history and Choice Scarf verdicts read off turn order.
Does Laplace use a neural network?
Only narrowly. A small value network with 368 hand-built features, trained on self-play to predict the winner at about 70% accuracy, re-ranks near-tied candidates on roughly 5 to 10% of turns. Everything else is search.
What is Laplace built on?
Python 3.12 for the agent, poke-env for the Showdown connection and the observable game state, poke-engine (a fast Rust Gen 9 engine) for the search, and PyTorch for the value head. Foul Play is the prior work the search design starts from.
Why is it called Laplace?
Two reasons. Lapras is called ラプラス (Rapurasu, Laplace) in Japanese. And Laplace's demon is the idea of something that could predict the future if it knew the complete state of the world, which is exactly the thing this bot cannot do and has to approximate by sampling.
Is Laplace open source, and can I run it myself?
Yes. The source is on GitHub at github.com/influxtion/Pokemon-Showdown-AI and it runs locally against a Pokémon Showdown server. A hosted instance you can challenge from the browser is in development.