Beyond Zork Random Room Connections

So I want to have a game where certain regions have random room connections (such as in beyond zork). A given region (let’s say the desert) would have 10 differently named rooms, and the first room would connect to one region, and the last room would connect out to another region, but inside the region would have random connections.

How do I do this with the following criteria:

  1. the room exits change on each playthrough (you don’t always just keep going west to get to the ending)
  2. the rooms may have more than one exit, but not necessarily (meaning sometimes you can go in a whole circle, sometimes you don’t)
  3. The last room’s exit to the new region must always be the same direction, like the first room’s exit to the old region must always be the same direction, though those two rooms need not be the same rooms each time.

Basically the same way that beyond zork does it.

Ideally, the actual randomization will happen when first entering the region (so if you restore your game to before you entered the region the region would be re-randomized).

I’ve been wanting to play with BZ-style randomized zones as well; I banged my head against it for a few weeks once but never got anywhere :confused: (The Recipe Book has that honeycomb example which is quite nice, but it’s a very different thing, alas)

Do you guys think this might help at all?

Sorry if I can’t respond and this is a bit rushed, but I was curious myself, and this might be a good start.

Obviously not all the rooms are randomized, but I bet the program could be tweaked e.g. have a bunch of second-rooms room 2 in the table, then have a random row with room 2’s 2nd location turned to room 3, and so forth. That might be in another table…

…or you might be able to define a region and define each room as “sorted” or “unsorted” and say each region has a boss room. Each second-room entry of the table is a boss room–one that, say, leads to another region.

Then running through the regions, for each row with a second-room of boss room, let its second-room be a random unsorted room in region X. Now the second-room is sorted.

Hope this makes some sort of sense.
randomdir.txt (3.41 KB)

I had something similar that worked, but I don’t remember what I did - it became an abandoned idea. I’ll dig through my files and see if I can find it - it was quite a while ago.

As I recall, BZ obeyed a grid constraint for its randomized sections. This makes things easier.

I’d do it roughly like this:

have a 5x5 array, empty;
put a room in the middle;
repeat until five rooms exist:
    pick a random room X;
    pick a random direction D (n/s/e/w/ne/se/nw/sw);
    look at the location Y which is D from X;
    if it's outside the grid, restart loop;
    if Y is occupied by a room, add an exit from X to Y (if there isn't one) and restart the loop;
    otherwise add a room at Y, add an exit;
add an exterior exit east from the easternmost room (or a random one);
add an exterior exit west from the westernmost room (or a random one).

I had so much fun with this problem that I think I’ve worked out a complete solution:

[code]Shore is a room.

Oasis is a room.

The player carries a first marker, a second marker, and a third marker.

A maze is a kind of room.

A maze-region is a kind of region. A maze-region has a text called the room description. A maze-region has room called the entrance. A maze-region has a room called the exit. A maze-region has a direction called the way in. A maze-region has a number called the connectivity. The connectivity of a maze-region is usually 3.

The Desert is a maze-region. There are ten mazes in the desert. The entrance of the desert is Shore. The exit of the desert is Oasis. The way in of the desert is west. The room description of the desert is “You are in a desert. Dunes allow passage to [the list of viable directions].”

When play begins:
Repeat with area running through maze-regions:
Repeat with place running through mazes in area:
Now the description of place is the room description of area;
Now the printed name of place is the printed name of area;

Definition: A direction is horizontal if it is not up and it is not down and it is not inside and it is not outside.

Definition: a room (called place) is connected rather than unconnected:
Repeat with way running through directions:
If the room way from place is a room, yes;

Connection availability relates a direction (called way) to a room (called origin) when the room way from origin is nothing. The verb to be unused from implies the connection availability relation.

Definition: a direction (called way) is viable if it is not unused from the location.

Maze entry relates a room (called origin) to a maze-region (called area) when origin is the entrance of area. The verb to be the starting point of implies the maze entry relation

Before going nowhere from a room that is the starting point of a maze-region (called area):
if the noun is not the way in of area, continue the action;
Let last-step be a random unconnected maze in area;
Link last-step symmetrically to the exit of area via the way in of area;
Let origin be the entrance of area;
Let way be the way in of area;
While there is an unconnected maze (called destination) in area:
Link origin symmetrically to destination via way;
Now way is a random connection from origin to destination;
Now origin is destination;
Link origin symmetrically to last-step via a random connection from origin to last-step;
[This makes a single path from the entrance to the exit. It may be twisty, but it’s not really a maze.
But you can use a the same phrases to add additional random connections, e.g.:]
Repeat with N running from 1 to the connectivity of area:
Now origin is a random maze in area;
Now destination is a random maze in area;
Let way be a random connection from origin to destination;
If way is a direction, link origin symmetrically to destination via way.

To decide which object is a random connection from (origin - a room) to (destination - a room):
Let choices be 0;
Repeat with way running through horizontal directions that are unused from origin:
If the opposite of way is unused from destination, increment choices;
Let N be a random number from 1 to choices;
Repeat with way running through horizontal directions that are unused from origin:
if the opposite of way is unused from destination, decrement N;
if N is 0, decide on way;
[We should never get here during the creation of the “correct path.”]
decide on nothing;

To link (origin - a room) symmetrically to (destination - a room) via (way - a direction):
link origin one way to destination via way;
link destination one way to origin via the opposite of way;

To link (origin - a room) one way to (destination - a room) via (way - a direction):
If way is:
– north: now destination is mapped north of origin;
– northwest: now destination is mapped northwest of origin;
– west: now destination is mapped west of origin;
– southwest: now destination is mapped southwest of origin;
– south: now destination is mapped south of origin;
– southeast: now destination is mapped southeast of origin;
– east: now destination is mapped east of origin;
– northeast: now destination is mapped northeast of origin;
– down: now destination is mapped below origin;
– up: now destination is mapped above origin;
– inside: now destination is mapped inside origin;
– outside: now destination is mapped outside origin;

test me with “w”

You can see there are a couple of ugly hacks:

  1. It seems that it’s not possible to use a variable in the “now X is mapped Y of Z” phrase. [rant]In addition, I couldn’t come up with any legal way to say “Now X is mapped inside/outside of Z.” edit: Thanks for the answer, Felix.[/rant]

  2. I couldn’t come up with a legal phrase meaning “a random horizontal direction that is unused from A and is the opposite of a horizontal direction that is unused from B.” Which is why I wrote the crazy loop over N instead.

My knowledge of graph theory is sketchy, but I think my algorithm is sound and covers all cases. Of course I spent so long on this that Zarf came up with a much simpler solution. Using real geometry seems like a smart way to solve the problem.

One question: does the random number seed get saved as well when you save the game? If so, then last-minute calculations may be pointless.

The required syntax, I believe, is now X is mapped outside Z without the “of”—similarly for all the non-compass compass directions: above, below, inside, and outside.


Is there a way to fake this? For instance, is there a way to find out what the seed is, write it to an external file associated with the saved game, and then read it back after restoring and seed the random-number generator with it (as per WI 8.18)?

EDIT: In this case we don’t want to save the seed; I’m just asking in case you want to save the random seed for some reason – like using the seed to re-generate something the same way each time, without needing to store the stuff in memory. (Which I think zarf has done in one of his games, unless I misunderstood what he was saying about it.)

Glulx doesn’t let you get the current seed, but it does let you set one. So you could take the first random value, save that, and then set it as the seed. It’s probably dubious in theory to reseed a random-number generator with its own output, but since we aren’t doing cryptography it’s unlikely to matter.

This would only let you recreate the same sequence of numbers as long as the same interpreter was used, because the spec doesn’t define a particular algorithm. To do it reliably across interpreters you’d want to ignore the inbuilt RNG and use your own.

djfletch is correct.

What I was doing in the game you’re thinking of (Hunter in Darkness) was using an algorithm to repeatably generate text from a seed value. But it wasn’t an randomly-generated seed value; it was fixed. The whole point of that code was to not use the VM’s random number generator at all.

I’m starting to wonder if the only way to really do this is to have 5 or 6 different “maps” of a given region, and have it choose one of those maps at random when you first enter the area…

Is there any way to break into the beyond zork code and see how infocom did it?

Why is that? Zarf’s grid solution seemed to me like it would work perfectly.

I’d love to see the reverse engineering for that. And, since I’m greedy, Double Fanucci in Zork Zero :slight_smile: – if anyone super talented in that sort of thing has/finds the z-machine specs and/or a lot of time, that could be really cool. The maps (more practically) or (cause I’m insanely curious about silly things) Double Fanucci.

Still, I don’t know–maybe you can play a little number magic. You could have 4 rooms in a 3x3 box. They are placed at random, and any room adjacent or diagonal to another is connected to that room. Maybe you could refine that and allow for a dead end or two if you’re careful.

Then you could have, say,

–the southwesternmost room has a passage south to a non-random area

–the northeasternmost room has a passage east to a non-random area.

This’d roughly conform to Zork’s having 4 random areas (I think?) though it wouldn’t be as spread out, and the possibilities might not be exciting.

This seems a lot less elegant than Zarf’s idea–and probably owes more to it than I thought at first glance–and a lot less generalizable. But it seems doable without too much problems. It looks like there’s a tradeoff between immediate usability and generalizability–at my level at least.

Whatever the ideal solution is, it’s interesting to see others’ approaches. I always wondered how they did this as a kid.

The disassembler tools at … tools.html work on Beyond Zork. However, grokking Z-machine assembly is more work than writing your own implementation from scratch, in all likelihood.

If you really want to replicate BZ behavior exactly, you’d probably do better to run the game over and over again until you understand what the algorithm does by demonstration.