10 REM MAN VERSUS BUGGY 20 REM Keith Anderson 30 REM (c) CET 1983 Published by BBC Publications 40 REM version 2.0 50 : 60 REM PORT SETUP 70 port = &FE60 :REM User port (see manual for details). 80 ?&FE62 = 15 :REM 00001111; 0 = input; 1 = output 90 PROCmotors_on 100 : 110 REM USER AREA 120 Xfactor = 1.175 :REM Adjust slightly on inaccurate TV sets 130 speedcontrol = 1 :REM Higher values make the Buggy slower 140 : 150 REM MAIN PROGRAM 160 ON ERROR IF ERR=17 THEN GOTO 430 ELSE PROCend:REPORT:PRINT" at line"ERL:END 170 : 180 MODE 7 190 PROCsetup_general 200 PROCsetup_program 210 PROCintroduction 220 IF (?port AND 32) THEN PROCnogo : END :REM Check if Buggy connected 230 : 240 MODE 4 250 PROCoff :REM Cursor off 260 REM Disable ESCAPE key 270 *FX 229,1 280 REPEAT 290 VDU 26 :REM Reset text & graphics windows 300 CLS 310 VDU 19,1,7;0; :REM White foreground 320 VDU 19,0,1;0; :REM Red background 330 PROCscale 340 PROCprepare1 350 UNTIL INKEY (space) 360 VDU 19,1,4;0; :REM Blue foreground 370 VDU 19,0,7;0; :REM White background 380 REM Disable edit keys 390 *FX 4,1 400 PROCgo_MVB 410 : 420 REM Re-enable ESCAPE key 430 *FX 229 440 MODE 7 450 PROCerror 460 END 470 : 480 : 490 REM PROCEDURES SPECIFICALLY FOR "MAN VERSUS BUGGY" 500 DEF PROCblank 510 LOCAL I 520 FOR I=0 TO 2 530 PRINT TAB(32,I) " " 540 NEXT 550 ENDPROC 560 : 570 DEF PROCerror 580 LOCAL answer 590 CLS 600 PRINT TAB(0,1) CHR$130 +"BBC Buggy" 610 PRINT TAB(7,10)"1. " +program_name$ +"." 620 PRINT TAB(7,12)"2. Exit program." 630 PRINT TAB(3,20)"Your choice: "; 640 answer = VAL( FNinput (1,"12")) 650 IF answer=1 THEN RUN 660 PROCcomplete 670 ENDPROC 680 : 690 DEF PROCprepare1 700 VDU 26 :REM Reset text and graphics windows 710 CLS 720 PROCscreen :REM Draw "Instrument panel" 730 VDU 26 :REM Reset text and graphics windows 740 PROCcentre ("MANUAL DRIVE",1) 750 VDU 29,640-(horiz DIV 2 *Xscale);320;:REM Set Graphics origin 760 PROCboundary (0,0,horiz,vert) 770 VDU 28,0,31,39,24 :REM Text window 780 BGX = horiz DIV 2 790 BGY = 12 800 PROCcalcpos 810 PROCcalcbug (GRX,GRY,0) 820 PROCdrawbug 830 oldX = GRX : oldY = GRY :REM Save screen position 840 PROCcentre ("Press 'ESCAPE' to change scale",4) 850 PROCspace (6) 860 ENDPROC 870 : 880 DEF PROCgo_MVB 890 LOCAL I$ 900 REPEAT 910 REPEAT UNTIL INKEY (nokey) 920 PROCcentre ("You are now in control of the Buggy !",4) 930 PROCcentre ("Use the arrow keys to move the Buggy",6) 940 REPEAT I$ = FNwait : UNTIL NOT INKEY (nokey) 950 PROCcentre ("Press ESCAPE to exit program.",4) 960 PROCcentre ("Press 'L' to switch the light meter.",6) 970 REPEAT 980 PROCupdate 990 I$ = FNwait 1000 PROCmanual 1010 IF INKEY (L) THEN eyesopen = FNtoggle (eyesopen,L) : PROCblank : IF eyesopen THEN light = ADVAL(1) DIV 100 1020 IF eyesopen THEN PRINT TAB(27,2) light ELSE PRINT TAB(27,2) ":::" 1030 UNTIL INKEY (escape) 1040 PROCcentre ("ESCAPE PRESSED.",4) 1050 UNTIL FNsure 1060 REM Flush sound buffer 1070 *FX 15 1080 ENDPROC 1090 : 1100 DEF PROCintroduction 1110 CLS 1120 PROCoff 1130 PROCdouble (CHR$130 +program_name$ +CHR$135,-1,5) 1140 PROCcentre ("Find the light source yourself.",12) 1150 PROCcentre ("Navigate using only the information",14) 1160 PROCcentre ("displayed on the screen.",16) 1170 PROCspace (21) 1180 ENDPROC 1190 : 1200 DEF PROCmanual 1210 IF INKEY (uparrow ) THEN PROCmove (forwards ,uparrow ,bumpers) 1220 IF INKEY (downarrow ) THEN PROCmove (backwards,downarrow ,nosensors) 1230 IF INKEY (leftarrow ) THEN PROCmove (left ,leftarrow ,bumpers) 1240 IF INKEY (rightarrow) THEN PROCmove (right ,rightarrow,bumpers) 1250 ENDPROC 1260 : 1270 DEF PROCmove (direction,key,sensors) 1280 IF NOT eyesopen THEN SOUND 1,-8,42+direction*4,-1 1290 ?port = direction :PROCdelay(speedcontrol) 1300 IF direction=left THEN PRINT TAB(16,2)box$ box$ 1310 IF direction=right THEN PRINT TAB(23,2)box$ box$ 1320 REPEAT 1330 ?port = direction OR 2 :PROCdelay(speedcontrol) 1340 ?port = direction :PROCdelay(speedcontrol) 1350 IF direction = forwards THEN distance = distance + 1 1360 IF direction = backwards THEN distance = distance - 1 1370 IF direction = left THEN turn = turn - 1 1380 IF direction = right THEN turn = turn + 1 1390 IF sensors THEN hit = (?port AND sensors) 1400 IF eyesopen THEN IF (distance MOD 10) = 0 AND (turn MOD 5) = 0 THEN PROCreadlight 1410 IF (distance MOD 20) = 0 AND (turn MOD 15) = 0 THEN PROCbug : PROCupdate 1420 UNTIL (INKEY (key) = FALSE) OR hit 1430 PRINT TAB(16,2)" " TAB(23,2)" " 1440 ?port = 0 1450 REM Flush sound buffer 1460 *FX 15 1470 PROCbug 1480 PROCupdate 1490 IF hit THEN PROCcrash (hit) 1500 ENDPROC 1510 : 1520 DEF PROCreadlight 1530 LOCAL temp 1540 temp = ADVAL(1) DIV 100 1550 PRINT TAB(27,2) temp 1560 PRINT TAB(32,0)" " TAB(32,1)" " TAB(32,2)" " 1570 IF temp>=light THEN SOUND 1,-8,233,1:PRINT TAB(32,1)box$ 1580 IF temp< light THEN SOUND 1,-8,205,1:PRINT TAB(32,2)box$ 1590 light = temp 1600 IF light>=maxlight-2 THEN SOUND 1,-15,245,2:PRINT TAB(32,0) CHR$ 225 1610 IF light> maxlight THEN maxlight = light 1620 IF light>= 655 THEN SOUND 1,-15,10,5 : PROCcentre ("Light source found, press ESCAPE.",6) 1630 ENDPROC 1640 : 1650 DEF PROCscale 1660 CLS 1670 scale = 10 :REM Temporary value 1680 Xscale = scale * Xfactor 1690 PROCcentre ("Place the Buggy in its area as shown,",2) 1700 PROCcentre ("with the wheels 12 cms from the edge.",4) 1710 PROCrectangle (226,288,1054,800) 1720 PRINT TAB(19,8) "N" TAB(9,14) "W" TAB(30,14) "E" 1730 VDU 29,0;288; :REM Reset graphics origin 1740 PROCcalcpos 1750 PROCcalcbug (640,12*scale,0) 1760 PROCdrawbug 1770 VDU 28,1,30,38,24 :REM Make text window 1780 VDU 29,0;0; :REM Reset graphics origin 1790 REPEAT 1800 CLS 1810 PROCedge 1820 PRINT TAB(36,1) "cm" 1830 PRINT TAB(0,1) "Enter distance West to East "; 1840 horiz = VAL( FNinput (3,digit$)) 1850 PRINT TAB(36,3) "cm" 1860 PRINT TAB(0,3) "Enter distance North to South "; 1870 vert = VAL( FNinput (3,digit$)) 1880 IF FNmin (horiz,vert) < BW * 6 THEN CLS : VDU 7 : PROCcentre ("Buggy space too cramped.",2) : PROCspace (4) : enoughspace = FALSE ELSE enoughspace = TRUE 1890 UNTIL enoughspace 1900 scale = 630/FNmax (horiz/1.77*Xfactor,vert) 1910 Xscale = scale * Xfactor 1920 VDU 26 :REM Text and graphics windows back to normal 1930 ENDPROC 1940 : 1950 DEF PROCsetup_program 1960 program_name$ = "MAN versus BUGGY" 1970 angle = 0 :REM Buggy's compass bearing 1980 turn = 0 :REM temporary angle 1990 distance = 0 :REM default value 2000 light = 0 :REM Light value 2010 maxlight = 0 :REM Maximum light level 2020 hit = 0 :REM flag for bumpers 2030 eyesopen = FALSE :REM light reading flag 2040 scale = 10 :REM default value 2050 L = -87 :REM Keyboard control value 2060 Xscale = scale * Xfactor :REM Xfactor set up in user area 2070 VDU 23,224,0,255,0,255,0,255,0,255 :REM User defined character 2080 VDU 23,225,255,255,255,255,255,255,255,255 2090 box$ = CHR$ 224:REM 'Blip' for screen display 2100 ENDPROC 2110 : 2120 DEF FNsure 2130 LOCAL answer$ 2140 SOUND 3,-15,95,10 2150 PROCdelay (300) 2160 PROCcentre ("Are you sure ( Y/N ) ? ",6) 2170 answer$ = FNinput (1,"YNyn") 2180 IF answer$="Y" OR answer$="y" THEN =TRUE ELSE =FALSE 2190 : 2200 DEF FNtoggle (variable,key) 2210 SOUND 0,-15,3,10 2220 REPEAT UNTIL NOT INKEY (key) 2230 =NOT variable 2240 : 2250 REM UNIVERSAL BUGGY PROCEDURES 2260 DEF PROCboundary (X1,Y1,X2,Y2) 2270 X1 = X1 * Xscale 2280 X2 = X2 * Xscale 2290 Y1 = Y1 * scale 2300 Y2 = Y2 * scale 2310 PROCrectangle (X1,Y1,X2,Y2) 2320 VDU 24,X1;Y1;X2;Y2; :REM Graphics window 2330 ENDPROC 2340 : 2350 DEF PROCbug 2360 PROCdrawbug 2370 PROCcalcpos 2380 PROCcalcbug (GRX,GRY,angle) 2390 PROCdrawbug 2400 MOVE oldX,oldY 2410 PLOT 29,GRX,GRY 2420 oldX = GRX : oldY = GRY 2430 IF FNlimit (BGX,BGY,BF,BF,horiz-BF,vert-BF) THEN PROCwarn ("The Buggy is going off the screen!") ELSE PROCcentre ("Press ESCAPE to exit program",4) 2440 ENDPROC 2450 : 2460 DEF PROCcalcbug (X,Y,angle) 2470 REM Accesses BF,BR,CW,BW,scale,Xscale 2480 REM Alters Buggy screen co-ordinates 2490 LOCAL SN,CS,leftoffset,rightoffset,frontoffset,rearoffset 2500 frontoffset = RAD angle 2510 rearoffset = RAD (angle-180) 2520 leftoffset = RAD (angle- 90) 2530 rightoffset = RAD (angle+ 90) 2540 REM Front middle of bumpers 2550 FMX = X + BF * SIN frontoffset * Xscale 2560 FMY = Y + BF * COS frontoffset * scale 2570 REM Rear middle of chassis 2580 RMX = X + BR * SIN rearoffset * Xscale 2590 RMY = Y + BR * COS rearoffset * scale 2600 REM Left side of buggy 2610 SN = SIN leftoffset * Xscale 2620 CS = COS leftoffset * scale 2630 REM Left bumper 2640 LBX = FMX + BW * SN 2650 LBY = FMY + BW * CS 2660 REM Front left corner 2670 FLX = FMX + CW * SN 2680 FLY = FMY + CW * CS 2690 REM Rear left corner 2700 RLX = RMX + CW * SN 2710 RLY = RMY + CW * CS 2720 REM Right side of buggy 2730 SN = SIN rightoffset * Xscale 2740 CS = COS rightoffset * scale 2750 REM Right bumper 2760 RBX = FMX + BW * SN 2770 RBY = FMY + BW * CS 2780 REM Front right corner 2790 FRX = FMX + CW * SN 2800 FRY = FMY + CW * CS 2810 REM Rear right corner 2820 RRX = RMX + CW * SN 2830 RRY = RMY + CW * CS 2840 ENDPROC 2850 : 2860 DEF PROCcalcpos 2870 REM Updates Buggy co-ordinates 2880 LOCAL A 2890 angle = angle + turn 2900 A = RAD angle 2910 BGX = BGX + distance * FWD * SIN A 2920 BGY = BGY + distance * FWD * COS A 2930 GRX = BGX * Xscale 2940 GRY = BGY * scale 2950 distance = 0 2960 turn = 0 2970 ENDPROC 2980 : 2990 DEF PROCcrash (bumper) 3000 IF (bumper AND leftbumper)<>0 THEN MOVE LBX,LBY:PLOT 6,FMX,FMY:hit = -1 3010 IF (bumper AND rightbumper)<>0 THEN MOVE RBX,RBY:PLOT 6,FMX,FMY:hit = 1 3020 SOUND 0,-15,9+hit,4 :REM Different sound for each bumper 3030 VDU 29,0;0; :REM Graphics origin 3040 VDU 24,510;220;800;700; :REM Graphics window 3050 MOVE 510,270 : MOVE 580,270 3060 PLOT 86+hit,580,220 :REM Only the relevant triangle is filled 3070 MOVE 730,270 : MOVE 800,270 3080 PLOT 86-hit,730,220 3090 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3100 PROCboundary (0,0,horiz,vert) 3110 PROCmove_buggy (backwards,safedistance,speedcontrol,nosensors) 3120 VDU 29,0;0; :REM Graphics origin 3130 VDU 24,510;220;800;700; :REM Graphics window 3140 MOVE 510,270 : MOVE 580,270 3150 PLOT 87,580,220 :REM Delete both triangles 3160 MOVE 730,270 : MOVE 800,270 3170 PLOT 87,730,220 3180 VDU 29,640-horiz DIV 2 * Xscale;320;:REM Graphics origin 3190 PROCboundary (0,0,horiz,vert) 3200 ENDPROC 3210 : 3220 DEF PROCdrawbug 3230 REM Ensures good corners at rear 3240 MOVE LBX,LBY 3250 PLOT 6,RBX,RBY 3260 MOVE RLX,RLY 3270 PLOT 30,FLX,FLY 3280 MOVE RLX,RLY 3290 PLOT 30,RRX,RRY 3300 PLOT 30,FRX,FRY 3310 PLOT 70,RLX,RLY 3320 ENDPROC 3330 : 3340 DEF PROCend 3350 REM Switches motors off, resets cursor, EDIT & ESCAPE keys, buffers, and PRINT format 3360 PROCmotors_off 3370 PROCon 3380 *FX 4 3390 *FX 229 3400 *FX 15 3410 @% = 10 3420 ENDPROC 3430 : 3440 DEF PROCmotors_off 3450 ?port = 8 3460 ENDPROC 3470 : 3480 DEF PROCmotors_on 3490 ?port = 0 3500 ENDPROC 3510 : 3520 DEF PROCmove_buggy (direction,move,speed,sensors) 3530 count = 0 3540 hit = 0 3550 REPEAT 3560 count = count + 1 3570 ?port = direction :PROCdelay (speed) 3580 ?port = direction OR 2:PROCdelay (speed) 3590 hit = (?port AND sensors) 3600 UNTIL hit OR count>=move 3610 ?port=0 3620 IF direction = left THEN turn = turn - count 3630 IF direction = right THEN turn = turn + count 3640 IF direction = backwards THEN distance = distance - count 3650 IF direction = forwards THEN distance = distance + count 3660 PROCbug 3670 PROCupdate 3680 ENDPROC 3690 : 3700 DEF PROCnogo 3710 PROCcentre ("Buggy not connected, END OF PROGRAM.",21) 3720 PRINT 3730 ENDPROC 3740 : 3750 DEF PROCscreen 3760 REM "Instrument panel" 3770 VDU 28,0,30,39,24 :REM Text window 3780 CLS 3790 RESTORE 3800 FOR index = 1 TO 14 3810 READ M1,M2,D1,D2 3820 MOVE M1,M2 3830 DRAW D1,D2 3840 NEXT index 3850 PRINT TAB(6,0) "Position" 3860 PRINT TAB(19,0) "Deg" 3870 PRINT TAB(26,0) "Light" 3880 DATA 6, 280,1270, 280, 6, 210, 500, 210, 590, 210, 720, 210 3890 DATA 810, 210,1010, 210, 6, 140,1270, 140, 1070, 210,1270, 210 3900 DATA 150, 280, 150, 140, 500, 280, 500, 140, 590, 280, 590, 140 3910 DATA 720, 280, 720, 140, 810, 280, 810, 140, 1010, 280,1010, 140 3920 DATA 1070, 280,1070, 140, 1170, 280,1170, 210 3930 PROCedge 3940 ENDPROC 3950 : 3960 DEF PROCsetup_general 3970 REM Buggy dimensions are in centimetres 3980 BF = 3.9 :REM Buggy centre to bumper 3990 BR = 9 :REM Buggy centre to chassis rear 4000 CW = 6 :REM Half chassis width 4010 BW = 9 :REM Bumper width (1 side) 4020 FWD = 0.1431944:REM Travel (cms/pulse) 4030 safedistance = ( INT( SQR( BR*BR + CW*CW ) -BF )) / FWD +14 4040 REM Values to compare with port 4050 bumpers = 192 4060 leftbumper = 128 4070 rightbumper = 64 4080 nosensors = 0 4090 REM Keyboard control words 4100 uparrow = -58 4110 downarrow = -42 4120 leftarrow = -26 4130 rightarrow = -122 4140 space = -99 4150 nokey = -129 4160 escape = -113 4170 REM Port values for Buggy movement 4180 forwards = 0 4190 backwards = 5 4200 left = 4 4210 right = 1 4220 digit$ = "1234567890" :REM Acceptable characters for numeric input 4230 space$ = STRING$(36," ") 4240 @% = &303 :REM Print format 4250 ENVELOPE 3,1,5,-5,5,10,10,10,5,0,-1,-1,126,0 4260 ENDPROC 4270 : 4280 DEF PROCupdate 4290 PRINT TAB(6,2) INT(BGX+0.5) "," INT(BGY+0.5) 4300 angle = (360+angle) MOD 360 4310 PRINT TAB(19,2) angle 4320 ENDPROC 4330 : 4340 DEF PROCwarn (text$) 4350 PROCcentre (text$,4) 4360 SOUND &103,3,100,10 4370 SOUND &102,3,117,10 4380 ENDPROC 4390 : 4400 : 4410 REM UTILITIES 4420 DEF PROCcentre (text$,line) 4430 PRINT TAB(1,line) SPC 38 4440 PRINT TAB( FNcentre (text$),line) text$; 4450 ENDPROC 4460 : 4470 DEF FNcentre (text$) =19-LEN(text$) DIV 2 4480 : 4490 DEF PROCcomplete 4500 CLS 4510 PROCdouble (CHR$ 131 +"Mission completed.",-1,10) 4520 PROCend 4530 ENDPROC 4540 : 4550 DEF PROCdelay (period) 4560 LOCAL index 4570 FOR index = 1 TO period : NEXT index 4580 ENDPROC 4590 : 4600 DEF PROCdouble (text$,X,Y) 4610 IF X<0 THEN X = FNcentre (text$) 4620 PRINT TAB(X-1,Y ) CHR$ 141;text$ 4630 PRINT TAB(X-1,Y+1) CHR$ 141;text$ 4640 ENDPROC 4650 : 4660 DEF PROCedge 4670 PROCrectangle (6,6,1274,1018) 4680 ENDPROC 4690 : 4700 DEF FNinput (length,allowed$) 4710 LOCAL input$,ascii 4720 PRINT STRING$(length,".");STRING$(length,CHR$ 8); 4730 PROCon:*FX 15 4740 REPEAT ascii = ASC FNwait 4750 IF ascii=127 AND LEN(input$)>0 THEN input$ = LEFT$(input$,LEN(input$)-1):VDU ascii 4760 IF INSTR(allowed$,CHR$ ascii) AND LEN(input$)13 AND ascii<>127 THEN ascii = 7 4770 IF ascii=13 AND LEN(input$)<1 THEN ascii = 7 4780 IF ascii=127 THEN VDU 46,8 ELSE VDU ascii 4790 UNTIL ascii=13:PRINT:PROCoff 4800 =input$ 4810 : 4820 DEF FNlimit (X,Y,X1,Y1,X2,Y2) 4830 IF X>X1 AND XY1 AND YB THEN =A ELSE =B 4870 : 4880 DEF FNmin (A,B) 4890 IF A"" 5160 *FX 4 5170 =I$ 5180 :