Speaking of the maze, everyone must be familiar with it. I personally feel that the maze is a great test of human direction. At least my sense of direction is not good, especially in 3D space. During this time, I used 3D plotting for my mentor's project, so I tried my best to create a 3D maze. To draw a 3D maze game, we need to start from two dimensions. Two-dimensional maze:
The procedure of the Maze:In real life, we often use mathematical methods to describe and solve problems (mathematical modeling ). Similarly, if we want to use a program to solve the problem, we have to program the problem. If you don't talk nonsense, go to the topic:
We can use a matrix to describe the entire Maze.:
If the element is 1, it indicates that it is empty. If the element is 0, it indicates the wall..
In order to describe the problem easily, we use a matrix of nine rows and nine columns to describe the problem, and assume that () is the entrance and () is the exit.
There are also some common maze programs on the Internet, but they all have a feature that the generated maze may not have reachable paths from the entrance to the exit (you can generate a maze through loops, until there is a reachable path), or there are several reachable paths from the entrance to the exit (if you want to only have a unique reachable path, it won't work). Most of these algorithms use random numbers to generate the matrix of the Maze matrix (where 0, 1 elements are randomly generated), and then use iterative and backtracking algorithms to find the path from the entrance to the exit. Since matrix is random, it cannot be ensured that the entrance to the exit is reachable, which is the cause of the above problem.
Algorithm idea:I think everyone has learned
Tree (for details about Tree operations, refer to my previous article)Such data structures, such as tree traversal of DFS, BFs, and tree depth. Of course, there are also many types of trees, such as full Binary Trees, red/black trees, and B trees. But I am not talking about this,
But another property I found: there is only one path from one node to another!Now we can contact the question I mentioned above.
Let's take a look at how the contact was made:First, we initialize the elements of the entire matrix to 0, that is, all elements are walls,
Our task is to split the wall (so that the element is equal to 1) to form a maze. How to split the wall is the key to our algorithm!
FirstWe can randomly find an initial vertex A () in the matrix and set the value of this vertex to 1, removing the wall of this vertex.
ThenGenerates a random integer randnum from 0 to 3 (0, 1, 2, and 3 represent the upper, lower, and left directions (
Note: two parts are separated.). If there is no wall at the position separated from the current position in this direction, it cannot be split. Then a random number is generated and the wall is split in other directions. (
Note that the wall is split on the premise that the wall is located in the same direction.) Finally, in the previous step, the system repeats until there is no wall to be split in the four directions of the current position. Then, it goes back to the previous position of the current position ), then perform the operation in the previous step until there is no wall to be split !.
I have always believed that images speak better than words. Here we use images to illustrate the above steps:
For example, we use a matrix of nine rows and nine columns. The initial vertex is (4, 4 ).
1. At the beginning, only the wall at the initial point was removed.
2. Random Number randnum = 2. Start to split the wall to the left. Because () is 0 (with a wall), the wall can be split, so it is located at () and, the result is as follows:
3. Then the random randnum = 1 is generated, and the wall is split down. Because (6, 2) is 0 (with a wall), the wall can be split. Therefore, the wall at the positions (5, 2) and (6, 2) can be removed, the result is as follows:
4. Continue to generate the random number randnum = 0 and start to split the wall up. Because () is 1 and there is no wall, it cannot be split, so the random number is re-generated. The result is the same as that in the previous figure:
5. Continue to generate a random number randnum = 3 and start to split the wall to the right. Because (6, 4) has 0 walls, you can split the walls at (6, 3) and (6, 4) positions. The result is as follows:
Repeat the preceding steps to obtain a possible maze matrix:
Note:1. the rows and columns of the Maze matrix must be the base, and the positions of the initial points must be an even number. (This is determined by the algorithm, because the algorithm always starts from the initial point and the step size is 2 to reach the entry point and exit point, therefore, the distance between the initial point, the entry point, and the exit point must be a multiple of step 2 ). 2. It is best to select the initial vertex in the middle of the matrix. It can be imagined that the essence of an algorithm is to arrive at another vertex from the initial vertex, and branches will be generated in the middle (backtracking reason, if you go back to the initial point, the Branch is generated at the initial point) to other points (including the entry point and exit point ). Therefore, we can describe a tree, and the initial point is the root node of the tree. In order to quickly find the reachable path between the exit point and the entry point, the depth of the tree should be small, so that the initial selection should be in the middle. 3. Why should I choose to check whether the block is a wall instead of an adjacent block, or how many blocks are separated? The width of the road is the same as that of the wall. (You can deduce the width of the road and the wall when the adjacent block is used or the number of blocks is separated !)
The above graphic text shows how to generate a maze. Let's take a look at how to generate an accessible path from the entrance to the exit:As shown in the previous figure, the yellow part is the reachable path (the only one). Because the maze is small, we can see at a glance that when the maze is large, we will rely on the Matrix to calculate it. In the above Maze generation algorithm, we can record the nodes when splitting the wall. When splitting to the entrance, the path from the initial point to the entrance is recorded. Likewise, we can also obtain the path from the initial point to the exit, so that we can easily obtain the path from the entrance to the exit based on the two paths.
As I mentioned earlier, the entire algorithm is the process of generating a tree. The initial point is the root node. Finding the reachable path is equivalent to finding the path from the entry node in the tree to the exit node. As mentioned above, the accessible paths of any two nodes in the tree are unique, so the entrance to the exit path of the Maze generated by the algorithm is unique.
At this point, we have already talked about the entire algorithm IDEA and process. The source code (C ++, vs2010 implementation) is given below. The source file provides a detailed comment, so there is no more explanation.
5 files in total: 1. maze. H 2, maze. cpp 3, mazestack. H 4, mazestack. cpp 5, Main. cpp.
The details are as follows:
1. maze. h
# Include <iostream> # include <ctime> # include <vector> # define M 9 // the rows in the Maze # define N 9 // The column in the Maze // construct the maze type // using namespace STD; class mazestack; // declare the class maze // define the maze node information. {Public: int I; Int J; int state ;}; class mazemat {maze matrix [m] [N]; // maze matrix vector <maze> entrypath; // from the initial point to the entry path vector <maze> exitpath; // from the initial point to the exit path vector <maze> finalpath; // The path mazestack * mazestack from the entry to the exit; // define the stack public: void initmaze (); // initialize the maze matrix void createmaze (); // generate the maze matrix void displaymaze (); // display the maze matrix void findway (); // find the path from the entrance to the exit };//////////////////
2. maze. cpp
# Include "mazestack. H "using namespace STD; void mazemat: initmaze () // initialize the maze matrix {for (INT I = 0; I <m; I ++) for (Int J = 0; j <n; j ++) {matrix [I] [J]. I = I; matrix [I] [J]. j = J; matrix [I] [J]. state = 0; // the initialization of the Maze matrix element is 0, that is, all is the wall} mazestack = new mazestack (); entrypath. clear (); // initialize the exitpath of each path. clear (); finalpath. clear ();} void mazemat: createmaze () // generates a maze matrix. The path from the initial point to the entry and exit is recorded in the middle. {int I = 4; // set the initial vertex. Note that J must be an even integer Int J = 4; bool left = false; // indicates the four initialization directions. False indicates You can search for bool right = false; bool up = false; bool down = false; matrix [I] [J] in this direction. state = 1; // set the initial point to null, that is, not the wall srand (INT) time (0); // generate a random seed, make the running status different from maze temp; temp. I = I; temp. j = J; temp. state = 0; int count1 = 0; int num1 = 0; mazestack-> push (temp); // Add the initial vertex to the stack while (1) // continuously search for feasible directions to form a maze {temp. I = I; temp. j = J; int randnum = 0; randnum = rand () % 4; //, // assume that the first element () of the Maze matrix is the entrance, the last element (M-1, N-2) for the exit if (temp. I = 0 & temp. j = 0) {entrypath. clear (); W Hile (mazestack-> isempty () = false) {entrypath. push_back (mazestack-> gettop (); // obtain the path mazestack-> POP () ;}for (int ii = entrypath. size ()-1; II> = 0; II --) {mazestack-> push (entrypath [II]); // restore stack} If (temp. I = M-1 & temp. j = N-1) {exitpath. clear (); While (mazestack-> isempty () = false) {exitpath. push_back (mazestack-> gettop (); // obtain the path mazestack-> POP () ;}for (INT I = exitpath. size ()-1; I> = 0; I --) {Ma Zestack-> push (exitpath [I]); // restore stack} switch (randnum) {Case 0: // search for if (up = false & I> 1 & matrix [I-2] [J]. state! {Mazestack-> push (temp); matrix [I-1] [J]. state = 1; matrix [I-2] [J]. state = 1; I = I-2; left = false; Right = false; up = false; down = false;} elseup = true; break; Case 1: // search down if (down = false & I <M-2 & matrix [I + 2] [J]. state! = 1) {mazestack-> push (temp); matrix [I + 1] [J]. state = 1; matrix [I + 2] [J]. state = 1; I = I + 2; left = false; Right = false; up = false; down = false;} elsedown = true; break; Case 2: // search left for if (Left = false & J> 1 & matrix [I] [J-2]. state! = 1) {mazestack-> push (temp); matrix [I] [J-1]. state = 1; matrix [I] [J-2]. state = 1; j = J-2; left = false; Right = false; up = false; down = false;} elseleft = true; break; Case 3: // search for if (Right = false & J <N-2 & matrix [I] [J + 2]. state! = 1) {mazestack-> push (temp); matrix [I] [J + 1]. state = 1; matrix [I] [J + 2]. state = 1; j = J + 2; left = false; Right = false; up = false; down = false;} elseright = true; break ;} // end switch if (left & Right & up & down) // when the upper, lower, and lower rows are not available, perform backtracing {If (mazestack-> isempty ()) // generate the maze {return;} else after backtracking. // perform the stack Export Operation {I = mazestack-> gettop (). i; j = mazestack-> gettop (). j; mazestack-> POP (); left = false; Right = false; up = false; down = false; }}// end while} V Oid mazemat: displaymaze () // display the maze {matrix [0] [0]. state = matrix [M-1] [N-1]. state = 2; // 2 indicates the entry and exit for (INT I = 0; I <finalpath. size (); I ++) {matrix [finalpath. at (I ). i] [finalpath. at (I ). j]. state = 3; // 3 indicates the reachable path.} cout <"the upper left corner indicates the entrance, the lower right corner indicates the exit, and OO indicates the reachable path. "<Endl; For (int K = 0; k <n + 2; k ++) // cout on the outer wall of the Maze matrix <" ■ "; cout <Endl; For (INT I = 0; I <m; I ++) {cout <"■"; for (Int J = 0; j <N; j ++) {Switch (Matrix [I] [J]. state) {Case 0: cout <"■"; break; // Display Wall case 1: cout <"; break; // display empty case 2: cout <" "; break; // display Entry and Exit Case 3: cout <"oo"; break; // display reachable path }}cout <"■"; cout <Endl ;} for (int K = 0; k <n + 2; k ++) cout <"■"; cout <Endl;} void mazemat: findway () // find the reachable path {finalpath. clear (); // clear int I = 0, j = 0; for (I = entrypath. size ()-1, j = exitpath. size ()-1; I >=0 & J> = 0; I --, j --) {If (entrypath. at (I ). i! = Exitpath. At (j). I | entrypath. at (I). J! = Exitpath. at (j ). j) {break ;}}if (I <0) // the path from the initial point to the exit goes through the entry {for (int K = exitpath. size ()-entrypath. size ()-1; k> = 0; k --) {finalpath. push_back (exitpath. at (k) ;}} else if (j <0) // exit through the initial point to the entry path {for (int K = entrypath. size ()-exitpath. size ()-1; k> = 0; k --) {finalpath. push_back (entrypath. at (k) ;}} else // The initial point to the entry and exit paths partially overlap or there is no overlap {for (int K = 0; k <= I + 1; k ++) {finalpath. push_back (entrypath. at (k) ;}for (int K = J; k> = 0; k --) {finalpath. push_back (exitpath. at (k ));}}}
3. mazestack. h
# Include "maze. H "typedef maze elementtype; // The stack definition typedef struct node {elementtype data; struct node * Next;} node; Class mazestack {public: mazestack (): bottom (null), top (null), size (null ){}~ Mazestack () {} bool isempty (); bool push (elementtype E); elementtype gettop (); elementtype POP (); Private: node * bottom; node * top; int size ;};
4. mazestack. cpp
# Include "mazestack. H "bool mazestack: isempty () // judge whether the stack is empty {If (Top = bottom) return true; return false;} bool mazestack: Push (maze m) // stack {node * temp; temp = top; Top = new node (); If (! Top) return false; top-> DATA = m; top-> next = temp; size ++; return true;} maze mazestack: Pop () // output stack {node temp; temp. data = Top-> data; temp. next = Top-> next; Delete top; Top = temp. next; size --; return temp. data;} maze mazestack: gettop () // gets the top element of the stack {return top-> data ;}
5. Main. cpp
#include"MazeStack.h"void main(){MazeMat matrix;matrix.initMaze();matrix.createMaze();matrix.FindWay();matrix.displayMaze();}
The specific procedure is as follows:
9 rows and 9 columns of the Maze:
2. the maze of 19 rows and 19 columns:
3. the maze of 29 rows and 29 columns:
The program implementation above the transformation from 2-dimension to 3-dimension is implemented on the two-dimensional plane using the console through C ++, which is obviously not vivid enough.
So I used qt5 + OpenGL to implement 3D effects.And can be operated with the mouse. QT is selected because it is also programmed in C ++. Therefore, the previously written program can be directly run without any changes.
Programming ideology:1. The first step is to use the previous program to generate the matrix of the Maze matrix. 2. Use the maze matrix information to generate 3D images. 3. Use the Perspective change function glulookat to constantly change the perspective, so as to simulate the scenario of a maze.
User Guide:1. the up and down keys control forward and backward. 2. The left and right keys control the left turn, right turn, and start at the top of the page. You can see the overall picture of the MAP and the position (yellow) of yourself on the map ). 4. Press the I key to enter the game mode. You can go through the maze, press the O key to exit the game mode, and go to the top view mode to view information. 5. Press the P key to display the accessible paths (green) from the entrance to the exit. 6. The entrances and exits are marked in red and green respectively.
The specific display effect is as follows:1. Initial situation (top view ):
2. Show accessible paths in the Top View:
3. In game mode:
4. displayed accessible paths in game mode:
5. Go to the top view to view the current position in game mode:
6. Arrival Exit:
Disadvantages of 3D effects: Because the texture contour is not obvious, the rotation chart is not obvious, and the moving stride is a little large. Without Multiple tests, there may be bugs.
Due to limited space, the code will not be pasted here. For specific source code and executable programs, see the following link:
[QT programming] 3d maze games