之前发了一个迷宫游戏,后面说要继续写,现在来填坑了!
编写说明
1.利用C语言创建了一个迷宫,实现用栈进行寻路,并打印出来
2.利用打印余清屏实现了简单的走迷宫游戏
算法思想
在此是说明大体思路,具体细节请看代码,我注释的还是比较详尽的。另外,我自己写的迷宫小游戏在这里不多叙述,有兴趣的话自己看一下。
(1)利用随机函数,二维数组,与递归思想随机产生一个迷宫
- 初始化迷宫,将迷宫中的数据全部赋予WALL(宏定义中有,代表0),并将迷宫最外围赋予ROUTE(宏定义中有,代表1),这样是为了防止将来创建迷宫时把迷宫挖穿。
- 创建迷宫,主要思路是:随机向迷宫的四个方向判断,如果是WALL,则将改点设置为ROUTE,否则换一个方向判断。递归调用改函数以生成迷宫。
- 利用随机函数随机生成迷宫入口,并利用指针将入口的值返回给主函数的in和out。
(2)实现栈,并利用栈进行迷宫寻路
- 利用结构体实现栈的结点,需要注意的是,该结构体中存储的数据是一个含有两个元素的数组,利用该数组存储迷宫的对应下标,可以以此控制迷宫。
- 编写入栈函数与出栈函数,要注意的是,在调用该函数之前,先要编写初始化栈的函数,并将迷宫入口的数据赋予栈的入口
- 我是直接利用if else语句对迷宫进行判断,如果是路,则进栈,并将原先的迷宫位置的数据该为WALL,如果四周全是WALL,则退栈。
- 这样可以找到迷宫的出口,但是也同样会破坏迷宫的结构,所以我将迷宫复制了一份,待栈走完后,利用栈中存储的迷宫位置的数据将迷宫相应位置的数据进行修改,方便最后打印迷宫
- 打印迷宫
运行结果插图:
源码如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 42 //迷宫区域大小,最外层是保护区
#define WALL 0 //表示该位置是墙 wall
#define ROUTE 1 //表示该位置是路 route
#define END 8 //打印路的标识符
typedef struct Stack{
int arr[2];//利用下标与迷宫对接,将maze[x][y]中的x,y分别存储在arr[0]与arr[1]中
struct Stack*next;
}Stack;//结构体,使用、实现栈(其实感觉和单链表差不多)
//函数声明
Stack* InitStack(int in, int(*maze)[N]);
Stack* CreatStack(int(*maze)[N], Stack*Top, int x, int y);
Stack* BackStack(int(*maze)[N], Stack*Top, int x, int y);
void FindMaze(Stack*Top, int(*maze)[N], int out);
void Endprint(int(*maze)[N], Stack*Top);
void CopyMaze(int(*maze1)[N], int(*maze2)[N]);
void InitMaze(int(*maze)[N]);
void CreatMaze(int(*maze)[N], int x, int y);
void print(int(*maze)[N]);
void CreatInAndOut(int(*maze)[N], int*in, int*out);
int Game(int *x, int *y, int(*maze)[N], int out, int direction);
int Decide(int x, int y, int direction, int(*maze)[N]);
//初始化栈(顺带创建了第一个栈)
Stack* InitStack(int in, int(*maze)[N]){
Stack*Top = (Stack*)malloc(sizeof(Stack));//该指针是头结点,即Top->next永远是栈顶
if (Top == NULL){
printf("栈初始化函数错误!\n");
return NULL;
}
Top->next = NULL;
Stack* L = (Stack*)malloc(sizeof(Stack));//重新创建一个指针,将迷宫入口赋予该栈
L->next = Top->next;
Top->next = L;
L->arr[0] = in;
L->arr[1] = 1;
*(*(maze + in) + 1) = WALL;//将口封住
return Top;
}
//头插入法创建栈,返回新的头结点
Stack* CreatStack(int(*maze)[N], Stack*Top, int x, int y) {
Stack*p = (Stack*)malloc(sizeof(Stack));
p->arr[0] = x;
p->arr[1] = y;
p->next = Top->next;
Top->next = p;
*(*(maze + x) + y) = WALL;
return Top;
}
//退栈,同进栈一样返回新的头结点
Stack* BackStack(int(*maze)[N], Stack*Top, int x, int y){
Stack*p = (Stack*)malloc(sizeof(Stack));
p = Top->next;
Top->next = Top->next->next;
free(p);
p = NULL;
return Top;
}
//迷宫寻路函数(该函数调用入栈与退栈函数)
void FindMaze(Stack*Top, int(*maze)[N], int out){
//若栈顶元素是迷宫出口,则循环结束
if ((Top->next)->arr[0] == out && (Top->next)->arr[1] == N - 2){
return;
}
int x = Top->next->arr[0];
int y = Top->next->arr[1];
if (*(*(maze + x) + y + 1) == ROUTE) {
//检测右方是不是路
FindMaze(CreatStack(maze, Top, x, y + 1) , maze, out);
}
else if (*(*(maze + x + 1) +y) == ROUTE) {
//检测上方是不是路
FindMaze(CreatStack(maze, Top, x + 1, y) , maze, out);
}
else if (*(*(maze + x - 1) +y) == ROUTE) {
//检测下方是不是路
FindMaze(CreatStack(maze, Top, x - 1, y), maze, out);
}
else if (*(*(maze + x) + y - 1) == ROUTE) {
//检测左方是不是路
FindMaze(CreatStack(maze, Top, x, y - 1), maze, out);
}
else{
//死路,退栈
FindMaze(BackStack(maze, Top, x, y) , maze, out);
}
}
//打印寻到的路径
void Endprint(int(*maze)[N],Stack*Top){
Top = Top->next;
while (Top != NULL){
int x = Top->arr[0];
int y = Top->arr[1];
*(*(maze + x) + y) = END;
Top = Top->next;
}
print(maze);
}
//初始化迷宫
void InitMaze(int(*maze)[N]){
//生成墙体
for (int i = 0; i < N; ++i){
for (int j = 0; j < N; ++j){
*(*(maze + i) + j) = WALL;
}
}
//迷宫外围保护,防止挖穿
for (int i = 0; i < N; ++i){
*(*(maze)+i) = ROUTE;
*(*(maze + N - 1) + i) = ROUTE;
*(*(maze + i)) = ROUTE;
*(*(maze + i) + N - 1) = ROUTE;
}
}
//递归创建迷宫,将其存储在二维数组maze[N][N]中(备注:迷宫创建的算法是参考CSDN上某位大佬的,我把链接放在这 https://blog.csdn.net/jjwwwww/article/details/106586256)
void CreatMaze(int(*maze)[N], int x, int y){
if (*(*(maze + x) + y) == WALL){//如果该出是墙体,则开始创建迷宫
//判断迷宫是否会形成环
if (*(*(maze + x + 1) + y) + *(*(maze + x - 1) + y) + *(*(maze + x) + y + 1) + *(*(maze + x) + y - 1) <= ROUTE) {
*(*(maze + x) + y) = ROUTE;//调用成功,将该位置设置为:路
int direction[4] = { 0, 1, 2, 3 };
for (int i = 4; i > 0; --i){//四个方向都要尝试
int ret = rand() % i;//随机生成 0 -- i-1 中的数 (0,1,2,3)
//交换,防止重复
int tmp = direction[ret];
direction[ret] = direction[i - 1];
direction[i - 1] = tmp;
//由于每次循环i都会变化,故不会出现重复的下标
switch (direction[i - 1]){
case 0:CreatMaze(maze, x - 1, y); break;//数组标记上移一位
case 1:CreatMaze(maze, x + 1, y); break;//数组标记下移一位
case 2:CreatMaze(maze, x, y - 1); break;//数组标记左移一位
case 3:CreatMaze(maze, x, y + 1); break;//数组标记右移一位
default: break;
}
}
}
}
}
//打印迷宫
void print(int(*maze)[N]){
for (int i = 0; i < N; ++i){
for (int j = 0; j < N; ++j){
if (*(*(maze + i) + j) == END){
printf("* ");
}
else if (*(*(maze + i) + j) == ROUTE){
printf(" ");
}
else printf("国");
}
printf("\n");
}
printf("\n");
}
//随机生成迷宫的入口与出口,将结果赋予两个指针参数
void CreatInAndOut(int(*maze)[N], int*in, int*out) {
int a, b;
int flag_a = 0;
int flag_b = 0;
while (1){
if (flag_a + flag_b == 2) {
break;
}
//产生下标与迷宫最外层相符的随机数,可以排除下标为1和N-2的位置
a = 2 + rand() % (N - 4);//随机产生 2 -- N-3 之间的数
b = 2 + rand() % (N - 4);
//由于传入的是指针,故无需返回值
if (*(*(maze + a) + 2) == ROUTE && flag_a == 0) {//若条件成立,则使指针in指向入口下标a
*in = a;
*(*(maze + a) + 1) = ROUTE;
flag_a = 1;
}
if (*(*(maze + b) + N - 3) == ROUTE && flag_b == 0) {//若条件成立,则使指针out指向入口下标b
*out = b;
*(*(maze + b) + N - 2) = ROUTE;
flag_b = 1;
}
}
}
//复制迷宫,防止接下寻路的时候来迷宫被破坏(将maze1的数据拷贝到maze2中)
void CopyMaze(int(*maze1)[N], int(*maze2)[N]) {
for (int i = 0; i < N; ++i){
for (int j = 0; j < N; ++j){
*(*(maze2 + i) + j) = *(*(maze1 + i) + j);
}
}
}
//进行迷宫游戏的函数
int Game(int *x, int *y, int(*maze)[N], int out, int direction){//这里要修改 x y 的值,故传入指针
switch (direction){
case 1://上移
*(*(maze + *(x)) + *(y)) = ROUTE;
*(*(maze + *(x)-1) + *(y)) = END;
*x = *x - 1;
break;
case 2://下移
*(*(maze + *(x)) + *(y)) = ROUTE;
*(*(maze + *(x)+1) + *(y)) = END;
*x = *x + 1;
break;
case 3://左移
*(*(maze + *(x)) + *(y)) = ROUTE;
*(*(maze + *(x)) + *(y)-1) = END;
*y = *y - 1;
break;
case 4://右移
*(*(maze + *(x)) + *(y)) = ROUTE;
*(*(maze + *(x)) + *(y)+1) = END;
*y = *y + 1;
break;
default:{
printf("数据有误!请重新输入!");
return 1;
}
}
if (*x == out&&*y == N - 2){
return 0;
}
else{
return 1;
}
}
//传入位置与想要移动的方向,判断移动后位置在迷宫里是否为路,若是返回1否则返回0
int Decide(int x, int y, int direction, int(*maze)[N]){
//direction的1,2,3,4,分别代表上下左右
if (direction<1 || direction>4){
printf("\n\t\t\t方向输入有误!");
system("pause");
printf("---------输入回车键继续....");
return 0;
}
//判断在迷宫所在方向是不是路
if (direction == 1){
//迷宫中向上移动
if (*(*(maze + x - 1) + y) == ROUTE){
return 1;
}
else{
return 0;
}
}
else if (direction == 2){
//迷宫中向下移动
if (*(*(maze + x + 1) + y) == ROUTE){
return 1;
}
else{
return 0;
}
}
else if (direction == 3){
//迷宫中向左移动
if (*(*(maze + x) + y - 1) == ROUTE){
return 1;
}
else{
return 0;
}
}
else{
//迷宫中向右移动
if (*(*(maze + x) + y + 1) == ROUTE){
return 1;
}
else{
return 0;
}
}
}
//主函数
int main(){
printf("\n\t\t-------------------------------------------------------------------------------------------------------------------------------");
printf("\n\t\t---------------------------声明:此程序在VS2013上编写,在该平台上使用 <.c> 与 <.cpp> 均能运行----------------------------------");
printf("\n\t\t-------------------------------------------------------------------------------------------------------------------------------");
while (1){
printf("\n\n\n\n\n\t\t\t\t--------------------------------------------------------------------------\n");
printf("\t\t\t\t--------------------------------------------------------------------------\n");
printf("\t\t\t\t--------------------------------------------------------------------------\n");
printf("\t\t\t\t||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n");
printf("\t\t\t\t------------------------- 迷宫游戏 ------------------------------\n");
printf("\t\t\t\t||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||\n");
printf("\t\t\t\t--------------------------------------------------------------------------\n");
printf("\t\t\t\t- 1 --------------------- 迷宫寻路 ----用栈进行迷宫寻路----------\n");
printf("\t\t\t\t- 2 --------------------- 迷宫游玩 ----自己随便编的--------------\n");
printf("\t\t\t\t- 0 --------------------- 退出游戏 ------------------------------\n");
int a;
printf("请选择:>");
scanf("%d", &a);
if (a == 0){
printf("再会!!");
return 0;
}
else if (a == 1){
system("cls");
int maze[N][N];
int copyMaze[N][N];
int in = 0;
int out = 0;
int *inp = ∈//该指针指向迷宫入口位置,即指向in
int *outp = &out;//该指针指向迷宫出口位置,即指向out
srand(time(NULL));
//迷宫的创建与初始化,打印迷宫
InitMaze(maze);
CreatMaze(maze, 14, 14);//从maze[14][14]的位置开始创建迷宫
CreatInAndOut(maze, inp, outp);//寻找迷宫的入口与出口,将其赋予in和out
CopyMaze(maze, copyMaze);//将原迷宫复制到copyMaze中
print(maze);
printf("\t\t按回车键进行迷宫寻路------------");
system("pause");
system("cls");
//用栈进行寻路,并打印出最终路线
Stack*Top = InitStack(in, copyMaze);//返回的指针Top->next指向该栈的栈顶
FindMaze(Top, copyMaze, out);
Endprint(maze, Top);//打印函数
system("pause");
}
else if (a == 2){
//1.创建迷宫
//2.写函数,函数参数应该包括:1.迷宫指定位置,2.迷宫出口位置,3.指向迷宫的指针,4.移动的方向
//该函数应该对修改后的迷宫进行打印
//该函数返回一个整数赋予flage,控制该游戏是否继续执行
//3.不断运行该函数,直到游戏终止
system("cls");
int maze[N][N];
int copyMaze[N][N];
int in = 0;
int out = 0;
int *inp = ∈//该指针指向迷宫入口位置,即指向in
int *outp = &out;//该指针指向迷宫出口位置,即指向out
srand(time(NULL));
//迷宫的创建与初始化,打印迷宫
InitMaze(maze);
CreatMaze(maze, 14, 14);//从maze[14][14]的位置开始创建迷宫
CreatInAndOut(maze, inp, outp);//寻找迷宫的入口与出口,将其赋予in和out
//以上是迷宫的创建
//现在我们有了一个随机迷宫,迷宫的出口(out)与入口(in)坐标
int direction;//控制移动方向
int flage = 1;//控制游戏是否结束
//将迷宫的入口位置存入x,y方便使用
int x = in;
int y = 1;
maze[x][y] = END;
//创建两个指针指向 x y 方便修改
int *px = &x;
int *py = &y;
while (flage){
system("cls");
print(maze);
printf("\n\n\n\t\t请输入想要移动的方向:>");
printf("\n\t\t\t* 代表目前人物所在位置");
printf("\n\t\t注:1,2,3,4分别代表上下左右,其它数字均为非法数字!");
scanf("%d", &direction);
//先进行位置判断,若要移动的方向在迷宫处显示为路,则移动,否则不移动
//返回1,则证明方向合法且移动方向是路(可以移动)
if (Decide(x, y, direction, maze) == 1){
flage = Game(px, py, maze, out, direction);
}
print(maze);
system("pause");
printf("\n\t\t-------按回车键继续....");
}
}
else{
printf("输入数据有误!!");
}
system("cls");
}
return 0;
}
ok,拜拜~~~~