; scanline fill by John Metcalf
; call with d=x-coord, e=y-coord
; set end marker
fill:
ld l,255
push hl
; calculate bit position of pixel
nextrun:
ld a,d
and 7
inc a
ld b,a
ld a,1
bitpos:
rrca
djnz bitpos
ld c,b
ld b,a
; move left until hitting a set pixel or the screen edge
seekleft:
ld a,d
or a
jr z,goright
dec d
rlc b
call scrpos
jr nz,seekleft
; move right until hitting a set pixel or the screen edge,
; setting pixels as we go. Check rows above and below and
; save their coordinates to fill later if necessary
seekright:
rrc b
inc d
jr z,rightedge
goright:
call scrpos
jr z,rightedge
ld (hl),a
inc e
call checkadj
dec e
dec e
call checkadj
inc e
jr seekright
; check to see if there's another row waiting to be filled
rightedge:
pop de
ld a,e
inc a
jr nz,nextrun
ret
; calculate the pixel address and whether or not it's set
scrpos:
ld a,e
and 248
rra
scf
rra
rra
ld l,a
xor e
and 248
xor e
ld h,a
ld a,l
xor d
and 7
xor d
rrca
rrca
rrca
ld l,a
ld a,b
or (hl)
cp (hl)
ret
; check and save the coordinates of an adjacent row
checkadj:
sla c
ld a,e
cp 192
ret nc
call scrpos+1
ret z
inc c
bit 2,c
ret nz
pop hl
push de
jp (hl)
Saturday, 29 April 2017
ZX Spectrum Scanline Flood Fill
Sunday, 29 May 2016
Divide and Conquer Line Algorithm for the ZX Spectrum
While attempting to write a game in 256 bytes I needed a routine to draw lines, but Bresenham's line algorithm weighs in at approx ~120 bytes. The only suitable alternative I'm aware of is recursive divide and conquer: divide a line into two smaller lines and call the draw routine with each in turn:
/* Draw a line from (ax,ay) to (bx,by) */
int draw ( ax, ay, bx, by )
{
int midx, midy;
midx = ( ax+bx ) / 2;
midy = ( ay+by ) / 2;
if ( midx != ax && midy != ay )
{
draw( midx, midy, ax, ay );
draw( bx, by, midx, midy );
plot( midx, midy );
}
}
This is significantly smaller thank Bresenham's, 32 byte of Z80. However, there are a couple of compromises: it's slower and the lines aren't perfect because the rounding errors accumulate.
; draw lines using recursive divide and conquer
; from de = end1 (d = x-axis, e = y-axis)
; to hl = end2 (h = x-axis, l = y-axis)
DRAW:
call PLOT
push hl
; calculate hl = centre pixel
ld a,l
add a,e
rra
ld l,a
ld a,h
add a,d
rra
ld h,a
; if de (end1) = hl (centre) then we're done
or a
sbc hl,de
jr z,EXIT
add hl,de
ex de,hl
call DRAW ; de = centre, hl = end1
ex (sp),hl
ex de,hl
call DRAW ; de = end2, hl = centre
ex de,hl
pop de
ret
EXIT:
pop hl
ret
; ---------------------------
; plot d = x-axis, e = y-axis
PLOT:
push hl
ld a,d
and 7
ld b,a
inc b
ld a,e
rra
scf
rra
or a
rra
ld l,a
xor e
and 248
xor e
ld h,a
ld a,l
xor d
and 7
xor d
rrca
rrca
rrca
ld l,a
ld a,1
PLOTBIT:
rrca
djnz PLOTBIT
or (hl)
ld (hl),a
pop hl
ret
Alternatively the de(end1) = hl(centre) test can be replaced with a recursion depth count to create an even slower 28 byte routine:
; draw lines using recursive divide and conquer
; from de = end1 (d = x-axis, e = y-axis)
; to hl = end2 (h = x-axis, l = y-axis)
DRAW:
ld c,8
DRAW2:
dec c
jr z,EXIT
push de
; calculate de = centre pixel
ld a,l
add a,e
rra
ld e,a
ld a,h
add a,d
rra
ld d,a
call DRAW2 ; de = centre, hl = end1
ex (sp),hl
call DRAW2 ; de = centre, hl = end2
call PLOT
ex de,hl
pop hl
EXIT:
inc c
ret

