/// <summary> /// Just do some initialization and call the main routine, /// that is analyze_cell() /// </summary> public void GenerateMaze(int sizeX, int sizeY, int smoothness, int seed) { iSmooth = smoothness; MazeSizeX = sizeX; MazeSizeY = sizeY; maze_base = new int[MazeSizeX * MazeSizeY]; maze_data = new byte[MazeSizeX, MazeSizeY]; stateStack = new FastStack <cMazeState>(); r = new Random(seed); MazeInit(); cMazeState state = new cMazeState(r.Next() % MazeSizeX, r.Next() % MazeSizeY, 0); analyze_cell(state, r); }
/// <summary> /// Just do some initialization and call the main routine, /// that is analyze_cell() /// </summary> /// <param name="sizeX"></param> /// <param name="sizeY"></param> /// <param name="seed"></param> public void GenerateMaze(int sizeX, int sizeY, int seed, int smoothness) { iSmooth = smoothness; MSIZEX = sizeX; MSIZEY = sizeY; maze_base = new int[MSIZEX * MSIZEY]; maze_data = new Byte[MSIZEX, MSIZEY]; s_stack = new Stack(); r = new Random(seed); MazeInit(r); cMazeState s = new cMazeState(r.Next() % MSIZEX, r.Next() % MSIZEY, 0); analyze_cell(s, r); }
public cMazeState( cMazeState s ) { x=s.x; y=s.y; dir=s.dir; }
/// <summary> /// This is the main routine. /// The algorithm is pretty simple and very efficient. /// At the beginnins there are walls everywhere. /// /// The algorithm walks around the maze choosing the /// random path at every step and looks if it can /// remove the wall between the cells. /// /// The test that allows to remove the wall is also really /// simple: if the two cells are already connected then /// the wall is not allowed. /// /// The only trick is the check whether the two cells are /// connected. To answer this question, the algorithm /// keeps the chains of connected walls. It works like this: /// - each chain consist of pointers to consecutive cells /// in the chain, last pointer is -1 and the cell with /// such value in maze_base is called base_cell of a cell. /// - at the beginning there are no chains, looking /// at maze_base[cellindex] you can find the value of -1 /// - when two chains are merged, the pointer of the base cell /// of one of chains is changed so that it points to the /// base_cell of the other chain. /// /// I've read about a similar trick by Tarjan but it looked /// much complicated ( or maybe I didn't understand it well ). /// Nevertheless, my code works really fast! Try to beat it. /// </summary> /// <param name="s"></param> /// <param name="r"></param> void analyze_cell( cMazeState s, Random r ) { bool bEnd = false, found; int indexSrc, indexDest, tDir=0, prevDir=0; while (true) { if ( s.dir == 15 ) { while ( s.dir == 15 ) { s = (cMazeState)s_stack.pop(); if ( s == null ) { bEnd = true; break; } } if ( bEnd == true ) break; } else { do { prevDir = tDir; tDir = (int)Math.Pow( 2, r.Next()%4 ); if ( (r.Next()%32) < iSmooth ) if ( (s.dir & prevDir) == 0 ) tDir = prevDir; if ( (s.dir & tDir) != 0 ) found = true; else found = false; } while ( found == true && s.dir!=15 ); s.dir |= tDir; indexSrc = cell_index( s.x, s.y ); // direction W if ( tDir == 1 && s.x > 0 ) { indexDest = cell_index( s.x-1, s.y ); if ( base_cell( indexSrc ) != base_cell ( indexDest ) ) { merge( indexSrc, indexDest ); maze_data[s.x, s.y] |= (byte)Direction.W; s_stack.push ( new cMazeState(s) ); s.x -= 1;s.dir = 0; } } // direction E if ( tDir == 2 && s.x < MSIZEX-1 ) { indexDest = cell_index( s.x+1, s.y ); if ( base_cell( indexSrc ) != base_cell ( indexDest ) ) { merge( indexSrc, indexDest ); maze_data[s.x+1, s.y] |= (byte)Direction.W; s_stack.push ( new cMazeState(s) ); s.x += 1;s.dir = 0; } } // direction N if ( tDir == 4 && s.y > 0 ) { indexDest = cell_index( s.x, s.y-1 ); if ( base_cell( indexSrc ) != base_cell ( indexDest ) ) { merge( indexSrc, indexDest ); maze_data[s.x, s.y] |= (byte)Direction.N; s_stack.push ( new cMazeState(s) ); s.y -= 1;s.dir = 0; } } // direction S if ( tDir == 8 && s.y < MSIZEY-1 ) { indexDest = cell_index( s.x, s.y+1 ); if ( base_cell( indexSrc ) != base_cell ( indexDest ) ) { merge( indexSrc, indexDest ); maze_data[s.x, s.y+1] |= (byte)Direction.N; s_stack.push ( new cMazeState(s) ); s.y += 1;s.dir = 0; } } } // else } // while }
/// <summary> /// Just do some initialization and call the main routine, /// that is analyze_cell() /// </summary> /// <param name="sizeX"></param> /// <param name="sizeY"></param> /// <param name="seed"></param> public void GenerateMaze( int sizeX, int sizeY, int seed, int smoothness ) { iSmooth = smoothness; MSIZEX = sizeX; MSIZEY = sizeY; maze_base = new int[MSIZEX*MSIZEY]; maze_data = new Byte[MSIZEX, MSIZEY]; s_stack = new Stack(); r = new Random ( seed ); MazeInit( r ); cMazeState s = new cMazeState(r.Next()%MSIZEX, r.Next()%MSIZEY, 0); analyze_cell( s, r ); }
/// <summary> /// This is the main routine. /// The algorithm is pretty simple and very efficient. /// At the beginnins there are walls everywhere. /// /// The algorithm walks around the maze choosing the /// random path at every step and looks if it can /// remove the wall between the cells. /// /// The test that allows to remove the wall is also really /// simple: if the two cells are already connected then /// the wall is not allowed. /// /// The only trick is the check whether the two cells are /// connected. To answer this question, the algorithm /// keeps the chains of connected walls. It works like this: /// - each chain consist of pointers to consecutive cells /// in the chain, last pointer is -1 and the cell with /// such value in maze_base is called base_cell of a cell. /// - at the beginning there are no chains, looking /// at maze_base[cellindex] you can find the value of -1 /// - when two chains are merged, the pointer of the base cell /// of one of chains is changed so that it points to the /// base_cell of the other chain. /// /// I've read about a similar trick by Tarjan but it looked /// much complicated ( or maybe I didn't understand it well ). /// Nevertheless, my code works really fast! Try to beat it. /// </summary> /// <param name="s"></param> /// <param name="r"></param> void analyze_cell(cMazeState s, Random r) { bool bEnd = false, found; int indexSrc, indexDest, tDir = 0, prevDir = 0; while (true) { if (s.dir == 15) { while (s.dir == 15) { s = (cMazeState)s_stack.pop(); if (s == null) { bEnd = true; break; } } if (bEnd == true) { break; } } else { do { prevDir = tDir; tDir = (int)Math.Pow(2, r.Next() % 4); if ((r.Next() % 32) < iSmooth) { if ((s.dir & prevDir) == 0) { tDir = prevDir; } } if ((s.dir & tDir) != 0) { found = true; } else { found = false; } } while (found == true && s.dir != 15); s.dir |= tDir; indexSrc = cell_index(s.x, s.y); // direction W if (tDir == 1 && s.x > 0) { indexDest = cell_index(s.x - 1, s.y); if (base_cell(indexSrc) != base_cell(indexDest)) { merge(indexSrc, indexDest); maze_data[s.x, s.y] |= (byte)Direction.W; s_stack.push(new cMazeState(s)); s.x -= 1; s.dir = 0; } } // direction E if (tDir == 2 && s.x < MSIZEX - 1) { indexDest = cell_index(s.x + 1, s.y); if (base_cell(indexSrc) != base_cell(indexDest)) { merge(indexSrc, indexDest); maze_data[s.x + 1, s.y] |= (byte)Direction.W; s_stack.push(new cMazeState(s)); s.x += 1; s.dir = 0; } } // direction N if (tDir == 4 && s.y > 0) { indexDest = cell_index(s.x, s.y - 1); if (base_cell(indexSrc) != base_cell(indexDest)) { merge(indexSrc, indexDest); maze_data[s.x, s.y] |= (byte)Direction.N; s_stack.push(new cMazeState(s)); s.y -= 1; s.dir = 0; } } // direction S if (tDir == 8 && s.y < MSIZEY - 1) { indexDest = cell_index(s.x, s.y + 1); if (base_cell(indexSrc) != base_cell(indexDest)) { merge(indexSrc, indexDest); maze_data[s.x, s.y + 1] |= (byte)Direction.N; s_stack.push(new cMazeState(s)); s.y += 1; s.dir = 0; } } } // else } // while } // function
public cMazeState(cMazeState s) { x = s.x; y = s.y; dir = s.dir; }