I Spent 120+ Hours on Coding in January 2021 and I Didn’t Get Paid for It as a Developer

120+ hours of my time in January was not mine. I gave it up to finally achieve a goal I forgot I had up till now. That goal was to compete in the 2021 AI competition called Battlecode. 

I recall some time in my sophomore year of college in  2015-16 that a friend of mine had mentioned Battlecode. He was interested in it but it had already ended that year. I remember going through some of the Battlecode website and thinking it looked pretty cool and then forgetting about it until next January. Each year the time came around and I would go to the page and check out the last year’s game or read about the page but I never felt I could attempt to compete in it. 

Finally, after years of checking out the page and reading in-depth postmortem strategies, and glancing through the code of the winners and other competitors, I decided it was my year to compete. I didn’t care what programming language it was going to be in or how challenging it would be to set up, I was all in. 

Below I give a short introduction of what Battlecode is, followed by an introduction to this year’s theme with basic spec information. Afterward, I’ll share some of my thoughts going into the competition and how it played out from my perspective. This would include how my strategy shifted and what I changed with my bot. Finally, I’ll close with my thoughts on the experience and how it made me a better programmer. 

Overview

Introductions

Intro to Battlecode

Welcome to MIT’s longest-running programming competition, Battlecode

Most of this is paraphrased from their website. Battlecode is a real-time strategy game in which competitors write an AI player to compete with. The AI player has to be strategic about managing a robot army and control how the robots work together to defeat an opponent. It has been called the “Super bowl for programmers.” They also mention that as a contestant, I will learn how to use artificial intelligence, pathfinding, distributed algorithms, and communication to make the AI as competitive as possible. I definitely agree with that statement. Without spoiling anything, I learned all of those concepts, but they weren’t all learned from the lectures the developers put on. I actually learned quite a lot from the contestants themselves who are mostly students. 

Everyone has about 22 days (4 more if you qualify for finals) to write an intelligent AI in a constrained environment. There are even fewer days if you are not a student due to the eligibility rules for their tournaments. With that knowledge in my mind, at the beginning of January, I immediately joined the Discord, followed Battlecode on Twitch, and started devouring anything I could about the upcoming game. 

Intro to Battlecode 2021

The game this year was related to politics due to the election I believe. The robot types were, the Enlightenment Center, Muckraker, Politician, and Slanderer. 

The objective was to either have the most votes by the end of the 1500 round limit or to eliminate all the opponent’s robots from the field. 

Each robot has a circular radius of vision that can determine information such as what robots are around or the location of squares in the radius. Each robot can also perform an action, such as movement, or a specific ability for the type, providing that their cooldown is below 1. They each have different cooldowns as well depending on their type. 

Something important to know is that each robot runs its own instance of the code you write for it and cannot share variables with other robots at all. This was new to me and it got me very excited to think of solutions to this. The only way a robot could communicate was through a “flag” variable that represented a 24-bit integer. In order for Robot A to read Robot B’s flag though, Robot A had to have Robot B’s RobotID. This could be tricky if Robot A has never seen Robot B in its vision radius before. 

The “health” of a unit was determined by influence and conviction. Influence represented the base health of the robot. A robot’s conviction can go higher or lower throughout the game depending on what happens but cannot go higher than the initial influence. Once the robot’s conviction goes below 0 (not at 0), it is either “converted” to the other team, or dies. 

The maps are played on a 2D square grid where units can move in 8 directions, north, northeast, east, and so on. The coordinates are between 10,000 and 30,000 and are randomly generated. This can be seen in the following image:

From the Specs document.

In previous years, there were impassable squares that a robot would need to move around. This year, passability was instead used for each map tile and it was given a rating between (1 – 0.1). The passability determined the cooldown of a unit’s action. For instance, if a passability was (0.4) and a robot went across it, the robot’s cooldown would add 6 turns to it. So lower passability slowed down robots by increasing the cooldown for the unit. Higher passability on maps were denoted in a lighter color while lower passability is denoted with a darker color. 

Here is more details regarding the different robot types:

Battlecode 2021 units for blue and red teams

