Achilles

This past weekend I participated in the CivicHacks "Game Jam for Good". The goal was to raise awareness of the global water crisis and ultimately promote PackH2O, a Columbus-based startup that designs water backpacks for developing water-stressed regions.

The jam lasted 48 hours. My entry is called "Achilles".

Achilles is a multiplayer text-based simulation. You the player must manage a village in a third-world country experiencing a water crisis. You can play it here (bit.ly/waterjamachilles) assuming I haven't stopped paying for the cloud server.

It's incredibly depressing. Really, only bad things can happen. I had plans to add pregnancy and childbirth, but ran out of time. Here's a video of it in action:

The core idea was this: to convince people of the effectiveness of the PackH2O backpack, a promotional game should put players in the shoes of the people who will use it. And I think I accomplished that. In the game, the backpack allows people to carry twice as much water. The player experiences first-hand through gameplay how useful the backpack is.

Despite the game's inherent awfulness, it won an "honorable mention", which actually turned out to be good for a $500 gift card. :) You can check out the other winning games on the CivicHacks website.

Technology

On the backend, I wrote Achilles in Python using Flask as a web server framework (highly recommended).

I used gevent for greenlets, which made it very easy to write time-based procedures for each character. For example, here's how a man builds a hut:

if village['build_material'] > 0:
    village['build_material'] -= 1
    notify(world, village['id'])
    state['state'] = 'building'
    notify(world, man['id'])
    gevent.sleep(world_seconds(world, 60 * 60 * 17))
    village['huts'] += 1
    notify(world, village['id'])
    man['state'] = None
    notify(world, man['id'])
    send(village['id'], { 'event': '{0} finished building a hut.'.format(man['name']) })
else:
    send(village['id'], { 'event': 'Not enough build material for a hut.' })

The "notify" and "send" functions send JSON objects to the relevant clients over WebSockets.

On the frontend, I only used jQuery (no plugins) and Mustache.js for templating.

If you're interested, check out the code here on Github.

Compression-based programming

I used this game jam as an opportunity to try out compression-based programming as advocated by the excellent Casey Muratori. The idea is, instead of spending time upfront designing a complex cathedral-like architecture, you should write straightforward, ugly, even repetitive code (copying and pasting). When it's done, you go back and "compress" the code into something nicer via refactoring.

Of course, some things are straightforward enough that you can compress them as you go. For example I always knew there would be a "send" function.

Casey says one of the big problems with "normal" programming is that you assume you know everything at the beginning of a project, when in reality, you often don't. Compression-based programming has you architecting things only after you've seen the whole picture.

After a weekend of experimentation, I think this pattern of coding results in plain, boring, easy to understand code, which is definitely a good thing. Normally I come up with some super fancy way to write everything very elegantly, which creates more work than it's worth in the end.

Another paradigm Casey rails against is object-oriented programming, so I also tried writing everything procedurally. The result was again boring but simple and easy.

The biggest win was separating state from behavior. On both the client and server, all the state lived in a single object, parts of which were operated on by various procedures.

Normally, I often link state and behavior so closely that they're impossible to separate. Every time I write a closure (probably my favorite bad habit), I squirrel away an opaque bit of state inextricably tied to an anonymous bit of behavior.

Time to wrap this up: you should try coding in a boring, straightforward, state-separated-from-behavior, procedural style. The result is a breath of fresh air in a world of increasingly clever object models and cathedral architectures.