;*************************************************************************
; GPL3+
; Copyright 2023 by Sean Conner.
; Draws a maze on a Color Computer.
;
;NOTE: This program has a bug for instructional purposes. See
; https://boston.conman.org/2023/11/27.1 for more information.
;*************************************************************************
include "Coco-DP.i"
include "Coco-video.i"
VIDEO equ $0E00
NORTH equ 8
EAST equ 4
WEST equ 2
SOUTH equ 1
EXPLORE equ 2
BACKTRACK equ 3
BG equ 0
xpos equ U76 ; these are unused locations
ypos equ U77 ; in the direct page of the Coco
xstart equ UF4
ystart equ UF5
lfsr equ UF6
color equ UF7
rnd4.cache equ UF8
rnd4.cnt equ UF9
;*************************************************************************
org $4000
start lda $FF22 ; set G1C mode-64x64 4-colors
anda #$07
ora #G1C.PIA
sta $FF22
sta $FFC4 + (G1C.MODE & 4 <> 0)
sta $FFC2 + (G1C.MODE & 2 <> 0)
sta $FFC0 + (G1C.MODE & 1 <> 0)
ldx #$FFD2 ; point to frame buffer address bits
lda ECB.grpram ; get MSB of frame buffer
.mapframebuf clrb ; isolate next bit of address
lsla
rolb
sta b,x ; inform hardware of bit value
leax -2,x ; point to next "bit address"
cmpx #$FFC4 ; 7-bits of address required
bne .mapframebuf
.clear_screen ldx ECB.beggrp ; address of frame buffer
clra
clrb
.cls_loop std ,x++ ; clear frame buffer
cmpx ECB.endgrp ; are we done with the clearing?
bne .cls_loop ; keep going if not.
ldd #32 * 256 + 32 ; starting position
std xpos
std xstart
.reseed lda $112 ; read timer value
beq .reseed ; if zero, read again
sta lfsr ; seed our random number generator
clr rnd4.cnt ; and clear the rnd cache count
;*************************************************************************
explore lda #EXPLORE ; exploring free territory
sta color
.loop bsr boxed_in ; can we move?
beq backtrack ; if not, start backtracking
lbsr rnd4 ; pick a random direction
lslb
leax movetab,pc
jsr b,x ; call drawing function
bra .loop
;*************************************************************************
backtrack lda #BACKTRACK
sta color
.loop ldd xpos ; check to see if we're back
cmpd xstart ; at the starting point,
beq done ; and if so, we're done
ldd xpos ; can we backtrack NORTH?
decb
lbsr getpixel
cmpb #EXPLORE
bne .check_east
lbsr move_north.now ; if so, move NORTH and see if
bra .probe ; we have to keep backtracking
.check_east ldd xpos ; east ...
inca
lbsr getpixel
cmpb #EXPLORE
bne .check_west
lbsr move_east.now
bra .probe
.check_west ldd xpos ; yada yada ...
deca
lbsr getpixel
cmpb #EXPLORE
bne .check_south
lbsr move_west.now
bra .probe
.check_south ldd xpos
incb
lbsr getpixel
cmpb #EXPLORE
bne .probe
lbsr move_south.now
.probe bsr boxed_in ; can we stop backtracking?
bne explore ; if so, go back to exploring
bra .loop ; else backtrack some more
;*************************************************************************
done jsr [$A000]
beq done
cmpa #32
lbeq start.clear_screen
jmp [$FFFE]
;*************************************************************************
; BOXED_IN Are we boxed in?
;Entry: none
;Exit: A - direction flag
;*************************************************************************
boxed_in clr ,-s ; clear direction flags
ldb ypos
beq .check_east
subb #2 ; look up two pixels
lda xpos
lbsr getpixel ; get the color there
tstb ; 0?
bne .check_east ; if not, look towards the east
lda ,s ; set NORTH flag
ora #NORTH
sta ,s
.check_east lda xpos ; now look east
cmpa #62
beq .check_west
adda #2
ldb ypos
lbsr getpixel
tstb
bne .check_west
lda ,s
ora #EAST
sta ,s
.check_west lda xpos ; and so on ...
beq .check_south
suba #2
ldb ypos
bsr getpixel
tstb
bne .check_south
lda ,s
ora #WEST
sta ,s
.check_south ldb ypos
cmpb #62
beq .done
addb #2
lda xpos
bsr getpixel
tstb
bne .done
lda ,s
ora #SOUTH
sta ,s
.done lda ,s+ ; set flags
rts
;*************************************************************************
movetab bra move_north
bra move_east
bra move_west
bra move_south
;*************************************************************************
; MOVE_* Move (draw) along the maze
;Entry: A - dir
;Exit: A - trashed
; B - trashed
; X - trashed
;*************************************************************************
no_movement rts
move_north anda #NORTH
beq no_movement
.now bsr setpixel
dec ypos
bsr setpixel
dec ypos
bra setpixel
move_east anda #EAST
beq no_movement
.now bsr setpixel
inc xpos
bsr setpixel
inc xpos
bra setpixel
move_west anda #WEST
beq no_movement
.now bsr setpixel
dec xpos
bsr setpixel
dec xpos
bra setpixel
move_south anda #SOUTH
beq no_movement
.now bsr setpixel
inc ypos
bsr setpixel
inc ypos
;*************************************************************************
; SETPIXEL Set a pixel
;Uses: xpos
; ypos
;Exit: X - video address
; D - trashed
;*************************************************************************
setpixel ldd xpos
bsr point_addr ; get video address
stb ,-s ; save mask
ldb color ; get color to use
tsta ; any shift?
beq .setit ; if not, skip
.rotate lslb ; shift color bits
deca
bne .rotate
.setit lda ,x ; get screen data
anda ,s ; mask screen data
sta ,s
orb ,s+ ; add in color
stb ,x ; save back to video screen
rts
;*************************************************************************
; GETPIXEL Get the color of a given pixel
;Entry: A - x pos
; B - y pos
;Exit: X - video address
; A - 0
; B - color
;*************************************************************************
getpixel bsr point_addr ; get video address
comb ; reverse mask (since we're reading
stb ,-s ; the screen, not writing it)
ldb ,x ; get video data
andb ,s+ ; mask off the pixel
.rotate lsrb ; shift color bits
deca
bne .rotate
.done rts ; return color in B
;*************************************************************************
; POINT_ADDR calculate the address of a pixel
;Entry: A - xpos
; B - ypos
;Exit: X - video address
; A - shift value
; B - mask
;*************************************************************************
point_addr.bits fcb %00111111,%11001111,%11110011,%11111100 ; masks
fcb 6,4,2,0 ; bit shift counts
point_addr pshs u,a ; save U and xpos
lda #16 ; # byte per line
mul ; calculate offset to line
addd ECB.beggrp ; add in start of video buffer
tfr d,x
ldb ,s ; get xpos
lsrb ; xpos /= 4
lsrb
abx ; add x offset into video address
lda ,s+ ; get xpos
anda #3 ; xpos %= 4
leau .bits,pc ; point to mask bits table
ldb a,u ; get mask
leau 4,u ; point to shift value table
lda a,u ; get shift value
puls u,pc ; restore U and return
;***********************************************************************
; RND4 Generate a random number 0 .. 3
;Entry: none
;Exit: B - random number
;***********************************************************************
rnd4 dec rnd4.cnt ; any more cached random #s?
bpl .cached ; yes, get next cached number
ldb #3 ; else reset count
stb rnd4.cnt
bsr random ; get random number
stb rnd4.cache ; save in the cache
bra .ret ; and return the first number
.cached ldb rnd4.cache ; get cached value
lsrb ; get next 2-bit random number
lsrb
stb rnd4.cache ; save ermaining bits
.ret andb #3 ; mask off our result
rts
;***********************************************************************
; RANDOM Generate a random number
;Entry: none
;Exit: B - random number (1 - 255)
;***********************************************************************
random ldb lfsr
andb #1
negb
andb #$B4
stb ,-s ; lsb = -(lfsr & 1) & taps
ldb lfsr
lsrb ; lfsr >>= 1
eorb ,s+ ; lfsr ^= lsb
stb lfsr
rts
;*************************************************************************
end start
text/plain; charset=us-ascii
This content has been proxied by September (ba2dc).