• Follow our Instagram!
  • Curious about what we're currently doing about bots? Check out the latest updates from staff in this thread.

Battle Bot mikumiku37: a self-play VGC bot reached #1 on the VGC Reg M-C ladder

Hi everyone. On October 1, mikumiku37, a bot I've been working on, reached #1 on the [Gen 9 Champions] VGC 2026 Reg M-C ladder at 1857 Elo, 81.2% GXE and 1775 ± 25 Glicko.

1790976621203.png

The ladder at 23:47 PDT on October 1.

The bot behind mikumiku37 is a small transformer (about 8.7M parameters) trained from scratch through self-play reinforcement learning: PPO against a league of its own past versions, with no human replays, and only terminal rewards. Part of the design is adapted from the Jaxcalibur technical writeup, with additional modeling for VGC and doubles layered on top. It trained on roughly 1,260 public tournament teams from Reg M-B and M-C (some spreads were guessed), inside a custom battle simulator that runs about 650x faster than Showdown. The bot can run with AlphaZero-style search, but the policy itself was trained without it.

The network encodes nothing beyond the game state. It sees the battle from its own side, plus static dex data (types, base stats, move data), with no damage calculator, Smogon usage stats, or speed resolver. The search is AlphaZero-style in that the policy network proposes moves and the value network evaluates positions, so no game is ever played out to the end. It does differ from Jaxcalibur's search in a few ways. Jaxcalibur runs a pUCT tree search four plies deep (about two turns), with 20,480 rollouts across 32 sampled worlds. Ours looks only one turn ahead, but treats that turn as the simultaneous-move game it actually is: in each of 16 sampled worlds, it builds the full payoff table of our top 8 joint actions against the opponent's top 8 replies and solves it for a mixed strategy, rather than growing a tree. Doubles makes this necessary, since two active slots and their targets produce far more joint actions than singles does.

Truth be told, none of this was the original plan. mikumiku37 was meant to be an A/B test: the same network as an earlier account, with search added on top, to see whether search helped. On its own, the network had peaked at 1747 over 100 games. With search, mikumiku37 went 248–110 (69.3%) and reached #1 in its 358th game, rotating among the ten teams that performed best during training. This surprised me, given that the model had trained for only 48.3 hours on a single consumer GPU (an RTX 5090); the checkpoint that reached #1 had played around 330 million training games. The network doesn't appear to be anywhere near saturating, and it's still training, so I expect near-future versions to be noticeably stronger.

For the time being, I am not planning on open sourcing the battle engine or the weights, given the potential impact it could have on laddering, and even official Pokemon Champions tournaments. However, I am thinking about other ways to make the model available as an educational or practice resource after it finishes training. There's a variety of possibilities with search visualization, interpreting how it scores positions, and so on.

For now, mikumiku37 is accepting challenges in Pokemon Showdown. It will play a random team that saw moderate success during training. A technical writeup is also coming up soon.

Happy to answer questions, and curious what people who played it thought.
 
Last edited:
Very cool stuff. I played the bot six times last night and had a suspicion it was one due to how fast it declined open team sheets haha. It made a few nonsensical plays, but overall played fundamentally well. It had the highest GXE on the ladder for most of last night which is itself an impressive achievement.

I’d be interested in helping out if you do further work with this!
 
Very cool stuff. I played the bot six times last night and had a suspicion it was one due to how fast it declined open team sheets haha. It made a few nonsensical plays, but overall played fundamentally well. It had the highest GXE on the ladder for most of last night which is itself an impressive achievement.

I’d be interested in helping out if you do further work with this!
Thanks! I was looking into a few confusing plays I saw on replays last night, and turns out they were caused by me leaving simulated RNG seeds during search at only 4 seeds. So it saw some outlier worlds that didn't make much sense. The version that's accepting battles is searching with 16 seeds, but ideally you want around 64~128.

Appreciate you playing it! I will continue to improve and test it before I put it to laddering again. Feel free to DM me on Discord (shao) if you want to talk about further work with it.
 
I respect the decision not to release this publicly, more craven characters I’m sure would try to make a quick dollar out of this with no regards for how damaging it could be to online tournaments.

Is there any way you could turn this into a web tool that gives advice on what Pokemon you should bring and especially what you should lead? I’ve been learning VGC recently and that feels like the most complex part by a wide margin, it would be nice to do revision before local tournaments if I could put in my pokepaste and it calculates good leads against meta teams, like ones that top-cut regionals for example. Obviously you can spend a few hours with a pen and paper doing that yourself but I’d rather spend that time practicing actually playing the game than thinking about what to lead in any given matchup.
 
the bot is extremely impressive. i went 3-9 against it tonight in a brief session; i mostly felt like the team i was using that i recently top 16ed baltimore regionals with got exposed, the bot was excellent at punishing its shortcomings in ways that many human players weren't able to. the bot isn't really using tricks, it just plays extremely fundamentally soundly. like i said, it's really impressive.

Is there any way you could turn this into a web tool that gives advice on what Pokemon you should bring and especially what you should lead? I’ve been learning VGC recently and that feels like the most complex part by a wide margin

please do not open source this or anything else related to the project, please keep the genie in the bottle. i don't want vgc to turn into chess where meta developments are derived from exploring the engine outputs.
 
As someone building a similar bot I would love to discuss further with you
my bot didn't get as far as yours but was able to ladder peak at 1700 normalizing around 1600
used rl with ppo but had a different approach. please dm me back: lordnimnim on discord.
 
Have you considered adding options to:
1. Have the bot ask for the pokepaste of the team it should use in the chat request in some way
2. Give people the option to ask to see two instances of the bot play each other with said teams for matchup testing purposes
 
Well, since I suggested it last time, can we run Deep Blue v. Kasparov but its mimikyu37 v. Wolfe/Cybertron/some other top VGC player/Michaelderbeste again
 
It is exploitable with kingambit. It doesn't seem to ever predict that you just attack it outright. Volcarona will always be free to overheat and raichu can focus blast.
 
If you ever do further work I'd love to help out! I've been trying to develop my own VGC bot, but I don't think I've gotten my strength anywhere near yours ELO-wise. This is so cool! Only 48 hours of training is crazy.
 
Really impressive project — I was especially interested in how differently the search is structured compared with Jaxcalibur.

I had a few technical questions if you don't mind.

First, for the one-turn search, how exactly is each cell in the payoff matrix evaluated? My understanding is that you apply each pair of joint actions in a sampled world and then use the value network to evaluate the resulting position rather than rolling the game out further. How are stochastic outcomes such as damage rolls, crits, misses, and secondary effects handled when computing that cell value?

Second, how does the policy represent VGC joint actions? Does the network score a complete joint action for both active Pokémon directly, including targets, or are the two slots predicted separately and then combined? I’m particularly curious about how it learns correlations such as double-targeting, Protect + partner attack, or coordinated switches.

You also mentioned that PPO self-play uses a league of past versions. How are opponents sampled from that league, and did you find this meaningfully better than pure current-policy self-play?

I was also curious about the choice to search only one turn ahead. The recent Nessie123 writeup takes a somewhat different approach: it solves the root simultaneous game and then selectively deepens leaves that are more likely to affect the root value. Did you experiment with anything similar? More generally, under a fixed inference budget, did you find that spending compute on a wider one-turn solve was more valuable than spending some of it on additional selective depth?

Finally, the compute requirement really surprised me. I had assumed that training a Pokémon bot at this level would require something closer to an H100 running for a week, so seeing ~330M games in only 48.3 hours on a single RTX 5090 changed my intuition quite a bit. How much of that efficiency would you attribute to the battle simulator versus the network/training setup itself? Do you have a rough sense of the simulator throughput or batch size during training, and whether the 5090 was mainly compute-limited or memory-limited?

Thanks again for sharing all of this — really interesting project!
 
Really impressive project — I was especially interested in how differently the search is structured compared with Jaxcalibur.

I had a few technical questions if you don't mind.

First, for the one-turn search, how exactly is each cell in the payoff matrix evaluated? My understanding is that you apply each pair of joint actions in a sampled world and then use the value network to evaluate the resulting position rather than rolling the game out further. How are stochastic outcomes such as damage rolls, crits, misses, and secondary effects handled when computing that cell value?

Second, how does the policy represent VGC joint actions? Does the network score a complete joint action for both active Pokémon directly, including targets, or are the two slots predicted separately and then combined? I’m particularly curious about how it learns correlations such as double-targeting, Protect + partner attack, or coordinated switches.

You also mentioned that PPO self-play uses a league of past versions. How are opponents sampled from that league, and did you find this meaningfully better than pure current-policy self-play?

I was also curious about the choice to search only one turn ahead. The recent Nessie123 writeup takes a somewhat different approach: it solves the root simultaneous game and then selectively deepens leaves that are more likely to affect the root value. Did you experiment with anything similar? More generally, under a fixed inference budget, did you find that spending compute on a wider one-turn solve was more valuable than spending some of it on additional selective depth?

Finally, the compute requirement really surprised me. I had assumed that training a Pokémon bot at this level would require something closer to an H100 running for a week, so seeing ~330M games in only 48.3 hours on a single RTX 5090 changed my intuition quite a bit. How much of that efficiency would you attribute to the battle simulator versus the network/training setup itself? Do you have a rough sense of the simulator throughput or batch size during training, and whether the 5090 was mainly compute-limited or memory-limited?

Thanks again for sharing all of this — really interesting project!

doing something similar currently (singles)

simulator quality matters a lot and is going to be the main blocker for someone without significant pokemon experience, but it's a matter of time before either llms are able to one-shot a reasonably accurate vectorized sim or someone open-sources one

the genie is well and truly out of the bottle

the compute bottleneck is near non-existent, you start hitting diminishing returns after about a day of self-play on a 5070, especially if you back it up with search - trivial in vgc, where sheets are open

there are a lot of people on this website with an undergraduate understanding of computer science and access to claude opus or gpt astra

there are in fact likely people cheating already, the ones posting in this subforum are just the ones experimenting for the sake of their own curiosity

i also frankly dont see any way to stop it - solid engines are light enough to run local and playing the correct Nash distribution of moves in pokemon is not inherently suspicious
 
Hi everyone. On October 1, mikumiku37, a bot I've been working on, reached #1 on the [Gen 9 Champions] VGC 2026 Reg M-C ladder at 1857 Elo, 81.2% GXE and 1775 ± 25 Glicko.

View attachment 867195
The ladder at 23:47 PDT on October 1.

The bot behind mikumiku37 is a small transformer (about 8.7M parameters) trained from scratch through self-play reinforcement learning: PPO against a league of its own past versions, with no human replays, and only terminal rewards. Part of the design is adapted from the Jaxcalibur technical writeup, with additional modeling for VGC and doubles layered on top. It trained on roughly 1,260 public tournament teams from Reg M-B and M-C (some spreads were guessed), inside a custom battle simulator that runs about 650x faster than Showdown. The bot can run with AlphaZero-style search, but the policy itself was trained without it.

The network encodes nothing beyond the game state. It sees the battle from its own side, plus static dex data (types, base stats, move data), with no damage calculator, Smogon usage stats, or speed resolver. The search is AlphaZero-style in that the policy network proposes moves and the value network evaluates positions, so no game is ever played out to the end. It does differ from Jaxcalibur's search in a few ways. Jaxcalibur runs a pUCT tree search four plies deep (about two turns), with 20,480 rollouts across 32 sampled worlds. Ours looks only one turn ahead, but treats that turn as the simultaneous-move game it actually is: in each of 16 sampled worlds, it builds the full payoff table of our top 8 joint actions against the opponent's top 8 replies and solves it for a mixed strategy, rather than growing a tree. Doubles makes this necessary, since two active slots and their targets produce far more joint actions than singles does.

