Forest edge
Paths lead into the forest to the west and northwest. Also, a well-marked path extends east.
> go west
Forest
This is a dimly lit forest, with large trees all around.
> go west
Behind House
> enter the white house
Kitchen
> go west
Living Room
> open the coffin
The gold coffin opens. A sceptre, possibly that of ancient Egypt itself, is in the coffin. The sceptre is ornamented with jewels.
> take the sceptre
Taken.
> put the gold coffin in the trophy case
Done.
> go east
> go east
> go east
> go east
And that is the power of prayer right there: it teleports you to the forest with the gold coffin. (It also stops the trap door from shutting behind you from now on, which is very handy.) In unrelated news, I have always wondered why the authors of Zork chose the British spelling of sceptre instead of the more common in the United States spelling "scepter". Perhaps because it seems more archaic? A nice touch.
We've decoded the major data structures - or, at least, gotten a start on them. There's rather a lot more to do with objects, but we'll come back to that later. Let's really get into the heart of the story file now: the code.
Every instruction in the Z-machine instruction set has the same parts:
- An opcode, which gives the fundamental purpose of the instruction
- Between 0 and 7 operands
Many instructions have in addition:
- a conditional branch target
- where to store the result computed
and two instructions are followed by zstring-encoded text.
It is pretty clear that this instruction set was designed for concision in common cases, but it is still pretty easy to understand.
Over the next few episodes I'm going to quote from the Z-machine specification and show what code I wrote to implement each bit of the spec. Before we get into that though, a subtle but extremely interesting feature of OCaml that I have not yet discussed.
I want my instruction decoding function to have the following header:
let decode story (Instruction address) =
Of course I have created yet another wrapper type around integers, this one representing "I have a pointer to an instruction". I am going to have to be reading a lot of bytes out of the story in this very long, complicated method. I think it is a bit silly to have to write
Story.read_byte story addr
every time. OCaml lets me do this inside the decode function:
let read_byte = Story.read_byte story in
Examine that carefully. Doesn't read_byte take two operands, a story and an address? It looks like we have only partially applied arguments to the function here!
Well" yes and no.
I have misled you when I said that we were defining functions that take some number of operands. In fact, all functions in OCaml take exactly one value as a parameter, and return exactly one value as a result. (Assuming that they return at all; a function could of course simply failwith.) When you say
let adder a b = a + b
this is just a short way of writing
let adder a = let nested_function b = a + b in nested_function
In fact there is an even shorter syntax for that which I have not yet mentioned; OCaml supports lambda expressions, the same as C#. It would be more accurate to say that this is the same as:
let adder a = fun b -> a + b
Or, as a commenter points out, we can go even farther:
let adder = fun a -> fun b -> a + b
What does adder 1 give you? It gives you back a function which takes an argument, names it b, adds 1 to it, and returns the result.
In C# we would say
Func<int, int> Adder(int a) { return b => a + b; }
or in C# 6:
Func<int, int> Adder(int a) => b => a + b;
Or go full lambda:
Func<int, Func<int, int>> adder = a => b => a + b;
Note how much more concise OCaml is in all forms. Type inference for the win!
So anyways, we are perfectly within our right to partially apply the Story.read_byte method with one argument; that will give us back what is logically a nested function closed over that argument. Now we can read bytes without specifying what story to read from; the function already knows.
I think that's enough for today. Next time on FAIC: we'll actually get started on decoding instructions.