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
> 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.
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.