Spiral Challenge Revisited

I am a bit annoyed that I haven’t been able to explain how my spiral challenge solution works clearly enough.

To rehash the challenge it is this: Generate the image below, it will be tested in VICE C64 with Inject To RAM. Smallest number of bytes wins.

The desired result for the spiral challenge

The image is a rectangular spiral winding clockwise inwards starting at the upper left corner using inverted @ which has a screen code of $80.

Initial conditions

The code loads in so the Entry Point is located at address $73 which is called every time the kernal prints a character. At this point x = $ff, y = $b1 and the Z flag is clear so a bne at address $73 will be taken.

The submitted code

This is the result that won the challenge, it is not really intended to be read and understood as is but I’ll break it down below.

$46 dex
$47 ldy #$ec
$49 txa
$4a adc #$0e
$4c bpl $50
$4e eor #$ff
$50 adc #8
$52 bmi $52
$54 sta 2
$56 tya
$57 bpl $5b
$59 eor #$ff
$5b cmp 2
$5d bcs $60
$5f txa
$60 lsr
$61 lda #$20
$63 bcc $67
$65 asl
$66 asl
$67 sta $03c5
$6a inc $68
$6c bne $70
$6e inc $69
$70 iny
$71 cpy #$14
$73 bne $49
$75 beq $46

The entry point is not the first address, after loading and printing out a character the kernal jumps to $73.

Source

; code begins at EntryPoint
; x is row #, y is column #
; x is $ff at entry, loops back to entry point every line
org $46
DrawRow:
	dex			; decrement the row # here to make row loop work without extra cpx
	ldy #-20		; y is horizontal position, leftmost = -20, rightmost = +19
DrawChar:			; first iteration y starts with 1, so there are 19 bytes to ignore
	txa
	adc #14			; compensate for initial x value
	bpl Bottom_Half
	eor #$ff		; negate for right side
Bottom_Half:
	adc #8			; largest x=20, so add 8 to y, largest y = 12
Halt:
	bmi Halt		; when row = $78 the adc will set the N flag so loop infinitely when done
	sta 2			; store off the vertical distance from center
	tya
	bpl Right_Side
	eor #$ff
Right_Side:			; a = horizontal distance from center
	cmp 2			; horiz dist > vert dist?
	bcs Horiz		; => on a horizontal slice
	txa			; on a vertical slize
Horiz:
	lsr			; odd or even distance?
	lda #$20		; space on odd distance
	bcc DrawSpace
	asl			; invert @ on even distance
	asl
DrawSpace:
	sta $400-40*1-19	; adjust 1 row up + y start value 
	inc DrawSpace+1		; increment destination address
	bne NotCrossPage
	inc DrawSpace+2
NotCrossPage
	iny
	cpy #20
EntryPoint:
	bne DrawChar		; <- autostarts here with Z clear (address $73)
	beq DrawRow		; loop each row

Theory

The spiral is drawn by sweeping the screen top to bottom, and each row left to right. At the top left corner y = -20 (horizontal position) and x = $ff + 14 = 13 (vertical position). Each column y increments and each row x decrements.

To break down the idea I’ve split up the screen in slices, where the left and right edges towards the center are the “horizontal” slices (pink, light blue), and the top and bottom slices (cyan, purple) are “vertical slices”. There is a section in the center that is always vertical as seen here:

The blue line is considered the center (horizontal and vertical distance are both 0).

Processing begins at the top/left of the screen minus 51 because of the initial values of x and y but once the top left character column is considered -20 (in the y register).

the horizontal distance to the center is (0-20) = 20 = H, and the vertical is 13 ($ff + 14) = V. for this calculation it doesn’t matter if we’re in the upper or lower / left or right distance to the center.

To make up for the screen not being a square I add 8 to the vertical position so V2 = V+8 (there are 40 columns and 25 rows, 40/2 – 25/2 = 8)

From the two distances I just pick the greater value D = H > V2 ? H : V2; and now I can simply check if D is even or odd which is just an lsr / bcc which lets me pick either inverted @ for even numbers (0 is even!) or space for odd numbers!

This is literally all it does. And there is a check for V2 < 0 to stop processing (bmi Halt)

To get the spiral to wind the correct direction (and also not just be all “concentric” rectangles) I just fiddled a bit with constants and branch conditions, I didn’t actually work out the finer details by hand!

Published by Space Moguls

I make Commodore 64 games and sometimes demos.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: