Plotter II

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