Here is the code listing for Plotter II, an update to the original Plotter that demonstrates the concepts of Structured Applesoft, as defined by Juiced.GS staff writer Ivan Drucker in Volume 14, Issue 4, and Volume 15, Issue 1. This code is also available in SHK and ZIP archive formats.
See also the online supplements to the print material.
REM Plotter v1.1, March 2010 REM by Ivan Drucker REM This program plots random hi-res pixels. REM It changes color when a user presses a key. REM If the key is 0-7, it uses that color. REM C clears the screen. Q or ESC quits. REM If it's any other key, the computer beeps. REM This program demonstrates the syntax of Structured Applesoft. REM It illustrates most of the concepts described in the Structured Applesoft articles REM in the December 2009 and March 2010, issues of Juiced.GS, as well the online bonus REM material at http://www.juiced.gs. Specific concepts demonstrated in this program: REM source code written in editor, then pasted into emulator or EXEC'd on Apple II REM subroutine-oriented program flow with minimal main routine REM organization of code (global variable declaration 10-99, 100-9999 main routine, 10000-> subroutines) REM self-contained, specific-purpose subroutines with labels, parameters and return values REM IF, FOR, WHILE, and TRY (with bug fix for March 2010 article) structures REM global and local variable and array declaration, and constant indication REM indentation as part of structures REM blank lines for clarity REM extensive non-numbered commenting REM user comments separated with :: from structure part comments REM using QuitFlag to perform shutdown operations along the way to the program end REM consistent, clear syntax with regard to parantheses, colons, and other details REM one statement per line except for structure parts or logically related statements REM temporary variables REM no GOTO except in structure parts REM Not demonstrated: REM SWITCH structure REM THROWing errors REM using FINALLY with THROW or RETURN from a catch block REM every variety of IF and WHILE structure REM Note: it is strongly recommended that you view this Structured Applesoft REM source file in TextWrangler (free) or BBEdit (both at http://www.barebones.com) REM with the Applesoft BASIC language module installed. You can get the module REM from http://www.juiced.gs in the Dec 2009 Issue Links under Plotter. REM REM To install it, right-click on TextWrangler or BBEdit, choose Show Package Contents, REM and drop it into Contents/Resources/Language Modules. Then restart the editor, REM open this file, and choose Applesoft BASIC from the language menu at the bottom REM of the window. REM ----PROGRAM STARTS HERE----- NEW REM lines 0-9 are reserved 10 REM Initial Setup REM declare global variables 40 LET QT = 0 : REM QT->quitFlag 41 LET PC = 1 : REM PC->pixelColor REM declare global constants 50 DIM CN$(7) : REM CONSTANT; CN$->colorNames 51 CN$(0) = "BLACK 1" : CN$(1) = "GREEN" : CN$(2) = "VIOLET" : CN$(3) = "WHITE 1" 52 CN$(4) = "BLACK 2" : CN$(5) = "ORANGE" : CN$(6) = "BLUE" : CN$(7) = "WHITE 2" 55 LET E$ = CHR$(27) : REM CONSTANT E$->ESC key 100 REM Main Routine 110 TEXT : HOME 115 HGR 150 P1$ = "INITIAL COLOR?" : GOSUB 11200 : REM AskAndSetColor 160 REM IF 161 ON (NOT QT) GOTO 190 : GOTO 300 190 GOSUB 10400 : REM DisplayColorName 200 REM WHILE 201 ON (NOT QT) GOTO 210 : GOTO 289 210 GOSUB 10100 : REM CheckForKey 220 IF (R1$<>"") THEN P1$ = R1$ : GOSUB 10200 : REM HandleKeyPress 240 GOSUB 10000 : REM ChoosePlotSpot 250 P1 = R1 : P2 = R2 : GOSUB 10700 : REM PlotPixel 260 P1 = 1 : GOSUB 11100 : REM Delay 288 GOTO 200 289 REM END WHILE 290 GOTO 330 300 REM ELSE :: initial color entry error, or ESC 310 GOSUB 11000 : REM DrawBigX 320 P1 = 1 : GOSUB 11100 : REM Delay 330 REM END IF 350 GOSUB 10900 : REM SayGoodbye 499 REM END IF 9999 END REM Subroutines 10000 REM SUB^ChoosePlotSpot:10000-10099 {} REM Randomly picks and returns hi-res coordinate REM in: nothing REM out: R1->H coordinate (0-279), R2->V coordinate (0-161) REM indicate use of global variable in this routine 10001 REM global PC REM get horizontal position 10010 REM IF 10011 ON (PC=0 OR PC=3 OR PC=4 OR PC=7) GOTO 10015 : GOTO 10030 REM if color is black or white, plot any horizontal pixel 10015 ZZ = INT(RND(1) * 279) 10020 GOTO 10060 10025 REM ELSE REM plot color 1 or 5 on odd horizontal pixels, 2 or 6 on even 10030 ZZ = INT(RND(1) * 139) 10040 ZZ = (ZZ * 2) 10050 IF (PC=1 OR PC=5) THEN ZZ = (ZZ + 1) 10060 REM END IF 10070 R1 = ZZ REM get vertical position 10080 R2 = INT(RND(1)*160) 10099 RETURN 10100 REM SUB^CheckForKey:10100-10199 {} REM Checks to see if the user pressed a key, and returns it if so. REM in: nothing REM out: R1$ = key pressed or "" if none REM declare local variable for this subroutine only 10105 LET KB = 0 : REM KB->keyboardBufferValue 10110 KB = PEEK(49152) 10115 REM IF 10116 ON (KB>127) GOTO 10120 : GOTO 10150 10120 R1$ = CHR$(KB - 128) : REM convert ASCII value of key to string 10130 POKE 49168,0 : REM clear KB buffer 10135 GOSUB 10600 : REM QuickBuzz 10140 GOTO 10160 10150 REM ELSE 10155 R1$ = "" : REM indicate no key pressed 10160 REM END IF 10199 RETURN 10200 REM SUB^HandleKeyPress:10200-10299 {} REM Calls appropriate routine REM based on which key was pressed REM in: P1$ = key REM out: nothing 10210 REM IF 10211 ON (P1$="C" OR P1$="c") GOTO 10215 : GOTO 10230 10215 HGR : REM Clear HiRes Screen 10220 GOTO 10290 10230 REM ELSE IF 10231 ON (P1$="Q" OR P1$="q" OR P1$=E$) GOTO 10235 : GOTO 10250 10235 GOSUB 10800 : REM ShutDown 10240 GOTO 10290 10250 REM ELSE IF 10251 ON (ASC(P1$)>47 AND ASC(P1$)<56) GOTO 10260 : GOTO 10280 REM check for 0 through 7, indicating color should be changed 10260 P1 = VAL(P1$) : GOSUB 10300 : REM ChangePixelColor 10265 GOSUB 10400 : REM DisplayColorName 10270 GOTO 10290 10280 REM ELSE 10285 GOSUB 10500 : REM Beep 10290 REM END IF 10298 RETURN 10300 REM SUB^ChangePixelColor:10300-10399 {} REM Assigns the pixel color; persists until changed REM in: P1 = color to be set (0-7) REM out: nothing REM globals: PC will contain new color value 10301 REM global PC 10310 PC = P1 10320 HCOLOR = PC 10399 RETURN 10400 REM SUB^DisplayColorName:11200-11299 {} REM Prints name of current color in text area REM in/out: nothing REM indicate use of global in this routine 10401 REM GLOBAL PC 10410 VTAB 22 10420 PRINT CN$(PC);" " 10499 RETURN 10500 REM SUB^Beep:10500-10599 {} REM Beeps once, and that's all REM in/out: nothing 10510 CALL -1052 10599 RETURN 10600 REM SUB^QuickBuzz:10600-10699 {} REM buzzes speaker briefly REM in/out: nothing 10610 FOR ZZ=1 TO 5 : POKE -16336,0 : NEXT ZZ 10699 RETURN 10700 REM SUB^PlotPixel:10700-10799 {} REM Draws a dot on the HGR screen, or a big X if quitting REM parameters: P1:H position, P2:V position REM indicate use of global variable in this routine 10701 REM GLOBAL QT REM Declare local vars for this routine 10705 LET PX=P1 : REM PH->pixelHPos 10706 LET PY=P2 : REM PV->pixelVPos 10710 REM IF 10711 ON (NOT QT) GOTO 10730 : GOTO 10750 : REM if not quitting 10730 HPLOT PX,PY : REM plot the point 10740 GOTO 10770 10750 REM ELSE; program is quitting, so handle 10760 GOSUB 11000 : REM DrawBigX 10770 REM END IF 10799 RETURN 10800 REM SUB^ShutDown:10800-10899 {} REM Initiates program exit. quitFlag is set; other REM routines can test for it and clean things up REM if needed. REM in/out: nothing REM globals: QT set to 1 10801 REM GLOBAL QT 10810 QT = 1 : REM set quitFlag 10899 RETURN 10900 REM SUB^SayGoodbye:10900-10999 {} REM sets text mode, clears screen, says bye to user REM in/out: nothing 10910 TEXT 10920 HOME 10930 PRINT "BYE!" 10999 RETURN 11000 REM SUB^DrawBigX:11000-11099 {} REM Draws a big white X across the screen and waits for a short duration REM used during quit REM in/out: nothing REM HCOLOR will be 3; note global PC will remain what it was 11010 P1 = 3 : GOSUB 10300 : REM ChangePixelColor 11020 HPLOT 0,0 TO 279,159 11030 HPLOT 0,159 TO 279,0 11050 P1 = 3 : GOSUB 11100 : REM Delay 11099 RETURN 11100 REM SUB^Delay:11100-11199 {} REM Does nothing for a length of time REM in: P1->delay multiplier REM out: nothing 11110 FOR ZZ = 1 TO P1 11115 FOR ZY = 1 TO 75 : NEXT ZY 11120 NEXT ZZ 11199 RETURN 11200 REM SUB^AskAndSetColor:11200-11499 {} REM Prompts user for color (and demonstrates advanced error handling in a while loop) REM in: P1$ = prompt string REM out: nothing REM for a full explanation of the error handling below, see the article REM bonus material, in the March 2010 Issue Links at http://www.juiced.gs 11205 LET IC = 0 : REM IC->Initial Color 11206 LET PS$ = P1$ : REM PS$->Prompt String 11207 LET OK = 0 : REM OK->if true, ready to return, if false, loops again 11208 LET R1 = -1 : REM R1$->default return value 11210 REM WHILE 11211 ON (NOT OK) GOTO 11230 : GOTO 11489 11230 REM TRY 11231 Z9 = PEEK(248) : ONERR GOTO 11300 11240 VTAB 21 : HTAB 1 : PRINT PS$; REM next line could throw a REENTER error on non-numeric input 11250 INPUT "";IC REM GOSUB 10300 could throw an ILLEGAL QUANTITY error if IC > 7 11260 P1 = IC : GOSUB 10300 : REM ChangePixelColor REM clean up text 11270 HOME REM set return value and indicate ready to return 11280 OK = 1 11290 POKE 216,0 : GOTO 11400 11300 REM CATCH 11301 POKE 216,0 : ER = PEEK(222) : POKE 223,Z9 : CALL -3288 11310 REM CATCH ERROR: REENTER :: if user enters a non-number 11311 ON (ER=254) GOTO 11320 : GOTO 11330 11320 PRINT : PRINT SPC(39) : HTAB 1 11321 PRINT "PLEASE ENTER A NUMBER." 11329 GOTO 11400 11330 REM CATCH ERROR: ILLEGAL QUANTITY :: if HCOLOR > 7 11331 ON (ER=53) GOTO 11340 : GOTO 11380 11340 PRINT : PRINT SPC(39) : HTAB 1 11345 PRINT "VALID COLORS ARE 0 THROUGH 7." 11349 GOTO 11400 11380 REM CATCH OTHERS REM always required, even if it does nothing REM in this case, only possible other error is BREAK (CTRL-C) REM if we get that, or anything else unexpected, REM quit via QuitFlag (flow out of program, shutting down along the way) 11382 OK = 1 11383 GOSUB 10800 : REM ShutDown 11389 GOTO 11400 11400 REM FINALLY 11401 GOSUB 11410 : GOTO 11450 REM always buzzes after entry 11410 GOSUB 10600 : REM QuickBuzz 11420 RETURN 11450 REM END TRY 11488 GOTO 11210 11489 REM END WHILE 11499 RETURN