Apple I Replica Creation -- Chapter 5: Programming in BASIC

 
Chapter 5
Programming in BASIC


Introduction


As its name suggests, Beginner's All-Purpose Symbolic Instruction Code (BASIC) is a great high-level programming language for beginners. BASIC was developed at Dartmouth College in 1964 and became the dominant programming language on microcomputers in the 1970s and '80s. If you visit your local library, you'll probably find dozens of books devoted to programming in BASIC, whether for the Apple II, Commodore 64, or IBM PC. All these variations of BASIC have the same base syntax, but they differ in more advanced features. Apple I BASIC is among the simplest of the variations. In this chapter, you'll learn how to set up BASIC on the Apple I and write some simple programs.


Setting Up BASIC


The original Apple I did not have BASIC in ROM. Instead, users had to either load it into RAM using an optional cassette interface, or painstakingly type the entire program in by hand. If you're using a Replica I ROM, you already have BASIC ready to run. Power the system up and press Reset. At the / prompt, type:

E000R


This means "run the code, starting at address $E000." Press Return and a > prompt will appear. You're now running BASIC.

The Apple I supports only uppercase type. However, if you're using a PS/2 keyboard, it will probably be possible for you to input lowercase text. The Replica I video circuitry will properly display lowercase, but the BASIC and Apple I software will not recognize it. Keep Caps Lock on to avoid entering any lowercase letters.


Hello World


First, we'll discuss a few steps to take when you're loading BASIC for Apple I.


The PRINT Command


We'll start at the same place at which every programming introduction starts: "Hello World." Load BASIC and type the following at the prompt:

10 PRINT "HELLO WORLD"

20 END


Type RUN followed by pressing Return, and the program will display:

HELLO WORLD


In the aforementioned example, note the line numbers down the left column of the code. The processor executes statements in numerical order. If, later on, you came back and added the line:

15 PRINT "GOODBYE WORLD"


Line 15 would execute before line 20, even though line 20 was typed in first. If you ran the program, the result would be:

HELLO WORLD

GOODBYE WORLD


To see a list of all your code, type:

LIST


The program you entered will be printed to screen, line by line. If you were to type

10 PRINT "GOODBYE WORLD"


your original line 10 would be overwritten with the new line 10. This is especially useful when you discover a typo.

As you've probably guessed, the PRINT command prints to screen. The END command tells the processor when to stop executing.

Multiple strings can be printed with one PRINT. Separating strings with a semicolon will cause them to be printed without any space between them:

>PRINT "HELLO";"WORLD"

HELLOWORLD


Using commas will insert spaces so that the strings line up in columns:

10 PRINT "1","2"

20 PRINT "428","84"

30 END

>RUN

1 2

428 84


The TAB Command


TAB is used to insert spaces before the next PRINT. This is useful for formatting. For example, TAB 15 indents a line 15 spaces; TAB 20 indents 20 spaces.

10 TAB 15: PRINT "HELLO"

20 TAB 20: PRINT "WORLD"

30 END

>RUN

               HELLO

                    WORLD


A colon ( : ) is used to place two instructions on the same line and can be used with any BASIC instruction, not just with TAB.


The GOTO Command


Suppose we want to write a really obnoxious program that says "Hello World" over and over again. This is where the GOTO command comes into play:

10 PRINT "HELLO WORLD"

20 GOTO 10

30 END


The program loops infinitely, printing "HELLO WORLD" each time, and never reaches line 30.


Welcome, User (Input, Variables, and Strings)


In this section, we'll look at inputting data and storing it in variables. Variables can be one of two types, either integer strings or character strings. An integer may be named with a letter or a letter and a digit (for example, A, N, A1, B8). A character string must be named with a letter and a dollar sign ($; for example, A$, R$, Z$).

Characters are ASCII; therefore, each character in a string occupies 1 byte of memory. BASIC needs to be told how many bytes to allocate to a string, a process called dimensioning. The maximum string length is 255 characters (or bytes). For example:

10 PRINT "WELCOME TO THE APPLE I!"

20 DIM N$(20)

30 INPUT "WHAT IS YOUR NAME", N$

40 INPUT "PICK A NUMBER",A

50 PRINT "YOUR NAME IS "; N$

60 PRINT "YOU PICKED "; A

70 END


The output of this code will look like this:

>RUN

WELCOME TO THE APPLE I!

WHAT IS YOUR NAME?TOM

PICK A NUMBER?5

YOUR NAME IS TOM

YOU PICKED 5

>


You may notice that there is a question mark added after WHAT IS YOUR NAME. A question mark is automatically inserted after each INPUT statement. Unfortunately, there is no way to turn it off.

Let's examine the importance of quotation marks in statements. Note the difference between lines 30 and 40 in this code:

10 DIM N$(2)

20 N$="HI"

30 PRINT N$

40 PRINT "N$"

50 END


>RUN

HI

N$


The first line prints the string contained in the variable N$. The second line, because of the quotes, literally prints "N$."


Calculator (Math)


Apple I BASIC allows simple mathematical functions to be performed directly from the command line. Without writing a program, you can simply type:

>PRINT 8+3

11

>PRINT 3-7

-4

>PRINT (8+3)*4

44

>A=12

>PRINT A-7

5

>B = A*3

>PRINT B

36

>


Apple I BASIC only supports integers; so, if you perform division, you'll get results like this:

>PRINT 38/9

4


You can, however, use MOD (modulus) to calculate the remainder.

>PRINT 38 MOD 9

2


From these two commands, we can ascertain that 38/9 is equal to 4 2/9.

Here's a simple program to add two numbers:

10 INPUT "FIRST NUM",A

20 INPUT "SECOND NUM",B

30 PRINT A+B

40 END

>RUN

FIRST NUM?9872

SECOND NUM?1111

10983


BASIC supports integers in the range of –32,767 to 32,767 (2 bytes). There are several mathematical functions built into BASIC (Table 5.1).

Function Description
ABS(N) Returns the absolute value of N. If N is positive, N will be returned. If N is negative, –N will be returned.
SGN(N) Returns 1 if N is positive, 0 if N is 0, and –1 if N is negative.
RND(N) Returns a random number between 0 and N - 1 if N is positive. Returns a random number between N + 1 and 0 if N is negative.
Table 5.1 BASIC's Built-in Mathematical Functions


Here's a quick example of the functions in action:

10 A= RND (-10000)

20 PRINT "RANDOM INT IS: ";A

30 PRINT "SIGN OF INT IS: "; SGN (A)

40 PRINT "ABSOLUTE VALUE OF INT IS: "; ABS (A)

50 END

>RUN

RANDOM INT IS: -9758

SIGN OF INT IS: -1

ABSOLUTE VALUE OF INT IS: 9758


Each time you run this program, RND will generate a new random number.


Count Down (FOR/NEXT)


The FOR and NEXT commands create a loop that runs a set number of times:

FOR I=a TO b STEP c

instructions here

NEXT I


In a simple example, a = 1, b = 10, and c = 1. For the first iteration of the loop, a = 0. Then, the NEXT I instruction is reached, and a is incremented by c (in this case, 1). The program continues to loop until b = c. Here's an example:

10 INPUT "ENTER INCREMENT",I

20 INPUT "START WHERE",S

30 FOR V=S TO 0 STEP -I

40 PRINT V

50 NEXT V

60 END

>RUN

ENTER INCREMENT?3

START WHERE?27

27

24

21

18

15

12

9

6

3

0


If STEP is left off the FOR statement, STEP will default to +1.


Some (IF/THEN)


IF/THEN is a very powerful tool that allows the program to branch in two directions. Look at this sample:

