|
3DMaze
by Ricardo Fernandes Lopes
|
3D Maze download as a Tap file and instruction can be found here ( 3D MAZE version 1.0 for Jupiter ACE ) ( Copyright (c) 2007 by Ricardo F. Lopes ) ( under the GNU General Public License version 2 ) ( Start the game with: ) ( 3DMAZE ) ( Game control keys: ) ( I = Step forward ) ( J = Turn left ) ( L = Turn right ) ( K = Step backward ) ( H = 2D map look-up ) ( Q = Quit game ) ( ============= ) ( MISC. WORDS ) ( ============= ) 16 BASE C! ( Hex ) CREATE CMOVE ( src dst n -- : Move n bytes from src to dst ) DF C, ( RST 18 ; get 'n' ) 42 C, ( LD B,D ; BC = 'n' ) 4B C, ( LD C,E ) DF C, ( RST 18 ; get 'dst' ) D5 C, ( PUSH DE ; save it ) DF C, ( RST 18 ; get 'src' ) E1 C, ( POP HL ; HL = 'dst' ) EB C, ( EX DE,HL ; DE = 'dst' , HL='src' ) ED C, B0 C, ( LDIR ; move 'n' bytes ) FD C, E9 C, ( JP (IY) ; end ) CMOVE DUP 2- ! ( Make CMOVE an executable word ) CREATE TOUPPER ( c -- C : convert a character to uppercase ) DF C, ( RST 18h ; E = char to convert ) 7B C, ( LD A,E ; A = char to convert ) CD C, 07 C, 08 C, ( CALL 0807h ; to-upper ROM routine ) 5F C, ( LD E,A ; E = converted char ) D7 C, ( RST 10h ; Push char to Data Stack ) FD C, E9 C, ( JP [IY] ; end ) TOUPPER DUP 2- ! ( Make TOUPPER an executable word ) DECIMAL : 2DUP ( x1 x2 -- x1 x2 x1 x2 ) OVER OVER ; : 1+! ( adr -- ) DUP @ 1+ SWAP ! ; : KEY ( -- c : wait for a keypress ) BEGIN INKEY 0= UNTIL BEGIN INKEY ?DUP UNTIL ; ( Random Number Generator ) 0 VARIABLE RND : RANDOMIZE 15403 @ RND ! ; : RANDOM RND @ 31421 * 6927 + DUP RND ! ; : RAND RANDOM U* SWAP DROP ; ( n1 -- n2 : n2 = random from 0 to n1-1) ( ==================== ) ( GRAPHIC CHARACTERS ) ( ==================== ) CREATE GRAPH 272 ALLOT ( Graphic characters ) ( Load graphic chars from files created with FontEd ) GRAPH 256 BLOAD GRAPH ( ASCII 0 to 31 = graph ) GRAPH 256 + 8 BLOAD SLASH ( ASCII 47 = slash / ) GRAPH 264 + 8 BLOAD BACKSLASH ( ASCII 92 = backslash \ ) : GR ( Set graphic characters to char generator mem ) GRAPH 11264 256 CMOVE ( ASCII 0-31 ) GRAPH 256 + 11640 8 CMOVE ( ASCII 47, slash ) GRAPH 264 + 12000 8 CMOVE ( ASCII 92, backslash ) ; ( ====== ) ( MAZE ) ( ====== ) ( Maximum Maze dimensions + margins ) 32 CONSTANT MAXX ( must be 32, the screen width ) 22 CONSTANT MAXY ( Current maze dimensions ) 10 VARIABLE XSIZE 7 VARIABLE YSIZE ( Add to maze size ) : X+ ( n -- ) XSIZE @ + 3 MAX 30 MIN XSIZE ! ; : Y+ ( n -- ) YSIZE @ + 3 MAX 20 MIN YSIZE ! ; CREATE MAZE MAXX MAXY * ALLOT ( Maze mem ) ( Convert room xy coordinates to maze mem address ) : XY>ROOM ( x y -- room ) MAXX * + MAZE + ; ( Room walls as bit masks ) 1 CONSTANT WEST ( 0001 West wall ) 2 CONSTANT SOUTH ( 0010 South wall ) 4 CONSTANT EAST ( 0100 East wall ) 8 CONSTANT NORTH ( 1000 North wall ) 15 CONSTANT ALL ( 1111 All walls ) 2 CONSTANT RIGHT 4 CONSTANT BACK 8 CONSTANT LEFT : TURN ( facing1 dir -- facing2 : Change Direction ) OVER 16 * ROT OR ( NESW -> NESWNESW ) SWAP / ( Turn ) 15 AND ( NESWNESW -> NESW ) ; ( ============= ) ( DRAW 2D MAP ) ( ============= ) : _MAP ( Draw 2D maze map ) YSIZE @ 2+ 0 ( line count including margins ) DO 0 I XY>ROOM ( source = maze ) 9216 I 32 * + ( destination = screen ) XSIZE @ 2+ ( column count, including margins ) CMOVE ( copy maze to screen ) LOOP ; : _ROOM ( room -- : Draw one maze room in 2D ) DUP C@ SWAP ( Stack: walls room ) MAZE - 9216 + ( Stack: walls screen ) C! ( Set screen char ) ; : _POS ( room -- : Show player position in 2D map ) DUP C@ 16 OR SWAP MAZE - 9216 + C! ; ( ================= ) ( MAZE GENERATION ) ( ================= ) : INIT ( Initialize maze before generate) YSIZE @ 2+ 0 DO XSIZE @ 2+ 0 DO ALL I J XY>ROOM C! ( Close rooms ) LOOP 0 I XY>ROOM DUP C@ EAST AND SWAP C! ( West border ) XSIZE @ 1+ I XY>ROOM DUP C@ WEST AND SWAP C! ( East border ) LOOP XSIZE @ 2+ 0 DO I 0 XY>ROOM DUP C@ SOUTH AND SWAP C! ( North border ) I YSIZE @ 1+ XY>ROOM DUP C@ NORTH AND SWAP C! ( South border ) LOOP ; ( Walking to next room ) CREATE WLK ( const table for WALK word ) 0 , -1 , MAXX , 0 , 1 , 0 , 0 , 0 , MAXX NEGATE , : WALK ( room1 facing -- room2 facing : Walk to facing room ) DUP 2 * WLK + @ ( displacement ) ROT + SWAP ; : REMOVE ( room facing -- room facing : Remove facing wall ) 2DUP -1 XOR ( facing bit mask ) OVER C@ AND ( clear facing bit ) SWAP C! ( store it back ) OVER _ROOM ( update screen ) ; : CUT ( room1 facing -- room2 : Open walls to next room ) REMOVE ( remove facing wall ) WALK ( go to next room ) BACK TURN ( look back ) REMOVE ( remove back wall ) DROP ( discard facing ) ; CREATE FACES 4 ALLOT ( direction buffer for neighbor check ) : CHECK ( n room facing -- n : Check & count if next room is closed ) WALK ( walk to next room ) SWAP C@ ALL = ( is it a closed room? ) IF OVER FACES + C! ( save facing ) 1+ ( count as closed ) ELSE DROP ( discard facing ) THEN ; : CHECKAROUND ( room -- room n : Check around for closed rooms ) 0 ( start counting closed neighbors ) OVER WEST CHECK OVER NORTH CHECK OVER EAST CHECK OVER SOUTH CHECK ; ( Select a random direction toward a closed room ) : RNDFACE ( n -- facing ) RAND FACES + C@ ; 0 VARIABLE REMAINING ( remaining rooms to visit ) : DFS ( room #rooms -- : Depth-First Search maze generation ) 1- REMAINING ! ( rooms to visit ) 0 SWAP ( stack a marker ) BEGIN REMAINING @ ( stop when all rooms visited ) WHILE CHECKAROUND ?DUP ( any closed neighbor? ) IF OVER SWAP ( stack current room ) RNDFACE CUT ( cut a passage to a closed room ) REMAINING @ 1- ( count visited rooms ) REMAINING ! ELSE DROP ( backtrack last visited room ) THEN REPEAT BEGIN 0= UNTIL ( clear stack to marker ) ; : GENERATE ( Start maze generation ) CLS INIT _MAP XSIZE @ 2 / YSIZE @ 2 / ( Start from maze center ) XY>ROOM XSIZE @ YSIZE @ * DFS ; : SETEXIT ( Set a random maze exit at North border ) XSIZE @ RAND 1+ 0 XY>ROOM SOUTH CUT DROP ; : START ( -- room facing : Generate a random start position at South ) XSIZE @ RAND 1+ YSIZE @ XY>ROOM NORTH ; ( ============== ) ( DRAW 3D MAZE ) ( ============== ) 0 VARIABLE LOOKUPS ( Number of 2D map invoking ) 0 VARIABLE STEPS ( Number of steps ) : .SCORE ( Display score and controls ) 0 24 AT ." 3D MAZE" 2 25 AT ." Steps" 3 26 AT STEPS @ . 5 25 AT ." Helps" 6 26 AT LOOKUPS @ . 15 25 AT ." I" 16 24 AT ." JKL Move" 18 25 AT ." H Help" 20 25 AT ." Q Quit" ; CREATE MRKS ( 3D drawing key screen coordinates ) ( A B ) 0 C, 22 C, 1 C, 21 C, 5 C, 17 C, 8 C, 14 C, 10 C, 12 C, 11 C, 11 C, : MARKS ( n -- A[n] B[n] ) 2 * MRKS + DUP C@ SWAP 1+ C@ ; ( Draw Vertical edges: ) ( Left edge column = A[n+1]-1 ) ( Right edge column = B[n+1]+1 ) ( 1 past Last line = B[n+1]+1 ) ( First line = A[n+1] ) : _EDGES ( n -- : Draw Vertical Edges ) 1+ MARKS 1+ ( A[n+1] B[n+1]+1 ) OVER 1- ( A[n+1] B[n+1]+1 A[n+1]-1 ) SWAP ROT ( A[n+1]-1 B[n+1]+1 A[n+1] ) OVER SWAP ( A[n+1]-1 B[n+1]+1 B[n+1]+1 A[n+1] ) DO ( A[n+1]-1 B[n+1]+1 ) OVER I SWAP AT 4 EMIT ( Draw left edge ) I OVER AT 1 EMIT ( Draw right edge ) LOOP DROP DROP ( discard left & right column coord ) ; ( Draw Back Wall: ) ( Top line = A[n+1]-1 ) ( Bottom line = B[n+1]+1 ) ( 1 past last column = B[n+1]+1 ) ( First column = A[n+1] ) : _BACK ( n -- : Draw Back Wall ) 1+ MARKS 1+ ( A[n+1] B[n+1]+1 ) OVER 1- ( A[n+1] B[n+1]+1 A[n+1]-1 ) ROT ROT ( A[n+1]-1 A[n+1] B[n+1]+1 ) DUP ROT ( A[n+1]-1 B[n+1]+1 B[n+1]+1 A[n+1] ) DO ( A[n+1]-1 B[n+1]+1 ) OVER I AT 2 EMIT ( Draw top line ) DUP I AT 8 EMIT ( Draw bottom line ) LOOP DROP DROP ( discard top & bottom line coord ) ; ( Draw Left Wall: ) ( Bottom line = B[n] ) ( Top line = A[n] ) ( 1 past last column = A[n+1] ) ( First column = A[n] ) : _LWALL ( n -- : Draw Left wall ) DUP MARKS SWAP ( n B[n] A[n] ) ROT 1+ MARKS DROP ( B[n] A[n] A[n+1] ) SWAP ( B[n] A[n+1] A[n] ) DO ( B[n] ) I I AT 92 EMIT ( Draw top line \ ) DUP I AT 47 EMIT ( Draw bottom line / ) 1- ( update bottom line coord ) LOOP DROP ( discard bottom line coord ) ; ( Draw Right Wall: ) ( Bottom line = B[n+1]+1 ) ( Top line = A[n+1]-1 ) ( 1 past last column = B[n]+1 ) ( First column = B[n+1]+1 ) : _RWALL ( n -- : Draw Right Wall ) DUP 1+ MARKS 1+ SWAP 1- ( n B[n+1]+1 A[n+1]-1 ) ROT MARKS SWAP DROP 1+ ( B[n+1]+1 A[n+1]-1 B[n]+1 ) ROT ( A[n+1]-1 B[n]+1 B[n+1]+1 ) DO ( A[n+1]-1 ) DUP I AT 47 EMIT ( Draw top line / ) I I AT 92 EMIT ( Draw bottom line \ ) 1- ( update top line coord ) LOOP DROP ( discard top line coord ) ; ( Draw Left Back Wall: ) ( Bottom line = B[n+1]+1 ) ( Top line = A[n+1]-1 ) ( 1 past last column = A[n+1] ) ( First column = A[n] ) : _LBACK ( n -- : Draw Left Back Wall ) DUP 1+ MARKS 1+ ( n A[n+1] B[n+1]+1 ) ROT MARKS DROP ( A[n+1] B[n+1]+1 A[n] ) ROT DUP 1- ( B[n+1]+1 A[n] A[n+1] A[n+1]-1 ) SWAP ROT ( B[n+1]+1 A[n+1]-1 A[n+1] A[n] ) DO ( B[n+a]+1 A[n+1]-1 ) DUP I AT 2 EMIT ( Draw top line ) OVER I AT 8 EMIT ( Draw bottom line ) LOOP DROP DROP ( discard top & bottom line coord ) ; ( Draw Right Back Wall: ) ( Bottom line = B[n+1]+1 ) ( Top line = A[n+1]-1 ) ( 1 past last column = B[n]+1 ) ( First column = B[n+1]+1 ) : _RBACK ( n -- : Draw Right Back Wall ) DUP 1+ MARKS 1+ SWAP 1- ( n B[n+1]+1 A[n+1]-1 ) SWAP ROT MARKS SWAP DROP 1+ ( A[n+1]-1 B[n+1]+1 B[n]+1 ) OVER ( A[n+1]-1 B[n+1]+1 B[n]+1 B[n+1]+1 ) DO ( A[n+1]-1 B[n+1]+1 ) OVER I AT 2 EMIT ( Draw top line ) DUP I AT 8 EMIT ( Draw bottom line ) LOOP DROP DROP ( discard top & bottom line coord ) ; ( Check if facing wall exist ) : WALL? ( room facing -- flag ) SWAP C@ AND ; : _3D ( room facing -- ) CLS .SCORE 5 0 ( max View depth = 5 rooms ) DO I _EDGES ( Draw vertical edges ) 2DUP LEFT TURN WALL? ( Is there a wall at left? ) IF I _LWALL ( draw left wall ) ELSE 2DUP LEFT TURN WALK ( Go to left room ) RIGHT TURN WALL? ( Is there a left back wall?) IF I _LBACK ( draw left back wall ) THEN THEN 2DUP RIGHT TURN WALL? ( Is there a wall at right? ) IF I _RWALL ( draw right wall ) ELSE 2DUP RIGHT TURN WALK ( Go to right room ) LEFT TURN WALL? ( Is there a right back wall? ) IF I _RBACK ( draw right back wall ) THEN THEN 2DUP WALL? ( Facing a wall? ) IF I _BACK LEAVE ( Draw back wall and leave loop ) ESLE WALK ( Move forward ) OVER MAZE - 32 < ( Maze exit? ) IF LEAVE ( Leave loop ) THEN THEN LOOP DROP DROP ( Discard room & facing ) ; ( ============== ) ( GAME CONTROL ) ( ============== ) ( Check if the exit was found ) : EXIT? ( room -- flag ) MAZE - 32 < ; : .FACE ( facing -- : Print facing direction ) DUP WEST = IF ." West" THEN DUP SOUTH = IF ." South" THEN DUP EAST = IF ." East" THEN NORTH = IF ." North" THEN ; : .INFO ( room facing -- : Print info bar at screen bottom ) 100 DUP BEEP 22 0 AT ." Facing " .FACE ." , S:" STEPS @ . ." H:" LOOKUPS @ . EXIT? IF 50 DUP BEEP 30 DUP BEEP ." EXIT" THEN ; : _2D ( room facing -- : Draw 2D map and wait for a keypress ) CLS _MAP OVER _POS .INFO KEY DROP ( Wait for a keypress ) ; : FORWARD ( room1 facing -- room2 facing : Step forward ) 2DUP WALL? 0= IF WALK STEPS 1+! THEN ; : BACKWARD ( room1 facing -- room2 facing : Step backward ) BACK TURN FORWARD BACK TURN ; : PLAY 0 STEPS ! 0 LOOKUPS ! GENERATE SETEXIT START 2DUP _2D BEGIN 2DUP _3D KEY TOUPPER ROT ROT 3 PICK ASCII I = IF FORWARD THEN 3 PICK ASCII K = IF BACKWARD THEN 3 PICK ASCII J = IF LEFT TURN THEN 3 PICK ASCII L = IF RIGHT TURN THEN 3 PICK ASCII H = IF 2DUP _2D LOOKUPS 1+! THEN ROT ASCII Q = 3 PICK EXIT? OR UNTIL _2D ; : .MENU CLS ." ____________3D_MAZE_______v 1.0_" 4 11 AT ." Width:" 5 10 AT ." Height:" 7 11 AT ." I" 8 10 AT ." JKL Set Maze Size" 10 11 AT ." P Play" 12 11 AT ." Q Quit" 20 3 AT ." c 2007 by Ricardo F. Lopes" 21 3 AT ." General Public License v.2" ; : .SIZE 4 18 AT XSIZE @ . 5 18 AT YSIZE @ . ; : 3DMAZE ( Start the 3D game ) GR RANDOMIZE .MENU BEGIN .SIZE KEY TOUPPER DUP ASCII I = IF 1 X+ THEN DUP ASCII K = IF -1 X+ THEN DUP ASCII J = IF -1 Y+ THEN DUP ASCII L = IF 1 Y+ THEN DUP ASCII P = IF PLAY .MENU THEN ASCII Q = UNTIL CLS ; |