A while back I recreated one of the first known versions of Zork to ZIL. This is a write-up of the notes I did during the process and it will be an ongoing series that is updated here.
Zork is maybe one of the most famous computer games ever. It was originally developed at MIT and it was written in MDL, a Lisp like language. This is a documentation of the process of an attempt to recreate one of the earliest, preserved incarnations of Zork in ZIL. During the following months and years it progressively got a better and better parser and a widening map. Known versions are a 387 point from July 1977, a 500 point from December 1977, a version with an added 100 point end-game from April 1978 and the final 616+100 point version from December 1979 (The version from July 1981 only include minor bug fixes). I might eventually make ZIL versions of these too.
Zork 285 is the earliest known preserved version of the mainframe version of Zork. This version is aproximately three weeks into the development in 1977 or as Tim Anderson retold the history in The New Zork Times in 1985:
"By late May, Adventure had been solved, and various DM’ers were looking for ways to have fun. Marc Blank was enjoying a respite from medical school; I had just finished
my master’s degree; Bruce Daniels was getting bored with his Ph.D. topic; and Dave Lebling was heartily sick of Morse code. Dave wrote (in MUDDLE) a command parser that
was almost as smart as Adventure’s; Marc and I, who were both in the habit of hacking all night, took advantage of this to write a prototype
four-room game. It has long since vanished. There was a band, a bandbox, a peanut room (the band was outside the door, playing “Hail to the Chief”), and a “chamber filled
with deadlines.” Dave played and tested the game, saw that it was pretty awful, and left to spend two weeks basking in the sun.
Marc, Bruce, and I sat down to write a real game. We began by drawing some maps, inventing some problems, and arguing a lot about how to make things work. Bruce still
had some thoughts of graduating, thus preferring design to implementation, so Marc and I spent the rest of Dave’s vacation in the terminal room
implementing the first version of Zork."
The History of Zork by Tim Anderson, The New Zork Times, Winter 1985 (Vol. 4, No. 1)
If the above account is correct, I guess it was a very busy three weeks.
There is two known binaries from this period preserved; one from June 12th and one from June 14th. There are very small differences between these and I have chosen to use the later one for this conversion. The only differences I have found are two bugs that are fixed in the later version and an added synonym to PUSH:
- Bug: The game will crash if you try to DROP a treasure in the trophy case that’s not in your possession.
- Bug: GET or DROP without specifying an object will crash the game.
- PRESS is added as a synonym to PUSH.
PDP-10 is the hardware and ITS (“Incompatible Timesharing System”) is the operating system.
PDP-10 is a 36-bit computer. 36 bits seems odd in today’s world with 32-bit or 64-bit computers but actually have advantages.
- It can address more memory (than 32 bit), up to 2^18 (256K) memory locations each containing a 36-bit WORD. This amount of memory was nicknamed “Moby”, after the whale Moby Dick, since it was considered an enormous amount of memory at the time.
- A 36-bit WORD can, for example, store five 7-bit ASCII characters or six six-bit characters inside a single WORD.
- 36 are dividable with 2, 3, 4, 6, 9, 12 and 18. Because of this numbers are often expressed in the octal numeral system.
- 36 bits allow bigger integer numbers and floating point numbers with bigger precision stored inside a single WORD.
The filesystem in ITS is a bit peculiar compared with today’s tree-structures. Each file
consists of four parts each part stored in a single WORD; the first WORD indicate the device (DSK: is the local device), the second the directory in up to six six-bit characters, the third is the six characters of the first part of the filename and the fourth is the six characters of the second part of the filename. In ITS the files are usually referred to like:
The standard text editor inside the ITS is Emacs and the
FNAME2is often used to indicate the version of the file. So, for example
DEFS 1 is the first version of the file and
DEFS 2is the second, and so on.
Lastly, keep in mind that there is no security in ITS. Every user has full admin rights and login doesn’t use passwords. It all works on an honor system I guess.
The GitHub repositories at MITDDC contains extracted material from backup tapes. The repository zork-1977-07 is of special interest for this project. The file
\tree.txt contains the filedates for all files in the repository.
From the file
\9005183\taa\frob.glue [Jun 8 1977] we can see at line 8,
<SET FOO (!.DEFS !.ROOMS !.TELL !.MAZER !.AACT)>, see that the game is glued together and compiled from the source-files;
DEFS, ROOMS, TELL, MAZER and AACT.
<USE "GLUE"> <SNAME "MARC"> <GROUP-LOAD "DEFS NBIN"> <GROUP-LOAD "ROOMS NBIN"> <GROUP-LOAD "TAA;TELL NBIN"> <GROUP-LOAD "MAZER NBIN"> <GROUP-LOAD "AACT NBIN"> <SET FOO (!.DEFS !.ROOMS !.TELL !.MAZER !.AACT)> <GROUP-GLUE FOO <> <>> <GROUP-DUMP "TAA;FOO GBIN" FOO ,PRINT>
We don’t have all the files from the correct dates but these are the ones we have to work with:
DEFS 81 [Jun 30 1977]: This file contains a lot of type definitions and some functions to manipulate these newly defined types and the lists and vectors they contain. Much of this is built into ZIL and won’t need to be converted.
ROOMS 154 [Jun 14 1977]: Contrary to what one might believe, this is not where the rooms are defined. Instead this is where all basic functions for input, parsing and verb handling are defined. Luckily there is a version from the correct date available.
TELL 35 [Jun 28 1977]: This file is not written in MDL at all, instead it is originally written in assembler. The TELL function is built into ZIL and won’t need to be converted.
MAZER 78 [Jun 30 1977]: This file contains definitions and types for directions and exits. In ZIL this is mostly built into to language and much in here won’t need to be converted.
AACT: This is by far the biggest file and should contain all definitions of rooms and objects and actions associated whit these. Unfortunately there is no early version of this file preserved. In later versions it got split into DUNG and ACT and the earliest versions of these are
DUNG 56 [Dec 12 1977] and
ÀCT 37 [Dec 10 1977].
In addition to the above source files there are:
MADADV HELP [Jun 6 1977]: A text-file that is read and printed during run-time when the user issues the command HELP.
MADADV INFO [Jun 14 1977]: A text-file that is read and printed during run-time when the user issues the command INFO.
MADADV SAVE [Jun 14 1977]: This is the compiled game from this date. Luckily the text is readable ASCII in compiled MDL and the functions appear in the same order as they are defined in the source files. This makes it possible to extract text with, for example, notepad++ from this file and also to see that all cases inside the functions are converted and/or the function maybe is identical to the later one from December.
This file can be run on a PDP-10 ITS and if you don’t have one of those it is possible to run the file on an PDP-10 ITS emulator.
There there is a ongoing project to restoring and emulating the PDP-10 ITS and you can set up your own emulation locally. Something I won’t go into more here, I refer to the project on how to do that. Fortunately there is also an instance of emulator that you can log into over telnet.
- Log into to server at IP-address
10003. Use the telnet protocol. I myself use Kitty as terminal software.
- When you see
"Connected to the KA-10 simulator MTY device, line 0", press
- Now it is time to login. Type
Enter. The username can be up to six characters long.
- Set up your terminal,
:TCTYP AAA SCROLL NO MORE WIDTH 100.
- Start version 54 of MDL,
- Load and start the game,
<RESTORE "MADMAN; MADADV JUN14">$. The
$means that you press
ÈSCto execute the commands inside MDL,
TT ITS.1650. DDT.1547. TTY 21 2. Lusers, Fair Share = 99% THIS IS TT ITS, A HIGHTY VOLATILE SYSTEM FOR TESTING For brief information, type ? For a list of colon commands, type :? and press Enter. For the full info system, type :INFO and Enter. You may have to set the correct terminal type. Try :TCTYP AAA or :TCTYP DATAPOINT PLEASE LOG IN! Type ":login", your name, and Enter. Please log out when your are done. :login heasm To see system messages, do ":MSGS<CR>" :tctyp aaa no more scroll width 100 :KILL *:mud54 MUDDLE 54 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <RESTORE "MADMAN;MADADV JUN14">$ Welcome to adventure. You are in an open field west of a big white house, with a closed, locked front door. >
In the file
ROOMS 154 we find the following line:
<SETG WINNERS '["BKD" "TAA" "MARC" "PDL"]>. These users obviously have some special privileges (BKD = Bruce Daniels, TAA = Tim Anderson, MARC = Marc Blank and PDL = Peter David Lebling). Well, if you login as one of these users you will be able to stop the execution of the game with
Ctrl-Gwithout exiting the MDL interpreter. In this state you can inspect and change variables, redefine and run functions and restart the game. This will be useful later on.
*:mud54 MUDDLE 54 IN OPERATION. LISTENING-AT-LEVEL 1 PROCESS 1 <RESTORE "MADMAN;MADADV JUN14">$ Welcome to adventure. You are in an open field west of a big white house, with a closed, locked front door. > *ERROR* CONTROL-G? LISTENING-AT-LEVEL 2 PROCESS 1 ,HERE$ #ROOM [WHOUS "West of House." NORTH SOUTH WEST EAST] <3 ,ROOMS>$ #ROOM [LOBBY "Dam Lobby" SOUTH NORTH EAST MATCH GUIDE ] <SETG HERE <3 ,ROOMS>>$ #ROOM [LOBBY "Dam Lobby" SOUTH NORTH EAST MATCH GUIDE ] <RDCOM>$ This room appears to have been the waiting room for groups touring the dam. There are exits here to the north and east marked 'Private', though the doors are open, and an exit to the south. There is a matchbook whose cover says 'Visit Beautiful FCD#3' here. Some guidebooks entitled 'Flood Control Dam #3' are on reception desk. >
It is fairly easy to locate in the compiled file where each function is. If we use the function INVENT from
ROOMS 154 as an example.
<DEFINE INVENT ("AUX" (ANY <>)) #DECL ((ANY) <OR ATOM FALSE>) <MAPF <> <FUNCTION (X) #DECL ((X) OBJECT) <COND (<OVIS? .X> <OR .ANY <PROG () <TELL "You are carrying:"> <SET ANY T>>> <PRINC "A "> <PRINC <ODESC2 .X>> <OR <EMPTY? <OCONTENTS .X>> <PRINC " with ">> <MAPR <> <FUNCTION (Y) #DECL ((Y) <LIST [REST OBJECT]>) <PRINC <ODESC2 <1 .Y>>> <COND (<G? <LENGTH .Y> 1> <PRINC " and ">) (<0? <LENGTH .Y>> <PRINC ".">)>> <OCONTENTS .X>> <CRLF>)>> <AOBJS ,WINNER>> <OR .ANY <TELL "You are empty handed.">>>
It looks something like this in the compiled file.
<unprintable>You are carrying:<unprintable> A <unprintable> with <unprintable> and <unprintable> .<unprintable>You are empty handed.<unprintable>
This makes it possible to verify that all the texts are included and correct in the converted file. The becomes especially valuable when trying to convert the functions that are in