Advertisement
Guest User

Random Perfect Maze Generator with C++ by Jay Seong

a guest
Aug 5th, 2015
4,581
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.15 KB | None | 0 0
  1. /*******************************************************************************************
  2. * Name:             Jay Seong                                                              *
  3. * Description:      Randomly generates a perfect maze using depth-first search algorithm   *
  4. * Date:             02/11/2010                                                             *
  5. * Data Structures:  Double array of structs for cells, stack for back-tracking             *
  6. * Others:           fstream is used to save maze into a file                               *
  7. *                                                                                          *
  8. * NOTE: Transcribed from a YouTube video https://www.youtube.com/watch?v=EvAzVhAii_o by    *
  9. * Stephen Pendley to distribute for public use.  All credit for this version of the code   *
  10. * and it's original goes to Jay Seong.                                                     *
  11. *******************************************************************************************/
  12.  
  13. #include <iostream>
  14. #include <ctime>
  15. #include <windows.h>
  16. #include <conio.h>
  17. #include <stack>
  18. #include <fstream>
  19. #include "stdafx.h" //http://sourceforge.net/p/wpbdc/website/ci/master/tree/Judge/StdAfx.h
  20.  
  21. using namespace std;
  22.  
  23. /********************************
  24. * USED FOR THE SIZE OF THE MAZE *
  25. *   Must be an odd number for   *
  26. *    maze traversal reasons     *
  27. ********************************/
  28. #define SIZE 11
  29.  
  30. // CELL STRUCTURE
  31. struct Cell
  32. {
  33.     bool visited;
  34.     bool top_wall;
  35.     bool bot_wall;
  36.     bool left_wall;
  37.     bool right_wall;
  38.     char display;
  39. };
  40.  
  41. // FUNCTION DECLARATIONS
  42. void Initialize(Cell Level[][SIZE]);
  43. void ClearScreen();
  44. void Redraw(Cell Level[][SIZE]);
  45. void GenerateMaze(Cell Level[][SIZE], int &posX, int &posY, int &goalX, int &goalY);
  46. void SaveMaze(Cell Level[][SIZE]);
  47.  
  48. // MAIN
  49. int main() {
  50.     Cell Level[SIZE][SIZE];
  51.     int posX = 0;
  52.     int posY = 0;
  53.     int goalX = 0;
  54.     int goalY = 0;
  55.     bool game_over = false;
  56.  
  57.     while(!game_over) {
  58.         system("cls");
  59.         Initialize(Level);
  60.         Redraw(Level);
  61.         GenerateMaze(Level, posX, posY, goalX, goalY);
  62.         SaveMaze(Level);
  63.  
  64.         char input;
  65.         cout << "Create a new Maze? (Y)/(N): ";
  66.         cin >> input;
  67.  
  68.         if((input != 'n') && (input != 'N') && (input != 'y') && (input != 'Y'))
  69.             cout << "Invalid option" << endl;
  70.         else if((input == 'n') || (input == 'N')) {
  71.             game_over = true;
  72.             cout << "Good bye!" << endl;
  73.         }
  74.     }
  75.  
  76.     _getch();
  77.     return 0;
  78. }
  79.  
  80. // INITIALIZE MAZE
  81. void Initialize(Cell Level[][SIZE]) {
  82.     for(int i=0; i<SIZE; i++) {
  83.         for(int j=0; j<SIZE; j++) {
  84.             Level[i][j].display = '*';
  85.             Level[i][j].visited = false;
  86.             Level[i][j].top_wall = true;
  87.             Level[i][j].bot_wall = true;
  88.             Level[i][j].left_wall = true;
  89.             Level[i][j].right_wall = true;
  90.         }
  91.     }
  92.     for(int i=1; i<SIZE-1; i++) {
  93.         for(int j=1; j<SIZE-1; j++) {
  94.             // Border Cells have fewer accessible walls
  95.             Level[1][j].top_wall = false;
  96.             Level[SIZE-2][j].bot_wall = false;
  97.             Level[i][1].left_wall = false;
  98.             Level[i][SIZE-2].right_wall = false;
  99.         }
  100.     }
  101. }
  102.  
  103. // CLEAR SCREEN
  104. void ClearScreen()
  105. {
  106.     HANDLE hOut;
  107.     COORD Position;
  108.     hOut = GetStdHandle(STD_OUTPUT_HANDLE);
  109.     Position.X = 0;
  110.     Position.Y = 0;
  111.     SetConsoleCursorPosition(hOut, Position);
  112. }
  113.  
  114. // REDRAW MAZE
  115. void Redraw(Cell Level[][SIZE]) {
  116.     for(int i=0; i<SIZE; i++) {
  117.         cout << endl;
  118.         for(int j=0; j< SIZE; j++)
  119.             cout << " " << Level[i][j].display;
  120.     }
  121. }
  122.  
  123. // GENERATE MAZE
  124. void GenerateMaze(Cell Level[][SIZE], int &posX, int &posY, int &goalX, int &goalY) {
  125.     srand((unsigned)time(NULL));                                            // Pick random start cell
  126.     int random = 0;
  127.     int randomX = ((2*rand())+1)%(SIZE-1);                      // Generate a random odd number between 1 and SIZE
  128.     int randomY = ((2*rand())+1)%(SIZE-1);                      // Generate a random odd number between 1 and SIZE
  129.     posX = randomX;                                             // Save player's initial X position
  130.     posY = randomY;                                             // Save player's initial Y position
  131.     int visitedCells = 1;
  132.     int totalCells = ((SIZE-1)/2)*((SIZE-1)/2);
  133.     int percent = 0;
  134.     stack<int> back_trackX, back_trackY;                        // Stack is used to trace the reverse path
  135.  
  136.     Level[randomY][randomX].display = 'S';                      // Set S as the start cell
  137.     Level[randomY][randomX].visited = true;                     // Set start cell as visited;
  138.  
  139.     while(visitedCells < totalCells)
  140.     {
  141.         if(((Level[randomY-2][randomX].visited == false) && (Level[randomY][randomX].top_wall == true && Level[randomY-2][randomX].bot_wall == true)) ||
  142.            ((Level[randomY+2][randomX].visited == false) && (Level[randomY][randomX].bot_wall == true && Level[randomY+2][randomX].top_wall == true)) ||
  143.            ((Level[randomY][randomX-2].visited == false) && (Level[randomY][randomX].left_wall == true && Level[randomY][randomX-2].right_wall == true)) ||
  144.            ((Level[randomY][randomX+2].visited == false) && (Level[randomY][randomX].right_wall == true && Level[randomY][randomX+2].left_wall == true)))
  145.         {
  146.             random = (rand() % 4) + 1;      // Pick a random wall 1-4 to knock down
  147.  
  148.              // GO UP
  149.             if((random == 1) && (randomY > 1)) {
  150.                 if(Level[randomY-2][randomX].visited == false) {    // If not visited
  151.                     Level[randomY-1][randomX].display = ' ';    // Delete display
  152.                     Level[randomY-1][randomX].visited = true;   // Mark cell as visited
  153.                     Level[randomY][randomX].top_wall = false;   // Knock down wall
  154.  
  155.                     back_trackX.push(randomX);          // Push X for back track
  156.                     back_trackY.push(randomY);          // Push Y for back track
  157.  
  158.                     randomY -= 2;                   // Move to next cell
  159.                     Level[randomY][randomX].visited = true;     // Mark cell moved to as visited
  160.                     Level[randomY][randomX].display = ' ';      // Update path
  161.                     Level[randomY][randomX].bot_wall = false;   // Knock down wall
  162.                     visitedCells++;                 // Increase visitedCells counter
  163.                 }
  164.                 else
  165.                     continue;
  166.             }
  167.  
  168.             // GO DOWN
  169.             else if((random == 2) && (randomY < SIZE-2)) {
  170.                 if(Level[randomY+2][randomX].visited == false) {    // If not visited
  171.                     Level[randomY+1][randomX].display = ' ';    // Delete display
  172.                     Level[randomY+1][randomX].visited = true;   // Mark cell as visited
  173.                     Level[randomY][randomX].bot_wall = false;   // Knock down wall
  174.  
  175.                     back_trackX.push(randomX);          // Push X for back track
  176.                     back_trackY.push(randomY);          // Push Y for back track
  177.  
  178.                     randomY += 2;                   // Move to next cell
  179.                     Level[randomY][randomX].visited = true;     // Mark cell moved to as visited
  180.                     Level[randomY][randomX].display = ' ';      // Update path
  181.                     Level[randomY][randomX].top_wall = false;   // Knock down wall
  182.                     visitedCells++;                 // Increase visitedCells counter
  183.                 }
  184.                 else
  185.                     continue;
  186.             }
  187.  
  188.             // GO LEFT
  189.             else if((random == 3) && (randomX > 1)) {
  190.                 if(Level[randomY][randomX-2].visited == false) {    // If not visited
  191.                     Level[randomY][randomX-1].display = ' ';    // Delete display
  192.                     Level[randomY][randomX-1].visited = true;   // Mark cell as visited
  193.                     Level[randomY][randomX].left_wall = false;  // Knock down wall
  194.  
  195.                     back_trackX.push(randomX);          // Push X for back track
  196.                     back_trackY.push(randomY);          // Push Y for back track
  197.  
  198.                     randomX -= 2;                   // Move to next cell
  199.                     Level[randomY][randomX].visited = true;     // Mark cell moved to as visited
  200.                     Level[randomY][randomX].display = ' ';      // Update path
  201.                     Level[randomY][randomX].right_wall = false; // Knock down wall
  202.                     visitedCells++;                 // Increase visitedCells counter
  203.                 }
  204.                 else
  205.                     continue;
  206.             }
  207.  
  208.             // GO RIGHT
  209.             else if((random == 4) && (randomX < SIZE-2)) {
  210.                 if(Level[randomY][randomX+2].visited == false) {    // If not visited
  211.                     Level[randomY][randomX+1].display = ' ';    // Delete display
  212.                     Level[randomY][randomX+1].visited = true;   // Mark cell as visited
  213.                     Level[randomY][randomX].right_wall = false; // Knock down wall
  214.  
  215.                     back_trackX.push(randomX);          // Push X for back track
  216.                     back_trackY.push(randomY);          // Push Y for back track
  217.  
  218.                     randomX += 2;                   // Move to next cell
  219.                     Level[randomY][randomX].visited = true;     // Mark cell moved to as visited
  220.                     Level[randomY][randomX].display = ' ';      // Update path
  221.                     Level[randomY][randomX].left_wall = false;  // Knock down wall
  222.                     visitedCells++;                 // Increase visitedCells counter
  223.                 }
  224.                 else
  225.                     continue;
  226.             }
  227.  
  228.             percent = (visitedCells*100/totalCells*100)/100;        // Progress in percentage
  229.             cout << endl << "   Generating a Random Maze... " << percent << "%" << endl;
  230.         }
  231.         else {
  232.             randomX = back_trackX.top();
  233.             back_trackX.pop();
  234.  
  235.             randomY = back_trackY.top();
  236.             back_trackY.pop();
  237.         }
  238.  
  239.         ClearScreen();
  240.         Redraw(Level);
  241.     }
  242.  
  243.     goalX = randomX;
  244.     goalY = randomY;
  245.     Level[goalY][goalX].display = 'E';
  246.     system("cls");
  247.     ClearScreen();
  248.     Redraw(Level);
  249.     cout << endl << "\a\t   Complete!" << endl;
  250. }
  251.  
  252. // SAVE MAZE
  253. void SaveMaze(Cell Level[][SIZE]) {
  254.     ofstream output;
  255.     char file[20];
  256.     char input;
  257.  
  258.     cout << endl << "Save Maze? (Y)/(N): ";
  259.     cin >> input;
  260.  
  261.     if ((input == 'y') || (input == 'Y')) {
  262.         cout << endl << "Save as: ";
  263.         cin >> file;
  264.  
  265.         output.open(file);
  266.  
  267.         for (int i = 0; i < SIZE; i++) {
  268.             output << endl;
  269.             for (int j = 0; j < SIZE; j++) {
  270.                 output << Level[i][j].display << " ";
  271.             }
  272.         }
  273.  
  274.         cout << "Maze has been saved to" << "\"" << file << "\"" << endl;
  275.         output.close();
  276.     }
  277.  
  278. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement