Tuesday, March 12, 2013

Suspension of Parser Disbelief

At last, it's done: I have expanded the 53-section prototype of my gamebook.js engine into a fully playable, complete implementation of Fire on the Water, the second gamebook in the Lone Wolf series, created by Joe Dever in the 80s. To the obvious question (Why start with the second book?), I don't really have a good answer, apart from the fact that FotW was one of the earliest gamebooks I've read (in French, as La traversée infernale), and always one of my favorites (I think in large part because of the maritime theme).

So to recap, gamebook.js is an experimental crossbreed between two classic genres: interactive fiction (IF) and gamebooks. Instead of navigating an explicit menu of choices (as with a classical gamebook), those are rather willfully concealed after each section, and your job is to "reveal" them by typing any command you want (using clues from the text) which the parser then tries to match. The idea is to expand, as much as possible, the feeling of "freedom" while exploring the gamebook world, as well as offering a novel (and hopefully fun) way to interact with it.

So far so good.. but given the typical small number of choices for a section, what's the point really in having a parser, and how does it work anyway? It's true that it obviously couldn't be as sophisticated as a complex IF engine, but I think the one I've created works well in a gamebook setting, and listing its relevant features is probably the best way to show why:
  • A stemmer is used, to reduce word inflections to common, more easily matchable forms (e.g stemmer = stemming = stemmed = stem)
  • A meticulously hand-assembled table of synonyms is also used
  • The (web-based) textual environment supports contextual word autocompletion (thus offering hints, which can be turned off)
  • The ambiguity of certain choices can be enhanced or lessened with (again) tediously, manually curated sets of words (although the default is to match the words (and their synonyms) found in the text of the choices)
  • Although complex sentence structures are not supported (as it would be useless in most cases), compound expressions can be used (e.g. "go inside") to enhance meaning (or illusion thereof)
  • The Action Chart and item management subsystem is seamlessly integrated in the textual interface (so after winning a combat, you can "use your Healing Potion", for instance, or "eat a Meal", if required)
So the trick is actually to suspend your "parser disbelief", and allow yourself to compose commands as they naturally come, and more often than not (I contend) the flow and coherence of the story will make it work seamlessly.

Some Technical Aspects (for those interested)

  • The engine is open and implemented in 100% JavaScript (it should run at least in recent versions of Chrome, Firefox and Safari), using a few excellent external packages (the jQuery Terminal plugin, which I modified a bit, and a JS implementation of the classic Porter Stemmer algorithm)
  • The content is fully contained in a single, highly structured JSON file, which must be hosted on Project Aon for legal reasons
  • The extraction of content from the original Project Aon XML file is semi-automated using a Python script, which weaves it with another customized, handcrafted "override" file, to yield a single final JSON file (in theory, this means that expanding to other LW books should be fairly easy, although the amount of work that must go in the "override" file should not be underestimated, as it would be very hard to fully automate everything)
  • The JSON content file (almost a DSL in itself) has an elaborate set of structures to implement the (sometimes complex, borderline ambiguous) ruleset (boolean requirement operators for certain choices (i.e. must have X amount of gold, or possess the Kai Discipline of Y), item description structures, etc.)
  • The architecture of the engine is adequately decoupled: the general logic (applicable to any LW gamebook) is contained in a single module (~1500 lines), while the book-specific rules and behaviors are kept in a separate module (in this case, ~500 lines of FotW-specific code) with a "pluggable" interface (where any section needing a special treatment simply has an entry in a dictionary data structure)