10 DIM N$(20)

20 INPUT "WHAT IS YOUR NAME", N$

30 IF N$ = "TOM" THEN 100

40 PRINT "HELLO, STRANGER!"

50 END

100 PRINT "WELCOME BACK, TOM!"

110 END


If the user's name is Tom, the program issues a GOTO that jumps execution to line 100. If it's not Tom, the program continues executing at the next line, which is 40. IF/THEN statements can be used with an instruction. Here's a sample using PRINT:

10 DIM N$(20)

20 INPUT "WHAT IS YOUR NAME", N$

30 IF N$ = "SECRETAGENT" THEN PRINT "THE CROW FLIES AT MIDNIGHT."

40 PRINT "WELCOME TO THE APPLE I, "; N$; "!"

50 END

>RUN

WHAT IS YOUR NAME?TOM

WELCOME TO THE APPLE I, TOM!

>RUN

WHAT IS YOUR NAME?SECRETAGENT

THE CROW FLIES AT MIDNIGHT.

WELCOME TO THE APPLE I, SECRETAGENT!


If you've programmed in other languages, you're used to having an ELSE statement, such as "If a then b else c." Unfortunately, ELSE is not provided by Apple I BASIC.


Expressions


Apple I BASIC supports the following types of expressions:

A = B

A > B

A < B

A >= B (A is greater than or equal to B)

A <= B (A is less than or equal to B)

A <> B (A does not equal B)

A # B (same as A <> B)


Only = and # may be used with strings. These expressions evaluate to 1 if true and 0 if false. For example:

>PRINT 5=5

1

>PRINT 5=6

0


The IF/THEN statement bases its operation on the resulting 1 or 0. In fact, from the command line you can even type:

>IF 1 THEN PRINT "HI"

HI


It's possible to combine multiple statements with the AND and OR commands:

40 IF A=5 AND B=12 THEN PRINT "WINNER!"

50 IF A=7 OR B=19 OR N$="TOM" OR I$="HELLO" THEN PRINT "WHAT AN ODD COMBINATION."


Parentheses can be used for nesting statements, which are useful for ordinary algebra:

>PRINT (5+2)*8

56


More interestingly, parentheticals can also be used with AND/OR statements:

10 A=5

20 B=8

30 C=11

40 IF A=5 AND (B=927 OR C=11) THEN PRINT "CLOSE ENOUGH!"

50 END


>RUN

CLOSE ENOUGH!


Finally, we have NOT. NOT allows us to get the BASIC-equivalent of NAND and NOR logic gates. With it, we can write statements such as:

IF NOT (A=5 AND B=7) THEN PRINT "NOT BOTH, BUT POSSIBLY ONE"

IF NOT (A=9 OR B=2) THEN PRINT "NEITHER"



The GOSUB Command


GOSUB, which is short for "go to subroutine," is like a more advanced GOTO command. Whereas GOTO permanently branches off to a new location, GOSUB lets the user branch off, run a few lines of code, then RETURN where the program left off before branching. It works like this:

10 GOSUB 100

20 GOSUB 100

30 END


100 PRINT "HELLO"

110 RETURN


>RUN

HELLO

HELLO


Here's another example using nested subroutines:

10 PRINT "START"

20 GOSUB 100

30 PRINT "FINISH"

40 END


100 PRINT "SUBROUTINE 1"

110 GOSUB 200

120 RETURN


200 PRINT "SUBROUTINE 2"

220 RETURN


>RUN

START

SUBROUTINE 1

SUBROUTINE 2

FINISH


When GOSUB is called, BASIC records the line number of origin. RETURN is like a GOTO, which goes back to that original point and begins executing at the next line. Up to eight subroutines can be nested. The program above uses two nested subroutines.

GOSUB is a vital tool for structuring programs. It allows us to establish subroutines, which we can repeatedly use within our program. A well-written subroutine may even be worth saving to use in future programs. In the next example, the sample program illustrates the uses of GOSUB and GOTO. It's more complex than the previous programs we've looked at, so I've included REMs (remarks). The REM statements are not executed by BASIC. They are only displayed when the program is LISTed and exist only to provide guidance to those reading the code.

This program is similar to the battle scenes in a traditional text adventure or dungeon game:

10 REM DUNGEON BATTLE

20 DIM I$ (1)


30 REM HEALTH OF MONSTER M AND YOU Y

40 M = RND(1000)

45 PRINT "MONSTER'S HEALTH: ";M

50 Y = RND(1000)

55 PRINT "YOUR HEALTH: ";Y


60 REM WEAPON STRENGTHS OF MONSTER M1 AND YOU Y1

70 M1 = 250

80 Y1 = 250

100 REM USE A GOTO TO MAKE A LOOP.

101 REM IF/THEN'S ARE USED TO BREAK OUT OF THE LOOP.

120 INPUT "DO YOU WANT TO FIGHT OR RUN (F/R)", I$

130 IF I$ = "R" THEN GOTO 200

140 GOSUB 500

150 IF Y < 1 THEN GOTO 400

160 IF M < 1 THEN GOTO 300

170 GOTO 100


200 PRINT "YOU FLEE IN COWARDLY TERROR. "

210 GOTO 1000


300 PRINT "YOU HAVE VANQUISHED THE MONSTER!"

310 GOTO 1000

400 PRINT "THE MONSTER HAS EATEN YOU."

410 GOTO 1000


500 REM ATTACK

510 M = M-RND(Y1)

520 Y = Y-RND(M1)

530 PRINT "MONSTER HEALTH: "; M

540 PRINT "YOUR HEALTH: "; Y

550 RETURN


1000 END


Here are two sample runs of the game:

>RUN

MONSTERS HEALTH: 466

YOUR HEALTH: 758

DO YOU WANT TO FIGHT OR RUN (F/R)?F


MONSTER HEALTH: 335

YOUR HEALTH: 558

DO YOU WANT TO FIGHT OR RUN (F/R)?F


MONSTER HEALTH: 164

YOUR HEALTH: 474

DO YOU WANT TO FIGHT OR RUN (F/R)?F


MONSTER HEALTH: -21

YOUR HEALTH: 408

YOU HAVE VANQUISHED THE MONSTER!


>RUN

MONSTERS HEALTH: 326

YOUR HEALTH: 69

DO YOU WANT TO FIGHT OR RUN (F/R)?F


MONSTER HEALTH: 312

YOUR HEALTH: -20

THE MONSTER HAS EATEN YOU.



Arrays


An array is a collection of variables stored consecutively in memory. They are accessed by a single variable name followed by their array location in parentheses (as a subscript). Table 5.2 shows a sample array named A.

Location Value
1 89
2 7
3 123
4 2
5 1015
6 42
7 123
Table 5.2 Sample Array A


In this example, 89 would be accessed with A(1), 42 with A(6), and so on. An attempt to access a value outside 1 to 7 will produce an out-of-range error (RANGE ERR).

Like a string, which is actually an array of characters, an array needs to be dimensioned with DIM. Here's a program to create an array similar to the one shown in Table 5.2 and then print all the values:

10 REM DETERMINE ARRAY LENGTH

20 C = RND(20)

30 DIM A(C)


100 REM LOAD VALUES

110 FOR I = 1 TO C

120 A(I) = RND(32767)

130 NEXT I

200 REM PRINT VALUES

210 FOR I=1 TO C

220 PRINT A(I)

230 NEXT I

500 END


>RUN

10411

26608

8259

785

5324

30034

32729

428


Arrays are a useful means of organizing data and are especially well suited to use with FOR/NEXT loops. They also provide the ability to work with a varying number of variables. The execution of the program just shown would not be possible using ordinary variables. When each variable has its own name (for example, A, B), there is no way to loop through them, let alone declare a random number of variables.