Truth be told, none of this was the original plan. mikumiku37 was meant to be an A/B test: the same network as an earlier account, with search added on top, to see whether search helped. On its own, the network had peaked at 1747 over 100 games. With search, mikumiku37 went 248–110 (69.3%) and reached #1 in its 358th game, rotating among the ten teams that performed best during training. This surprised me, given that the model had trained for only 48.3 hours on a single consumer GPU (an RTX 5090); the checkpoint that reached #1 had played around 330 million training games. The network doesn't appear to be anywhere near saturating, and it's still training, so I expect near-future versions to be noticeably stronger.

For the time being, I am not planning on open sourcing the battle engine or the weights, given the potential impact it could have on laddering, and even official Pokemon Champions tournaments. However, I am thinking about other ways to make the model available as an educational or practice resource after it finishes training. There's a variety of possibilities with search visualization, interpreting how it scores positions, and so on.

For now, mikumiku37 is accepting challenges in Pokemon Showdown. It will play a random team that saw moderate success during training. A technical writeup is also coming up soon.

Happy to answer questions, and curious what people who played it thought.
hi this bot of yours is really cool ive played it 3 times with perish and won all 3 are teams like a blindspot of the ais if so id love to know why
 
Does it only accept challenges in the standard Reg MC format or does it accept challenges in the bo3 format as well?
It's currently taking Bo1 only, but I've enabled open team sheets. At match start, the bot wait for 20 seconds, and it matches your choice if you accept OTS.

hi this bot of yours is really cool ive played it 3 times with perish and won all 3 are teams like a blindspot of the ais if so id love to know why
Perish was bugged earlier in the search engine, but it's been fixed now. I've been monitoring the win rate against Perish teams and it seems to do well into it. Let me know if anything seems off.

Really impressive project — I was especially interested in how differently the search is structured compared with Jaxcalibur.

I had a few technical questions if you don't mind.

First, for the one-turn search, how exactly is each cell in the payoff matrix evaluated? My understanding is that you apply each pair of joint actions in a sampled world and then use the value network to evaluate the resulting position rather than rolling the game out further. How are stochastic outcomes such as damage rolls, crits, misses, and secondary effects handled when computing that cell value?

Second, how does the policy represent VGC joint actions? Does the network score a complete joint action for both active Pokémon directly, including targets, or are the two slots predicted separately and then combined? I’m particularly curious about how it learns correlations such as double-targeting, Protect + partner attack, or coordinated switches.

You also mentioned that PPO self-play uses a league of past versions. How are opponents sampled from that league, and did you find this meaningfully better than pure current-policy self-play?

I was also curious about the choice to search only one turn ahead. The recent Nessie123 writeup takes a somewhat different approach: it solves the root simultaneous game and then selectively deepens leaves that are more likely to affect the root value. Did you experiment with anything similar? More generally, under a fixed inference budget, did you find that spending compute on a wider one-turn solve was more valuable than spending some of it on additional selective depth?

Finally, the compute requirement really surprised me. I had assumed that training a Pokémon bot at this level would require something closer to an H100 running for a week, so seeing ~330M games in only 48.3 hours on a single RTX 5090 changed my intuition quite a bit. How much of that efficiency would you attribute to the battle simulator versus the network/training setup itself? Do you have a rough sense of the simulator throughput or batch size during training, and whether the 5090 was mainly compute-limited or memory-limited?

Thanks again for sharing all of this — really interesting project!
Thanks! For the search: yeah, each cell is "apply both joint actions in a sampled world, then ask the value net about the next turn's position," with no rollout. Chance is handled by sampling. We step the real engine with several different RNG seeds per cell, so damage rolls, crits, misses and secondaries come from actually drawing them, and then we average the value net over seeds and sampled worlds. There's probably a smarter way to do this. Then we solve the matrix with regret matching, blending worst-case with expected value. On joint actions, each slot's action already includes its target. Slot 1 is predicted first, then slot 2 is predicted conditioned on slot 1's choice through a pairwise term, with legality masks on the pair.

