C/C++利用栈实现随机生成简单迷宫

    上一篇文章中迷宫是基于程序员自身对于迷宫障碍物的构建而实现,具有主观因素,那么本篇文章基于srand((unsigned)time(NULL))函数来随机生成迷宫大小、障碍物坐标、出口坐标以及入口坐标,更加灵活。本文围墙的范围为[3,25],但由于随机生成的迷宫存在偶然性,因此尺寸较大的迷宫出现通路的概率反而较小,所以往往运行结果显示出的迷宫尺寸较小。本文使用的IDE是VS 2015,由于寻找路径速度过快,建议在每次循环时使用Sleep函数对永真循环进行一段时间的悬挂,否则有可能将会出现栈中栈顶指针对于系统的攻击,也就是会出现访问权限冲突的状况,请读者根据自己的开发环境进行处理。若使用VS 2015开发的读者,在运行过程中杀毒软件可能会误将指针访问判断为恶意程序攻击,可能会弹出阻止该程序运行的窗口,该种情况直接点击阻止该程序运行并勾选不再提醒即可,请读者注意!!!

(基于程序员自身对于迷宫障碍实现的主观构建:https://blog.csdn.net/qq_45505634/article/details/105380600


​//预编译区::
#include "stdafx.h"
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include<windows.h>
#define MAXLEN 25		//迷宫包括外墙的最大行列数
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 15
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
#define UNDERFLOW -3
using namespace std;

//数据结构定义区::
typedef int status;

//坐标位置类型
typedef struct {
	int r;		//迷宫中第r行
	int c;		//迷宫中第c列
}PosType;

//栈中元素值域的类型
typedef struct {
	int ord;		//通道块在路径上的序号
	PosType seat;		//通道块在迷宫上的通道位置
	int di;		//从此通道块走向下一通道的方向
}SElemType;

//定义链式栈的存储结构
struct LNode {
	SElemType data;		//数据域
	LNode *next;		//指针域
};

typedef struct LStack {
	LNode *top;		//栈顶指针
	LNode *base;		//栈底指针
	int stacksize;		//栈的大小
}SqStack;

//迷宫类型(需要打印呈现)
typedef struct {
	int	r;
	int c;
	char addr[MAXLEN][MAXLEN];		//表示通道的矩阵
}MazeType;

//函数声明区::
void InitStack(LStack &s);
status StackEmpty(LStack s);
void PushStack(LStack &s, SElemType e);
void Pop(LStack &s, SElemType &e);
status DestroyStack(LStack &s);
void OverturnStack(SqStack S, SqStack &T);
void InitMaze(MazeType &maze);
status CreatMaze(MazeType &maze, PosType &start, PosType &end);
status WhetherPass(MazeType &maze, PosType curpos);
void FootPrint(MazeType &maze, PosType curpos);
PosType NextPos(PosType &curpos, int i);
void MarkPrint(MazeType &maze, PosType curpos);
status MazePath(MazeType &maze, PosType start, PosType end, SqStack &S);
void PrintMaze(MazeType &maze, PosType start, PosType end);
void PrintStack(SqStack S);

//主函数
int main(void) {
	SqStack S, T;
	InitStack(T);
	MazeType maze;
	PosType start, end;
	start.c = start.r = 0; end.c = end.r = 0;
	while (1) {
		//Sleep(200);
                InitStack(S);		//每次都要将S和maze进行初始化,否则将记录上一次的数据,产生错误
		InitMaze(maze);
		printf("----------------创建迷宫开始----------------\n");
		if (!CreatMaze(maze, start, end)) {
			printf("初始化失败!!!\n");
			exit(OVERFLOW);
		}
		printf("----------------创建迷宫结束----------------\n");
		printf("\n");
		printf("----------------原始迷宫模型图(障碍物随机生成)----------------\n");
		PrintMaze(maze, start, end);
		if (!MazePath(maze, start, end, S))		//当栈被销毁的时候,则没有一条通路
		{
			system("cls"); continue;
		}
		else break;
	}
	printf("\n");
	printf("----------------走出迷宫的路径----------------\n");
	OverturnStack(S, T); PrintStack(T); DestroyStack(S);
	printf("----------------迷宫路径模型图(o代表一条通路)----------------\n");
	PrintMaze(maze, start, end);
	system("pause");
	return 0;
}

//---------栈的算法开始------------
//构造一个空栈
void InitStack(LStack &s) {
	s.top = (LNode*)malloc(STACK_INIT_SIZE * sizeof(LNode));		//为指针p分配空间
	s.base=(LNode*)malloc(STACK_INIT_SIZE * sizeof(LNode));
	if (!s.base) {
		printf("分配失败,退出程序!");
		exit(OVERFLOW);
	}
	s.base=s.top;		//将栈底和栈顶指针指向p指向的位置		
	s.stacksize = STACK_INIT_SIZE;
	return;
}

//若栈s为空栈,则返回true,否则返回false
status StackEmpty(LStack s) {
	if (s.top == s.base) return TRUE;		//若栈顶指针与栈底指针重合,则是空栈
	else return FALSE;
}

//插入元素e成为新的栈顶元素
void PushStack(LStack &s, SElemType e) {
	if (s.top - s.base >= s.stacksize) {
		s.base = (LNode*)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(LNode));
		if (!s.base) exit(OVERFLOW);
		s.top = s.base + s.stacksize;
		s.stacksize += STACKINCREMENT;
	}
	(*s.top).data.di= e.di;
	(*s.top).data.ord = e.ord;
	(*s.top).data.seat.r = e.seat.r;
	(*s.top).data.seat.c = e.seat.c;
	s.top++;
	return;
}

