PILOT YOUR ATARI

ANTIC v1.1 / APRIL 1982 / PAGE 12

PILOT YOUR ATARI

by Ken Harms

PILOT is not just another computer language, it is designed to meet some of the needs of new programmers, educators, and children.

PILOT grew out of work by John Starkweather at the University of California at San Francisco back in 1972. He wanted a language which would make it easy to write tutorial programs for students, programs capable of recognizing responses other than the typical “1, 2, 3 multiple choice” style prevalent in current teaching programs. With PILOT, it is easy to ask, “Who was the first president of the United States?” and record and score answers such as “President Washington,” “I believe it was G. Washington,” “George Washington,” “GEORGE WASHINGTON,” “Washington”. PILOT needs only three statements to accomplish this type of user interaction.

Dean Brown at Stanford Research Institute proved that teachers could understand PILOT, and students loved it. Since PILOT is word-oriented, as contrasted to BASIC’s number orientation, it naturally fits the “riddle” and “tell-a-story” type of program which youngsters like. At the same time, Seymour Papert at MIT developed a new way to conceptualize and teach about geometry and shapes. This development was called “Turtle Graphics” and proved ideal for use in home computers. Atari wisely included a Turtle Graphics command language with the PILOT module.

The old “Cartesian Coordinate” system required commands like this:

Start at position X=20 and Y=10. Draw a line to X=40 and Y=10; draw a line to X=40 and Y=30; draw a line to X=20 and Y=30; finally, draw a line to X=20 and Y=10.

Can you guess what figure this is? How big it is? Using Turtle Graphics the same pictures can be drawn like this:

Do this 4 times: draw a line 20 spaces long, turn Right 90 degrees.

The box shape is more apparent and the commands are more readily understood. Only 14 or 15 commands represent the core of PILOT. All are only one or two characters long and easily remembered—a “J” is the “jump to” command. Anyone who is not a good typist will appreciate the wisdom of short commands. Short, easy to remember commands and Turtle Graphics combined with Atari’s wonderful screen editor will make almost anyone’s introduction to computing more pleasurable and rewarding. Finally, PILOT programs become naturally organized around modules. This encourages a well-structured programming style. (Oh yes, PILOT includes full use of the Atari sound system—more on that in a later article.)

PILOT is available in two packages; one is just the language cartridge and users guide (about $90), the other is a well documented comprehensive package that I recommend (about $130). This package includes:

PILOT CARTRIDGE—(love those cartridges; little fingers can’t destroy them)

STUDENT PILOT—a cleverly illustrated learner’s manual for the new programmer.

PILOT PRIMER—an instruction manual for the experienced programmer

DEMONSTRATION TAPES—two cassettes showing language, color, graphics, and sound.

POCKET CHART—presents all commands in an easy-to-use format.

I like Atari’s version of PILOT. There are still a few rough spots; not all syntax errors are caught, the manuals do not include indices, several commands are not explained in the manual, and a few typographical errors remain to confuse you. In spite of these few “start-up” problems Atari PILOT meets its “primary design goals”; it is “consistent and easy to learn…it allows reasonable access to the Atari system capabilities, but not at the user’s expense.”

We intend to help you get the most from PILOT. Watch for programming tips, warnings, and more help. Address your questions to:

K.W. Harms
c/o ANTIC
297 Missouri St.
San Francisco, CA 94107
ANTIC v1.2 / JUNE 1982 / PAGE 22

PILOT YOUR ATARI

LARGE TEXT

by Ken Harms

This series of articles will show you how to do what ATARI left out of the PILOT manuals, fancy tricks such as large letters and changing colors, useful features like breaking strings into words and using the mysterious commands in the demonstration programs.

When you run your PILOT program, three sets of instructions work together to give you the result you need. The operating system in the 400/800 provides the instructions for reading the keyboard, writing characters to the TV screen, and I/O devices, such as disk drives and printers. Additionally the PILOT cartridge contains the translation system which actually interprets your PILOT program for the ATARI hardware. These two systems working together allow the ATARI to perform the instructions you provide with the third type of instructions, the PILOT application program.

PILOT programs operate on data stored in the computer’s memory or RAM (random access memory). PILOT stores each variable, constant, or instruction as a value in a unique location or address. These are like P.O. boxes. You can put messages into them and read data from them. Some addresses are used by the operating system to hold information such as the color used on the screen and what size text characters to print, large or small. PILOT lets you change the contents of these addresses to give greater graphics control.

The operating system supports fourteen different ways to display data on the screen. Those of you familiar with BASIC know eight of these modes. PILOT normally uses only two modes, Graphics 0, and Graphics 7, these are a text and a graphics mode. But you can turn on at least two of the extra modes to display large letters as eyecatching program titles.

To enable large text, we need to change values in two special addresses, 1373 and 1374, by using a special form of the Compute command:

C:@B1373=16
C:@B1374=1

This command might read as: “COMPUTE the ‘byte’ at address 1373 equals 16”. A byte is computerese for a value in memory. The first command puts a 16 in address 1373 to tell the ATARI that you want a graphic screen with regular letters at the bottom. The value 1 at address 1374 tells the ATARI that you want it to print medium-large letters. These mode 1 letters are so large that only 20 fit on a line. Listing 1, lines 20 and 30, demonstrate these commands.

The next command you’ll need is WRITE. It tells the ATARI to write data to a specific “device.” These devices are identified by letters such as “D” for disk, “P” for printer, “C” for cassette and “S” for screen. Line 40 tells the ATARI to write to the screen “MODE 1 LETTERS.” Of course, it will write anything you want. So, with those three simple commands, you have a dramatic opening for a program.

Change the contents of location 1374 to determine the size and number of characters per line.

1374=0
regular letters, 40 per line
1374=1
20 rows of medium letters, 20 characters per line
1374=2
10 rows of large letters20 characters per line

The *TEST2 module demonstrates mode 2 large letters. In both modes, try using upper, lower and inverse characters. You’ll find that each prints in a different color for interesting effects.

Address 1373 is the “sub-mode” address.

1373=0
a full screen (no “text window”)
1373=16
split screen (text “text window”)
1373=32
full screen opens without erasing prior data

Listing 2 uses the 32 sub-mode to erase the text window. If you’re in sub-mode or 32, any text (even the READY at the end of a program) clears the screen; use a PA: command to keep the screen up. To change any mode or sub-mode, you must CLOSE:S between modes and issue botli 1373 and 1374 commands in the next mode. After entering a new mode, always issue a WRITE command before a type command (T:).

Next time, we’ll look at changing colors and breaking strings into letters or words.

