Reactions to "Purely Functional Retrogames"

I just read this blog series on "purely functional retrogames" from six years ago, on the basis of a recommendation from my Twitter friend/occasional conference-co-attendee Scott Vokes.

Things I thought were interesting points/good takeaways:

  • It's better to nest state-keeping records deeply, rather than making wide/flat ones; never have more than a few fields to refer to, and you can pass around chunks at a time to different subroutines.
  • Being forced to think out data-dependencies can be a good thing:

  • [In a purely functional style], functions can't access any data that isn't passed in. That means you need to think about what data is needed for a particular function, and "thread" that data through your program so a function can access it. It sounds horrible when written down, but it's easy in practice. 
    In fact, just working out the data dependencies in a simple game is an eye-opening exercise. It usually turns out that there are far fewer dependencies than you might imagine.
    Obviously, I like this point, since it's largely what my research is about! Programming a game in linear logic honestly looks more like imperative programming than functional (since you manipulate state directly and locally), but with proof-theoretic tools, we can easily extract and visualize those key data dependencies.
  • The outputs of the "process world state" step are effectively a changelog, or instructions for which changes to make, not a changed world itself! He didn't elaborate much on this point, so it's less clear to me why this approach simplifies threading of the world data, but maybe I'll give it a try next time I write a game functionally.
  • From the followup: bugs/difficulties in functional code have a lot in common with bugs in imperative code. Yes, I can definitely corroborate that statement with personal experience, though I'd argue they're a lot easier to debug in a functional setting because you can limit your scope of analysis to the literal scope of the error (rather than worrying about invisible interactions with global state).
Some nitpicks:

  • From Part 1: "I know that ML has references and that processes in Erlang can be used to mimic objects, but if you go down that road you might as well be using C." Whoa now, what? And lose inductive datatypes and pattern matching? No thanks. Honestly, I'd be pretty interested in a detailed comparison between writing a game in purely functional ML vs "ref cells allowed" ML.
  • From the followup: "not being able to reuse names" - OK, so Erlang (as of 2008) doesn't support shadowing I guess? That's not inherent to FP; seems like a minor quibble. Same goes for the dictionary type lament, I think.
  • In Part 4 he said the followup would address "what about FRP?" and never did. I'm really curious about this, as someone who finds "direct-style" functional programming of games to be a lot more comprehensible than FRP.
Part of what's interesting to me here is how much both functional programming and game development have changed in the last six years. He said something about there being "more Atari hackers than Haskell devs" at the time of writing; I'd doubt that's true anymore. And, while there have been advances on two "ends of a spectrum" in tools for hobbyist game development -- I'm mainly talking about Twine and Unity; interactive fiction and 3D world sims -- there really hasn't been that much attention paid (AFAIK*) to enabling the game design tropes so common in "retrogames" -- top-down worlds, discrete movement, non-"realistic" physics. Maybe we see those things as outdated now, and maybe that's fair, but I'd argue it's strange that we're not yet seeing "first-person shooter" or "puzzle platformer" as equally outdated and overplayed.

I wish more people paid attention as this series does to the fact that "simple arcade games" are still pretty dang hard to program in a reasonable, scalable, intuitive way, and that nailing down good tools for that domain can still open a pretty wide space of novel, experimental design.

--

* with the notable exception of PuzzleScript.