Friday, 27 May 2016
Langton's Ant for the ZX Spectrum
Langton's Ant is an automata which creates a complex pattern by following a couple of simple rules:
- If the ant is on an empty pixel, turn 90° right, set the pixel then move forward
- If the ant is on a set pixel, turn 90° left, reset the pixel then move forward
The ant's path appears chaotic at first before falling into a repetitive “highway” pattern, moving 2 pixels diagonally every 104 cycles.
Here's the code to display Langton's Ant on the ZX Spectrum in 61 bytes. It runs in just over a second so you might want to add a halt to slow things down:
org 65472
ld de,128*256+96
ANT:
; halt
ld a,c ; check direction
and 3
rrca
add a,a
dec a
jr nc,XMOVE
add a,e ; adjust y position +/-1
ld e,a
cp 192
ret nc
xor a
XMOVE:
add a,d ; adjust x position +/-1
ld d,a
; ----------
and 7 ; calculate screen address
ld b,a
inc b
ld a,e
rra
scf
rra
or a
rra
ld l,a
xor e
and 248
xor e
ld h,a
ld a,d
xor l
and 7
xor d
rrca
rrca
rrca
ld l,a
ld a,1
PLOTBIT:
rrca
djnz PLOTBIT
; ----------
ld b,a ; test pixel
and (hl)
jr nz,LEFT ; turn left/right
inc c
inc c
LEFT:
dec c
ld a,b ; flip pixel
xor (hl)
ld (hl),a
jr ANT

Saturday, 3 October 2015
The Matrix Digital Rain for the ZX Spectrum
A few days ago I coded The Matrix digital rain effect, a fictional representation of the code for the virtual reality of The Matrix. The technique is simple: fill the screen with random characters and scroll down columns of attributes, occasionally switching between black and green.
Here's the final code - 147 bytes of Z80 using the default Sinclair font:
org 08000h
; black border / black attributes
xor a
out (0FEh),a
ld hl,05AFFh
attr: ld (hl),a
dec hl
bit 2,h
jr z,attr
; fill screen with random characters
ld e,a
fillscr:ld d,040h
fill: call rndchar
ld a,d
cp 058h
jr nz,fill
inc e
jr nz,fillscr
; digital rain loop
frame: ld b,06h
halt
column: push bc
; randomize one character
call random
and 018h
jr z,docol
add a,038h
ld d,a
call random
ld e,a
call rndchar
; select a random column
docol: call random
and 01Fh
ld l,a
ld h,058h
; ~1% chance black -> white
ld a,(hl)
or a
ld bc,0247h
jr z,check
; white -> bright green
white: cp c
ld c,044h
jr z,movecol
; bright green -> green
cp c
ld c,04h
jr z,movecol
; ~6% chance green -> black
ld bc,0F00h
check: call random
cp b
jr c,movecol
ld c,(hl)
; move column down
movecol:ld de,020h
ld b,018h
down: ld a,(hl)
ld (hl),c
ld c,a
add hl,de
djnz down
pop bc
djnz column
; test for keypress
ld bc,07FFEh
in a,(c)
rrca
jr c,frame
ret
; display a random glyph
rndchar:call random
crange: sub 05Fh
jr nc,crange
add a,a
ld l,a
ld h,0
add hl,hl
add hl,hl
ld bc,(05C36h)
add hl,bc
ld b,8
char: ld a,(hl)
ld (de),a
inc d
inc hl
djnz char
ret
; get a byte from the ROM
random: push hl
ld hl,(seed)
inc hl
ld a,h
and 01Fh
ld h,a
ld (seed),hl
ld a,(hl)
pop hl
ret
seed:

