maze/code.cpp
2024-04-06 17:35:11 +08:00

332 lines
7.6 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <utility>
#include <conio.h>
#include <windows.h>
using namespace std;
// 显示区域的大小
const size_t sWidth = 60, sHeight = 24;
// 迷宫的实际大小(必须是奇数!)
const size_t width = 33, height = 15;
const char wall = 1;
const char path = 0;
const char target = 2;
// 地图
char map[height][width];
bool fog[height][width];
bool walk[height][width];
// 带凿墙列表
vector<pair<pair<int, int>, int> > walls;
/*
随机prim算法的核心是
1、让迷宫全是墙
2、选一个格作为迷宫的通路然后把它的邻墙放入列表
3、当列表里还有墙时
——1、从列表里随机选一个墙如果它对面的格子不是迷宫的通路
————1、把墙打通让对面的格子成为迷宫的通路
————2、把那个格子的邻墙加入列表
——2、如果对面的格子已经是通路了那就从列表里移除这面墙
*/
enum Dir { Up, Down, Left, Right };
// 四周一步
int xx[] = { 0, 0, -1, 1 };
int yy[] = { -1, 1, 0, 0 };
// 四周两步
int x2[] = { 0, 0, -2, 2 };
int y2[] = { -2, 2, 0, 0 };
// 玩家坐标
int playerx;
int playery;
int SPX;
int SPY;
const int margin = 3;
// 移动光标到xy位置
void gotoxy(int x, int y)
{
COORD coord = { (short)x, (short)y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
// 设置全地图为墙
void setAllWall()
{
for (int y = 0; y < height; ++y)
for (int x = 0; x < width; ++x)
map[y][x] = wall;
}
// 是否越界
bool isOutBounds(int x, int y)
{
return (x<0 || x >= width
|| y<0 || y >= height);
}
// 向四周探索
void explore(int x, int y)
{
// 遍历四个方向
for (int i = 0; i < 4; ++i)
{
// 顺着一条路走
for (int x1 = x, y1 = y;
!isOutBounds(x1, y1)
&& map[y1][x1] == path;
x1 += xx[i], y1 += yy[i])
{
// 每走一个格子检查四周是否为通路
for (int fy = y1 - 1; fy <= y1 + 1; ++fy)
for (int fx = x1 - 1; fx <= x1 + 1; ++fx)
if (!isOutBounds(fx, fy)
&& fog[fy][fx])
fog[fy][fx] = false;
}
}
}
// 将坐标处的墙添加到待通墙中
void pushAroundWall(int x, int y)
{
// 遍历四个方向
for (int i = 0; i < 4; ++i)
{
int tx = x + xx[i];
int ty = y + yy[i];
if (isOutBounds(tx, ty))
continue;
int wx = x + x2[i];
int wy = y + y2[i];
if (isOutBounds(wx, wy))
continue;
// 只要是墙就加入列表
if (map[ty][tx] == wall)
walls.push_back(pair<pair<int, int>, int>(pair<int, int>( tx,ty ),i ));
}
}
// 展示地图
void showMap()
{
int dx = sWidth / 2 - playerx;
int dy = sHeight / 2 - playery;
// 移动光标到最开始的位置
gotoxy(0, 0);
// 遍历整个地图
for (int sy = 0; sy < sHeight; ++sy)
{
for (int sx = 0; sx < sWidth; ++sx)
{
//putchar(map[y][x]?'@':' ');
int x = sx - dx;
int y = sy - dy;
const char *Symbol[5] = { "", "", "", "", "" };
if (isOutBounds(x, y))
{
printf("");
continue;
}
if (x == playerx && y == playery)
{
printf("");
continue;
}
if (fog[y][x])
{
printf("");
continue;
}
if (!walk[y][x])
{
printf("");
continue;
}
if (map[y][x] == path)
{
printf("");
continue;
}
if (map[y][x] == target)
{
printf("");
continue;
}
printf("");
continue;
// 到此截断,后面为单字符地图时用
// int d = 0;
// for (int i = 0; i < 4; ++i)
// {
// if (!isOutBounds(x + xx[i], y + yy[i]) && map[y + yy[i]][x + xx[i]] == wall)
// d |= 1 << i;
// }
// const int up = 1;
// const int down = 2;
// const int left = 4;
// const int right = 8;
// char ch = 0;
// switch (d)
// {
// case 0:
// ch = '&';
// break;
// //case up:
// //case down:
// case up | down:
// ch = '|';
// break;
// //case left:
// //case right:
// case left | right:
// ch = '-';
// break;
// default:
// ch = '+';
// }
// putchar(ch);
}
cout << endl;
}
//gotoxy(sWidth/2+1, sHeight/2+1);
//putchar('A');
}
// 生成地图算法,参数为起始点坐标
void generate(int cx, int cy)
{
// 首先将地图全部设置为墙
setAllWall();
// 填满迷雾,清空已经走过的路径
for (int i = 0; i < width*height; ++i)
*((bool*)fog + i) = *((bool*)walk + i) = true;
//设置玩家的坐标
playerx = cx;
playery = cy;
// 从起点开始,将四周的墙壁添加到待凿列表中
pushAroundWall(cx, cy);
// 把这个点变成路
map[cy][cx] = path;
// 只要还有待凿的墙,就一直循环
while (!walls.empty())
{
// 随机找个待凿的墙
int index = rand() % walls.size();
int wx = walls[index].first.first;
int wy = walls[index].first.second;
int d = walls[index].second;
// 如果是墙,打穿,将下一个点四周的墙壁加入待凿列表
if (map[wy + yy[d]][wx + xx[d]] == wall)
{
map[wy][wx] = path;
map[wy + yy[d]][wx + xx[d]] = path;
pushAroundWall(wx + xx[d], wy + yy[d]);
}
// 打穿后,将该墙移除待凿列表
walls.erase(walls.begin() + index);
}
map[height-2][width-2] = target;
// 展开迷雾
explore(playerx, playery);
}
// 玩家移动,参数是移动的方向
bool playerMove(Dir dir)
{
if (0 > dir || dir >= 4)
return false;
int tx = playerx + xx[dir];
int ty = playery + yy[dir];
if (isOutBounds(tx, ty))
return false;
if (map[ty][tx] == wall)
return false;
if (map[ty][tx] == target)
{
system("cls");
cout << "游戏胜利!" << endl;
system("pause");
return true;
}
// 只有是路的时候才可以移动
if (map[ty][tx] == path) {
playerx = tx, playery = ty;
walk[ty][tx] = false;
}
// 移动完后再次探索迷雾
explore(playerx, playery);
return false;
}
// 每一帧执行更新
bool updata()
{
char ch = getch();
bool win = false;
switch (ch)
{
case 'w':
win = playerMove(Dir::Up);
break;
case 's':
win = playerMove(Dir::Down);
break;
case 'a':
win = playerMove(Dir::Left);
break;
case 'd':
win = playerMove(Dir::Right);
break;
case 'q':
exit(0);
break;
case 'r':
return false;
break;
}
return !win;
}
int main()
{
// 设置种子
srand((unsigned int)time(0));
printf("WSAD移动Q退出R重开");
system("pause");
while (true) {
// 生成地图
generate(1, 1);
// 游戏循环
do {
// 输出地图
showMap();
} while (updata());
}
return 0;
}