Battlecode 2021’s units. From left to right: Politicians, Muckrakers, Slanderers, Enlightenment Centers

  • Enlightenment Centers (EC) are the only immobile robot and they functioned as a base to spawn other robots. They generate influence each turn based on the round number and use that influence to create more units.The EC determines the influence of the unit spawned and that influence is taken from the EC’s influence.  Maps also can have neutral enlightenment centers that can be captured by your politicians. This unit also uses the ability of “Bid” in order to bid a specified amount of influence in order to attempt to gain a vote.
  • Politicians (Polis) are the main attackers for your team and use an ability called “Empower.” This is used in a specific radius around the robot and will use a function to determine how much damage it does to an enemy and how much health/conviction it heals allies. The function is ((C – 10) * empowerFactor) / n where C is equal to the amount of conviction the robot has and “n” is the number of robots in the radius of attack. The “-10” is the politician tax that is incurred in order to empower. The empowerFactor is associated with the Muckrakers. 
  • Muckrakers (Mucks) were used as the main scout unit since they have the largest vision radius. They also have the ability to “expose” slanderers which will destroy the slanderer and increment the muckraker “buff” for your team. The muckraker buff can also be called the “empower factor” because it is used when determining how much damage is done when an ally politician “empowers.” They still have a limited action radius even with a larger vision radius. 
  • Slanderer (Slands) was able to passively use an ability called “embezzle” which would generate income at a specific rate according to how much influence you gave the robot. They also have a passive ability called “camouflage” which makes them look like a politician except to a Muckraker. They only generated over 50 turns and then at turn 300 of their life, they turned into a politician. These robots needed to be protected from Muckrakers otherwise the other team would get a special boost. 

Here are more details associated with the robots:

Source: From the specs on Battlecode2021.

How the Competition Worked

So something I found out right away was that I only qualified for the first two tournaments. Overall the tournament schedule was as follows:

In previous years, the 2nd tournament was used for seeding and non-students would not be able to participate. I didn’t find this out right away so it was an awesome surprise once the 2nd week started that I could still participate. 

The tournaments leading up to the final week were run as single elimination and then the finals week of tournaments were double elimination. 

Throughout this time, there were scrimmages that were used to rank teams on a leaderboard. Ranked scrims would run every couple of hours with about 4 games at a time to determine your ELO (skill rating). Teams could also request unranked scrimmages to see how they match up against another team. I did this often and found it helpful to watch the replays and see how my bot would do against other teams.

Let’s Talk About the Code!

Sprint 1 – The First 7 Days

After waiting a couple of days in January, the first day of Battlecode was finally here. Teh Devs (no that’s not a typo, that’s what they call themselves ha!) waited until the evening of the 1st Monday to livestream and walk through the specifications and what the game was about. I tuned in to watch and followed along very excited to get it working.

I downloaded the necessary files and began to read through the specs, which refers to the document and information about how the competition works, in more detail. I was learning a lot from the Discord channels as I struggled through the installation of the client and worked to get it set up using Visual Studio Code. Thanks to all those early people answering questions and being patient with newbies. I definitely needed those questions answered too. 

The programming language the competition was using this year was Java. I believe it used that in the past as well but I had never personally coded in Java. Fortunately to my delight and surprise, Java is very similar to C#, which I had been coding in the last 2 years at my job. In college, I remember vaguely programming in Java with a clunky IDE and I could not figure it out. The IDE was called Eclipse, and nothing against Eclipse, I just couldn’t figure out how to get this game setup with it. I had hoped to use it for debugging purposes but instead I ended up using the console to print out statements with variables or the classic “Here!” string to mark where the code was going. 

Once I finally got the client installed, Java 8 downloaded, and Visual studio code connected, I began to look into the code. Teh Devs gave us an example bot with very nice comments explaining what everything did. It was a great starting point and I started to understand how it worked. 

Something that was mentioned a lot throughout the specs and Discord channel was the bytecode limit. I didn’t really understand what that was until a couple of days into the competition. I explain more about it in the appendix here (hopefully I remember to link it) but the gist of it is that they need to limit the computation each bot gets in order to make the game interesting and force the competitor to be creative. Each statement in your code incurs a bytecode payment and so the bigger the statement, the more bytecode it uses up. I actually didn’t run into any issues with bytecode until the second week, but I still learned a lot regarding it.

The coolest things I learned were through a lecture talking about communication and pathfinding. For one thing, I had no idea what pathfinding algorithms looked like until one of Teh Devs, Jerry, explained it on Twitch. He went through Bug pathing and the different versions of it. The next part about communication was game changer for me with my bot. 

The only way in this game to communicate with another bot was through a “flag” that could be set to a number of 2^24 bit integer. So, when I wanted to have my robot communicate to my home base “Hey, I found the enemy base, it’s over here”, I ended up sending the x-coordinate, then the y-coordinate in 2 separate turns by setting the flag to each coordinate on opposite turns. This worked for the most part and I did spend a decent amount of time implementing it, but it wasn’t very efficient and could be prone to issues if I missed a coordinate somehow. 

