Here's a first draft of a TAS of Zork I for Apple II. It uses revision 88 of the game, which, according to
a survey by Data Driven Gamer, is "by far the most widely distributed version". The total time is 18871 frames or 5:14.52, in 258 moves.
User movie #638893574504520990
Link to video
(Since this TAS is for Apple II, I debated about whether to add it to this thread here in the
MS-DOS Games forum or start a new thread in the
Other Computers forum. I decided it's probably better to keep all the discussion for the game in one thread, even if it's a multi-platform game.)
You may have seen that I've been working on
scripting TASes with Lua and that I used the technique to
improve the "fastest eaten by a grue" TAS. This is a straightforward extension to the full game. I didn't do independent route research for this run; instead I implemented
Gym Slow's RTA route, unmodified except for a
SUPER command at the beginning to activate
superbrief mode. There are various small changes that would make the run faster taking the Apple II platform into account, as well as potential larger route changes taking advantage of the RNG manipulation that is possible in a TAS. I haven't done any of those. My idea was to let this run serve as a baseline to compare future improvements against.
The run being scripted in Lua (actually
Fennel) means that there is a script (
100%.fnl) that contains a lot of code like this:
;; "80-COLUMN DISPLAY? (Y/N)"
(enter-text "n")
;; Skip over some loading. Get to somewhere near the first input prompt.
(savestate.next-frame 300)
(enter-commands ["super"])
(wait-for-keyboard-ready)
(savestate.next-frame 1) ;; RNG manipulation (avoid songbird).
; TODO use Shift or other keys for RNG manipulation.
;; Enter the schedule of commands.
;; TODO joining with "." can save time and alter RNG.
(enter-commands
[
;; Climb the tree, get egg, and climb down again.
"n"
"n"
"u"
"get egg"
"d"
;; Enter the house.
"s"
"e"
"open"
;; ...
])
You can modify the run by modifying the script and re-running it in BizHawk. However, even small changes will require re-syncing RNG. I haven't done anything yet to automate RNG manipulation, which is needed to avoid unwanted random encounters, win combat quickly, and prevent certain other random events. I implemented RNG manipulation in this run by inserting 1-frame delays, though I think there are better ways to do it. You can see one instance of RNG manipulation in the snippet above, the
(savestate.next-frame 1). More about RNG below.
Other notes on this run and thoughts on possible improvements:
40-column mode vs. 80-column mode. The first thing the game does is offer a choice between 40-column mode and 80-column mode. 80-column mode looks nice: it has more text on the screen and uses both upper- and lowercase letters. I did a quick test of commands up to collecting the sword and lamp in the living room; it was 1279 frames in 40-column mode and 1341 frames in 80-column mode. So I guess 40-column mode is generally faster. But the choice of 40 or 80 columns could be considered a speed/entertainment tradeoff. Ultimately, I'd like to make the control script adaptively manipulate RNG, such that the run can be played back in either mode.
Brief versus verbose. Besides the default verbose mode, the game offers a
brief mode (which only shows you the long description of a room the first time you enter it, and a short description thereafter) and a
superbrief mode (which always shows you the short description). Superbrief obviously saves time, as screen output on the Apple II is less than instant. Like the number of columns, the level of output verbosity could be considered a speed/entertainment tradeoff. (And similarly, any change will require re-synchronizing RNG.)
RNG. Speaking of RNG, the good and bad news is that the RNG in the Apple II version is very sensitive, changing with granularity smaller than a frame. I suspect (but have not confirmed) the Apple II port of Zork uses the built-in
KEYIN random number generator, which simply rapidly increments a 16-bit number whenever waiting for keyboard input. This is good in the sense that, in principle, you can probably get any RNG output you need with less than a frame of waiting. It's bad in that it's hostile to console verification, and the Virtu core doesn't provide easy access to sub-frame inputs, as far as I know. In this run, I've done RNG manipulation by manually inserting frame delays. But I also experimented with toggling the Shift key while entering commands, and that alone seems to change the CPU cycles enough to affect RNG. I think it should be possible to eventually do such RNG manipulation automatically, using the script, but it will require more work to understand the game's memory layout, in order to read the results of commands.
You can see a listing of the part of the ROM that increments the 16-bit random number in the
technical reference manual:
C83B:E6 4E 57 GETKEY INC RNDL ;BUMP RANDOM SEED
C83D:D0 02 C841 58 BNE GETK2
C83F:E6 4F 59 INC RNDH
C841:AD 00 C0 60 GETK2 LDA KBD ;KEYPRESS?
C844:10 F4 C83B 61 BPL GETKEY ;=>NOPE
C846:8D 10 C0 62 STA KBDSTRB ;CLEAR STROBE
C849:60 63 RTS
Connecting commands with dots. It's possible to enter multiple commands at once, separated by periods. This capability is
given in the manual. (c-square, your
N,N,U,GET EGG,D in
Post #476712 would have worked if you used periods instead of commas.) It was the main trick used to speed up the
"fastest eaten by a grue" TAS, where it enabled ending input early. I didn't use this feature in this run, but I did a quick test, and to my dismay it appears that entering multiple commands on one line is slightly faster.
N.N.U.GET EGG.D was 1690 frames in my test, compared to 1709 frames with the commands on separate lines. I say "to my dismay" because this would be a pretty extreme speed/entertainment tradeoff, a small gain in speed for a large decrease in entertainment. It's nicer to watch a run where the results of commands are close to the commands that caused them, not separated from them by pages of scrolling. I'm tempted not to make use of this trick, except perhaps when traversing long distances, such as through the mazes.
Even if you were to enter every command of the run on one long line, it wouldn't allow ending input super early, because you would still have to press keys to scroll through all the
[MORE] prompts and get to the ending. I tried joining just the last few commands, and buffering a Space press to clear the final
[MORE] (as in
Post #536873), but it doesn't work in this full-game run: after winning, the game seems to clear the keyboard buffer, or something, such that you have to wait for the final
[MORE] to appear before you can dismiss it.
Two-part commands. The Gym Slow route occasionally splits one command into two parts, in order to reduce keystrokes. This is when you enter a partial command, then the game asks for clarification, and you enter the word that's missing. For example, the route uses
PUT SOLID and
CASE to put the ("solid") gold coffin in the trophy case, because that saves having to enter the word
IN:
>PUT SOLID
WHAT DO YOU WANT TO PUT THE SOLID IN?
>CASE
DONE.
This is good for an RTA run on a modern computer where the output is instantaneous, but on the Apple II it's probably better to spend some extra frames on input so the game doesn't have to emit so much output:
PUT SOLID IN CASE. (Incidentally, these two-part commands don't work when entered as a single line separated by a period: you can't do
PUT SOLID.CASE.)
A similar case is in the dam maintenance room, where this route does
PUSH ALL. There's only one thing in the room you need to push, but this command results in a screenful of output as you try to push every item (including the one you need to push). It may be faster to be more specific in the command so that there's less output.
Early thief kill? This route leaves the battle with the thief until near the end. But before that, there are two occasions where you enter the thief's hideout in order to warp to the temple; each of these displays a long message about the thief entering the room and requires RNG manipulation to avoid getting killed or wounded (which would reduce carrying capacity). It may be possible, with RNG manipulation, to kill the thief at the first encounter. This would ease the rest of the run, as there would be no need to worry about random thief encounters or combat in the hideout. I haven't yet checked to see how combat works in the source code.
It's conceivable that a route would call for getting robbed by the thief at a time when you're carrying lots of treasure far from the house, as that would effectively warp the treasure to be near the house, and free up your carrying capacity to pick up more items. I hope that's not required, because it would require careful manipulation. The thief's attack isn't a random probability per room; he actually physically moves around the cave at random. The route already uses the
"raft of holding" bug (bug #27 in Graeme Cree's list) for the hardest part of inventory weight management.
Vampire bat RNG manipulation? Normally, you're supposed to use the garlic to incapacitate the bat, which otherwise picks you up and drops you in a random place in the coal mine. It may be possible to instead allow the bat to grab you, and manipulate it to drop you deep in the mine, saving one of the traversals through the mine. (The current route traverses the mine a total of four times, twice heading in and twice heading out.) It's possible for the bat to drop you outside, in the squeaky room, so it wouldn't be necessary to have the garlic even on the way out.
Bypass torch/dumbwaiter puzzle? Bug #41 in Nathan Simpson's list says that you don't need the torch in order to get light into the drafty room past the coal mine. There's a trick where you can store the candles in the sack and still fit through the small opening. I don't think it would save a ton of time, because you'd still need to get to the end of the mine and back to put the coal in the dumbwaiter, but it could free up routing possibilities with regard to when the torch gets deposited in the trophy case. The page says it only works if you extinguish and re-light the candles, so it would require getting the matchbook from the dam lobby, which the route currently doesn't do.