Replacing State Variables with Function Assignment

This post is part of a collection on Code and Computers.

When writing my game for the last Ludum Dare, the structure of game flow evolved considerably as development went on and vague ideas like "have a game over screen" or "show the computer thinking" got implemented. The structure I used to handle game states is probably one you've seen before:

  if state == "turn.player" then
    playerturn()
  elseif state == "turn.cpu" then
    cputurn()
  elseif state == "cpu.thinking" then
    -- todo animate thinking
    if frame - thinkstart > 90 then
      state = "turn.cpu" end
  elseif state == "message" then
  ...

This isn't very elegant, but all possible states are in one place so they're easy to see, and it's easy to make additions. It's not the worst thing I could have done.

Looking over the code afterwards though, while a lot of things would be different if I rewrote it from scratch, this structure reminded me of a section in Thinking Forth I'd read just recently, specifically part of Chapter 8: Minimizing Control Structures about device-appropriate text output:

If the only purpose to setting a flag is so that later some code can decide between one function and another, you're better off saving the address of the function itself. (PDF pg 274)

Or, more compactly:

Don't set a flag, set the function.

To clarify how this applies to my situation above, I could turn my large if-else statement into this:

def _update
  do_update()
end

That's the punchline, but how do I actually do this? The answer is pretty straightforward - I just need to take each of the parts inbetween the then and elseif above and make them into functions, and instead of changing the state variable, just assign do_update. So, for example, whever I had this...

state = "turn.player"

I should instead have something like this:

do_update = playerturn

Where playerturn is the update function that would have previously been called when state == "turn.player". In languages like Lua or Javascript where functions are first-class values this is trivial, and even in C you can use function pointers to achieve the same effect.

I took a little time to rewrite my LD submission using this style, and overall it increased my line count while decreasing my character count - the line increase is probably due to function declarations.

There were only a few places where the transition wasn't straightforward: outside the of the main update function, the functions that drew the cursor and those that check for wins and losses used the state variable to determine the current player. If this were Javascript I'd just make those functions properties of the main update function; in Lua functions aren't objects, and though you can make callable objects, to be quick I stuck with what I knew and assigned those functions separately. Another easy way to do it for Lua would be to have a kind of "logic" or "driver" object that you switch instead of just a plain function.

You can see the results here.

For this code the benefit of doing this wasn't particularly dramatic (though every byte counts in pico8), but for larger projects it's pretty easy to imagine the appeal of having valid program states defined as a number of driver objects that fit a single interface rather than as a soup of statements inside a big switch. I'm sure at some point I'll run into that kind of big switch lurking in legacy code before too long, and now I'll know what to do when I find it. Ψ