10 *TEST1 [MEDIUM LETTERS MODE 1
20 C:@B1373=16 [SPLIT SCREEN
30 C:@B1374=1 [SET MODE 1
40 WRITE:S, MODE 1 LETTERS
50 PA:240 [PAUSE TO WATCH SCREEN
60 CLOSE:S [REQUIRED TO CHANGE MODES
70 J:*TEST2
80 *TEST2 [LARGE LETTERS MODE 2
90 C:@B1373=16 [SPLIT SCREEN
100 C:@B1374=2 [SET MODE 2
110 WRITE:S. THIS IS MODE 2
120 T: "T"YPED TEXT APPEARS BELOW SCREEN
130 PA:240
140 CLOSE:S
150 J:*TEST0
160 *TEST0
170 C:@B1373=0
180 C:@B1374=0
190 WRITE:S, THIS IS WRITE IN MODE 0
200 PA:100
ANTIC v1.3 / AUGUST 1982 / PAGE 36

PILOT YOUR ATARI

COLORS FOR YOUR PILOT

by Ken Harms

This month I will show you how to use all 128 colors of the ATARI and how you can rapidly change these colors in your displays.

To display data on the TV screen, PILOT first gets data (character or graphics information) from your program and then looks at special memory locations to determine the color to use. You can use a maximum of four colors at one time on your screen. Each color is selected by the PEN: (color) instruction. This instruction calls these locations by the names “Red”, “Blue”, “Yellow”, and “Erase”. Once PILOT knows what name (location) a line belongs to, it uses the color value found there for all lines drawn by that PEN:(color) instruction.

When PILOT looks at the “Blue” location it will find a color value there. This value will cause the ATARI to draw blue lines when you first turn it on. Fortunately, you can put any color value into these locations. So, even though PILOT calls these locations by color names (for convenience) any color may be found there. You can change these colors using a special form of the C:ompute command. Turn your machine on and type this in direct mode:

C:@B710=86
C:@B712=5*16+6

The first instruction might be spoken “Compute byte 710 equals 86”. In this case, the 710 is the special address PILOT calls its “Blue” location. The 86 is a color value for a red color. In effect we put “red paint into a can labeled blue”. In the second instruction, the “712” is PILOT’s “Erase” register. The “5” is a hue (color) number and the “6” is a luminance number (more on them later).

In the graphic mode, PILOT uses four locations or registers. Their names, addresses and uses are listed in Table 1.

TABLE 1
NameRegisterValueUsed forAddress
Red070Graphics708
Yellow126Graphics709
Blue2148Text Window & Graphics710
None3148Not Used711
Erase40Background & Border712

You change the color of any register (paint can) by placing a different color value in any of the addresses. Color values are made up of two numbers, a “hue number” and a “luminence” or brightness number. Table 2 gives these values and what they usually look line on my TV.

TABLE 2
HueLuminance
0 = gray0—lowest possible luminance (black)
1 = green brown2—
2 = yellow /orange4—
3 = orange6—
4 = red /orange8—
5 = pink10—
6 = bluish purple12—
7 = purple14—maximum luminance (white)
8 = blue
9 = bright blue
10 = turquoise
11 = greenish blue
12 = green
13 = yellowish green
14 = orangish green
15 = light orange

The color value needed in each register is calculated as follows:

Hue number * 16 + luminance number.

A color value for the red we used above is 86 or “16*5 + 6.” Changing a register can be done at any time in your program.

The listing draws two houses in different color registers and then changes the colors rapidly to illustrate the power of this technique.

Let me leave you with an experiment: Use Mode 1 or Mode 2 letters (see last issue) and determine which color registers are used for uppercase and lowercase letters.

You may be interested in a new learning club for PILOT/ LOGO users. It has a good newsletter, simple programs and an educational orientation. It is free to people under 18. Write to:

Young People’s LOGO Association
1208 Hillsdale Drive
Richardson, Texas 75081
10 R:HOUSES
20 R:------- Draws houses and shifts
30 R:------- all four color registers
40 R:------- ANTIC Issue 3
50 *COLOR
60 GR:CLEAR
70 GR:GOTO -20,10
80 U:*HOUSE
90 GR:GOTO 20,10
100 U:*HOUSE
110 U:*REGISTER0
120 PA:240
130 U:*REGISTER1
140 PA:240
150 U:*REGISTER2
160 PA:240
170 U:*REGISTER4
180 E:
190 *HOUSE
200 GR:PEN YELLOW
210 GR:TURNTOO
220 GR:TURN 135;DRAW 14
230 GR:TURN 45;PEN BLUE;DRAW 15 [REG 2
240 GR:TURN 90;DRAW 5
250 GR:TURN 90;FILL 8
260 GR:TURN -90;DRAW 10
270 GR:TURN -90;PEN RED;FILL 8 [REG 0
280 GR:TURN 90;PEN BLUE;DRAW 5
290 GR:TURN 90;FILL 14
300 GR:TURN 45;PEN YELLOW;FILL 14 [REG 1
310 E:
320 *REGISTER0
330 C:#A=192 [HUE 12 LUM 0
340 *INCREMENT0
350 C:@B708=#A
360 T:708 = #A
370 PA:30
380 C:#A=#A+2
390 J(#A<202):INCREMENT0
400 E:
410 *REGISTER1
420 C:#A=224 [HUE 14 LUM 0
430 *INCREMENT1
440 C:@B709=#A
450 T:709 = #A
460 PA:30
470 C:#A=#A+2
480 J(#A<228):*INCREMENT1
490 E:
500 *REGISTER2
510 C:#A=80  [HUE 5 LUM 0
520 *INCREMENT 2
530 C:@B710=#A
540 T:710 = #A
550 PA:30
560 C:#A=#A+2
570 J(#A<88):*INCREMENT2
580 E:
590 *REGISTER4
600 C:#A=144 [HUE 9 LUM 0
610 *INCREMENT4
620 C:@B712=#A
630 T:712 = #A
640 PA:30
650 C:#A=#A+2
660 J(#A<152):*INCREMENT4
670 E:
ANTIC v1.4 / OCTOBER 1982 / PAGE 25

PILOT YOUR ATARI

The Musical PILOT

by KEN HARMS

This article will open the door to string parsing, a powerful way to analyze PILOT strings. Along the way, we’ll read and write on the disk/cassette, do some Boolean algebra, change data types and reveal a beautiful PILOT bug. And, oh yes, we’ll play four-voice music.

As always, we’ll be way “beyond the book.” Since it will be getting pretty deep, I’ll give page references to Atari’s PILOT Primer.

A string is a combination of letters, numbers, symbols, words, etc., “strung together.” In PILOT, a “string variable” is made by giving it a name (always beginning with “$”) in an A:ccept or C:ompute instruction (pp. 69-76). The book tells how to concatenate (“grow”) strings. We’ll discuss how to parse (“cut”) strings so you can analyze each part of a string. This could be useful for analyzing sentences, riddles, or in this case, for storing data for a program’s use (PILOT lacks a “Data” statement).

String parsing relies on the Match String command which produces three pre-named variables, $Left, $Match, and $Right (pp. 41-44, 81-82). Parsing programs work as follows (refer to the Pilot Player listing):

  1. Place the string into the “accept buffer” (line 1270).
  2. Match on the “separator.” In this case, I used the blank as a separator. In line 1280, we skip over the initial blank, which the A:ccept instruction inserts in each string, and M:atch on the second blank. (Note the right arrow in the instruction which doesn’t print in front of the “_”).
  3. Check for the end of string (the JN: in line 1290).
  4. Store the remainder of the string (found in $Right) in a safe place (line 1300).
  5. Use $LEFT as the parsed word, letter, etc. (lines 1310-1370).
  6. Jump back to step 1.

Although this may seem complicated, it’s conceptually as easy as BASIC.

To play a C,D,E,F chord for a sixteenth, the Pilot Composer produces a string looking like this: “ 1 3 5 6 16 ! ”. The first four values are the usual notes (pp. 106-107) for each of the ATARI’s four voices. The “16” is the inverse duration of the note (1/16 of a note). The “!” is a “terminator” to tell us that we’re out of notes. Our problem: parse it and play it. The *Loop2 routine (lines 1250-1390) cuts the string and sets up variables for each voice and for the PAUSE command. After each Match String, the variables look this way (the underlines represent blanks):

PASS$PLAYVALUES
BEFORE MATCH
$LEFT$MATCH$RIGHT$LEFT
USED FOR
0_1_3_5_6_16_NULLNULLNULL
1_1_3_5_6_16__1_____3_5_6_16_#A
2_3_5_6_16__3_____5_6_16_#B
3_5_6_16__5_____6_16_#C
4_6_16__6_____16_#D
5_16__16_______#L
6_____16_______NO MATCH

Simply put, each value marches to the left into the $LEFT bucket and then gets used. Notice that the “no match” in pass six did not change any of the special string variables.

The Pilot Composer parses strings in a similar fashion but on each letter. In this case, the match parsing instruction (line 1200) skips two spaces (the leading blank and the first letter) and M:atches on the next character to put all remaining characters in $MATCH (the comma does that). Once the string is split, a simple $LEFT inspection finds the character and then restores the balance of the string. The *TRANSLATE module (lines 1400-1690) performs a similar M:atch to find good notes and durations in $GOODNOTES and $GOODDURATION, and then to translate them into note and duration values. The translation lookup in $NOTEABLE is “fail safe” — it first M:atches on the note followed by “/” and then M:atches on the subsequent “.”. This forces the value (a 5, say) into $LEFT. This was required, since at M:atch for 1 or 8 without the “.” would have found the value of notes C and G. Of course, I could have designed the string in reverse order — that’s an improvement for you.

Let’s digress to the music before going on with the programming. The Pilot Music “System” now has two simple programs. Pilot Composer accepts four-note chords composed of the eight basic notes (no sharps or flats), followed by a duration (a whole note, half note, etc.). It checks these data, catches most errors, and rings a “bell” when it’s ready for another chord. It won’t find short chords, so make sure you enter four notes and a duration, or change the *TRANSLATE module between lines 1670 and 1680. Chords are written to the disk or cassette every 10 chords. This is required since the maximum length of an accept buffer is 254 characters.

The Pilot Player asks for a tempo (how fast to play) and a file of music. It then opens that file and plays the notes stored there.

Back to the Pilot Composer program. Under PILOT (pp. 73), strings are concatenated by naming two strings in a C:ompute (or A:ccept) instruction (e.g.: C:$ONE=$ONE$TWO). If, however, one of the strings is “undefined” because it has never been used before, it has the value of a text literal rather than the value of a string. In the example, if $TWO had the value JOHN but $ONE was undefined, the new value of $ONE would be $ONEJOHN — hardly what we wanted! I avoid this by initializing strings used in this way (see lines 130 & 140).

PILOT input and output (I/O) is handled with READ:, WRITE: and CLOSE: instructions. Each instruction requires a “device name” (a "C:" for cassette or a "D:" for disk) and, for disk, a file name. These are separated from following data by a comma. The data can be text literals, numeric or string variables. In a single file, READ: must be separated from WRITE: by a CLOSE:. You can try this in immediate mode or in a program:

DISK
WRITE:D:TEST,ABCD
CLOSE:D:TEST
READ:D:TEST,$STRING
T:$STRING

CASSETTE
WRITE:C:,ABCD
CLOSE:C:
READ:C:,$STRING
T:$STRING

We’ll have more on I/O in a future article to discuss a hidden glitch. For now, just do as line 430 does and put all device specifications in a single string.

Keeping a clean screen in a program often requires erasing a line on the screen. It’s not so simple in PILOT since the “blank line” string automatically defaults to one character. Lines 750 and 1230 show an easy way; just print a series of blanks followed by a non-printing character such as an arrow. Line 750, for instance, prints the #A followed by a blank and a left arrow. When the line is printed, the right-most character is blanked out, and the left arrow holds the space, but doesn’t show. You can type an arrow by hitting the ESC key then holding down the CTRL key while hitting the desired arrow key. Repeat all three strokes for each arrow.

Although the Primer tells us that variables come in two flavors — strings (pp. 69-81) and numerics (pp. 85-92), we never find out how to change one into the other. It’s simple but tricky. String variables can be made from numeric variables by C:omputing or A:ccepting them:

C:$ONE=#A
A:$ONE=#A

A string variable can be turned into a numeric variable ONLY by A:ccepting it:

A:#A=$ONE

After this instruction, #A will have the numeric value from $ONE; non-numeric data will be disregarded (see the Player program, lines 1310-1350).

Line 1140 in the Player program presents a powerful way to combine “relational operators” to make “conditional statements” (pp. 89-90). Linking conditions with “+” signs creates “logical ors”. For instance, line 1140 would be read, “if #T = 256 OR if #T = 128 OR if #T = 64 then J:ump . . .”. In other words, if #T equaled any one of the three numbers, the program would find a “true” and J:ump. Neat! But, you can’t do it the other way, with a JN: instruction to execute on a “false,” because the “N” looks at the M:atch register, not at the conditionals.

You can get “logical ands” by multiplying the conditionals:

T(#T=100)*(#U=200)*(#V=50):ALL THREE

This statement would be read: “if #T = 100 AND if #U=200 AND if #V=50 then T:ype ALL THREE”.

At last, the BUG. (A friend says that micros are too small to have bugs. She claims that they have fleas!) Right there on page 31 the Primer tells us that the computer “ignores” remarks. Although that may be accurate in the linguistic sense, it’s not so in the operative sense. In line 1150 in the Composer program the remark set off by a “[” MUST be typed without spaces. It seems that the [ turns any intervening spaces into significant space and, therefore, part of the accept buffer. Ditto for other commands. I don’t know if it’s a bug or a flea — I know it’s a bear to figure out! (Atari’s internal manuals even have it wrong!) Be safe, don’t use brackets when in doubt.

50 R:PILOT COMPOSER
60 R:ANTIC:, VOL 1 # 4
70 R:
100 R: INIT
100 *INIT
120 R:
130 C:$NOTEVALUEB=
140 C:$PLAYVALUES=
150 C:$END=!
155 R: REMEMBER THE SPACE BETWEEN EACH SET OF CHARACTERS
160 C:$GOODNOTES=C D E F G A B 0
170 C:$GOODDURATION=1 2 4 8 S 0
180 C:$NOTETABLE=C. 1/ D. 3/ E. 5/ F. 6/ G. 8/ A. 10/ B. 12/ O. 0/ 1. 1/2. 2/4. 4/ 8. 8/ S. 16/
300 R: FILE
310 *FILE
320 R:
330 T: ENTER DEVICE TO SAVE MUSIC ON
340 T:D=DISK, C=CASSETTE
350 A:$D
360 R:NEXT, CHECK TO SEE IF CASSETTE
370 M: C
380 CY:$FILESPEC=C:
390 JY:$FILEDONE [IF CASB JUMP OUT
400 M: D
410 TV: ENTER FILE NAME
420 AY:$FILE    [GET FILE NAME
430 CY:$FILESPEC=$D:$FILE
440 TN:I DON'T KNOW THAT DEVICE
450 JN:*FILE
460 *FILEDONE
470 T:} [ESC-CTRL-CLEAR .. CLEARS SCREEN
500 R: INSTRUCTIONS
510 *INSTRUCTIONS
520 R:
530 T:
540 T:NOTES ARE: C D E F G A B
550 T:      AND 0 FOR OFF
560 T:
570 T:DURATIONS ARE:
580 T:      1=WHOLE      2=HALF
590 T:      4=QUARTER    8=EIGHTH
600 T:      S=SIXTEENTH  0=NONE
610 T:
620 T: ENTER & TO QUIT
630 T:
700 R: ENTER
710 *ENTER
720 R:
730 C:#A=#A+1
740 POS:1,12
750 T:ENTER 4 NOTES + DURATION FOR CHORD #A [SPACE, ESC-CTRL-LEFT
760 POS: 17, 15 1450
770 A:$NOTES
780 M:&
790 JY:*ENDER
800 EY:
810 U:*CHECKNOTES
820 SO:20 [BEEP ON COMPLETION
830 PA:7
840 SO:0
850 WRITE(#A=10):$FILESPEC,$PLAYVALUES
860 C(#A=10):#A=0
870 J:*ENTER
900 R:      ENDER
910 *ENDER
920 R:
930 C:$PLAYVALUES=$PLAYVALUES!
940 WRITE:$FILESPEC,$PLAYVALUES
950 CLOSE:$FILESPEC
960 T:
970 T:SAVED IN FILE $FILESPEC
980 T:
990 T:SESSION ENDED
1000 E:
1100 R:  CHECKNOTES
1110 *CHECKNOTES
1120 R:
1130 A:=$NOTES [MOVE $N. TO ACCEPT
1140 MS:, [MATCH ON 1ST BLANK
1150 A:=$RIGHT!/[ADD/,MOVE TO ACCEPT
1160 C:#C=0 [SETS NOTE COUNTER TO O
1170 C:*NOTEVALUES=
1180 C:#G=0
1190 *LOOP
1195 R: TWO RIGHT ARROWS AND COMMA
1200 MS:,    [SKIP 2 SPACES TYPE ESC-CTRL-R. ARROW
1210 CN(#G=0):$PLAYVALUES=$PLAYVALUES$NOTEVALUES
1220 POSN(#G=0) :2,22
1225 R: 38 BLANKS UP ARROW NEXT LINE
1230 TN(#G=0): [ESC-CTRL-UP
1240 EN:
1250 MS:$RIGHT[MATCH W/O 1ST LETTER
1260 C:$SAVE=$MATCH [SAVE ALL
1270 A:=$LEFT [$L. HAS BLANK+LETTER
1275 R: RIGHT ARROW & UNDERLINE NEXT LINE
1280 MS:_ [SKIP BLANK & LETTER
1290 R:*LEFT HAS THE LETTER WE NEED
1300 C:$NDTE=*LEFT
1310 U:*TRANSLATE
1320 A:=$SAVE [PUT ALL IN BUFFER
1330 J:$LOOP
1400 R: TRANSLATE
1410 *TRANSLATE
1420 R:
1430 C:#C=#C+1
1440 E(#C=7):
1450 A(#C<5):=$GOODNOTES
1460 A(#C=5):=$GOODDURATION
1470 M:$NOTE
1480 POSN:2,22
1490 TN: ERROR IN THIS VALUE: $NOTE
50 R:PILOT PLAYER
60 R:ANTIC, VOL 1, # 4
70 R:
80 R:
300 R: FILE
310 *FILE
320 R:
330 T:ENTER DEVICE TD PLAY MUSIC FROM
340 T:D=DISK, C=CASSETTE
350 A:$D
360 R:NEXT, CHECK TO SEE IF CASSETTE
370 M: C
380 CY:$FILESPEC=C:
390 JY:$FILEDONE [IF CASS JUMP OUT
400 M: D
410 TY: ENTER FILE NAME
420 AY:$FILE [GET FILE NAME
430 CY:$FILESPEC=$D:$FILE
440 TN:I DON'T KNOW THAT DEVICE
450 JN:*FILE
460 *FILEDONE
470 T:} [ESC-CTRL-CLEAR .. CLEARS SCREEN
1000 R: TEMPO & PLAY
1010 R:
1020 R: TEMPO
1030 *TEMPO
1040 T:} [ESC-CTRL-CLEAR CLEARS SCREEN
1050 POS:9,5
1060 T:PLEASE ENTER A TEMPO
1070 T:
1080 T:          256 = Adagio
1090 T:          128 = Andante
1000 T:           64 = Allegro
1110 POS:17,11
1120 *RESTART
1130 A:#T
1140 J(#T=256)+(#T=128)+(#T=64):*READ
1150 T:PLEASE ENTER NUMBER AGAIN
1160 J:*RESTART
1170 R: READ
1180 *READ
1190 T:
1200 T:       PLAYING FILE $FILESPEC
1210 READ:$FILESPEC,$PLAYVALUES
1220 R:THIS DEMOS WORD PARSING
1230 *LOOP1
1240 C:#N=0
1250 *LOOP2
1260 C:#N=#N+1
1270 A:=$PLAYVALUES
1275 R:NEXT LINE ESC-CTRL-LEFT THEN UNDERLINE
1280 MS:_
1290 JN:*READ
1300 C:$PLAYVALUES=$RIGHT
1310 A(#N=1):#A=$LEFT
1320 A(#N=2):#B=$LEFT
1330 A(#N=3):#C=$LEFT
1340 A(#N=4):#D=$LEFT
1350 A(#N=5):#L=$LEFT
1360 A:=$LEFT
1370 M:!
1380 EY:
1390 J(#N<5):*LOOP2
1400 SD:#A#B#C#D
1410 PA:#T/#L
1420 J:*LOOP1
1500 R:SET G FLAG FOR BAD NOTE
1510 CN:#G=1
1520 EN:
1530 A(#C=6):=$NOTE
1540 M(#C=6):!
1550 EY(#C=6):
1560 POSN(#C=6):2,22
1570 TN(#C=6):TOO MANY VALUES: *NOTE
1580 CN(#C=6):#G=1
1590 EN(#C=6):
1600 POS(#C>6):2,22
1610 T(#C>6):TOO MANY VALUES:#NOTE
1620 C(#C>6):#G=1
1630 E(#C>6) :
1640 A:=$NOTETABLE
1650 MS:$NOTE.
1660 A:=$RIGHT
1670 MS:/
1680 C:$NOTEVALUES=$NOTEVALUES$LEFT
1690 E:
ANTIC v1.5 / DECEMBER 1982 / PAGE 38

PILOT YOUR ATARI

Holiday Trees

by KEN HARMS

Add to your holiday pleasure by decking out these cybernetic trees using this PILOT program. It comes complete with colored lights, a scrolling message, and Jingle Bells in one-part harmony. To do this we will use some innovative techniques that will expand your understanding of PILOT programming.

Let’s wander through the listing. After the title lines, we find a J:ump command at line 50. As you’ll see, we U:se *PARSE, *COLORS, and *LLOOP over and over as the program operates. Each time PILOT hits a U:se or J:ump command, it goes to the first instruction (in this case, line 1) and reads every line until it finds the required module name. Putting often-used modules near the front of the listing makes the program run faster. PILOT is fast. Even putting the modules at the end of the 225 lines of this program did not noticeably slow down the song, but this programming concept makes it run even faster.

Now J:ump to *DRAWTREES (lines 1000-1540). This module uses a mirror-image concept to draw two trees for nearly the price of one. Notice that the first tree is drawn at X=-40, Y=32 (lines 1050-1070) and the second at X=40, Y=32 (lines 1080 & 1090). This means that the Y positions in both trees are the same while the X positions differ by only the sign. As a result, we can draw in the same location in both trees by using positive and negative values of .the same number for the X position.

We use this concept to draw the stars and balls with a single position and *MIRRORSTAR and *MIRRORBALL modules (lines 2100-2160 and 2400-2460). The C:ompute instruction in line 2140 changes the sign of #X by multiplying it by -1. Simple and neat!

Back to the *TREE module. PILOT graphics uses only four colors. Although it calls these RED, BLUE, YELLOW and ERASE, PILOT really looks at a memory location each time it draws in a PEN color to see what color should be used. Normally, of course, it finds a number in BLUE which means blue. In line 1650, we force a different number into location 708 to tell PILOT that we want it to draw in green whenever it hits a BLUE command. Line 1760 sets the RED pen to brown. Location 709 controls YELLOW and 711 the ERASE commands. You might want to experiment (or refer to ANTIC #3 or Atari’s BASIC Manual) to see how these “registers” work.

After we finish drawing and decorating the trees, we end up at line 1530, which C:omputes a string into the $MESSAGE variable. I had to double space the message because the A:ccept command, used later in the *PARSE module, automatically inserts blanks at the start and end of each string. At present, there doesn’t seem to be a good way around this restriction, but we end up with a nice message anyway. Although the printer doesn’t show it, an ESCAPE character is placed between each word to preserve word spacing. This is necessary because A:ccept also condenses all multiple spaces to single spaces. The ESCAPE character will not print the message: you enter it by pressing the ESCAPE key twice.

You’ll probably want to enter your own message. Just type [space] [ESC] [space] between each word and two ESC’s at the end. Also, keep the message less than 255 letters long.

When finished drawing the trees, we J:ump to *MAINLOOP (lines 600-699). This module is the workhorse, it plays the song, calls for the message and color changes. It’s rather long but really simple to type in. All the *LLOOP commands are on multiples of three — just type it once and use Atari’s wonderful screen editor to change the line number. Ditto for the SO:ound and PA:use commands.

*MAINLINE does one other important thing. Since the program doesn’t use any keystrokes, the ATARI would soon begin changing screen colors. The C:ompute in line 688 puts a 0 in location 77 to tell the computer that a key has been pressed even when none was. This delays the “attract” mode each time through the loop.

The next module, *LLOOP, simply calls *PARSE and *COLORS. Last issue covered breaking (“parsing”) strings into individual characters. That’s what the *PARSE module does. As you type it, remember the two right arrows in line 150 and 37 in line 180. The arrows tell the MS: command to skip a character for each arrow before looking for a M:atch.

After skipping 37 characters in line 180, the MS:$RIGHT in line 190 forces the first 37 letters into the $LEFT string which we T:ype in line 210. That’s the billboard section of the message. By repeatedly stripping off the first character and adding it to the end of the message, we make the words march across the text window at the bottom of the graphic screen. Oh yes, C:@B656? That’s a memory location which tells PILOT to T:ype the message on the second line of the text window. Without that, each message would T:ype on a different line and would scroll off the top. (Just for fun, the lines are numbered through 3.)

Although *PARSE is busy, *COLORS (lines 300-400) is a speedy devil too. By C:omputing different values for location 709, *COLORS changes the color in the YELLOW pen. This flashes red, blue, brown, and yellow in the stars and balls.

To close, let me answer two questions. How do I get PILOT to number the modules in different series? Simple. As I build a program, each module is stored in a different disk file. After all modules are debugged, each is LOADed into memory and RENumbered in a number series which doesn’t overlap with any other module. It’s then SAVEd, memory NEWed and the next module loaded. After all are RENumbered, all are LOADed into a complete program and SAVEd in a different file.

Last, how do I get those big letters in the R:emarks? Just enter a control N (a bar symbol) right after the colon.

Best wishes for a happy holiday season watching your cybernetic trees!

1 R:
10 R:CHRISTMAS TREES
20 R:
30 R: ANTIC, VOLUME 1,
40 R:
50 J:*DRAWTREES
100 R:
110 R: PARSE
120 R:
130 *PARSE
140 A:=$MESSAGE
150 MS:,
155 R: LINE 150 IS 2 RIGHT ARROWS AND COMMA
160 MS:$RIGHT
170 A:*MESSA6E=*MATCH*LEFT
180 MS:,
185 R: LINE 180 IS 37 RIGHT ARROWS AND COMMA
190 MS:$RIGHT
200 C:@B656=1
210 T:$LEFT
220 E:
300 R:
310 R: COLORS
320 R:
330 *COLORS
340 C:#B=#B+1
350 C(#B=1):@B709=146
360 C(#B=2):@B709=66
370 C(#B=3):@B709=26
380 C(#B=4):@B709=18
390 CC#B=4):#B=0
400 E:
500 R:
510 R: LLOOP
520 R:
530 *LLOOP
540 U:*COLDRS
550 U: *PARSE
560 S0:0
570 E:
600 R:
601 R: MAINLOOP
602 R:
603 *MAINLDOP
604 U: *PARSE
605 R: 1ST PARSE TO GET TEXT
606 R: NOTE NUMBER SEQUENCE
607 SO:22
608 PA:16
609 U:*LLOOP
610 SO:22
611 PA:16
612 U:*LLOOP
613 SO:22
614 PA:32
615 U:*LLOOP
616 SO:22
617 PA:16
618 U:*LLOOP
619 SO:22
620 PA:16
621 U:*LLOOP
622 SO:22
623 PA:32
624 U:*LLOOP
625 SO:22
626 PA:16
627 U:*LLOOP
628 SO:25
629 PA:16
630 U:*LLOOP
631 SO:18
632 PA:24
633 U:*LLOOP
634 SO:20
635 PA:8
636 U:*LLOOP
637 SO:22
638 PA:48
639 U:*LLOOP
640 SD:0
641 PA:16
642 U:*LLOOP
643 SD:23
644 PA:16
645 U:*LLOOP
646 SO:23
647 PA:16
648 U:*LLOOP
649 SO:23
650 PA:24
651 U:*LLOOP
652 SO:23
653 PA:8
654 U:*LLOOP
655 SO:23
656 PA:16
657 U:*LLOOP
658 SO:22
659 PA:16
660 U:*LLOOP
661 SO:22
662 PA:16
663 U:*LLOOP
664 SO:22
665 PA:8
666 U:*LLOOP
667 SO:22
668 PA:8
669 U:*LLOOP
670 SO:25
671 PA:16
672 U:*LLOOP
673 SO:25
674 PA:16
675 U:*LLOOP
676 SO:23
677 PA:16
678 U:*LLOOP
679 S0:20
680 PA:16
681 U:*LLOOP
682 SO:18
683 PA:48
684 U:*LLOOP
685 SO:0
686 SO:0
687 PA:64
688 C:@B77=0
689 J:*MAINLDOP
1000 R:
1010 R: DRAWTREES
1020 R:
1030 *DRAWTREES
1040 GR:CLEAR
1050 C:#X=-40
1060 C:#Y=-28
1070 U:*TREE
1080 C:#X=40
1090 U:*TREE
1100 R: NOW PUT SOME STARS ON THEM
1110 C:#X=-40
1120 C:#Y=32
1130 U:*STAR
1140 C:#X=40
1150 U:*STAR
1160 R: OK THAT DID THE TOPS, NOW FOR A FEW MORE
1170 C:#X=-43
1180 C:#Y=16
1190 U:*STAR
1200 U:*MIRRORSTAR
1210 C:#X=-32
1220 U:*STAR
1230 U:*MIRRORSTAR
1240 C:#X=-56
1250 C:#Y=0
1260 U:*STAR
1270 U:*MIRRORBTAR
1280 C:#X=-24
1290 U:*STAR
1300 U:*MIRRORSTAR
1310 C:#X=-65
1320 C:#Y=-20
1330 U:*STAR
1340 U:*MIRRORSTAR
1350 C:#X=-13
1360 U:*STAR
1370 U:*MIRRORSTAR
1380 R: HOW BOUT A FEW BALLS?
1390 C:#X=-43
1400 C:#Y=8
1410 U:*BALL
1420 U:*MIRRORBALL
1430 C:#X=-50
1440 C:#Y=-10
1450 U:*BALL
1460 U:*MIRRORBALL
1470 C:#X=-33
1480 C:#Y=-12
1490 U:*BALL
1500 U:*MIRRORBALL
1510 R: TREES DRAWN, SET UP TYPING, COLOUR AND MUSIC LOOP
1520 R: SPACE BETWEEN EACH CHARACTER, HIT SPACE, ESC, ESC, SPACE BETWEEN EACH WORD AND SPACE, ESC, ESC, SPACE, ESC,ESC AT E
1530 C:*MESSAGE=H A V E A H A P P Y H O L I D A Y !
1540 J:*MAINLOOP
1600 R:
1610 R: TREE
1620 R:
1630 *TREE
1640 R: NEXT LINE SETS "BLUE" PEN TO GREEN
1650 C:@B710=(12*16)+6
1660 GR:PEN BLUE
1670 GR:GOTO #X+28,#Y+5
1680 GR:TURNTO 0
1690 GR:TURN -26
1700 GR:DRAW 63
1710 GR:TURN 232
1720 GR:DRAW 2
1730 GR:FILL 61
1740 R: DRAW THE TRUNK
1750 R: NEXT LINE SETS "RED" PEN TO BROWN
1760 C:@B708=(14*16)+(4)
1770 GR:PEN RED
1780 GR:GOTO #X+4,#Y
1790 GR:TURNTO
1800 GR:DRAW 4
1810 GR:PEN ERASE
1820 GR:GOTO #X-4,#Y-1
1830 GR:PEN RED
1840 GR:FILL 5
1850 E:
1900 R:
1910 R: STAR
1920 R:
1930 *STAR
1940 GR:PEN YELLOW
1950 GR:GOTO #X,#Y
1960 GR:TURNTO 6
1970 GR:DRAW 4
1980 GR:TURN 180
1990 GR:DRAW 2
2000 GR:TURN 90
2010 GR:DRAW 2
2020 GR:TURN 180
2030 GR:DRAW 4
2040 E:
2100 R:
2110 R: MIRRORSTAR
2120 R:
2130 *MIRRORSTAR
2140 C:#X=(#X*-1)+1
2150 U:*STAR
2160 E:
2200 R:
2210 R: BALL
2220 R:
2230 *BALL
2240 GR:PEN YELLOW
2250 GR:GOTO #X,#Y
2260 GR:TURNTO 0
2270 C:#A=0
2280 *STARTBALL
2290 C:#A=#A+1
2300 GR:4(DRAW #A;TURN90)
2310 J(#A<3):*STARTBALL
2320 GR:TURNTO 270;PEN BLUE;DRAW 1
2330 GR:1(TURN 90;PEN YELLOW;DRAW 2;PEN BLUE; DRAW 2)
2340 GR:3(TURN 90;DRAW 1; PEN YELLOW;DRAW 2;PEN BLUE;DRAW 2)
2350 E:
2400 R:
2410 R: MIRRORBALL
2420 R:
2430 *MIRRORBALL
2440 C:#X=(#X*-1)+1
2450 U:*BALL
2460 E:
ANTIC v1.6 / FEBRUARY 1983 / PAGE 50

PILOT YOUR ATARI

SOUNDER

by Ken Harms

Atari PILOT was designed as an easy-to-use language giving “reasonable control of the machines’ capabilities.” PILOT’s SO:und command, however, isn’t very reasonable. This article will show you how to get the great sounds ATARI can produce in spite of PILOT. We’ll also generate a good random number (PILOT’s is almost useless for most purposes), produce animated character graphics, use the joystick to move large cursors, and give you a start on translating BASIC sound effects to PILOT modules.

The ATARI hardware system is the consummate sound computer. Even BASIC lets you use only a small fraction of the hardware’s ability. Normal PILOT lets you use almost none. But, with special C:ompute commands, PILOT can give you everything BASIC can. That special command is “Compute at byte” or, in PILOT, C:@Bxxx. The “xxx” refers to the “address” of a “byte” (or character) of memory. The ATARI uses values in certain “addresses” to turn sounds on or off, set margins, etc. For instance, to tell ATARI that the left margin should be at column 3, we issue a C:@B82 = 3.

Under PILOT, the SO:und command controls only the frequency (pitch) of each voice. The distortion and loudness are set to give a clear, bell-like tone. However, two registers are available to control each of the four voices’ pitch and distortion/loudness. The addresses of these registers are:

FunctionVoice 0Voice 1Voice 2Voice 3
Pitch53760537625376453766
Control53761537635376553767

Numbers used in the pitch register are different from PILOT’s SO:und command. They are especially confusing because larger numbers in the pitch register produce lower tones (opposite of normal PILOT). Luckily for translators, the pitch numbers are the same as BASIC’s sound command.

The real fun starts with the control register. ATARI cleverly uses these values to control both the loudness and distortion of the voices. Different distortion values produce machine guns, laser swords, locomotives, and many other special sounds.

Loudness values run from 0 to 15 (16 values). Distortion values occur every 32 points from 0 to 224 (8 values). To get numbers for the control register, simply add the distortion and loudness numbers you want, and assign them to the appropriate control register with a C:@Bxxx command. (See your BASIC manual for more information on distortion and loudness.) The table below gives the BASIC SOUND command values for each distortion number:

BASIC DISTORTION NUMBER0 2 4 6 8 10 14
CONTROL REGISTER VALUES03264128160192224

So, to produce a sound at pitch 100 with loudness 8 (medium) in distortion 4 for voice 0, execute the following instructions:

C:@B53760=100
C:@B53761=8+64

You could wear out several keyboards typing the various combinations to test them out. To help you pilot your way through sounds, I’ve included PILOT SOUNDER. It’s really much easier to type than it looks, since over half of it repeats and the AUTO command makes it almost automatic. Just type through line 700, then up-cursor to 610, change the *FVOICE0 to *FVOICE1, return, change #Qs to #Ss, etc., through all the FVOICES. Remember to change the C:@B values on the 80 lines. Then do the same for the CVOICEs. You’ll have hours of fun planning sounds for your next PILOT program, or just sounding off — my kids love it!

PILOT SOUNDER displays all eight registers and shows actions between the registers.

Lines 240 and 250 C:ompute values for the trigger (%T8 = 1 if pressed, 0 if not) and the position of the joystick (%J0 — see PILOT Primer, appendix D). I move them into numeric variables so that the values don’t change as we proceed through the program. If the trigger is pressed, *CURSORMOVE blanks the old cursor (line 330), calculates the new position, and prints a new cursor (lines 460-470).

If the trigger was not pressed, *VALUECHANGE calculates a new value for the register where the cursor is. This is tricky. The A:ccept in line 520 puts the row value into the accept register where it’s M:atched against line 530. If the cursor is in column #2 (pitches), line 540 jumps to a frequency (pitch) calculator for voice 0, 1, 2, or 3, depending on the match. Line 570 does the same thing for control values if the cursor was in column 3. See the PILOT Primer, pages 64 and 65 for more data on the JM: command. The *CVOICE modules use a little modulo math to calculate the distortion and loudness values stored in each register. They then call *FACTOR which increases or decreases these values based on the joystick position. Note that loudness values between 16 and 32, inclusive, are not allowed — in essence, we’re using a base 16 (hexidecimal) counting system.

Now look at that long condition in line 210. When you ADD conditions, it’s the same as “or-ing” them. That line says “if J0 = 0 or if J0 = 5 or if J0 = 6 or if J0 = 10 (any one of them) J:ump to *SENSE.” Multiplying conditions [(J0 = 0)* (J0 = 5). . .] ANDs them and requires all to be true before the statement is executed.

SPECIAL EFFECTS presents a few simple sounds and graphics. Jackhammer was inspired by the ATARI Connection, Volume 1, Number 2 (which has 10 other neat sounds for ambulances, etc., in BASIC). Jackhammer C:omputes address 84 to set the cursor on row 8 and then address 82 to set the left margin on column 14. If the margin hadn’t been changed, you’d have to use a POS:ition command before each T:ype command in *PICTURE — a lot of work! The neatest trick occurs on lines 1110 and 1150 which uses one of ATARI’s many internal clocks to generate a semi-random number to control the length of the PA:use. The random number generated by the ? is just too big (+32768 to -32768) for most purposes. Address 20 always contains a number between 255 and 0 — and counts down every 60th of a second. Interestingly, the sound registers (and many other locations) are “read-only” registers which also contain random numbers between 0 and 255. They are even better for this purpose since they are more random than the count-down clock in address 20.

Jackhammer illustrates a simple counter to replace BASIC’s FOR/NEXT loop. Here’s how the two languages compare:

BASIC
For Z = 0 to 15
  program . . .
Next Z
  more program

PILOT
C:#Z = 0
*LOOPNAME
  program . . .
C:#Z=#Z+1
E(#Z=15):
J:*LOOPNAME
  more program

PILOT uses more lines. It also runs much faster than BASIC — you’ll probably have to slow down the BASIC routines you code.

The *BOUNCING BALL and *LIGHTNING modules were translated from Jerry White’s excellent MUSIC LESSONS (available from Swifty Software — the package is jam-packed, two-sided disk in BASIC with many more special effects, player pianos, etc., in a tutorial format). The ball translation shows how to handle non-integer loops (i.e., a FOR /NEXT loop using steps or values which are not whole numbers). I just multiplied them up to integers, as well as all values used for pitches, etc. Here’s how it was done:

BASIC
For Y = 22 to 20 Step -0.5 
  program 
NEXT Y 

PILOT
C:#Y=22*2
*BALL1
  program
C:#Y=#Y-1
J(#Y>20):*BALL1
E:

Since there are 24 steps of 0.5 between 22 and 10, and 24 steps of 1 between 44 and 20, the loops are equivalent.

Throughout SPECIAL EFFECTS, I used numeric variables for register addresses rather than type them in each time (see *REGISTERS).

Another good source for special effects is Educational Software’s TRICKY TUTORIAL #10 which codes about 50! As always, the most satisfying source is your imagination . . . assisted by PILOT SOUNDER!

100 R: ***** PILOT SOUNDER *****
110 R:
120 R: ANTIC VOL 1
130 R: K. W. HARMS
140 R: NO. 6
150 *MAINLINE
160 R:
170 U:*STARTUP
180 R:
190 *SENSE
200 R:
210 J(%J0=0)+(%J0=5)+(%J0=6)+(%J0=10):*SENSE
220 R:JUMP TO SENSE IF JOYSTICK IDLE
230 R: OR ON DIAGONAL
240 C:#T=%T8 [SENSE TRIBGER ON JOYSTICK
250 C:#J=%J0 [SENSE JOYSTICK POSITION
260 U(#T=0):*CURSORMOVE [TRIG PRESSED
270 U(#T=0):*VALUECHANGE [NO PRESS
280 J:*SENSE [WORK DONE, SENSE AGAIN
290 R:
300 *CURSORMOVE
310 R:
320 POS:(#C*10)-5,#R+1
330 T:          [10 BLANKS
340 C(#J=4):#C=#C-1 [MOVE LEFT
350 C(#J=8):#C=#C+1 [MOVE RIGHT
360 C(#J=1):#R-#R-5 [MOVE UP
370 C(#J=2):#R=#R+5 [MOVE DOWN
380 R:CALCULATE WRAPAROUNDS
390 R:ONLY COLUMNS 2 & 3 ARE OK
400 R:ONLY ROWS 5,10,15 & 20 ARE OK
410 C(#C=1):#C=3 [TOO LEFT, GO RIGHT
420 C(#C=4):#C=2 [TOO RIGHT, GO LEFT
430 C(#R<5):#R=20[TOO FAR UP, GO DOWN
440 C(#K>20):#R=5[TOO FAR DOWN, GO UP
450 R:PRINT CURSOR IN NEW POSITION
460 POS:(#C*10)-5,#R+1
470 T:^^^^^^ [6 REVERSE SHIFT *S
480 PA:15 [SLOW DOWN FOR HUMANS
490 E:
500 R:
510 *VALUECHANGE
520 A:=#R[PUT ROW # INTO ACCEPT REG.
530 M:5,10,15,20
540 JM(#C=2):*FVOICE0,*FVOICE1,*FVOICE2,*FVOICE3
550 R:LINE ABOVE JUMPS ON VALUES
560 R:OF ROWS IN THE ACCEPT REGISTER
570 JM(#C=3):*CVOICE0,*CVOICE1,*CVOICE2,*CVOICE3
580 R:SAME FOR CONTROL VALUES
590 E:
600 R:
610 *FVOICE0
620 C(#J=1):#Q=#Q-1 [LOWER VALUE
630 C(#J=2):#Q=#Q+1 [HIGHER VALUE
640 C(#Q>255):#Q=0  [WRAPAROUND
650 C(#Q<0):#Q=255  [DITTO
660 POS:(#C*10)-5,#R
670 T:   #Q  [REM IS SPACE HOLDER
680 C:@B53760=#Q [VALUE INTO REG
690 E:
700 R:
710 *FVOICE1
720 C(#J=1):#S=#S-1 [#R & #T WERE
730 C(#J=2):#S=#S+1 [ALREADY USED
740 C(#S>255):#S=0  [WRAPAROUND
750 C(#S<0):#S=255  [DITTO
760 POS:(#C*10)-5,#R
770 T: #S [REM IS SPACE HOLDER
780 C:@B53762=#S [VALUE INTO REG
790 E:
800 R:
810 *FVOICE2
820 C(#J=1):#U=#U-1 [LOWER VALUE
830 C(#J=2):#U=#U+1 [HIGHER VALUE
840 C(#U>255):#U=0  [WRAPAROUND
850 C(#U<0):#U=255  [DITTO
860 POS:(#C*10)-5,#R
870 T:   #U [REM IS SPACE HOLDER
880 C:@B53764=#U [VALUE INTO REG
890 E:
900 R:
910 *FVOICE3
920 C(#J=1):#V=#V-1 [LOWER VALUE
930 C(#J=2):#V=#V+1 [HIGHER VALUE
940 C(#V>255):#V=0  [WRAPAROUND
950 C(#V<0):#V=255  [DITTO
960 POS:(#C*10)-5,#R
970 T:   #V  [REM IS SPACE HOLDER
980 C:@B53766=#V [VALUE INTO REG
990 E:
1000 R:
1010 *CVOICE0
1020 C:#D=(#W/32) [BASIC'S DISTORTION
1030 C:#L=#W\32 [MODULO IS LOUDNESS
1040 U:*FACTOR
1050 C:#W=#D+#L
1060 POS:(#C*10)-5,#R
1070 T:#D+#L=#W       [SPACE HOLDER
1080 C:@B53761=#W [INTO CNTRL REG
1090 E:
1100 R:
1110 *CVOICE1
1120 C:#D=(#X/32) [BASIC'S DISTORTION
1130 C:#L=#X\32 [MODULO IS LOUDNESS
1140 U:*FACTOR
1150 C:#X=#D+#L
1160 POS:(#C*10)-5,#R
1170 T:#D+#L=#X       [SPACE HOLDER
1180 C:3B53763=#X [INTO CNTRL REG
1190 E:
1200 R:
1210 *CVOICE2
1220 C:#D=(#Y/32) [BASIC'S DISTORTION
1230 C:#L=#Y\32 [MODULO IS LOUDNESS
1240 U:*FACTOR
1250 C:#Y=#D+#L
1260 POS:(#C*10)-5,#R
1270 T:#D+#L=#Y       [SPACE HOLDER
1280 C:@B53765=#Y [INTO CNTRL REG
1290 E:
1300 R:
1310 *CVOICE3
1320 C:#D=(#Z/32) [BASIC'S DISTORTION
1330 C:#L=#Z\32 [MODULO IS LOUDNESS
1340 U:*FACTOR
1350 C:#Z=#D+#L
1360 POS:(#C*10)-5,#R
1370 T:#D+#L=#Z       [SPACE HOLDER
1380 C:@B53767=#Z [INTO CNTRL REB
1390 E:
1400 R:
1410 *FACTOR
1420 C(#J=1):#L=#L-1 [LOWER VALUE
1430 C(#J=2):#L=#L+1 [HIGHER VALUE
1440 C(#L>15):#D=#D+1 [15 IS HIGHEST
1450 C(#L>15):#L=0 [LOUDNESS LEVEL
1460 C(#L<0):#D=#D-1 [0 IS LOWEST
1470 C(#L<0):#L=15 [WRAPAROUND
1480 C(#D>7):#D=0 [LEVEL 7 IS HIGHEST
1490 C(#D<0):#D=7 [LEVEL 0 IS LOWEST
1500 C:#D=#D*32
1510 E:
1520 R:
1530 *STARTUP
1540 GR:QUIT [CLEAR SCREEN
1550 C:@B752=1 [TURN OFF CURSOR
1560 POS:2,3
1570 T:   VOICES   PITCH # CONTROL #
1580 POS:2,4
1590 T:   VOICE 0    53670     53761
1600 POS:2,9
1610 T:   VOICE 1    53672     53763
1620 POS:2,14
1630 T:   VOICE 2    53674     53765
1640 POS:2,19
1650 T:   VOICE 3    53676     53767
1660 C:#R=5  [SET UP ROW FOR START
1670 C:#C=2  [SET UP COLUMN FOR START
1680 POS:(#C*10)-5,#R+1 [START POS
1690 T:^^^^^^ [6 REVERSE SHIFT *S
1700 E:
10 R: SPECIAL EFFECTS
20 R: ANTIC VOL 1, NO. 6
30 R:
40 U:*RESISTERS
100 U:*BOUNCINGBALL
110 U:*JACKHAMMER
120 U:*LIGHTNING
490 E:
500 R:
510 *BOUNCINGBALL
520 C:#Z=6[NUMBER OF BOUNCES
530 *BALL1
540 C:#Y=22*2
550 *BALL2
560 POS:18,(#Y/2)+1
570 T: [SPACE HOLDER
580 POS:18,:#(Y/2)
590 T:'  [CTRL
600 C:@B#A=(#Y*10)/2
610 C:@B#B=224+((#Y/4)-5)
620 C:#Y=#Y-1
630 J(#Y>10):*BALL2
640 PA:15
650 *BALL3
660 POS:18,(#Y/2)-1
670 T: [SPACE HOLDER
690 POS:18,(#Y/2)
690 T:' [CTRL .
700 C:@B#A=(#Y*10)/2
710 C:@B#B=224+((#Y/4)-5)
720 C:#Y=#Y+1
730 J(#Y<(22*2)):*BALL3
740 C:#Z=#Z-1
750 C:@B#A=0
760 C:@B#B=0
770 J(#Z>0):*BALL1
780 E:
1000 R:
1010 *JACKHAHMER
1020 ER:QUIT
1030 C:@B752=1 [TURN OFF CURSOR
1040 C:#Z=0
1050 U:*PICTURE
1060 *JACKHAMMER1
1070 C:@B#A=103
1080 C:@B#B=96+14
1090 POS: 16,17
1100 T: [CTRL S
1110 PA:@B20
1120 SO:0
1130 POS:16,17
1140 T: [TYPE A SPACE
1150 PA:@B20/7
1160 C:#Z=#Z+1
1170 E(#Z=15):
1180 J:JACKHAMMER1
1190 *PICTURE
1200 C:@B84=8 [SETS ROW
1210 C:@B82=14[SETS MARGIN
1220 T:      [BLANK TO MOVE TO MARGIN
1230 T:      [6 CTRL N
1240 T:    [CTRL V, BLANK, CTRL B
1250 T:    [SAME AS 1180
1260 T:    [SAME AS 1180
1270 T:    [SAME AS 1180
1280 T:    [CTRL B, BLANK, CTRL F
1290 T:   [CTRL B, CTRL V
1300 T:      [3 BLANK, REVERSE BLANK
1310 T:     [3 BLANK, CTRL S
1320 C:@B82=2 [RESETS MARGIN
1330 POS:2,18
1340 T:
1350 R:LINE ABOVE IS 76 REVERSE SPACES
1360 E:
1500 R:
1510 *LIGHTNING
1520 C:#X=-70
1530 GR:CLEAR [HERE TO TURN ON SCREEN
1540 T:
1550 T: NEVER TWICE IN THE SAME PLACE, EH?
1560 R:
1570 *LIGHT1
1580 U:*STRIKE
1590 U:*SOUND
1600 C:#X=#X+14
1610 PA:60
1620 J(#X<75):*LIGHT1
ANTIC v2.1 / APRIL 1983 / PAGE 62

PILOT YOUR ATARI

AUTOPILOT

by Ken Harms

In our grand tradition, we again present you avid Pilots with something from the wide blue yonder — a previously unreported program to make your flights of fancy easier. Our Auto Pilot is a self-loading menu program that you can put on every Pilot disk. It is so easy to use, even young children can do it — in fact, that’s why I designed it and they like the animated face that tells them what to do. Nevertheless, the menu is sophisticated and makes use of previously unpublished aspects of Pilot that allow it to call other programs from itself.

With Auto Pilot on your disk, powering up the ATARI automatically loads a short program which draws a face and animates its mouth to form the words “Please wait half a minute.” That program loads another program which displays the menu (the first 20 files on the disk, each with a “program number”) and animates the mouth to ask “Please type number for the program you wish to run.” When the number, followed by a [RETURN], is entered, the chosen program is automatically loaded and run. When the operator wishes to change programs, [SYSTEM RESET] restarts the menu programs.

The system requires no changes to your existing Pilot programs. If the three files we will create are on the disk, they will run any Pilot programs automatically. After you’ve built the three files, using this article, a process which should take only an hour or two, you merely copy them using DOS option O to any disks you wish, which takes only a few minutes.

Every Pilot Your Atari tries to present a tutorial in the form of useful programs. This article demonstrates the Pilot variable table and the use of one program to LOAD and RUN another. Tape users could find these concepts useful but won’t be able to use the system. (Although it isn’t possible to make an efficient tape-based menu system, the Pilot Primer presents one which you may try.)

Start with an empty, formatted disk. The first program is PUTTER. Power up under BASIC and enter PUTTER. SAVE the program under the name PUTTER and RUN it to produce an AUTORUN.SYS file on the new disk. If the number check doesn’t check, examine your typing and redo. Finally, test the AUTORUN.SYS program by powering off and on. You should hear DOS booting and then see several valid Pilot commands displayed with error messages. That’s okay since you have the BASIC cartridge loaded and it won’t recognize Pilot commands.

So far, we’ve typed in a program called PUTTER which runs under BASIC to produce a “binary file” under the name AUTORUN.SYS. A binary file is a string of numbers which the ATARI will read as an Assembly Language program. Since the program is in the name AUTORUN.SYS, it will be read and executed each time the computer is powered up (see DOS manual for more information). Part of this Assembly Language program fools the ATARI into accepting data from the disk as if they came from the keyboard, and attempting to execute them under direction from the cartridge. This program includes five Pilot commands. You saw them when you tested it under BASIC. First, a one is C:omputed into position 580. That tells the ATARI to reboot DOS whenever the RESET button is pushed. Next, the screen colors are changed to turn the borders red and the letters to blue so that the “Ready” prompt won’t display while the menu programs are being loaded. Last, two instructions load a program called MENU.SYS and run it.

The AUTORUN.SYS program will load any Pilot program which has been saved in a file called MENU.SYS. You can SAVE your favorite program under that name and it will load and execute whenever the ATARI is booted or RESET is pushed. Be sure to add a GR:QUIT or other GR:aphic call to the front of your program to reset the screen colors.

On to the next task. Pull out the BASIC cartridge and insert PILOT. When you turn power back on you’ll get an error 170 since the computer was looking for a file called MENU.SYS and, naturally, didn’t find it. Type in the MENU.SYS program. When you get to the *FACE and later modules, you’ll see some T:ype lines with graphics characters exactly as they appear in the listing, so that the face will appear on the screen as it will appear when the program runs. Now SAVE the program in a file called MENU.SYS. RUN the program to see if it draws a face and moves the mouth. If everything works right it’ll fail with an error 170 since it looks for a file called DIRECT.SYS which you haven’t typed yet.

MENU.SYS includes some interesting commands. Lines 60 and 70 are “C:ompute at byte” instructions. The number following the “B” is an “address” of a character (or “byte”) of memory. The ATARI uses values in certain addresses to control features of the system. The address 752 turns the cursor off (1) or on (0). Location 709 controls the color of text characters. These commands are used later (see lines 2120 & 2130) to control the cursor position.

The next interesting command is the LOAD D:DIRECT.SYS at line 200. When you give a LOAD command from the keyboard, it loads the new program over the old. You then have to type RUN. When a program issues a LOAD command, however, Pilot first NEWs memory, then LOADs the program and proceeds to RUN it. Neat! (At this time, there appears to be no way to overlay programs — aarrgh!)

’Nuff said about MENU.SYS. Except that you should also issue a SAVE D:FACE,1480,2210 command to save the routines which you’d have to type later when you enter DIRECT.SYS.

Onward! We’re ready to enter DIRECT.SYS. Type it in (remembering to enter the control characters in line 280) up to line 1480. LOAD the FACE file to get lines 1480 through 2210 into DIRECT.SYS. Last, type lines 2220 through 2410 (remember control characters in line 2360). SAVE everything in a file called DIRECT.SYS. You can RUN this program to test it and see an animated mouth without a face (the face will be drawn by MENU.SYS). You should see a directory list down the right side of the screen.

Before we get into the details of DIRECT.SYS, let me explain a few design considerations. The whole system is designed to fit the non-typing, limited-reading user. Accordingly, I chose to turn on the red borders to keep interest up. The face is drawn in one program and the list in a second so that the first program will be very short and will load quickly. (If you want a single program, LOAD MENU.SYS then DIRECT.SYS. I numbered the two so that DIRECT.SYS will overlay and erase the unneeded commands in MENU.SYS. Although this will save a few seconds as you transfer files to a new disk, you’ll wait a looong time before you see the list.) The list will include the first 20 files which don’t end in the letters “SYS”. I skip those files since one almost never RUNs them. This keeps unneeded information off the screen.

I chose to present the 20 files and a face rather than more files to make things easy and friendly. The face is a warm welcome to our friends who may still be a little intimidated by the computer. And if you try, you can almost always get the really important files into the first 20. Yes, one could scroll the screen to see more. It’s a feature which would be nice for more experienced users but which may not be so easy for the new guys. If you add one, let me know. Last, the dot between a file name and its extender is omitted so that you can use all 11 letters to make more useful program titles.

Frankly, friends. Pilot is not a good language for menu systems. There is no way to directly manipulate individual characters in a string without adding unwanted spaces, spaces which cannot be included in file names. The 65 lines of code starting at line 800 can be done in about 10 lines in BASIC. (After saying this, some 10-year-old whiz will find a 3-line method next week!)

DIRECT.SYS starts off in *INITIALIZATION by specifying that the variable $FILENAME is filled with 15 characters. This variable must be defined before all others so that it is the first variable in the list of variables kept by Pilot. In essence. Pilot stores all variables in special memory locations beginning at an address which is stored in the “word” located at 178. To Pilot, a word is two adjacent memory cells. It interprets these by multiplying the second value by 256 and then adding the first number. This allows the ATARI to talk to up to 64,000 memory locations. Line 2270 sets the variable #P (pointer) equal to the start of string space.

Each string is stored in the following format:

First 2 bytes  Length of the variable
Next 1 byte    Length of the variable name
Next X bytes   The variable name itself
Next 1 byte    Length of the data
Next y bytes   The data itself

After C:omputing SFILENAME in line 2240, we should find that the address pointed to by word 178 has a value of 27 (the length of the entire item) made up as follows:

ADDRESS ABOVE 178       VALUE
0 -    Length of item   27
1 -    Length of item   00
2 -    Length of name   08
2-10   Name             FILENAME
11-    Length of data   15
12-27  Data             DUMMYSPACEST015

We’re going to manipulate the value of the “length of data” byte to fool Pilot into believing that there are only 13 spaces in the variable. This will cut off the “sectors used” data for each file so that the list is a bit neater. Line 2280, then, adds nine to #P to move that value to the length of data pointer. (I know that the table above says to move 11 bytes to #P. The nine works — perhaps the first variable in the table is pointed to somewhat differently?) Its work done, *INITIALIZATION returns to the main program.

Line 270 sets Auxiliary 1 byte to the value of two meaning “open the disk to read the file directory” (Auxiliary 1 is the equivalent to “aexpl” in the OPEN command described in the DOS Reference Manual). We then begin reading file names. The READ command will send a formatted file name with eight characters (or blanks), three characters (or blanks) for the extender, and three numbers for the number of sectors, into the variable SFILENAME. By A:ccepting SFILENAME, we can search for “FREE SECTORS”, always the last entry in the directory, and for “SYS” (lines 360 & 380). We J:ump to *FINI or to the loop, as appropriate, to skip the “SYS” items. This means that you can’t end a file name in “SYS” (such as MYSYS.ONE) and still get it to show on the menu.

After we’ve found a good filename, line 420 does the magic. By C:omputing the data length byte to equal 13, we cut off the number-of-sectors data in positions 14, 15 and 16 and leave a formatted variable ready for T:yping in line 430 or 440. The extra blank between “#F” and “=” in line 430 compensates for the extra digit in file numbers greater than nine. Be sure to enter the control V before the #F and the control B after $FILENAME; they’ll make a nice box around your list.

After getting your file number, DIRECT.SYS proceeds to read all the files again, skipping SYS files, to count to the number you requested. And the fun begins in *RUNNER at line 920. Basically, our problem is to insert a dot (period) between the file name and its extender, add the“D:” drive designation and then remove all blanks. This is a bear! First, we C:ompute the ASCII values for “D:” into the first two memory locations for the filename (see the BASIC Reference Manual, Appendix C).

Next, we make a space for the dot by moving the last character in the extender (position 13) to position 14, then position 12 to 13, and 11 to 12 (see *EXPANDLOOP). A simple C:ompute at position 11 (line 1170) inserts the dot.

The Atari Operating System requires that a valid file name contain no embedded blanks. Unless a file name is eight characters long, the file name read from disk will contain blanks. Your job, *DELETELOOP, should you care to accept it, is to locate the first blank space in the filename. Starting at line 1240, we inspect the values contained in the memory locations for the file name to see if any contain a blank (ASCII 32). If none do, the program J:umps to *LOADER. If a blank is found, the position is remembered and we move to the *MOVELEFTLOOP. This routine moves the value in position 11 (the dot from line 1170) into the blank space. It then moves the first extender value down, and loops until the entire extender is moved.

After all the moving is done, the program goes to *RUNNER which does only two things. The GR:aphic QUIT clears the screen and restores the borders to their usual color. LOAD loads the program you chose and runs it. Thereafter, any press of RESET will reload the menu programs and let you choose a new program by typing a simple number.

Looking through the string variable table can be a powerful (if complex) tool. One final point: strings are stored in ascending order by occurrence in the program. This means that the first string will have the lowest memory locations and will be pushed downward by later strings.

I hope you’ll find the AUTO PILOT helpful and fun. My four-year-old calls the face “Bugs” — she likes her.

10 R:      MENU.SYS
20 R:AN AUTOMATED MENU SYSTEM
30 R:      PART 1
40 R: ANTIC #7 KEN HARMS
50 R:
60 C:@B752=1 [TURN OFF CURSOR
70 C:@B709=154 [TURNS ON LETTERS
80 U:*FACE
90 T:HI! \
100 U:*OPEN
110 T:PLEASE \
120 U:*PUCKER
130 T:WAIT
140 U:*HALF
150 T:JUST \
160 U:*TIGHT
170 T:A MINUTE.
180 U:*OPEN
190 U:*SMILE
200 LOAD D:DIRECT.SYS
1470 R:
1480 *FACE
1490 POS:2,5
1490 POS:2,5
1500 R: USE CTRL Ps , reverse CTRL
     Ys, and
     CTRL Ys. CTRL F, G,
     & N for mouth .
1510 T       ***
1520 T:    **   **
1530 T:   *       *
1540 T:   * *   * *
1550 T:   *   *   *
1560 T:   *       *
1570 T:   * ***** *
1580 T:   *       *
1590 T:    *******
1600 T:
1610 PA:30
1620 E:
1630 *SMILE
1640 U:*SETXY
1650 POS:7,11
1660 T:*****
1670 POS:7,12
1680 T: [ERASES MOUTH BOTTOM
1690 PA:5
1700 U:*RESETXY
1710 E:
1720 *OPEN
1730 U:*SETXY
1740 POS:7,11
1750 T:*****
1760 POS:7,12
1770 T:*****
1780 PA:5
1790 U:*RESETXY
1800 E:
1810 *TIGHT
1820 U:*SETXY
1830 POS:7,11
1840 R: CTRL U
1850 T:*****
1860 POS:7,12
1870 T: [TYPE 5 SPACES
         AFTER COLON
1880 PA:5
1890 U:*RESETXY
1900 E:
1910 *PUCKER
1920 U:*SETXY
1930 POS:7,11
1940 T:*****
1950 POS:7,12
1960 T:*****
1970 PA:5
1980 U:*RESETXY
1990 E:
2000 *HALF
2010 U:*SETXY
2020 POS:7,11
2030 T:*****
2040 POS:7,12
2050 T:*****
2060 PA:5
2070 U:*RESETXY
2080 E:
2090 R:
2100 *SETXY
2110 R: STORES CURSOR POSITION
2120 C:#X=@B85 [GET X COORDINATE
2130 C:#Y=@B84 [GET Y COORDINATE
2140 E:
2150 R:
2160 *RESETXY
2170 R: RESTORES CURSOR POSITION
2180 C:@B85=#X
2190 C:@B84=#Y
2200 E:
2210 R:
Listing omitted for now
ANTIC v2.4 / JULY 1983 / PAGE 24

PILOT YOUR ATARI

Lines Away

by KEN HARMS

PILOT offers some built-in program development tools which our other-lingual friends envy. But one feature I’ve always missed is the ability to delete more than one line at a time. This month we present a short program which solves that problem and demonstrates yet another interesting feature — reading the screen.

Type in DELETER and save it on tape or disk. Suppose you’ve been programming away, and suddenly find yourself with a number of unneeded lines. Make sure you have no line numbers above 9950, then LOAD DELETER and issue the following command:

J:*DELETER

You’ll be asked to give the starting line number you wish deleted, the ending number, and the increment by which lines are numbered. Enter these, press RETURN and DELETER will erase lines at the rate of 100 per 8 seconds. If lines are numbered unevenly, enter an increment of one and all lines will be deleted. (It may be slightly faster if you RENumber such a program before LOADing DELETER. This puts all lines on the same increment so fewer numbers are deleted.)

When you’re all done, SAVE your program without the DELETER lines. See “PILOT Primer”, Appendix B, page 151 (disk) or 160 (tape) to find out how to save part of a program.

With all that introduction over, let’s find out how the thing works! The first part of the program is devoted to clearing the screen (the ESC-SHIFT-CLEAR character in line 9953), T:yping messages and getting the line numbers, and increment (lines 9954 through 9975). Each time a variable is A:ccepted, we check to see that it fits the data we need. For instance, the starting number (#S) cannot be less than zero or larger than 9999 (the highest line number allowed by PILOT). The ending number (#E) must be larger than the starting number (lines 9969 and 9970). Finally, lines 9974 and 9975 make sure that the increment is not less than or larger than 100. The 100 maximum is arbitrary, you can change it to be anything you wish.

Those double sets of conditions in parentheses (lines 9962, for instance) mean if either the condition in the first set OR the condition in the second set is true, execute the command. If the conditions are multiplied, the statement will execute only if condition one AND condition two are both true. To interpret conditional commands, PILOT first evaluates all the conditions. It substitutes a one for each true condition and a zero for each false one. It then does the math linking the commands and if the result is greater than zero, executes the command. You can get fancy with all the signs (a pair of conditions separated by a minus will execute only if the first is true AND the second is false). Experimentation is the rule.

So on to the fun part. The *PRINTLINES module clears the screen and then prints numbers beginning at the starting number, incremented as directed and ending at the last number to be deleted or after 20 lines have been printed. *DELETE types a J:ump command, then POS:itions the cursor to the top of the screen. Line 9990 is the magic incantation.

In PILOT, values are placed into specific memory locations with the C:@Bn = x command. We read this as “C:ompute at byte n the value x.” A byte is computerese for a character. The “n” is the (decimal) address of the byte and “x” is the value we will store in that address. The ATARI uses values at different addresses to control different machine functions such as sounds and colors.

Line 9990 C:omputes a 13 into address 842. The 13 tells the Atari “when you stop, read your next instruction from the screen rather than the keyboard.” Redirecting the flow of information in and out of the computer is easy on the ATARI because it employs a good “operating system”, one of the first such systems on the market. So, right after printing a set of line numbers and a J:ump command, and after telling the ATARI to read the screen, line 9991 E:nds the program. And what do you know, the old operating system reads those numbers, thinks they’re the same as typing a number without a command on the keyboard and erases each line! When it gets to the bottom of the list it reads a J:*RESTART command and executes it.

Now the first thing *RESTART does is C:ompute a 12 into 842. You’re right, the 12 tells the ATARI to turn off the screen reading and start reading the keyboard again. We then check to see if all line numbers have been T:yped and, if not, J:ump to *PRINTLINES to start the procedure all over again.

I left the numbers on the screen to track progress. If you don’t like them, you could insert a C:@B instruction to turn the letters blue. Remember to turn the letters on again with another C:@B or a GR:QUIT.

You can get some real fun from the “842 tango” by using it to modify a program while it turns. Say you want to save a person’s name in a program. Ask for the name in a T:ype / A:ccept set of statements which puts it into a variable we’ll call SINPUTNAME. Then clear the screen, T:ype a C:ompute statement like this:

C:*NAME = $INPUTNAME

Follow this by a J:ump command on the screen, POS:ition the cursor, C:ompute the 13 into 842 and E:nd the program. Remember to use a line number in the compute command but no number on the jump. If you have followed the outline of DELETER for a *RESTART, you can SAVE your new program with the name imbedded in it. I’m sure you’ll find other uses for “the magic of the 842.”

9950 R: PILOT AUTO LINE DELETER
9951 R: ANTIC K. W. HARMS
9952 *DELETER
9953 T:} [CLEAR SCREEN
9954 POS:2,11
9955 T:   P I L O T  D E L E T E R 
9956 *REENTER
9957 T:
9958 T:ENTER LINE NUMBERS TO BE DELETED:
9959 *NEWSTART
9960 T:START  \
9961 A:#S
9962 T(#S<0)+(#S>9999):}ENTER NEW START [} IS BELL. TYPE ESC, CTRL, 2
9963 J(#S<0)+(#S>9999):*NEWSTART
9964 *NEWEND
9965 T:END
9966 A:#E
9967 T(#E<0)+(#E>9999):}ENTER NEW END
9968 J(#E<0)+(#E>9999):*NEWEND
9969 T(#S>#E):}START LARGER THAN END
9970 J(#S>#E):*REENTER
9971 *NEWINCREMENT
9972 T:INCREMENT  \
9973 A:#I
9974 T(#I<1)+(#I>100):}ENTER NEW INCREMENT
9975 J(#I<1) + (#I>100) :*NEWINCREMENT
9976 *PRINTLINES
9977 GR:QUIT
9978 C:#L = [Line counter
9979 PCS: 2, 2
9980 *PRINTLOOP
9981 C:#L=#L+1 [Increment line counter
9982 T:#S [Line number to delete
9983 C:#S = #S + #I
9984 J(#S>#E) : *DELETE [Job done
9985 J(#L = 20) : *DELETE [Enough lines
9986 J:*PRINTLOOP
9987 * DELETE
9988 T: J : *RESTART [Command on screen
9989 PCS: 0,0 [Get to top of screen
9990 C:@B842=13 [Set to read screen
9991 E: [Stops, gives control to the screen reader
9992 * RESTART
9993 C:@B842=12 [Set write to screen
9994 T(#S = #E) + (#S>#E) :SQ
9995 E(#S = #E) + (#S>#E) :
9996 J: *PRTNTI TNF.S
9997 R: E N D  O F  P R O G R A M 
ANTIC v2.5 / JULY 1983 / PAGE 24

PILOT YOUR ATARI

REDEFINE CHARACTERS

Cursive letters are one possibility

by KATHY and PHIL BERGH

Exciting rumors are leaking fast from silvery silicon gulch. LOGO has been publicly shown and is now scheduled for release in the fall. Atari has completed designing Super PILOT and has been using it in its Computer Camps. The specs sound great, four turtles, all visible, all graphic modes and much, much morel Although Atari hasn’t yet decided to release Super PILOT for the general public, we’re hopeful. ANTIC will run full reviews on both languages as soon as possible.

ANTIC’s monthly schedule gives us twice as much space for PILOT. Luckily, we’ve found a pair of accomplished programmers to share the work of producing creative, useful PILOT programs each month. With this column we welcome Phil and Kathy Bergh as authors. Kathy is a teacher in Washington state. Together, they wrote the only PILOT program yet accepted by APX. I think you’ll enjoy their work as much as I do. — Ken Harms


We have often wished that ATARI had used a traditional division sign instead of the slash for math computations. Perhaps you would like to have animations on the screen with text. Could your program use French accent marks, German umlauts, or even a whole foreign alphabet? Well, PILOT can give you all of these and more, if you design your own customized characters. We will provide you with an overview of character design and show you how to redesign any characters you wish. This article’s first program changes the capital “L” to cursive form. The second program creates a steam locomotive in place of six graphics characters and animates it. After these, let your imagination run wild!

ATARI’s character set is in Read Only Memory (ROM) and, as the name implies, you cannot change it. You can, however, copy it into Random Access Memory (RAM), change any characters you like, and tell the computer to use your new set instead of the one in ROM. This article designs and uses characters in Graphics Mode 0 (text mode).

Each character in the set can be visualized as an eight by eight grid of light bulbs, each of which can be either “on” or “off.” Each row of the grid is remembered by the computer as one memory byte, so eight bytes are needed to represent the whole grid (one character). The first step in redesigning the set is to color in boxes on small lined graph paper. The colored boxes represent the lighted bulbs. Figure 1 shows our custom letter, a cursive “L” on paper.

The boxes are binary (they are either on or off), but PILOT needs them in decimal notation. The conversion is easy. The numbers across the top of the chart show the decimal value of each column. For the decimal value of each row, add the column values of the filled-in boxes. In the top row, the 4, 2, and 1 column are filled in, so the value of the first byte is 7. Add across each row until you have the value of all rows, These will be the values of the eight bytes making up your custom character.

An even easier way to do this is to use one of the many BASIC utility programs which design characters. They show exactly what the character will look like with screen artifacting and other considerations. Some give the byte value as part of the screen display. Just write the values down.

Figure 1
DECIMAL VALUE OF COLUMNS
1286432168421
DECIMAL VALUE OF BYTES
        7
        15
        124
        12
        63
        109
        57
        0

Next, find the end of the program in the computer’s memory so we can put the new character above it. In Program 1, Line 70 Cromputes a value of #Z which is the memory location where the program ends (@word176) divided by the number of bytes in one K (1024) plus three more K. PILOT stores the end of program in RAM space in the two bytes at address 176. We are used to seeing @B for “at byte”, but in this case it takes two bytes to remember the end of the program, so the “B” is left out and PILOT gets those two bytes and automatically converts them to a two-byte address.

The Operating System requires that the new character set start at a 1K boundary in memory. The #Z variable will point to a boundary because when we divide by 1024, PILOT ignores the remainder, leaving us at the whole number of a 1K boundary. We then add an arbitrary 3K to insure that we are in clear space. At least 1K must be allowed. Using 3K allows room for program expansion. Line 80 multiplies the K value by 1024 to get the address of the first byte of our custom character set.

This new character set address is saved as #Z, #W, and #A (lines 80, 90 and 100). Variables #Z and #W will be used and incremented while #A will be used to reset values.

PILOT looks at the value stored in byte 756 to find the first memory page of the character set that the computer is going to use. In line 110, the pointer to the ROM character set is multiplied by 256 to convert that page value to a byte address (there are 256 bytes in a page), and it is saved as #Y.

And now the magic line! The C:ompute in line 120 puts the address we selected for the custom character set into address 756. From now on, PILOT will look at our new memory space rather than the ROM characters whenever it needs to display a character. Now it’s up to us to give it a new set to display.

Although we could design an entirely new set of 255 characters, it’s much easier to copy ATARI’s regular set and then change just those we need to change. *MOVEIT in lines 140 through 190, copies each of the ROM characters into “our” RAM space. Even if you don’t use all of them, all possible characters (even control graphics and inverse video) must be moved. The loop counter (#X) is set to zero (line 130), the contents of the first byte of the original set (@B#Y) is C:omputed into the new byte address (@B#Z), and #Y, #Z, and #X are each incremented by one. If all 1024 bytes have not been moved, the J:ump at line 190 loops back to copy another value.

Now that the whole set is in RAM, we need to find the character in the set that is to be changed. There is a chart entitled Internal Character Set on page 55 of the ATARI BASIC Reference Manual that shows the order of characters within the ROM character set. Multiplying the value of any character by eight gives the offset of the character into the table, in bytes. Adding this value to the address of the beginning of the new character set (#W) gives the first byte of the character to change (line 200). The Internal Character Set value of capital “L” is 44.

Lines 210 through 350 C:ompute the value we calculated for each row of the cursive “L” in Figure 1 into the spot where “L” was in RAM. The byte address is then incremented, and the next value inserted until all eight values are changed.

Usually, a program would tell the computer to use the new character set after moving the set and inserting the custom characters. We did this in line 120 before the set was moved to give an interesting effect of the letters appearing on the screen as they are moved. Once the program is RUN, the new set is in memory, and the “popping letters” effect is lost. Since PILOT restores the original ROM address to byte 756 after GR:QUIT, LOAD, RESET, and the first WRITE:S in a series, your program must provide a C:ompute @B756 after each occurrence of these commands to remind the computer that we are using a set of our own.

The TRAIN program works just like Program 1 except that the characters [CTRL]—A,S,D,F,G, and H are designed to resemble a train. Typing and retyping further along on the same line, chugs the train across the screen. Note that before each character is changed, the new address pointer must be reset (line 360, etc.) To see the train move again without re-running the program, enter J:*GO.

After typing in the programs and working out a character of your own, you will begin to see what fun this powerful tool for custom character sets can be. Even better, you don’t need to understand it to make it work! To change one character you need only change the Internal Character Set number in line 200 to match the character to be replaced and change the values in lines 210, 230, 250, 270, 290, 310, 330, and 350 to your numbers! You might try making flatcars and boxcars for the train. Other possibilities: Greek, cursive, Japanese and German fonts. Once your imagination is in gear, anything can happen!

We hope you find much fun and many uses for custom character sets.

0 R: PROGRAM 1   CAPITAL L 
5 R:ANTIC AUGUST 1983
7 R: PHIL & KATHY BERGH
10 GR:QUIT [Clear registers if re-running
20 T:        Cursive Capital L
30 T:
40 T:Please wait while the character set is moved.  This takes about 20 seconds.
50 PA:100
60 R:Cursive L poked into capital L
70 C:#Z=@176/1024+3 [New RAM character set pointer K value
80 C:#Z=#Z*1024 [New RAM character set pointer byte value
90 C:#W=#Z [Second new character set pointer
100 C:#A=#Z [Third new character set pointer
110 C:#Y=@B756*256 [Original Character set pointer
120 C:@B756=#A/256
130 C:#X=0 [Set loop counter to 0
140 *MOVEIT
150 C:@B#Z=@B#Y [Copy ROM byte into RAM
160 C:#Y=#Y+1    [Increment ROM and
170 C:#Z=#Z+1    [RAM pointers
180 C:#X=#X+1    [and counter
190 J(#X<1024):*MOVEIT
200 C:#W=#W+(44*8)[OLD ADDRESS+(INTERNAL CHAR SET #)TIMES 8)
210 C:@B#W=7     [Row 1
220 C:#W=#W+1
230 C:@B#W=15    [Row 2
240 C:#W=#W+1
250 C:@B#W=124   [Row 3
260 C:#W=#W+1
270 C:@B#W=12    [Row 4
280 C:#W=#W+1
290 C:@B#W=63    [Row 5
300 C:#W=#W+1
310 C:@B#W=109   [Row 6
320 C:#W=#W+1
330 C:@B#W=57    [Row 7
340 C:#W=#W+1
350 C:@B#W=0     [Row 8
360 T:
370 T:Sample cursive L's:
380 T:
390 T:Lori  Louise  London  Library
0 R:      TRAIN       
5 R: ANTIC AUGUST 1983
7 R: PHIL & KATHY BERGH
10 GR:QUIT [Clear registers if re-running
20 T:           ANIMATED TRAIN
30 T:
40 T:Please wait while the character set is moved.  This takes about 20 seconds.
50 PA:100
60 R:Train cars poked into CTRL A through H.
70 C:#Z=@176/1024+3 [New RAM character set pointer
80 C:#Z=#Z*1024 [New RAM pointer byte
90 C:#W=#Z [Second new character set pointer
100 C:#A=#Z [Third new character set pointer.
110 C:#Y=@B756*256 [Original character set pointer
120 C:@B756=#A/256 [Use RAM set
130 C:#X=0 [Set loop counter to 0
140 *MOVEIT [Copy ROM into RAM
150 C:@B#Z=@B#Y
160 C:#Y=#Y+1
170 C:#Z=#Z+1
180 C:#X=#X+1
190 J(#X<1024):*MOVEIT
200 C:#W=#W+((1+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL A
210 C:@B#W=7 [Back of caboose
220 C:#W=#W+1
230 C:@B#W=4
240 C:#W=#W+1
250 C:@B#W=127
260 C:#W=#W+1
270 C:@B#W=73
280 C:#W=#W+1
290 C:@B#W=73
300 C:#W=#W+1
310 C:@B#W=255
320 C:#W=#W+1
330 C:@B#W=56
340 C:#W=#W+1
350 C:@B#W=16
360 C:#W=#A  [Reset pointer to beginning of RAM set
370 C:#W=#W+((19+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL S
380 C:@B#W=224 [Front of caboose
390 C:#W=#W+1
400 C:@B#W=32
410 C:#W=#W+1
420 C:@B#W=254
430 C:#W=#W+1
440 C:@B#W=146
450 C:#W=#W+1
460 C:@B#W=146
470 C:#W=#W+1
480 C:@B#W=255
490 C:#W=#W+1
500 C:@B#W=28
510 C:#W=#W+1
520 C:@B#W=8
530 C:#W=#A
540 C:#W=#W+((4+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL D
550 C:@B#W=73 [Back of coal car
560 C:#W=#W+1
570 C:@B#W=0
580 C:#W=#W+1
590 C:@B#W=63
600 C:#W=#W+1
610 C:@B#W=63
620 C:#W=#W+1
630 C:@B#W=63
640 C:#W=#W+1
650 C:@B#W=255
660 C:#W=#W+1
670 C:@B#W=28
680 C:#W=#W+1
690 C:@B#W=8
700 C:#W=#A
710 C:#W=#W+((6+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL F
720 C:@B#W=183 [Front of coal car
730 C:#W=#W+1
740 C:@B#W=0
750 C:#W=#W+1
760 C:@B#W=240
770 C:#W=#W+1
780 C:@B#W=248
790 C:#W=#W+1
800 C:@B#W=252
810 C:#W=#W+1
820 C:@B#W=255
830 C:#W=#W+1
840 C:@B#W=28
850 C:#W=#W+1
860 C:@B#W=8
870 C:#W=#A
880 C:#W=#W+((7+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL G
890 C:@B#W=119 [Back of engine
900 C:#W=#W+1
910 C:@B#W=0
920 C:#W=#W+1
930 C:@B#W=126
940 C:#W=#W+1
950 C:@B#W=99
960 C:#W=#W+1
970 C:@B#W=127
980 C:#W=#W+1
990 C:@B#W=255
1000 C:#W=#W+1
1010 C:@B#W=28
1020 C:#W=#W+1
1030 C:@B#W=8
1040 C:#W=#A
1050 C:#W=#W+((8+64)*8)[OLD ADDRESS+((ATASCII+OFFSET)TIMES 8) CTRL H
1060 C:@B#W=192 [Front of engine
1070 C:#W=#W+1
1080 C:@B#W=48
1090 C:#W=#W+1
1100 C:@B#W=48
1110 C:#W=#W+1
1120 C:@B#W=252
1130 C:#W=#W+1
1140 C:@B#W=252
1150 C:#W=#W+1
1160 C:@B#W=254
1170 C:#W=#W+1
1180 C:@B#W=57
1190 C:#W=#W+1
1200 C:@B#W=16
1210 *GO
1220 POS:2,2
1230 T:}
1240 POS:14,10
1250 T:All Aboard!
1260 C:#P=2
1270 C:@B752=1 [Turn cursor off
1280 POS:2,18
1290 T: [36 CTRL M's
1300 POS:2,17
1310 T: ABCDEFGH [CTRL A through H
1320 PA:60
1330 *MOVETRAIN
1340 SO:0,0,0,0
1350 POS:#P,17
1360 T: ABCDEH [Space erases last car
1370 PA:5
1380 C:#P=#P+1
1390 J(#P<32):*MOVETRAIN
1400 C:@B752=0 [Turn cursor back on
1410 T:
1420 T: Type J:*GO to see the train again.
1430 E:
ANTIC v2.7 / OCTOBER 1983 / PAGE 23

PILOT YOUR ATARI

LONESOME PILOT

by KEN HARMS

Ken Harms is Contributing Editor for PILOT and Logo, who programs for the sheer joy of computing. Readers interested in contributing to our coverage of either of these languages are invited to write him care of ANTIC.


Sitting beside a calm, blue lake in Idaho’s Sawtooth mountains, I recently proved a philosophical statement by my friend, Anonymous: “A computer is a multi-purpose tool, not an all-purpose tool.” Out here, the best turtle graphic program is a poor substitute for a rod, reel and a well-chosen fly. So, while the nine-inch rainbows fry, here are a few lines concerning letters to the author and short but delightful programs illustrating character graphic animation under PILOT.

ANTIC and its authors attempt to answer readers’ questions either directly or through the I/O Board. Unfortunately, many letters are nearly unanswerable for reasons which may be illustrated by replying to a recent letter.

“In your article on Holiday Trees, you stated that you can get the big letters in the R:emark commands by placing a Control N right after the colon. I’ve tried this and it makes absolutely no difference in the looks of the print. What am I doing wrong?”

Answer: I was trying to explain how to get the Epson printer to print Rremarks lines in expanded mode. A similar special character can be used with the Atari and other printers; see your printer handbook. These characters have no effect on the listing displayed on the screen. No special characters will turn on the large screen letters (Graphics Mode 2). To answer this question I assumed the writer was listing to the screen. If he had included a description of his printer, I could have answered more helpfully.

“Your Sounder article (Volume 1, Issue 6) included a section on special effects that has puzzled me for some time. In the bouncing-ball section, absolutely nothing happens even though I have checked and rechecked the typing. I hear the sound effects, but there is no bouncing ball. I strongly suspect lines 590 and 690, followed by 570 and 670. What should I do on these lines?”

Several people reported this problem, most probably a result of the way we used to list programs. The Epson printer I use (like the Atari printers) does not print most control characters. The 590 and 690 lines are good guesses for the problem. The key sequence should be a Type [CTRL] [.] followed by a space and a remark bracket. The period in one remark didn’t print, leaving some confused. Lines 570 and 670 print blanks to erase the ball before the next line prints it again higher (or lower) on the screen. Be sure to include both the space and a remark bracket or PILOT will assume it’s a null line and do nothing.

If all else fails on a graphic screen, a good rule of thumb is to clear the screen and start over. One way to do this is to insert a line with Type [ESC] [CTRL] [CLEAR]. If that doesn’t work, try a GR:QUIT followed by a C:@B572=1 to turn off the cursor. In this program I’d insert the lines right after line 510, the start of the program.

“Also in the Sounder article, you lost me in the Jackhammer module, especially in lines 1220 to 1310, plus line 1340. The R:emarks were somewhat confusing as what came out on the screen looked like anything but a Jackhammer. I need some help interpreting these lines.”

Again, ANTIC’s new listing conventions, with full display of all characters, has solved this for future programs. In this case, however, the reader is subtly reporting an error in the remark statement intended to clarify a set of non-printing graphic characters. For all of you struggling with this, lines 1250 through 1270 are listed as “same as 1180.” Once they were. But I renumbered the program and forgot to change the remark. They should be “same as 1240.” Sorry folks!

Although these debugging problems were relatively simple (if I got them right!), most problems can be really difficult to diagnose from a few sentences. It really helps if you send along a disk or cassette with a copy of non-functioning programs and return postage, as well as a description of the problem and your hardware configuration. Be sure to keep your original copy! I can then see exactly what the computer sees and try to fix it.

And a final comment from our reader:

“I’m often struck by the exotic memory locations you use with pointer variables. Where do you come up with these locations and their various functions? Do you have a PILOT memory map? If you do, how do I obtain one? I’m always impressed by the way you can come up with just the right address to solve the tricky little problems. I never can, and believe me, it’s frustrating.”

The secret of finding just the right address to solve a tricky problem is writing articles only when the search for an address was successful. The number of programs which haven’t been written because the right address just can’t be located are many. For example, an address for all errors (we have one for I/O errors to disk) or a simple way to determine the length of a variable are attractive but elusive.

Although there is no good memory map for PILOT that I know of, you might find the following three resources helpful.

The BASIC Reference Manual by Atari includes many of the most useful addresses. The Memory Map by Educational Software, Inc., is the most complete O.S. map I’ve seen. “Mapping the ATARI,” by Ian Chadwick, is the most complete I haven’t seen. Since PILOT, like BASIC, works with Atari’s excellent Operating System, most of the addresses work with PILOT, But don’t expect locations such as variable addresses to work in a different language — these are definitely language-dependent. In a word — experiment.

The last resource is the PILOT External Specification, available free from Atari’s Customer Service group. The ‘External Spec’ is an internal document (not typeset, etc.) designed for the experienced programmer. It packs lots of information into its draft-form pages, but you’ll need some ingenuity to put these hints into use in your applications.

Now to this month’s program. Locomotive is a simple program combining character graphics and advanced sound effects to animate an old-fashioned steam locomotive. “Character graphics” describes pictures created by stringing together characters in Atari’s 256 character font. The program U:ses a *STARTUP module to get initial values for variables in #M and #R which control the left margin and the row number on which locomotive will print. Later, simply increasing this number and C:omputing it into address 82 changes the left margin to move the locomotive across the screen one space at a time. That’s the basic principle behind animating character graphics — print the characters, erase them, and reprint them in a different location. You could use the POS:ition command, but since the locomotive is five lines high, five P: commands would be needed, changing the margin is simpler. To eliminate erasing, each line of characters in the locomotive includes a blank at either end. This automatically erases the last character when the string is reprinted.

The program uses #R to change location 84 to set the line number on which to print the pattern. Simply changing positions 82 and 84 and printing either *TRAIN or *TRAINRIGHT moves the locomotive back and forth down the screen.

The *WHISTLE and *LOCO2 modules use special sound registers to control both a multi-voiced toot and the complex puff-puff of the locomotive. Simply, each of the four voices in PILOT is controlled by two registers — a frequency address and a control address. PILOT looks at values in the frequency register to figure out the pitch (frequency) and the control register to determine the distortion plus loudness values for each voice. See the BASIC Reference Manual or “Sounder” in ANTIC Oct.-Nov. 1982, for more information.

The *WHISTLE module sounds each of three voices at different frequencies and at distortion 160 (clear tones) but with loudness values of 8 and 10. It turns them off by setting the loudness values to (lines 2110 to 2130). The same technique gives the puffs. The variable #L sets up the maximum loudness (15 times 100) and then loops *LOCO1 and *LOCO2 first sound the loud puff and then loop through to rapidly decrease the loudness. The loop proceeds slowly at first while the train is starting up and goes faster and faster as the train speeds up. This increasing speed is accomplished by increasing the “step value” (variable #X) after each puff. See lines 1060 through 1100.

Well, it’s back to the campfire for these fish. Upcoming programs include a way to merge programs under program control and continuing coverage of Logo.

10 R:LOCOMOTIVE
20 R:ANTIC OCTOBER, 1983
30 R:
40 J:*MAINLINE
100 *TRAIN
110 C(#M=25)+(#M=4):#R=#R+1
120 C(#M=25)+(#M=4):#D=#D*-1
130 C:#M=#M+#D
140 C(#R=20):#R=0
150 C:@B82=#M
160 C:@B84=#R
170 J(#D<0):*TRAINRIGHT
180 T:        [8 BLANKS
190 T:  ````  [
200 T:  ** ** [
210 T:        [
220 T:  *````*[
230 E:
240 *TRAINRIGHT
250 T:         [9 BLANKS
260 T:   ````  [REM
270 T:  ** **  [REM
280 T:         [REM
290 T: *````*  [REM
300 R:INCLUDE BLANKS & REMARK SIGN       AFTER GRAPHIC ... THEY HOLD SPACES!
310 E:
1000 R:
1010 *MAINLINE
1020 U:*STARTUP
1030 *LOCO1
1040 C:#L=1500 [LOUDNESS VALUE
1050 *LOCO2
1060 C:@B53761=(#L-#X)/100
1070 C:#L=#L-#X
1080 J(#L>400):*LOCO2
1090 C(#X<150):#X=#X+1
1100 C:#Z=#Z-1
1110 J(#Z=0):*LOCO3
1120 U:*TRAIN
1130 J:*LOCO1
1140 *LOCO3
1150 PA:60
1160 U:*WHISTLE
1170 PA:60
1180 C:@B82=2[RESTORES LEFT MARGIN
1190 E:
2000 R:
2010 *WHISTLE
2020 C:#W=3 [NUMBER OF WHISTLES
2030 *WHISTLE1
2040 C:@B53762=40 [FREQ. VOICE 1
2050 C:@B53764=10 [FREQ. VOICE 2
2060 C:@B53766=90 [FREQ. VOICE 3
2070 C:@B53763=160+10[CNTRL VOICE 1
2080 C:@B53765=160+8 [CNTRL VOICE 2
2090 C:@B53767=160+10[CNTRL VOICE 3
2100 PA:50
2110 C:@B53763=160
2120 C:@B53765=160
2130 C:@B53767=160
2140 PA:35
2150 C:#W=#W-1
2160 E(#W=0):
2170 J:*WHISTLE1
3000 R:
3010 *STARTUP
3020 R: THESE VARIABLES POSITION TRAIN
3030 C:#M=5 [LEFT MARGIN LOCATION
3040 C:#R=5 [ROW NUMBER
3050 C:#D=1 [DIRECTION 1=LEFT,-1=RIGHT
3060 R: THESE VARIABLES CONTROL SOUNDS        AND NUMBER OF PUFFS
3070 C:#Z=188 [NUMBER OF PUFFS
3080 C:#X=15 [DECREASES LOUDNESS
3090 C:@B53760=15[ FREQUENCY, VOICE 0
3100 C:@B53761=3 [CNTRL VOICE 0
3110 U:*TRAIN
3120 PA:120
3130 U:*WHISTLE
3140 PA:30
3150 E:
ANTIC v2.9 / DECEMBER 1983 / PAGE 24

LOGO/PILOT

TURTLE SKETCHPAD

COAX HER OUT OF HER SHELL

by KATHY and PHIL BERGH

This winter season brings back those coding elves of the North (Puyallup, Washington, that is), Kathy and Phil Bergh. Their “Turtle SketchPad” program is a tour de force that integrates PILOT and Player/Missile graphics (PMG). PMG mechanics have been fully covered in other ANTIC articles; I have also found Educational Software’s “Tricky Tutorial” on the subject to be excellent. But for this program, just type away; it works fine. —Ken Harms


“Yes, Virginia, there is a turtle.” And just to prove it, we’ve coaxed her (or is it he?) to show herself to you on a sketchpad that lets you use the joystick to draw in any of the turtle’s regular colors. We hope that this entertaining “tool” will be so fun that you’ll play with it all year long. Although it is only 128 lines long, this amazing little program will show you how to read the joystick, get input directly from the keyboard, and move a player both horizontally and vertically using PMG but without using a machine language routine!

We know what you’re thinking: next, they’ll claim that they’re rewriting Missile Command in PILOT. We may, someday, but for our present purposes we don’t need speed, just a shape that will let us see where the cursor is without interfering with the design. Leaving PILOT is not necessary. We need only C:ompute the new location values and character shape into the RAM locations PILOT uses to create the screen image, and we’re set.

When RUN, SketchPad presents you with a title page, which then directs you to draw using a joystick in Port 1. If you press the fire button, the turtle fills as it draws. Pressing [R], [Y], or [B], prompts turtle to use a red, yellow, or blue pen. Press [U] (for up to move without drawing, and [E] to erase. As with regular turtle graphics, you cannot fill while erasing. So that you know where the turtle is at all times, a PMG player is positioned in the same location as the turtle, and shadows it wherever it goes.

Our program does not check the cursor location to ensure that the player stays on the screen at all times. As a result, if you drive off the bottom of the screen and keep going, you will eventually poke the player into the display list and get quite a bit of garbage on the screen.

Go off the side of the screen, and the player will quickly return to the screen’s opposite side, but the turtle will keep marching to the left (or right) for another 32,748 units or so before starting back toward the other side of the screen. Going off the top of the screen will — eventually — march your player through the program memory and alter the listing beyond recognition.

Now that you know why you should stay on the screen, you may think about ways in which you can keep the turtle from leaving it. Adding that code would be good programming practice.

Let’s look at the listing and see how SketchPad works. To speed things up, we’ve placed the least-used routines at the end of the program. We J:ump to them in line 10 so that the computer never has to see them again. The routine called *PLAYER (starting at line 20) gives the GR:aphics commands to the turtle and POKEs the player into its new location.

First, we keep the trigger value for Port 1 (%T8) as a variable. A zero here means that the fire button has not been pushed. A one means that it has. We “froze” %T8 into variable #T so that the value won’t change if you stop firing midway through the routine.

Line 40 is executed if the trigger is not pressed or if the pen is set to erase. To determine if the pen is set to erase, look into the special memory location where PILOT stores the current pen color — @B1363 . A zero here means erase, one means red, two means yellow, and three means blue. The command is executed if either of the conditions is true. This tells the turtle to draw to its new location (as decided by another routine).

The turtle’s present coordinates are contained in PILOT machine variables %X and %Y. Adding #B to the current location in %X gives us the new horizontal coordinate. By using the same simple step, but this time subtracting #A from %Y, we can produce the new vertical position. The NORTH, SOUTH, etc. routines C:ompute values into #B and #A, depending on the joystick location.

Line 50 tells the turtle to fill to the same new location, if the trigger is pressed and the pen is not set to erase. (Multiplying conditions means they all must be true for the command to operate.)

Next, we’ll show you how to move the player and stay with the turtle. Remember that #A is the change in the vertical position. Since the player moves vertically in half-steps, we must multiply #A by two (Line 60) before it can be used to increment the player’s position. Variable #J indicates the old vertical position of the player.

Line 70 adds the player-movement amount we C:omputed in line 60 to the old player position in #J to give us the new player location. Line 80 stores the new value as #Y.

Ready for the fun part? When the player moves vertically, it must be moved within the computer memory, and C:omputed into the new location byte-by-byte. This process is just like C:omputing a new character set into RAM (which was explained in detail in ANTIC, “Pilot Your Atari,” page 37, August 1983). The decimal values for each line within the player are C:omputed into B#Y and the next nine bytes in lines 90-270. The zeros at the edges of the player are used to erase any piece left behind during the move.

To the computer, our player looks like this:

Binary      Decimal
00000000     =  0
00000000     =  0
00100010     = 34
00010100     = 20
00001000     =  8
00001000     =  8
00010100     = 20
00100010     = 34
00000000     =  0
00000000     =  0

Because PILOT will not accept C:@B#Y+1=0, we must increment the byte in one line and C:ompute the value into the next.

Horizontal movement is easy. Just add the change in position (#B) to the old position (#X) and C:ompute the new value into B53248, which is the horizontal position register for player zero. Atari’s powerful graphics chip, ANTIC, takes care of horizontal travel. Lines 300 and 310 reset the values of #A and #B (our position changes) for the next time through the loop.

In line 320, we remind the turtle which color she is supposed to draw or fill with by C:omputing #C into B1363. The #C is set by *COLORCHANGE at lines 850 through 960. B764 holds the internal hardware value for the last key pressed. If that key is a [Y], [B], [R], [E], [U], or [CTRL C], the proper GR:aphics command will be executed. Line 930 “rings the internal bell” if any one of the command letters has been pressed.

Remember to press [ESC] before pressing [CTRL] and [2] when typing this line. The new pen color is stored in #C, and B764 is reset with a 255 so that it’s ready to be checked for new input.

The *MAINLINE routine that starts at line 330 puts a zero into B77 (the attract flag) to keep the screen colors from changing. Normally, they rotate to protect the screen if no input is entered on the keyboard within nine minutes. This kind of protection is required whenever you use joysticks for input. Next, *MAINLINE checks the keyboard @B764 to see if there is a number other than 255 there. A number other than 255 means that the user wants to change pens, so the program U:ses *COLORCHANGE.

Beginning at line 360, *MAINLINE A:ccepts the joystick position (%J0), M:atches it against its possible values, and J:umps to whichever routine correctly C:omputes the changes in position (#A and #B). We then J:ump back to *PLAYER to move the turtle and player, and start through the cycle again. Be careful when you type line 370. For each value to be significant, there must be a space both before and after it! If you do not include the comment at the end of line 370, you must add an underline after the five at the end of the line.

*SETUP (starting at line 600) contains the heart of the PMG. After clearing the screen, setting the pen color and turtle position, saving the initial pen color as #C, and Typing “please wait,” we need to initialize the player. First, we must enable the PMG routines. C:omputing a 62 into B559 tells ANTIC that we will be using PMG and that we want a standard-sized playfield, players and missiles (although we won’t use all of them), as well as one-line player resolution.

By defining #I as 6K less than the real amount of memory available (@B106), and POKEing that value into B54279 (PMBASE), we allow ANTIC to use the top 6K of memory to take care of players and missiles. C:omputing a zero into B53256 tells ANTIC that the player is normal-sized (line 680). Line 690 sets the player’s original byte position (#J), which is the page (#I) multiplied by 256 (bytes per page) and added to 1,024 (which is how far ANTIC says player zero must be from the PM base).

*CLEARPLAYER (line 710) keeps you from having two players on the screen if the program is being rerun. It puts a zero into the first byte of the player (#J), increments #J and a loop counter (#X), and loops through until all of the 256 bytes available to player zero are cleared.

We must then recalculate the player’s original byte position and add 124 to it, so that the player will appear in the center of the screen. Putting a one into B623 tells ANTIC that the player has priority over all of the background colors. #X is set at 124, the original horizontal position of the player, and is C:omputed into B53248 to let ANTIC know where the player is.

(Clearplayer prevents two players from appearing when you re-RUN the program. If you [BREAK] the program and attempt to clear the screen, however, the screen will fill with garbage. Just hit [RESET] —KWH)

The player’s color is set to white (line 800) and the players are lit up by C:omputing a three into B53277. A zero here makes the player disappear. Now, all of our housekeeping is finished, and our player is ready to go!

The remainder of the program types the instructions and the title page. This section is followed by a set of R:emark statements that list the variables used and what they mean. (Including a table like this in a program is a very good habit to form. A few weeks — or even a few days — after you have written a program, you may wish to modify it. Being reminded which variables are available for use, and which ones have been defined, is a real time-saver.)

In conclusion, we hope that you have a New Year full of fun designing with Sketchpad and writing Player/Missile graphics programs of your own. Good luck!

Next month, it’s back to Logo for a look at a wide range of books and resource materials that are available for home and school.

10 J:*TITLEPAGE
20 *PLAYER  [THE PLAYER IS AN "X"
30 C:#T=%T8 [KEEP TRIGGER VALUE AS A VARIABLE
40 GR(#T=0)+(@B1363=0):DRAWTO %X+#B,%Y-#A [DRAW IF TRIGGER NOT PRESSED OR PEN IS ERASE
50 GR(#T=1)*(@B1363<>0):FILLTO %X+#B,%Y-#A [FILL IF TRIGGER PRESSED AND NOT ERASE
60 C:#A=#A*2 [SCALING FACTOR
70 C:#J=#J+#A [COMPUTE NEW VERTICAL VALUE FOR PLAYER
80 C:#Y=#J [KEEP IT AS #Y
90 C:@B#Y=0  [THROUGH LINE 270 - MOVE PLAYER TO NEW VERTICAL POSITION
100 C:#Y=#J+1
110 C:@B#Y=0
120 C:#Y=#J+2
130 C:@B#Y=34
140 C:#Y=#J+3
150 C:@B#Y=20
160 C:#Y=#J+4
170 C:@B#Y=8
180 C:#Y=#J+5
190 C:@B#Y=8
200 C:#Y=#J+6
210 C:@B#Y=20
220 C:#Y=#J+7
230 C:@B#Y=34
240 C:#Y=#J+8
250 C:@B#Y=0
260 C:#Y=#J+9
270 C:@B#Y=0
280 C:#X=#X+#B [COMPUTE NEW HORIZONTAL POSITION
290 C:@B53248=#X [POKE IT INTO PLAYER/MISSLE BASE
300 C:#A=0 [RESET A
310 C:#B=0 [RESET B
320 C:@B1363=#C [POKE REMINDER OF WHICH PEN TO USE
330 *MAINLINE [CHECKS JOYSTICK
340 C:@B77=0 [SET ATTRACT FLAG TO KEEP SCREEN FROM CHANGING COLORS
350 U(@B764<255):*COLORCHANGE [CHANGE COLOR IF THERE IS KEYBOARD IMPUT
360 A:=%J0 [GRAB VALUE OF JOYSTICK
370 M: 1 , 9 , 8 , 10 , 2 , 6 , 4 , 5 [MATCH VALUE OF JOYSTICK
380 JM:*NORTH,*NE,*EAST,*SE,*SOUTH,*SW,*WEST,*NW [JUMP TO APPROPRIATE ROUTINE FOR DIRECTION TRAVELED
390 J:*MAINLINE    [THROUGH LINE 690-
400 *NORTH C:#A=-1 [COMPUTE NEW
410 J:*PLAYER      [POSITION IN
420 *NE C:#A=-1    [APPROPRIATE
430 C:#B=1         [DIRECTION
440 J:*PLAYER
450 *EAST C:#B=1
460 J:*PLAYER
470 *SE C:#A=1
480 C:#B=1
490 J:*PLAYER
500 *SOUTH C:#A=1
510 J:*PLAYER
520 *SW C:#A=1
530 C:#B=-1
540 J:*PLAYER
550 *WEST C:#B=-1
560 J:*PLAYER
570 *NW C:#A=-1
580 C:#B=-1
590 J:*PLAYER [JUMP BACK TO MOVE PLAYER AND DRAW LINE
600 *SETUP [SET UP PLAYER/MISSLE GRAPHICS
610 GR:CLEAR;GOTO 0,0;PEN YELLOW
620 C:#C=@B1363 [PUT CURRENT PEN VALUE IN #C
630 T:
640 T:  INITIALIZING ...... PLEASE WAIT
650 C:@B559=62 [ENABLE PMG(32)+ONE LINE PLAYER RES.(16)+USE PLAYERS & MISSILES(12)+STANDARD PLAYFIELD(2)
660 C:#I=@B106-24 [RESERVE 6K FOR PMG
670 C:@B54279=#I [PMBASE
680 C:@B53256=0  [SIZE OF PLAYER 0 - NORMAL, 1 - DOUBLE, 3 - QUAD. (2=0)
690 C:#J=#I*256+1024 [ADDRESS OF PLAYER'S 256 BYTES
700 C:#X=0 [#X IS TEMPORARILY A LOOP COUNTER
710 *CLEARPLAYER
720 C:@B#J=0
730 C:#X=#X+1
740 C:#J=#J+1
750 J(#X<256):*CLEARPLAYER
760 C:#J=#I*256+1024+124 [ADDRESS OF PLAYER 0 IN RAM
770 C:@B623=1 [PRIORITY SELECTION - PLAYER 0 -3 HAS PRIORITY OVER ALL THREE BACKGROUND COLORS
780 C:#X=124
790 C:@B53248=124 [PLAYER 0 HORIZONTAL POSITION
800 C:@B704=14
810 C:@B53277=3  [2 TURN ON PLAYER + 1 TURN ON MISSLES
820 T:}
830 U:*INSTRUCTIONS
840 J:*PLAYER
850 *COLORCHANGE
860 GR(@B764=11):PEN UP   [CHANGE PEN USED UPON KEYBOARD INPUT
870 GR(@B764=21):PEN BLUE
880 GR(@B764=40):PEN RED
890 GR(@B764=42):PEN ERASE
900 GR(@B764=43):PEN YELLOW
910 GR(@B764=146):PEN YELLOW;CLEAR
920 U(@B764=146):*INSTRUCTIONS
930 T(@B764=21)+(@B764=40)+(@B764=42)+(@B764=11)+(@B764=43)+(@B764=146):}\
940 C:#C=@B1363  [SAVE NEW PEN VALUE
950 C:@B764=255  [RESET KEYBOARD BUFFER
960 E:
970 *INSTRUCTIONS
980 T: R - PEN RED        U - PEN UP
990 T: B - PEN BLUE       E - ERASE
1000 T: Y - PEN YELLOW     CTRL C - CLEAR
1010 E:
1020 *TITLEPAGE
1030 GR:QUIT
1040 POS:11,5
1050 T:TURTLE SKETCHPAD
1060 POS:12,8
1070 T:ANTIC Volume 2
1080 POS:15,9
1090 T:Issue 9
1100 R:BY KATHY AND PHIL BERGH
1110 POS:2,14
1120 T:     DRAW using a joystick in Port 1. To FILL, press the trigger. You change the PEN colors by \
1130 T:pressing R for RED, B for BLUE, Y for YELLOW, U for UP, and E for ERASE. You need not press return. \
1140 T:To CLEAR the screen, press CONTROL and C.
1150 POS:6,22
1160 T:Press RETURN to continue \
1170 A:
1180 J:*SETUP
1190 R:*****************************
1200 R:VARIABLES:
1210 R:   #X - HORIZONTAL POSITION OF                PLAYER
1220 R:   #Y - VERTICAL POSITION OF                  PLAYER
1230 R:   #I - PAGE NUMBER OF PMBASE
1240 R:   #J - ADDRESS OF PLAYER 0 IN                RAM
1250 R:   #A - VERTICAL POSITION                     INCREMENT
1260 R:   #B - HORIZONTAL POSITION                   INCREMENT
1270 R:   #C - SAVED VALUE OF THE                    COLOR REGISTER IN USE
1280 R:   #T - SAVED VALUE OF TRIGGER
ANTIC v2.12 / MARCH 1984 / PAGE 32

LOGO/ PILOT

MERGING TRAFFIC

PILOT does it on the run

by PHIL and KATHY BERGH

MERGING IN RUN MODE? SURE!

This month’s PILOT article again features Phil and Kathy Bergh and an innovative program that merges PILOT programs under program control. You can use this technique to “overlay” code and thus fit large programs into small memory spaces by LOADing only the sections of the program needed at one time. Then, when a new section is needed, you LOAD it “over” some unneeded lines.

Our PILOT/Logo columns aim to present useful procedures using features of the languages not covered in the manuals. We invite you to send ideas jor articles youd like to see, or complete articles, to me in care of this column, just cover something new and useful. Next month I will use Logo to make large letters (BASIC’s Mode 1 and 2), and show you two safe places to put machine-language code. —Ken Harms


THE CHALLENGE: produce a useful PILOT program that teaches a technique or procedure not covered in depth elsewhere. To meet this challenge, we present a set of diskette-based, math-drill programs that show how to merge a new subprogram from diskette under program control without erasing the current program. We also will list the code changes necessary to use the program from cassette.

THE APPLICATION: a math-drill game with menu selection of math operation. We know that the slash mark, which Atari uses for its division computations, is not understood by younger students, so we drew upon the character set redefinition program presented in ANTIC, August 1983, to create a custom division character We will not review the technique here. The routine that prints the traditional division sign can easily be used in math programs of your own.

MATHMERG

The main program file is titled MATHMERG. It provides the title page, custom character set, menu, screen format, and correction routines. The other four files (subprograms) contain the problems and answers that will be merged with the main program.

The menu offers choices of addition, subtraction, multiplication, and division. When a choice is made, the name of the file holding the subprogram to be merged is written to the screen, the cursor is positioned above the LOAD statement, the computer is ordered to read the screen, and the program is E:nded. The computer is now in immediate mode and executes the LOAD command as if it were just entered from the keyboard. Because the program is not running, it avoids the automatic NEW that PILOT supplies to erase the current program before loading another file. ANTIC covered this automatic keyboard feature more fully in the Deleter program (ANTIC, “Lines Away,” p. 24, July 1983).

MERGE FILES

Each of the subprograms we will merge are carefully numbered to position the T:ype statements from the small merge files to come after the POS:ition statements in the main program. Similarly, the answers come before the M:atch statements. Changing any line numbers could crash the programs. Notice that the main program has many lines that can be entered by renumbering previous lines and making small changes (such as the problem number). After you enter and save the first merge file, simply change the signs and numbers and save it again with the new name.

You can easily create your own merge files with problems suited to your needs. Change them as often as you wish without the difficulties caused by going into a large program and finding all of the lines that need modification.

A LOOK AT THE LISTING

Let’s look through the listing to see how it works. The code from line 275 through 320 causes the title page to be written in large letters. For a more detailed look at how this works, see “Large Text” in The Best of ANTIC, Vol. 1. Remember that when you write to the screen, you must use a CLOSE:S to let the computer know you are finished. See line 440 for an example.

The lines indented with commas are part of a custom character set routine. They create a traditional division sign to replace the slash. This allows us to format division problems with one number above the other on the drill screens.

Lines 445 through 535 write the menu in large letters on a black screen and type the instructions in the text window. The routine starting at line 540 detects if the [SELECT] or [START] button has been pressed. Always C:ompute a value of eight into byte 53279 to clear it before checking to see if a console button has been pressed. This prevents re-reading a previous press. If [OPTION] is pressed, there will be a three at byte 53279. [SELECT] is a five and [START] is a six. Line 550 J:umps to *STARTPRESSED only if there is a six in byte 53279. Line 555 checks for a five. If neither [SELECT] nor [START] were pressed, we J:ump back to *CONSOLEBUTTONS to check again.

Lines 570 to 610 move the menu arrow to the next choice. The line that the arrow is on is called #L. It is incremented by two each time [SELECT] is pressed. If it is greater than seven, it is set to one again. After the arrow moves, we J:ump back to check the console buttons. Lines 625 through 640 identify the file to be loaded according to the position of the pointer on the menu screen.

MERGING FILES

Now the fancy stuff — we merge the chosen file! We also learn something about Atari DOS and PILOT’s load routines. Line 660 clears the graphics screen and prepares for normal text. We then skip down two lines on the screen and T:ype a “please wait” message. We then T:ype four blank lines. Line 690 T:ypes a LOAD command on the screen and we T:ype down two more lines. Line 696 T:ypes a J:ump command on the screen so the program will restart. Note that the J:ump command is followed by seven “up-arrows.” To include an up-arrow in your program, press [ESC] and release, then press and hold [CTRL] while you push the up-arrow. You will do this seven times. When the program is run, the up-arrows will position the cursor three rows above the load command.

Line 700 forces the computer to read from the screen by C:omputing a 13 into byte 842. When the program is Emded (line 705), the READY prompt appears. The cursor drops to the line with our LOAD command, and that line is acted upon as if it were just typed by hand on the screen.

“But how,” you may ask, “does the program get running again?” Good question. The trick answer is simple. After PILOT LOADS the file T:yped by line 690, it prints a READY prompt, skips a line and positions the cursor on the line just below. And guess what? When it hits that line, it finds the command J:*TAG2 already printed there. Since the Atari is still in auto-keyboard mode, it reads the J:ump command, PILOT takes over and does the J:ump.

Why are we J:umping to *TAG2 in the merge programs? Because *TAG2 is part of our main program after we forced the LOAD. At line 780 we finish the procedure by C:omputing a 12 into byte 842. This tells the computer to stop reading from the screen.

Lines 800 through 1510 POS:ition the math problems on the screen. Lines 1640 through 2470 present and correct the problems. Remember that you can enter much of this code by changing line numbers, problem numbers, and positions. Do not forget the space in and underline after the M:atch commands, or the program will accept incorrect answers.

Finally, *CORRECT at line 2570 uses the random number generator to play a series of notes and flash the screen colors if the user gets a problem correct. *ERROR gives a two-note response to incorrect answers, and the problem is repeated.

CASSETTE VERSION

The custom character and drill screen in Math Practice can be easily used from cassette by LOADing MATHMERG from tape and then LOADing whatever problem file you wish. Many different problem sets can be accessed on different tapes. You are not limited to one file for each type of problem, as disk users are, because tape files are not called by name by the program. Two disk files of the same name are, of course, not allowed.

Cassette users should replace two lines in the listing with the following:
675 T:Please insert the $PROGRAMNAME tape and press play
690 T:LOAD C:[seven up-arrows]

If you do not want the LOAD commands that appear in the text window to be visible, then add:

676 C:@B709=5
781 C:@B709=10

Line 676 changes the luminance of the text to match the background, thus rendering it invisible. The second line restores the color values.

The youngsters who tested this program found it “more fun than flash-cards.” The adults found other ways to utilize some of these ideas. We hope you, too, will find it instructive and enjoyable.

Listing 1

195 *BEGIN
200 ,    C:#Z=@176/1024+3
205 ,    C:#Z=#Z*1024
210 ,    C:#Y=@B756*256
215 ,    C:@B756=#Z/256
220 ,    C:#W=#Z
225 R:#Y POINTS TO ORIGINAL CHARACTER SET
230 R:#Z POINTS TO NEW RAM CHARACTER SET
235 R:#W IS ALSO THE ADDRESS OF THE NEW CHARACTER SET
240 R:*******************************
245 R: PROGRAM DESIGNED FOR MERGING
250 R: WITH OTHER PROGRAMS - DO NOT
255 R:CHANGE THE LISTED LINE NUMBERS
260 R:*******************************
265 C:#M=0  [#M INITIALIZATION
270 C:#L=1  [#L IS THE MENU LINE THE POINTER IS ON
275 C:@B1373=16 [USE SPLIT SCREEN
280 C:@B1374=2  [USE LARGE CHARACTERS
285 POS:3,3
290 WRITE:S,
295 ,    C:@B756=#W/256
300 POS:3,3
305 WRITE:S,MATH PRACTICE
310 POS:3,6
315 WRITE:S, +  -  *  /
320 R:By Kathy and Phil Bergh
325 PA:40
330 ,    C:#X=0
335 *MOVEIT C:@B#Z=@B#Y [PART OF CHARACTER SET PROGRAM
340 ,    C:#Y=#Y+1
345 ,    C:#Z=#Z+1
350 ,    C:#X=#X+1
355 ,    J(#X<1024):*MOVEIT
360 ,    C:#W=#W+120
365 ,    C:@B#W=0
370 ,    C:#W=#W+1
375 ,    C:@B#W=24
380 ,    C:#W=#W+1
385 ,    C:@B#W=0
390 ,    C:#W=#W+1
395 ,    C:@B#W=126
400 ,    C:#W=#W+1
405 ,    C:@B#W=0
410 ,    C:#W=#W+1
415 ,    C:@B#W=24
420 ,    C:#W=#W+1
425 ,    C:@B#W=0
430 ,    C:#W=#W+1
435 ,    C:@B#W=0
440 CLOSE:S
445 *START
450 POS:3,2
455 C:@B1373=16 [USE SPLIT SCREEN
460 C:@B1374=2  [USE LARGE CHARACTERS
465 WRITE:S,}
470 ,    C:@B756=#W/256
475 POS:3,1
480 WRITE:S,+ ADDITION
485 POS:3,3
490 WRITE:S,- SUBTRACTION
495 POS:3,5
500 WRITE:S,X MULTIPLICATION
505 POS:3,7
510 WRITE:S,/ DIVISION
515 POS:1,#L
520 WRITE:S,>
525 T:
530 T:      SELECT to move pointer
535 T:          START to load
540 *CONSOLEBUTTONS
545 C:@B53279=8   [CLEARS CONSOLE BUTTON REGISTER
550 J(@B53279=6):*STARTPRESSED  [JUMP IF START IS PRESSED
555 J(@B53279=5):*INCREMENT  [JUMP IF SELECT IS PRESSED
560 PA:15
565 J:*CONSOLEBUTTONS   [LOOP IF NO BUTTON WAS PRESSED
570 *INCREMENT  [MOVE POINTER ARROW, LOCATION KEPT AS #L
575 POS:1,#L
580 WRITE:S,_
585 C:#L=#L+2
590 C(#L>7):#L=1
595 POS:1,#L
600 WRITE:S,>
605 PA:15
610 J:*CONSOLEBUTTONS
615 *STARTPRESSED
620 CLOSE:S
625 C(#L=1):$PROGRAMNAME=ADD
630 C(#L=3):$PROGRAMNAME=SUBTRACT
635 C(#L=5):$PROGRAMNAME=MULTIPLY
640 C(#L=7):$PROGRAMNAME=DIVIDE
645 *MERGEIT
650 J(#L=#M):*TAG2
655 C:#M=#L [DUMMY VALUE TO CHECK TO PREVENT LOADING THE SAME FILE THAT IS CURRENTLY IN MEMORY
660 GR:QUIT
665 T:
670 T:
675 T:PLEASE WAIT WHILE I LOAD $PROGRAMNAME
680 T:
682 T:
684 T:
686 T:
690 T:LOAD D:$PROGRAMNAME
692 T:
694 T:
696 T:J:*TAG2↑↑↑↑↑↑↑
700 C:@B842=13 [FORCES COMPUTER TO READ FROM SCREEN
705 E:
770 *TAG2
780 C:@B842=12 [FORCES COMPUTER TO WRITE TO SCREEN
790 GR:QUIT
795 C:@B756=#W/256
800 POS:4,2
820 POS:3,3
840 POS:3,4
850 T:***
860 POS:14,2
880 POS:13,3
900 POS:13,4
910 T:***
920 POS:24,2
940 POS:23,3
960 POS:23,4
970 T:***
980 POS:34,2
1000 POS:33,3
1020 POS:33,4
1030 T:***
1040 POS:4,9
1060 POS:3,10
1080 POS:3,11
1090 T:***
1100 POS:14,9
1120 POS:13,10
1140 POS:13,11
1150 T:***
1160 POS:24,9
1180 POS:23,10
1200 POS:23,11
1210 T:***
1220 POS:34,9
1240 POS:33,10
1260 POS:33,11
1270 T:***
1280 POS:4,16
1300 POS:3,17
1320 POS:3,18
1330 T:***
1340 POS:14,16
1360 POS:13,17
1380 POS:13,18
1390 T:***
1400 POS:24,16
1420 POS:23,17
1440 POS:23,18
1450 T:***
1460 POS:34,16
1480 POS:33,17
1500 POS:33,18
1510 T:***
1640 *PROBLEM1
1650 POS:4,5
1660 A:$ANSWER1
1670 M: $CORRECT1_
1680 UY:*CORRECT
1690 UN:*ERROR
1700 JN:*PROBLEM1
1710 *PROBLEM2
1720 POS:14,5
1730 A:$ANSWER2
1740 M: $CORRECT2_
1750 UY:*CORRECT
1760 UN:*ERROR
1770 JN:*PROBLEM2
1780 *PROBLEM3
1790 POS:24,5
1800 A:$ANSWER3
1810 M: $CORRECT3_
1820 UY:*CORRECT
1830 UN:*ERROR
1840 JN:*PROBLEM3
1850 *PROBLEM4
1860 POS:34,5
1870 A:$ANSWER4
1880 M: $CORRECT4_
1890 UY:*CORRECT
1900 UN:*ERROR
1910 JN:*PROBLEM4
1920 *PROBLEM5
1930 POS: 4,12
1940 A:$ANSWER5
1950 M: $CORRECT5_
1960 UY:*CORRECT
1970 UN:*ERROR
1980 JN:*PROBLEM5
1990 *PROBLEM6
2000 POS:14,12
2010 A:$ANSWER6
2020 M: $CORRECT6_
2030 UY:*CORRECT
2040 UN:*ERROR
2050 JN:*PROBLEM6
2060 *PROBLEM7
2070 POS:24,12
2080 A:$ANSWER7
2090 M: $CORRECT7_
2100 UY:*CORRECT
2110 UN:*ERROR
2120 JN:*PROBLEM7
2130 *PROBLEM8
2140 POS:34,12
2150 A:$ANSWER8
2160 M: $CORRECT8_
2170 UY:*CORRECT
2180 UN:*ERROR
2190 JN:*PROBLEM8
2200 *PROBLEM9
2210 POS: 4,19
2220 A:$ANSWER9
2230 M: $CORRECT9_
2240 UY:*CORRECT
2250 UN:*ERROR
2260 JN:*PROBLEM9
2270 *PROBLEM10
2280 POS:14,19
2290 A:$ANSWER10
2300 M: $CORRECT10_
2310 UY:*CORRECT
2320 UN:*ERROR
2330 JN:*PROBLEM10
2340 *PROBLEM11
2350 POS:24,19
2360 A:$ANSWER11
2370 M: $CORRECT11_
2380 UY:*CORRECT
2390 UN:*ERROR
2400 JN:*PROBLEM11
2410 *PROBLEM12
2420 POS:34,19
2430 A:$ANSWER12
2440 M: $CORRECT12_
2450 UY:*CORRECT
2460 UN:*ERROR
2470 JN:*PROBLEM12
2480 POS:2,21
2490 T:Would you like to try these problems again or try another skill? Type AGAIN, ANOTHER, or QUIT \
2500 A:$AGAIN
2510 M: AGAIN , ANOTHER , QUIT_
2520 JM:*TAG2,*START,*QUIT
2530 *QUIT
2540 T:}
2550 T:Thanks for playing.  See you again soon.
2560 E:
2570 *CORRECT
2580 C:#X=0
2590 *ANOTHERNOTE
2600 C:#J=?\8
2610 SO(#J=0):13
2620 C(#J=0):@B710=6
2630 SO(#J=1):15
2640 C(#J=1):@B710=14
2650 SO(#J=2):17
2660 C(#J=2):@B710=196
2670 SO(#J=3):18
2680 C(#J=3):@B710=100
2690 SO(#J=4):20
2700 C(#J=4):@B710=56
2710 SO(#J=5):22
2720 C(#J=5):@B710=148
2730 SO(#J=6):24
2740 C(#J=6):@B710=70
2750 SO(#J=7):25
2760 C(#J=7):@B710=26
2770 PA:?\2*4
2780 C:#X=#X+1
2790 J(#X<12):*ANOTHERNOTE
2800 PA:32
2810 SO:0
2820 C:@B710=148
2830 E:
2840 *ERROR
2850 SO:12
2860 PA:4
2870 SO:1
2880 PA:8
2890 SO:0
2900 E:

Listing 2

805 R:ADDITION PROBLEMS -- save in disk file named ADD or on separate tape.
810 T:10  [ADDITION PROBLEMS TO MERGE
830 T:+17 [WITH MAIN PROGRAM
870 T: 8
890 T:+ 4
930 T:15
950 T:+ 5
990 T:17
1010 T:+13
1050 T: 5
1070 T:+ 9
1110 T:24
1130 T:+18
1170 T:13
1190 T:+10
1230 T:15
1250 T:+11
1290 T:25
1310 T:+ 8
1350 T:11
1370 T:+19
1410 T: 9
1430 T:+ 6
1470 T:12
1490 T:+ 9
1520 C:$CORRECT1=27
1530 C:$CORRECT2=12
1540 C:$CORRECT3=20
1550 C:$CORRECT4=30
1560 C:$CORRECT5=14
1570 C:$CORRECT6=42
1580 C:$CORRECT7=23
1590 C:$CORRECT8=26
1600 C:$CORRECT9=33
1610 C:$CORRECT10=30
1620 C:$CORRECT11=15
1630 C:$CORRECT12=21

Listing 3

805 R:SUBTRACTION PROBLEMS -- save in disk file named SUBTRACT or on separate tape.
810 T:10  [SUBTRACTION PROBLEMS TO
830 T:- 7 [MERGE WITH MAIN PROGRAM
870 T: 8
890 T:- 4
930 T:15
950 T:- 5
990 T:17
1010 T:- 3
1050 T:25
1070 T:- 9
1110 T:24
1130 T:-13
1170 T:13
1190 T:-10
1230 T:15
1250 T:-11
1290 T:25
1310 T:-11
1350 T:29
1370 T:-19
1410 T: 9
1430 T:- 6
1470 T:12
1490 T:- 6
1520 C:$CORRECT1=3
1530 C:$CORRECT2=4
1540 C:$CORRECT3=10
1550 C:$CORRECT4=14
1560 C:$CORRECT5=16
1570 C:$CORRECT6=11
1580 C:$CORRECT7=3
1590 C:$CORRECT8=4
1600 C:$CORRECT9=14
1610 C:$CORRECT10=10
1620 C:$CORRECT11=3
1630 C:$CORRECT12=6

Listing 4

805 R:MULTIPLICATION PROBLEMS -- save in disk file named MULTIPLY or on separate tape.
810 T:10  [MULTIPLICATION PROBLEMS TO
830 T:X 7 [MERGE WITH MAIN PROGRAM
870 T: 8
890 T:X 4
930 T: 5
950 T:X 5
990 T: 7
1010 T:X 3
1050 T: 3
1070 T:X 9
1110 T:12
1130 T:X 3
1170 T:11
1190 T:X 5
1230 T: 6
1250 T:X 8
1290 T: 7
1310 T:X 8
1350 T: 9
1370 T:X 9
1410 T:11
1430 T:X 6
1470 T:12
1490 T:X 5
1520 C:$CORRECT1=70
1530 C:$CORRECT2=32
1540 C:$CORRECT3=25
1550 C:$CORRECT4=21
1560 C:$CORRECT5=27
1570 C:$CORRECT6=36
1580 C:$CORRECT7=55
1590 C:$CORRECT8=48
1600 C:$CORRECT9=56
1610 C:$CORRECT10=81
1620 C:$CORRECT11=66
1630 C:$CORRECT12=60

Listing 5

805 R:DIVISION PROBLEMS -- save in disk file named DIVIDE or on separate tape.
810 T:10  [DIVISION PROBLEMS TO MERGE
830 T:/ 2 [WITH MAIN PROGRAM
870 T: 8
890 T:/ 4
930 T:15
950 T:/ 5
990 T:42
1010 T:/ 6
1050 T:77
1070 T:/11
1110 T:24
1130 T:/ 8
1170 T:35
1190 T:/ 7
1230 T:56
1250 T:/ 8
1290 T:25
1310 T:/ 5
1350 T:28
1370 T:/ 4
1410 T:48
1430 T:/ 6
1470 T:64
1490 T:/ 8
1520 C:$CORRECT1=5
1530 C:$CORRECT2=2
1540 C:$CORRECT3=3
1550 C:$CORRECT4=7
1560 C:$CORRECT5=7
1570 C:$CORRECT6=3
1580 C:$CORRECT7=5
1590 C:$CORRECT8=7
1600 C:$CORRECT9=5
1610 C:$CORRECT10=7
1620 C:$CORRECT11=8
1630 C:$CORRECT12=8
ANTIC v3.05 / MARCH 1984 / PAGE 32

EDUCATION

TELLING TIME IN PILOT

Easy educational program—only 104 lines

by Richard Seltzer

SYNOPSIS

This is a simple and well-documented program to teach children to tell time using three levels of difficulty. Best of all, it’s only 104 lines long and runs on all Atari computers. Antic Disk subcribers simply LOAD D:TIME.PLT [RETURN]. Now type RUN.

In “Turtle Sketch Pad” in the December 1983 Antic, it was interesting to see how to use PEEK and POKE-type commands in PILOT to get results similar to programs written in BASIC.

But the real power and value of PILOT comes from its simplicity. Programs that stick to PILOT (without all the PEEKS and POKEs) can be written and rejuggled right at the keyboard and can be understood at a glance.

In other words, for question and answer kinds of drills and exercises, teachers or parents can write programs in PILOT as easily as they might prepare worksheets or handouts. PILOT programs are a very do-it-yourself medium. The following program illustrates the power and simplicity of PILOT with Turtle Graphics. I wrote it for my daughter Heather, age six, who wanted practice in telling time. It provides three levels of difficulty — hours alone, quarter hours, and five minute increments — all in just 104 short instructions.

PROGRAM NOTES

PILOT’s TURN and TURNTO commands, using the 360 degrees of a circle, are well suited to drawing lines radiating from a center point, like the hands of a clock. For instance, for the hour hand, we pick a random number from 0 to 11 (line 170), set 0 equal to 12 (line 180). Then (in line 200) we go to the center of the screen (0,0), and from the straight up position (TURNTO in line 190) turn 30 degrees times the number of the hour and draw a line 15 units long (just a bit shorter than the minute hand, which we arbitrarily made 20 units long in line 190).

For the Quarter Hour version, we add an extra line (line 390) so the hour hand realistically moves ahead a quarter of 30 degrees (or 15/2) for each quarter hour beyond the hour. Similarly for the five minute version (line 590), the hour hand moves ahead a twelfth of 30 degrees (5/2) for each five minute increment beyond the hour.

Using the clock hands alone, without the numbers, made the games more interesting to play and also greatly simplified the programming.

Variables:

In the five minute version, if the correct answer was 5:05, with the standard format of #H:#M the program would expect an answer of 5:5. So in line 660, we add a match of #H:05, so the right answer is recognized as right. Also, when the answer is an exact hour, the natural inclination is to type just the number of the hour, without a colon and zeroes. Lines 460 and 670 make sure that that, too, will be accepted as a match.

Richard Seltzer is the author of two children’s books, The Lizard of Oz and Now and Then and Other Tales from Ome. He lives in West Roxbury, Mass.
10 T:WHAT'S YOUR NAME?
20 A:$NAME
30 GR:CLEAR
40 *CIRCLE
50 GR:PEN RED;GOTO 0,0;TURNTO #X;GO 25
60 C:#X=#X+1
70 J(#X<>360):*CIRCLE
80 *START
90 C:#R=0
100 C:#T=0
110 T:DO YOU WANT TO PLAY HOURS (H), QUARTER HOURS (Q) OR FIVE MINUTES (M)? (TYPE H,Q, OR M)
120 A:
130 M:H,Q,M
140 JM:*HOUR,*QUARTER,*MINUTE
150 JN:*START
160 *HOUR
170 C:#H=?\12
180 C(#H=0):#H=12
190 GR:GOTO 0,0;TURNTO 0;PEN YELLOW;DRAW 20
200 GR:GOTO 0,0;TURNTO #H*30;DRAW 15
210 GR:PEN RED;GOTO 0,0
220 T:
230 T:WHAT TIME IS IT, $NAME? (JUST TYPE THE HOUR)
240 A:
250 M:#H
260 C:#T=#T+1
270 TN:NO, IT'S REALLY #H. GOOD LUCK ON THE NEXT ONE, $NAME.
280 PAN:150
290 UY:*RIGHT
300 GR:GOTO 0,0;TURNTO #H*30;PEN ERASE;DRAW 15
310 J(#T<12):*HOUR
320 GR(#T=12):GOTO 0,0;TURNTO 0;PEN ERASE;DRAW 20
330 J(#T=12):*REPLAY
340 *QUARTER
350 C:#H=?\12
360 C(#H=0):#H=12
370 C:#Q=?\4
380 C:#N=15*#Q
390 GR:GOTO 0,0;TURNTO #H*30;TURN #Q*(15/2);PEN YELLOW;DRAW 15
400 GR:GOTO 0,0;TURNTO #Q*90;DRAW 20
410 GR:PEN RED;GOTO 0,0
420 T:
430 T:WHAT TIME IS IT, $NAME? (USE THE FORM 9:15, 10:30, ETC.)
440 A:
450 M:#H:#N
460 M(#Q=0):#H
470 C:#T=#T+1
480 UY:*RIGHT
490 UN:*ANSWER
500 GR:GOTO 0,0;TURNTO #H*30;TURN #Q*(15/2);PEN ERASE;DRAW 15
510 GR:GOTO 0,0;TURNTO #Q*90;DRAW 20
520 J(#T<12):*QUARTER
530 J(#T=12):*REPLAY
540 *MINUTE
550 C:#H=?\12
560 C(#H=0):#H=12
570 C:#M=?\12
580 C:#N=#M*5
590 GR:GOTO 0,0;TURNTO #H*30;TURN #M*(5/2);PEN YELLOW;DRAW 15
600 GR:GOTO 0,0;TURNTO #M*30;DRAW 20
610 GR:PEN RED;GOTO 0,0
620 T:
630 T:WHAT TIME IS IT, $NAME? (USE THE FORM 5:25, 12:05, ETC.)
640 A:
650 M:#H:#N
660 M(#N=5):#H:05
670 M(#N=0):#H
680 C:#T=#T+1
690 UY:*RIGHT
700 UN:*ANSWER
710 GR:GOTO 0,0;TURNTO #H*30;TURN #M*(5/2);PEN ERASE;DRAW 15
720 GR:GOTO 0,0;TURNTO #M*30;DRAW 20
730 J(#T<12):*MINUTE
740 J(#T=12):*REPLAY
750 *RIGHT
760 T:RIGHT!
770 C:#R=#R+1
780 SO:13
790 PA:15
800 SO:17
810 PA:15
820 SO:20
830 PA:15
840 SO:25
850 PA:30
860 SO:0
870 E:
880 *ANSWER
890 T(#N=0):NO, IT'S #H:00. GOOD LUCK ON THE NEXT ONE, $NAME.
900 PA(#N=0):150
910 E(#N=0):
920 T(#N=5):NO, IT'S #H:05. GOOD LUCK ON THE NEXT ONE, $NAME.
930 T(#N<>5):NO, IT'S #H:#N. GOOD LUCK ON THE NEXT ONE, $NAME.
940 PA:150
950 E:
960 *REPLAY
970 T:VERY GOOD, $NAME. OUT OF 12, YOU GOT #R RIGHT. WANT TO PLAY SOME MORE?
980 A:
990 M:Y,YES
1000 JM:*START
1010 JN:*END
1020 *END
1030 T:GOODBYE, $NAME.
1040 E: