Monday, 15 December 2014

Z80 Size Programming Challenge #2

Last week I issued the second Z80 programming challenge:

Something slightly more complex this time. Write the shortest code to mirror the entire Sinclair Spectrum screen (256×192 pixels) left to right including the colours / attributes. The deadline is Monday 15th, midday (GMT).

Target: under 50 bytes.

  1. Your program shouldn't rely on the initial contents of registers.
  2. No RAM/ROM other than the screen memory should be written to.
  3. Programs must return. The RET instruction is included in the size.
  4. So everyone has a fair chance comment with the code size not code.
  5. There are no prizes, just the chance to show off your coding skills.

Final Results

We stepped up the difficultly for the second challenge so congratulations to everyone who entered. Introspec ZX and Tim Webber discovered the shortest solutions. Here are the final results:

CoderSize
Introspec Zx34
Tim Webber34
John Metcalf34
Paul Rhodes35
Simon Brattel35
Jim Bagley36
Steve Wetherill38
John Young49
Chris Walsh49
Dariusz EM50

Winning Entries

Introspec submitted the first 34 byte solution using a couple of neat tricks. Note the use of CP L to check which side of the screen it's working on and the byte saved by setting B to #58:

                ld hl,16384+6912

screenflip:     ld d,h
                ld a,l
                xor #1F
                ld e,a
                cp l
                jr nc,noflip

                ld a,(de)
                ld c,(hl)
                ld (hl),a
                ld a,c
                ld (de),a

noflip:         ld b,#58
                ld a,h
                cp b
                jr nc,skipattr

byteflip:       rlc (hl)
                rra
                djnz byteflip
                ld (hl),a

skipattr:       dec hl
                bit 6,h
                jr nz,screenflip
                ret

Tim Webber's solution saves a series of addresses on the stack to be used later:

start:          ld hl,23296
loop1:          dec hl
                bit 6, h
                ret z
                ld a, 87
                cp h
                jr c, noinv
                ld b,8
doinv:          rl (hl)
                rra
                djnz doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Although I didn't enter I also found a couple of 34 byte solutions. The first mirrors two bytes in the inner loop:

                ld hl,16384
mirror:         ld d,h
                ld a,l
                xor 31
                ld e,a
                ld a,h
                cp 91
                ret z
                cp 88
                ld a,(de)
                ld c,a
                jr nc,attrib
                ld b,8
                rrca
mirrorbits:     rl (hl)
                rra
                djnz mirrorbits
                db 1 ; skip the next two instructions
attrib:         ld a,(hl)
                ld (hl),c
                ld (de),a
                inc l
                inc hl
                jr mirror

My second has two separate loops. The first loop mirrors bytes, the second mirrors the screen:

                ld hl,22527
mir:            ld a,128
mirrorbits:     rl (hl)
                rra
                jr nc,mirrorbits
                ld (hl),a
                dec hl
                bit 6,h
                jr nz,mir
mirror:         inc hl
                ld d,h
                ld a,l
                xor 31
                ld e,a
                ld a,h
                cp 91
                ret z
                ld a,(de)
                ld c,a
                ld a,(hl)
                ld (hl),c
                ld (de),a
                inc l
                jr mirror

Is 34 Bytes Optimal?

Definitely not! After the deadline a solution was discovered that combines code from Tim Webber and Introspec's entries to mirror the screen in 33 bytes:

start:          ld hl,23296 ; Tim Webber/Introspec
loop1:          dec hl
                bit 6, h
                ret z
                ld a, h
                ld b,88
                cp b
                jr nc, noinv
doinv:          rlc (hl)
                rra
                djnz doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Another 33 byte solution combines the code from Tim Webber and Simon Brattel's entries:

start:          ld hl,23296 ; Tim Webber/Simon Brattel
loop1:          dec hl
                ld a,h
                cp 88
                jr nc, noinv
                and 64
                ret z
                add a,a
doinv:          rlc (hl)
                rra
                jr nc,doinv
                ld (hl), a
noinv:          push hl
                bit 4,l
                jr nz, loop1
                pop de
                pop hl
                ld a,(de)
                ld c, (hl)
                ld (hl), a
                ex de, hl
                ld (hl), c
                jr loop1

Entries will be available shortly on John Young's website. Thanks to everyone who entered for making the contest a success :-)

No comments:

Post a Comment