Strings, In Depth


Apple I BASIC has considerably advanced string manipulation, given its other limitations. Extracting substrings is simple. A string's length can be retrieved with a single function call. Comparing two strings to see if they're equal is a trivial task.


Substrings


It is possible to select a substring by specifying the start and end points in a subscript. Suppose we have the string:

T$ = "APPLE I REPLICA CREATION"


This string has 24 characters, which are numbered 1 through 24. Substrings are specified in the form of T$(I,J), where I is the location of the first character to be printed and J is the location of the last:

>PRINT T$(1,5)

APPLE

>PRINT T$(7,9)

I R

>PRINT T$(21,21)

T

>PRINT T$(1,24)

APPLE I REPLICA CREATION


It is also possible to specify only the starting point. In which case, all characters from that point on are returned:

>PRINT T$(11)

PLICA CREATION



The LEN Function


LEN returns the number of characters in a string. For example:

>DIM R$(20)

>R$ = "REPLICA"

>PRINT LEN(R$)

7


This is useful when you're using a FOR/NEXT statement to cycle through each character in a string. LEN can be used to tell the FOR/NEXT when to stop. LEN also makes it easy to combine strings, as shown in the next section.


Appending Strings


It's easy to overwrite a string, using a command such as:

DIM $S(20)

$S = "ORIGINAL STRING"

$S = "NEW STRING"


It is also possible to append one string to the end of another. To do this, specify the location where the appended string should start. For example:

>DIM A$(30)

>DIM B$(30)

>A$ = "ABCDEFG"

>B$ = "HIJKLMNOP"

>A$(LEN(A$)+1) = B$

>PRINT A$

ABCDEFGHIJKLMNOP


If the location specified is before the end of the string, the rest of the string will be overwritten. Continuing from the previous example:

>DIM C$(30)

>C$ = "123"

>A$(4) = C$

>PRINT A$

ABC123



Conditionals


The = symbol can also be used to compare two strings. This works for simple comparisons of entire strings:

>DIM A$(30)

>DIM B$(30)

>DIM C$(30)

>A$ = "HELLO"

>B$ = "HELLO"

>C$ = "WORLD"

>PRINT (A$ = B$)

1

>PRINT (A$ = C$)

0


A 1 means that the strings are equal. A 0 means they are different. These comparisons can also be used in IF/THEN statements.

It is also possible to compare any two substrings:

>DIM A$(30)

>DIM B$(30)

>A$ = "NONETHELESS"

>B$ = "JOHANN THEILE"

>PRINT (A$(5,7) = B$(8,10))

1


Sample String Program


This simple program combines substrings, the LEN function, and string comparisons to reverse the order of a name. Here is a sample run of the program:

>RUN

ENTER YOUR FULL NAME?JAMES CONNOLLY

YOUR NAME IS: CONNOLLY, JAMES


The program in full is as follows:

10 REM FULL NAME, FIRST NAME, LAST NAME

15 DIM N$(50)

20 DIM F$(50)

25 DIM L$(50)

30 REM REVERSED NAME

35 DIM R$(50)


50 REM LOAD FULL NAME

55 INPUT "ENTER YOUR FULL NAME", N$


100 REM FIND FIRST NAME BY SEARCH FOR SPACE

105 FOR I = 1 TO LEN(N$)

110 IF N$(I,I) = " " THEN F$ = N$(1,I-1)

115 NEXT I


150 REM LAST NAME STARTS ONE CHAR AFTER THE

155 REM END OF THE FIRST NAME AND ENDS AT

160 REM END OF THE FULL NAME

165 L$ = N$(LEN(F$)+2, LEN(N$))


200 REM REARRANGE NAMES

205 R$ = L$

210 R$(LEN(R$)+1) = ", "

215 R$(LEN(R$)+1) = F$


250 PRINT "YOUR NAME IS: "; R$


300 REM WERE THOSE REALLY DIFFERENT NAMES?

305 IF F$ = L$ THEN PRINT "ARE YOU TELLING THE TRUTH?"


350 END


You might have noticed that the loop at lines 100–115 searches the entire string, even though there's no reason for it to continue after finding the space. Here's an alternative that breaks out of the loop once the space is found:

100 REM FIND FIRST NAME BY SEARCH FOR SPACE

105 FOR I = 1 TO LEN(N$)

110 IF N$(I,I) = " " THEN F$ = N$(1,I-1)

112 IF N$(I,I) = " " THEN 150

115 NEXT I



PEEK and POKE


PEEK and POKE are used for manually accessing memory locations. This is useful if you're interfacing with an input/output device or writing part of your program in assembly. Inconveniently, BASIC uses decimal for PEEKs and POKEs; as a result, you'll have to covert your address from hexadecimal to decimal (as discussed in Chapter 3) before POKEing or PEEKing.

To place the value 42 in location 9000, type:

POKE 9000,42


To read it back and print it to the screen, type:

PRINT PEEK (9000)


The Apple I has 65,535 memory locations. Apple I BASIC allows for integers in the range of –32,767 to 32,767. Memory locations 0 through 32767 are accessed directly. Addresses above 32,767 are accessed using Two's Complement notation (Table 5.3).

To get the Two's Complement notation for –2:

1. Convert +2 to binary.


0000 0000 0000 0010


2. Take the complement.


1111 1111 1111 1101


3. Add 1.


1111 1111 1111 1110


4. Convert to hexadecimal, for ease of use.


$FFFE


Two's Complement Notation Hexadecimal Value
+32,767 $7FFF
+32,766 $7FFE
... ...
+1 $0001
0 $0000
-1 $FFFF
-2 $FFFE
... ...
-32,767 $8001
-32,768 $8000
Table 5.3 Two's Complement Notations and Hexadecimal Values


Since location $8000 is represented by a value less than –32,767, it cannot be reached with BASIC.


The CALL Command


CALL is used to access a subroutine written in Assembly. It is used in the manner:

CALL n


Here, n is the memory location of the subroutine, which is represented in decimal format. In your Assembly subroutine, use an RTS to return control to the BASIC program.

CALL is useful if you want to write most of your program in BASIC but occasionally need a fast Assembly-language subroutine. Table 5.4 lists CALL commands and their meanings.

Command Explanation
AUTO a, b AUTO automatically numbers lines for you as they are typed. a is the first line number. b is the increment between lines. If b is not specified, it defaults to 10. Ctrl-D terminates AUTO mode.
CLR CLR resets all variables, FOR loops, GOSUBs, arrays, and strings. It does not delete the program in memory.
DEL a, b DEL deletes all lines of code between a and b, inclusive. If b is omitted, only line a is deleted.
LIST a, b LIST displays all lines of code between a and b, inclusive. If b is omitted, only line a is displayed. If both are omitted, all lines are displayed.
RUN a RUN does a CLR and then begins executing code starting at line a. If a is omitted, the program begins executing at the first line.
SCR SCR scratches (deletes) the entire program and clears memory.
LOMEM = n LOMEM sets the memory floor for user programs. It is initialized to 2048. LOMEM clears all user programs and values.
HIMEM = n HIMEM sets the memory ceiling for user programs. It is initialized to 4096. Replica I users can increase this value to 32767 to take advantage of the Replica I's extended memory. HIMEM clears all user programs and values.
Table 5.4 CALL Commands and Explanations


Table 5.5 lists CALL error codes and their meanings.

