ANTIC v1.1 / APRIL 1982 / PAGE 12
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
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
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 Name Register Value Used for Address Red 0 70 Graphics 708 Yellow 1 26 Graphics 709 Blue 2 148 Text Window & Graphics 710 None 3 148 Not Used 711 Erase 4 0 Background & Border 712
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 Hue Luminance 0 = gray 0—lowest possible luminance (black) 1 = green brown 2— 2 = yellow /orange 4— 3 = orange 6— 4 = red /orange 8— 5 = pink 10— 6 = bluish purple 12— 7 = purple 14—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
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):
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 FOR0 _1_3_5_6_16_ NULL NULL NULL 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
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
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:
Function Voice 0 Voice 1 Voice 2 Voice 3 Pitch 53760 53762 53764 53766 Control 53761 53763 53765 53767
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 NUMBER 0 2 4 6 8 10 14 CONTROL REGISTER VALUES 0 32 64 128 160 192 224
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
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 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
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 COLUMNS128 64 32 16 8 4 2 1 DECIMAL VALUE OF BYTES7 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
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
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
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.
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).
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.
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.
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.
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.
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:
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
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
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
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
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.
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.
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.
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: