BASIC

This is a BASIC language program for the Reddit backstage contest. It has been adapted to Microsoft Basic-85 and incorporates FabGL graphics management routines. The WIDTH instruction of line 160 is important for the operation of the graphics routines. The graphics routines are invoked when the video terminal collects the Escape character followed by an underscore, then the name of the routine and finally the coordinates separated by “;” at the end, the “$” character closes the string, for example “0x1b_GPIXEL5; 10 $” lights up a point on the screen at the coordinates x = 5 and y = 10. Unfortunately Microsoft Basic issues a CR on the terminal (even if the print is followed by a “;”) after a PRINT.  The WIDTH statement followed by 255 forces the interpreter not to issue a CR after PRINT. WIDTH nnn is a statement indicating the maximum number of columns in the terminal. https://www.reddit.com/r/retrobattlestations/comments/ov6w91/old_z80mbc2/

100 REM BASIC Month 6: The Mandelbaum Set
110 REM http://reddit.com/r/RetroBattlestations
120 REM written by FozzTexx
130 REM "You think you're better than me?"
140 REM Modified for Z80-MBC2 and ESP32 Fabgl graphics library
150 REM by Vito BLASI https://automatico.freevar.com
160 WIDTH 255
200 REM === Initialize variables and constants
210 PI = 3.14159265359:DIM PT(128)
220 GO(0) = 33:GO(1) = 138:GO(2) = 200
230 CM(0) = 1:CM(1) = 0:CM(2) = 0
240 CM(3) = 0:CM(4) = 1:CM(5) = 0
250 CM(6) = 0:CM(7) = 0:CM(8) = 1
260 GW = GO(2) * GO(2) / GO(1)
262 GOSUB 10000: REM Define functions
264 REM Disable cursor and clear screen
270 TH = GO(2) + 5:GOSUB 2630:TH = TH + SZ(1):GOSUB 2630:TH = TH + SZ(1)
280 RZ(0) = 640:RZ(1) = 480:REM Width & height of screen
290 SX = (RZ(0) - RZ(0) * 0.05) / GW:SY = (RZ(1) - RZ(1) * 0.07) / TH
300 SK = SX:IF SY < SK THEN SK = SY
310 PRINT FNCURSOROFF$;FNCLR$;FNPEN$(0,255,0);
320 REM "What in holy hell?"
330 X = -GW / 2:Y = -GO(2) / 2:GOSUB 2030:REM Translate
340 X = SK:Y = SK:GOSUB 2230:REM Scale
350 X = RZ(0) / 2:Y = RZ(1) / 2:GOSUB 2030:REM Translate
360 GOSUB 2820
370 RESTORE:REM Reset reading of DATA back to first object
380 GOSUB 2630:GOSUB 2720
390 GOSUB 2630
400 X = (GW - SZ(0)) * SK:Y = (GO(2) + SZ(1) + 5) * SK
410 GOSUB 2030:GOSUB 2720:GOSUB 2920
420 GOSUB 2630
430 GX = GO(1) / 2:GY = GO(2) / 2:GB = GY - GX:OO = GO(2) * GO(2) / GO(1) - GO(1)
440 GOSUB 4510

500 REM "Step aside, string bean."
510 X = -RZ(0) / 2:Y = -RZ(1) / 2:GOSUB 2030:REM Translate
520 A = PI / 2:GOSUB 2130:REM Rotate
530 X = GO(1) / GO(2):Y = X:GOSUB 2230:REM Scale
540 X = RZ(0) / 2 + (GW / 2 - GO(1) / 2) * SK:Y = RZ(1) / 2:GOSUB 2030:REM Translate
550 GOSUB 4510
560 IF HT > 1 THEN GOTO 510
570 GOSUB 4610

999 END

