Reservoir North

You are in a cavern to the north of what was formerly a lake. However, with the water level lowered, there is merely a shallow stream, easily. A slimy stairway climbs to the north.
There is a hand-held air pump here.

> take the pump

Taken.

> go south
> go south
> go east
> go down


The missing word “crossed” in the copy above is a bug in Mini-Zork. Obviously it is possible to get to Reservoir South before and after the lake is lowered; it is also possible to get to Reservoir North before the lake is lowered (by rubbing the magic mirror.) Both rooms share some logic for printing their description.

The Reservoir South logic is to first print “You are south of”, and then print either “a large lake, far too deep and wide to be”, or “what was formerly a lake. However, with the water level lowered, there is merely a shallow stream, easily”, and then finish up with “crossed. Paths lead east…” and so on.

The logic for Reservoir North is to first say “You are in a cavern to the north of “, and then either say “a large lake”, or the same alternative text as Reservoir South, followed by “. A slimy stairway climbs to the north.”

The right logic would have been for Reservoir north to also say “a large lake, far too deep and wide to be”, and finish with “crossed. A slimy stairway…”

I wonder if Zork proper has the same bug? If not, this bug was probably introduced when trimming the text down for the mini version of Zork.

Moving on.

Code for this episode is at https://github.com/ericlippert/flathead/tree/blog10

Last time we developed routines to give us all possible “next instructions” within a routine given an instruction. The time before that we developed a tool to take an item and a relation, and give us the reflexive and transitive closure of that relation. “All possible next instructions of a given instruction” is a relation; the transitive closure of that relation is all the instructions in a routine that can possibly be reached from a given instruction!

let all_reachable_addresses_in_routine story instr_address =
  let immediately_reachable_addresses address =
    let instr = Instruction.decode story address in
    let following = following_instruction instr in
    let branch = branch_target_instruction instr in
    let jump = jump_target_instruction instr in
    following @ branch @ jump in
  reflexive_closure instr_address immediately_reachable_addresses

This method takes the address of an instruction and produces a list of addresses of reachable instructions.

This seems like a good thing to apply our “accumulate a string from a list” helper to:

let display_reachable_instructions story address =
  let reachable = all_reachable_addresses_in_routine story address in
  let sorted = List.sort compare reachable in
  let to_string addr =
    let instr = Instruction.decode story addr in
    Instruction.display instr (Story.version story)  in
  accumulate_strings to_string sorted

To be perfectly honest I am not sure how the built-in comparison function I passed into List.sort works, since that thing is a list of wrapped instructions, not a list of integers. There’s some polymorphism going on here that I don’t quite understand. I’ll try to figure that out later. Regardless, we can now disassemble not just a single instruction, but an entire routine:

let () = 
  let story = Story.load "minizork.z3" in
  let text = Reachability.display_reachable_instructions story (Instruction 0x37d9) in
  Printf.printf "%s\n" text

And sure enough:

37d9: call 1d9b 3e88 ffff ->sp
37e2: storew sp 00 01
37e7: call 1d9b 4e50 28 ->sp
37ef: call 1d9b 4792 96 ->sp
37f7: store 10 2e
37fa: store 8a a7
37fd: store 36 01
3800: store 83 1e
3803: insert_obj g73 g00
3806: call 2c31 ->sp
380b: new_line
380c: call 30fa ->sp
3811: call 1c0d ->sp
3816: jump ffc2

Next time on FAIC: we’ll examine this routine; it has some unusual features.

3 thoughts on “Reservoir North

  1. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #2062

  2. The semantics of compare is described in (Comparisons section). It checks structural equality (I assume the order of constructor declaration is used) with the usual orderings of base types, but doesn’t work for functional values or cyclic structures. Note that trying to compare two values of different types is a compile-time error.

Leave a comment