Hacker News new | comments | show | ask | jobs | submit login
The DUNGEON (Zork I) source (github.com)
94 points by geospeck 100 days ago | hide | past | web | favorite | 50 comments

Not exactly Zork 1. Zork was originally written on MIT mainframes, but when they decided to start Infocom and release the game for profit they couldn't get it all to fit on the personal computers of the time, and so they split it into 3 parts. Zork 2 had the coal mine and the Bank of Zork, I think, and Zork 3 had the endgame. They then added some extra stuff to Zork 2 and 3 that wasn't in the original mainframe version.

The history of the source code is interesting. It was called Zork and written in MDL. At some point they renamed it to Dungeon, but then a little while later named it back to Zork. During the time it was called Dungeon, a DEC engineer logged into their system (open to the world on purpose so people could play the game) but instead of playing the game copied the source code off. Then they translated the game into Fortran so they could run it on PDP-11s. This source code is the descendant of that translation.

A version of it has been ported to the z-machine ( available on almost every platform) : http://penguincentral.com/retrocomputing/zdungeon/

Also referenced here: http://ifdb.tads.org/viewgame?id=4gxk83ja4twckm6j

reading old C like this, I always wonder how could people code like this back then but apparently it was transpiled from fortran. So I'd assume the original code looked better. I dug around and found it, for comparison here is the original rooms.f vs. rooms.c:



Here is the full fortran code: http://gunkies.org/wiki/Zork#Source_code

The original MDL source code is beautiful to read:


