Termite

Ok I will explain a nice graphics demo called termite.
This is a program written by Dan Englender...

If you know a bit calc community, you should really know him, he's a great asm developper.

Come back to our review and first look at the result of this program :



The visual feedback is pretty cool, let's see how Dan done it.

include "ion.inc" #define termites apdram ; each termite has x,y,state #define numterm 50 ; number of termites #define chips 500 #define changec 5 #ifdef TI83P .org progstart-2 .db $BB,$6D #else .org progstart #endif ret jr nc,init .db "Termites",0 init:


There are some interesting things here.
First, we have the standart ion header like defined by Joe Wingbermuehle (Ion developper corner).
I copy paste the code found on the official website joewing.net :

.nolist ;\ #include "ion.inc" ; \ .list ; \ #ifdef TI83P ; \ .org progstart-2 ; | Standard Ion .db $BB,$6D ; / Program Header #else ; / .org progstart ; / #endif ;/ ret ; use xor a if libraries are not used jr nc,start ; jump to the start ; of the program .db "This is the description",0 start: ret .end .end


As you can notice on the first piece of code, Dan will use the ion libraries (because there's no xor a).

The second thing you can see is that Dan defines some consts as the number of termites, chips (what's that?) and changec (something with coords change?) and a place to store termites informations (x, y state).

Let's continue :

ld bc,chips initchiploop push bc ld b,64 call ionrandom ld e,a ld b,96 call ionrandom call iongetpixel or (hl) ld (hl),a pop bc dec bc ld a,b or c jr nz,initchiploop


In this part, Dan loads 500 in bc, save bc which is used later to loop with dec bc, load a, b, or c, jr nz, initchiploop (means, loop until bc is equal to 0).

ionrandom return a value between 0 and b.The value is stored in a.
As you can see, Dan generate a random y coord (64 pixels height), then a random x coord (96 pixels width), then get the pixel state with iongetpixel.
iongetpixel also return the adress in the graphbuffer in hl, so or (hl) will do and or between a and the 8 bits containing the random pixel.
Then if the pixel was turned off, if becomes on, if it was on, it keeps on, and other pixels keeps at their state.
And loop 500 times (there's more pixels on the screen don't worry).

ld b,numterm ld hl,termites otherstart: inittermloop: push bc ld b,64 call ionrandom ld (hl),a inc hl ld b,96 call ionrandom ld (hl),a inc hl ld (hl),b inc hl ld (hl),b inc hl pop bc djnz inittermloop


Then Dan loads the number of termites, and do the same kind of task but this time he simply store the x, y and state into 4 bytes.
At this point, the state seems to be a dummy value (b into state with a b destroyed by ionrandom).
And it loops until numterm becomes 0 (in fact numterms isn't modified, but its value in b is decremented).

call ionfastcopy di termloop: ld a,$Fd out (1),a in a,(1) cp 191 ret z cp 254 call z,ionfastcopy ld b,numterm ld hl,termites


The call ionfastcopy copy the graphbuffer to the screen (but faster than the TI's routine).
Then we have direct input stuff.
When clear is pressed, the program stops, if enter is pressed, the graphbuffer is copied to the screen.
And finally, Dan loads numterm in b and prepare hl with termites data list adress.

termmoveloop: push bc ld e,(hl) inc hl ld d,(hl) inc hl push hl call getnewcoords ld a,d push de call iongetpixel pop de and (hl) pop hl jr z,nochip ld a,(hl) or a jr z,pickupchip putdownchip: ld (hl),0 dec hl ld d,(hl) dec hl ld e,(hl) inc hl inc hl call pixelon inc hl call forcedir dec hl jr nextterm nochip: dec hl ld (hl),d dec hl ld (hl),e inc hl inc hl jr nextterm


Ok the number of termites is saved on the stack, e get the x coord and de the y coord, save hl and call getnewcoords for the current termite.

Then Dan get the pixel pointed by the new coords, and do an and between a and the 8bits (pixels pointed and 7 bits around).
After that, the state is used and if the state is 0 then pick up chip, else put down chip.

Put down chip consists on turn on a pixel and change direction of the termite.

The no chip routine simply put new coord into the current termite coord and process to the next termite.

pickupchip: ld (hl),1 dec hl ld (hl),d dec hl ld (hl),e inc hl inc hl call pixeloff nextterm: inc hl inc hl pop bc djnz termmoveloop jr termloop


The pickupchip put the state 1 and save new coords of the termite in current coords then turn off the pixel.
Finally, the nextterm label simply increment hl (to go to the next x coord into the list and loop until the number of termite is 0.

When it's 0, it jumps to termloop (copy graphbuffer and read keys).

pixelon: push de push hl ld a,d call iongetpixel or (hl) ld (hl),a pop hl pop de ret pixeloff: push de push hl ld a,d call iongetpixel cpl and (hl) ld (hl),a pop hl pop de ret


Now two useful routines, to turn on or turn off the pixel, notice that cpl invert all bits from a.

getnewcoords: inc hl call changedir ld a,(hl) or a jr z,moveleft dec a jr z,moveright dec a jr z,moveup inc e ld a,e cp 64 ret nz ld e,0 ret moveleft: dec d ld a,d cp 255 ret nz ld d,95 ret moveup: dec e ld a,e cp 255 ret nz ld e,63 ret moveright: inc d ld a,d cp 96 ret nz ld d,0 ret


When termite requests for a new coord, the changedir could eventually change the direction (forcedir always change the direction).
Then depending the random number in (hl) (the dir), it could move left (0), move right (1), move up (2) or move down (3).

When movin down, we need to protect the floor (y = 64), and when moving up, we need to protect the roof (y = 0) etc...
If it's Ok, then return, else put the max/min number (63, 95, 0, 0).

It's really easy to move a pixel and to protect the screen isn't it? :D
changedir: ld b,changec call ionrandom or a ret nz forcedir: ld b,4 call ionrandom ld (hl),a ret .end


To conclude, here's the changedir routine and the forcedire (note that forcedir is executer if the random number in a is not 0.
So a big value in changec will allow termites to move easily, a tiny value the contrary.

I hope you find this review funny, this code is pretty cool, easy to read, easy to understand, and clean.
Thank you Dan Englender for this source code.