#include <iostream>
 #include<stdio.h>
 #include<windows.h>
 #include<conio.h>
 #include<time.h>
 #include<math.h>
 #include <fstream>
 #include <cstdlib>
 #define WALL  0 //墙 
 #define ROAD 1 //路径 
 #define PLAYER 2//玩家  //控制迷宫的复杂度,数值越大迷宫难度越小,最小值为0
 //默认为简单难度,可以在degree函数里调整不同难度
 int Rank = 6;//控制迷宫的大小,数值越大迷宫越大,最小值为8
 //默认为中等,可以在mazesize函数里调整不同大小
 int L = 32; void menu();   //主菜单界面
 void start();  //开始游戏
 void degree(); //游戏难度
 void mazesize();//迷宫大小
 void explain();//游戏说明
 void tips();//游戏提示
 int init(int** Maze);  //初始化迷宫
 void paint(int** Maze);//画迷宫
 void CreateMaze(int** maze, int x, int y);    //创建迷宫
 void move(int** Maze, char t, int* x, int* y);//移动角色//主函数
 int main() 
 {
     
     menu();
     return 0;
 }//主菜单
 void menu() 
 { 
     
     while (1) 
     {
         system("cls"); //清屏
         char c;
         printf("====================迷宫游戏==================");
         printf("\n==============================================\n");
         printf("\n||               1. 开始游戏                ||\n");
         printf("\n||               2. 游戏说明                ||\n");
         printf("\n||               3. 游戏难度                ||\n");
         printf("\n||               4. 迷宫大小                ||\n");
         printf("\n||               5. 游戏提示                ||\n");
         printf("\n||               6. 退出游戏                ||\n");
         printf("\n||                                          ||\n");
         printf("\n||     温馨提示:游戏前请查看游戏说明       ||\n");
         printf("\n||            作者:软件19-6 李海玮         ||\n");
         printf("==============================================\n");
         c = _getch();    //不回显函数
         switch (c) {
         case '1':
             start();
             break;  //开始一局游戏
         case '2':
             explain();
             break;  //进入游戏说明界面
         case '3':
             degree();
             break;  //调整游戏难度 
         case '4':
             mazesize();
             break;  //调整迷宫大小 
         case '5':
             tips();
             break;  //查看游戏提示
         case '6':
             printf("\n游戏结束");
             Sleep(1000);
             exit(0);
             break;  //结束程序
         default:
             break;
         }
     }
 }//构建迷宫
 void CreateMaze(int** maze, int x, int y) 
 {
     maze[x][y] = ROAD;    //确保四个方向随机,而不再是固定的上下左右这种排列 
     int direction[4][2] = 
     { 
         { 1,0 },
         { -1,0 },
         { 0,-1 },
         { 0,1 } 
     };    int i, j;
     for (i = 0; i < 4; i++) 
     {
         int r = rand() % 4;
         int temp = direction[0][0];
         direction[0][0] = direction[r][0];
         direction[r][0] = temp;
         temp = direction[0][1];
         direction[0][1] = direction[r][1];
         direction[r][1] = temp;
     }    //向四个方向开挖
     for (i = 0; i < 4; i++)
     {
         int dx = x;
         int dy = y;
         //控制挖的距离,由Rank来调整大小
         int range = 1 + (Rank == 0 ? 0 : rand() % Rank);
         while (range > 0) 
         {
             //计算出将要访问到的坐标 
             dx += direction[i][0];
             dy += direction[i][1];
             //排除掉回头路
             if (maze[dx][dy] == ROAD)
             {
                 break;
             }
             //判断是否挖穿路径
             int count = 0, k;
             for (j = dx - 1; j < dx + 2; j++)
             {
                 for (k = dy - 1; k < dy + 2; k++) 
                 {
                     //abs(j - dx) + abs(k - dy) == 1 确保只判断九宫格的四个特定位置
                     if (abs(j - dx) + abs(k - dy) == 1 && maze[j][k] == ROAD) 
                     {
                         count++;
                     }
                 }
             }
             //count大于1表明墙体会被挖穿,停止 
             if (count > 1)
                 break;
             //确保不会挖穿时,前进
             range -= 1;
             maze[dx][dy] = ROAD;
         }
         //没有挖穿危险,以此为节点递归
         if (range <= 0) 
         {
             CreateMaze(maze, dx, dy);
         }
     }
 }//初始化迷宫
 int init(int** Maze) 
 {
     int i;
     for (i = 0; i < L; i++) 
     {
         Maze[i][0] = ROAD;
         Maze[0][i] = ROAD;
         Maze[i][L - 1] = ROAD;
         Maze[L - 1][i] = ROAD;
     }
     
     //创造迷宫,(2,2)为起点
     CreateMaze(Maze, 2, 2);
     
     //画迷宫的入口和出口,给出玩家初始位置
     Maze[2][1] = PLAYER;
     
     //寻找出口
     for (i = L - 3; i >= 0; i--) 
     {
         if (Maze[i][L - 3] == ROAD) 
         {
             Maze[i][L - 2] = ROAD;
             //返回出口所在的纵坐标 
             return i;
         }
     }
 }//画迷宫
 void paint(int** Maze) 
 {
     int i, j;
     for (i = 0; i < L; i++) 
     {
         for (j = 0; j < L; j++) 
         {
             if (Maze[i][j] == ROAD)
                 printf("  ");//表示道路
             else if (Maze[i][j] == WALL)
                 printf("■");//表示墙
             else
                 printf("人");//表示玩家
         }
         printf("\n");
     }
 }//移动角色
 void move(int** Maze, char t, int* x, int* y) 
 {
     int i = *x, j = *y;//记录原始位置
     switch (t) {
     case 'w':    //向上移动
         *x -= 1;
         break;
     case 72:    //向上移动
         *x -= 1;
         break;
     case 's':    //向下移动
         *x += 1;
         break;
     case 80:    //向下移动
         *x += 1;
         break;
     case 'a':    //向左移动
         *y -= 1;
         break;
     case 75:    //向左移动
         *y -= 1;
         break;
     case 'd':    //向右移动
         *y += 1;
         break;
     case 77:    //向右移动
         *y += 1;
         break;
     default:
         break;
     }
     //符合条件,移动
     if (*x >= 0 && *x < L - 1 && *y >= 0 && *y < L - 1 && Maze[*x][*y] != WALL) 
     {
         Maze[i][j] = 1;
         Maze[*x][*y] = 2;
     }
     //否则保持位置不变
     else 
     {
         *x = i;
         *y = j;
     }
 }//开始游戏 
 void start() 
 { 
     char c;
     //x,y表示角色横纵坐标, out表示出口的纵坐标
     int* p, * q;
     int x = 2, y = 1, out = 0, i = 0;
     p = &x;
     q = &y;
     //随机数发生器初始化函数
     srand((unsigned)time(NULL));
     //申请数组空间
     int** Maze = (int**)malloc(L * sizeof(int*));
     for (i = 0; i < L; i++) 
     {
         Maze[i] = (int*)calloc(L, sizeof(int));
     }
     //得到出口纵坐标
     out = init(Maze);    //游戏开始
     system("cls");
     paint(Maze);
     while (c = _getch()) 
     {
         if (c == 27)   //如果输入为ESC键,结束游戏回到主菜单
             break;
         system("cls");//清屏
         move(Maze, c, p, q);//根据输入t进行移动
         paint(Maze);//重新绘制迷宫
         //已经到出口,游戏结束
         if (x == out && y == L - 2) 
         {
             system("cls");
             printf("=============\n");
             printf("恭喜你,过关了\n");
             printf("=============\n");
             printf("即将返回主菜单……");
             Sleep(2000);//执行挂起一段时间,暂停1.5秒后打印
             break;
         }
     }    //一局游戏结束,释放内存 
     for (i = 0; i < L; i++) free(Maze[i]);
     free(Maze);
 }//操作说明
 void explain() 
 {  
     while (1) 
     {
         char c;
         system("cls");
         printf("=================================================\n");
         printf("迷宫游戏,游戏的操作如下:\n");
         printf("\n1.请全屏进行游戏,以获得更好的游戏体验\n");
         printf("\n2.先将输入法调整为英文(小写)\n");
         printf("\n3.可使用键盘的w,s,a,d四个键控制角色上下左右移动\n");
         printf("\n  或者使用键盘的↑,↓,←,→四个键控制角色上下左右移动\n");
         printf("\n4.在任意界面按“ESC”键都可以返回到主菜单\n");
         printf("\n5.获胜条件:移动角色到出口处\n");
         printf("\n6.在菜单中可以调整游戏难度\n");
         printf("\n7.在菜单中可以调整迷宫大小\n");
         printf("\n祝你游戏愉快!!!\n");
         printf("=================================================\n");
         c = _getch();  //不回显函数 
         switch (c) 
         {
             //ESC键的ASCII码值 
         case 27:
             //返回主菜单
             menu();
             break;
         default:
             break;
         }
     }
 }//调整游戏难度 
 void degree() 
 { 
     while (1) {
         char c;
         system("cls");
         printf("==============================\n");
         printf("输入1,2,3,4,5进行难度调整:\n");
         printf("\n||         1.入门         ||\n");
         printf("\n||         2.简单         ||\n");
         printf("\n||         3.中等         ||\n");
         printf("\n||         4.困难         ||\n");
         printf("\n||         5.极难         ||\n");
         printf("==============================\n");
         c = _getch();  //不回显函数 
         switch (c) {
         case '1':
             Rank = 10;
             printf("\n当前游戏难度为:入门,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '2':
             Rank = 8;
             printf("\n当前游戏难度为:简单,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '3':
             Rank = 6;
             printf("\n当前游戏难度为:中等,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '4':
             Rank = 3;
             printf("\n当前游戏难度为:困难,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '5':
             Rank = 0;
             printf("\n当前游戏难度为:极难,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case 27:
             menu();
             break;
         default:
             break;
         }
     }
 }//调整迷宫大小
 void mazesize()
 {
     while (1) {
         char c;
         system("cls");
         printf("==============================\n");
         printf("输入1,2,3,4,5,6,7进行大小调整:\n");
         printf("\n||         1.极小         ||\n");
         printf("\n||         2.小           ||\n");
         printf("\n||         3.略小         ||\n");
         printf("\n||         4.中等         ||\n");
         printf("\n||         5.略大         ||\n");
         printf("\n||         6.大           ||\n");
         printf("\n||         7.极大         ||\n");
         printf("==============================\n");
         c = _getch();  //不回显函数 
         switch (c) {
         case '1':
             L = 8;
             printf("\n当前游戏大小为:极小,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '2':
             L = 16;
             printf("\n当前游戏大小为:小,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '3':
             L = 24;
             printf("\n当前游戏大小为:略小,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '4':
             L = 32;
             printf("\n当前游戏大小为:中等,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '5':
             L = 40;
             printf("\n当前游戏大小为:略大,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '6':
             L = 48;
             printf("\n当前游戏大小为:大,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case '7':
             L = 56;
             printf("\n当前游戏大小为:极大,即将返回主菜单……");
             Sleep(2000);
             menu();//返回主菜单
             break;
         case 27:
             menu();
             break;
         default:
             break;
         }
     }
 }//游戏提示
 void tips()
 {
     while (1)
     {
         char c;
         system("cls");
         printf("亲爱的玩家,你遇到困难了吗?\n");
         system("pause");
         printf("请输入1.是\t2.否\n");
         c = _getch();
         switch (c)
         {
         case'1':
             printf("罗克说:“其实走迷宫可以不带线团,你按下面的三条规则去走,就能够走得进,也能够走得出”\n");
             system("pause");
             printf("让我给你3条提示吧\n");
             system("pause");
             printf("第一条,进入迷宫后,可以任选一条道路往前走\n");
             system("pause");
             printf("第二条,如果遇到走不通的死胡同,就马上返回,并在该路口做个记号;\n");
             system("pause");
             printf("第三条,如果遇到了叉路口,观察一下是否还有没有走过的通道。\n");
             system("pause");
             printf("有,就任选一条通道往前走;没有,就顺着原路返回原来的叉路口,并做个记号。\n");
             system("pause");
             printf("然后就重复第二条和第三条所说的走法,直到找到出口为止\n");
             system("pause");
             printf("如果要把迷宫所有地方都搜查到,还要加上一条,就是凡是没有做记号的通道都要走一遍。”\n");
         case'2':
             printf("即将返回主菜单……");
             Sleep(2000);
             menu();
             break;
         case 27:
             //返回主菜单
             menu();
             break;
         default:
             break;
         }
     }
 }