1000 REM === Update current transformation matrix
1010 REM - Input: 3x3 matrix in 1D array NT
1020 REM - Updates 3x3 Matrix in 1D array CM
1030 FOR R = 0 TO 2:FOR C = 0 TO 2
1040 NM(R * 3 + C) = 0
1050 FOR K = 0 TO 2
1060 NM(R * 3 + C) = NM(R * 3 + C) + NT(R * 3 + K) * CM(K * 3 + C)
1070 NEXT K, C, R
1080 FOR K = 0 TO 3 * 3 - 1:CM(K) = NM(K):NEXT K
1090 RETURN

2000 REM === Translate - move origin
2010 REM - Input: X, Y
2020 REM - Updates current transformation matrix in CM
2030 NT(0) = 1:NT(1) = 0:NT(2) = X
2040 NT(3) = 0:NT(4) = 1:NT(5) = Y
2050 NT(6) = 0:NT(7) = 0:NT(8) = 1
2060 GOSUB 1030
2070 RETURN

2100 REM === Rotate - rotate drawing space
2110 REM - Input: Angle in radians in A
2120 REM - Updates current transformation matrix in CM
2130 NT(0) = COS(A):NT(1) = -SIN(A):NT(2) = 0
2140 NT(3) = -NT(1):NT(4) = NT(0):NT(5) = 0
2150 NT(6) = 0:NT(7) = 0:NT(8) = 1
2160 GOSUB 1030
2170 RETURN

2200 REM === Scale - modify unit lengths of drawing
2210 REM - Input: X, Y
2220 REM - Updates current transformation matrix in CM
2230 NT(0) = X:NT(1) = 0:NT(2) = 0
2240 NT(3) = 0:NT(4) = Y:NT(5) = 0
2250 NT(6) = 0:NT(7) = 0:NT(8) = 1
2260 GOSUB 1030
2270 RETURN

2300 REM === Transform single point using current transformation matrix
2310 REM - Input: X, Y
2320 REM - Returns transformed point in X and Y

Press RETURN to Continue
2330 NT(0) = X:NT(1) = Y:NT(2) = 1
2340 FOR R = 0 TO 2
2350 NM(R) = 0
2360 FOR K = 0 TO 2
2370 NM(R) = NM(R) + NT(K) * CM(R * 3 + K)
2380 NEXT K, R
2390 X = NM(0):Y = NM(1)
2400 RETURN

2500 REM === Draw line
2510 REM - Input: X1,Y1 X2,Y2
2520 X = X1:Y = Y1:GOSUB 2330:A1 = X:B1 = Y
2530 X = X2:Y = Y2:GOSUB 2330:A2 = X:B2 = Y
2540 PRINT FNDRAW$(A1,B1,A2,B2);
2550 RETURN

2600 REM === Load object from DATA
2610 REM - Reads the next object from DATA and leaves size in array SZ
2620 REM and paths in array PT
2630 ZI = 0:READ ZX:SZ(0) = ZX:READ ZY:SZ(1) = ZY
2640 READ ZC:PT(ZI) = ZC:ZI = ZI + 1
2650 IF ZC = 0 THEN RETURN
2660 FOR ZJ = 1 TO ZC:READ ZX:READ ZY
2670 PT(ZI) = ZX:ZI = ZI + 1:PT(ZI) = ZY:ZI = ZI + 1
2680 NEXT ZJ
2690 GOTO 2640

2700 REM === Draw path
2710 REM - Input: paths to draw in array PT
2720 ZI = 0
2730 ZC = PT(ZI):ZI = ZI + 1:IF ZC = 0 THEN RETURN
2740 X1 = PT(ZI):ZI = ZI + 1:Y1 = PT(ZI):ZI = ZI + 1
2750 FOR ZJ = 1 TO ZC - 1
2760 X2 = PT(ZI):ZI = ZI + 1:Y2 = PT(ZI):ZI = ZI + 1
2770 GOSUB 2520
2780 X1 = X2:Y1 = Y2:NEXT ZJ
2790 GOTO 2730

2800 REM == Save current transformation matrix
2810 REM Copies array CM to array OM
2820 FOR I = 0 TO 8:OM(I) = CM(I):NEXT I
2830 RETURN

