The bot never guesses. It writes each heap in binary and XORs them together, column by column with no carrying. That's the nim-sum.
- Facing a nim-sum of 0? Any move you make breaks the zero, and the bot can always restore it. It keeps handing you zeros until it takes the last match.
- Facing anything else? Some move turns it into 0. Make that move every turn and you take the last match. Charles L. Bouton proved this in 1901, one of the first results in combinatorial game theory.
Every game starts with a nonzero nim-sum and you move first, so a perfect bot can still be beaten.
A key opens an issue titled like nim: take 2 from A (game 1, move 1). A GitHub Action plays your move and the bot's with src/nim.py, redraws the board and replies to you. Every pixel here is drawn by src/scenes.py.



