10 REM SNAIL 20 REM Keith Anderson 30 REM (c) CET 1983 Published by BBC Publications 40 REM version 2.0 50 : 60 CLEAR 70 REM PORT SETUP 80 port = &FE60 :REM User port (see manual for details). 90 ?&FE62 = 15 :REM 00001111; 0 = input; 1 = output 100 PROCmotors_on 110 : 120 REM USER AREA 130 Xfactor = 1.175 :REM Adjust slightly on inaccurate TV sets 140 speedcontrol = 2 150 : 160 REM MAIN PROGRAM 170 REM Detect arrow keys 180 *FX 4,1 190 MODE 7 200 PROCsetup_general 210 PROCsetup_program 220 : 230 ON ERROR IF ERR=17 THEN GOTO 250 ELSE PROCend:REPORT:PRINT " on line"ERL:END 240 PROCintroduction 250 MODE7 260 IF (?port AND 32) THEN PROCnogo : PROCend : END:REM Check if Buggy connected 270 PROCoff :REM Cursor off 280 REPEAT 290 VDU 26 :REM Reset text & graphics windows 300 CLS 310 PROCmenu 320 IF option=1 THEN MODE 4 : PROCrecord : MODE 7 330 IF option=2 THEN MODE 4 : PROCdo : MODE 7 340 IF option=3 THEN MODE 4 : PROCscale : MODE 7 350 UNTIL option=4 360 : 370 MODE 7 380 PROCcomplete 390 END 400 : 410 : 420 REM PROCEDURES SPECIFICALLY FOR "SNAIL" 430 DEF PROCdo 440 PROCoff 450 IF mem%(1)=0 OR NOT enoughspace THEN PROCnomem ELSE PROCdo_again 460 ENDPROC 470 : 480 DEF PROCdo_again 490 LOCAL move,motor 500 VDU 19,1,7;0; :REM White foreground 510 VDU 19,0,1;0; :REM Red background 520 PROCget_ready 530 VDU 19,1,4;0; :REM Blue foreground 540 VDU 19,0,7;0; :REM White background 550 PROCcentre ("Repeating the route in memory.",6) 560 num = 0 570 room = TRUE 580 angle = 0 590 PROCupdate 600 REPEAT 610 IF room THEN PROCinc_pointer 620 PRINT TAB(1,2) num 630 move = INSTR(letter$,mem$(num))-1 640 motor = mem%(num) 650 PRINT TAB(34,2) MID$(letter$,move+1,1) ". " 660 IF move=forwards OR move=backwards THEN PRINT TAB(36,2) INT(mem%(num)*FWD+0.5) 670 IF move=left OR move=right OR move=wait THEN PRINT TAB(36,2) mem%(num) 680 IF move<>wait AND move<>stop THEN PROCmove_buggy (move,motor,speedcontrol,bumpers) 690 IF hit THEN PROCcrash (hit) 700 IF move=wait THEN PROCdelay (motor*1300) 710 UNTIL move=stop 720 PROCcentre ("Route completed",4) 730 PROCspace (6) 740 ENDPROC 750 : 760 DEF PROCget_ready 770 VDU 26 :REM Reset text and graphics windows 780 CLS 790 PROCscreen :REM Draw "Instrument panel" 800 VDU 26 :REM Reset text and graphics windows 810 PROCcentre (program_name$,1) 820 VDU 29,640-(horiz DIV 2*Xscale);320;:REM Set Graphics origin 830 PROCboundary (0,0,horiz,vert) 840 VDU 28,0,31,39,24 :REM Text window 850 BGX = horiz DIV 2 860 BGY = 12 870 PROCcalcpos 880 PROCcalcbug (GRX,GRY,0) 890 PROCdrawbug 900 oldX = GRX : oldY = GRY :REM Save screen position 910 PROCspace (6) 920 REPEAT UNTIL INKEY (nokey) 930 ENDPROC 940 : 950 DEF PROCinc_pointer 960 num = num + 1 970 IF num >= size-1 THEN PROCno_space 980 ENDPROC 990 : 1000 DEF PROCintroduction 1010 CLS 1020 PROCoff 1030 PROCdouble (CHR$130 +program_name$ +CHR$135,-1,5) 1040 PROCcentre ("Enter a route using",8) 1050 PROCcentre ("letter/number notation.",10) 1060 PROCcentre ("The Buggy will follow the",14) 1070 PROCcentre ("route and draw a ""SNAIL",16) 1080 PROCcentre ("TRAIL"" on the screen.",18) 1090 PROCspace (22) 1100 ENDPROC 1110 : 1120 DEF PROCmenu 1130 CLS 1140 PRINT TAB(0,1) CHR$130 +"BBC Buggy" 1150 PROCdouble (CHR$130 +program_name$ +CHR$135,-1,5) 1160 PRINT TAB(7,10) "1. Enter route into memory." 1170 PRINT TAB(7,12) "2. Repeat route in memory." 1180 PRINT TAB(7,14) "3. Reset scale" 1190 PRINT TAB(7,16) "4. Exit program." 1200 PRINT TAB(3,20) "Your choice: "; 1210 option = VAL( FNinput (1,"1234")) 1220 ENDPROC 1230 : 1240 DEF PROCnomem 1250 CLS 1260 VDU 19,0,1,0,0,0 :REM Red background 1270 COLOUR 129 1280 COLOUR 0 1290 PROCedge 1300 PROCcentre ("",5) 1310 PROCcentre (program_name$,6) 1320 PROCcentre ("",7) 1330 PROCcentre ("",14) 1340 PROCcentre ("No route in memory.",15) 1350 PROCcentre ("",16) 1360 COLOUR 128 1370 COLOUR 1 1380 PROCspace (24) 1390 ENDPROC 1400 : 1410 DEF PROCno_space 1420 VDU 7,4,28,0,31,39,24 1430 room = FALSE 1440 mem$(num) = "S" 1450 mem%(num) = 0 1460 PROCspace (6) 1470 ENDPROC 1480 : 1490 DEF PROCrecord 1500 IF NOT enoughspace THEN PROCscale 1510 VDU 19,1,7;0; :REM white foreground 1520 VDU 19,0,1;0; :REM red background 1530 REPEAT 1540 VDU 26 1550 PROCoff 1560 CLS 1570 PROCedge 1580 PROCcentre ("Design a route for the Buggy.",1) 1590 PROCcentre ("Buggy commands are: ",3) 1600 PROCcentre ("F Forward (cm)",5) 1610 PROCcentre ("B Back (cm)",6) 1620 PROCcentre ("L Left (deg)",7) 1630 PROCcentre ("R Right (deg)",8) 1640 PROCcentre ("W Wait (secs)",9) 1650 PROCcentre ("S Stop ",10) 1660 PROCcentre ("Enter commands: ",12) 1670 VDU 28,5,27,38,13 :REM Text window 1680 num = 0 1690 room = TRUE 1700 *FX 229,1 1710 REM Disable ESCAPE 1720 REPEAT 1730 IF room THEN PROCinc_pointer 1740 IF NOT room THEN PROCcentre ("No more space for instructions.",4) 1750 IF num > 14 THEN VDU 28,24,27,38,13 1760 PROCon 1770 REPEAT 1780 G$ = CHR$( ASC FNwait AND &DF ) 1790 IF NOT room OR INKEY(escape) THEN G$="S" 1800 UNTIL INSTR(letter$,G$) 1810 IF G$="F" THEN PRINT "Forward "; 1820 IF G$="B" THEN PRINT "Back "; 1830 IF G$="L" THEN PRINT "Left "; 1840 IF G$="R" THEN PRINT "Right "; 1850 IF G$="W" THEN PRINT "Wait "; 1860 IF G$="S" AND room THEN PRINT "Stop "; 1870 REPEAT 1880 line = VPOS 1890 temp = 0 1900 IF G$<>"S" THEN temp = VAL(FNinput(3,digit$)) 1910 IF temp=0 AND G$<>"S" THEN VDU 7:PROCdelay (200):PRINT TAB(8,line); 1920 UNTIL temp>0 OR G$="S" 1930 IF G$<>"S" THEN SOUND 1,-10,200,4 1940 IF G$="F" OR G$="B" THEN mem%(num) = temp/FWD ELSE mem%(num) = temp 1950 IF G$="S" THEN mem%(num) = 0 1960 mem$(num) = G$ 1970 UNTIL G$="S" 1980 *FX 229 1990 REM Re-enable ESCAPE 2000 mem$(num)="S" 2010 SOUND &11,-8,230,8 2020 PROCdelay (20) 2030 VDU 26 2040 PROCcentre ("Accept Y/N ",30) 2050 G$ = FNinput(1,"YyNn") 2060 UNTIL G$="Y" OR G$="y" 2070 ENDPROC 2080 : 2090 DEF PROCscale 2100 enoughspace = FALSE 2110 scale = 10 2120 Xscale = scale * Xfactor 2130 VDU 19,1,7;0; :REM white foreground 2140 VDU 19,0,1;0; :REM red background 2150 CLS 2160 PROCcentre ("Place the Buggy in its area as shown,",2) 2170 PROCcentre ("with the wheels 12 cms from the edge.",4) 2180 PROCrectangle (226,288,1054,800) 2190 PRINT TAB(19,8) "N" TAB(9,14) "W" TAB(30,14) "E" 2200 VDU 29,0;288; :REM Reset graphics origin 2210 PROCcalcpos 2220 PROCcalcbug (640,12*scale,0) 2230 PROCdrawbug 2240 VDU 28,1,30,38,24 :REM Make text window 2250 VDU 29,0;0; :REM Reset graphics origin 2260 REPEAT 2270 CLS 2280 PROCedge 2290 PRINT TAB(36,1) "cm" 2300 PRINT TAB(0,1) "Enter distance West to East "; 2310 horiz = VAL(FNinput(3,digit$)) 2320 PRINT TAB(36,3) "cm" 2330 PRINT TAB(0,3) "Enter distance North to South "; 2340 vert = VAL(FNinput(3,digit$)) 2350 IF FNmin (horiz,vert)0 THEN MOVE LBX,LBY:PLOT 6,FMX,FMY:hit = -1 3460 IF (bumper AND rightbumper)<>0 THEN MOVE RBX,RBY:PLOT 6,FMX,FMY:hit = 1 3470 SOUND 0,-15,9+hit,4 :REM Different sound for each bumper 3480 VDU 29,0;0; :REM Graphics origin 3490 VDU 24,510;220;800;700; :REM Graphics window 3500 MOVE 510,270 : MOVE 580,270 3510 PLOT 86+hit,580,220 :REM Only the relevant triangle is filled 3520 MOVE 730,270 : MOVE 800,270 3530 PLOT 86-hit,730,220 3540 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3550 PROCboundary (0,0,horiz,vert) 3560 PROCmove_buggy (backwards,safedistance,speedcontrol,nosensors) 3570 VDU 29,0;0; :REM Graphics origin 3580 VDU 24,510;220;800;700; :REM Graphics window 3590 MOVE 510,270 : MOVE 580,270 3600 PLOT 87,580,220 :REM Delete both triangles 3610 MOVE 730,270 : MOVE 800,270 3620 PLOT 87,730,220 3630 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3640 PROCboundary (0,0,horiz,vert) 3650 ENDPROC 3660 : 3670 DEF PROCdrawbug 3680 REM Ensures good corners at rear 3690 MOVE LBX,LBY 3700 PLOT 6,RBX,RBY 3710 MOVE RLX,RLY 3720 PLOT 30,FLX,FLY 3730 MOVE RLX,RLY 3740 PLOT 30,RRX,RRY 3750 PLOT 30,FRX,FRY 3760 PLOT 70,RLX,RLY 3770 ENDPROC 3780 : 3790 DEF PROCend 3800 REM Switches motors off, resets cursor, EDIT & ESCAPE keys, buffers, and PRINT format 3810 PROCmotors_off 3820 PROCon 3830 *FX 4 3840 *FX 229 3850 *FX 15 3860 @% = 10 3870 ENDPROC 3880 : 3890 DEF PROCmotors_off 3900 ?port = 8 3910 ENDPROC 3920 : 3930 DEF PROCmotors_on 3940 ?port = 0 3950 ENDPROC 3960 : 3970 DEF PROCmove_buggy (direction,move,speed,sensors) 3980 count = 0 3990 hit = 0 4000 REPEAT 4010 count = count + 1 4020 ?port = direction :PROCdelay (speed) 4030 ?port = direction OR 2:PROCdelay (speed) 4040 hit = (?port AND sensors) 4050 UNTIL hit OR count>=move 4060 ?port=0 4070 IF direction = left THEN turn = turn - count 4080 IF direction = right THEN turn = turn + count 4090 IF direction = backwards THEN distance = distance - count 4100 IF direction = forwards THEN distance = distance + count 4110 PROCbug 4120 PROCupdate 4130 ENDPROC 4140 : 4150 DEF PROCnogo 4160 PROCcentre ("Buggy not connected, END OF PROGRAM.",21) 4170 PRINT 4180 ENDPROC 4190 : 4200 DEF PROCscreen 4210 REM "Instrument panel" 4220 VDU 28,0,30,39,24 :REM Text window 4230 CLS 4240 RESTORE 4250 FOR index = 1 TO 14 4260 READ M1,M2,D1,D2 4270 MOVE M1,M2 4280 DRAW D1,D2 4290 NEXT index 4300 PRINT TAB(1,0) "No." 4310 PRINT TAB(6,0) "Position" 4320 PRINT TAB(19,0) "Deg" 4330 DATA 6, 280,1270, 280, 6, 210, 500, 210, 590, 210, 720, 210 4340 DATA 810, 210,1010, 210, 6, 140,1270, 140, 1070, 210,1270, 210 4350 DATA 150, 280, 150, 140, 500, 280, 500, 140, 590, 280, 590, 140 4360 DATA 720, 280, 720, 140, 810, 280, 810, 140, 1010, 280,1010, 140 4370 DATA 1070, 280,1070, 140, 1170, 280,1170, 210 4380 PROCedge 4390 ENDPROC 4400 : 4410 DEF PROCsetup_general 4420 REM Buggy dimensions are in centimetres 4430 BF = 3.9 :REM Buggy centre to bumper 4440 BR = 9 :REM Buggy centre to chassis rear 4450 CW = 6 :REM Half chassis width 4460 BW = 9 :REM Bumper width (1 side) 4470 FWD = 0.1431944:REM Travel (cms/pulse) 4480 safedistance = ( INT( SQR( BR*BR + CW*CW ) -BF )) / FWD +14 4490 REM Values to compare with port 4500 bumpers = 192 4510 leftbumper = 128 4520 rightbumper = 64 4530 nosensors = 0 4540 REM Keyboard control words 4550 uparrow = -58 4560 downarrow = -42 4570 leftarrow = -26 4580 rightarrow = -122 4590 space = -99 4600 nokey = -129 4610 escape = -113 4620 REM Port values for Buggy movement 4630 forwards = 0 4640 backwards = 5 4650 left = 4 4660 right = 1 4670 digit$ = "1234567890" :REM Acceptable characters for numeric input 4680 space$ = STRING$(36," ") 4690 @% = &303 :REM Print format 4700 ENVELOPE 3,1,5,-5,5,10,10,10,5,0,-1,-1,126,0 4710 ENDPROC 4720 : 4730 DEF PROCupdate 4740 PRINT TAB(6,2) INT(BGX+0.5) "," INT(BGY+0.5) 4750 angle = (360+angle) MOD 360 4760 PRINT TAB(19,2) angle 4770 ENDPROC 4780 : 4790 DEF PROCwarn (text$) 4800 PROCcentre (text$,4) 4810 SOUND &103,3,100,10 4820 SOUND &102,3,117,10 4830 ENDPROC 4840 : 4850 : 4860 REM UTILITIES 4870 DEF PROCcentre (text$,line) 4880 PRINT TAB(1,line) SPC 38 4890 PRINT TAB( FNcentre (text$),line) text$; 4900 ENDPROC 4910 : 4920 DEF FNcentre (text$) =19-LEN(text$) DIV 2 4930 : 4940 DEF PROCcomplete 4950 CLS 4960 PROCdouble (CHR$ 131 +"Mission completed.",-1,10) 4970 PROCend 4980 ENDPROC 4990 : 5000 DEF PROCdelay (period) 5010 LOCAL index 5020 FOR index = 1 TO period : NEXT index 5030 ENDPROC 5040 : 5050 DEF PROCdouble (text$,X,Y) 5060 IF X<0 THEN X = FNcentre (text$) 5070 PRINT TAB(X-1,Y ) CHR$ 141;text$ 5080 PRINT TAB(X-1,Y+1) CHR$ 141;text$ 5090 ENDPROC 5100 : 5110 DEF PROCedge 5120 PROCrectangle (6,6,1274,1018) 5130 ENDPROC 5140 : 5150 DEF FNinput (length,allowed$) 5160 LOCAL input$,ascii 5170 PRINT STRING$(length,".");STRING$(length,CHR$ 8); 5180 PROCon:*FX 15 5190 REPEAT ascii = ASC FNwait 5200 IF ascii=127 AND LEN(input$)>0 THEN input$ = LEFT$(input$,LEN(input$)-1):VDU ascii 5210 IF INSTR(allowed$,CHR$ ascii) AND LEN(input$)13 AND ascii<>127 THEN ascii = 7 5220 IF ascii=13 AND LEN(input$)<1 THEN ascii = 7 5230 IF ascii=127 THEN VDU 46,8 ELSE VDU ascii 5240 UNTIL ascii=13:PRINT:PROCoff 5250 =input$ 5260 : 5270 DEF FNlimit (X,Y,X1,Y1,X2,Y2) 5280 IF X>X1 AND XY1 AND YB THEN =A ELSE =B 5320 : 5330 DEF FNmin (A,B) 5340 IF A"" 5620 *FX 4 5630 =I$ 5640 :