//删除s的栈顶元素,并用e返回其值
void Pop(LStack &s, SElemType &e) {
	if (s.top == s.base) exit(ERROR);		//如果为空栈,退出
	s.top--;
	e = (*s.top).data;
	return;
}

//栈s的销毁
status DestroyStack(LStack &s) {
	free(s.base);
	s.base = NULL;
	s.top = NULL;
	s.stacksize = 0;
	return OK;
}

//将栈S中的所有元素翻转致栈T:用于对于路径的输出,由于栈不能直接访问栈底指针,所以需要翻转
void OverturnStack(SqStack S, SqStack &T) {
	SElemType e;
	do {
		Pop(S, e); PushStack(T, e);
	} while (S.base != S.top);
	return;
}
//---------栈的算法结束------------

//---------迷宫实现开始------------
//初始化迷宫
void InitMaze(MazeType &maze) {
	maze.c = 0;
	maze.r = 0;
	return;
}

//创建迷宫
status CreatMaze(MazeType &maze, PosType &start, PosType &end) {
	int i, j, m = 0, n = 0,random;
	srand((unsigned)time(NULL));
	//迷宫的行和列的范围为[3,25]
	printf("随机生成迷宫的行数和列数(包含外墙):");
	maze.r = rand()%23+3; maze.c = rand() % 23 + 3;
	printf("行数:%d,列数:%d\n",maze.r,maze.c);
	for (i = 0; i < maze.c; i++) {
		maze.addr[0][i] = '#';		//给出上下围墙
		maze.addr[maze.r - 1][i] = '#';
	}
	for (i = 1; i < maze.r - 1; i++) {
		maze.addr[i][0] = '#';		//给出左右围墙
		maze.addr[i][maze.c - 1] = '#';
	}
	for (i = 1; i < maze.r - 1; i++) {
		for (j = 1; j < maze.c - 1; j++) {
			//random的范围为[0,1]之间的整数
			random = rand()%2;
			if(random==0)
				maze.addr[i][j] = ' ';		//将围墙内的通道块随机赋空值表示可通行
			else 
				maze.addr[i][j] = '#';		//将围墙内的通道块随机赋#值表示障碍
		}
	}
	//随机生成的迷宫入口:入口的r只能在[1,(maze.r-2)]之间,c只能为0
	printf("\n随机生成的迷宫入口:");
	start.r = rand()%(maze.r-2)+1;
	start.c = 0;
	printf("(%d,%d)\n",start.r,start.c);
	//随机生成的迷宫出口:出口的r只能在[1,(maze.r-2)]之间,c只能为maze.c
	printf_s("\n随机生成的迷宫出口:");
	end.r = rand() % (maze.r - 2) + 1;
	end.c = maze.c-1;
	printf("(%d,%d)\n", end.r, end.c);
	maze.addr[start.r][start.c] = ' ';
	maze.addr[end.r][end.c] = ' ';
	return OK;
}

//判断当前位置可否通过,可通过返回true
status WhetherPass(MazeType &maze, PosType curpos) {
	if (maze.addr[curpos.r][curpos.c] == ' ') return TRUE;
	else return FALSE;
}