2900 REM == Restore transformation matrix
2910 REM Copies array OM to array CM
2920 FOR I = 0 TO 8:CM(I) = OM(I):NEXT I
2930 RETURN

3000 REM Mandelbaum arc
3010 REM - Input: Arc center at CX,CY; Start/end radians in SA,EA
3020 REM "If you want to live in a butcher shop, I'm gonna treat you like a piece of meat."
3030 IF (EA < SA) THEN EA = EA + 2 * PI
3040 NW = SZ(0):NH = SZ(1):NS = GO(0) / NW:SH = NH * NS
3050 RO = GO(1) / 2:RI = RO - GO(0)
3060 AL = (EA - SA) * GO(1) / 2:SG = INT(AL / SH)
3070 GA = (EA - SA) / SG
3080 GC = COS(2 * PI - GA):GS = SIN(2 * PI - GA):ZC = COS(0):ZS = SIN(0)
3090 F1 = CX + RI * GC:G1 = CY + RI * GS
3100 F2 = CX + RO * GC:G2 = CY + RO * GS
3110 F3 = CX + RI * ZC:G3 = CY + RI * ZS
3120 F4 = CX + RO * ZC:G4 = CY + RO * ZS
3130 D1 = F3 - F1:D2 = G3 - G1:D3 = F4 - F2:D4 = G4 - G2
3140 L1 = SQR(D1 * D1 + D2 * D2):L2 = SQR(D3 * D3 + D4 * D4)
3150 GOSUB 2820
3160 X = CX:Y = CY:GOSUB 2330:AX = X:AY = Y
3170 REM Walk through PT and draw
3180 FOR SN = 0 TO SG - 1
3190 GOSUB 2920
3200 X = -AX:Y = -AY:GOSUB 2030:REM Translate
3210 A = 2 * PI - (SA + SN * GA):GOSUB 2130:REM Rotate
3220 X = AX:Y = AY:GOSUB 2030:REM Translate
3230 ZI = 0
3240 ZC = PT(ZI):ZI = ZI + 1:IF ZC = 0 THEN GOTO 3350
3250 X1 = PT(ZI) * NS:ZI = ZI + 1
3260 Y1 = PT(ZI) * NS * (L1 - 1 + (L2 - L1 - 1) * (X1 / GO(0))) / L2:ZI = ZI + 1
3270 X1 = X1 + CX + RI:Y1 = Y1 + CY
3280 FOR ZJ = 1 TO ZC - 1
3290 X2 = PT(ZI) * NS:ZI = ZI + 1
3300 Y2 = PT(ZI) * NS * (L1 - 1 + (L2 - L1 - 1) * (X2 / GO(0))) / L2:ZI = ZI + 1
3310 X2 = X2 + CX + RI:Y2 = Y2 + CY
3320 GOSUB 2520
3330 X1 = X2:Y1 = Y2:NEXT ZJ
3340 GOTO 3240
3350 NEXT SN
3360 GOSUB 2920
3370 RETURN

4000 REM Mandelbaum line
4010 REM - Input: Start and end diagonal corners in X1,Y1 and X2,Y2
4020 REM "Wrong attitude, you're not bringing that trash into my house."
4030 NW = SZ(0):NH = SZ(1) + 1
4040 XD = X2 - X1:YD = Y2 - Y1
4050 IF XD > 0 AND YD < 0 THEN A = 0:WD = XD:HT = YD
4060 IF XD < 0 AND YD < 0 THEN A = 1.5 * PI:HT = XD:WD = YD
4070 IF XD < 0 AND YD > 0 THEN A = PI:WD = XD:HT = YD
4080 IF XD > 0 AND YD > 0 THEN A = 0.5 * PI:HT = XD:WD = YD
4090 WD = ABS(WD):HT = ABS(HT)
4100 NS = WD / NW:SH = INT(NH * NS)
4110 SG = INT((HT + SH - 1) / SH):SH = HT / SG
4120 SX = GO(0) / NW:SY = SH / NH
4130 GOSUB 2820
4140 AX = X1:AY = Y1:X = X1:Y = Y1:GOSUB 2330:OX = X:OY = Y
4150 X = X2:Y = Y2:GOSUB 2330:XD = X - OX:YD = Y - OY
4160 X = 0:Y = 0:GOSUB 2330
4170 X = -X:Y = -Y:GOSUB 2030:REM Translate
4180 GOSUB 2130:REM Rotate
4190 X = SX:Y = SY
4200 IF (XD < 0 AND YD < 0) OR (XD > 0 AND YD > 0) THEN Y = SX:X = SY
4210 GOSUB 2230:REM Scale
4220 X = OX:Y = OY:GOSUB 2030:REM Translate