That’s when Jerry introduced a completely different approach to communicating an (x,y) coordinate that could be done in 1 turn with a 2^24 bit integer. The approach was called Bitmasking. I discuss it more in the appendix below, but it felt awesome to first learn the way to do it, and then go through my code and implement it. 

After getting the communication working, I was able to beat the example bot and that felt great. To have a functioning and winning bot made me feel invincible. 

The rest of the first weekend was filled with trying to get a Muckraker spam coded as the top teams seemed to be doing that strategy. Essentially sending so many Muckrakers with 1 health that you could surround the enemy base. 

I took this strategy a step further after watching SuperCowPowers (who ended up winning Sprint 1 & 2!) use the Muck spam by surrounding an enemy EC but when he sent politicians to take over the enemy EC, the Muckrakers would move away from the enemy EC to make sure there was no dilution in power when the ally politician struck. That was very cool to get coded in as well. 

So putting all of this together, feeling the Monday deadline to the tournament, I ended up pulling my first all-nighter related to coding. What a strange achievement to have, I stayed up working Saturday night into Sunday morning around 5am. The time passed so quickly and I was wired the entire time without any caffeine as well. 

Monday came and I wasn’t quite ready. I had real work to do though but with the crunch of the deadline coming up quickly,  I ended up taking some vacation time to continue working on the code. The submission was due at 6:00PM CT and I worked about right up to the deadline. Later, I would, of course, find bugs but I think everyone had that experience. 

My lesson from the first week is to test a LOT and don’t try to implement new features right before the deadline if you can’t test it properly. Also, holy cow is the Discord active. It was tough to keep up to date with everyone. 

Sprint 2 – The Next 7 Days (7 – 14 days)

As I mentioned above, I didn’t realize I could participate in the 2nd Sprint tournament until after the first weekend of late night scrambling. In my head, the first tournament was the only chance I had to get onto the “big screen” on the twitch stream. 

I took notes during the first tournament after being knocked out early on and set to improving my bot. The biggest things I needed to improve was having my bot take neutral EC’s and to communicate better as well as having a good build order. Essentially, I had a functioning bot that could figure out how to attack an enemy base, but it wouldn’t consider anything else. I had a lot of work to do. 

The beginning of the week was slow for me with coding, I was still at my girlfriend’s family’s house and I was enjoying their company as well as working at my real job. It wasn’t until Thursday evening that I jumped into my code once more and started applying everything I was learning through Discord and the streamed lectures. I had a lot of things to catch up on and as I began applying the new strategies, my ranking started shooting up. The biggest improvement was actually going for neutral enlightenment centers which many people in the lower tiers hadn’t programmed in yet. 

I was feeling pretty good about my bot and the progress it was making as I headed into the weekend. The trouble that appeared in my Sprint 2 Bot began once I started checking replays of my bot versus some of the higher ranked teams. The specific one I recall that had the most impact on my sleep the next two nights was against California Roll, a.k.a Stone2000. He probably had no idea the amount of time I added to my bot due to the game but if it wasn’t him it might have been another team. The issue was his robot destroyed my robot by getting all of my slanderers which allowed him to get a huge buff which was used to then “self-empower.” Self-empower was a strategy of using the big buffs of 500x+ to create a huge politician and then have it empower near your EC which would give you the politician’s conviction multiplied by the 500x buff. It was an exponential growth that was a big strategy the 2nd week of the event. 

When I saw how easy it was for him to take out my slanderers, I knew it was time to try implementing a defense. The defense in this game was difficult to create and I went in not knowing the scope of what I was trying to accomplish 2 nights before the 2nd Sprint tournament. 

The idea I wanted to implement, since I had seen the other top teams do it, was to use weaker Politicians to circle around my Slanderers and kill incoming Muckrakers before they got close to the slanderer. The idea was pretty straightforward, however, coding it was another task entirely. Working with limited time to implement this change, I stayed up very late throughout the weekend and had another all-nighter attributed to coding the bot. By the end of the weekend, I had a working bot that I should have uploaded but I wanted to make it even better. The next step was to try pathfinding. 

On the Friday of that weekend, teh Devs came out with their last lecture which was expanding on pathfinding. I went through the video and tried my best to follow the code and ideas behind it to no avail. I ended up adding in something to try the pathfinding right before the deadline which ended up hurting my bot a lot. I didn’t get a chance to test it out against real opponents, and at that time, I was still not using old versions of my bot to test, so the bot was submitted for the Sprint 2 tournament with bugs in it. 

I ended up getting on the big screen (Twitch streaming) but was quickly defeated and out of the tournament. Fortunately, I wasn’t too upset, I was having way too much fun coding the bot and making it better to worry too much. It would have been nice to have recognition but I was happy with seeing myself as the underdog. 

