Friday, March 25, 2011

Cursor-10 Clojure bot

Usually when I say I love using programs to solve problems for me, I'm referring to some kind of machine learning. Today, I mean I'm using the raw power of automated mouse control beat a flash game that was pissing me off.

Cursor-10 is a strange and unpolished Japanese game. Try it out here.

Since its been my latest toy, I decided to write the bot in Clojure. I could have chosen Python, but manipulating the mouse is much easier in Clojure due to Java's Robot class. To be honest, the entire thing could have been written in something like AutoIt, but I wanted to take advantage of the abstractions available with Clojure's Lisp syntax to make everything as clean as possible.

Like I said, my choice of Clojure meant that I could take advantage of Java's Robot class- awesome. However, mouse-click actions are a side effect in Clojure land, meaning that its lazy evaluation made my Robot calls never happen. I needed to sprinkle doseq and dorun calls all over the place to force the side effects to actually be resolved. Not a huge deal, but it was the source of most of my debugging headaches.

So now I know how I'm going to play this game- clicking using Clojure/Java's Robot class. Next I need to know where to click. For some rapid prototyping, I started by manually entering coordinates for interesting game elements: crystals, ladders and boxes. This quickly proved an inadaquite solution... there must be a better way!

The better way was to use ImageMagick to programmatically find the coordinates of elements. Check out this blog post to see the details of how I did that.

It would have been awesome to use ImageMagick in real time to make my program more dynamic, but the computation took WAY too long for that to be possible. So I created lists in Clojure of everything I wanted to click on on each floor. These lists are currently contained inside the main module of the project, but it may have been cleaner to put them in their own text file and load that file on program startup.

After all that, I had a working bot. Check it out:

I win! The video starts at the final cursor (the only one that grabs crystals and gets points), but start at the beginning to see them all in action.

Note that I did give the bot some manual interaction; I started each cursor at the appropriate time. I could figure out the time between each level and make the bot fully autonomous, but that sounds like a lot of headache that I could devote to something more deserving.

The project source is available on github. There's a helpful README to get you started.

No comments:

Post a Comment