; ; MAZE DEMO: Draws mazes using recursive-descent maze generation algorithm ; Copyright 1999, Joseph Zbiciak ; ; ROM header and function stubs adapted from SHELL.SRC by Carl Mueller, Jr. ; org $5000 ROMWIDTH equ 10 ; rom is 10-bits wide ; EXEC-ROM HEADER ROMHDR: DCW lo|MODATA, hi|MODATA ; ^ moving object grafx DCW lo|RTAB, hi|RTAB ; ^ routine tab DCW lo|START, hi|START ; ^ start program address DCW lo|BKGDATA, hi|BKGDATA ; ^ background graphics DCW lo|CARDTAB, hi|CARDTAB ; ^ card tab DCW lo|TITLE, hi|TITLE ; ^ date / title string DCW $9F ; run code after title, clicks on DCW $00 ; -> to STIC $32 DCW $00 ; 0 = color stack, 1 = f/b mode DCW 9, 9, 9, 9 ; color stack elements 1 - 4 DCW $09 ; border color ; Moving Object offsets = last 16 pictures in GRAM ; [What is this for? Do I need it for this program? --JZ] DCW $180, $190, $1A0, $1B0, $1C0, $1D0, $1E0, $1F0 CARDTAB: DCW $1, $0 RTAB: DCW $0, $0 ; TITLE ; ; Copyright date, title, and code to patch title. PROC TITLE DCW 99, 'Maze Demo', $0 ; 1999 ; Code to patch title screen MVO@ R5, R6 ; Cyan screen MVII $09, R0 ; Color 9 is Cyan (pastels.) MVO R0, $28 ; Color stack 0 = Cyan MVO R0, $29 ; Color stack 1 = Cyan MVO R0, $2A ; Color stack 2 = Cyan MVO R0, $2B ; Color stack 3 = Cyan MVO R0, $2C ; Border color = Cyan ; Patch the title string to say '=JRMZ=' instead of Mattel. XORR R3, R3 ; Black MVII $23D, R4 ; First 'Mattel' in top-left JSR R5, $187B ; Write string (ptr in R5) DCW '=JRMZ=', 0 ; Guess who? :-) MOVR R7, R1 SUBI 8, R1 ; Point to '=JRMZ=' above (save 4 words) XORR R3, R3 ; Black MVII $2D5, R4 ; Second 'Mattel' in lower-right JSR R5, $1867 ; Write string (ptr in R1) ; Make all the rest of the text black to match MVII $243, R3 ; Start after first JRMZ MVII 7, R0 ; Mask = 0xFFF8. That's the 1s complement... COMR R0 ; ...of 7. (Saves an SDBD.) MVII 146, R2 ; We only need to touch 146 words. @@titlelp: MVI@ R3, R1 ; Read a word from the display ANDR R0, R1 ; Mask the foreground color MVO@ R1, R3 ; Write the word back INCR R3 ; Point to next word DECR R2 ; Decrement our loop count BNEQ @@titlelp ; Iterate. ; Done. MVI@ R6, R7 ; Return to caller ENDP ; HANDTAB ; Vector table for handling the controllers. HANDTAB: DCW lo|HTDisc, hi|HTDisc ; Disc handler DCW lo|HTKeypad, hi|HTKeypad ; Keypad handler DCW lo|HTActU, hi|HTActU ; Upper action btn DCW lo|HTActR, hi|HTActR ; Lower Right act btn DCW lo|HTActL, hi|HTActL ; Lower Left act btn ; HTDisc ; Handler for disc-press events PROC HTDisc JR R5 ENDP ; HTKeypad ; Handler for Keypad events PROC HTKeypad JR R5 ENDP ; Upper buttons handler PROC HTActU JR R5 ENDP ; Lower Right button handler PROC HTActR JR R5 ENDP ; Lower Left button handler PROC HTActL JR R5 ENDP ; Moving Objects bitmaps MODATA: DCW $0 ; Background Cards bitmaps BKGDATA: DCW $0 ; RAND: Generate a random number from 1 .. 1 << R0 into R0 RAND EQU $167D ;=========================================================================== ; START: Code which runs after title screen. PROC START MVO@ R5, R6 ; Save return address on stack DIS ; This demo has no interaction and no need for interrupts. XORR R0, R0 MVO R0, $2C ; Black border. MVO R0, $28 ; Shift display over 3 pixels, down 4 pixels. MVII 3, R0 MVO R0, $30 ; Horizontal delay = 3 INCR R0 MVO R0, $31 ; Vertical delay = 4 ; Draw maze as a set of black passages. Seed pixel is at (1,1) ; Each 2x2 block of colored squares will end up being one of ; the following with this algorithm: ; ; ## #. ## #. ; #. #. .. .. @@newmaze: MVII $00F0, R0 MVII $0200, R4 SDBD MVII $1492, R1 ; JSR R5, $1741 ; Fill screen w/ red colored squares MVII $26D, R2 ; Start in middle MVII 19, R3 MVO R3, $301 SLR R3, 1 MVO R3, $300 MVII 11, R3 MVO R3, $303 SLR R3, 1 MVO R3, $302 MVII 2, R0 JSR R5, RAND MVO R0, $304 @@mazelp: ; Clear the pixel at the current position. MVI@ R2, R0 SDBD ANDI $D1FF, R0 SDBD XORI $0200, R0 MVO@ R0, R2 ; delay loop MVII $3FF, R3 @@dly: MVO R0, $20 DECR R3 BNEQ @@dly ; Pick a direction to exit by. XORR R3, R3 ; Straightness factor: We can control how twisty the maze is ; by controlling how often we just try to go straight. MVII 4, R0 JSR R5, RAND CMPI 3, R0 ; Try straight-ahead 3/16th of the time BGT @@pickdir1 MVI $304, R0 B @@trystraight @@pickdir: CMPI $F, R3 ; If we've tried all four dirs, we're trapped BEQ @@trapped MVO R0, $20 ; vid enable @@pickdir1: MVII 2, R0 JSR R5, RAND @@trystraight: ANDI 3, R0 ; bit 1 is 'x/y', bit 0 is '-1 / +1' MVO R0, $304 ; See if we've already tried this direction. MVII 1, R1 ANDI 2, R0 BEQ @@pick1 SLL R1, 2 @@pick1: XOR $304, R0 BEQ @@pick0 ADDR R1, R1 @@pick0: MVO R1, $305 ; Ok, R1 is now 1, 2, 4 or 8 depending on which direction we're ; trying. See if that bit is already set in R3. ANDR R3, R1 BNEQ @@pickdir1 ; Yes it was, pick another. ; No it wasn't. Add it to the set of directions we've tried. XOR $305, R3 ; Update X and Y according to the direction we're trying. MVI $304, R0 ; Select X or Y based on bit 1 MVII $300, R4 ANDI 2, R0 ; Get bit 2. ADDR R0, R4 ; $300 or $302 ==> X or Y ; Add or subtract 1 based on bit 0. XOR $304, R0 ; Get bit 0 ADDR R0, R0 ; Multiply it by 2. ADD@ R4, R0 ; Add it to the value DECR R0 ; Subtract 1. val' = val + 2 * bit0 - 1. ; Are we within the screen borders? BMI @@pickdir ; Yes: Off top/left CMP@ R4, R0 ; Check right/bottom BGE @@pickdir ; Yes: Off right/bottom SUBI 2, R4 ; Reset R4 MVO R0, $305 ; Store candidate coordinate update MVO R4, $306 ; ... and which coordinate to update ; Ok, update our cardtab address and test the pixel there. ; Assume a horizontal move, and see if it's really a vertical move. MVI $304, R0 ; Our random number MVII 1, R1 ; Default to +/- 1 update on pointer. SDBD MVII $D83F, R4 ; horiz move: mask pixels 2, 3 ANDI 2, R0 BEQ @@xmove @@ymove: MVII 20, R1 ; +/- 20 update for vertical move. SDBD MVII $F1C3, R4 ; vert move: mask pixels 1, 3 @@xmove: XOR $304, R0 ; Now look at bit 0 to see if negative dir. BNEQ @@pmove @@nmove: NEGR R1 ; Negate movement if bit 0 clear. @@pmove: ADDR R2, R1 ; R1 has candidate CARDTAB address. MVI@ R1, R0 ; Load word from candidate destination SDBD ANDI $2400, R0 ; Look at lower-right pixel. ; (Hack: Ignore bit 0 so we can use the ; blue pixel as a "status" pixel.) BEQ @@pickdir ; Zero? This intersection's already taken. ; Non zero? Ok, we can advance into this square (whoo hoo!) @@domove: ; Move the candidate x/y position into our actual x/y position MVI $306, R5 MVI $305, R0 MVO@ R0, R5 ; Record the move in the new square (for backtrack purposes) MVI $304, R0 MVI@ R1, R3 SLL R3, 2 RRC R0, 2 ; Move two lsbs into to msbs RRC R3, 2 MVO@ R3, R1 ; Store in bits 14, 15 of word. ; Clear blue 'location' pixel SDBD MVII $FDFF, R0 AND@ R2, R0 MVO@ R0, R2 ; Clear pixels (drawing the maze) ; If we're moving in a negative direction, mask the current ; word. If we're moving in a positive direction, mask the ; new word. SLLC R3, 2 BNOV @@domask ; Mask old position if negative dir move. MOVR R1, R2 ; Make "new position" current position. @@domask: AND@ R2, R4 ; Mask the pixel. MVO@ R4, R2 ; Display it. MOVR R1, R2 ; Make new position current position for sure. ; Continue recursing down the maze. B @@mazelp @@trapped: ; Recurse back a level MVI@ R2, R0 ; Get current pixel. MOVR R0, R1 ; Copy it. SDBD ANDI $11FF, R0 ; Mask away our blue "location pixel" MVO@ R0, R2 ; Display it. RLC R1, 2 ; Grab the top two bits RLC R1, 2 ; Put them in the bottom two bits. ANDI 3, R1 ; Throw away the rest of the bits. MVO R1, $304 ; Decode the direction bits in R1/$304, and update coordinates. ; This is similar to how "pickdir" does it, except that we ; interpret the positive/negative bit the opposite way since ; we're backtracking now. MVII $300, R3 ANDI 2, R1 ; Bit 1 selects between X or Y ADDR R1, R3 ; $300 is X, $302 is Y MVI@ R3, R0 ; Get the coordinate that we need to update. XOR $304, R1 ; Get bit 0. ADDR R1, R1 ; Multiply bit 0 by 2. SUBR R1, R0 ; Subtract it from the coordinate INCR R0 ; Add 1. val' = val - 2*bit0 + 1. MVO@ R0, R3 ; Store updated coordinate. ; Decode direction bits and update CARDTAB pointer. MVI $304, R0 MVII 1, R1 ; Assume horiz move by default. +/- 1 update. ANDI 2, R0 ; Vertical move if bit 1 set. BEQ @@xtmove ; Yes: Horizontal move. MVII 20, R1 ; Vertical move. +/- 20 update. @@xtmove: XOR $304, R0 ; Get bit 0. BEQ @@ptmove ; If bit 0's set, negate the update amount. ; This is opposite of what pickdir does. NEGR R1 @@ptmove: ADDR R1, R2 ; Now update the pointer. ; Check to see if we're at the starting location. This is the ; termination condition for our recursion. CMPI $26D, R2 BNEQ @@mazelp ; Not at start? Keep recursing! ; We're back at the start. The maze is done. MVII $9, R0 MVO R0, $28 ; Make border cyan to signify completion. MVO R0, $2C XORR R3, R3 ; Sit around awhile. @@here: MVO R0, $20 MVO R0, $20 MVO R0, $20 MVO R0, $20 DECR R3 BNEQ @@here MVO R3, $2C ; Make border black again. MVO R3, $28 B @@newmaze ; Make a new maze.