AppleIIbot 280 char Applesoft Demos -- Part 2


Snowflake (141 byte assembly program)


link

Since it's getting to be winter I wanted to do a falling-snowflake mini-demo. In the end I liked the way this snowflake looked and wanted to animate it, which turned out to be a huge pain. Even with the large amount of symmetry it was just too big (mostly due to the bizzarre HGR pixel layout). I eventually got it down to around 140 bytes or so, but still too big for the previous loaders. (The orange/blue stripes is actually a bug I caused at the last minute because I removed a row of the sprite but forgot to update the line count. It looked cool though so I kept it).

The code uses the ampersand operator to run itself. In Applesoft this does a JMP to address $3F5. To save space I load the code there. The code starts there, overwrites the interrupt vectors (which we don't need) and keeps going into page $400 where text mode lives, which is why you see the weird chars on the screen (shown to the above right). This is the machine code being decoded to screen memory while we wait, and then we jump to it.

So how did I load 141 bytes of assembly when the previous record was around 128?

As a reminder, the previous code does 6+2 encoding, where each byte is split into 6 high bits and two low bits (which are then encoded into ASCII). The two low bits are grouped together with those of 3 consecutive bytes and stored at the end. The old code does two MOD (remainder) operations, one by 3 (to get the offset for the low bits) and one by 4 (we take the low bit value, shift right, and then mod by 4 to mask off the high bits before adding). There is no MOD operator on Applesoft so we have to instead divide and subtract, which takes a lot of room. So what if we could get rid of one of them? So I spent a lot of time figuring out how to get rid of the mod-by-4.

Instead of masking, we could just subtract the whole 6/4/2 bit second value. (Even better, we could XOR, but there's no XOR operation in Applesoft either). We subtract off the value before storing the top 6 bits, and when we add it back on we get the proper value back! The problem with that is this is a twos-complement situation and so in some cases we'd end up with a value above 256. No problem, just mask the bottom 8-bits... except in this case we've just traded one MOD for another.

So how to resolve this? Well it turns out that the Apple II bot emulates an Apple IIe and has lowercase support. So if we add an extra 64 to the values before doing the subtraction we don't get the wraparound problem, at the expense of having code that won't run on an Apple II+. Probably worth it. With this change we can now load programs up to 141 bytes in size. I did some other minor optimizations and combined constants to make it a bit smaller too. I'd really like to also get rid of the 4^MOD3 code but haven't had much luck on that part yet.

1REM,clV5QfWo3NQegoQoX&VPYo8,kYf]J+Y_60T9jb`6dkio^o<\2g000000?0003600L100?H0,B6$-<$I1.I<-?0..?-?0:O@):1K0O):1I7033N30H3-0012345.699<>7<<998654321P1G=J!H!AG80" ).B  $  #'0PP(2X2(C$C,, T  B(A(" 
2FORI=0TO141:POKE1013+I,4*PEEK(2054+I)-192+(PEEK(2195+I/3)-32)/4^(I-INT(I/3)*3):NEXT:&
Link to source: snow3.s

Plasma (141 byte assembly program)


link blue
link red

I was doing some work on rotozooming and plasma effects and managed to get a nice effect that fits under 128 bytes. This is assembly language so what's going on is a bit beyond the scope here, but it creates the circle texture by a repeated pattern of sine calls (based on the X and Y co-ordinates). A lookup table is used for the sine values to make things smaller/faster.

To make things more fun, the colors are then rotated. On fancier machines you could quickly do this by doing a hardware palette rotate, but the Apple II doesn't support that. So it has to rotate things manually by incrementing the colors in the texture and redrawing the screen.

You'll note the results flicker a lot, that's because the screen is displayed as it is drawn. You can avoid that with page-flipping, but that takes an extra 20-bytes but at around 146 bytes it was just too big to fit in a tweet. Here's the original no-flip version:
{B15}
1REM,=n9D`M1X/5Z.NJ.MJ-AS'1k-1b3kR4jjk/3bbnM9R(021QoPB25An-W3N/J_O;M7QkU:21oY_0&73<Y_D2Q463dWoR4i^3b6^E*FMhLE)/1%/1.00hmnaknbP(L3748DA$ 2@NJ&*,T8DL2'&U:2@H 28Z?<S-=TU
2FORI=0TO121:POKE3072+I,4*PEEK(2054+I)-192+(PEEK(2175+I/3)-32)/4^(I-INT(I/3)*3):NEXT:CALL3072

I mentioned how close I was to getting the code to fit, so of course everyone said that I should optimize things, most notably that I should bug qkumba for help. First though I went back and re-wrote my encoding scripts so they could generate the slightly more compact encoding figured out by Tom Greene that saves three bytes by putting the encoded strings in a quoted string rather than a REMark (comment) statement. You can also save a byte because if it's at the end of a program BASIC doesn't check for a closing quote. With the new encoding the page flipped version just barely fit, but there wasn't room to put a delay directive so the snapshot of the video was a boring blank screen as it takes around 11s or so to do the decoding.

Next though qkumba came by and saved the day, optimizing the assembly language to free up a few bytes, mostly noticing places where I was saving/restoring flags on the stack (you could re-arrange code to avoid that). The nice thing about saving space in the binary is it can save 1.5x the space in the BASIC program so after that we had enough room for a delay directive. I changed the colors to red from blue for variety.
{B15}1FORI=0TO140:POKE875+I,4*PEEK(2125+I)-192+(PEEK(2266+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",=n9D`M1X/5Z.Ni+Mi*AS'1kE.b3kR4jjk/3bbnM[0k0j_E`>0SS.X9RB(021QoPBX+R0XlQ/5AaV9F/Q-U9I73)mZ[/3/1BQ]g/Q<63nR4j@Xb2a<VD4-[o]E0#.1+01,/omnngmo4G0S+O6::>GO'#5C\'#4Q.M)-F#UW4VWD4PI*+#K+8b*Z?6*@_

Link to source: plasma_bot.s

C64 (144 byte assembly program)


link

This one seemed more interesting in my head. I'll troll everyone by having the Apple II bot display a Commodore 64 screen! It turns out that's much harder than you might think.

If you use double hi-res and around 1k of code/data you can get a good approximation (though still off, as the C64 is 320x200 while the Apple II can only do 280x192). Something like this:


This turns out to be hard. You can't just draw colored text on an Apple IIe. (a IIgs sort of can). So it's graphics. Double hi-res is a nightmare though, it's not a simple linear bitmap, but a weird mix of bank-switch shifted craziness. So I dropped down to hi-res.

I've done hi-res C64 trolling before with my Megademo but to fit in a tweet is even more challenging. No room for full bitmap, no room for compression. At first I thought it was not possible, but then I started messing with shape tables. You can actually get about 1/2 of things displayed with just plain BASIC, but you run out of room.

I moved to assembly language, but that still didn't quite fit. You need at least 16 chars if not more to display a c64 boot. In the end to fit in a tweet the best I could do was 8 approximate chars and then picked the ones that looked vaguely close. Not very satisfying, but maybe midly impressive you can get this close at all with such a limited space.
1FORI=0TO143:POKE1013+I,4*PEEK(2126+I)-192+(PEEK(2270+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",clYe8jlQ0RQ`X0JhZ%NoW56F1QmZX#Vo74mU/^I16?=ZT0Z,70ki0U/Yo`7b1QbWoPo`,ac^l?4:1-?99=06=?1->0Y1-79:10389/-8900.00(02/80'02*21(38%/8%/3+-8(02.46'17S(/#G@W04,W'3#P33-3$+Z(T[7/,/UG/0VT#+M1L@W^^UM5Q

This version was 144 bytes (I later got it down to 142) so no room for time skipping so you are stuck watching it decompress to the text page. I felt like it was fitting, as if it looked like the II was losing it's mind as it switched to c64 mode. It does make for un-interesting thumbnails on the appleiibot page though, which means most people don't bother clicking on it.

Link to source: c64.s

Triangles -- Applesoft with some Pokes


link

I was looking into doing a Serpinski triangle, but that turns out to be a bit tricky to do in a small space. However you can get an approximate Serpinski with a simple loop and a bitwise-AND. This seemed like it would be a great program for here, but the problem is Applesoft has no bitwise-AND instruction.

So how to do a bitwise-AND? You can open code one with a loop to iterate it bit by bit, but that's really slow and a pain on Applesoft, including all the complexity to do shifting and masking.

So what about assembly language? A full assembly language program would be overkill, but maybe we can get some plaintext assembly going. So that's what this code does. Applesoft tokens have the high bit set and can be used for those values. So the code at 100 is just doing a
LDA #$??
AND #$??
STA $24
RTS
and the POKEs are putting the proper values into the constants and then calling into the code that's inline in the program. It runs reasonably fast as well.
10 GR:COLOR=9
20 FOR X=0 TO 39
30 POKE 2138,X
40 FOR Y=0 TO X
50 POKE 2140,Y:CALL 2137
60 PLOT X,PEEK(36)
70 NEXT Y,X
100 SPEED=$)%DEL$`

That code only works if you allow lowercase (the back-tick for the $60 RTS). If you want to run this on an Apple II+ you'll need to do something different. After some back-and-forth in the comments the most elegant solution seems to be to use "LRUSR" which is a jump to an RTS in the Applesoft ROM. You can also be clever with line numbers if you prefer.

Sierpinski Zoom -- 140 byte Assembly Language


link

This one ended up surprisingly popular so I guess I should mention it.

I was messing around some more with the Sierpinski Triangles, using the algorithm from Hellmood's Memories demo

For the calculations, you more or less go across the 40x48 lores display and plot each point with
COLOR= ((Y-(X*T)) & (X+(Y*T)) & 0xf0
where T increments each frame. This works, but is slow, especially with the multiplies. There is no multiply instruction on 6502 and it takes at least a hundred cycles to implement it. One thing you can notice though is that you can take the Y*T outside the inner loop, and also you can get rid of the multiplies all together and replace them with adds at each step. The adds do end up being 8.8 fixed point (16-bit) adds which does slow things a bit.

The code ends up being 140 bytes, but 20 of those bytes are page-flipping to make the animation smoother.

You might ask if you can do this in hi-res? You could, but it would be a lot slower. Plotting a lo-res pixel is nontrivial, and hi-res is even more of a pain to do quickly. Plus you have roughly 8 times as man pixels to draw.
{B11}1FORI=0TO139:POKE876+I,4*PEEK(2125+I)-192+(PEEK(2265+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",=n9D`V/QfOoP.QaNnUnInQoRmIbNnPBT0XlTU3O;8=mY9X0PnQmJ0N9VBmQjXnDnQmYnCnQlR>em9n:le/Z,:ZbQ<63nb`:bejh<dUXoE/QfWoF/Qeie.X0NU0k0j_E`>0SU0CK0CH0S+4HE[4(@Y-&U+6&''0@:8(<+4*?3'+#+#:8H4M.X'#40//

Link to source: sier_bot.s

Water Drops -- 141 byte Assembly Language


link

This demo was based on an Atari8BitBot entry by Sebastian Igielski

That one fit in 128B. I reused the core algrithm but despite that I had trouble getting it below 150 bytes. In the end I did, but had to limit it to 4 colors and we're making some questionable assumptions about register variables.

The algoritm is you place the 2x2 square dot of value 31 at a random position, then iterate the sceen updating the colors, flipping between two buffers.

For each pixel:

         C
       A V B
         D
calculate color as NEW_V = (A+B+C+D)/2 - OLD_V then flip buffers.

Had to do some vaguely clever stuff here, including using HGR to clear memory to zero.
1FORI=0TO140:POKE875+I,4*PEEK(2125+I)-192+(PEEK(2266+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&"*el9D`9E`ImQminYnZ1.2,123Po>1QkU:(b6^0hKm:028JmZ3YTjaTbUARnbJlX9RZ80nS8Qn6X/\oSCLoX:LoX9Lo>Qlg20;nTmiogod+ho^mB570U]l/Q<Xn8+lan4bb4_1N8:Jo4G0[++E-$H=746F$<*@65U,L.#@$(7#$)5E@--;QY7*'E$%Oa_

Link to source: drops_bot.s

Animated Rickroll -- Basic


link

This demo came about when @Foone was trying to get a rickroll on the new PCBasicBot. I managed to use my box-drawing code to get something there, and then realized I might as well port it to Apple II.

I thought this would be easier, but it turns out I forgot I'd have to adjust the co-ordinates due to the weird aspect ratio of lo-res mode.

You can fit more boxes on Applesoft than in QBasic so there was room to stick some lyrics at the bottom.
0REM' G G/16/G$,1/9$57/>,+039,-6>G,576>#13(.+25#,(15 "(02!)%443G%35-2+56') *1:A+149>'7:9C 6:>D+:=@C'7C>E 7:>D+799>
1GR:?"    o/~ NEVER GONNA GIVE YOU UP o/~":DEFFNP(X)=PEEK(2054+I*5+X)-32
2FORI=0TO22:IFI=22THENI=15
3COLOR=FNP(0):FORY=FNP(3)TOFNP(4):HLINFNP(1),FNP(2)ATY:NEXTY,I
I did try porting this to hi-res as well, but it looked horrible due to color clash (and not really having good colors to draw people).

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


link

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
7 END
9 HGR:FORI=0TO7:HCOLOR=FNP(1)-32:FORY=FNP(4)TOFNP(5):HPLOTFNP(2),YTOFNP(3),Y:NEXTY,I
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))
2 IF PEEK(0)=76 THEN HGR:FORI=0TO7:HCOLOR=FNP(1)-32:FORY=FNP(4)TOFNP(5):HPLOTFNP(2),YTOFNP(3),Y:NEXTY,I:END
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

Wire Spark -- 141 Byte Assembly


link

This is a sort of typical palette-rotation demo that you might find on other platforms. The difference is that Apple II has no palette hardware, we are having to fake it up in software here.

The pattern is written to an offscreen 16x16 texture which is tiled to the 40x48 lo-res screen. Pageflipping is used. Each frame the entire screen is re-drawn, using a lookup table to handle the colors rotating. This is tricky in that unlike the plasma demo, we don't want to rotate the black color, and also we don't want to waste 16 full bytes on a color lookup table so we have to special case handle the dark blue color.

More trickery: we use the ROM HGR2 routine to initialize full-screen graphics, then use a soft-switch to drop down to lo-res mode. This also sets up the hi-res code to point to $4000, which is where our texture lives. We can then use the BKGRND hi-res ROM routine to initialize memory to $10 in not many bytes (this makes generating the texture a lot more compact). Using HGR like this makes for a cool effect when initialization is happening, but you can't see it on the twitter bot as I fast-forward past it so the thumbnail isn't just a blank screen.
1FORI=0TO140:POKE875+I,4*PEEK(2125+I)-192+(PEEK(2266+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",clZ48jl;=^X-QW<?WX>2(02TQV-?V+>b.i_,?b(Y1f/:2W0>bd^Xa,k0j_E_B1D^0M9R802,1QePBU3T0XlO;8=mY8J0N9X5U:21oY_03_2K/ZSf02X8Q<83nR4iJXb4T9W:JoKI04G0S$/E>3CM;3C;3S4*+Z6#'`QK=K/%+6*06*)WGTG$%#-Ua._

Link to source: wires_bot.s

Death Star Tie Fighter -- Applesoft BASIC


link

I was researching Apple IIe Mouse-text for other reasons and came across an old video that showed that the extra characters are perfect for making tie-fighters for some reason. Very odd. Otherwise mouse-text is great for making sort of mac-looking text guis but fairly useless for ascii art.

1HOME:POKE49167,0
2FORX=0TO64:POKE1024+RND(1)*999,174:NEXT
3FORI=0TO1:COLOR=6-I:FORJ=0TO1
4HLIN8,10AT6+J*10+I:HLIN7,11AT8+J*6+I:HLIN6,12AT10+J*2+I:NEXTJ,I
6VTAB6:HTAB11:?"()"
7FORX=13TO37:POKE1063+X,90:POKE1064+X,91:POKE1065+X,95
8FORI=1TO200:NEXT:VTAB9:HTABX:?"   ":NEXT
9GOTO7

Amiga Ball -- 141B Machine Language


link

I was wondering how hard it would be to make the Amiga Boing Ball. It turns out really hard in 141B. I did get a vaguely checkboard ball moving, even sorta rotating, and slowly bouncing around. The purple line is more of a killer than you might think, and the color is reused for the length which is why the ball doesn't bounce at the edge.

1FORI=0TO140:POKE875+I,4*PEEK(2125+I)-192+(PEEK(2266+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",clJlZ?QnV0QjPn7iD-:EV?ic1;=^1a6lhiZDQi5EmPSX,WE2=mUmQjY3ImYdX3Yo`3l1_0d1jjT1QhQAn:1e/Zk:ZYQiT/Yc5EkYh\^n\gimaoZ`X#ZmLn<$Rm01]a?oLlmlb4f;Q4G0S@'+5+6K'CE6(/L3;4:DJ#$'#<>'?6)3V+[C.KX(W3XH,6_

Link to source: ball.s

Floppy Rain -- Applesoft BASIC


link

From the same MouseTrap:PSeditor demo that had the tie-fighters they also had some MouseText floppy disk art. I couldn't tell from the screenshot exactly how they drew them so this is just an approximation. Using the 80-column card firmware here to switch in and out of mouse-test mode to draw things.
1?CHR$(4)"PR#3"
2?CHR$(27)
3N$=CHR$(14):I$=CHR$(15):B$=CHR$(8):F$=CHR$(10)+B$+B$+B$+B$+B$+B$
4GOSUB8:?"_____ "F$B$I$"ZA----_"F$B$I$"Z"N$"  o "I$"S_"F$B$I$"Z"N$"__|__"I$"_"N$
6GOSUB8:?N$"____ "F$I$"Z"N$" =='"I$"_"F$I$"Z"N$"_"I$" \T_"N$
7GOTO4
8VTAB1+RND(1)*20:HTABRND(1)*70:RETURN

Pastel Scroll -- No-poke Machine Language


link

For my LoveByte demos I had a few 16-byte demos, and I wondered if I could somehow encode them into plaint-text/BASIC tokens and thus have machine language without using POKE or PEEK. It is possible, but you have to expand the 16-byte demo out to nearly 64 bytes for it to work.

Some notes: the + on the call is because at one point the code was easier with 1-byte padding added (I had to re-calculate addresses every time I changed things). For BASIC here you are limited on ascii codes $21-$60. Uppercase outside of strings/comments gets automatically uppercased, and so do the higher ASCII chars like ~ and {.

You also get tokens for $80 through $EA. To make constants you have to LDA and then either shift right or EOR, other methods use banned characters. Doing a JSR is not possible ($20 is a space which the tokenizer eats) so I had to fake it by PHA pushing the destination address then return address on the stack and using RTS to call the functions. Very complex, but in the end it worked.

10 CALL +2064
20 ,PTAB(PR#UPSTORESPEED=@JJJHSPEED=XJHSPEED=COLOR=IXHSPEED=HIMEM:ITAB(HROT=`LEFT$STORESPEED=@JJJHSPEED=$JHSPEED=ONERRIXHSPEED=GOSUBI\HROT=`

16x16 8 Color Images


link, link

Lovebyte had a 16x16 image contest. Some of the results were pretty cool, so I worked on seeing how much I could fit in a tweet. It's a bit complex, especially because lo-res pixels aren't square. In the end I could approximate squares by using VLIN to draw the pixels, and it had a cool effect as the lines get drawn in.

Smolly Millions by Exocet
1GR:FORI=0TO135:C=PEEK(2161+I)-35:IFI<8THENA(I)=C:NEXT
4FORX=XTOX+1:COLOR=A(C-INT(C/8)*8):VLIN2*INT(I/8),33ATX+12:C=C/8:NEXT:X=X*(X<15):NEXT:"#%)*&$2.##+,,$###,#4>5$#+-G0U66#4DYJ4A>$,_Yb/>=%DGP`2=5%\,,_R5-%_'SbR4-%HbbJG+-$#_bPP+%$#C_RH+$$##PGO+$###KP#+$##KY_J1##,_XIbX,,5_WYYY55

An Eye for Graphics by LamerDeluxe
1GR:FORI=0TO135:C=PEEK(2162+I)-35:IFI<8THENA(I)=C:NEXT
4FORX=XTOX+1:COLOR=A(C-INT(C/8)*8):PLOT12+X,9+I/8:C=C/8:NEXT:X=X*(X<15):NEXT:GOTO1
6".+#'2*/(#,#34,-%+$345555,3455555$455>655+5=>HO654=A5RG@M5V65]H?M5>955H?E8V655R@E7>955=>EO=A55V6HG=VAAA6GH8>VV>MGLO5>>5HO+0O55HO,#+,,,,,#

Animated Bresenham Lines


link

I was trying to see if I could draw some arbitrary lines in Lo-res (it's easy to HLIN or VLIN but not diagonal). So I was working on Bresenham Lines, which work, but take up a lot of room. Signed compare is a pain on 6502. Did make a cool animated pattern though, which reminded some people of "LOOM".

This code uses the SETCOL machine language routine to increment COLOR by 3, which is built into the Apple II ROM for some reason.
1FORI=0TO140:POKE875+I,4*PEEK(2125+I)-192+(PEEK(2266+I/3)-35)/4^(I-INT(I/3)*3):NEXT
2&",=nV8QhAQgPl5GnV/QjZ8d0j*d0)g05ImQnYfXlR80f_ld1i`i:Ql2@X0`ml.5ieB0BP<,Xm+a0jJ6imD/BP/0Yi7d(AS0J>j14T;W5InMm]h5MlUlD=]ckl<1Xc91S/Bk5J(SmUmH4G0S469/4+1[_'$;%C#VD+(4D$8W#$)73F&$6'43)3G#V76D$_

Link to source: lines_bot.s

Animated Cube


link

I was trying to get a nice animated cube going with actual math. That turned out to be too difficult. Here we cheat a bit, and it's just got a few sets of 14 co-ordinates that it does connect-the-dot with some page-flipping to make it a bit smoother.
0REMOa5^JDfFOa>D"B9'S*>D"B5^JD9'S*fFKM9dRYfDKM6/"D=;O$6/"D9dRY=;O$fDD48YX_d;D40)$MDTP/0)$M8YX_DTP/d;
1HGR2:HCOLOR=3:DEFFNP(X)=PEEK(2054+32*J+I*2+X)+28
3FORJ=0TO2:FORI=0TO14:HPLOT44+FNP(0),FNP(1)TO44+FNP(2),FNP(3):NEXT
8POKE230,32+32*P:P=NOTP:POKE49236+P,0:CALL-3086:NEXT:GOTO3

On to Part 3
Back to Part 1
Back to main Apple II bot page