On the league: about half the games are against the current policy, and the rest against past snapshots. Those are weighted towards the ones it still struggles with (PFSP-style). Honestly, I never ran a clean ablation against pure self-play. It's mostly some level of insurance against exploiting and forgetting but this one is just vibes. Pure self-play might be better.

I did try endgame deepening, and slightly positive on endgame starts (~51.4%) but it's really not significant and the added compute was not worth it. Maybe I'll look more into this.

About the compute. The simulator is a Rust engine doing ~7k random battles/s on a single core. During training it's 8,192 battles in parallel, 32 steps each per update (~262k samples), and collection runs at ~100k steps/s including network inference. The PPO gradient update is ~70% of wall time, so the 5090 is compute-bound on learning, not waiting on the sim. I first had this idea when I had the model architecture around an year and half ago, but I was getting ~700 battles per minute on Showdown, while also encoding observations from text parsing which is just bad. That was keeping maybe 0.5% of my GPU busy.
 
Last edited:
Hi everyone. On October 1, mikumiku37, a bot I've been working on, reached #1 on the [Gen 9 Champions] VGC 2026 Reg M-C ladder at 1857 Elo, 81.2% GXE and 1775 ± 25 Glicko.

View attachment 867195
The ladder at 23:47 PDT on October 1.

The bot behind mikumiku37 is a small transformer (about 8.7M parameters) trained from scratch through self-play reinforcement learning: PPO against a league of its own past versions, with no human replays, and only terminal rewards. Part of the design is adapted from the Jaxcalibur technical writeup, with additional modeling for VGC and doubles layered on top. It trained on roughly 1,260 public tournament teams from Reg M-B and M-C (some spreads were guessed), inside a custom battle simulator that runs about 650x faster than Showdown. The bot can run with AlphaZero-style search, but the policy itself was trained without it.

The network encodes nothing beyond the game state. It sees the battle from its own side, plus static dex data (types, base stats, move data), with no damage calculator, Smogon usage stats, or speed resolver. The search is AlphaZero-style in that the policy network proposes moves and the value network evaluates positions, so no game is ever played out to the end. It does differ from Jaxcalibur's search in a few ways. Jaxcalibur runs a pUCT tree search four plies deep (about two turns), with 20,480 rollouts across 32 sampled worlds. Ours looks only one turn ahead, but treats that turn as the simultaneous-move game it actually is: in each of 16 sampled worlds, it builds the full payoff table of our top 8 joint actions against the opponent's top 8 replies and solves it for a mixed strategy, rather than growing a tree. Doubles makes this necessary, since two active slots and their targets produce far more joint actions than singles does.

Truth be told, none of this was the original plan. mikumiku37 was meant to be an A/B test: the same network as an earlier account, with search added on top, to see whether search helped. On its own, the network had peaked at 1747 over 100 games. With search, mikumiku37 went 248–110 (69.3%) and reached #1 in its 358th game, rotating among the ten teams that performed best during training. This surprised me, given that the model had trained for only 48.3 hours on a single consumer GPU (an RTX 5090); the checkpoint that reached #1 had played around 330 million training games. The network doesn't appear to be anywhere near saturating, and it's still training, so I expect near-future versions to be noticeably stronger.

For the time being, I am not planning on open sourcing the battle engine or the weights, given the potential impact it could have on laddering, and even official Pokemon Champions tournaments. However, I am thinking about other ways to make the model available as an educational or practice resource after it finishes training. There's a variety of possibilities with search visualization, interpreting how it scores positions, and so on.

For now, mikumiku37 is accepting challenges in Pokemon Showdown. It will play a random team that saw moderate success during training. A technical writeup is also coming up soon.

Happy to answer questions, and curious what people who played it thought.
Hey I am also trying to experiment with this as well, I was curious if you had a writeup for reference?
 
Back
Top