Error Code Explanation
>256 ERR A value restricted to one byte was outside the allowed range of 0 to 255.
>32767 ERR The value entered or calculated was outside the range of (–32767, 32767)
>8 FORS ERR There are more than eight nested FOR loops.
>8 GOSUBS ERR There are more than eight nested subroutines.
BAD BRANCH ERR There is an attempt to branch to a line number that does not exist.
BAD NEXT ERR A NEXT statement is encountered without a corresponding FOR.
BAD RETURN ERR A RETURN statement is encountered without a corresponding GOSUB.
DIM ERR There is an attempt to dimension a character string that has already been dimensioned.
END ERR There is no END command at the end of the program.
MEM FULL ERR Occurs when the size of an array exceeds the amount of space available in memory.
RANGE ERR The requested value is smaller than 1 or larger than the maximum value of the array or string.
RETYPE LINE Data entered for an INPUT is not of the correct type.
STR OVFL ERR The maximum length of the string is exceeded.
STRING ERR The attempted string operation was illegal.
SYNTAX ERR The line is not properly formatted or it contains some typo.
TOO LONG ERR There are too many nested parenthesis in a statement.
Table 5.5 CALL Error Codes and Explanations


Richard III: Interactive Fiction


Richard III is a piece of interactive fiction based on Shakespeare's play of the same name. It is presented here to give you an example of how a small program might be constructed. The story was written by Sarah McMenomy.


Walkthrough


Before writing any code, it's necessary to figure out the basics of how the game is going to work. McMenomy wrote a walkthrough of Richard III. Let's look at her original design:

Intro:

King Richard: Is thy name Tyrrel?

Tyrrel: James Tyrrel, and your most obedient subject.

King Richard: Art thou indeed?

Tyrrel: Prove me, my gracious lord.

King Richard: Dar'st' thou resolve to kill a friend of mine?

Tyrrel: Please you;

But I had rather kill two enemies.

King Richard: Why, then thou hast it! Two deep enemies,

Foes to my rest and my sweet sleep's disturbers,

Are they that I would have thee deal upon:

Tyrrel, I mean those bastards in the Tower.

Tyrrel: Let me have open means to come to them,

And soon I'll rid you from the fear of them.

King Richard: Thou sing'st sweet music. Hark, come hither, Tyrrel.

Go, by this token. Rise, and lend thine ear.

There is no more but so: say it is done,

And I will love thee and prefer thee for it.

Tyrrel: I will dispatch it straight.

Outside Tower.

Ravens are flying around your head as you stand outside the tower.

There are two spigots on the wall; one says "Haute," and the other,

"Caulde." "Caulde" is on.

>N

The Ravens swoop down and peck at you, blocking your entrance.

>Turn Haute on

"Haute" is now on.

>Turn Caulde off

"Caulde" is now off. The ravens are happily bathing in the hot water.

>N

You enter the tower.

Bottom of tower.

You are at the bottom of the tower. There is a dagger on the floor, and

a slip of paper underneath it. There is a guard on the stairs.

>Take dagger and paper

Taken.

>Read paper

The paper says "1483."

>Up

The guard blocks your ascent.

>Kill/stab guard

The guard crumples to the floor, falling on the dagger.

>Up

You ascend the stairs.

Middle of Tower.

You are in the middle of the tower. There is a key in the corner. There

are four number dials on the door to the north.

>Take key

Taken.

>N

The door is closed.

>Open door

You can't.

>Read dials

The dials read "0000."

>Turn first dial to 1

The dial clicks.

>Turn second dial to 4

The dial makes a whir.

>Turn third dial to 8

The dial squeaks.

>Turn fourth dial to 3

The dial whines.

>Open door

The door opens.

>N

You are so close...

Top of tower.

You are at the top of the tower. There is a door to the north.

>Unlock door

You push the key into the door and it swings open; you can see shapes

silhouetted in the moonlight.

>N

You enter the chamber of the sleeping princes...

Tyrrel: The tyrannous and bloody act is done,

The most arch deed of piteous massacre

That ever yet this land was guilty of.

Dighton and Forrest, who I did suborn

To do this piece of ruthless butchery,

Albeit they were fleshed villains, bloody dogs,

Melted with tenderness and mild compassion,

Wept like to children in their deaths' sad story.

'O, thus,' quoth Dighton, 'lay the gentle babes.'

'Thus, thus,' quoth Forrest, 'girdling one another

Within their alabaster innocent arms.

Their lips were four red roses on a stalk,

And in their summer beauty kissed each other.

A book of prayers on their pillow lay,

Which once,' quoth Forrest, 'almost changed my mind;

But, O! The devil' - there the villain stopped;

When Dighton thus told on - 'We smothered

The most replenished sweet work of nature

That from the prime creation e'er she framed.'

Hence both are gone with conscience and remorse:

They could not speak; and so I left them both,

To bear this tidings to the bloody king.

Your villainous task is done; long live King Richard!

***You have won***


I originally wanted to implement a command parser, but the complexity of writing this in BASIC would have made for a very poor beginner's example. To simplify things, I decided to make the options multiple-choice. The game is less interesting this way, but it also makes for an easier demonstration.


Structure


Now that we know what the game should look like from the user's perspective, let's examine the structures needed to implement it.

Each room will be a subroutine; consequently, we can allocate each a range of lines (Table 5.6).

Room Line Allocation
Outside Tower 1,000–1,999
Bottom of Tower 2,000–2,999
Middle of Tower 3,000–3,999
Top of Tower 4,000–4,999
Table 5.6 Line Allocations for Interactive Richard III


Most of the game will take place within the code allocated for the rooms shown in Table 5.6. However, we can make things simpler by using a few other subroutines. The Intro and Conclusion speeches can each be their own subroutines. Likewise, we can use a single subroutine to print the room descriptions. The description will be stored in a string by the room and then used by the subroutine. This will allow us to change the layout for all descriptions by simply modifying one subroutine (Table 5.7).

Subroutine Line Allocation
Introduction 30,000–30,499
Conclusion 30,500–30,999
Initialize 31,000–31,999
PRINT Room 32,000–32,499
Table 5.7 Subroutines for Interactive Richard III


Variables


Next, let's look at the variables we'll need. Ideally, each string of text would be stored in its own variable, making it easy to update and access data. Unfortunately, Apple I BASIC only allows 26 string variables, so the less commonly used strings will have to be stored directly in PRINT statements (Tables 5.8–5.12).

Object Variable Name Description
Room title R$ These variables will be overwritten at the beginning of each room and then used by the Print Room subroutine to display the room's information.
Room description D$
Temporary T$ A temporary variable, which can be used for any purpose.
Choice Y The user's input at the multiple choice.
Increment variable I This variable is used by the FOR/NEXT loops.
Table 5.8 Variables for All Rooms


Object Variable Name Description
Haute spigot H1 The haute and caulde spigots are either on (1) or off (0). By default, haute is off and caulde is on.
Caulde spigot C1
Table 5.9 Variables for Haute and Caulde Spigots


Object Variable Name Description
Dagger D2 The dagger is either in the player's possession (1) or not (0).
Paper P2 The paper is either in the player's possession (1) or not (0).
Guard G2 The guard is either alive (1) or dead (0).
Table 5.10 Variables for Bottom of Tower


Object Variable Name Description
Key K3 The key is either in the player's possession (1) or not (0).
Door D3 The door is either in the open (1) or closed (0) position.
Lock L3 An array of four integers holds the lock combinations. Each value is initialized to 0.
Table 5.11 Variables for Middle of Tower


Object Variable Name Description
Door D4 The door is either unlocked (1) or locked (0).
Table 5.12 Variables for Top of Tower


Skeleton


