Key Takeaways from a First-Time Contestant
I was dragged into Battlecode 2024 by one of our teammates. I had never heard of Battlecode before, but I was excited to try it out. I had a lot of fun and I’m glad I did it, and we ended up qualifying for the finals and placing 13th overall. So I figured I’d write a blog post about the experience from the perspective of a first time participant.
This was cross-posted from my blog, so if you’re interested check more out there.
What is Battlecode?
Battlecode is a contest where you write code to control a team of robots that have to accomplish some task. You can read more about it here.
This year the game was a duck based capture the flag game where our goal was to capture all 3 of the flags from the opponent. The game is played on a grid and each team has a base where they spawn ducks. Ducks can move around the map, build traps, and attack other ducks. The game is played in rounds, and each round the ducks are given a set amount of bytecode to execute their actions.
Here’s a quick snippet of what the game looks like
There’s a lot going on in that gif so let’s break it down a little bit.
Duck Actions
Each duck has a few actions to help attack or defend flags that it can perform each turn/round (shown at the bottom of the gif above). Each action has a specific cooldown so you can’t just spam the same action over and over again.
- Move to a new tile
- Build traps: water, bombs, stuns, dig a water pit, and fill a water pit
- Pick up flag
- Attack an enemy duck
- Heal
- Respawn
– When a duck dies, it can respawn at one of the team’s spawn points after ~20 rounds
Crumbs
There’s also a currency called crumbs that you can get from two ways: a few spawn on the map each round which you can pick up, and you also get some for killing enemy ducks in their territory.
Actions that build traps require crumbs, which requires you to be strategic about how you use your crumbs.
Why It’s Difficult
Since the same code gets deployed to all the ducks, you have to write code that can handle a lot of different situations. Maybe you want some ducks to focus on defending and building around base, maybe you want some designated to go out and capture flags, and maybe you want some to be aggressive and attack the enemy ducks.
A few things that make it difficult:
- There’s a limited size shared array that each duck can read and write
– This is the only way to communicate information between your ducks about the state of the game
– This means you have to be strategic about what information you store in the array and how you use it, and if you have all your ducks performing the same action based on the same information you have to be careful because otherwise they’ll cluster up doing the same thing so you have to be careful about how you distribute the work - Each duck is given 25K bytecode to execute per turn
– This means that each turn each duck gets to execute a certain number of actions, calculations, and memory reads and writes.
– If you want super good pathfinding (which we didn’t have) you have to be careful about how you use your bytecode in intensive calculations like this otherwise you’ll run out of bytecode and your ducks will just sit there and do nothing
– Luckily we didn’t have to worry about this too much since 25K is quite large and apparently in previous years its been much smaller
I also feel like it’s really hard to tell if your new bot is better than the previous version, like usually it’s better in some situations and worse in others. Unlike most software I’m used to working on it’s easy to tell if what you’ve made is better than before since if you added a new feature it’s better than before.
For this I’d say like at least half of the features I tried to develop didn’t work super well and just ended up scrapping the changes. There’s so many branches for dead features that just didn’t work out.
The Contest Structure
Ok so now that we have a basic understanding of the game, let’s talk about the actual competition.
Leaderboard
The leaderboard is one of the most important parts of the contest. It’s a semi-live leaderboard that shows the rankings of all the teams in the contest. Every 4 hours there would be ranked games played against your relative neighbors on the leaderboard and if you win you gain more points and if you lose you lose points.
Furthermore, you can manually queue your own ranked games against other teams as long as they allow it. This is important because you can’t just queue games against the same team over and over again to farm points.
However, you can also queue unranked games against any team which is important for testing your bot against other teams to see if the changes you made are actually better than before against real opponents.
Sprints
Sprints are a separate part of the contest where the organizers run a bracket of games and livestream the results. Sprints are played across all teams whether they’re in your division or not. The sprints are a fun way to see how your bot is doing against other teams and it’s also a good way to see how the other teams are doing.
The seeding of your team in the sprints is based on your leaderboard ranking, so if you’re doing well in the leaderboard you’ll be seeded higher in the sprints.
Tournaments
Tournaments are also livestreamed and are played across the teams in your divison in the same way as the sprints. The seeding of your team in the tournaments is based on your leaderboard ranking, so if you’re doing well in the leaderboard you’ll be seeded higher in the tournaments.
In our year the top 12 US college teams and the top 4 international teams qualified for the finals. In addition there’s other divisions like high school and new to battlecode teams that have their own tournament.
Our Robot
Ok now that we know more about what battlecode is and how the contest is structured, let’s talk about our robot and some of the strategies we used. This section is going to be a little bit blurry because I’m writing this ~2 months after the contest and I don’t remember everything we did.
Our Strategies
We had a few different strategies and variations of our bot across the tournament that we tried out especially as the game got tweaked for balance and we learned more about the game.
- Setup Phase
– For the first 200 out of the 250 rounds of setup we just had all of our ducks move around randomly to try to explore as much of it as we could
– After that we had our ducks move to the center of the map and build traps next to the wall dividing the two sides of the map - Base Defense
– We had designated ducks that would stay at all times guarding our flags and building traps around our base and especially right on the flag itself which we placed down bombs and stun traps right on the flag so that if the enemy tried to pick it up they would get stunned and we could attack them.
– We also decided to make a water moat checkboard grid pattern around our flags so that the enemy ducks would either have to spend crumbs trying to fill the water or go through on the diagonals which made sure that the enemy ducks couldnt completely swarm our base at once and it made them funnel through a few paths which made it easier for our ducks to defend.
– If a duck was guarding the flag and it saw an enemy duck nearby it would set a global variable in the shared array that would call other ducks to come help defend the flag. We also made sure that if these defense points were called that we would prefer ducks to spawn nearby to help defend the flag.
– But we had to be careful about this because if we called too many ducks to defend the flag then we wouldn’t have enough ducks to go out and capture the enemy flags. - Flag Passing
– We noticed that often our bots would get stuck surrounding the duck with the flag and preventing it from really moving anywhere so we implemented a flag passing strategy where it would pass the flag to another duck closer to where the flag needed to be captured
– We added this pretty late in the tournament and it worked pretty well. - Flag Return
– When a duck was returning the flag we had logic to assign nearby ducks to escort the duck returning the flag to make sure that it could get back to our base safely
– It also targeted to return to the base that was closest to where the flag carrier was
Things To Improve
- Pathfinding
– We took code from a previous year’s bot for doing BugNav pathfinding but in their year the bytecode limit was much smaller so we had a lot more bytecode that we could’ve been using to do smarter pathfinding but didn’t move to something better.
– Our pathfinding was so bad that in the sprints we would often get stuck trying to return the flag and often lost games because of it and the casters would make fun of us for it 😭 but it was funny so I didn’t mind - Better Distribution of Specializations
– One thing I didn’t mention was that when a duck does an action enough times it’ll specialize in that action and get more efficient at it. This specialization also limits it’s peak efficiency in other actions so we should’ve probably been more careful about this since for a lot of the tournament most of our ducks were specialized in healing and we didn’t really need that many ducks specialized in healing since it made us worse at fighting.
– I did make this a little bit more well balanced between healers and fighters at the end but I think this is something we should’ve done in a more calculated way to try to maximize the most out of our ducks - Stuck Flag Duck
– We just didn’t write any code to handle the case where a duck picks up the enemy flag and gets stuck somewhere like on an island surrounded by water and were just too lazy to fix it and it didn’t happen often enough for us to care about it too much. - Duck Standoff
– Sometimes our ducks would just sit there and do nothing and not move because both groups of ducks calculated that they were at a disadvantage and that they shouldn’t be aggressive which was annoying and we didn’t really have a good way to handle this. - Moving Flags
– We tried to move the flags around the map in setup which lets you change the location where your flags are but we didn’t invest enough time into this for it to be super effective.
– Other teams were able to move their flags around the map in more effective ways. Especially when they were scoring spots of the map based on things like the # of walls around the flag and the distance away from friendly spawns and enemy spawns.
– This is definitely a feature that we should’ve spent more time on since it was pretty effective for other teams
You can find our code here
Qualifying
I just thought this would be fun to include but to qualify for the finals we had to win this match and we were pretty excited when we did. Here’s a video of us winning the match
The Finals
This section is more dedicated to our experience in Boston for the finals, which was pretty amazing but if you want to skip this segment and go to reflection section below that’s cool too.
The Experience
The finals were held at MIT in Boston, and we all got flown out there for the event and it was my first time in memory being in Boston and the city was really pretty. We also ended up staying in the MIT dorms which was exciting because of the other people we met there through being in the dorms. Although, if I were to do it again I would’ve probably stayed in a hotel because the dorms are well ya know college dorms and could’ve been cleaner and I could’ve had a comfortable bed.
We also all were invited to a dinner before the finals where we got to meet the other teams and the organizers. It was interesting to see where everyone was from in addition we got some really nice food from them for the dinner.
The Results
The finals was hosted in their auditorium and was pretty fun to watch even if we went 0–2, but we did place 13th overall and it was already a huge accomplishment to make it this far.
Also they ran a estimathon where we had to guess a range on some question and I ended up winning a duck from correctly estimating the number of MIT dorm residents that offered to host teams for the finals. Here’s a video of me catching the duck:
Fun fact is that I put a notebook under my jacket when I before I went walking up there so the video looks kinda silly because of how I’m walking 😭
Reflection
I’m definitely not an expert on Battlecode, but I do have a few key takeaways from the experience and things I’d improve on if I were to do it again.
Invest Time in Writing Organized and Clean Code
Even though that it initially might seem like a fairly simple game even in a year where our game was relatively simple compared to other years it’s criticial to invest a lot of time in writing organized and clean code.
We didn’t do code reviews, and didn’t refactor our code as much as we should’ve and it ended up biting us throughout the rest of the tournament as we had to fix bugs and just try to understand what our code was doing. This is something that I would suggest everyone invests more time in especially at the beginning to set up a good foundation and structure for your project so that you can build on it and make changes more easily.
Part of the reason we didn’t do this is because we felt we were rushed to get features out for the sprints to see how we were doing against everyone else and wanted our games to be shown on the stream.
Sprints Aren’t Everything
This brings us into the next point that sprints aren’t everything and don’t matter too much. You definitely should focus on the main event itself and not getting too caught up in making your bot perfect for the sprints.
In addition, if you don’t end up making it that far in the sprints it’s not the end of the world. We never got our games shown on the sprint stream and certaintly didn’t win them. At least our year it felt like the bracket we were in (US college) was relatively small and if you don’t end up making it super far in the sprint it’s not over for your team and you can still qualify for the finals.
Scrimmage a Lot
As I mentioned earlier, it’s super difficult to tell if your new bot is better than the previous version since you can only locally test your bot against other variants of code that you have and in a lot of cases it’s not super helpful to test against your previous versions of your bot because if they’re too similiar they’ll often draw a lot or you’ll see that the change you made is better in some situations and worse in others.
This is why it’s important to scrimmage a lot of other teams to see if your changes are actually better than before against real opponents that you’ll likely face in ranked games and the tournaments.
It didn’t cross my mind until the end of the tournament when another team shared that they did this, but I think it’s a really good idea to make a script to automatically queue games against other teams and with some sort of evaluation to see if your changes are actually better than before. One script is linked here
Even if you don’t have a script to automatically do this, it’s still important to manually queue games against other teams to see if your changes are actually better than before with the changes you made. We didn’t and we still queued 818 total unranked scrimmaged which is the 8th most of any team. And 7th most total scrimmages with 1,294 in total.
Watch Your Games
One of the downsides to an automated script to queue games is that you probably wouldn’t be watching your games as often. It’s super valuable to watch the games that you’re playing to see what situations your bot is doing well in and what situations it’s doing poorly in.
This gives you a lot of information about what you can potentially do to improve your bot and your strategies.
Watch the Other Teams
It’s also equally important to watch the other teams games (especially if they have auto scrimmages off) to see what strategies they’re using and how their bot is doing.
If you see a team that’s doing much better than you or you see some interesting strategies that they’re using, don’t be afraid to steal and augment their strategies to fit your bot potentially even better than how they’re using it.
Use Community Resources
The Battlecode community is super helpful and there’s a lot of resources out there to help you get started and improve your bot. There’s a lot of teams that have shared their code and strategies from previous years and it’s a great way to get started and see what other teams are doing.
In addition there’s a lot of code from previous years that also works every year and is a great way to get started and see what other teams are doing. For example: shared array communication, pathfinding, etc. All of these are things that you can find in previous years code and use in your bot.
Advice to New Participants
It can be overwhelming to get started with Battlecode because there’s a lot of things to learn about: the game specifications, the contest structure, strategies, limitations on the game, how to communicate between your ducks, running games locally, etc.
Not to mention that it can be difficult to start writing code because you have to get used to what methods exist and what actions you can perform and what information you can and cannot access and can be difficult to work with. I definitely highly suggest that you use an IDE with lots of autocomplete so you can preview all available methods. It feels a lot like working with a library like Pandas where there’s a lot of methods and you have to get used to what’s available and sort of feels like another language entirely.
It definitely frustrated me at the start because I just wanted to add some basic features but as a combination of: our project not being super organized, me not being familiar with the game, or how to write code for it, it was quite annoying to get started. But it’s worth it to push through and get started because it’s a lot of fun and you’ll learn a lot.