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 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!