Each phase of the game is its own subroutine. Rooms can easily be rearranged. Adding another room simply requires adding another subroutine. Italicized names are used in place of line numbers. Omitting line numbers in the program's rough draft will make it easier to make changes along the way.

GOSUB initialize

GOSUB introduction

GOSUB outside_tower

GOSUB bottom_tower

GOSUB middle_tower

GOSUB top_tower

GOSUB conclusion

END


Initialization


The program should start by initializing all the variables we're going to use.

initialize:

DIM R$(255)

R$ = "X" : REM ROOM TITLE

DIM D$(255)

D$ = "X" : REM ROOM DESCRIPTION

DIM T$(255)

T$ = "X" : REM TEMPORARY VARIABLE

DIM L3(4) : REM LOCK COMBINATION

FOR I = 1 TO 4

L3(I) = 0 : REM LOCK COMBINATION SET TO 0000

NEXT I

H1 = 0 : REM HAUTE IS OFF

C1 = 1 : REM CAULDE IS ON

D2 = 0 : REM NO DAGGER

P2 = 0 : REM NO PAPER

G2 = 1 : REM GUARD ALIVE

K3 = 0 : REM NO KEY

D3 = 0 : REM DOOR CLOSED

D4 = 0 : REM DOOR LOCKED

RETURN


Introduction and Conclusion Subroutines


We can address the subroutines for the introduction and conclusion next because they are extremely basic. These two methods consist of nothing more than a series of PRINT statements followed by a RETURN to give control back to the calling routine.

An INPUT line halfway through pauses the scrolling text so that the user has time to read it. The user need not enter any data, but only presses keys for the program to continue.

When a line of poetry exceeds 40 characters, it is manually divided into two lines. The second line is indented four spaces using TABs.

PRINT "KING RICHARD: IS THY NAME TYRREL?"

PRINT "TYRREL: JAMES TYRREL, AND YOUR MOST"

TAB 4: PRINT "OBEDIENT SUBJECT."

PRINT "KING RICHARD: ART THOU INDEED?"

PRINT "TYRREL: PROVE ME, MY GRACIOUS LORD."

PRINT "KING RICHARD: DAR'ST' THOU RESOLVE TO"

TAB 4: PRINT "KILL A FRIEND OF MINE?"

PRINT "TYRREL: PLEASE YOU;"

TAB 4: PRINT "BUT I HAD RATHER KILL TWO ENEMIES."

PRINT "KING RICHARD: WHY, THEN THOU HAST IT!"

TAB 4: PRINT "TWO DEEP ENEMIES,"

PRINT "FOES TO MY REST AND MY SWEET SLEEP'S"

TAB 4: PRINT "DISTURBERS,"

PRINT "ARE THEY THAT I WOULD HAVE THEE DEAL"

TAB 4: PRINT "UPON:"

PRINT "TYRREL, I MEAN THOSE BASTARDS IN THE"

TAB 4: PRINT "TOWER."

PRINT "TYRREL: LET ME HAVE OPEN MEANS TO COME"

TAB 4: PRINT "TO THEM,"

PRINT "AND SOON I'LL RID YOU FROM THE FEAR OF"

TAB 4: PRINT "THEM."

PRINT "KING RICHARD: THOU SING'ST SWEET MUSIC."

TAB 4: PRINT "HARK, COME HITHER, TYRREL."

INPUT "CONTINUE",T$

PRINT "GO, BY THIS TOKEN. RISE, AND LEND THINE"

TAB 4: PRINT "EAR."

PRINT "THERE IS NO MORE BUT SO: SAY IT IS DONE,"

PRINT "AND I WILL LOVE THEE AND PREFER THEE FOR"

TAB 4: PRINT "IT."

PRINT "TYRREL: I WILL DISPATCH IT STRAIGHT."

RETURN


The conclusion is nearly identical:

PRINT "TYRREL: THE TYRANNOUS AND BLOODY ACT IS"

TAB 4: PRINT "DONE,"

PRINT "THE MOST ARCH DEED OF PITEOUS MASSACRE"

PRINT "THAT EVER YET THIS LAND WAS GUILTY OF."

PRINT "DIGHTON AND FORREST, WHO I DID SUBORN"

PRINT "TO DO THIS PIECE OF RUTHLESS BUTCHERY,"

PRINT "ALBEIT THEY WERE FLESHED VILLAINS,"

TAB 4: PRINT "BLOODY DOGS,"

PRINT "MELTED WITH TENDERNESS AND MILD"

TAB 4: PRINT "COMPASSION,"

PRINT "WEPT LIKE TO CHILDREN IN THEIR DEATHS'"

TAB 4: PRINT "SAD STORY."

PRINT "'O, THUS,' QUOTH DIGHTON, 'LAY THE"

TAB 4: PRINT "GENTLE BABES.'"

PRINT "'THUS, THUS,' QUOTH FORREST,"

TAB 4: PRINT "'GIRDLING ONE ANOTHER"

PRINT "WITHIN THEIR ALABASTER INNOCENT ARMS."

PRINT "THEIR LIPS WERE FOUR RED ROSES ON A"

TAB 4: PRINT "STALK,"

INPUT "CONTINUE", T$

PRINT "AND IN THEIR SUMMER BEAUTY KISSED EACH"

TAB 4: PRINT "OTHER."

PRINT "A BOOK OF PRAYERS ON THEIR PILLOW LAY,"

PRINT "WHICH ONCE,' QUOTH FORREST, 'ALMOST"

TAB 4: PRINT "CHANGED MY MIND;"

PRINT "BUT, O! THE DEVIL' - THERE THE"

TAB 4: PRINT "VILLAIN STOPPED;"

PRINT "WHEN DIGHTON THUS TOLD ON - 'WE"

TAB 4: PRINT "SMOTHERED"

PRINT "THE MOST REPLENISHED SWEET WORK OF NATURE"

PRINT "THAT FROM THE PRIME CREATION E'ER SHE"

TAB 4: PRINT "FRAMED.'"

PRINT "HENCE BOTH ARE GONE WITH CONSCIENCE AND"

TAB 4: PRINT "REMORSE:"

PRINT "THEY COULD NOT SPEAK; AND SO I LEFT THEM"

TAB 4: PRINT "BOTH,"

PRINT "TO BEAR THIS TIDINGS TO THE BLOODY KING."

INPUT "CONTINUE", T$

PRINT "YOUR VILLAINOUS TASK IS DONE."

PRINT "LONG LIVE KING RICHARD!"

PRINT

PRINT "***YOU HAVE WON***"

RETURN


PRINT Room Subroutine


PRINT Room is so simple it barely deserves its own subroutine. I wrote it this way to allow for customization. Only one line of code has to be changed to modify the display of every room title or description.

TAB 10: PRINT T$

PRINT D$

INPUT "CONTINUE",T$

RETURN


Outside Tower


Let's examine the first room. The title and description variables are set and the PRINT Room subroutine is called. Next, the program enters the CHOICE loop. The options are printed and IF statements are used to choose where to go next. Some options will print a message and return the user to the loop. Others will enter a subroutine. The Haute and Caulde subroutines allow the user to use the H1 and C1 variables. When H1 and C1 are set correctly, the CHOICE loop jumps to NEXT_LEVEL and then returns from the subroutine.