//若该通道块走过并且可通,就记录下来
void FootPrint(MazeType &maze, PosType curpos) {
	maze.addr[curpos.r][curpos.c] = 'o';
	return;
}

//指示并返回下一位置的坐标
PosType NextPos(PosType &curpos, int i) {
	switch (i) {		//向各个方向前进一个单位,并返回位置值
	case 1:curpos.c += 1; break;		//向东前进一个单位
	case 2:curpos.r += 1; break;		//向南前进一个单位
	case 3:curpos.c -= 1; break;		//向西前进一个单位
	case 4:curpos.r -= 1; break;		//向北前进一个单位
	default:exit(ERROR);
	}
	return curpos;
}

//曾经走过,但不是通路,就标记
void MarkPrint(MazeType &maze, PosType curpos) {
	maze.addr[curpos.r][curpos.c] = '@';
	return;
}

//若迷宫存在一条通路,则求出一条通路存放到栈中
status MazePath(MazeType &maze, PosType start, PosType end, SqStack &S) {
	PosType curpos;		//记录当前元素位置
	int curstep = 1, flag = 0;	//记录能通行的通道块在栈中的路径顺序
	SElemType e;		//记录可压住栈中的当前通道块的信息
	curpos = start;
	do {
		if (WhetherPass(maze, curpos)) {		//如果该路径块可通行
			FootPrint(maze, curpos);		//记录下通行过的痕迹
			e.ord = curstep;		//将栈中的顺序给e的ord属性
			e.seat.c = curpos.c;		//将该通道块的位置给e的curpos属性
			e.seat.r = curpos.r;
			e.di = 1;		//将初始方向设为向东(1)
			PushStack(S, e);		//将该可通的通道块压入栈
			if (curpos.r == end.r&&curpos.c == end.c) {		//如果遇到了出口则退出
				return TRUE;
			}
			else {		//如果没有遇到出口
				curpos = NextPos(curpos, 1);		//那么寻找下一个位置
				curstep++;		//计数器加1
			}
		}
		else {		//如果该路径块不通
			if (!StackEmpty(S)) {		//如果栈不为空
				Pop(S, e);		//将栈顶元素出栈也就是退回上一个元素,将e返回出来判断是否再次进行方向的改变,也就是将栈顶元素进行悬挂操作
				while (e.di == 4 && !StackEmpty(S)) {		//当四个方向都不通并且栈b不为空时
					MarkPrint(maze, e.seat);		//记录该通道块不通
					Pop(S, e);
					//将栈顶元素出栈也就是退回上一个位置
				}
				if (e.di < 4) {		//当四个方向没有尝试完时
					e.di++;		//换一个方向
					PushStack(S, e);		//将换方向之后的位置压栈
					curpos = NextPos(e.seat, e.di);		//当前位置下移
				}
			}
		}
	} while (!StackEmpty(S));
	return FALSE;
}

//将标记路径信息输出到终端显示屏
void PrintMaze(MazeType &maze, PosType start, PosType end) {
	int i, j;
	printf("          ");		//10个空格
	for (i = 0; i <maze.c; i++) printf("%2d", i);
	printf("\n");
	for (i = 0; i < maze.r; i++) {
		if (i == start.r - 1) printf("entrance%2d", start.r - 1);
		else if (i == start.r)	printf("      ->%2d", start.r);
		else printf("%10d", i);
		for (j = 0; j < maze.c; j++) {
			printf("%2c", maze.addr[i][j]);
			if (i == end.r - 1 && j == end.c) printf(" exit");
			else if (i == end.r&&j == end.c) printf("<-");
		}
		printf("\n");
	}
	return;
}

