Wednesday 30 July 2014

Summer Retrochallenge 3: Techniques for "Shoehorning" Classic IF into the MC-10

One of the things I’ve enjoyed doing with the MC-10 is converting a bunch of classic interactive fiction (IF) games to run on it. I’ve described elsewhere the speedy 4 line word wrap routine I developed to facilitate this process. It completely frees one from one of the most tedious aspects of converting text message intensive programs, such as IF games, which is formatting text string output. It can also save memory by eliminating redundant white spaces often used to accomplish this task. However, one of the other hurdles of converting IF programs is how to accommodate the large amounts of data, such as text strings, and also numeric data, that such programs typically include. I want to share two techniques I have developed that have allowed me to port some classic IF programs, which were developed on machines with more than 16K, such as memory enhanced versions of the TRS-80 Model 1, 48K Atari, or the C64. Using these techniques I have been able to squeeze these games into the more constricted 20K memory space of the MC-10

Lots of DATA
The first technique is to remove the largest sequence of DATA statements that are read into a numeric array and replace this with reading a file from cassette directly into the array. This technique uses a command that as far as I am aware is completely unique to MC-10/Alice Basic: CLOAD*VARNAM, “FILENAME”.  This command can be used to easily read any numeric array from tape (or disk file when using the VMC-10 emulator).  This technique can save large amounts of memory because it eliminates all the redundant DATA statements, which play no role in a program once their information has been transferred into an array using the READ command.  In other words, it prevents the numeric data from having to be held in two places in memory at once--array variable memory space and as DATA statements in the program listing itself.  Since this special command can only be used with numeric arrays and not string arrays it can only be used to help remove redundant numeric data.  However, I have found that many IF programs, especially those of the classic IF author Scott Adams, typically use large amounts of numeric data to encode the complex movements between locations, so this technique can still be very helpful.

Dr. Who
In some cases, such as in my recent port of “Dr. Who,” I was able to combine various different arrays into one, and then use offsets for the added arrays.  For example I could take arrays A(10), B(10), C(10) and turn them into the single array A(N), A(10+N), A(20+N).  Such a process is not as tedious or time consuming as you might think, as you can simply use the Search and Replace function of your text editor to change the names of the added arrays and add the necessary offset number.  For instance, in the above all, I would have to do is search for all instances of “B(“ and replace these with “A(10+”.  By doing such combining, you can keep the extra file load to one instance at the start of the program.  One of my large IF games will therefore typically have two files such as PIRATE1 and PIRATE2 (Scott Adams' second adventure). You can see below that after running the program file PIRATE1 the user is prompted to load “the second part” consisting of the file “PIRTATE2”.

PIRATE1 and PIRATE2
The second technique I have developed allows me to deal with the redundancy of reading a large number of text strings from DATA statements into text arrays.  Again this leads to the information being stored in two places in memory at once (the DATA statements and the space reserved for the text array variable).  What I do is to change a specific long sequence of such strings to a “read on demand” sequence of DATA statements.  When any specific string is needed, you simply call a subroutine that uses the RESTORE command to reset the READ command to start from the beginning of the DATA statements and then READ into a single variable as many times necessary to get to the desired text string. This sometimes requires rearranging the DATA statements so that the sequence of strings is at the front of the list of all DATA statements. This is necessary because Micro Color Basic's RESTORE command doesn’t allow you to select the program line you want to the data pointer to be set to. There is a little sacrifice of display speed using this method, but this is partly offset by the fact that the MC-10’s Basic is a little speedier than many other Basics. Also, you can use the other speed techniques I have discussed elsewhere, such as using single character variable names that are declared first in the list of variables for doing the work of such a subroutine.  Also, you must remember to do a “dummy run” for the entire list of strings at program startup so that any additional  DATA statements can be read and stored as usual.

Using these techniques I have been able to shoehorn a number of classic programs into the 20K of my favourite little 8-bit machine:
Scott Adams
David Malmberg
Tim Hartnell
James Smith
The following is an MSWord VisualBasic macro that I use to search for PRINT statements and replace them with the assignment of the string to the variable M$ followed by a call to my Word Wrap routine (GOSUB1):

Sub Macro3()
'
' Macro3 Macro
'
'
    Selection.Find.ClearFormatting
    With Selection.Find
        .Text = "print"""
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.TypeText Text:="M$="""
    Selection.Find.ClearFormatting
    With Selection.Find
        .Text = """"
        .Replacement.Text = ""
        .Forward = True
        .Wrap = wdFindContinue
        .Format = False
        .MatchCase = False
        .MatchWholeWord = False
        .MatchWildcards = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
    End With
    Selection.Find.Execute
    Selection.MoveRight Unit:=wdCharacter, Count:=1
    Selection.TypeText Text:=":GOSUB1"
End Sub

No comments:

Post a Comment