git @ Cat's Eye Technologies Zzrk / 722ab90
Initial import of Zzrk 1.0 2007.0506 sources. Cat's Eye Technologies 10 years ago
2 changed file(s) with 603 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 Zzrk - Adventures in the Great Unsaturated Grammar
1 ====
2
3 What is it?
4 -----------
5
6 Zzrk is a toy text adventure (or, if you prefer, a toy work of interactive
7 fiction) written in "pure" Zz -- assuming such a concept makes any sense.
8 Zz is a dynamic meta-language designed for the APE parallel computing
9 project to enable variants on languages such as FORTRAN to be quickly
10 developed. As such, Zz maintains very little distinction between the
11 language definition level and the language use level. For this reason, it
12 might be more accurate to describe Zz as a self-modifying grammar.
13
14 Since Zz is typically used to define programming languages, I thought it
15 would be a nice abuse to try to use it to write an actual program (albeit
16 a very language-like one.) The result is Zzrk.
17
18
19 Playing the Game
20 ----------------
21
22 First, you need an implementation of Zz. The only one I've found, and
23 subsequently the one I've written Zzrk around, is OpenZz. It can be
24 gotten from http://openzz.sourceforge.net/.
25
26 Although OpenZz does have an interactive mode, it unfortunately assumes
27 you're using Zz to describe a compiler. Since I assume you'll want to
28 play Zzrk interactively (as opposed to typing the sequence of actions you
29 want to take into a text file, piping it through Zzrk, and seeing what
30 happens), here's a guide to working around some of OpenZz's drawbacks.
31
32 First, you can't just specify zzrk.zz as the input to ozz. Instead,
33 start OpenZz, then at the "ozz>" prompt, type
34
35 /include "zzrk.zz"
36
37 You can then treat the "ozz>" prompt as the prompt for the adventure
38 game parser. Try the usual actions, and see what happens. Be forewarned
39 that any unrecognizable command on your part -- an unknown verb, noun, or
40 other part of speech -- will trigger a syntax error. And, because OpenZz
41 thinks you are the input to a compiler, accumulating 10 of these errors
42 will actually cause OpenZz to quit!
43
44
45 The Game Itself
46 ---------------
47
48 The game itself is embarrassingly simplistic, but there are a few nominal
49 puzzles just to demonstrate that the standard adventure game furniture can
50 be concocted in Zz. Collecting treasures will get you points, and
51 obtaining 50 points will win the game (that is, if you have 50 points and
52 you type "score", you will get a message telling you that you have won.
53 You will still need to quit OpenZz through some other manual action, such
54 as typing Ctrl-D, or causing syntax errors.)
55
56
57 Comments
58 --------
59
60 I originally wrote zzrk.zz on November 21st, 2003. I gave it actual
61 puzzles, wrote this readme, and released it under a BSD license on
62 May 6, 2007.
63
64 A couple of annoying things about Zz...
65
66 The documentation for OpenZz doesn't mention that the /if { } construct
67 has a variant that takes an else clause. And, /return does not actually
68 cause an immediate return, it only assigns a value to the nonterminal
69 under consideration. For these reasons, I was originally writing many of
70 my tests twice (like /if a == b {} /if a != b {}). Then I noticed, in
71 examining the results of /krules, that the kernel does in fact support
72 else. The fact that curly braces actually denote lists means they're not
73 optional in tests though, and the nesting is still pretty annoying.
74
75 The other annoying thing is that there's no way to prioritize selection
76 of nonterminals. For example, I feel very strongly that it ought to be
77 possible to write the score_of production like this:
78
79 /$num_t -> "score_of" coin { /return 5 }
80 /$num_t -> "score_of" jewel { /return 10 }
81 /$num_t -> "score_of" sceptre { /return 15 }
82 /$num_t -> "score_of" crown { /return 20 }
83 /$num_t -> "score_of" object^$ { /return 0 }
84
85 On the basis that coin et al. are more specific than object^$, and should
86 be selected before it. But, it's not possible to set this up, at least as
87 far as I can see. Which is a pity, because this sort of "catch-all"
88 mechanism would also enable much better error handling.
89
90 A couple of nice things about Zz...
91
92 The parser-oriented approach is, of course, very nice for an adventure
93 game. It was very simple to create a parser which is in some respects
94 sophisticated: it can understand "pick up the key" just as easily as
95 "get key". Even nicer is that the scope rules (verbs that apply only
96 to objects that are being held, are in the same room, or either) are
97 implemented directly as productions in the grammar.
98
99 Changing the grammar of the language you are using *on the fly* can be
100 very scary, but also very powerful. Note that until you learn what the
101 magic word is, you can't even use it without causing a syntax error.
102 But afterward it is a full-fledged part of the parser's vocabulary.
103 Note also that this is how the properties of an object are updated:
104 the production which handles "e_exit square_room" is replaced by one
105 that returns a different value, once the door is open.
106
107 Some of the action productions are a bit clumsy because they contain
108 logic that should probably be associated with the object instead.
109 Putting lists of statements in a property of the object, and using
110 Zz's /execute facility, would probably allow a "method-like" style
111 that permits this, but I haven't played with it.
112
113 Lastly, it's interesting to note that internal helper functions (not
114 to mention the full complement of OpenZz builtins) are all available to
115 the player during the course of the game. For example, try
116
117 move player to chest
118
119 and see what happens. Even better, why not try
120
121 object snake "snake" "Eek!" wall wall wall wall "no" loc player
122 look
123 examine snake
124
125 Using Zz's notion of scopes, it might be possible to protect the
126 internals from being invoked like this, but considering Zzrk is just a
127 toy it hardly seems worth bothering.
128
129 Happy adventuring!
130
131 -Chris Pressey
132 May 6, 2007
133 Vancouver, BC
0 !! zzrk.zz - a simple text adventure written in "100% pure Zz"
1 !! Initial skeleton, Nov 21 2003 Chris Pressey
2 !! Minimally fleshed-out (50 pt) version, May 6 2007 Chris Pressey
3
4 !! Copyright (c)2003, 2007 Cat's Eye Technologies. All rights reserved.
5 !!
6 !! Redistribution and use in source and binary forms, with or without
7 !! modification, are permitted provided that the following conditions
8 !! are met:
9 !!
10 !! 1. Redistributions of source code must retain the above copyright
11 !! notices, this list of conditions and the following disclaimer.
12 !! 2. Redistributions in binary form must reproduce the above copyright
13 !! notices, this list of conditions, and the following disclaimer in
14 !! the documentation and/or other materials provided with the
15 !! distribution.
16 !! 3. Neither the names of the copyright holders nor the names of their
17 !! contributors may be used to endorse or promote products derived
18 !! from this software without specific prior written permission.
19 !!
20 !! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 !! ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT
22 !! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 !! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 !! COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 !! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 !! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 !! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 !! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 !! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 !! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 !! POSSIBILITY OF SUCH DAMAGE.
32
33 !! ------------------- object system ---------------
34
35 !! define objects as a Zz type.
36
37 !! define the identity of an object.
38
39 /ident -> "obj" object^o { /return o as ident }
40
41 !! define equality on objects.
42
43 /$cond -> object^a "=" "=" object^b {
44 /if obj a == obj b { /return 1 } else { /return 0 }
45 }
46 /$cond -> object^a "!" "=" object^b {
47 /if obj a == obj b { /return 0 } else { /return 1 }
48 }
49
50 !! ----------- object definition definition -----------
51
52 /objects := {} !! list of all defined objects
53
54 /stat -> "object" ident^o { !! "forward" declaration
55 /object -> o { /return o }
56 }
57
58 !! actual object declaration
59 /stat -> "object" ident^o string_e^sdesc0 string_e^desc0 ...
60 object^n_exit0 object^s_exit0 object^e_exit0 object^w_exit0 ...
61 string_e^takeable0 object^loc0 {
62 /object -> o { /return o }
63 /string_t -> "b_sdesc" o { /return sdesc0 }
64 /string_t -> "b_desc" o { /return desc0 }
65 /object -> "b_n_exit" o { /return n_exit0 }
66 /object -> "b_s_exit" o { /return s_exit0 }
67 /object -> "b_e_exit" o { /return e_exit0 }
68 /object -> "b_w_exit" o { /return w_exit0 }
69 /string_t -> "b_takeable" o { /return takeable0 }
70 /object -> "b_loc" o { /return loc0 }
71 /noun -> sdesc0 { /return o }
72 /objects := objects & { o }
73 }
74
75 /string_t -> "sdesc" object^o { /return b_sdesc o }
76 /string_t -> "desc" object^o { /return b_desc o }
77 /object -> "n_exit" object^o { /return obj b_n_exit o }
78 /object -> "s_exit" object^o { /return obj b_s_exit o }
79 /object -> "e_exit" object^o { /return obj b_e_exit o }
80 /object -> "w_exit" object^o { /return obj b_w_exit o }
81 /string_t -> "takeable" object^o { /return b_takeable o }
82 /object -> "loc" object^o { /return obj b_loc o }
83
84 !! ----------- object definitions proper -----------
85
86 object nowhere
87
88 object nowhere "nowhere" ...
89 "You can't see anything like that here." ...
90 nowhere nowhere nowhere nowhere "no" nowhere
91
92 object wall "wall" ...
93 "You see nothing special." ...
94 nowhere nowhere nowhere nowhere "no" nowhere
95
96 object square_room
97 object low_tunnel
98 object disused_armoury
99 object junction
100 object troll_room
101 object library
102 object treasure_room
103
104 object door
105
106 object player "yourself" ...
107 "As beautiful as ever." ...
108 nowhere nowhere nowhere nowhere "no" square_room
109
110 object square_room "Square Room" ...
111 "You are in a square room. A passage leads north; to the east is a door." ...
112 low_tunnel wall door wall "no" nowhere
113
114 object door "door" ...
115 "A heavy iron door, rusting with age." ...
116 nowhere nowhere nowhere nowhere "no" square_room
117
118 object low_tunnel "Low Tunnel" ...
119 "This is a low tunnel. It heads north and south." ...
120 disused_armoury square_room wall wall "no" nowhere
121
122 object key "key" ...
123 "A small, shiny key." ...
124 nowhere nowhere nowhere nowhere "yes" low_tunnel
125
126 object disused_armoury "Disused Armoury" ...
127 "Dust covers eveything here. A passage leads south." ...
128 wall low_tunnel wall wall "no" nowhere
129
130 object coin "coin" ...
131 "A standard, but nonetheless valuable, gold coin." ...
132 nowhere nowhere nowhere nowhere "yes" low_tunnel
133
134 object sword "sword" ...
135 "A finely-crafted implement of bloodletting." ...
136 nowhere nowhere nowhere nowhere "yes" disused_armoury
137
138 object junction "Junction" ...
139 "Rough-hewn passages lead off in all directions." ...
140 troll_room treasure_room library square_room "no" nowhere
141
142 object jewel "jewel" ...
143 "It is a dazzling blue gem, probably worth a pretty penny." ...
144 nowhere nowhere nowhere nowhere "yes" junction
145
146 object troll_room "Troll Room" ...
147 "Bloodstains and axe-gouges grace the walls." ...
148 wall junction wall wall "no" nowhere
149
150 object troll "troll" ...
151 "A nasty rubbery green sort with foul breath." ...
152 nowhere nowhere nowhere nowhere "no" troll_room
153
154 object chest "chest" ...
155 "Large and ornately carved out of cedar." ...
156 nowhere nowhere nowhere nowhere "no" troll_room
157
158 object crown "crown" ...
159 "A regal crown fashioned from gold, studded with topaz." ...
160 nowhere nowhere nowhere nowhere "yes" chest
161
162 object sceptre "sceptre" ...
163 "A tapered length of hardwood studded with jewels and crystals." ...
164 nowhere nowhere nowhere nowhere "yes" treasure_room
165
166 object library "Library" ...
167 "None of these books look like they've been disturbed for ages." ...
168 wall wall wall junction "no" nowhere
169
170 object book "book" ...
171 "Its leather binding is very dusty." ...
172 nowhere nowhere nowhere nowhere "yes" library
173
174 object treasure_room "Treasure Room" ...
175 "Unfortunely all that remains in most of the shelves are cobwebs." ...
176 junction wall wall wall "no" nowhere
177
178
179 !! ----------------- object modifier utilities ------------
180
181 /stat -> "move" object^o "to" object^loc {
182 /object -> "b_loc" o { /return loc }
183 }
184
185 !! ------------------- verbs ------------------
186
187
188 !! general statement -> command bridge.
189
190 /stat -> command^$
191
192 !! travel
193
194 /command -> go_verb^$ direction^d {
195 /if d == north { /newloc = obj n_exit loc player }
196 /if d == south { /newloc = obj s_exit loc player }
197 /if d == east { /newloc = obj e_exit loc player }
198 /if d == west { /newloc = obj w_exit loc player }
199 /if newloc == wall {
200 /print "There's a wall in the way."
201 } else {
202 /if newloc == door {
203 /print "The door is closed and locked."
204 } else {
205 /if newloc == nowhere {
206 /print "You can't go that way."
207 } else {
208 move player to newloc
209 look
210 }
211 }
212 }
213 }
214
215 /command -> direction^d { go d }
216
217 /go_verb -> "move" {}
218 /go_verb -> "walk" {}
219 /go_verb -> "go" {}
220 /go_verb -> "travel" {}
221
222 /direction -> "north" { /return north }
223 /direction -> "south" { /return south }
224 /direction -> "east" { /return east }
225 /direction -> "west" { /return west }
226 /direction -> "n" { /return north }
227 /direction -> "s" { /return south }
228 /direction -> "e" { /return east }
229 /direction -> "w" { /return west }
230
231 !! pick up
232
233 /command -> pickup_verb^$ visible_noun^n {
234 /if n == nowhere {
235 /print "You can't see any such thing."
236 } else {
237 /if n == sceptre {
238 /print "Almost as if it were alive, it evades your grasp."
239 } else {
240 /if takeable n == "yes" {
241 move n to player
242 /print "Taken."
243 } else {
244 /print "You can't carry that!"
245 }
246 }
247 }
248 }
249
250 /pickup_verb -> "get" {}
251 /pickup_verb -> "grab" {}
252 /pickup_verb -> "take" {}
253 /pickup_verb -> "pick" "up" {}
254
255 !! put down
256
257 /command -> putdown_verb^$ held_noun^n {
258 /if n == nowhere {
259 /print "You aren't carrying any such thing."
260 } else {
261 move n to loc player
262 /print "Dropped."
263 }
264 }
265
266 /putdown_verb -> "drop" {}
267 /putdown_verb -> "put" "down" {}
268
269 !! examine
270
271 /command -> examine_verb^v nearby_noun^n {
272 /print desc n
273 }
274
275 /examine_verb -> "examine" {}
276 /examine_verb -> "inspect" {}
277 /examine_verb -> "look" "at" {}
278
279 !! look
280
281 /command -> look_verb^$ {
282 /print sdesc loc player
283 /print desc loc player
284 /foreach o in objects {
285 /if o != player {
286 /if loc o == loc player {
287 /print "You can see a", sdesc o, "here."
288 }
289 }
290 }
291 }
292
293 /look_verb -> "look" {}
294 /look_verb -> "l" {}
295
296 !! inventory
297
298 /command -> inv_verb^$ {
299 /inv_list := {}
300 /foreach o in objects {
301 /if loc o == player {
302 /inv_list := inv_list & { o }
303 }
304 }
305 /inv_length := inv_list.length
306 /if inv_length == 0 {
307 /print "You are empty-handed."
308 } else {
309 /print "You are carrying:"
310 /foreach o in inv_list {
311 /print " a", sdesc o
312 }
313 }
314 }
315
316 /inv_verb -> "inventory" {}
317 /inv_verb -> "inv" {}
318 /inv_verb -> "i" {}
319 /inv_verb -> "take" inv_verb^$ {}
320
321 !! score
322
323 /command -> "score" {
324 /score_v := 0
325 /foreach o in objects {
326 /if loc o == player {
327 /score_v := score_v + (score_of o)
328 }
329 }
330 /print "Your score is",score_v,"points out of a possible 50."
331 /if score_v == 50 {
332 /print "Congratulations! You won the adventure!"
333 }
334 }
335
336 /$num_t -> "score_of" object^o {
337 /sc := 0
338 /if o == coin { /sc := 5 }
339 /if o == jewel { /sc := 10 }
340 /if o == sceptre { /sc := 15 }
341 /if o == crown { /sc := 20 }
342 /return sc
343 }
344
345 !! open
346
347 /command -> open_verb^$ nearby_noun^n {
348 /if n == door {
349 /if e_exit square_room != door {
350 /print "It's already open."
351 } else {
352 /if loc key != player {
353 /print "It's locked."
354 } else {
355 /object -> "b_e_exit" square_room { /return junction }
356 /print "The door creaks open!"
357 }
358 }
359 } else {
360 /if n == chest {
361 /if loc troll == loc player {
362 /print "The troll guards it jealously."
363 } else {
364 /if loc crown != chest {
365 /print "It's already open."
366 } else {
367 move crown to loc player
368 /print "You open the chest, revealing a beautiful crown."
369 }
370 }
371 } else {
372 /print "You can't open that!"
373 }
374 }
375 }
376
377 /open_verb -> "open" {}
378 /open_verb -> "unlock" {}
379
380 !! fight
381
382 /command -> fight_verb^$ visible_noun^n {
383 /if n != troll {
384 /print "Violence isn't the answer to this one."
385 } else {
386 /if loc sword != player {
387 /print "You don't stand a chance bare-handed."
388 } else {
389 move troll to low_tunnel
390 /print "You dodge and weave and valiantly deliver a stunning blow!"
391 /print "The troll flees!"
392 }
393 }
394 }
395
396 /fight_verb -> "fight" {}
397 /fight_verb -> "attack" {}
398 /fight_verb -> "kill" {}
399
400 !! read
401
402 /command -> read_verb^$ nearby_noun^n {
403 /if n != book {
404 /print "There's nothing written on it."
405 } else {
406 /print "Matters arcane and esoteric fill this volume."
407 /print "You notice one word of magical essence in particular: YKZMNIFN"
408 /command -> "ykzmnifn" {
409 /if loc player == loc sceptre {
410 move sceptre to player
411 /print "The sceptre floats right into your hand!"
412 } else {
413 /print "Nothing happens here."
414 }
415 }
416 }
417 }
418
419 /read_verb -> "read" {}
420
421 !! ---------------------------- parse errors
422
423 /command -> noun^n {
424 /print "But what do you want to do with the",n,"?"
425 }
426
427 !! It would be great if we could do this, but we can't.
428 !!
429 !! /command -> any^$ noun^$ {
430 !! /print "I don't understand what you mean."
431 !! }
432
433 !! ---------------------------- nouns
434
435 /noun -> "the" noun^n { /return n }
436 /noun -> "a" noun^n { /return n }
437 /noun -> "an" noun^n { /return n }
438
439 /visible_noun -> noun^n {
440 /if loc n == loc player {
441 /return n
442 }
443 /if loc n != loc player {
444 /return nowhere
445 }
446 }
447
448 /held_noun -> noun^n {
449 /if loc n == player {
450 /return n
451 }
452 /if loc n != player {
453 /return nowhere
454 }
455 }
456
457 /nearby_noun -> noun^n {
458 /if loc n == player || loc n == loc player {
459 /return n
460 }
461 /if loc n != player && loc n != loc player {
462 /return nowhere
463 }
464 }
465
466 !! --------------------------- start
467
468 look