PC BASIC Bot 280 char Demos


After doing a lot of demos on the Applesoft BASIC bot I got to thinking about GW-BASIC and QBasic, the other two BASIC dialects I spent time coding on in the 90s.

I did some prep work in October 2020 as there wasn't a GW-BASIC bot. Then in February 2021 Kay Savetz set up the PC BASIC Bot.

Palette Shift Demo

actual link simulated link

Despite spending a lot of time coding on GW-BASIC I never really used any of the advanced features at the time. It is a much more rich and complex environment than Applesoft and I am sure there are all kinds of advanced tricks.

This one uses the "MODE 9" 640x350x16 EGA mode (back in the day it was a revelation when someone told me about this, all of my older BASIC books only went up to CGA and I didn't know you could program anything better).

While EGA only supported 16 colors, you could choose from a palette of 64, which is what this example is doing. This is the first time I've ever used the "PALETTE USING" and "FIX" functions. It's also so nice to have a built in "MOD" operator.

Anyway I wanted to have a nice color pallette shifting demo, you can't do that on the Apple II and the other 8-bit/16-bit architectures won't let you forget it.

1 DIM A%(16):SCREEN 9
2 FOR I=0 TO 6:READ C:A%(I)=C:NEXT:DATA 32,52,38,46,38,52,32
3 FOR Y=0 TO 350:LINE (0,Y)-(639,Y),FIX((Y MOD 14)/2):NEXT
5 A%(7)=A%(0):FOR I=0 to 7:A%(I)=A%(I+1):NEXT
6 FOR I=0 TO 1000:NEXT:GOTO 4

Machine Language Loader -- Color Bars

actual link simulated link

The PC BASIC bot would be an interesting venu for loading DOS demos. DOS demos are a bit crazy, and people do amazing things in 32-bytes or less. I over-optimistically thought I'd try with a 128-byte demo as that's what we can load in Applesoft, but it turns out loading assembly language is really hard in GW-BASIC despite a lot of support in the language for doing so.

The demo I chose is my 128B color bar demo that I actually wrote for this purpose. It's a DOS COM file which allows a lot of assumptions that the expert demo size coders exploit. I tried to avoid those as I am sure many don't hold inside of GW-BASIC. I did have to modify the program to set the DS segment to be the same as CS (raising the file size to 129 bytes).

The demo targets an 8086 machine with MCGA graphics, sort of like the IBM PS/2 Model 25 machines they replaced the Apple IIs with at my high school. The demo uses 320x200x256 Model 13h which in theory isn't directly supported by GW-BASIC.

Below is the first successful attempt at getting the program to load. It uses the 6-bit encoding from the Applesoft (and other 6502) BASIC bots. I thought it would be more compact due to the avaiability of MOD and AND but not really, those are big, and you can't run things together without spaces like you can for Applesoft.

Also the machine code is stored in a string. GW-BASIC supports getting the address of arrays and strings, I'm not sure if I can consistently get data out of a REM statement like on Applesoft.

Knowing where to put things involves all kinds of x86 knowledge about segments and the like. I just picked somewhere high up as GW-BASIC lives in one 64k segment.

0 DIM B%(200),Q(200),D(200)
1 A$="h:J]ph>:m>h:b]jFyhl:hJ:\pvdLWwhp:uC<WxuC<Wxi@:]gU:f;eI:W;IjW:wA\je:KyNZx;Y:yfl\puJef;nruLLntuntuJPrryZu;Xktf<:::::I::;<=U::>BFb::;<==HMFrwJ>fat:G:A^N=:JDFZKOCZLFP]]akSfAs?:A:?s"
2 FOR I=1 TO 132
3 B%(I)=(ASC(MID$(A$,I,1))-58)*4
4 Q(I)=((ASC(MID$(A$,133+(I-2)/3,1))-58))
5 D(I)=(4^((I-1) MOD 3))
6 B%(I)=B%(I)+(INT(Q(I)/D(I)) AND 3)
35 DEF SEG=&H4000
40 for I=0 to 132:POKE I+256,B%(I+1):NEXT
70 V=256:CALL V
I spent more time than I should have trying to reduce this in size, and came up with this, which is still too big to fit in a tweet.
1DEF SEG=100:DEF FNP(X)=ASC(MID$(A$,X))-58:A$="=Ah>:m>h:b]jFyhl:hJ:\pvdLWwhp:uC<WxuC<Wxi@:]gT:f;eI:W;IjW:wA\je:KyNZx;Y:yfl\puJef;nruLLntuntuJPrryZu;Xktf<:::::I::;<=U::>BFb::;<=HMFrwJ>fat:G:A^K=:JDFZKOCZLFP]]akSfAs?:A:?s"
3FOR I=0 TO 128:POKE I,FNP(I+1)*4+(INT(FNP(130+(I-1)/3)/(4^(I MOD 3))) AND 3):NEXT:CALL V
When the bot finally arrived, I worked and got it fitting in a tweet. I had to reduce the color bars to only two as I could only fit 116 bytes of executable.
1DEF SEG=256:DEF FNP(X)=ASC(MID$(A$,X))-35:A$="3:a32f4a3MSc0oaa2aB3U^m]<NpSf3n<5Mqn<5Ppb6*T`I2_4^B3P4>bP1p:Rc^+BrCRq/Q3p_eMgn?]_1gkiDE_kn_kn:Gk_oSh3QYk_433%03A3345616/[`3'OJ]#0#*G4-/C48,C5/9FFJT<O*\(#"
2FOR I=0 TO 116:POKE I,4*FNP(I+1)-64+FNP(118+I\3)\4^(I MOD 3):NEXT:CALL V
In the end this didn't work, as for GWBASIC the PC bot uses PC-BASIC. So my only hope was QBASIC and I did manage to get it working with the following code:
DEF FNP(X)=ASC(MID$(A$,X))-35:A$="3:a32f4a3MSc0oaa2aB3U^m]<NpSf3n<5Mqn<5Ppb6*T`I2_4^B3P4>bP1p:Rc^+BrCRq/Q3p_eMgn?]_1gkiDE_kn_kn:Gk_oSh3QYk_433%03A3345616/[`3'OJ]#0#*G4-/C48,C5/9FFJT<O*\(#"
FOR I=0 TO 116:POKE I,4*FNP(I+1)-64+FNP(118+I\3)\4^(I MOD 3):NEXT:CALL ABSOLUTE (V)

Three Colors Bars -- 122 byte Machine Language


It took a while but I figured out how to find the address of the string directly (hint: use SADD not VARPTR). This allowed fitting another line of colors in the color bars.
FOR I=0 TO 122
POKE I,4*PEEK(V+I)-204+(PEEK(V+123+I\3)-35)\4^(I MOD 3)

Rickroll Animation -- Pure Basic


I thought I was done, but then Foone was trying to get a Rickroll going, and I knew this would be the perfect thing for my box drawing library for the AppleIIbot and one thing led to another...

I originally used PEEK but Foone's idea to use MID$ ended up being a lot more robust and smaller in the end.

A$="p ~ ~7GYG~31FG\3U^Ge2/BP\27Zf~2U[Ue`FM:FwJS/A&GU).&AI,;8RTO~8OUCMwSU8;1+F]k`GP\ep_j\p1[ifq`itipp^wft1^gfq`_f\e"
FOR I=0 TO 21
LINE (FNP(2),FNP(4))-(FNP(3),FNP(5)),FNP(1)-32,BF
IF I=21 THEN I=15

One Program / Two Bots -- Applesoft and GW-Basic


I was wondering how hard it would be to make a program that would run under both Applesoft and GW-Basic. Turns out to not be too bad. The fact both are by Microsoft helped.

The PEEK used to check which machine we're on is the official Apple II machine-detection code which is 6 on IIe machines like the bot. Luckily GW-BASIC doesn't try to parse code you don't reach. QBasic does so this won't run there.
0 A$="'2aBW'271A'8?8A&.1DU&RaBS&bkHW$2ORS% -FS"
1 DEF FNP(X)=ASC(MID$(A$,I*5+X))
2 IF PEEK(64435)=6 THEN 9
5 SCREEN 7:FOR I=0 TO 7:LINE (FNP(2),FNP(4))-(FNP(3),FNP(5)),FNP(1)-32,BF:NEXT
The first attempt the colors on the PC version didn't match. The HGR colors 4 5 6 7 almost match CGA colors 0 2 1 3 so if we could only somehow efficiently swap to get those... I did manage in the end but it's really ugly. I also changed the machine detection to PEEK(0) which on Applesoft is a JMP instruction ($4C / 76).
0 A$="'2aBW'271A'8?8A&.1DU&RaBS&bkHW$2ORS% -FS":DEF FNP(X)=ASC(MID$(A$,I*5+X))
5 SCREEN 1:FOR I=0 TO 7:LINE (FNP(2),FNP(4))-(FNP(3),FNP(5)),3 AND(216\4^(FNP(1)-36)),BF:NEXT

Frequent Questions

Code/Tool Availability

The code and utilities I used to make these can be found on github: https://github.com/deater/dos_programs.git

Back to my Demos Page
See my AppleIIbot programs