SMOLNET PORTAL home about changes
;*************************************************************************
;	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
Response: 20 (Success), text/plain
Original URLgemini://gemini.conman.org/boston/2023/11/27/maze-bug.asm
Status Code20 (Success)
Content-Typetext/plain; charset=us-ascii