Writeup

A Pokémon card agent that plays itself

×

The game

The job is to play Pokémon cards against other people's code. Not the real game on a table. A simulator called cabt, which is a rules engine that only offers legal moves, so the agent never has to guess what is allowed.

The interface

An agent here is a small Python file plus a 60-card deck. Each turn the engine asks, which of these legal options do you want, and you return an index. That is the whole interface. I shipped it as a tar.gz named submission.tar.gz.

Copy what wins

I did not start by inventing a genius policy. I watched what was already winning. Kaggle posts daily episode logs, thousands of finished games as JSON. A kernel I called ptcg-mine-meta parsed those files, grouped them by archetype, which is the family of deck, like a fire attacker or a stall list, and kept the most common winning deck in each family.

Watch winners. Play yourself. Send the file.

  1. 01Mine the winnersdaily episode logs → top deck per archetype
  2. 02Play itself50 games in cabt, sides swapped
  3. 03Ship itsubmission.tar.gz
A winning card from the logs, a self-play loop, then the tar.gz.

Make it play itself

Then I made that deck play itself. The self-play kernel copies the agent into a writable folder, because the Kaggle input disk is read-only, and runs fifty games with sides swapped so going first is not a cheat. I wrote the win rate and the error rate to a JSON file. If the agent crashes, you see it here before you waste a submission.

The score

The ladder is a rating, like chess. My accepted scores went 621, then a dip to 532, then 549, 571, 642, and 708. The last one is the one that counts. 2057 of 6807 teams. Mid pack. The climb is the part I care about, because it means the miner plus the self-play loop actually moved the number.

It went down once, then up. The last run is the one on the board.

Accepted ladder scores, in order. The last dot is 708.3.

What I won't pretend

What I would not claim. I did not solve the game. 708 is not the top of that board. The miner clones decks that already work. The self-play check is a sanity test, not a full search. If you want the next step, it is a better policy than copy the winner, not another scrape of yesterday's log.

The files

I put the files under the writeup. Take one, or take the zip.

writeup.md · 27 lines

# A Pokémon card agent that plays itself
## The game
The job is to play Pokémon cards against other people's code. Not the real game on a table. A simulator called cabt, which is a rules engine that only offers legal moves, so the agent never has to guess what is allowed.
### The interface
An agent here is a small Python file plus a 60-card deck. Each turn the engine asks, which of these legal options do you want, and you return an index. That is the whole interface. I shipped it as a tar.gz named submission.tar.gz.
## Copy what wins
I did not start by inventing a genius policy. I watched what was already winning. Kaggle posts daily episode logs, thousands of finished games as JSON. A kernel I called ptcg-mine-meta parsed those files, grouped them by archetype, which is the family of deck, like a fire attacker or a stall list, and kept the most common winning deck in each family.
## Make it play itself
Then I made that deck play itself. The self-play kernel copies the agent into a writable folder, because the Kaggle input disk is read-only, and runs fifty games with sides swapped so going first is not a cheat. I wrote the win rate and the error rate to a JSON file. If the agent crashes, you see it here before you waste a submission.
## The score
The ladder is a rating, like chess. My accepted scores went 621, then a dip to 532, then 549, 571, 642, and 708. The last one is the one that counts. 2057 of 6807 teams. Mid pack. The climb is the part I care about, because it means the miner plus the self-play loop actually moved the number.
## What I won't pretend
What I would not claim. I did not solve the game. 708 is not the top of that board. The miner clones decks that already work. The self-play check is a sanity test, not a full search. If you want the next step, it is a better policy than copy the winner, not another scrape of yesterday's log.

Credits

KindWriteup
DateSep 2026
TagsKaggle, Agents, Cards