We're still doing the weekly Friday Afternoon Hacks at The Hub Halifax. In my previous blog post, I talked about how I was going to finally catch up with my 12-year-old self and type in a BASIC adventure game program from 1983.
A surprising number of friends emailed me after the last post, saying they remember that book, and that they had never managed to type in the program either.
It's certainly not the best text-based adventure ever, but it's surprisingly more interesting to play than I expected. You'll notice that you can get stuck in the Marsh and then can't do anything - there's no Quit command, but just click on the "STOP" button on the web page. If you don't know what to do, type HELP to get a list of commands.
Typing this in was a bit of a challenge. The source code in the book looks like it was taken directly from a dot-matrix printout of the real application code - quirky line numbers and all. The program uses $O and $D as variable names - It's still a bad idea, but it was especially a bad idea back when fonts were blurry and blocky and hard to tell apart.
Also I can't imagine what it would have been like typing this program in with the rudimentary editors available in 1983. Copying and pasting repetitive code, doing bulk search and replace, using version control, even simply being able to save my progress in a fraction of a second - these are all things I take for granted now that really didn't exist on the original vintage computers of the early 80s.
Now that the BASIC version works, I'm going to be rewriting it in as many platforms and technologies as I can. First up, to keep things simple, I'm rewriting this in Ruby, running on the command line with standard I/O.
I thought I would take one pass through transliterating the code from BASIC to Ruby as closely as possible, and then rewrite it using Ruby features and idioms. Unfortunately, the original BASIC approach used GOTOs and GOSUBs everywhere, which is a 'feature' that thankfully hasn't been implemented like that in Ruby. Here's the heart of the program's command parser, for example:
460 ON VB GOSUB 500,570,640,640,640,640,640,640,640,980,980,1030,1070,1140,1180,1220,1250,1300,1340,1380,1400,1430,1460,1490,1510,1590Pretty sexy, eh? I'm still going to write this in Ruby twice, but in a different way.
The BASIC program mushes all of the components together: the main event loop, the locations, the allowable words and what they do, how magic items work, scoring - everything. The data is stored in a set of parallel arrays that aren't otherwise linked together. The parsing, as you can see above, depends entirely on jumping to line number references.
The first Ruby version will store the data and handle events in roughly the same way as the BASIC program. The second Ruby version will try to be as open as possible. The core application will be an event loop and a set of frameworks for managing locations and setting up data, and the data and vocabulary will be set up as a set of configuration files. That way, the game can be modified by simply changing these configuration files. If I was working in Java, I'd probably do these in XML - but for this I'll use actual Ruby files with arrays and hashes.
Some of the items or actions in the game have special behaviours - such as changing the exits in a specific room, or teleporting you to a random location. If I was doing this in Java and setting up the configuration in XML files, I'd have to plan ahead and have configuration parameters for every possible special case. With Ruby, since the configuration files are in Ruby, and since code can be passed around just like data, I can include code blocks directly in the configuration elements.
Even though I've been using Ruby and Rails for several years, I really haven't explored this whole passing code blocks things very thoroughly - so this should be a fun exercise. I figure this will also help get me ready for when I write this in LISP.