The hip trend these days in game dynamics is “compulsion loops,” where in one of the game activities lets us win gold or coins or some kind of virtual currency, which lets us buy stuff, which helps us play the game better, which earns more gold, and so on. (Stephanie Morgan gave a great Creative Mornings Talk on this.)

As we win more, our skills improve and we get more attached to the game. These days, if we want to short-cut the process and level-up more quickly, we simply spend real money to buy virtual currency via in-app purchase.

The Stir Fry iPhone game includes a great example of a compelling compulsion loop, along with an entertaining premise and fun interactions.

The core idea is that you can’t let your veggies burn up in their frying pans. You can flip them and hit other similar veggies to score points, and if you are lucky, you could get a fortune cookie, which earns you coins at the end of the game. You can buy potholders, fire extinguishers and other tools to improve your ability to keep your veggies from burning up. The addition of other elements to the game play also keeps you from getting bored once you get good.

There are two aspects to this compulsion loop that deepen engagement and increase effectiveness. First, the creative variety and story telling aspect of the props deepens engagement in the game. Secondly, including an aspect of chance and randomness in the reward system makes it more addictive.

It may seem counter-intuitive, but the element of chance is a key difference between something being work and something being play. (Of course, in work we don’t always get more when we work harder, but that’s the prevailing mythology. In a game we know the rules and we buy into the randomness because it is fun.)

In recent New York Times article, Paul Howard-Jones shed some light on this phenomenon:

computer games stimulate the brain’s reward system to produce dopamine, a chemical “which helps orient our attention and enhances the making of connections between neurons, which is the physical basis for learning.”

Mr. Howard-Jones said that research has shown that the introduction of a chance or game element into any reward system increases dopamine production. “For generations, we educators have done everything we can to maintain a consistent relationship between reward and achievement, but the neuroscience is telling us something different,” he said in an interview.

According to Mr. Howard-Jones, students learn more, and are happier to continue learning, when they are offered the chance of a reward rather than a guaranteed reward.

While it seems illogical, I think we’ve all experienced playful activities from games to sports where the element of chance adds to that edgy, uncertain anticipation that makes the reward that much more sweet. If only we could apply the same philosophy to all aspects of our lives, since there is an element of chance in everything we do. Of course, I think one of the reasons games are fun is simply because they are a diversion meant only for entertainment and the game play is a gift to ourselves.

Check out Stir Fry iPhone game for a neat new example of well-thought out game dynamics or just for a fun diversion.

I’m working my way through an epic Rails 3.1 upgrade and some of my cucumber features were failing because I was using a custom RSpec matcher and the method wasn’t found.

My custom matcher looks something like this:

module CustomMatchers

  class XmlSubsetMatcher

  def be_xml_subset_of(expected)

and when I ran my feature I was getting this failure:

undefined method `xml_subset_of?' for # (NoMethodError)

As it turns out, in my zeal to make sure everything was using the latest and great new stuff, I had forgotten to move over this critical configuration line in cucumbers env.rb:


Now, my cucumber feature is happily failing cuz my code doesn’t work. Whew. I couldn’t find this documented anywhere and I’m not even sure where this documentation would belong. I found a hint on the cucumber wiki rspec expectations page, but none of the code on that page is actually needed when using cucumber with Rails, so I decided not to touch it and just write this blog post.

Update: more links and ogg and webm details

I found that I needed to convert an m4a audio file (which is what QuickTime saves when I record audio) to a wav file, so I decided to use my favorite “can opener.” The versatile open source ffmpeg tool has always seemed to be able to convert anything to anything in audio-video formats.

I decided to pull the source from git:

$ git clone git://
$ cd ffmpeg/

Stable versions are tagged (which I could see with “git tag -l”). I don’t need to live on the edge right now, so I switched to the tag “n0.9.1” which I assume is for the latest stable build “harmony” 0.9.1 and made a local branch based on that.

$ git co n0.9.1
$ git checkout -b n0.9.1

Instructions for building ffmpeg are in the “INSTALL” file. I discovered I needed yasm, which I could install with brew. Here’s what I did:

$ brew install yasm
$ ./configure
$ make
CC libavdevice/alldevices.o
CC libavdevice/avdevice.o
CC libavdevice/lavfi.o
AR libavdevice/libavdevice.a
CC libavfilter/af_aconvert.o
libavfilter/af_aconvert.c:53: warning: function declaration isn’t a prototype
libavfilter/af_aconvert.c:105: warning: function declaration isn’t a prototype
CC libavfilter/af_aformat.o
CC libavfilter/af_anull.o
CC libavfilter/af_aresample.o
ffserver.c: In function ‘parse_ffconfig’:
ffserver.c:4236: warning: ‘avcodec_get_context_defaults2’ is deprecated (declared at ./libavcodec/avcodec.h:3948)
ffserver.c:4237: warning: ‘avcodec_get_context_defaults2’ is deprecated (declared at ./libavcodec/avcodec.h:3948)
LD ffserver_g
CP ffserver
STRIP ffserver

I saw a lot of warnings, but they didn’t seem to negatively affect what I was trying to do. I found a nice blog post from catswhocode to remind me of the usage, and was able to use this simple command:

$ ./ffmpeg -i frog.m4a frog.wav
ffmpeg version 0.9.1, Copyright (c) 2000-2012 the FFmpeg developers
built on Jan 7 2012 21:19:08 with llvm_gcc 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
libavutil 51. 32. 0 / 51. 32. 0
libavcodec 53. 42. 4 / 53. 42. 4
libavformat 53. 24. 2 / 53. 24. 2
libavdevice 53. 4. 0 / 53. 4. 0
libavfilter 2. 53. 0 / 2. 53. 0
libswscale 2. 1. 0 / 2. 1. 0
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'frog.m4a':
major_brand : M4A
minor_version : 0
compatible_brands: M4V M4A mp42isom
creation_time : 2012-01-08 05:09:05
Duration: 00:00:07.22, start: 0.000000, bitrate: 206 kb/s
Stream #0:0(und): Audio: aac (mp4a / 0x6134706D), 44100 Hz, stereo, s16, 201 kb/s
creation_time : 2012-01-08 05:09:05
handler_name :
Output #0, wav, to 'frog.wav':
major_brand : M4A
minor_version : 0
compatible_brands: M4V M4A mp42isom
creation_time : 2012-01-08 05:09:05
encoder : Lavf53.24.2
Stream #0:0(und): Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
creation_time : 2012-01-08 05:09:05
handler_name :
Stream mapping:
Stream #0:0 -> #0:0 (aac -> pcm_s16le)
Press [q] to stop, [?] for help
size= 1244kB time=00:00:07.22 bitrate=1411.3kbits/s
video:0kB audio:1244kB global headers:0kB muxing overhead 0.003611%

$ ls
frog.m4a frog.wav