This week I participated in Cygni’s Paintbot Tournament, a programming challenge where the players write bots to play a game for them. The goal of the game is to color as many tiles as possible, this is done either by walking on a tile or blowing up a bomb. Bots can steal tiles from other bots by coloring a tile a second time (or third or fourth…). Whichever bot owns the most colored tiles at the end of the game wins.
We had about two weeks to prepare and program our bots. And it was a really fun two weeks! As time went on, I saw my bot clime the leader board playing against the, rather dumb, training bots. And eventually my bot placed first every time.
My first bot started out as a clone of the training bot “AggroBot”, and I gave it the creative name “AggroBot2”. One thing to note is that you could receive points blowing up bombs on enemy bots, and this was the goal of “AggroBot’s”.
I started by implementing a breath-first-search pathfinding so that my bot would not get stuck on obstacles. I weighted different tiles differently in the pathfinding, so that my bot would avoid stepping on the same tile twice or prefer stepping on other bots’ colors.
After a few days, it was time for a training tournament among my friends. I had set up my own Paintbot server and it was game on! My bot placed second of three. After discussing with the others, I decided I had to rework the strategy of my bot.
Instead of just blowing up my bombs on the nearest enemy, my bot would calculate the points it could get by blowing up for some of the nearby tiles and head there. But it would also count how many steps it had to take to get there. A few points less for a target much closer would surely yield more points in the end, then always reaching for the absolute best target.
Now on to optimize the bot. Caching a few values here, some parallel programming
there, and soon my bot was blazing fast. But there was one thing the bugged me,
from the server we receive an
explosionInfos array that should have contained
information about the explosions that happened the previous frame, but it was
always empty. This was a bug in the server.
Fortunately, the server was open source on GitHub and relatively easy to fix. I
deployed the fix on my server and my bot’s calculations had never been so fast.
I opened a pull-request fix, and the accepted and deployed the fix before the
tournament. (I should have added
if (bot == mine) winner = bot;)
One problem my bot encountered was that headed for bombs that other bots would reach before it. One solution to this could have been to ignore all bobs that were closer to an enemy, but not all enemies wanted bombs.
My solution was to create a GUI using the MonoGame framework, which also was really fun to work with. In the GUI I drew the game live as I played and allowed the user (me) to click on tiles the bot should go to or avoid. When left clicking on a tile, the bot used pathfinding to go there and then continue with its preprogrammed actions. When middle clicking a tile the bot’s pathfinding knew to avoid those tiles. With this feature I would be invincible!
Screenshot of GUI at the end of one of the training games during the tournament. “BotenAnna” is mine.
When the event started it began with two trial tournaments, to make sure nothing major was off with our bots. I noticed that my caching persisted between rounds, something making the bot crash. But we had time for small fixes like that.
In the real tournament, my bot place second in the first round which meant it would proceed. In the second round I pulled no punches and took control of my bot using the GUI. It got me a definitive first place. In the finals my bot would face “A⭐ is born”, “Painto Picasso” (two bots I had never faced before), and “Sonic the Hog” (a friend’s bot).
And my bot crashed immediately.
When setting up MonoGame I had to include a font for writing the players names with, and when doing this I only included some characters, and no default character for rendering unknown characters. So, the star emoji in “A⭐ is born’s” name crashed my bot, and I placed dead last.
Lessons learned, think about the edge cases! And not only about edge cases in the model of your programs, but in the UI too!
But over all I had fun and I hope Cygni host something similar again in the future.
Now that the tournament is over, I have published the code of my bot on my GitHub page.