//输出栈中的路径
void PrintStack(SqStack S) {
	int flag = 0;
	printf("迷宫中的一条通路如下:\n");
	do {
		S.top--;		//将栈顶指针指向想要输出的栈顶元素
		if (flag % 5 == 0) printf("\n");
		switch (S.top->data.di) {
		case 1:
			printf("(%d,%d)向东->", S.top->data.seat.r, S.top->data.seat.c);
			flag++; break;
		case 2:
			printf("(%d,%d)向南->", S.top->data.seat.r, S.top->data.seat.c);
			flag++; break;
		case 3:
			printf("(%d,%d)向西->", S.top->data.seat.r, S.top->data.seat.c);
			flag++; break;
		case 4:
			printf("(%d,%d)向北->", S.top->data.seat.r, S.top->data.seat.c);
			flag++; break;
		}
	} while (S.base != S.top);
	printf("结束\n");
	return;
}
​

  • 12
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个使用深度优先搜索(DFS)算法来生成随机迷宫的 C++ 代码: ```c++ #include <iostream> #include <stack> #include <cstdlib> #include <ctime> using namespace std; const int MAZE_SIZE = 10; enum Direction { NORTH, EAST, SOUTH, WEST }; struct Cell { bool visited; bool walls[4]; }; void init_maze(Cell maze[][MAZE_SIZE]) { for (int i = 0; i < MAZE_SIZE; i++) { for (int j = 0; j < MAZE_SIZE; j++) { maze[i][j].visited = false; maze[i][j].walls[NORTH] = true; maze[i][j].walls[EAST] = true; maze[i][j].walls[SOUTH] = true; maze[i][j].walls[WEST] = true; } } } bool is_valid(int row, int col) { return row >= 0 && row < MAZE_SIZE && col >= 0 && col < MAZE_SIZE; } void remove_wall(Cell& current, Cell& next) { if (current.walls[NORTH] && current.walls[SOUTH] && current.walls[EAST] && !current.walls[WEST] && next.walls[NORTH] && next.walls[SOUTH] && next.walls[WEST] && !next.walls[EAST]) { current.walls[WEST] = false; next.walls[EAST] = false; } else if (current.walls[NORTH] && current.walls[SOUTH] && !current.walls[EAST] && current.walls[WEST] && next.walls[NORTH] && next.walls[SOUTH] && !next.walls[WEST] && next.walls[EAST]) { current.walls[NORTH] = false; next.walls[SOUTH] = false; } else if (current.walls[NORTH] && !current.walls[SOUTH] && current.walls[EAST] && current.walls[WEST] && next.walls[SOUTH] && !next.walls[NORTH] && next.walls[WEST] && next.walls[EAST]) { current.walls[SOUTH] = false; next.walls[NORTH] = false; } else if (!current.walls[NORTH] && current.walls[SOUTH] && current.walls[EAST] && current.walls[WEST] && !next.walls[SOUTH] && next.walls[NORTH] && next.walls[WEST] && next.walls[EAST]) { current.walls[NORTH] = false; next.walls[SOUTH] = false; } } void generate_maze(Cell maze[][MAZE_SIZE], int start_row, int start_col) { stack<pair<int, int>> stack; stack.push(make_pair(start_row, start_col)); maze[start_row][start_col].visited = true; srand(time(NULL)); while (!stack.empty()) { int row = stack.top().first; int col = stack.top().second; stack.pop(); int directions[4] = { NORTH, EAST, SOUTH, WEST }; for (int i = 0; i < 4; i++) { int index = rand() % 4; int direction = directions[index]; directions[index] = directions[i]; int next_row = row, next_col = col; switch (direction) { case NORTH: next_row--; break; case EAST: next_col++; break; case SOUTH: next_row++; break; case WEST: next_col--; break; } if (is_valid(next_row, next_col) && !maze[next_row][next_col].visited) { maze[next_row][next_col].visited = true; remove_wall(maze[row][col], maze[next_row][next_col]); stack.push(make_pair(next_row, next_col)); } } } } void print_maze(Cell maze[][MAZE_SIZE]) { for (int i = 0; i < MAZE_SIZE; i++) { for (int j = 0; j < MAZE_SIZE; j++) { if (maze[i][j].walls[NORTH]) { cout << "+---"; } else { cout << "+ "; } } cout << "+" << endl; for (int j = 0; j < MAZE_SIZE; j++) { if (maze[i][j].walls[WEST]) { cout << "| "; } else { cout << " "; } } cout << "|" << endl; } for (int j = 0; j < MAZE_SIZE; j++) { cout << "+---"; } cout << "+" << endl; } int main() { Cell maze[MAZE_SIZE][MAZE_SIZE]; init_maze(maze); generate_maze(maze, 0, 0); print_maze(maze); return 0; } ``` 这段代码中,我们使用了一个来存储当前正在访问的单元格,并随机选择一个未访问的相邻单元格进行访问。在访问过程中,我们使用 `remove_wall()` 函数来移除当前单元格和相邻单元格之间的墙壁。最后,我们使用 `print_maze()` 函数来打印生成随机迷宫

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值