Sunday, 26 July 2015
Z80 Size Programming Challenge #5
Recently I issued the fifth Z80 challenge for the Sinclair Spectrum:
This time the challenge is to write a solid flood fill routine to fill a region of unset pixels, bounded in 4 directions (up, down, left, right) by set pixels or the screen edge. The routine should be called with the X and Y coordinates in a register. There's no need to set the screen attributes.
Scoring is multi-objective: a routine will be judged by the code size and stack space required to fill a test image. Your routine will be awarded one point for each competing routine it is smaller *and* uses less stack space than. The routine(s) with the most points will be declared winner(s).
The deadline is Wednesday 22nd July, midday (GMT).
- The X and Y coordinates are in pixels with 0,0 at the top left.
- No memory other than the screen, stack and your routine can be written.
- If you call a ROM routine it's size will be added to your code size.
- Programs must return. The RET instruction is included in the size.
- So everyone has a fair chance comment with the code size not code.
- There are no prizes, just the chance to show off your coding skills.
The test image is designed to check correct behaviour at the screen boundary and to be pathological — triggering suboptimal behaviour in some common flood fill algorithms:

Final Results
Congratulations to everyone who coded a working flood fill and to Dworkin Z Amberu who claimed first place by being shorter and using less memory than competing entries.
Entries have been plotted on this genuine fake Spectrum screenshot. If the graph is empty below and to the left of an entry, that entry is in first place:
| Colour | Coder | Code | Memory | Time |
|---|---|---|---|---|
| Red | John Metcalf | 98 | ~2K | 2.1 seconds |
| Orange | Paul Rhodes | 102 | ~1.8K | 3.2 seconds |
| Yellow | Ralph Becket | 109 | ~2K | 8.8 seconds |
| Green | Miguel Jódar | 166 | ~800 bytes | 4.8 seconds |
| White | Dworkin Z Amberu | 58 | ~9.8K | 28.6 seconds |
| Cyan | John Metcalf | 54 | ~6.1K | 28.6 seconds |
| Black | Dworkin Z Amberu | 84 | ~270 bytes | 40 seconds |
| Blue | Dworkin Z Amberu | 192 | 8 bytes | ~40 minutes |
| Purple | Adrian Brown | 199 | 12 bytes | ~3 hours? |
Shortest Entry
The simplest entry is a recursive routine weighing in at 54 bytes. Despite being too heavy on the stack to score well it's one of the easiest to understand. Each time the routine is called it checks whether or not the pixel at X,Y is set. If not the pixel will be set then the fill routine is called recursively with the pixels up, down, left and right of the current pixel:
; called with e = X horizontal, d = Y vertical
FILL:
ld b,e
ld a,d
and 248
rra
cp 96
ret nc
rra
rra
ld l,a
xor d
and 248
xor d
ld h,a
ld a,e
xor l
and 7
xor e
rrca
rrca
rrca
ld l,a
ld a,128
PLOTBIT:
rrca
djnz PLOTBIT
or (hl)
cp (hl)
ret z
ld (hl),a
inc e
call nz,FILL
dec e
dec de
call ZFILL
inc de
call FILL
inc d
inc d
ZFILL:
call nz,FILL
dec d
ret
The winning entries will be available shortly.
Monday, 6 April 2015
Z80 Size Programming Challenge #4
The fourth Z80 challenge for the ZX Spectrum was issued last week:
Back to something simple for the next challenge, a diagonal fade-to-white CLS. Write the shortest code to wipe the screen by increasing the ink colour of each character until it reaches white.
The clear should start at the top left and move one character across the screen per frame. The initial screen can be assumed to be monochrome — black text, white background, flash off, bright off. There's no need to clear the screen bitmap. Here's a demonstration of the clear in slow motion:

