趣味编程之迷宫游戏
昨天正式开始带两个孩子学习c语言编程,为了让他们能主动的记录下来进步成长的足迹,要求他们进入csdn 程序开发者社区,注册,并发布他们的第一个hello world 程序的博客文章,布置完作业后才想到自己作为12年社区成员还没有都没有在社区发布过一篇文章,惭愧呀,万一孩子们不会问我,我也不会,还怎么当孩子们的老师呀,赶快试着模拟做了一遍我留给孩子的作业。让人欣慰的是两个孩子很积极的完成了作业,很高兴。希望两个孩子在这个开发者社区,好好学习天天向上。
今天作为第二个作业,我就想起了大学时肖老师教我们的经典迷宫程序,想起来当时刚学编程的同学们很是兴奋。所以今天就选这个题目吧
关于迷宫的背景知识我在开发者社区找了一下
https://blog.csdn.net/weixin_43401438/article/details/84110307?
这个链接比较经典。感谢作者。
孩子们的作业是
1 下载该代码,在你的电脑上调试成功运行。
2 然后把原文中的算法思路用csdn 插入流程图的形式表达出来
3 你认为代码中那一段写的比较精彩,为什么
4.自己消化吸收,三个月后,自己从一个空白的文件开始写出自己的迷宫程序
另外我在社区里找到一段代码,调试了一下,感觉很新颖,可惜忘记是哪个链接了,如果你发现我用了你的代码,可以告诉我。我把你的链接见到这里。
这个类似最早期游戏的程序,可以用光标移动上下左右键,实现单步迷宫前进,写的很是简洁,用递归的方法实现了迷宫的随机初始化。我增加了一段小代码,完成自动寻路的表达,当按下空格键,实现自动的寻找路径的过程。
希望两个同学
1.增加上一个示例中路径标示
2.增加查找最优路径的,什么是最优路径,就是从入口到出口路径最短的一条通路。
以下代码是在vc2017下编译调试通过的
// mazedemo.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#define Height 25 //迷宫的高度,必须为奇数
#define Width 25 //迷宫的宽度,必须为奇数
#define Wall 1
#define Road 0
#define Start 2
#define End 3
#define Esc 5
#define Up 1
#define Down 2
#define Left 3
#define Right 4
#define Auto 6
int map[Height + 2][Width + 2];
int mask[Height + 2][Width + 2];
int RecordX[(Height + 2)*(Width + 2) + 10];
int RecordY[(Height + 2)*(Width + 2) + 10];
int RecordFX[(Height + 2)*(Width + 2) + 10];
int StepX[4];
int StepY[4];
void gotoxy(int x, int y) //移动坐标
{
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void hidden()//隐藏光标
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut, &cci);
cci.bVisible = 0;//赋1为显示,赋0为隐藏
SetConsoleCursorInfo(hOut, &cci);
}
void create(int x, int y) //随机生成迷宫
{
int c[4][2] = { 0,1,1,0,0,-1,-1,0 }; //四个方向
int i, j, t;
//将方向打乱
for (i = 0; i < 4; i++)
{
j = rand() % 4;
t = c[i][0]; c[i][0] = c[j][0]; c[j][0] = t;
t = c[i][1]; c[i][1] = c[j][1]; c[j][1] = t;
}
map[x][y] = Road;
for (i = 0; i < 4; i++)
if (map[x + 2 * c[i][0]][y + 2 * c[i][1]] == Wall)
{
map[x + c[i][0]][y + c[i][1]] = Road;
create(x + 2 * c[i][0], y + 2 * c[i][1]);
}
}
int get_key() //接收按键
{
char c;
while (c = _getch())
{
if (c == ' ') return Auto;//空格
if (c == 27) return Esc; //Esc
if (c != -32)continue;
c = _getch();
if (c == 72) return Up; //上
if (c == 80) return Down; //下
if (c == 75) return Left; //左
if (c == 77) return Right; //右
}
return 0;
}
void paint(int x, int y) //画迷宫
{
gotoxy(2 * y - 2, x - 1);
switch (map[x][y])
{
case Start:
printf("入"); break; //画入口
case End:
printf("出"); break; //画出口
case Wall:
printf("▇"); break; //画墙
case Road:
printf(" "); break; //画路
}
}
void game()
{
int x = 2, y = 1; //玩家当前位置,刚开始在入口处
int c; //用来接收按键
int curr_step = 0;
int failflag = 0;
//右方向
StepX[0] = 0;
StepY[0] = 1;
//左方向
StepX[2] = 0;
StepY[2] = -1;
//下方向
StepX[1] = -1;
StepY[1] = 0;
//上方向
StepX[3] = 1;
StepY[3] = 0;
for (int i = 0; i < Height + 2; i++)
for (int j = 0; j < Width + 2; j++)
mask[i][j] = 0;
for (int i = 0; i < (Height + 2)*(Width + 2) + 10; i++)
{
RecordX[i] = 0;
RecordY[i] = 0;
RecordFX[i] = 0;
}
RecordX[0] = x;
RecordY[0] = y;
RecordFX[0] = 0;
mask[x][y] = 1;
c = 0;
while (failflag == 0)
{
gotoxy(2 * y - 2, x - 1);
printf("●"); //画出玩家当前位置
if (map[x][y] == End) //判断是否到达出口
{
for (int i = 1; i < curr_step; i++)
{
x = RecordX[i];
y = RecordY[i];
gotoxy(2 * y - 2, x - 1);
printf("* ");
}
gotoxy(30, 24);
printf("到达终点,按任意键结束");
_getch();
break;
}
if (c != Auto)
c = get_key();
else Sleep(100);
if (c == Esc)
{
gotoxy(0, 24);
break;
}
switch (c)
{
case Up: //向上走
if (map[x - 1][y] != Wall)
{
paint(x, y);
x--;
curr_step++;
RecordX[curr_step] = x;
RecordY[curr_step] = y;
RecordFX[curr_step] = 0;
}
break;
case Down: //向下走
if (map[x + 1][y] != Wall)
{
paint(x, y);
x++;
curr_step++;
RecordX[curr_step] = x;
RecordY[curr_step] = y;
RecordFX[curr_step] = 0;
}
break;
case Left: //向左走
if (map[x][y - 1] != Wall)
{
paint(x, y);
y--;
curr_step++;
RecordX[curr_step] = x;
RecordY[curr_step] = y;
RecordFX[curr_step] = 0;
}
break;
case Right: //向右走
if (map[x][y + 1] != Wall)
{
paint(x, y);
y++;
curr_step++;
RecordX[curr_step] = x;
RecordY[curr_step] = y;
RecordFX[curr_step] = 0;
}
break;
case Auto:
//自动走
if (1)
{
int mflag = 0;
for (int m = RecordFX[curr_step]; m < 4; m++)
{
int x1, y1;
x1 = x + StepX[m];
y1 = y + StepY[m];
if (map[x1][y1] != Wall && mask[x1][y1] == 0)
{
paint(x, y);
x = x1;
y = y1;
RecordFX[curr_step] = m;
curr_step++;
RecordX[curr_step] = x;
RecordY[curr_step] = y;
mask[x][y] = 1;
RecordFX[curr_step] = 0;
mflag = 1;
break;
}
else RecordFX[curr_step] = m;
}
if (mflag == 0)
{
while (curr_step >= 0 && RecordFX[curr_step] == 3)
{
paint(x, y);
mask[x][y] = 0;
curr_step = curr_step - 1;
x = RecordX[curr_step];
y = RecordY[curr_step];
}
if (curr_step >= 0)
{
paint(x, y);
mask[x][y] = 0;
curr_step = curr_step - 1;
x = RecordX[curr_step];
y = RecordY[curr_step];
RecordFX[curr_step] = RecordFX[curr_step] + 1;
}
}
}
break;
}
if (curr_step == 0 && RecordFX[curr_step] == 4)
{
gotoxy(30, 24);
printf("无法到达终点,按任意键结束");
_getch();
break;
}
}
}
int main()
{
system("maze demo ");
int i, j;
srand((unsigned)time(NULL)); //初始化随即种子
hidden(); //隐藏光标
for (i = 0; i <= Height + 1; i++)
for (j = 0; j <= Width + 1; j++)
if (i == 0 || i == Height + 1 || j == 0 || j == Width + 1) //初始化迷宫
map[i][j] = Road;
else map[i][j] = Wall;
create(2 * (rand() % (Height / 2) + 1), 2 * (rand() % (Width / 2) + 1)); //从随机一个点开始生成迷宫,该点行列都为偶数
for (i = 0; i <= Height + 1; i++) //边界处理
{
map[i][0] = Wall;
map[i][Width + 1] = Wall;
}
for (j = 0; j <= Width + 1; j++) //边界处理
{
map[0][j] = Wall;
map[Height + 1][j] = Wall;
}
map[2][1] = Start; //给定入口
map[Height - 1][Width] = End; //给定出口
for (i = 1; i <= Height; i++)
for (j = 1; j <= Width; j++) //画出迷宫
paint(i, j);
game(); //开始游戏
_getch();
return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单
// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件