git @ Cat's Eye Technologies Zzrk / master README.markdown
master

Tree @master (Download .tar.gz)

README.markdown @masterview rendered · raw · history · blame

Zzrk - Adventures in the Great Unsaturated Grammar
==================================================

What is it?
-----------

Zzrk is a toy text adventure (or, if you prefer, a toy work of interactive
fiction) written in "pure" Zz — assuming such a concept makes any sense.
Zz is a dynamic meta-language designed for the APE parallel computing
project to enable variants on languages such as FORTRAN to be quickly
developed.  As such, Zz maintains very little distinction between the
language definition level and the language use level.  For this reason, it
might be more accurate to describe Zz as a self-modifying grammar.

Since Zz is typically used to define programming languages, I thought it
would be a nice abuse to try to use it to write an actual program (albeit
a very language-like one.)  The result is Zzrk.


Playing the Game
----------------

First, you need an implementation of Zz.  The only one I've found, and
subsequently the one I've written Zzrk around, is OpenZz.  It can be
gotten from [http://openzz.sourceforge.net/](http://openzz.sourceforge.net/).

Although OpenZz does have an interactive mode, it unfortunately assumes
you're using Zz to describe a compiler.  Since I assume you'll want to
play Zzrk interactively (as opposed to typing the sequence of actions you
want to take into a text file, piping it through Zzrk, and seeing what
happens), here's a guide to working around some of OpenZz's drawbacks.

First, you can't just specify zzrk.zz as the input to ozz.  Instead,
start OpenZz, then at the `ozz>` prompt, type

    /include "zzrk.zz"

You can then treat the `ozz>` prompt as the prompt for the adventure
game parser.  Try the usual actions, and see what happens.  Be forewarned
that any unrecognizable command on your part -- an unknown verb, noun, or
other part of speech -- will trigger a syntax error.  And, because OpenZz
thinks you are the input to a compiler, accumulating 10 of these errors
will actually cause OpenZz to quit!


The Game Itself
---------------

The game itself is embarrassingly simplistic, but there are a few nominal
puzzles just to demonstrate that the standard adventure game furniture can
be concocted in Zz.  Collecting treasures will get you points, and
obtaining 50 points will win the game (that is, if you have 50 points and
you type `score`, you will get a message telling you that you have won.
You will still need to quit OpenZz through some other manual action, such
as typing Ctrl-D, or causing syntax errors.)


Comments
--------

I originally wrote `zzrk.zz` on November 21st, 2003.  I gave it actual
puzzles, wrote this readme, and released it under a BSD license on
May 6, 2007.

A couple of annoying things about Zz...

The documentation for OpenZz doesn't mention that the `/if { }` construct
has a variant that takes an `else` clause.  And, `/return` does not actually
cause an immediate return, it only assigns a value to the nonterminal
under consideration.  For these reasons, I was originally writing many of
my tests twice (like `/if a == b {} /if a != b {}`).  Then I noticed, in
examining the results of `/krules`, that the kernel does in fact support
`else`.  The fact that curly braces actually denote lists means they're not
optional in tests though, and the nesting is still pretty annoying.

The other annoying thing is that there's no way to prioritize selection
of nonterminals.  For example, I feel very strongly that it ought to be
possible to write the `score_of` production like this:

    /$num_t -> "score_of" coin     { /return  5 }
    /$num_t -> "score_of" jewel    { /return 10 }
    /$num_t -> "score_of" sceptre  { /return 15 }
    /$num_t -> "score_of" crown    { /return 20 }
    /$num_t -> "score_of" object^$ { /return  0 }

On the basis that `coin` et al. are more specific than `object^$`, and should
be selected before it.  But, it's not possible to set this up, at least as
far as I can see.  Which is a pity, because this sort of "catch-all"
mechanism would also enable much better error handling.

A couple of nice things about Zz...

The parser-oriented approach is, of course, very nice for an adventure
game.  It was very simple to create a parser which is in some respects
sophisticated: it can understand "pick up the key" just as easily as
"get key".  Even nicer is that the scope rules (verbs that apply only
to objects that are being held, are in the same room, or either) are
implemented directly as productions in the grammar.

Changing the grammar of the language you are using *on the fly* can be
very scary, but also very powerful.  Note that until you learn what the
magic word is, you can't even use it without causing a syntax error.
But afterward it is a full-fledged part of the parser's vocabulary.
Note also that this is how the properties of an object are updated:
the production which handles `e_exit square_room` is replaced by one
that returns a different value, once the door is open.

Some of the action productions are a bit clumsy because they contain
logic that should probably be associated with the object instead.
Putting lists of statements in a property of the object, and using
Zz's `/execute` facility, would probably allow a "method-like" style
that permits this, but I haven't played with it.

Lastly, it's interesting to note that internal helper functions (not
to mention the full complement of OpenZz builtins) are all available to
the player during the course of the game.  For example, try

    move player to chest

and see what happens.  Even better, why not try

    object snake "snake" "Eek!" wall wall wall wall "no" loc player
    look
    examine snake

Using Zz's notion of scopes, it might be possible to protect the
internals from being invoked like this, but considering Zzrk is just a
toy it hardly seems worth bothering.

Happy adventuring!

-Chris Pressey  
May 6, 2007  
Vancouver, BC