;************************************************************************* ; GPL3+ ; Copyright 2023 by Sean Conner. ; Draws a maze on a Color Computer. ; ;NOTE: This program has a bug for instructional purposes. See ; 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