My biggest take aways from this week was:

  1. Test your code after changes no matter what.
  2. Don’t try to make a huge change right before a deadline. 
  3. Settle for “good” before trying to achieve “great”, you may end up making your project worse than it started. 
  4. Make lots of commits when working on a project. 

Qualifying Tournament Week – (14 – 21 days)

From the start of Battlecode this year, I knew I would keep working on the robot until the end. Even though I wouldn’t compete anymore, I could still scrimmage with other people and that was exciting enough for me. 

The last full week and weekend available, I continued to code out bugs and try to add in more features. Part way through the week, a big update to how the Muckraker buff was implemented which rendered the strategy to self-empower your Enlightenment Center void. The buff only applied to when you attacked with a politician at your opponent. This update wasn’t too bad for me though since my defense was still subpar and I hadn’t focused on winning with the self-empower strategy. 

A lot of the week was messing with the build order and the logic for when to spawn a certain robot. Most of the basic mechanics had been finished and I was to the point where I was, as one player described it, “turning dials” in regard to what robots would spawn and what amount of them. 

The last couple of cool things that I implemented was an actual working pathfinding and adding communication for what conviction a neutral or enemy enlightenment center was at. 

The pathfinding ended up being a manual search for everything ahead of the robot. They would get a distant point and look at only the squares that would get them closer to the point, from there, the robot chose the square with the highest passability. For the most part, this worked the way I wanted it and it was at least better than having nothing especially on certain maps where the low passibility tiles were spread out. Teh Devs definitely wanted to have pathfinding be relevant. 

The last update to communication I made was a decent challenge. The challenge came from figuring out how I would store coordinates and keep everything organized in the code when the Enlightenment Center received communication from a bot. The goal was to have a bot send not only the coordinates of the neutral or enemy Enlightenment Center location, but also the conviction that the Enlightenment Center was at. With the neutral locations, it was a little easier as the conviction would not change other than if it would go lower if the opponent tried to take it. The enemy Enlightenment Center was a bit trickier to figure out but in the end I did a decent job. The code would start saving the amount necessary for the neutral or enemy location once found and then send a little more than enough for the capturing. This helped a lot when capturing multiple neutral bases as once the Enlightenment Center sent the robot to one neutral base, it would switch focus to the next one. This resulted in more neutral bases captured quicker which allowed more robots to be built. I believe this update resulted in a couple more wins but at this point in the competition, the people I played were very good. 

My lessons I learned from Week 3:

  1. Watch replays a lot in order to improve your strategy. 
  2. Refactor your code in order to save time when working on improvements.

Final 4 Days

The final couple of days were for the top teams to continue refining their bots and get a couple of last minute scrimmages to see if the changes were beneficial or not. Essentially, the teams were guessing at this point though since it’s hard to predict what the maps would be and most of the games were decided based on the maps. 

I spent my time continuing to scrimmage people and testing out new code I would put in. The change ideas would come from watching other bots and replays and how their bot did something cooler or better than mine, so I would try to incorporate that into my bot. 

The final event was fun to watch and Teh Devs had the team members themself commentate on their own games and it was entertaining to hear and see the players on video. The final games can be seen here: https://challonge.com/bc21_final

Final Thoughts 

This event was a ton of fun. I have never spent so much time coding on something in this short amount of time. The event was well done and I enjoyed the process immensely. It helped me become a better coder by far starting with the fact that it was in a language that I hadn’t coded in before. I did a little of Java in college but I didn’t remember anything from that. Learning the differences of Java compared to C# was cool. It felt rewarding to push myself and surround myself with a group of smart people around my age who were also coding a lot and incorporating strategies and concepts I hadn’t thought of. The event as a whole helped me grow and I am a stronger coder due to it. I am looking forward to the next year of competition and I wanted to say a final congratulations to all the participants. The time spent here will be remembered and worth it in the long run. 

More Post-Mortem-Type Posts From Other Players

https://www.stoneztao.com/blog/posts/20210201/

https://ivyzhang.me/bc21-postmortem

Stats

Lines of Code:

ExtensionTotal CodeTotal CommentTotal Blank
.Java4039287567

Commits

The Number of Participants and Teams

  • 656 teams & 1605 individuals 
  • Finalists 20 teams & 52 individuals

Sprint 2 Ranking:

My Elo Rating Over Time

Meta This Year

  1. Muckrakers Spam at 1 health 
    1. Surround the Enemy Enlightenment Centers with Muckrakers
    2. Get a huge buff and self-empower.
  2. Defend with Politicians the slanderers.
  3. Buff Muckrakers to take out enemy slanderers

Leave a Reply

Your email address will not be published.