Target: under 50 bytes.
The deadline is Monday 6th April, midday (GMT).
- Your program shouldn't rely on the initial contents of registers.
- Programs must halt between frames. The HALT is included in the size.
- No RAM/ROM other than the attribute memory should be written to.
- Programs must return. The RET instruction is included in the size.
- So everyone has a fair chance comment with the code size not code.
- There are no prizes, just the chance to show off your coding skills.
Final Results
Congratulations to everyone who entered and Arcadiy Gobuzov who claimed first place with a solution in 26 bytes. Most of the solutions use LDDR to move the attribute data with anonymous and Ralph Becket being the two exceptions. Here are the final results:
| Coder | Size |
|---|---|
| Arcadiy Gobuzov | 26 |
| ub880d | 27 |
| Bohumil Novacek | 27 |
| anonymous | 27 |
| Adrian Brown | 27 |
| John Metcalf | 27 |
| Ralph Becket | 30 |
| Jim Bagley | 31 |
| Paul Rhodes | 31 |
Winning Entry
Here's Arcadiy's winning entry in 26 bytes:
xor a ; if comment then 25, but exit if a==56 on start
loop:
ld hl,#5ADF ;
cp (hl) ;
ld bc,#02E0 ; 23 lines of attributes
ld de,#5AFF ;
lddr ; move down attributes
ld c,e ; e = #1F
add hl,bc ;
lddr ; roll upper line of attributes to right
halt
ret z
ld a,(de) ; de = first address of attibutes
cp #3F ;
adc a,c ; add 0 or 1 (carry)
ld (de),a ; now a in range [38..3f]
jr loop
Here's my own solution in 27 bytes. Unfortunately I missed the final CP (HL) to squeeze out the last byte:
fadetowhite:
ld de,23295 ; 90 255
ld a,(de)
cp 63
ret z
ld hl,23263 ; 90 223
ld bc,736 ; 2 224
halt
lddr
ld c,e
add hl,bc
lddr
ld a,(de)
cp 63
adc a,c
ld (de),a
jr fadetowhite
Here's an alternative — a fade-to-black wipe (from white ink, black paper, no bright, no flash) in 25 bytes:
fadetoblack:
ld de,23295 ; 90 255
ld a,(de)
or a
ret z
ld hl,23263 ; 90 223
ld bc,736 ; 2 224
halt
lddr
ld c,e
add hl,bc
lddr
ld a,(de)
add a,l
sbc a,l
ld (de),a
jr fadetoblack
Monday, 30 March 2015
Z80 Size Programming Challenge #3
Recently I issued the third Z80 programming challenge for the ZX Spectrum:
The deadline is Monday 30th March, midday (GMT).
Target: under 125 bytes.
- The X and Y coordinates are in pixels with 0,0 at the top left.
- The sprite needs to be clipped if it goes over the screen edge.
- Sprite data can be formatted however you like within 64 bytes.
- Programs must return. The
RETinstruction is included in the size. - So everyone has a fair chance comment with the code size not code.
- There are no prizes, just the chance to show off your coding skills.
Solutions can be emailed to digital.wilderness@googlemail.com or posted here after the deadline.
Final Results
Congratulations to everyone who rose to the challenge, this was a tough one. Adrian claimed an impressive victory with a neat piece of self-modifying code. Here are the final results:
| Coder | Size |
|---|---|
| Adrian Brown | 68 |
| John Metcalf | 88 |
| Ralph Becket | 97 |
| Arcadiy Gobuzov | 99 |
Winning Entry
Adrian Brown submitted an ingenious solution in only 68 byte. The code displays a sprite pixel by pixel in approx 18ms. The instruction at DS_SetResOp is modified to set, reset or leave the appropriate bit.
DrawSprite:
; At most we want to draw 16 lines (lets store
; the 4 onto c as well as its saves a byte)
ld bc, 01004h
DS_YLoop:
; Gotta be able to stop doing all this push/pop
; with exx at some point - but hey ho
push bc
push de
; Splitting is actually helpful as it gives us
; the byte increase on clipping :D
DS_XLoop1:
; Lets get that data byte
ld b, 4
DS_XLoop2:
; Bit cheaty, roll the actual data, it will end
; up back as it started so thats fine
ld a, (hl)
rlca
rlca
ld (hl), a
; Store the data pointer
push hl
; See if we want to draw or not, bit sneaky
; because of data layout
or %10011111
ld l,a
; Now calculate the screen address, start it
; here so carry is clear
ld a,e
rra
; Lets use the check to set the C flag
cp 96
jr nc, DS_SkipPixel
rra
or a
rra
push af
xor e
and %11111000
xor e
ld h,a
; Now work out the opcode for set/res bit (we need
; 01 for bit, 10 for res and 11 for set - so data
; needs to be 10 for bit, 01 for res and 00 for set)
ld a,d
and %00000111
rlca
rlca
; Thats nice, this will do the cpl for us on the
; bit number ;)
xor l
rla
ld (DS_SetResOp + 1),a
pop af
xor d
and %00000111
xor d
; Move across - check for clipping, do it here so
; we can use a as a value > 192
inc d
jr nz, DS_NoClipX
; Stick Y off the bottom so the rest of the line is clipped
; we can use a at this point as its got to be > 192
ld e, a
DS_NoClipX:
rrca
rrca
rrca
ld l,a
; Go set/res the bit
DS_SetResOp:
set 0, (hl)
DS_SkipPixel:
; Store the data pointer
pop hl
; Go do the byte of data
djnz DS_XLoop2
; Now we need to move to the next bytes
inc hl
dec c
jr nz, DS_XLoop1
pop de
pop bc
; Just increase down
inc e
djnz DS_YLoop
ret
;***********************************************************
; Sprite Data twiddled a bit, Mask/Data/Mask/Data
; Mask = 0 we want the screen, set data to 1 means we convert
; the set/res into a bit which is fine, All rolled right
; three bit to get the pixel data i want in bits 3+4
;***********************************************************
SpriteData:
db %10101010, %01001011, %10110100, %10101010
db %10101010, %11110101, %01011111, %10101010
db %11001010, %01011111, %11110101, %10110010
db %01101011, %01010101, %01010101, %10111100
db %11001101, %11010101, %01010101, %00110111
db %11001101, %11110111, %01010101, %00110111
db %01010111, %11010101, %01110101, %11010101
db %01010111, %01010101, %01010101, %11011101
db %01010111, %01010101, %01110101, %11010101
db %01010111, %01010101, %11010101, %11011101
db %11001101, %01010101, %01110111, %00110111
db %11001101, %11010101, %11011101, %00110111
db %01101011, %01110101, %01010111, %10111100
db %11001010, %01011111, %11110101, %10110010
db %10101010, %11110101, %01011111, %10101010
db %10101010, %01001011, %10110100, %10101010
Here my own solution in 88 bytes. This displays the sprite row by row and is slightly faster, taking approx 5ms.
; called with hl = address of sprite, de = position on screen
putsprite:
ld c,16
nextline:
ld a,d
and 7
inc a
ld b,a
ld a,e
rra
cp 96
ret nc
rra
or a
rra
push de
push hl
ld l,a
xor e
and 248
xor e
ld h,a
ld a,l
xor d
and 7
xor d
rrca
rrca
rrca
ld l,a
ld e,255
spd:
ex (sp),hl
ld a,(hl)
inc hl
ld d,(hl)
inc hl
ex (sp),hl
push bc
rrc e
jr noshift
shiftspr:
rra
rr d
rr e
noshift:
djnz shiftspr
push hl
ld b,3
mask:
bit 0,e
jr z,bm1
and (hl)
db 254 ; jr bm2
bm1:
xor (hl)
bm2:
ld (hl),a
inc l
ld a,l
and 31
ld a,d
ld d,e
jr z,clip
djnz mask
clip:
bit 0,e
ld e,0
pop hl
pop bc
jr nz,spd
pop hl
pop de
inc e
dec c
jr nz,nextline
ret
sprite:
db %11111100, %00111111, %00000000, %00000000
db %11110000, %00001111, %00000011, %11000000
db %11100000, %00000111, %00001100, %00110000
db %11000000, %00000011, %00010000, %00001000
db %10000000, %00000001, %00100010, %00000100
db %10000000, %00000001, %00100111, %00000100
db %00000000, %00000000, %01000010, %00010010
db %00000000, %00000000, %01000000, %00001010
db %00000000, %00000000, %01000000, %00010010
db %00000000, %00000000, %01000000, %00101010
db %10000000, %00000001, %00100000, %01010100
db %10000000, %00000001, %00100010, %10100100
db %11000000, %00000011, %00010001, %01001000
db %11100000, %00000111, %00001100, %00110000
db %11110000, %00001111, %00000011, %11000000
db %11111100, %00111111, %00000000, %00000000