Notice that MDL is almost Common Lisp:

        #DECL ((NUM) FIX)
        <TELL "Time passes...">
        <REPEAT ((N .NUM))
            #DECL ((N) FIX)
            <COND (<OR <L? <SET N <- .N 1>> 0>
                       <CLOCK-DEMON ,CLOCKER>
                       <FIGHTING ,FIGHT-DEMON>>

    (defun wait (&optional (num 3))         ; same arglist
      (declare (fixnum num))                ; similar declaration
      (tell "Time passes...")               ; some call
      (repeat ((n num))                     ; some loop macro, see below
        (declare (fixnum n))                ; declaration
        (cond ((or (< (setq n (- n 1)) 0)   ; old-style COND, OR, <, SETQ, -
                   (clock-demon clocker)    ; some call
                   (fighting fight-demon))  ; some call
               (return)))))                 ; return from loop
Where REPEAT would be implemented as:

    (defmacro repeat (vars decl &body body)
      `(let ,vars
         (loop (progn ,@body))))

Common Lisp basically got type declarations, rich argument lists, ... from MDL.

Indeed... as soon as I saw this, I skimmed the (smug towards Lispers!) MDL primer [0] and wrote a few (broken) esrap rules to parse some MDL into Lisp. For example yours gives:

    DEMUDDLE> (parse 'expr *lispm-expr*)
     (TELL "Time passes...")
       ((OR (L? (SET 'N (- (LVAR N) 1)) 0) (CLOCK-DEMON (GVAR CLOCKER))
Someone more determined could write a small MDL->CL translator and produce a CL port of Zork (chock full of special declarations, since MDL uses dyamic scoping).

I also found the following interesting remark in the primer: "One of the implementors of Zork has been heard to say that Zork is a huge conditional".

[0] http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-29...

I read parts of the MDL manual. It supported hacks whereby it could shift to using parentheses, as well as evaluation/quoting conventions that are more like Lisp.

thanks I hope thats the end of that rabbithole, that MDL almost looks like XML

neat: https://github.com/itafroma/zork-mdl/blob/master/rooms.mud#L...

It looks exactly like Lisp to me, just with angle brackets rather than parens.

That's because both LISP, XML (and React) are just trees.

Would be interesting to make a React port of this for the web, might look similar to MDL

Honest question as someone who never got comfortable with Lisp languages. Is the code in parser.mud easy to read. One of those 100 line functions, could you jump to the middle of it and start understanding the meaning as someone familiar with C like languages? Even though I can figure out the syntax it looks like line noise to me but perhaps it is because i've not done much Lisp coding.

I wouldn't call that code easy to read, and that's coming as someone who has actually at some point learned enough MDL to actually know the syntax rather than have to reverse engineer it on the spot. There's a couple of reasons why that code is rough to read today:

- It's doing very complicated operations that operate on mutable global data, and structuring it as huge and deeply nested functions rather than splitting the operations up to smaller chunks with meaningful names. But you'd see exactly the same kind of thing in non-Lisp source code of that era; it's just different sensibilities.

- The code is incredibly heavy on conditionals. Which makes sense given the problem domain: parsing a pseudo-natural language. But MDL is a language where the conditionals kind of suck. COND is basically unreadable in any Lisp, you'd very rarely see people use it today. In CL you'd have more readable options like IF, WHEN and UNLESS. In MDL the only option is misusing short-circuiting AND/OR as a poor man's IF. Which they do in places, which doesn't help readability either.

- The use of angle brackets makes everything look like a sea of less-/greater -than comparisons. At least I just can't help it. It's especially bad when combined with the array indexing syntax.

> COND is basically unreadable in any Lisp, you'd very rarely see people use it today. In CL you'd have more readable options like IF, WHEN and UNLESS.

I wouldn't say "very rarely"; COND is still used for multi-way conditionals. Virtually everyone I know would write:

    (cond ((minusp x) 'negative)
          ((plusp  x) 'positive)
          (t          'zero))
Rather than:

    (if (minusp x)
        (if (plusp x)
IF, WHEN, and UNLESS are generally preferred where they fit nowadays, but I wouldn't call writing them with COND "basically unreadable", either, ie:

    (cond (pred then)
          (t    else))
    (cond (pred then))
    (cond ((not pred) then))
Compared to:

    (if pred then else)
    (when pred then)
    (unless pred then)

Indeed, I always thought COND was a construct sorely missing from other languages. Pattern matching is becoming popular for similar uses. I honestly feel it can go over board in many of the same ways though.

As someone very comfortable with Lisp languages: it is hard to read. Initially, the angle brackets do throw me off a bit.

Beyond that, I'd have to read the language manual to make sense of notations like ,foo and .bar.

The code makes a lot of references to non-local names. Someone reading the code would benefit from being familiar with the semantics of what those denote.

What's going on in those functions isn't "rocket science" though.

Pretty sure the fortran was itself a port. My apocryphal memory is that the original is for some custom system, which wikipedia tells me was "MDL". The fortran was the result of it being carried to more common systems.

Yes. The Infocom games were written in MDL, which was a LISP derivative.

And developed on a PDP-11 almost too the end of the company...

Weren't they using a 10? I don't remember but it'd at least be surprising not to while they were still at MIT.

Ah yes, my bad. And it is not even that long since i read the history on Filfre. Guess i have been reading so much about the 11 i got the two mixed...

The 11 had such a pretty instruction set, though it was kinda small for developing a program like Zork.

I think they eventually had a TOPS-20.

One of the gnarliest code bases I ever worked in was a very large C project where the inner core had been run through a f2c transpiler. Over the subsequent decade the surrounding code was a hodgepodge of people taking their own interpretations of autogenerated C code because folks didn't question why the code looked the way it did and thus they did their best to maintain the same look and feel. Oh and no one really knew how that original inner core worked, there were no docs, no oral tradition, and it was over 20 years old.

While I was still working there we accumulated enough major change requests to the application that finally got the go ahead to throw the original code base out and start from scratch.

The download links at http://gunkies.org/wiki/Zork#Source_code are all broken.

atleast this one worked: http://simh.trailing-edge.com/games/dungeon.zip (Bob's port to Fortran)

What version of c used integer and logical as type decls?

In http://blog.zarfhome.com/2017/08/your-load-is-too-heavy-zork... , Andrew Plotkin was pointing to an Inform 6 version of Zork by Allen Garvin , http://plover.net/~agarvin/zork1.txt derived from the original decompiled Z-machine code.

And http://plover.net/~agarvin/zorkbugs.txt is a list of Zork bugs.

See also Open Adventure:


This code is a forward-port of the Crowther/Woods Adventure 2.5 from 1995, last version in the main line of Colossal Cave Adventure development written by the original authors. The authors have given permission and encouragement for this release, it obsolesces all the 350-point versions and previous 2.x (430-point) ports.

Knuth has a version of this game. Fun read: http://www-cs-faculty.stanford.edu/~knuth/programs/advent.w....

What a thrill it was when I first got past the green snake! Clearly the game was potentially addictive, so I forced myself to stop playing — reasoning that it was great fun, sure, but traditional computer science research is great fun too, possibly even more so.

I wish more people had this attitude to distracting things.

Which aspect? The respect, or the interest in research that equaled it? :)

I suspect you mean both. And I agree. I'd probably agree with all permutations of meaning here, actually.

Note: Best to run that program through `cweave` and read the typeset output, rather than read the `.w` file directly.

Indeed, I should have mentioned this. Thanks!

This is also a chapter in https://smile.amazon.com/Selected-Papers-Games-Lecture-Notes...

I would be lying if I said this was super easy to read. It is easy, though. Not sure if it is a good exposition for literate programming. I certainly like it, but I think I was predisposed to.

Yeah when reading some of Knuth's literate programs, I get the feeling that they are probably the best possible exposition of programs that are not so good to read. :-) That is, the programs aren't structured modularly like good modern programmers would write (encapsulation, separation of concerns, etc.) — instead they freely use global variables, gotos, etc., in the programming style of the 60s with some of Knuth's idiosyncratic improvements. But given that "bad" program, the one with the globals and the gotos, Knuth's literate programming system produces what is probably the best possible exposition of that program — at least for reading as printed material (on paper not on screen).

I actually have grown to like globals because of this writing style. I'll note that most of what he writes is self contained in the section they are in. However, some things require you to have knowledge of how the system works. You can try and limit this from folks locally, but you wind up having confusing state passing tricks that can, amusingly, lead to bugs.

This was also discussed a couple of days ago:


That Makefile made my day...

  # On SCO Unix Development System 3.2.2a, the const type qualifier does
  # not work correctly when using cc.  The following line will cause it
  # to not be used and should be uncommented.
Write once, run anywhere provided all the tweaking is done properly. Those were the days.

EDIT: formatting.

Neat. compiled right up on my SunOS 4.1.4 machine with only a slight modification (dsub.c had some C++ style comments that the old BSD cc didn't like).

  phoenix$ zork
  Welcome to Dungeon.                     This version created 11-MAR-91.
  You are in an open field west of a big white house with a boarded
  front door.
  There is a small mailbox here.

4.1.4? Yummy, my favorite! Is it running on real hardware or in a VM? If the former, what software do I need and how can I get an image please?

I'm running it on the real deal - a 1991-ish SPARCstation IPC. 25MHz of SPARC goodness.

Most of these machines are dead because the power supply output capacitors have failed, but a fairly easy soldering job and they are back up and running. My original SCSI HD also failed (a 424MB Seagate ST1480N), but I've subbed in a SCSI2SD. Works a treat. I basically just play Nethack on it. I've also been experimenting with TeX 3.141 on it.

As far as a VM, I believe it is possible to run 4.1.4 within QEMU. I haven't personally tried, but I have had success in the past running some versions of Solaris 2.x for sun4m in QEMU. I believe you can emulate a SPARCstation 5 with tcx graphics fairly well with that.

It would be interesting to refactor zork into HTML+CSS and set it up like cssZenGarden.com so folks could add their own designs.

Although a much smaller text adventure game would me more achievable.

You can create HTML based interactive fiction with the latest inform: http://inform7.com/

That's basically Twine: https://twinery.org

that's new to me, thanks!

A cavalcade of GOTOs

Back then, stacks (and the private namespaces resulting from the use of functions/methods in most modern languages) were probably considered a superfluous resource indulgence: 1970s bloatware.

Might have been ported from assembly, this is not really the very original source. As someone said, version one was for mainframe or something.

It was ported from Fortran, and that version itself was ported from the original written in a LISP derivative called MDL.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact