Courage is Better With Cowardice


My ants had already learned courage, and now they know the importance of cowardice. It’s been about two weeks since I uploaded a new bot, and this new version is much improved. The last real version of my bot was able to play 63 games, and ended with a skill rating of about 58.

Today’s intelligence level: real swarm.

It took a couple of deploys to get the newest version of my bot up, but after only a few games it’s now rated at almost 69. At the moment I’m typing this, my bot is once again the best Clojure bot in the content, and is on the edge of the top 500 (although I expect to fall out shortly).

After doing some simple work on my bot (such as using the random seed the content provides to let you run game replays correctly), I found and fixed the bugs I had mentioned last time. The biggest problem the last version of my bot was having (besides stupid behavior due to bugs) was defense. Since the ants didn’t care too much about enemy ants (and sometimes actively avoid them) under the right circumstances it was possible to walk in and take one of my hills without too much effort. The bug fixes made this worse as the ants spread out better so there were fewer to act as defense.

This was fixed by implementing a strategy that I thought of a while ago, but was remedied of when I saw a competitor using it. By strategically placing ants around my hills I can raise the bar for anyone trying to attack. In the picture at the top of this post you can see my 2nd level arrangement (out of three). This simple defense works great against single file streams of ants. Combined with new code that causes all nearby ants to run home if the hill gets attacked my hills have been able to survive much longer than they ever would have before. In some games, an enemy loses all their extra resources unsuccessfully trying to take my hill.

Things aren’t perfect. A side effect of the way things work is getting an ant near one of my hills can, under circumstances that aren’t nearly rare enough, prevent my bot from doing any further work. My colony may survive, but it’s not out gathering food or razing other hills. This in combination with a large number of opponent ants means that my bot can be shut down and eliminated by a correct show of force.

The last thing I had to do was fix a problem I didn’t expect to have: my bot times out. In easy games (especially the initial “does the bot crash” game bots run through when first uploaded) my bot can generate so many ants that it actually goes over it’s turn time. I added a little code so skip processing ants when my bot is about to run out of time, and I have seen it in action in production. Due to some quirk of the Python server implementation the order of ants to the bots being tested in is a discernible pattern. So when ants stop moving (because I ran out of time and didn’t get to issue them any orders) it makes a very obvious pattern on the field.

While the code seems to work very well, it does still fail on the ultra-small test map for some reason. I’m going to have to keep an eye on my bot to see if it happens in any other games. I may have to make it more aggressive.

Less Bugs In My Clojure Means More Ants

My bot is getting better. After taking a little time off, I spent a few hours last night making updates. While I haven’t deployed them, my current bot has continued to test it’s potential. It’s been playing a lot of random_walk maps (which it handles better than the maze maps), and my rank is now in the top 1200.

Current intelligence level: stupid swarm.

While spending a bunch of time yesterday, I uncovered a couple of bugs in my code that explained some of the odd behavior I’ve seen (such as ants getting stuck together in small features). It turns out that I was using contains on a list, which does nothing. This is actually rather odd. contains checks to see if a key is in a collection, but doesn’t raise an exception in this circumstance. keys shows the behavior that I was expecting:

user=> (contains? (list 1 2 3 4) 3)
user=> (keys (list 1 2 3 4))
ClassCastException java.lang.Long cannot be cast to [...]

So because of this, some of the tests I had in my code were useless, essentially always returning false. On top of that, I found another bug. I was checking to see if collections were empty like this:

