Print statements for debugging once felt like the best thing since sliced bread. But what I didn’t realize was they were also holding me back.
I get it though, they’re easy to use, simple to set up, and when a lot of bot makers started there weren’t many other tools available. with some well-placed prints you can solve plenty of problems.
prints help us know what our bot is “thinking” when we’re testing. it’s usually the first thing a bot maker reaches for.
But they can become a crutch. When you run into a problem they aren’t good for you can find yourself drowning in a sea of prints. without the other tools at your disposal, you’re fighting a debug fire with a water gun, when there’s a whole set of hoses and extinguishers waiting for you. so what’s the alternative?
What happens when you have built a bot for a game that’s not finished and run into a crash? I sat down with Ben Cahill from Frost Giant to talk about just that when Storm Gate’s AI wouldn’t stop crashing
At the start of the year I added disruptors to my PiGBot. Getting them to fire their Nova Ball attack reliably—while avoiding friendly fire—was the hardest challenge I had taken on up to that point.
In one test run, I watched as the Nova Ball, seemingly locked on its target, suddenly veered off course, detonated early, and missed completely. It made no sense. Frustrated, I did what anyone else would do: added more print statements.
Print statements for the Nova Ball’s duration. Print statements for its available targets.
Before long I was staring at a wall of text in my terminal, trying to make sense of it all.
Weeks went by. I grew more and more perplexed.
Finally, I brought it up with the top bot creator of NegativeZero. When I showed him the problem, he just stared at the torrent of logs and said, “How can you get any information from this?”
I shrugged, and he showed me his setup. He walked me through in-game overlays, chat commands, and IDE tools—each one giving a clearer picture of what the bot was actually doing. That’s when I realized I had been working with the wrong lens. Let me walk you through a few of them.
Chat Debug
Similar to print statements, you instead get the bot to send updates of what it’s thinking using the in-game chat:
self.client.chat_send(“Your message here”).
The advantage over print is being able to pinpoint the timing with what’s happening in game. You can pause, rewind, and slow down the replay to match the chat message to the bot’s action.
Step Debugger
You’re probably familiar with this from other coding projects. When I first started bot development, I had a hard time getting it to work. But it’s less tricky than it looks once you set up debugpy.
set “type” to “debugpy”
set “program” to point at your bot’s entry script (usually run.py)
set “console” to “integratedTerminal” so you can see logs properly
• SC2PATH → the folder where StarCraft II is installed (e.g. D:StarCraft II)
• PYTHONPATH → your project folder (so IDE finds your bot code)
Once that’s in place you’ll be able to set breakpoints and pause your game to inspect variables.
Debug Commands & Display
what the game looks like with debug display
The most powerful is the ability to use Client.py within Python-SC2 to control and display debug representations right in the game. You can pause the game, generate units to create scenarios, write persistent labels to keep track of what’s happening, and draw shapes or lines to visually display what the bot is doing.
After adding these tools to my bot, I finally saw what was going wrong: the Disruptor’s Nova Ball was losing its target because I miscalculated the attack decay, which caused it to veer off course looking for something new. 🤦🏾♂️
🛠️ In the Workshop
🚀 PiGBot now can detect invisible units and dodge targeted attacks from Ravager’s Biles, Disruptor’s Nova balls and Psionic storm. If only it was so easy to dodge having to do a refactor of my attack system
🗒️ ./run Notes:
Level up your debugging with a simple visual tool. Here’s some starter code: