The Adventure begins again

Colossal Cave Adventure was the origin of many things; the text adventure game, the dungeon-crawling D&D (computer) game, the MOO, the roguelike genre. Computer gaming as we know it would not exist without ADVENT (as it was known in its original PDP-10 incarnation).

Long ago, you might have played this game. Or maybe you’ve just heard stories about it, or vaguely know that “xyzzy” is a magic word, or have heard people say “You are in a maze of twisty little passages, all alike”,

Though there’s a C port of the original 1977 game in the BSD game package, and the original FORTRAN sources could be found if you knew where to dig, Crowther & Woods’s final version – Adventure 2.5 from 1995 – has never been packaged for modern systems and distributed under an open-source license.

Until now, that is.

With the approval of its authors, I bring you Open Adventure. And with it some thoughts about what it means to be respectful of an important historical artifact when it happens to be software.

This is code that fully deserves to be in any museum of the great artifacts of hacker history. But there’s a very basic question about an artifact like this: should a museum preserve it in a static form as close to the original as possible, or is it more in the right spirit to encourage the folk process to continue improving the code?

Modern version control makes this question easier; you can have it both ways, keeping a pristine archival version in the history and improving it. Anyway, I think the answer to the general question is clear; if heritage code like this is relevant at all, it’s as a living and functional artifact. We respect our history and the hackers of the past best by carrying on their work and their playfulness.

I’ve actually dealt with this question before, which is why Super Star Trek has both interface improvements and a -t option that invokes the original TTY interface in all its brutal simplicity. Open Adventure will have a similar option.

When Willie Crowther wrote the very first version in 1976 he was also writing firmware for the earliest generation of routers on the operational ARPANET – he was one of the most ingenious and capable programmers of his time. The code makes a fascinating study in how to push the limits of the primitive tools then available to him.

It’s very strange to the modern eye just to see a simulation like ADVENT written with no analogue even of C structures, let alone objects. But the FORTRAN Crowther wrote in didn’t have such things; game state was all global variables, a “feature” preserved in the mechanically translated C of 2.5. (Which, alas, is extremely ugly code full of gotos.)

It also looks odd, 40 years after the fact, to see the amount of code complexity devoted to space/time optimization so that (for example) you don’t have to re-parse the text master of the dungeon-defining database on every startup. That’s what you had to do then, when a room-filling minicomputer cranked many fewer instructions per second than the controller in your microwave oven.

Despite all the energy Crowther and Woods had to spend fighting ancient constraints, ADVENT was a tremendous imaginative leap; there had been nothing like it before, and no text adventure that followed it would be innovative to quite the same degree.

Thus, one of my goals moving forward will be to make the logical design of the dungeon simulation easier to understand for a modern reader. This will probably entail something parallel to what was done in the BSD Games port – gradually massaging the code into more idiomatic C. This reflects my judgment that it’s more important to make Crowther & Wood’s algorithmic thinking more visible than it is to, in any sense, preserve the details of their code.

It’s actually more difficult to decide how much to change their data structures. In idiomatic C one would collect all the saveable game state into a structure rather than leaving it as a mess of global variables that have to be saved and restored one at a time. And a lot of the strange bit-packing hacks in the database representation could probably be done away with today. But would doing that sort of thing obscure their achievement too much?

Probably not – and the baseline version will still be visible in the repository, after all. Likely what I’ll end up doing (if I can allocate the time) is cleaning up stuff like that and leaving comments explaining what it looked like in the FORTRAN original.

I don’t plan on any gameplay changes yet. Any such things will be reversible by the switch to restore historic behavior.

One thing I definitely plan is to modify the code so it can be regression-tested by capturing command logs, replaying them to the game and checking that the output is as expected – testing a full walkthrough should be possible. Matter of fact that needs to happen before anything else so that the correctness of changes can be verified.

This is not a strategy that would likely have occurred to anyone (well, maybe outside of a handful of people at Bell Labs) in 1977. Finding it thinkable depends on a mindset created by Unix pipes and redirection that was only gestating then.

Replay also busts one of Crowther & Woods’s original goals – thwarting attempts to get around obstacles in the game with any investment less than quitting and playing again. Towards this end they deliberately obscured the encoding of save files to make point tweaks of the game state difficult.

That, however, is a hack that fails the Kerckhoffs’s Law test – it’s useless or near useless in an environment where the “adversary” has the source code. When ADVENT (so called because PDP-10 filenames were limited to six characters of uppercase) was written, that was a pretty safe assumption, but today it will never be safe again. No harm, then, in dropping their obscurifying measures.

Source code obscurity is a “feature” from 1977 I miss less than even FORTRAN…

59 comments

  1. As Penn and Teller are wont to say, a true magic trick is even more amazing after you reveal the trick.

    Imagine an art guide you might pick up from any museum, pointing out details and historical methods behind the pictures hanging on the wall, that any visitor would likely overlook if they weren’t an art history major. Ideally, any comments you write explaining the original form of the data structures and the savegame tweaks would exist in a form that non-programmers could similarly read and comprehend. Especially if it’s in a form that nascent hackers would read and comprehend.

    (Meanwhile: don’t forget a quick note on why it’s not called ADVENTURE.)

  2. >Colossal Cave Adventure was the origin of many things;…the dungeon-crawling D&D game

    Huh? I’m curious as to how you come to this conclusion.

    Never mind. I’m just being pedantic…

  3. Somewhere I have a copy of the port to CDC’s FORTRAN, using 60-bit words. Always wanted to bring it forward into another language, but never had the time. Kudos, esr.

  4. The earliest version I ever saw (circa 1977) was in Control Data FORTRAN, and I thought that was the original. Did the PDP-10 version come before or after that?

    The Control Data version did have the option to save and restore a game, which was done by actually saving the complete sequence of input as plain text, along with a starting seed value for the random number generator. Later this was changed to also save the seed value at the point of saving, thus thwarting people who would cheat by editing their savefiles.

    Later, some people at my school added 30+ extra rooms onto the cave. I don’t know of that variant ever getting saved.

    1. >Did the PDP-10 version come before or after that?

      Before, though possibly not by more than months. The original code was written on a PDP-10 at Bolt Beranek & Newman, then finished on another PDP-10 at the Stanford AI Lab.

  5. Good call to put (computer) after D&D. OD&D (that is, the original edition of the tabletop game) was published in 1974 and had of course been kicking around Lake Geneva and Minneapolis for a couple years before that. By 1975 it certainly would have been known on both coasts. Jon Peterson’s _Playing At The World_ is probably the best, and almost certainly the best-researched, account, although if you’re only reading for the D&D parts you have a lot of wargame history to slog through first.

  6. Astonishing, just 6000 lines, code comments and documentation combined. It might use a lot of gotos, but it is amazingly readable and clear code, before even considering it is a mechanical translation from Fortran. (It is, isn’t it?) That is what I call tight. I wonder if it can be compressed any further, or if this spaghetti goto form is as space-efficient as we can make it.

    1. >I wonder if it can be compressed any further, or if this spaghetti goto form is as space-efficient as we can make it.

      I have no interest in compressing it further. I’d prefer making it more readable and getting rid of all those GOTOs.

  7. If you were planning to rewrite it entirely, you could do much worse than to start with Graham Nelson’s reimplementation in Inform 6…which is a procedural language designed to compile down to z-code (the Infocom story format).

    http://www.ifarchive.org/if-archive/infocom/compilers/inform6/examples/Advent.inf

    Note that it’s not the much more linguistically interesting Inform 7, which is a declarative rather than a procedural language. There is actually a faithful reimplementation of the outside-the-cave bit of Adventure in Inform 7 embedded within my own _Mentula Macanus: Apocolocyntosis_. Which is a pornographic and terrifically intertextual text adventure set in the Roman world. What does that have to do with a cave system in Kentucky? Good question. The best place for that source code is https://www.stiffymakane.com/MMA/source_191.html (through section _198.html). Those portions of the code are safe for work. Unlike most of the rest.

  8. >I have no interest in compressing it further. I’d prefer making it more readable and getting rid of all those GOTOs.

    My compression interest is based on the way I can usually compress my code by a good factor when I shift into LISP mode. But looking at this code, it seems clear enough as it is, and not sure how to transform it into LISP without expanding it. At least at first. Maybe if I spent a few hours with the code base something would occur to me. I know, different goal from yours, which is to clean up the C code. I’m just ruminating, how would it turn out in idiomatic LISP, of some 1.5 or later variant. And it would be interesting if the Haskell crowd took their own swing at it. And with your test harness, we could all verify that our versions have the correct behavior.

    I guess step one would be documenting the text file format, which describes all the rooms and the connections between rooms, and the actions and objects in and on each room.

    Question 1: can clarity be improved without increasing line count by using a LISP or a Haskell/ML.

    Question 2: can line count be reduced by using a LISP or Haskell/ML, while increasing clarity.

  9. We had it on our PDP-10 at Ramada Inns Corporate Systems back in the ’70s, and it came from SAIL.

    We had to limit its use because it was chewing up so much machine time.

    The “maze of twisty little passages all alike” has been part of my vocabulary since then.

  10. > At the bottom of the very first page of Knuth’s magnificent Adventure-as-a-Literate-Program

    Wow Adam, good find. I only saw a few gotos in that. That is the first Literate Program more than 5 pages in length that I’ve read through. Amazing. Wish Literate Programming had taken off more.

  11. Do you have access (and rights) to the pre-translated FORTRAN sources? In the interest of historical preservation, it might be nice to include an archive of the original code so the world can see it as it existed before the mechanical translation to C. I’m sure it’s available somewhere on the web, but since your repo is now the de facto home of ADVENT, it seems like a logical place to put it on display.

    1. >Do you have access (and rights) to the pre-translated FORTRAN sources?

      The FORTRAN for the 350-point version is at the Interactive Fiction Archive. I don’t know where the FORTRAN for the 430-point 2.5 can be found, or even if it still exists at all.

  12. As it should be.
    Tradition is not about guarding the cold ash, but about passing on the burning torch.

  13. > Tradition is not about guarding the cold ash, but about passing on the burning torch.

    Interesting way of putting it.

  14. This source code, it’s a maze of twisting little GOTOs, all different.

    For shits and giggles, I downloaded the source, compiled it and fed it to afl, along with a dictionary of commands pulled from the database, to see if afl could figure out how to play ADVENT in a similar manner to how it figured out how generate JPEG files. I’m not sure if doing this makes me a bad person, or just weird.

    Either way, I’m curious to see what happens once afl gets done with the first pass, and starts basing it’s tests on previous ones that did something interesting.

  15. Don’t need literate programming: just write the comments before writing the code. Top-down design iteration refines both comments and code. End result is a complete working program that anyone with either the source code or comments can understand.

    Talking about spaghetti code, IBM wrote some doozies in the day. Converting the gotos into structured code revealed some subtle bugs, I can tell you.

  16. >one of Crowther & Woods’s original goals – thwarting attempts to get around obstacles in the game with any investment less than quitting and playing again

    Why did they have a goal like this? What is the use in frustrating players? There is an almost linear change through the paste decades of videogames becoming less and less punishing. Not necessarily meaning less difficult i.e. the player less likely to screw up, just less consequences to screw-ups. Recently, you don’t even have to save as it autosaves at checkpoints.

    I sort of agree that your character dying should matter, it makes things feel more serious, unconsequential deaths that result just in restarting from the checkpoint five minutes ago are less immersive. This is why lately there are mods with permadeath, like The Journey for Skyrim and perhaps it is coming back in original games as well.

    But early 1980’s games were pretty sadistic and making the player replay everything at the smallest mistake and it seems it may have originated here.

    I thought back then the fledling game industry did not know better. But it turns out it was a conscious goal?

  17. I think death-means-you-start-the-game-over is a good dynamic when gameplay is suitably randomized so that getting back to the point where you died is just as much of a challenge as it was the previous time through. Nethack is a good example of this. But ADVENT is deterministic (except for the movement of the dwarves IIRC, which is a trivial detail); starting over to recover from a mistake is nothing but an annoying finger exercise.

  18. Was gonna say – testing in light of dwarf randomness will be a pain.

    Only a slight pain, though. One of the great things about ADVENT is that you can invoke it as

    advent < cmds.txt

    I miss text adventures sometimes.

    1. >Was gonna say – testing in light of dwarf randomness will be a pain.

      I’m working that problem now. The answer is to add a “seed” command to set the PRNG seed, than when a game is initially logged have it generate a seed command into the log.

      Well, that’s the theory. Presently something is buggy and dwarf appearances don’t reproduce yet. I’ll figure it out.

  19. > (Which, alas, is extremely ugly code full of gotos.)

    Is there any known history of velociraptor attacks associated with ADVENT?

  20. > I think death-means-you-start-the-game-over is a good dynamic when gameplay is suitably randomized so that getting back to the point where you died is just as much of a challenge as it was the previous time through.

    I don’t think it is, necessarily. If there’s any sort of scaling difficulty, then if you die 75% of the way through the game, then you’re clearly good enough to get there, and the first 25, 50, whatever percentage short of 75% sounds right, is just a tedious make-work obstacle in the way of being allowed to increase your skill by practicing at the level of the part that you died on, even if you can’t turn your brain completely off for it as you could with a deterministic game.

    Or, if the structure of the game is that there are multiple “difficult parts”, some earlier, and some later, then it becomes a question of whether if you’re only skilled enough to pass them, say, 30% of the time rather than 100% (your odds of passing the first two is therefore 9%, first three 2.7%, etc), whether you should be entitled to see the later parts of the game at all on the strength of each of those “lucky passes”.

    I think that it’s partly an artifact of timesharing vs individual computers and game consoles. Open source aside (and, even with access to the source, it could still be enforced if they don’t have the means to compile and run their own version and the system-provided version won’t let them load their modified save files), a culture that only people who are truly elite are “allowed into the club” and the implementors and sysadmins are tasked with enforcing this, becomes less tolerable when you paid $60 for the whole game and won’t get $30 back when you find you can only reliably reach the halfway point.

    I think this is why at the other extreme there are games where you don’t need any skill at all – in the latest Mario games, if you die enough times, the game will let you simply skip that section or watch the computer play it for you, because you (or your parents – the option is, I suspect, intended for small children) paid for it and therefore have the ‘right’ to see the whole story (so far as there is a story) and end credits if you want to. Nothing but your pride forces you to try over and over to get past that one level.

  21. Taking a quick glance at that code, I have to wonder just how much simpler ADVENT could be if it were reimplemented in Perl or Python.

    1. I guess once the source is cleaned up into idiomatic modern C, you could machine-translate it into Python and start from there…

      :)))

  22. >I think that it’s partly an artifact of timesharing vs individual computers and game consoles.

    I think a lot of it is an artifact of arcade games.

  23. >Taking a quick glance at that code, I have to wonder just how much simpler ADVENT could be if it were reimplemented in Perl or Python.

    I decided to set this (Python) as a goal for myself after reading the original post back on the 22nd. It will undoubtedly take me quite some time but I’ve wanted to create my own text adventure for awhile. What better place to start than sorting through the nuts and bolts of the original.

    I could have sworn I’d played completely through ADVENT a few times years ago, but yesterday I realized that Zork must have confabulated into ADVENT. I’m playing through it now for apparently the first time and the urge to look up a walkthrough is driving me crazy.

  24. I hope strongly that you would not introduce autotools into the build process of Advent.

    Currently reading through git repo for SST, so I was surprised, at first, when I encountered merge of autotools suite.

    c 7465 (53.98%) in 11 files
    shell 4016 (29.04%) in 8 files
    m4 2275 (16.45%) in 29 files
    autotools 72 (0.52%) in 4 files

    This is horrifying.

    1. >I hope strongly that you would not introduce autotools into the build process of Advent.

      Will never happen, I hate autotools.

      Ignore the SST C code, it’s only there for historical reference. The Python translation has been the actively developed version for years.

  25. … And short look at the result of running autogen.sh and ./configure produce config.h with a bunch of defines that aren’t ever used anywhere else.
    What’s the point? What’s the point of… that???

    What’s worse, it’s useless. Trying to build C version of super-star-trek on a system with no python (just python2 and python3, not symlinked to $PATH/python) causes it to fail. And there’s no need for python to build historic C version. Not a line of python used.
    It’s like appendix ready to burst…

  26. > I’m playing through it now for apparently the first time and the urge to look up a walkthrough is driving me crazy.

    You and me both. I’m mostly resisting the urge, though I have succumbed to the temptation of hints offered in-game a couple times. Grabbing a walkthrough would be the easy way to go, but would be cheating myself of the satisfaction of figuring out how to get past an obstacle (e.g. chasm in the hall of mists). I am however very seriously considering getting out some graph paper and drawing maps as I go. I’m not sure I should consider putting the map down on paper instead of trying to keep it in my head cheating. I’m pretty sure more that a few people who’ve played before drew their own maps, in which case, I’d not be cheating any more than any other person has cheated.

    1. > I’m pretty sure more that a few people who’ve played before drew their own maps, in which case, I’d not be cheating any more than any other person has cheated.

      I’m pretty sure everyone who has ever played this game seriously has drawn maps. Also that nobody considers this cheating.

  27. > Taking a quick glance at that code, I have to wonder just how much simpler ADVENT
    > could be if it were reimplemented in Perl or Python.

    I have to wonder how much simpler the TOPS-10 System could be if it were reimplemented in Perl or Python.

  28. I’m pretty sure everyone who has ever played this game seriously has drawn maps. Also that nobody considers this cheating.

    Possibly relevant test: could the actual adventurer do it?

    The adventurer could easily make a map as he is going along. The adventurer is highly unlikely to have ontotech available.

  29. I am not sure that I understand the purpose of converting to C (or then cleaning it up). Unless you are planning to add features, surely you’d be better off starting with the original FORTRAN code and patching GCC to be able to compile it?

    If you are working for preservation then presumably anything other than the original source code is sacrilege. If you are reimplementing it in a more modern language, then you would probably be better off with a complete rewrite to C++ or Python.

    Either way, I’ll give it a whirl when it’s packaged :)

    1. >I am not sure that I understand the purpose of converting to C (or then cleaning it up). Unless you are planning to add features, surely you’d be better off starting with the original FORTRAN code and patching GCC to be able to compile it?

      Adventure 2.5 didn’t exist as FORTRAN code. Don Woods translated it to C with a custom converter before it got to me. The distribution contained a comment apologizing for the poor quality of the resulting code.

      Here are the features we have already added:

      A “seed” command has been added. This is not intended for human use but as a way for game logs to set the PRNG (pseudorandom-number generator) so that random events (dwarf & pirate appearances, the bird’s magic word) will be reproducible.

      A -l command-line option has been added. When this is given (with a file path argument) each command entered will be logged to the specified file. Additionally, a generated “seed” command will be put early in the file capturing the randomized start state of the PRNG so that replays of the log will be reproducible.

      Using “seed” and -l, the distribution now includes a regression-test suite for the game. Any log captured with -l (and thus containing a “seed” command) will replay reliably, including random events.

      The adventure.text file is no longer required at runtime. Instead, it is compiled at build time to a source module containing C structures, which is then linked to the advent binary.

      >If you are working for preservation then presumably anything other than the original source code is sacrilege.

      I reject the premise. We best honor the work of the hackers of the past not by treating it as a dead museum exhibit, but as a living tradition which is ours to extend in the same spirit of invention and playfulness. Besides, there’s version control. If you want the pristine source, check out the base revision.

      >If you are reimplementing it in a more modern language, then you would probably be better off with a complete rewrite to C++ or Python.

      That may come, eventually. But it is notoriously difficult to perfectly preserve behavior in a clean-sheet rewrite. Better to get it to clear and readable C from which it could be translated to a more modern language; Go would be a fine candidate.

  30. Random Observer, 2017-05-24:

    Taking a quick glance at that code, I have to wonder just how much simpler ADVENT could be if it were reimplemented in Perl or Python.

    The 350-point FORTRAN code has been translated to Python 3, and is maintained by Brandon Rhodes as ‘python-adventure’.

    Complete with ALL UPPERCASE OUTPUT, and “traditional mode” that emits output at 1200 baud. For verisimilitude.

    1. >Did all of the copyright holders agree to the relicensing?

      Both of them, yes. Don reported that Will raised one technical question about whether 3-clause BSD might be better, but they agreed to 2-clause.

    1. >Some discussion of the copyright status:

      I added a comment. It is probably true that the U.S. adoption of the Berne Convention bwtween 1.0 and 2.5 makes a difference to the copyright status.

  31. TOPS-10, the OS, was the source of the six character file name restriction, not PDP-10, the ISA. (IIRC, the restriction was not only six characters, but chosen from DEC’s “sixbit” character set, so a file name fit in one 36 bit word. https://en.wikipedia.org/wiki/Six-bit_character_code )

    That said, are we sure that adventure was developed on TOPS-10 machines? There were at least three other OS running on PDP-10s at about that time, Tenex (from BBN?), ITS (MIT), and I’m blanking on what Stanford’s AI lab used.

  32. Anyway to get the initial commit? I.E. the pristene code before people started working on it. I only see v 1, and v .90, both which have been worked on recently

    Thank you

    Lonnie

Leave a Reply to Slacker Cancel reply

Your email address will not be published. Required fields are marked *