The Lessons I Learned From MIT’s Battlecode 2017 Competition (Post-Mortem)

Stuart Johnson
11 min readFeb 4, 2017

--

I am not a good programmer. Unfortunately, my studies of Java began a mere week before BattleCode 2017 began, and as a result I would have been perfectly merry disappearing in round two, never to be seen again.

Against all odds, “test bot please ignore” defeated round after round of bots during the qualifying tournament to reach the top 32 teams out of over 450 participants in the final competition. Us. We. I. We were one win away from a paid flight to MIT to watch the final competition unfold in person, despite a pretty major failure in round five against “Oak’s Disciples” (where our bot stopped functioning comepletely for some inexplicable reason) that knocked us into the loser’s bracket. I’m beyond proud of myself, especially considering most of our primary competition were several years our senior.

We made a lot of mistakes that I have no excuse for, all of which I plan (or at least hope) to avoid during next year’s competition. With some fortune, you can learn from my errors and become a better Battlecoder. A day or three was lost several times during development, which is not a price you can afford to pay when you have 22 days to code an AI. First however, is some necessary context about this year’s brief and game specs.

BattleCode: Farming Simulator, Now With Guns

I’m going to explain in as little detail as possible. If you’re interested, the full brief can be found on the BattleCode website at http://www.battlecode.org

The game’s theme this year was aptly dubbed ‘bullet hell’ by the organisers. Unlike previous years where fighting has mostly been done with targeted lasers, this time we were provided with projectiles instead, allowing for creative dodging strategies. The game’s currency was unsurprising: bullets. Confusingly, units were built with bullets, but bullets were also fired by soldiers, scouts and tanks, meaning you couldn’t just send off your steel legion firing in a random direction as many of us dreamed of early on.

Another important facet was that bullets could also damage their own team, meaning it was important to make sure there was nothing in the way of your firing. Scouts in particular could move faster than their bullets, meaning it was important you didn’t fire and then shoot yourself next turn.

There were six units in this edition of BattleCode which were all well balanced (at least after the first week) and useful in their own way. These were:

Archons — The headquarters of your operation. Can move around slowly and build Gardeners. High HP, but once it’s gone, it’s gone, and you can no longer build your economy.
Gardeners — Despite sounding like a cruel joke in a battle scene, the addition of these worker units was one of the core twists this year. Gardeners could plant ‘bullet trees’ that would provide resources based on their health that round. Gardeners could ‘water’ these to increase their health. Thus, having a stable network of Gardeners and trees was imperative to success.
Scouts —Fast moving, low damage units who ignore terrain.
Soldiers — You guessed it. Standard fighting unit with a gun. Also has the option to fire a three-bullet cone (a ‘triad’) or a five-bullet cone (a ‘pentad’). To this day, I am lost as to what the Chinese mafia has to do with shooting three bullets instead of one.
Tank — The same as soldiers, except larger, slower and more expensive. To counteract their weaknesses, their bullets did increased damage and travelled faster. Perfect for dealing with pesky scouts who could easily dodge most other units. A mildly useless ability they posessed was damaging trees by attempting to move onto them. Any team with common sense would just build Lumberjacks instead to deal with neutral trees.
Lumberjacks — Around the map were a varying number of neutral trees. These had a fair amount of health and blocked movement for all units other than scouts. These could be shot down (terribly inefficient and expensive), run over with tanks (terribly inefficient and expensive), or be cut down by lumberjacks. Some maps were almost entirely filled with these trees, making lumberjacks a staple of most compositions, especially if the Archon could sense a lot of neutral trees around the spawn. Another important feature was that lumberjacks had a melee attack where they would damage every unit in a circle around it, regardless of team. This fed into our strategy later on, but I’ll come to that in a bit.

There are a lot more nuances I won’t mention for simplicity’s sake.

The Formation of Test Bot Please Ignore

In mid December, the developers of Battlecode posted an IAmA on Reddit which quickly hit the front page. As a direct result of this, the competition showing this year was roughly quadruple what it had been in previous years. After some time spent reading through the thread, I posted on the forums asking for a team, and within a few hours I had picked up a few more Redditors to complete the merry band.

After some waiting, the specs were announced, and we were off.

Mistake 1: Trying to Write a ‘Good’ Bot Before a Working one