4230 REM Walk through PT and draw
4240 FOR SN = 0 TO SG - 1
4250 ZI = 0
4260 ZC = PT(ZI):ZI = ZI + 1:IF ZC = 0 THEN GOTO 4350
4270 X1 = PT(ZI):ZI = ZI + 1
4280 Y1 = PT(ZI) * (SH - 1) / SH - SN * (SH / SY):ZI = ZI + 1
4290 FOR ZJ = 1 TO ZC - 1
4300 X2 = PT(ZI):ZI = ZI + 1
4310 Y2 = PT(ZI) * (SH - 1) / SH - SN * (SH / SY):ZI = ZI + 1
4320 GOSUB 2520
4330 X1 = X2:Y1 = Y2:NEXT ZJ
4340 GOTO 4260
4350 NEXT SN
4360 GOSUB 2920

4370 REM Return height to decide if it's time to stop
4380 X = AX:Y = AY + SH:GOSUB 2330
4390 HT = SQR((X - OX) * (X - OX) + (Y - OY) * (Y - OY))
4400 RETURN

4500 REM === G
4510 CX = GX:CY = GY - GB:SA = 0:EA = PI:GOSUB 3030
4520 X1 = GO(0):Y1 = GY - GB:X2 = 0:Y2 = GY + GB:GOSUB 4030
4530 CX = GX:CY = GY + GB:SA = PI:EA = 0:GOSUB 3030
4540 X1 = GO(1):Y1 = GY + GB:X2 = GX:Y2 = GY + GB - GO(0):GOSUB 4030
4550 RETURN

4600 REM === O
4610 CX = GX + OO:CY = GY - GB:SA = 0:EA = PI:GOSUB 3030
4620 X1 = GO(0) + OO:Y1 = GY - GB:X2 = OO:Y2 = GY + GB:GOSUB 4030
4630 CX = GX + OO:CY = GY + GB:SA = PI:EA = 0:GOSUB 3030
4640 X1 = GO(1) - GO(0) + OO:Y1 = GY + GB:X2 = GO(1) + OO:Y2 = GY - GB:GOSUB 4030
4650 RETURN

9000 REM "All aboard the pain train."
9010 DATA 39,16,15,3,-16,0,-16,0,-13,3,-13,3,-3,0,-3,0,0,10,0,10,-3,6,-3
9020 DATA 6,-13,10,-13,10,-16,6,-16,3,-16,11,16,-16,12,-16,12,-13,16,-13
9030 DATA 16,0,19,0,19,-13,23,-13,23,-16,19,-16,16,-16,5,25,-16,27,-16
9040 DATA 27,-13,25,-13,25,-16,19,36,-9,33,-10,32,-11,34,-13,36,-12,39
9050 DATA -12,34,-16,30,-14,29,-11,32,-7,35,-6,36,-5,34,-3,32,-4,29,-4
9060 DATA 34,0,38,-1,39,-5,36,-9,0
9070 DATA 53,16,15,23,-13,23,-16,20,-16,16,-16,13,-16,13,-13,16,-13,16
9080 DATA -3,13,-3,13,0,23,0,23,-3,20,-3,20,-13,23,-13,18,53,-13,53,-16
9090 DATA 46,-16,43,-16,43,-13,43,-10,43,-6,43,-3,43,0,53,0,53,-3,46,-3
9100 DATA 46,-6,51,-6,51,-10,46,-10,46,-13,53,-13,11,10,-16,7,-16,3,-16
9110 DATA 0,-16,0,-13,3,-13,3,0,7,0,7,-13,10,-13,10,-16,14,37,-16,33,-9
9120 DATA 29,-16,26,-16,26,0,29,0,29,-10,32,-4,34,-4,37,-10,37,0,40,0,40
9130 DATA -16,37,-16,0
9140 DATA 52,8,5,0,0,0,-8,3,-4,5,-8,5,0,3,10,0,8,-8,6,0,2,7,-4,9,-4,4,11
9150 DATA 0,11,-8,15,0,15,-8,6,18,-8,16,-8,16,0,18,0,20,-4,18,-8,2,23,-4
9160 DATA 21,-4,4,25,-8,21,-8,21,0,25,0,3,31,0,26,0,26,-8,12,32,-4,35,-4
9170 DATA 36,-5,36,-7,35,-8,32,-8,32,0,35,0,35,0,36,-1,36,-3,35,-4,3,41
9180 DATA 0,39,-8,37,0,2,38,-4,40,-4,6,42,-8,42,-1,44,0,45,0,47,-1,47,-8
9190 DATA 5,48,0,48,-8,50,-4,52,-8,52,0,0
10000 REM
10010 REM ** DEFINE FUNCTIONS **
10020 DEF FNPEN$(R%, G%, B%) = CHR$(27)+"_GPEN"+STR$(R%)+";"+STR$(G%)+";"+STR$(B%)+"$"
10030 DEF FNBRUSH$(R%, G%, B%) = CHR$(27)+"_GBRUSH"+STR$(R%)+";"+STR$(G%)+";"+STR$(B%)+"$"
10040 DEF FNPIXEL$(X%, Y%) = CHR$(27)+"_GPIXEL"+STR$(X%)+";"+STR$(Y%)+"$"
10050 DEF FNDRAW$(X1%, Y1%, X2%, Y2%) = CHR$(27)+"_GLINE"+STR$(X1%)+";"+STR$(Y1%)+";"+STR$(X2%)+";"+STR$(Y2%)+"$"
10060 DEF FNRECT$(X1%, Y1%, X2%, Y2%) = CHR$(27)+"_GRECT"+STR$(X1%)+";"+STR$(Y1%)+";"+STR$(X2%)+";"+STR$(Y2%)+"$"
10070 DEF FNFILLRECT$(X1%, Y1%, X2%, Y2%) = CHR$(27)+"_GFILLRECT"+STR$(X1%)+";"+STR$(Y1%)+";"+STR$(X2%)+";"+STR$(Y2%)+"$"
10080 DEF FNELLIPSE$(X%, Y%, W%, H%) = CHR$(27)+"_GELLIPSE"+STR$(X%)+";"+STR$(Y%)+";"+STR$(W%)+";"+STR$(H%)+"$"
10090 DEF FNFILLELLIPSE$(X%, Y%, W%, H%) = CHR$(27)+"_GFILLELLIPSE"+STR$(X%)+";"+STR$(Y%)+";"+STR$(W%)+";"+STR$(H%)+"$"
10110 DEF FNPATH$(POINTS$) = CHR$(27)+"_GPATH"+POINTS$+"$"
10120 DEF FNFILLPATH$(POINTS$) = CHR$(27)+"_GFILLPATH"+POINTS$+"$"
10130 DEF FNSCROLL$(X%, Y%) = CHR$(27)+"_GSCROLL"+STR$(X%)+";"+STR$(Y%)+"$"
10140 DEF FNCLR$ = CHR$(27)+"_GCLEAR$"
10150 DEF FNCURSORON$ = CHR$(27)+"_E1$"
10160 DEF FNCURSOROFF$ = CHR$(27)+"_E0$"
10170 DEF FNCLRTERM$ = CHR$(27)+"_B$"
10180 RETURN

Loading