; ; 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. ; This version has been modified to work with as1600. ; ORG $5000 ROMW 10 ; rom is 10-bits wide ; EXEC routine equates PRTR5 EQU $187B ; ASCIIZ string @R5 to screen @R4 PRTR1 EQU $1867 ; ASCIIZ string @R1 to screen @R4 RAND EQU $167D ; Random number. FILL EQU $1741 ; Fill R0 locations @R4 w/ value in R1 ; System-wide equates VIDEN EQU $0020 ; Video enable handshake ; EXEC-ROM HEADER ROMHDR: WORD MODATA WORD RTAB WORD START WORD BKGDATA WORD CARDTAB WORD TITLE BYTE $9F ; run code after title, clicks on BYTE $00 ; -> to STIC $32 BYTE $00 ; 0 = color stack, 1 = f/b mode BYTE 9, 9, 9, 9 ; color stack elements 1 - 4 BYTE $09 ; border color ; Moving Object offsets = last 16 pictures in GRAM ; [What is this for? Do I need it for this program? --JZ] DECLE $180, $190, $1A0, $1B0, $1C0, $1D0, $1E0, $1F0 CARDTAB DECLE $1, $0 RTAB: DECLE $0, $0 ; TITLE ; ; Copyright date, title, and code to patch title. TITLE: PROC BYTE 99, 'Maze Demo', 0 BEGIN ; 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. CLRR R3 ; Black MVII #$23D, R4 ; First 'Mattel' in top-left CALL PRTR5 ; Write string (ptr in R5) STRING '=JRMZ=' ; Guess who? :-) BYTE 0 MOVR PC, R1 SUBI #8, R1 ; Point to '=JRMZ=' above (save 4 words) CLRR R3 ; Black MVII #$2D5, R4 ; Second 'Mattel' in lower-right CALL PRTR1 ; 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. RETURN ; Return to caller ENDP ; HANDTAB ; Vector table for handling the controllers. HANDTAB WORD 0 ; Disc handler WORD 0 ; Keypad handler WORD 0 ; Upper action btn WORD 0 ; Lower Right act btn WORD 0 ; Lower Left act btn ; Moving Objects bitmaps MODATA: DCW $0 ; Background Cards bitmaps BKGDATA: DCW $0 ;=========================================================================== ; START: Code which runs after title screen. START: PROC BEGIN ; Save return address on stack ; "Local" variables @@xc EQU $300 ; X card position @@xp EQU $301 ; X pixel position @@yc EQU $302 ; Y card position @@yp EQU $303 ; Y pixel position @@dir EQU $304 ; Direction @@tdir EQU $305 ; Directions we've tried at this intersection @@move EQU $305 ; Updated pixel coordinate @@axis EQU $306 ; Pointer to axis that was updated DIS ; This demo has no interaction and no need for interrupts. CLRR 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 MVII #$1492, R1 ; CALL FILL ; Fill screen w/ red colored squares MVII #$26D, R2 ; Start in middle MVII #19, R3 MVO R3, @@xp SLR R3, 1 MVO R3, @@xc MVII #11, R3 MVO R3, @@yp SLR R3, 1 MVO R3, @@yc MVII #2, R0 CALL RAND MVO R0, @@dir @@mazelp: ; Clear the pixel at the current position. MVI@ R2, R0 ANDI #$D1FF, R0 XORI #$0200, R0 MVO@ R0, R2 ; delay loop MVII #$3FF, R3 @@dly: MVO R0, VIDEN DECR R3 BNEQ @@dly ; Pick a direction to exit by. CLRR R3 ; Straightness factor: We can control how twisty the maze is ; by controlling how often we just try to go straight. MVII #4, R0 CALL RAND CMPI #3, R0 ; Try straight-ahead 3/16th of the time BGT @@pickdir1 MVI @@dir, R0 B @@trystraight @@pickdir: CMPI #$F, R3 ; If we've tried all four dirs, we're trapped BEQ @@trapped MVO R0, VIDEN ; vid enable @@pickdir1: MVII #2, R0 CALL RAND @@trystraight: ANDI #3, R0 ; bit 1 is 'x/y', bit 0 is '-1 / +1' MVO R0, @@dir ; See if we've already tried this direction. MVII #1, R1 ANDI #2, R0 BEQ @@pick1 SLL R1, 2 @@pick1: XOR @@dir, R0 BEQ @@pick0 ADDR R1, R1 @@pick0: MVO R1, @@tdir ; 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 @@tdir, R3 ; Update X and Y according to the direction we're trying. MVI @@dir, 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 @@dir, 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, @@move ; Store candidate coordinate update MVO R4, @@axis ; ... 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 @@dir, R0 ; Our random number MVII #1, R1 ; Default to +/- 1 update on pointer. MVII #$D83F, R4 ; horiz move: mask pixels 2, 3 ANDI #2, R0 BEQ @@xmove @@ymove: MVII #20, R1 ; +/- 20 update for vertical move. MVII #$F1C3, R4 ; vert move: mask pixels 1, 3 @@xmove: XOR @@dir, 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 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 @@axis, R5 MVI @@move, R0 MVO@ R0, R5 ; Record the move in the new square (for backtrack purposes) MVI @@dir, 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 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. 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, @@dir ; Decode the direction bits in R1/@@dir, 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 @@dir, 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 @@dir, 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 @@dir, 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 CLRR R3 ; Sit around awhile. @@here: MVO R0, VIDEN MVO R0, VIDEN MVO R0, VIDEN MVO R0, VIDEN DECR R3 BNEQ @@here MVO R3, $2C ; Make border black again. MVO R3, $28 B @@newmaze ; Make a new maze. ENDP