Skip to content
Common Lisp implementation of Joseph Powers' classic game.
Common Lisp
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

The Wizard’s Castle for Common Lisp README


From the “Final instructions” section of the article introducing Wizard’s Castle (Power 1980):

These instructions are meant to be a guide only. Feel free to experiment with the various responses when running the game (this is have the fun of the game). For the best results use equal parts imagination and common sense.

I first took these words as license to tinker with the source code and make the game say and do different things. But, now that I type them out, it seems more like Power was actually encouraging players to experiment in order to figure out how to play the game.

Wizard’s Castle is a little primitive to over the kind of combinatorial possibilities of play that a game like Nethack offers, but there is potential. This implementation is done to fulfill the following goals:

  • Faithfully play it as originally coded.
  • Provide the options to play the Commodore PET and MSDOS versions of the game.
  • Make it easy to expand the game’s scope of play and to offer some minor fixes and improvements.

I have consulted the original article, as well as source code for the other editions of the game.

How to play

Currently, this game runs in a Common Lisp REPL. Run the REPL, load the package and run the MAIN function.

CL-USER> (load "wizard.lisp")

If you wish to experiment, or for play-testing:

CL-USER> (load "wizard.lisp")
CL-USER> (in-package #:wizard)

Right now, running a test game is just like running a regular game with a few shortcuts to skip the castle and adventurer setup phases.

WIZARD> (setup-test)
[... output elided ...]
WIZARD (test)

See the section “Testing symbols and functions” for more information about these functions.

NOTE: ZOT is one of the nicknames of the package, and you may see that instead of WIZARD in these examples.

Exported symbols, functions and their options


MAIN plays the game. With no arguments it defaults to the game as originally coded. The following keyword options to MAIN are available:

:ADVENTURER (or adventurer-object Nil)

Provide an adventurer object to the play functions. This bypasses the adventurer setup phase. Use the MAKE-ADVENTURER function to create a custom adventurer. The MAKE-TEST-ADV function will create a few pre-made adventurer characters.

:CASTLE (or castle-object Nil)

Provide a castle object for the main adventure. This bypasses the castle setup phase. If the castle object already has a CAS-ADVENTURER object defined, the game will use that, if not, the game will proceed with the adventurer setup.

:INTRO (or string Nil)

Provide some text to print at the introduction of the game, as in the MSDOS version. The MSDOS intro text is provided in +INTRO-TEXT-DOS+.

:HELP (or string Nil)

Provide some text for the HELP option as in the MSDOS version. The MSDOS help text is provided in +HELP-TEXT-DOS+.


If T, MAIN returns the whole castle object. If Nil, MAIN returns only CAS-HISTORY.


Play the Commodore PET game as adapted by John O’Hare. Right now it just turns on *CURSE-NOTIFY* as below:

(let ((*curse-notify* T))

The curse notice text is bound to +CURSE-NOTICE-OHARE+.

I have not yet figured out how to format the output for the shorter line length in this edition.


Play the MSDOS game as adapted by J.T. Stetson. Basically this:

(main :intro +intro-text-dos+ :help +help-text-dos+)

New features

*FORGETFULNESS* (or symbol Nil)

By default, to conform to original code, *FORGETFULNESS* is set to FORGET-RANDOM which unmaps a random room in the castle, regardless of whether it was mapped or not. Set *FORGETFULNESS* to FORGET-MAPPED and it will forget a room that has already been mapped.

*GAZE-MAPPER* (or symbol Nil)

Gazing into orbs can give information about other rooms in the castle, but this information isn’t reflected in the map, because what the orbs say isn’t always true.

Setting *GAZE-MAPPER* to GAZE-MAP-NAIVE will cause let the adventurer to map the rooms that the orbs inform about.

Setting *GAZE-MAPPER* to GAZE-MAP-ASK will cause the game to ask the player if it should map the creature at the coordinates specified.


The format string used by WIZ-FORMAT. By default, this is set to +ALL-CAPS+. You can set it to +MIXED-CASE+ when you want less obnoxious output strings.


Common Lisp’s array subscripts have to be translated into the system used for the orginal game. By default this is set to +WIZARD+ and so coordinate will be translated. When set to +ARRAY+ the game uses array coordinates.

Testing symbols and functions


A special variable holding a reusable random-state. Used by the testing environment to recreate castle objects and replay games. Default value is a new random state from (MAKE-RANDOM-STATE T).


An adventurer object for testing. Default value, Nil. Use MAKE-TEST-ADV to create a test adventurer.


A castle object for testing. Default value, Nil. Instead of making deep copies of the testing environment’s castle object, the testing environment reuses the random state *R* to regenerate it.


Make a test adventurer object from a predefined set. Accepts one optional symbol arguement.


The set of predefined adventurers is roughly as follows:

A female human fighter: highly capable and skilled, well armed and armored, but poor, blind.
A male hobbit: smart and fast (skilled in running-away), but weak; poor, unarmed and unarmored; has a book stuck to his hands.
A female dwarf: strong, somewhat graceful and more brave than smart; well armored but less well armed, poor and poorly equipped.
A male human: strong, agile, but dumb and forgetful; well-armed, but poorly armored; poor and poorly equipped.
A female elf: highly intelligent, somewhat graceful but weak; no money, poorly armed and armored; has many flares, and the runestaff but lazy and lethargic.
A human male: moderate iq, but weak and clumsy; unarmed, unarmored, no equipment; extremely rich, but has hole in his wallet (leech).
A human with randomly selected sex: average abilities and equipment; poor but at least owns a lamp. This is the character I would always make in the character setup phase.

See the source code for their exact specifications.


Sets up *A* and *Z* using a copy of *R* for the random state in making *Z* and MAKE-TEST-ADV for *A*. After this is run, *A* and *Z* may be passed or MAIN or used in TEST for playing.


Maps all the rooms in a given castle. Of course, CAS-ADVENTURER must be defined.


Play a testing game with a resuable random-state. The equivalent of the following:

(let ((*random-state* (make-random-state *r*)))
  (main :adventurer *a* :castle *z* :last-castle T))


Something went wrong with that request. Please try again.