Comments

  1. I think that when the "output of processing the world" is a change log, certain kinds of changes are easier to compose using only local reasoning; and it is easier to pass less data into each lower level state transition function (without resorting to arrows). It is sort of a reinvention of a state monad. Not all changes will compose well in this regime, but it saves the implementor from writing a function to merge worlds.

    That said, I think the global, ambient state of modal logics is a better fit for games generally, especially considering how board game rules are written--and the composition of functions will often look like a prioritized modal logic.

    One interesting thought that only crystallized for me recently is why/wherefore different game mechanics & systems are naturally described in different ways: it's awkward to use counters and 60 discrete choices a second to describe Mario's jump, and it's awkward to describe turn taking as the broadcast of events informing independent entities that they should stop accepting input for a while. Not to mention that both those mismatched modeling attempts will be error-prone in ways that have nothing to do with the actual mechanic in question! (I think the fact that Swink wrote Game Feel with envelope diagrams and data designers often say things like "power curves" has been staring me in the face for a while.)

    The specific insight was that the notion of "operational logics" (Mateas & Wardrip-Fruin had an excellent summary at DiGRA 2009) really succinctly captures why and where these mismatches happen, and it helps explain the success of e.g. Twine and Puzzlescript over, respectively, raw HTML (no specific support for the operational logic) or a mere Sokoban engine (Puzzlescript's spatial matching logic makes it more than just a "make a game in a genre" tool).

    2d graphical logics like you describe for arcade games are really interesting and ubiquitous, and even form the outer structure of Puzzlescript games, so exploring and explaining them can net a big payoff. How do you feel about (for example) VGDL as a formalism? Does it not expose the right bits of the logic, or does it bring in too much baggage from e.g. resource logics in an ad hoc way that impairs reasoning?

    I guess the question I have is: if Mario and Chess want to be written in different languages, are those differences just a matter of syntax, or of semantics and even worldview? Of course any Turing equivalent formalism is capable of expressing both games, but there's a reason that so many puzzle platformers are written in Game Maker, but not so many digital board games.

    Ack, I'm ranting--I'll leave it at "languages have opinions", which you've already said more cleanly (and for which operational logics give a nice lens); and "specificity and generality are opposed", which looks tautological but has important consequences--compare Game Maker and Unity: users of the former have certainly produced more design exploration and innovation in the space for which it's suitable. Is the Ur-game-language a language of perfectly general expression, or is it a coordination language for diverse specialized logics?

    And how might requirements differ for a language to design a game with versus a language to validate a game design?

    Sorry for the enormous comment! I've actually wanted to chat with you about this stuff for a while (I'm afraid this is more "at" than "with", sorry!), and I think there's a lot of important work to be done with logic and games/interactive systems--and I hope our respective labs (I'm at the Expressive Intelligence Studio at UCSC) can also work together some!

    ReplyDelete
    Replies
    1. This comment is full of juicy things I need to read about -- thanks! I've grabbed the DiGRA paper on operational logics and it looks super interesting.

      By the way, I don't have a "lab" here -- it's just me working on a thesis with PL-oriented advisors, trying to pick up all the games-relevant stuff from conferences, papers, and occasional meetings with other CMU faculty. (We games researchers are very disconnected here, though new faculty Jess Hammer is trying to change that.)

      I'd really like to have more contact, and possibly collaboration, with folks (including you) at UCSC -- I'm hoping in particular to put together a paper (maybe for FDG?) on the "multiagent mechanics" stuff I wrote about in the previous post, and I think it could really benefit from coauthorship with some of y'all who are immersed in, and well-versed in, the related work. Please contact me by email (found on my webpage) if you think such a thing could be fruitful. :)

      Here's a bit of opining on your specific points:
      "if Mario and Chess want to be written in different languages, are those differences just a matter of syntax, or of semantics and even worldview?"
      -- I think it's an interesting question whether they fundamentally *do* want to be written (or at least, like, specified executably) in different languages. Or maybe that's kind of the same as what you're saying; could they "elaborate" to the same language or would one of them (presumably Mario) just fail to have the essential things about it captured by anything broad enough to encompass both? I'm hoping my thesis can answer this question to some degree, but at the moment I don't know. I think the specific instance of "VGDL" (which I've looked into just a bit) is not quite good enough because it doesn't have a clear *execution* model corresponding to an abstraction of the actual game's execution -- that's one of the main things my thesis language sets out to address.

      "Is the Ur-game-language a language of perfectly general expression, or is it a coordination language for diverse specialized logics?"

      I don't know anything about the Ur-game-language (will look it up), but I really like the phrase "coordination language for diverse specialized logics." A lot of people are starting to see languages like Haskell (and even moreso dependently-typed langs like Agda and Idris) as platforms for "embedded domain specific languages"; maybe we need general-purpose languages that are good for embedding "game-specific logics."

      Thanks for the thought-provoking comment!

      Delete
    2. Ah! Sorry about my cultural assumption. I hope CMU's game researchers can gravitate together—I often get insights for my work when listening to how other people approach their own problems, and I'm sure that one could do that by talking about a variety of application domains (as being in a PL context might do) as well as by talking about a variety of techniques (as being in a primarily games context does).

      I think the multiagent mechanics stuff is a great fit for FDG and a topic of certain interest to many people at EIS, in large part because agent behavior is a major research topic of our fearless leader Michael Mateas (obligatory citation of his ABL language and Façade). ABL and its kin have been deployed in at least a couple different areas of the design space you identified. I also suspect that Comme il Faut (the social physics underlying Prom Week) is being used in more diverse ways, and I'll send your recent post along to the folks working on that.

      "...could they "elaborate" to the same language or would one of them (presumably Mario) just fail to have the essential things about it captured by anything broad enough to encompass both?"
      I think "essential" is a tricky word here. I mean, from the perspective of a tool-assisted speedrunner, the frame-by-frame discrete movements of Mario are vitally important and essential. But from the perspective of a game designer, I think the abstraction of continuous movement and time (draw a curve to describe the "feel" of the jump) is more natural and better captures the "essence".

      The critique of VGDL as lacking an execution model is interesting. What does the Python implementation of VGDL add on top of the semantics? Or do you mean that designers using VGDL can't customize the execution model or replace it with their own? Or do you mean that the only way to understand a VGDL game's rules is to execute them via forward simulation?

      By "Ur-game-language" I just meant "the hypothetical primitive game language", the one underlying or encompassing all games. I'm also drawn to the idea of coordinating specialized logics—you see this in SMT solvers as well. So, my money is on "game design modulo theories", where the theories are operational logics. But what's the game design equivalent to the propositional logic that binds statements in those theories together?

      Delete
  2. Mmm, makes me want to sit down and write a functional game again.. I remember my trickiest bug to track down in Bouncecrab 1 actually came straight from the one place in the code I'd acquiesced and used a ref cell rather than threading the data through explicitly, "for simplicity's sake" :P

    Also, I know I've told you this story before, but whenever anyone pulls out the "might as well be using C" line, I can't help but remember the time I said something similar to Benjamin Pierce; he furrowed his brow thoughtfully, smiled knowingly, and said, "Maybe, but it really is a *much* better C..." Data types and pattern matching are surely one of the biggest reasons why!

    ReplyDelete

Post a Comment

Popular posts from this blog

Reading academic papers while having ADHD

Using Twine for Games Research (Part II)

Using Twine for Games Research (Part III)