1. RE: To: Evan Marshall (Maze Maker)
- Posted by Don Phillips <Graebel at hotmail.com> Jun 06, 2002
- 405 views
> I'm glad you found it interesting. I was thinking about making a 3D > maze and decided a 2D one would be easier to start with. > I found an algorithm very similar to yours somewhere on the net (I can't > > remember where :( ) and decided to go for simplicity(?) over speed for > > the first draft. I plan on going back to increase the speed later, as > right now I have more time to wait for a program to run than I do to > develop it! > I am also going to make the maze printable and am working on a print > preview routine. (That should take me quite awhile!) > > Don Phillips wrote: Yes, I found it very interesting. Its good to try something new every once in a while and optimizing this code was alot of fun. I was able to speed it up even further and reduce the code in the main loop quite a bit from the one I posted last. Also I was able to make the status indicator consistant in movement. I think I like this version the best. Not only is it faster, shorter, and easier to understand, I believe it makes better overall (and harder) mazes to solve. -=-=-=-=-=-=-=-=-=- without warning include Win32Lib.ew -- register controls with win32lib constant MainWin = create( Window, "Maze", NULL, 0.1, 0.1, 0.8, 0.8, or_all({WS_CLIPCHILDREN,WS_CLIPSIBLINGS}) ), Canvas = create( Window, "", MainWin, 0, 0, 1, 1, {WS_CHILD,WS_VISIBLE,WS_DLGFRAME,WS_CLIPCHILDREN,WS_CLIPSIBLINGS} ), MaxXLbl = createEx( EditText, "", Canvas, 14, 7, 50, 15, {WS_CHILD,WS_VISIBLE,WS_DISABLED}, {0} ), MaxYLbl = createEx( EditText, "", Canvas, 74, 7, 50, 15, {WS_CHILD,WS_VISIBLE,WS_DISABLED}, {0} ), EditX = create( EditText, "20", Canvas, 10, 22, 50, 20, ES_NUMBER ), EditY = create( EditText, "20", Canvas, 70, 22, 50, 20, ES_NUMBER ), RunMaze = create( DefPushButton, "Make Maze", Canvas, 131, 18, 140, 29, 0 ), Status = create( ProgressBar, "", Canvas, 0, 0, 1, 1, 0 ) -- define globals sequence NewPos -- remove a wall in specified direction procedure RemoveWall( integer Direction ) if Direction = 1 then drawLine( MainWin, (NewPos[1]-1)*10+1, (NewPos[2]-1)*10, (NewPos[1]-1)*10+10, (NewPos[2]-1)*10 ) elsif Direction = 2 then drawLine( MainWin, (NewPos[1]-1)*10, (NewPos[2]-1)*10+1, (NewPos[1]-1)*10, (NewPos[2]-1)*10+10 ) elsif Direction = 3 then drawLine( MainWin, (NewPos[1]-1)*10+10, (NewPos[2]-1)*10+1, (NewPos[1]-1)*10+10, (NewPos[2]-1)*10+10 ) else drawLine( MainWin, (NewPos[1]-1)*10+1, (NewPos[2]-1)*10+10, (NewPos[1]-1)*10+10, (NewPos[2]-1)*10+10 ) end if end procedure -- make the maze procedure makeMaze() integer Direction integer Index integer PosX integer PosY integer RoomsX integer RoomsY integer UsedRooms sequence Grid sequence Mask sequence Move sequence Path sequence Size sequence Slice -- clear screen repaintWindow( MainWin ) -- get size of grid Size = value( getText(EditX) ) RoomsX = Size[ 2 ] Size = value( getText(EditY) ) RoomsY = Size[ 2 ] -- enforce maximums Size = getClientRect( MainWin ) if RoomsX > floor((Size[3] - 20) / 10) then setText( EditX, sprintf( "%d", {floor((Size[3] - 20) / 10)} )) RoomsX = floor((Size[3] - 20) / 10) end if if RoomsY > floor((Size[4] - 80) / 10) then RoomsY = floor((Size[4] - 80) / 10) setText( EditY, sprintf( "%d", {floor((Size[4] - 80) / 10)} )) end if -- set status indicator range to maximum UsedRooms = 0 setScrollRange( Status, 0, RoomsX * RoomsY * 2 ) -- initialize grid Grid = {} Grid &= { repeat( 0, RoomsX+2 ) } Grid &= repeat( 0 & repeat( 1, RoomsX ) & 0, RoomsY ) Grid &= { repeat( 0, RoomsX+2 ) } -- draw initial grid on screen setPenColor( MainWin, Yellow ) for IterY = 0 to RoomsY do drawLine( MainWin, 10, IterY*10+10, RoomsX*10+10, IterY*10+10 ) end for for IterX = 0 to RoomsX do drawLine( MainWin, IterX*10+10, 10, IterX*10+10, RoomsY*10+10 ) end for setPenColor( MainWin, Black ) -- set random initial position PosX = rand( RoomsX ) + 1 PosY = rand( RoomsY ) + 1 Grid[ PosY ][ PosX ] = 0 NewPos = { PosX, PosY } Mask = { 0, 1, 0, 2, 0, 3, 0, 4, 0} Move = { {0,-1}, {-1,0}, {1,0}, {0,1} } Index = 2 Path = repeat( {}, RoomsX * RoomsY + 1 ) Path[2] = NewPos while Index != 1 do -- update the indicator and let winlib handle events UsedRooms += 1 setScrollPos( Status, UsedRooms ) doEvents( 0 ) -- get movement grid slice Slice = {} for SliceIter = -1 to 1 do Slice &= Grid[ NewPos[2]+SliceIter ][ NewPos[1]-1..NewPos[1]+1 ] end for -- mask to find valid move positions Slice = reverse( sort( (Slice and Mask) * Mask )) if not Slice[1] then -- no valid moves, remove from path Index -= 1 NewPos = Path[ Index ] else -- move in random direction Direction = Slice[ rand(find(0,Slice)-1) ] RemoveWall( Direction ) NewPos += Move[ Direction ] Index += 1 Path[ Index ] = NewPos Grid[ NewPos[2] ][ NewPos[1] ] = 0 end if end while -- maze done, cut out random top and bottom piece PosX = rand( RoomsX ) + 1 drawLine( MainWin, (PosX-1)*10+1, 10, (PosX-1)*10+10, 10 ) PosX = rand( RoomsX ) + 1 drawLine( MainWin, (PosX-1)*10+1, RoomsY*10+10, (PosX-1)*10+10, RoomsY*10+10 ) -- clear status indicator setScrollPos( Status, 0 ) end procedure -- run the maze algorithm procedure onClick_RunMaze() makeMaze() end procedure onClick[ RunMaze ] = routine_id( "onClick_RunMaze" ) -- resize controls to parent procedure onResize_MainWin( integer Style, integer CX, integer CY ) setRect( Canvas, 0, CY-60, CX, 60, True ) setRect( Status, 283, 23, CX-300, 18, True ) setText( MaxXLbl, sprintf( "Max %d", {floor((CX - 20) / 10)} )) setText( MaxYLbl, sprintf( "Max %d", {floor((CY - 80) / 10)} )) end procedure onResize[ MainWin ] = routine_id( "onResize_MainWin" ) -- initialize procedure onOpen_MainWin() setWindowBackColor( MainWin, Black ) setWindowBackColor( MaxXLbl, getSysColor(COLOR_BTNFACE) ) setWindowBackColor( MaxYLbl, getSysColor(COLOR_BTNFACE) ) setFocus( EditX ) end procedure onOpen[ MainWin ] = routine_id( "onOpen_MainWin" ) -- event loop WinMain( MainWin, Maximize ) -=-=-=-=-=-=-=-=-=- Enjoy!