The Haute and Caulde subroutines take their variables, H1 and C1 respectively, and invert their values from 0 to 1 or 1 to 0. (Though they are technically integers, we're using them as Boolean—true or false—variables.) In some languages there is an instruction for this, but in Apple I BASIC there is not. Instead, the Haute and Caulde subroutines demonstrate two different methods for inverting a Boolean variable.

T$ = "OUTSIDE THE TOWER"

D$ = " RAVENS ARE FLYING AROUND YOUR HEAD AS YOU STAND OUTSIDE THE TOWER.

THERE ARE TWO SPIGOTS ON THE WALL; ONE SAYS 'HAUTE,' AND THE OTHER,

'CAULDE.' 'CAULDE' IS ON."


GOSUB print_room


choose:

PRINT "1) ENTER THE TOWER"

PRINT "2) TURN HAUTE SPIGOT"

PRINT "3) TURN CAULDE SPIGOT"


INPUT "CHOICE", Y

IF Y = 1 AND H1 = 1 AND C1 = 0 THEN next_level

IF Y = 1 THEN PRINT "THE RAVENS SWOOP DOWN AND PECK AT YOU, BLOCKING YOUR ENTRANCE."

IF Y = 2 THEN GOSUB haute

IF Y = 3 THEN GOSUB caulde

INPUT "CONTINUE",T$

GOTO choose


next_level:

PRINT "YOU ENTER THE TOWER."

RETURN


haute:

H1 = H1 + 1

IF H1 = 2 THEN H1 = 0

IF H1 = O THEN PRINT "HAUTE IS NOW OFF."

IF H1 = 1 THEN PRINT "HAUTE IS NOW ON."

RETURN


caulde:

C1 = 1 – C1

IF C1 = O THEN PRINT "CAULDE IS NOW OFF."

IF C1 = 1 THEN PRINT "CAULDE IS NOW ON."

RETURN


Bottom of the Tower


The most interesting feature in this room is the behavior of the paper. The option READ PAPER is only displayed, and only works, if the paper is in the player's possession.

T$ = "BOTTOM OF THE TOWER"

D$ = "YOU ARE AT THE BOTTOM OF THE TOWER. THERE IS A DAGGER ON THE FLOOR, AND A SLIP OF PAPER UNDERNEATH IT. THERE IS A GUARD ON THE STAIRS."


print_room


choose:

PRINT 1) "ATTACK GUARD"

PRINT 2) "GO UP STAIRS"

PRINT 3) "PICK UP PAPER"

PRINT 4) "PICK UP DAGGER"

IF P2 = 1 THEN PRINT "5) READ PAPER"


INPUT "CHOICE", Y

IF Y = 1 THEN GOSUB attack_guard

IF Y = 2 AND G2 = 0 THEN GOTO next_level

IF Y = 2 THEN PRINT "THE GUARD BLOCKS YOUR ASCENT."

IF Y = 3 THEN GOSUB get_paper

IF Y = 4 THEN GOSUB get_dagger

IF Y = 5 AND P2 = 1 THEN PRINT "THE PAPER SAYS '1482'."

INPUT "CONTINUE",T$

GOTO choose


next_level:

PRINT "YOU ASCEND THE STAIRS."

RETURN


get_paper:

IF P2 = 1 THEN PRINT "YOU ALREADY HAVE THE PAPER."

IF P2 = 1 THEN RETURN


P2 = 1

PRINT "YOU TAKE THE PAPER."

RETURN


get_dagger:

IF D2 = 1 THEN PRINT "YOU ALREADY HAVE THE DAGGER."

IF D2 = 1 THEN RETURN


D2 = 1

PRINT "YOU TAKE THE DAGGER."

RETURN


attack_guard:

IF D2 = 1 THEN PRINT "THE GUARD KNOCKS YOU TO THE GROUND."

IF D2 = 1 THEN RETURN


G2 = 0

PRINT "THE GUARD CRUMPLES TO THE FLOOR, FALLING ON THE DAGGER."

RETURN


Middle of the Tower


The "combination lock" in this room is a four-integer array. Only when all four values are correctly set via the ENTER_COMBINATION subroutine can the player continue to the next room.

T$ = "MIDDLE OF THE TOWER"

D$ = "YOU ARE IN THE MIDDLE OF THE TOWER. THERE IS A KEY IN THE CORNER. THERE ARE FOUR NUMBER DIALS ON THE DOOR TO THE NORTH."


print_room


choose:

PRINT "1) PICK UP KEY"

PRINT "2) OPEN DOOR"

PRINT "3) ENTER COMBINATION"

PRINT "4) ENTER ROOM"


INPUT "CHOICE", Y

IF Y = 1 THEN GOSUB get_key

IF Y = 2 AND L3(1) = 1 AND L3(2) = 4 AND L3(3) = 8 AND L3(4) = 3 THEN GOSUB open_door

IF Y = 2 THEN PRINT "THE COMBINATION IS NOT CORRECT."

IF Y = 3 THEN GOSUB enter_combination

IF Y = 4 AND D3 = 1 THEN next_level

IF Y = 4 THEN PRINT "THE DOOR IS CLOSED."

INPUT "CONTINUE",T$

GOTO choose


next_level:

PRINT "YOU ARE SO CLOSE..."

RETURN


get_key:

IF K3 = 1 THEN PRINT "YOU ALREADY HAVE THE KEY."

IF K3 = 1 THEN RETURN


K3 = 1

PRINT "YOU TAKE THE KEY."

RETURN


enter_combination:

INPUT "TURN FIRST DIAL TO", L3(1)

PRINT "THE DIAL CLICKS."

INPUT "TURN SECOND DIAL TO", L3(2)

PRINT "THE DIAL WHIRRS."

INPUT "TURN THE THIRD DIAL TO", L3(3)

PRINT "THE DIAL SQUEAKS."

INPUT "TURN THE FOURTH DIAL TO", L3(4)

PRINT "THE DIAL WHINES. "

RETURN


open_door:

IF D3 = 0 THEN PRINT "THE DOOR IS LOCKED."

IF D3 = 0 THEN RETURN

PRINT "THE DOOR OPENS."

D3 = 1

RETURN


Top of the Tower


The final room is trivial. The door is unlocked with the key from the previous room—but only if the player picked it up! If you're considering to expand this game, the option to move freely between rooms, picking up and dropping objects, would surely be a welcome feature.

T$ = "TOP OF THE TOWER"

D$ = "YOU ARE AT THE TOP OF THE TOWER. THERE IS A DOOR TO THE NORTH."


print_room


choose:

PRINT "1) UNLOCK THE DOOR"

PRINT "2) ENTER THE CHAMBER."


INPUT "CHOICE", Y

IF Y = 1 THEN GOSUB unlock_door

IF Y = 2 AND D4 = 1 THEN next_level

IF Y = 2 THEN PRINT "THE DOOR IS LOCKED."

INPUT "CONTINUE",T$

GOTO choose


next_level:


PRINT "YOU ENTER THE CHAMBER OF THE SLEEPING PRINCESS... "

RETURN


unlock_door:

IF D4 = 1 THEN PRINT "THE DOOR IS ALREADY UNLOCKED"

IF D4 = 1 THEN RETURN


D4 = 1

PRINT "YOU PUSH THE KEY INTO THE DOOR AND IT SWINGS OPEN; YOU CAN SEE SHAPES SILHOUETTED IN THE MOONLIGHT."

RETURN


Richard III Code


Here is the complete code for Richard III. It can also be found in the Supplemental Software package, so those with a serial I/O board from Briel Computers will be able to transfer it to their replica via the terminal.

The italicized headers from earlier sections have been replaced with REM lines to allow them to be stored in the program. Before you begin entering lines, be sure to increase HIMEM to 32767. This program is too large to run in the standard 8K.

10 REM RICHARD III: (BARELY) INTERACTIVE FICTION

30 GOSUB 31000 : REM INITIALIZE

40 GOSUB 30000 : REM INTRODUCTION

50 GOSUB 1000 : REM OUTSIDE OF TOWER

60 GOSUB 2000 : REM BOTTOM OF TOWER