In the first few days, the winning teams’ strategy was basically ‘Build gardeners, have them run off and plant some trees, repeat’. We were in the unfortunate mindset that once our super-good and super well-structured bot was ready, we’d easily stomp the competition. We started developing high level mechanics like multiple bot behaviours before we’d even managed to make our gardeners function.

It sounds ridiculous now that I put finger to keyboard, but it’s so easy to start running before you can walk. I beseech all teams reading this in preparation for BattleCode 2018 to actually make a working bot that wins matches before you do anything else. Contrary to what other post mortems tell you, sure as hell go and try to conquer the leaderboards in those first few days. What it means is that you have a functional bot significantly better than anyone else’s functional bot, which is not ever a bad place to be.

And so it was, as the sprint tournament approached, that we didn’t have a bot at all. Too much time was spent executing the former half of our name, which meant that it looked as if all our opponents were going to successfully complete the second half. I panicked, and made the stupid decision of giving up. A day or two before the tournament however, my teammate emerged with his brain child…

Mistake 1.5: Trying to Copy Other Strategies

This was honestly a massive waste of time on my part. A few days after scrimmages launched, a team called Waterloo Omega Ruby (WOR) had a slightly different strategy of planting trees.

How we, and most other teams planted trees.

“Flowers”
The most popular way of planting trees. Gardeners found a location based on arbitrary conditions, and planted five trees in all directions but one around themselves. Mainly used because it was dead easy to implement as well as being decently effective.

The WOR approach allowed for more easy unit movement

“Forest”
Waterloo used a spread out forest of trees with a network of gardeners to maintain them. This was protected by a ring of soldiers around the perimeter. This strategy annihilated the scout heavy meta early on as attacked gardeners could simply run away to where a soldier was

I wasted a whole day trying to replicate this to underwhelming results. Meanwhile, the sprint tournament drew nearer and nearer. I should have been working on my soldier code. I should have been working to counter aggressive scouts. But I didn’t.

The Rush Bot is Born

I honestly cannot take any credit for this. I was feeling more than a bit lost, with not a lot of ideas and far too many bugs to work on. There was so much structure left to build that I couldn’t really start on the actual bot. A few days before the tournament, my teammate pushes a new branch which focuses on using scouts that hide in trees to kill the enemy gardeners. While we were one of the first teams to adopt this strategy, it became overwhelmingly the dominant meta in the sprint tournament. The problem? We started so much later that we carried this strategy out a lot worse than the competition. We quickly lost our first game and were knocked out of the running. By this point, two of our team had dropped out leaving just me and Milo.

Mistake 2: Thinking that Scouts Wouldn’t be Nerfed After Their Ridiculously Strong Showing

While other teams developed their soldiers to defend from scout attacks, Milo slavishly worked on his scout ai. By midway through the seeding tournament deadline, I have no doubt that we had one of the best scout ai around. We invariably won duels with other scouts in addition to occasionally trading with a gardener.

But we were too late. The scout meta was long gone.

By this point, soldier code was effective defending gardeners, and with scouts’ reduced damage, they could no longer take out gardeners before being nuked from orbit by patrolling soldiers. Again, Milo came to the rescue with his mass lumber bot. The strategy was dead simple. We had played with build orders dependent on how many trees surrounded the spawn, but it didn’t provide satisfactory results. built a single scout to take bullets from neutral trees (something not a lot of teams did, meaning our economy got a huge boost at the start) and then built a bunch of other units in a set order, which were mainly lumberjacks. The seeding tournament went alright and we were eliminated in round four after two wins and two losses.

Developing the Lumber Rush

We knew we could never out-code or out-algorithm students from prominent colleges, or even out-work teams of four high school students who would see each other every day to work on the bot. The plan was that if we used a strategy most teams had never seen before, their bot would react in a sub-optimal way. The orthodox meta of gardener nests protected by an expanding ring of soldiers was thrown to the wayside. In retrospect, lumberjacks were a bit underpowered, but for the most part that didn’t matter. One thing we noticed was that we died a lot to fast soldier rushes. We never truly managed to resolve this issue, nor the slew of others that plagued us (like our archon getting stuck in front of all our units) although to try and counteract this we introduced a sort of ‘gas cloud’ of lumberjacks, where they’d try to remain 2 units away from every other lumberjack. As we built more units, the cloud expanded until it encompassed the enemy base.

A late version of the lumberjack cloud in action.

Mistake 3: Not Including Rush Code

We were ribbed by high ranking teams simply because their soldiers knew how to run backwards. That’s it. Running Backwards. Because lumberjacks moved at the same speed as soldiers, they could never close the gap on good soldier micro. Fortunately, this problem never came to haunt us, although if we’d made top 16 I have no doubt we’d be kicking ourselves. The match above was taken from our round 5 victory in the qualifying tournament, and the casters were just begging our bot to attack before our opponent could amass soldiers. We had over 110 lumberjacks by the time our cloud found their nest. If we were up against better soldier AI (the fools didn’t make their soldiers run backwards) then we would have lost the best of three for sure. Certainly a sobering experience.

Mistake 3: Not Creating Maps Specifically to Break our Bots

We might have even made top 16 had we tried a little bit harder to break our bots. What we didn’t know at that time was that the devs are known for making maps to test bots in the final tournament. And then disaster struck in round five. We were unfortunately matched against the team predicted to win the competition, Oak’s Disciples. But to aggravate matters, our bot decided to not work! The maps for that round were designed so that the archon couldn’t move. But due to the way our unit building code worked, we never tried to build in the free directions. So I sat there, frozen in shock, as my opponent’s blue legions marched towards my location.

Our Greatest Victory

Round 5, loser’s bracket B. At this point, it’s all or nothing. We are fortunately not matched against one of the highest seeded teams, so there was no tactical stomp inbound. We lost the first map because of the problem fighting good soldier code, won the second because it was open and the balloon just expanded and expanded until we destroyed them. And then the third map.

Victory. A blowout victory. Because the map was filled with trees, our gardener army just built and built into this massive blob you see in the video. It was a wonderful feeling sitting with my family as Test Bot forces engulfed <insert farming pun here>.

The Future

Battlecode has been the most fun programming I’ve had in a long time. It was in fact the first time I’ve ever applied programming to an actual problem that needed a real solution, and I absolutely recommend it to anyone who can code. Prizes are only available to students, but the competition is open to all.

I plan to take part in Battlecode 2018, and 2019, and hopefully every year up to 2023 which would be my last year as an undergrad.

Battlecode 2018 — Earth, Mars, and unfortunately Scope Creep as well.

The Battlecode organisers tried some new things this year. The premise was fantastic — Earth is dying. Build rockets to escape to mars, where the last 250 round of gameplay takes place. Unfortunately though, technical hitches and delays caused a lot of frustration.

I did Battlecode 2018 for only a short week before dropping out due to general angst — Almost nobody could get it running for the first four days. To the devs credit though, many nights of insufficient sleep were had, and much 1–1 technical support was offered to get the ball rolling. Despite this however, four days had been lost, and the sprint tournament was just around the corner. The fact that there was a big difference in when people could start developing was frustrating for sure since in this competition every hour counts. This was coupled with the late-announced news that only four international teams would be permitted in the final tournament, and international teams were disqualified from the Highschool bracket. I felt… disenfranchised to say the least. This was for good reason —The MIT schedule doesn’t allow the tournament to extend past January very far, and last year many international teams couldn’t make it to the finals in person due to lack of notice (three days to bail on commitments and fly to another continent is a tricky one). Some teams could be there, some couldn’t. To avoid this, the international bracket allowing 4 teams through was held several days prior to allow for more notice. It still left a bit of a bad taste in my mouth though, since usually numbers of US teams and international teams in the finals were even.

It’s a story better left untold, but in the end I was banned without warning from the Discord server for reasons relating to the sprint tournament that may or may not have been justified. There are regrets from both parties there.

I’ll be back in 2019 though. Don’t think I no longer recommend Battlecode. It couldn’t be further from the truth. A good portion of the organising team is undergrads! Insane! I couldn’t ever see myself being able to reliably turn out a competition of such quality.

I’m Stuartj in Battlecode, usually competing under a variation of the name ‘Test Bot Please Ignore’ so keep an eye out for me in 2019. Good hunting, my fellows.

--

--

Stuart Johnson

Seventeen year old British student aspiring to AI academia or full stack development. I write about my adventures through education and technology.