(if (empty my-collection) [...]

That’s a mistake too. empty is a new function in Clojure 1.3 which returns an empty version of the collection passed to it (so it will give you an empty set if you pass it a set). This also caused subtle bugs. The correct function was empty?, but I wasn’t looking that closely at autocomplete.

With that fixed, my bot looks quite a bit better. The ants don’t get stuck and they spread out better on all maps, even though there isn’t any code specifically instructing them to do that. When testing, I noticed that this means it’s much easier to take my hills because there are fewer ants milling about now. I added some code to have everyone rush home when an enemy approaches, but I haven’t given it any real test yet. It looked like it might have kicked in during  test game, but I was tired of working by then and decided to do the real testing later.

So as it is, I don’t want to post my updated version until I can test better. If I post what I have at this moment I’m pretty sure my rating will drop more than a few points. But I now know that my bot can handle over 600 ants without timing out. Before it almost never got above ~250 because the ants ended up blocking the hills.

B17 Flying Fortress


Last weekend I finished making a copy of the B17 Flying Fortress that GE posted on Thingiverse earlier this year. To get it to print easier I split it up into individual parts instead of one printing plate and scaled it up 20% to max out the wing length on my Thing-o-Matic’s build platform. After some paint I think it looks really good.

Painting it turned out to be a big hassle. I tried using an airbrush, but I didn’t want to spend too much to start out. As a result, I spent less than $30 on the whole setup. Everything worked decently except for the little propellant can. I had seen warnings online about how poor those things were, but I figured it was an exaggeration.

It was not.

Now With Line of Sight

Over the weekend I updated my bot to use a line of sight to decide on what to do for each ant. This fixes some of the worst behaviors my ants had, but it’s not perfect. The ants no longer crowd up trying to get to food or a hill they can’t reach, but they’re still not terribly bright. I had to turn off the food reservation system because it wasn’t intelligent enough and the side effects were worse than the benefits.

So how smart is my bot now? I’m not sure. It should be better, but the AI Challenge keeps having server problems. My bot had to wait most of the weekend for games to start being played again, and they seemed to have another problem today. Because of this games aren’t happening very fast at all so my bot hasn’t had the chance to move up to it’s true rank. The AI Challenge forms have posts about alternate servers you can test you bot on, I may have to go to that.

I’m a little tired of working on the bot at this point, even though I can think of quite a few things I should do. After all the time I’ve put in lately, it would be nice to see my bot reach it’s potential (or at least where it was before the last change). The slow game rate was very demotivating.

Getting Better At Clojure

My bot topped out around 1000th place. After a while it started to lose, which wasn’t that surprising. For various reasons, my bot is very bad on the maze maps and those seem to come up the majority of the time.

I spent the week trying to make my bot more intelligent. I’ve wanted to use gradients to give my bots marching orders, so I worked on code to do it. I wrote it over two days or so and rewrote it at least twice before I tested it as I kept thinking through the algorithm. I was really pleased when, except for one a mistyped variable name, it worked the first time.

I started testing how fast it was (since bots in the AI Challenge are limited to 3 seconds per turn) and it was great on tiny test cases. As I went to test it on random data that represented something the size of the large maps, it started crashing. I spent a bunch of time chasing down a StackOverflowError bug. I was pretty sure it was a bug in my code for quite a while, but as it turned out it’s just a known issue in Clojure, my code was technically correct. If you embed LazySeq in LazySeq in LazySeq over and over when Clojure goes to get a value it can go so deep that it runs out of stack space. The solution is to force evaluation to remove the “Lazy-ness”.

Unfortunately, things are still way too slow. Doing a full re-build every turn is never going to work, so I need to make it so I do partial updates every turn. While doing a little research I found that Clojure has a hidden queue type, which is drastically faster at removal (about 60x in a simple test case) than my List based solution.

In the mean time I have made my bot smarter. I’m hoping my bot is now up to tired toddler, but we’ll see as it starts to run games. I added a food reservation system to prevent tons of ants from getting piled up trying to get to a single piece. I also added some code to help with exploration, but I had to disable it as it caused a weird side effect I didn’t feel like debugging tonight. It actually caused more jams.

Speaking of jams, while watching my last replay I noticed an odd case. The ants are programed not to go backwards if possible. When a group of ants gets boxed in to a concave area in a map, if the outside ants push “in”, they won’t want to go backward and end up locking all the ants in. I did shuffle some code around, so this may no longer be an issue. I’ll just have to keep an eye on it.

Ants Gain Courage, Film at 11

I’ve uploaded a new version of my bot to the AI Challenge site. My bot was, I believe, the 10th best Clojure bot before I updated my code and wiped out my rating. The new code probably won’t play it’s first game until early tomorrow morning. I put in a fix for the possible issue of my ants failing to defend their hills, giving my ants courage when they could see one of my hills.

The problem with ants getting trapped that I mentioned before actually bit me. In my bot’s 5th game, it’s first move was into such a corner. As a result, it did precisely nothing the entire match, until an enemy ant kindly came along and wiped me out.

At least that’s fixed now. New intelligence rating: very tired toddler.