70 GOSUB 3000 : REM MIDDLE OF TOWER

80 GOSUB 4000 : REM TOP OF TOWER

90 GOSUB 30500 : REM CONCLUSION

100 END


31000 REM INITIALIZE

31010 DIM R$(255)

31015 R$ = "X" : REM ROOM TITLE

31020 DIM D$(255)

31025 D$ = "X" : REM ROOM DESCRIPTION

31030 DIM T$(255)

31035 T$ = "X" : REM TEMPORARY VARIABLE

31040 DIM L3(4) : REM LOCK COMBINATION

31045 FOR I = 1 TO 4

31050 L3(I) = 0 : REM LOCK COMBINATION SET TO 0000

31055 NEXT I

31060 H1 = 0 : REM HAUTE IS OFF

31065 C1 = 1 : REM CAULDE IS ON

31070 D2 = 0 : REM NO DAGGER

31075 P2 = 0 : REM NO PAPER

31080 G2 = 1 : REM GUARD ALIVE

31085 K3 = 0 : REM NO KEY

31090 D3 = 0 : REM DOOR CLOSED

31095 D4 = 0 : REM DOOR LOCKED

31100 RETURN


30000 REM INTRODUCTION

30010 PRINT "KING RICHARD: IS THY NAME TYRREL?"

30015 PRINT "TYRREL: JAMES TYRREL, AND YOUR MOST"

30020 TAB 4: PRINT "OBEDIENT SUBJECT."

30025 PRINT "KING RICHARD: ART THOU INDEED?"

30030 PRINT "TYRREL: PROVE ME, MY GRACIOUS LORD."

30035 PRINT "KING RICHARD: DAR'ST' THOU RESOLVE TO"

30040 TAB 4: PRINT "KILL A FRIEND OF MINE?"

30045 PRINT "TYRREL: PLEASE YOU;"

30050 TAB 4: PRINT "BUT I HAD RATHER KILL TWO ENEMIES."

30055 PRINT "KING RICHARD: WHY, THEN THOU HAST IT!"

30060 TAB 4: PRINT "TWO DEEP ENEMIES,"

30065 PRINT "FOES TO MY REST AND MY SWEET SLEEP'S"

30070 TAB 4: PRINT "DISTURBERS,"

30075 PRINT "ARE THEY THAT I WOULD HAVE THEE DEAL"

30080 TAB 4: PRINT "UPON:"

30085 PRINT "TYRREL, I MEAN THOSE BASTARDS IN THE"

30090 TAB 4: PRINT "TOWER."

30095 PRINT "TYRREL: LET ME HAVE OPEN MEANS TO COME"

30100 TAB 4: PRINT "TO THEM,"

30105 PRINT "AND SOON I'LL RID YOU FROM THE FEAR OF"

30110 TAB 4: PRINT "THEM."

30115 PRINT "KING RICHARD: THOU SING'ST SWEET MUSIC."

30120 TAB 4: PRINT "HARK, COME HITHER, TYRREL."

30125 INPUT "CONTINUE",T$

30130 PRINT "GO, BY THIS TOKEN. RISE, AND LEND THINE"

30135 TAB 4: PRINT "EAR."

30140 PRINT "THERE IS NO MORE BUT SO: SAY IT IS DONE,"

30145 PRINT "AND I WILL LOVE THEE AND PREFER THEE FOR"

30150 TAB 4: PRINT "IT."

30155 PRINT "TYRREL: I WILL DISPATCH IT STRAIGHT."

30160 INPUT "CONTINUE",T$

30165 RETURN


30500 REM CONCLUSION

30505 PRINT "TYRREL: THE TYRANNOUS AND BLOODY ACT IS"

30510 TAB 4: PRINT "DONE,"

30515 PRINT "THE MOST ARCH DEED OF PITEOUS MASSACRE"

30520 PRINT "THAT EVER YET THIS LAND WAS GUILTY OF."

30525 PRINT "DIGHTON AND FORREST, WHO I DID SUBORN"

30530 PRINT "TO DO THIS PIECE OF RUTHLESS BUTCHERY,"

30535 PRINT "ALBEIT THEY WERE FLESHED VILLAINS,"

30540 TAB 4: PRINT "BLOODY DOGS,"

30545 PRINT "MELTED WITH TENDERNESS AND MILD"

30550 TAB 4: PRINT "COMPASSION,"

30555 PRINT "WEPT LIKE TO CHILDREN IN THEIR DEATHS'"

30560 TAB 4: PRINT "SAD STORY."

30565 PRINT "'O, THUS,' QUOTH DIGHTON, 'LAY THE"

30570 TAB 4: PRINT "GENTLE BABES.'"

30575 PRINT "'THUS, THUS,' QUOTH FORREST,"

30580 TAB 4: PRINT "'GIRDLING ONE ANOTHER"

30585 PRINT "WITHIN THEIR ALABASTER INNOCENT ARMS."

30590 PRINT "THEIR LIPS WERE FOUR RED ROSES ON A"

30595 TAB 4: PRINT "STALK,"

30600 INPUT "CONTINUE", T$

30605 PRINT "AND IN THEIR SUMMER BEAUTY KISSED EACH"

30610 TAB 4: PRINT "OTHER."

30615 PRINT "A BOOK OF PRAYERS ON THEIR PILLOW LAY,"

30620 PRINT "WHICH ONCE,' QUOTH FORREST, 'ALMOST"

30625 TAB 4: PRINT "CHANGED MY MIND;"

30630 PRINT "BUT, O! THE DEVIL' - THERE THE"

30635 TAB 4: PRINT "VILLAIN STOPPED;"

30640 PRINT "WHEN DIGHTON THUS TOLD ON - 'WE"

30645 TAB 4: PRINT "SMOTHERED"

30650 PRINT "THE MOST REPLENISHED SWEET WORK OF NATURE"

30655 PRINT "THAT FROM THE PRIME CREATION E'ER SHE"

30660 TAB 4: PRINT "FRAMED.'"

30665 PRINT "HENCE BOTH ARE GONE WITH CONSCIENCE AND"

30670 TAB 4: PRINT "REMORSE:"

30675 PRINT "THEY COULD NOT SPEAK; AND SO I LEFT THEM"

30680 TAB 4: PRINT "BOTH,"

30685 PRINT "TO BEAR THIS TIDINGS TO THE BLOODY KING."

30690 INPUT "CONTINUE", T$

30700 PRINT "YOUR VILLAINOUS TASK IS DONE."

30705 PRINT "LONG LIVE KING RICHARD!"

30710 PRINT

30715 PRINT "***YOU HAVE WON***"

30720 INPUT "CONTINUE",T$

30725 RETURN


32000 REM PRINT ROOM

32010 TAB 10: PRINT T$

32015 PRINT D$

32020 INPUT "CONTINUE",T$

32025 RETURN


1000 REM OUTSIDE THE TOWER

1010 T$ = "OUTSIDE THE TOWER"

1015 D$ = "RAVENS ARE FLYING AROUND YOUR HEAD AS YOU STAND OUTSIDE THE TOWER. THERE ARE TWO SPIGOTS ON THE WALL;"


1016 D$(LEN(D$)+1) = "ONE SAYS 'HAUTE,' AND THE OTHER, 'CAULDE.' 'CAULDE' IS ON."


1020 GOSUB 32000


1025 PRINT "1) ENTER THE TOWER"

1030 PRINT "2) TURN HAUTE SPIGOT"

1035 PRINT "3) TURN CAULDE SPIGOT"


1040 INPUT "CHOICE", Y

1045 IF Y = 1 AND H1 = 1 AND C1 = 0 THEN 1200

1050 IF Y = 1 THEN PRINT "THE RAVENS SWOOP DOWN AND PECK AT YOU, BLOCKING YOUR ENTRANCE."

1060 IF Y = 2 THEN GOSUB 1300

1065 IF Y = 3 THEN GOSUB 1400

1070 INPUT "CONTINUE",T$

1075 GOTO 1025


1200 REM NEXT LEVEL

1205 PRINT "YOU ENTER THE TOWER."

1210 RETURN


1300 REM HAUTE

1305 H1 = H1 + 1

1310 IF H1 = 2 THEN H1 = 0

1315 IF H1 = O THEN PRINT "HAUTE IS NOW OFF."

1320 IF H1 = 1 THEN PRINT "HAUTE IS NOW ON."

1325 RETURN


1400 REM CAULDE

1405 C1 = C1 - 1

1410 C1 = ABS(C1)

1415 IF C1 = O THEN PRINT "CAULDE IS NOW OFF."

1420 IF C1 = 1 THEN PRINT "CAULDE IS NOW ON."

1425 RETURN


2000 REM BOTTOM OF THE TOWER

2010 T$ = "BOTTOM OF THE TOWER"

2015 D$ = "YOU ARE AT THE BOTTOM OF THE TOWER. THERE IS A DAGGER ON THE FLOOR, AND A SLIP OF PAPER UNDERNEATH IT."

2016 D$(LEN(D$)+1) = "THERE IS A GUARD ON THE STAIRS."


2020 GOSUB 32000


2025 PRINT "1) ATTACK GUARD"

2030 PRINT "2) GO UP STAIRS"

2035 PRINT "3) PICK UP PAPER"

2040 PRINT "4) PICK UP DAGGER"

2045 IF P2 = 1 THEN PRINT "5) READ PAPER"


2050 INPUT "CHOICE", Y

2055 IF Y = 1 THEN GOSUB 2500

2060 IF Y = 2 AND G2 = 0 THEN GOTO 2200

2065 IF Y = 2 THEN PRINT "THE GUARD BLOCKS YOUR ASCENT."

2070 IF Y = 3 THEN GOSUB 2300

2075 IF Y = 4 THEN GOSUB 2400

2080 IF Y = 5 AND P2 = 1 THEN PRINT "THE PAPER SAYS '1482'."

2085 INPUT "CONTINUE",T$

2090 GOTO 2025


2200 REM NEXT LEVEL

2205 PRINT "YOU ASCEND THE STAIRS."

2210 RETURN


2300 REM GET PAPER

2305 IF P2 = 1 THEN PRINT "YOU ALREADY HAVE THE PAPER."

2310 IF P2 = 1 THEN RETURN

2315 P2 = 1

2320 PRINT "YOU TAKE THE PAPER."

2325 RETURN


2400 REM GET DAGGER

2405 IF D2 = 1 THEN PRINT "YOU ALREADY HAVE THE DAGGER."

2410 IF D2 = 1 THEN RETURN

2415 D2 = 1

2420 PRINT "YOU TAKE THE DAGGER."

2425 RETURN


2500 REM ATTACK GUARD

2505 IF D2 = 0 THEN PRINT "THE GUARD KNOCKS YOU TO THE GROUND."

2510 IF D2 = 0 THEN RETURN

2515 G2 = 0

2520 PRINT "THE GUARD CRUMPLES TO THE FLOOR, FALLING ON THE DAGGER."

2525 RETURN


3000 REM MIDDLE OF THE TOWER

3010 T$ = "MIDDLE OF THE TOWER"

3015 D$ = "YOU ARE IN THE MIDDLE OF THE TOWER. THERE IS A KEY IN THE CORNER."

3016 D$(LEN(D$)+1) = "THERE ARE FOUR NUMBER DIALS ON THE DOOR TO THE NORTH."


3020 GOSUB 32000


3025 PRINT "1) PICK UP KEY"

3030 PRINT "2) OPEN DOOR"

3035 PRINT "3) ENTER COMBINATION"

3040 PRINT "4) ENTER ROOM"


3045 INPUT "CHOICE", Y

3050 IF Y = 1 THEN GOSUB 3200

3055 IF Y = 2 AND L3(1) = 1 AND L3(2) = 4 AND L3(3) = 8 AND L3(4) = 3 THEN GOSUB 3400

3060 IF Y = 2 AND D3 = 0 THEN PRINT "THE COMBINATION IS NOT CORRECT."

3065 IF Y = 3 THEN GOSUB 3300

3070 IF Y = 4 AND D3 = 1 THEN 3100

3075 IF Y = 4 THEN PRINT "THE DOOR IS CLOSED."

3080 INPUT "CONTINUE",T$

3085 GOTO 3025


3100 REM NEXT LEVEL

3105 PRINT "YOU ARE SO CLOSE..."

3110 RETURN


3200 REM GET KEY

3205 IF K3 = 1 THEN PRINT "YOU ALREADY HAVE THE KEY."

3210 IF K3 = 1 THEN RETURN

3215 K3 = 1

3220 PRINT "YOU TAKE THE KEY."

3225 RETURN


3300 REM ENTER COMBINATION

3305 INPUT "TURN FIRST DIAL TO", L3(1)

3310 PRINT "THE DIAL CLICKS."

3315 INPUT "TURN SECOND DIAL TO", L3(2)

3320 PRINT "THE DIAL WHIRRS."

3325 INPUT "TURN THE THIRD DIAL TO", L3(3)

3330 PRINT "THE DIAL SQUEAKS."

3335 INPUT "TURN THE FOURTH DIAL TO", L3(4)

3340 PRINT "THE DIAL WHINES."

3345 RETURN


3400 REM OPEN DOOR

3405 PRINT "THE DOOR OPENS."

3410 D3 = 1

3415 RETURN


4000 REM TOP OF THE TOWER

4010 T$ = "TOP OF THE TOWER"

4015 D$ = "YOU ARE AT THE TOP OF THE TOWER. THERE IS A DOOR TO THE NORTH."


4020 GOSUB 32000


4025 PRINT "1) UNLOCK THE DOOR"

4030 PRINT "2) ENTER THE CHAMBER."4035 INPUT "CHOICE", Y

4040 IF Y = 1 THEN GOSUB 4200

4045 IF Y = 2 AND D4 = 1 THEN 4100

4050 IF Y = 2 THEN PRINT "THE DOOR IS LOCKED."

4055 INPUT "CONTINUE",T$

4060 GOTO 4025


4100 REM NEXT LEVEL

4105 PRINT "YOU ENTER THE CHAMBER OF THE SLEEPING PRINCES..."

4110 RETURN


4200 REM UNLOCK DOOR

4205 IF K3 = 0 THEN PRINT "YOU DO NOT HAVE A KEY"

4210 IF K3 = 0 THEN RETURN

4215 IF D4 = 1 THEN PRINT "THE DOOR IS ALREADY UNLOCKED"

4220 IF D4 = 1 THEN RETURN

4225 D4 = 1

4230 PRINT "YOU PUSH THE KEY INTO THE DOOR AND IT SWINGS OPEN; YOU CAN SEE SHAPES SILHOUETTED IN THE MOONLIGHT."

4235 RETURN


Summary


This chapter has attempted to provide a reasonable introduction to programming the Apple I in BASIC. Particular emphasis has been placed on the peculiarities of the Apple I's version of BASIC. For more sample programs written in Apple I BASIC, visit the Apple I Owners Club on Applefritter. If you'd like a more in-depth guide to programming BASIC in general, most public libraries will have countless books on the subject.



← Previous Contents Next →