上文:[摸鱼] 用冰茶姬生成随机迷宫
赶紧补完这个坑,,自己写的破游戏被班长丢到了班级活动里简直羞耻得要死(/ω\)
针对上次迷宫进行了细节优化,并添加了双人对战功能。
# 双人对战功能添加
# 写在前面
(吐血.jpg)。。这就叫软件的维护吗_(:з」∠)_
面对自己的代码楞半天 不知道怎么改,感慨之至遂作此画:
<img src = "https://s1.ax1x.com/2020/10/28/B1MqVH.png" width = "600px">
以后一定要记得给自己留一条后路 TAT
# 实现方法
通过代码复制(正经脸),改成两个人。检测到键盘输入时,判断哪个玩家移动了,进行相应移动,另一个玩家原地不动,分别输出新的位置就 OK 啦。详见代码叭 (「・ω・)「
# 功能优化
# 闪屏严重问题
上次代码是这样写的:
if (kbhit()) | |
{ | |
getch(); | |
char op = getch(); | |
system("cls"); | |
MAZE_Print(); | |
blabla... |
每次都输出一次地图。。能不闪屏么。。
解决方法:只更新角色位置。将光标定位在角色位置,输出 '\b' 和空格 清除角色,再重新输出即可。
# 出入口不明确
被小伙伴说不知道往哪走~~(迷宫从左上走到右下不是常识么)~~。
解决方法:左上和右下再挖掉一面墙就能看出来了。。感谢 @Dragon_Hao (还木有链接..) 协助修改。
虽然思路很简单,改这段代码的时候可费劲了(躺),吸取教训吸取教训..
# 控制台输出方阵难看
于是就把迷宫改成了长宽不一样的,让控制台里看上去方方的 hhh
其实用全角字符可以一下子占两格,看上去就方了 emmm
# 简化部分代码
QwQ.. 拆函数呗..
水完啦水完啦,,上代码 (๑>ڡ<)☆
Code:
#include <cstdio> | |
#include <iostream> | |
#include <cstdlib> | |
#include <windows.h> | |
#include <conio.h> | |
#include <time.h> | |
#define rep(i, s, t) for (int i = s; i <= t; i++) | |
using namespace std; | |
const int N = 1e3 + 10; | |
int Row, Col, Seed; | |
char Map[N][N]; | |
bool Vis_Map[N][N]; | |
int X1 = 2, X2 = 2, Y1 = 1, Y2 = 1; // 两人物位置坐标 | |
struct Disjoint_Set | |
{ | |
int Father, Size = 1; | |
} D_Set[N * N]; | |
int GetID(int i, int j) // 获取节点编号 | |
{ | |
return (i - 1) * Col + j; | |
} | |
int GetFa(int x) | |
{ | |
return D_Set[x].Father == x ? x : D_Set[x].Father = GetFa(D_Set[x].Father); | |
} | |
void D_Merge(int x, int y, int i, int j) | |
{ | |
int Fx = GetFa(x), Fy = GetFa(y); | |
if (Fx == Fy) | |
return; | |
if (D_Set[Fx].Size < D_Set[Fy].Size) | |
swap(Fx, Fy); | |
D_Set[Fy].Father = Fx; | |
D_Set[Fx].Size += D_Set[Fy].Size; | |
Vis_Map[i][j] = 1; | |
return; | |
} | |
void Build() // 建立迷宫 | |
{ | |
//init | |
srand(Seed); | |
rep(i, 1, Row) | |
rep(j, 1, Col) | |
{ | |
D_Set[GetID(i, j)].Father = GetID(i, j); | |
if (i == 1 || j == 1 || i == Row || j == Col) | |
Map[i][j] = '#'; | |
else if (i & 1 && j & 1) | |
Map[i][j] = '#'; | |
else if (i & 1 || j & 1) | |
Map[i][j] = '*'; | |
else | |
Map[i][j] = ' '; | |
} | |
//build | |
while (D_Set[GetFa(GetID(2, 2))].Size != (Row / 2) * (Col / 2)) | |
{ | |
int i, j; | |
do | |
{ | |
i = rand() % Row + 1, j = rand() % Col + 1; | |
} while (Map[i][j] != '*' || Vis_Map[i][j]); | |
if (Map[i][j + 1] == '#') | |
D_Merge(GetID(i - 1, j), GetID(i + 1, j), i, j); | |
else | |
D_Merge(GetID(i, j - 1), GetID(i, j + 1), i, j); | |
} | |
rep(i, 1, Row) | |
rep(j, 1, Col) | |
if (Map[i][j] == '*') | |
if (Vis_Map[i][j]) | |
Map[i][j] = ' '; | |
else Map[i][j] = '#'; | |
} | |
void MAZE_Print() | |
{ | |
Map[2][1] = ' '; // 挖墙 qwq | |
Map[Row][Col - 1] = ' '; | |
rep(i, 1, Row) | |
{ | |
rep(j, 1, Col) | |
printf("%c", Map[i][j]); | |
printf("\n"); | |
} | |
} | |
void Set_Handle(int x, int y) // 改变光标位置,单独拆开来写了 | |
{ | |
COORD pos = {y, x - 1}; | |
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); | |
SetConsoleCursorPosition(hOutput, pos); | |
} | |
void Hide_Cursor() // 隐藏光标闪烁 | |
{ | |
HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE); | |
CONSOLE_CURSOR_INFO CursorInfo; | |
GetConsoleCursorInfo(Handle, &CursorInfo); | |
CursorInfo.bVisible = 0; | |
SetConsoleCursorInfo(Handle, &CursorInfo); | |
} | |
void Process(int dx, int dy) | |
{ | |
Set_Handle(X1, Y1); | |
printf("\b "); | |
int tx = X1 + dx, ty = Y1 + dy; | |
if (tx == Row && ty == Col - 1) // 胜利条件 | |
{ | |
Set_Handle(Row + 1, 0); | |
printf("P1 win!\n"); | |
system("pause"); | |
exit(0); | |
} | |
if (Map[tx][ty] == '#' || ty < 1) | |
Set_Handle(X1, Y1); | |
else | |
Set_Handle(X1 = tx, Y1 = ty); | |
if (X1 == X2 && Y1 == Y2) // 判断两个角色重合 | |
printf("\bO"); | |
else | |
printf("\b@"); | |
} | |
void Process2(int dx, int dy) // 这边好像也可以压到上个函数里 emm? | |
{ | |
Set_Handle(X2, Y2); | |
printf("\b "); | |
int tx = X2 + dx, ty = Y2 + dy; | |
if (tx == Row && ty == Col - 1) // 胜利条件 | |
{ | |
Set_Handle(Row + 1, 0); | |
printf("P2 win!\n"); | |
system("pause"); | |
exit(0); | |
} | |
if (Map[tx][ty] == '#' || ty < 1) | |
Set_Handle(X2, Y2); | |
else | |
Set_Handle(X2 = tx, Y2 = ty); | |
if (X1 == X2 && Y1 == Y2) // 判断两个角色重合 | |
printf("\bO"); | |
else | |
printf("\b$"); | |
} | |
void Update() // 持续获取键盘信息,更新状态 | |
{ | |
while (1) | |
{ | |
if (kbhit()) | |
{ | |
Hide_Cursor(); | |
char op1 = getch(); | |
if (op1 == -32) | |
{ | |
char op = getch(); // 上下左右 72, 80, 75, 77 | |
switch (op) | |
{ | |
case 72: | |
Process(-1, 0); | |
break; | |
case 80: | |
Process(1, 0); | |
break; | |
case 75: | |
Process(0, -1); | |
break; | |
case 77: | |
Process(0, 1); | |
break; | |
default: | |
Process(0, 0); | |
} | |
Process2(0, 0); // 另一个角色不动 | |
} | |
else | |
{ | |
if (op1 < 'a') // 切换大小写方便判断 | |
op1 += 32; | |
switch (op1) | |
{ | |
case 'w': | |
Process2(-1, 0); | |
break; | |
case 's': | |
Process2(1, 0); | |
break; | |
case 'a': | |
Process2(0, -1); | |
break; | |
case 'd': | |
Process2(0, 1); | |
break; | |
default: | |
Process2(0, 0); | |
} | |
Process(0, 0); // 另一个角色不动 | |
} | |
} | |
// Sleep(20); | |
} | |
} | |
void init() | |
{ | |
printf("请选择迷宫大小:(输入序号)\n 1. 小\n 2. 中\n 3. 大\n 4. 巨大\n"); | |
scanf("%d", &Row); | |
switch (Row) | |
{ | |
case 1: | |
Row = 11, Col = 21; | |
break; | |
case 2: | |
Row = 21, Col = 41; | |
break; | |
case 3: | |
Row = 31, Col = 61; | |
break; | |
case 4: | |
Row = 37, Col = 81; | |
break; | |
} | |
printf("输入地图种子:\n"); | |
scanf("%d", &Seed); | |
system("cls"); | |
printf("生成中"); | |
Sleep(500); | |
printf("."); | |
Sleep(500); | |
printf("."); | |
Sleep(500); | |
printf("."); | |
system("cls"); | |
} | |
int main() | |
{ | |
init(); | |
Hide_Cursor(); | |
Build(); | |
MAZE_Print(); | |
Process(0, 0); | |
Process2(0, 0); | |
Update(); | |
system("pause"); | |
return 0; | |
} |
效果图:
<img src = "https://s1.ax1x.com/2020/10/28/B1GxRs.png" width = "500px">
反正咱已经废了 Orz