Frotz and Bocfel can't parse PDP10 in V1/V2 Zork — a shift-lock (z machine spec 3.7.1) easter egg

I found this while building RustyGrue, a from-scratch Z-machine/Glulx interpreter in Rust. When my parser didn’t recognize a word I expected it to, I checked it against dfrotz and Bocfel, and discovered they don’t recognize it either. It turns out all three of us were wrong, and Infocom was right. I’m not sure if this has been talked about before on the forum (The Zork V1/V2 issue. I did find something on the forum about V3 Zork 1, which is a different issue) (let me know!), but here’s what I found.

Here’s what the easter egg looks like: In Zork I, the machine in the Machine Room, the coal-to-diamond contraption “shaped somewhat like a clothes dryer”, answers to the synonym PDP10. Infocom named it after the machine ZIL itself was compiled on. It’s not a throwaway response; it’s a full noun synonym, and you can solve the entire diamond puzzle without ever saying “machine”:

Machine Room
This is a large room which seems to be air-conditioned. In one corner there is a
machine (?) which is shaped somewhat like a clothes dryer. On the ‘panel’ there is
a switch which is labelled in a dialect of Swahili…

> examine pdp10
> The machine is closed.

> open pdp10
> The lid opens.

> put coal in pdp10
> Done.

> close pdp10
> The lid closes.

> turn switch with screwdriver
> The machine comes to life (figuratively) with a dazzling display of colored lights
> and bizarre noises. After a few moments, the excitement abates.

> open pdp10
> The lid opens, revealing a huge diamond.

> destroy pdp10
> What do you want to destroy the pdp10 with?

That last one is my favorite: the parser takes pdp10 as a noun phrase, echoes it back with an article, and asks for an instrument.

None of those commands works in dfrotz or Bocfel 2.4. On the V1 (zork1-r2) and V2 (zork1-r15) releases, both answer:

> open pdp10
> I don’t know the word ‘pdp10’.

The word is in the dictionary — entry #385 in both releases, a synonym of object #15, alongside dryer and lid.

Here’s the cause: In the spec section 3.7.1: “In Versions 1 and 2 only, when encoding text for dictionary words, shift-lock Z-characters 4 and 5 are used instead of the single-shift Z-characters 2 and 3 when the next two characters come from the same alphabet.”

ZILCH did exactly that. The real entries:

V1 zork1-r2 : 55 35 95 07 → z-chars [21, 9, 21, 5, 8, 7] p d p LOCK 1 0
V2 zork1-r15: 55 35 95 28 → z-chars [21, 9, 21, 5, 9, 8] p d p LOCK 1 0

Six Z-chars, end bit set, and correctly sorted. The shift-lock is what makes pdp10 fit: the adjacent 1 and 0 are both in A2, so one lock covers both. Encoding with single shifts instead needs seven Z-chars (p d p shift 1 shift 0), so it truncates at six, and it can never match. To type PDP10 at Zork you must implement section 3.7.1.

Bocfel derives its shift character as shiftbase = zversion <= 2 ? 1 : 3, which yields Z-chars 2/3 for V1/V2. It single shifts and never locks. I tried running Zork 1 through Frotz, and it also outputs “I don’t know the word ‘pdp10’”.

Note also that V1 and V2 encode the same word to different bytes — V1’s A2 alphabet row differs per section 3.5.4, putting 0 at A2 slot 7 — so a fix needs both the lock rule and the V1 alphabet row.

This doesn’t actually affect hardly anything. A Z-char 4 or 5 in the body of a V1/V2 entry is a lock, so you can count the affected words straight out of the story file. I checked the Zork I/II V1/V2 stories I have:

Zork I r2 (V1): 618 entries, 1 lock encoded (“pdp10”)

Zork I r15 (V2): 617 entries, 1 lock encoded (“pdp10”)

Zork II r7 (V2): 625 entries, 0 lock encoded

Words with an isolated A2 character (trap-door, h2o, the . sentence separator) are unaffected, because a single shift and a lock encode identically there. The rule only bites on two or more adjacent same-alphabet characters, and exactly one word qualifies.

It also only ever worked in V1/V2. By r88 (V3) shift-locks were gone from the format, ZILCH truncated pdp10 into a malformed entry with a dangling shift and no end bit, and every interpreter, including mine, correctly says it doesn’t know the word.

It’s a small thing, but it’s a clear sentence in the spec, the fix is a few lines, and there’s a fun result at the end of it.

6 Likes

Dang, I went a good 15 years before anybody called me out on this. I have a comment in Bocfel’s source about this, and it was always a lame comment that bothered me whenever I read it:

1.1 of the standard revises the encoding for V1 and V2 games. I am
not implementing the new rules for two basic reasons:

  1. It apparently only affects three (unnecessary) dictionary words in
    the known V1-2 games.
  2. Because of 1, it is not worth the effort to peek ahead and see
    what the next character is to determine whether to shift once or
    to lock.

Lame not least of which because it says two reasons but it’s clearly only one reason: I was too lazy to do it.

I suppose now I have to actually implement it!

4 Likes

Lol, sorry about that! It really is a super tiny issue, basically affecting one (or actually three you say? What are the other two words?) unimportant word in a couple versions of one Infocom game though!

Just wait until the PunyInform maintainers decide to add Z2 support!

6 Likes

According to the original 1.1 update doc: “nasty-” (looking), “storm-” (tossed)

And after posting this, I thought about it for a second and realized that of course those two words don’t fit the rule; they fit another rule in that same paragraph: “If the truncation to 6 Z-characters leaves a multi-Z-character construction incomplete, the end-bit of the last word is not set.”

My comment covered both rules, not just the shift locking one. I just had forgotten exactly what the original spec update said.

2 Likes

Both words are removed from the r88 (v3) source code. Presumably because ZILCH couldn’t compile them correctly – at least for a while – and the developers decided it was easier to drop those words than to fix the bug right away.

2 Likes

I also see that the official 1.1 standard doesn’t include the truncation rule that’s in ZSpec11.txt, and which affects these words. Seems the consensus has landed on this simply being a bug, as you note (and as ZSpec11.txt speculates), which is completely reasonable.

1 Like