Maze Solving Using Stacks - Exhaustive Method

maze solver

Solution ideas

The easiest way to use a computer to solve a maze is the exhaustive method.
The specific idea is as follows (refer to the C language version of the data structure of Tsinghua University Press):
First, start from the entrance and explore along a certain direction. The direction continues until all possible paths have been traversed. This idea is very similar to the characteristics of the stack. According to a certain sequence direction, each step is pushed into the stack. If the square that cannot be walked or the next direction has been passed, the current step is popped out of the stack. until the end of the maze is reached.

related code

//base.h

#ifndef BASE_H
#define BASE_H

#include<cstdio>
#include<cstdlib>
#include<malloc.h>

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2

typedef int Status;

typedef int DirectiveType;

typedef struct {
    
    
	int row;
	int col;
}PosType;//通道块类型,代表的坐标(行,列)

typedef struct {
    
    
	int step;//在路径中的序号
	PosType seat;//位置坐标
	DirectiveType di;//方向 1代表东 2代表南 3代表西 4 代表北	
}SElemType;//栈元素类型,

#endif // !BASE_H

//Map.h

#ifndef MAP_H
#define MAP_H
#include "Stack.h"


#define ROW 10
#define COL 10
#define RANGE 100

typedef struct {
    
    
	int m, n;
	int arr[RANGE][RANGE];
}MazeType;

Status InitMaze(MazeType &Maze, int a[][COL], int row, int col);

Status Pass(MazeType Maze, PosType CurPos);
Status FootPrint(MazeType &Maze, PosType CurPos);

Status MarkPrint(MazeType &Maze, PosType CurPos);     //形参为地图的引用,以及当前位置,函数作用将当前位置置为走过但不能通过


SElemType CreatSElem(int step, PosType pos, int di);


PosType NextPos(PosType CurPos, DirectiveType di);         //返回值为下一步位置,形参当前位置坐标变量  当前移动方向


Status PosEquare(PosType Pos1, PosType Pos2);     //形参为两个坐标,函数用来判断是否到达终点
void PrintMaze(MazeType Maze);         //打印迷宫
Status MazePath(MazeType &Maze, PosType start, PosType end);         //寻找迷宫路径,形参包括(迷宫的引用,起点坐标,终点坐标)

#endif // !MAP_H




//Stack.h

#include "base.h"


typedef struct {
    
    
	SElemType *base;
	SElemType *top;
	int stackSize;
}SqStack;

#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

Status InitStack(SqStack &S);
Status GetTop(SqStack S, SElemType &e);
Status Push(SqStack &s, SElemType e);
Status Pop(SqStack &s, SElemType &e);
Status StackEmpty(SqStack s); Status DestroyStack(SqStack &s);
Status ClearStack(SqStack &s);
int StackLength(SqStack s);
Status StackTraverse(SqStack s, Status(*visit)(SElemType e));


//Map.cpp
#include "Map.h"

Status InitMaze(MazeType &Maze, int a[][COL], int row, int col)
{
    
    
	//初始化map地图
	for (int i = 1; i <= row; i++)
	{
    
    
		for (int j = 1; j <= col; j++)
			Maze.arr[i][j] = a[i - 1][j - 1];
	}

	for (int j = 0; j <= col + 1; j++)
		Maze.arr[0][j] = Maze.arr[row + 1][j] = 1;
	for (int i = 0; i <= row + 1; i++)
		Maze.arr[i][0] = Maze.arr[i][col + 1] = 1;
	Maze.m = row;
	Maze.n = col;

	return OK;
}

Status Pass(MazeType Maze, PosType CurPos)
{
    
    
	//形参地图,位置,   判断该位置是否走过

	if (Maze.arr[CurPos.row][CurPos.col] == 0)
		return 1;
	else return 0;
}

Status FootPrint(MazeType &Maze, PosType CurPos)
{
    
    
	Maze.arr[CurPos.row][CurPos.col] = 2;//通的过,留下足迹
	return OK;
}

Status MarkPrint(MazeType &Maze, PosType CurPos)     //形参为地图的引用,以及当前位置,函数作用将当前位置置为走过但不能通过
{
    
    
	Maze.arr[CurPos.row][CurPos.col] = 3;//走过但是不能通过
	return OK;
}

SElemType CreatSElem(int step, PosType pos, int di)
{
    
    
	//返回值为栈元素,函数作用为初始化栈元素并返回
	SElemType e;
	e.step = step;
	e.di = di;
	e.seat = pos;
	return e;
}

PosType NextPos(PosType CurPos, DirectiveType di)         //返回值为下一步位置,形参当前位置坐标变量  当前移动方向
{
    
    
	PosType Pos = CurPos;
	switch (di)
	{
    
    
	case 1:Pos.col++; break;//East
	case 2:Pos.row++; break;//south
	case 3:Pos.col--; break;//west
	case 4:Pos.row--; break;//north
	}
	return Pos;
}

Status PosEquare(PosType Pos1, PosType Pos2)     //形参为两个坐标,函数用来判断是否到达终点
{
    
    
	if (Pos1.col == Pos2.col && Pos1.row == Pos2.row)
		return 1;
	else return 0;
}
void PrintMaze(MazeType Maze)         //打印迷宫
{
    
    
	int i, j;
	printf("  ");
	for (i = 0; i <= COL + 1; i++)
		printf("%2d", i);
	printf("\n");
	for (i = 0; i <= ROW + 1; i++)
	{
    
    
		printf("%2d", i);
		for (j = 0; j <= COL + 1; j++)
		{
    
    
			switch (Maze.arr[i][j])
			{
    
    
			case 0:printf("  "); break;//没有走过
			case 2:printf(" *"); break;//走过且走的通
			case 3:printf("  "); break;//走过但不通
			case 1:printf(" #"); break;//障碍
			}
		}
		printf("\n");
	}
}
Status MazePath(MazeType &Maze, PosType start, PosType end)         //寻找迷宫路径,形参包括(迷宫的引用,起点坐标,终点坐标)
{
    
    
	SqStack S;            //路径栈
	SElemType e;          //栈元素,包含(位置,步数,下一步方向)
	InitStack(S);		  //初始化栈
	PosType CurPos = start;     //声明当前坐标初始化为开始坐标
	int Curstep = 1;       //当前步数
	do
	{
    
    
		if (Pass(Maze, CurPos))        //如果没走过
		{
    
    
			FootPrint(Maze, CurPos);     //在该位置留下足迹
			e = CreatSElem(Curstep, CurPos, 1);  //将当前位置,步数,以及移动方向初始化为栈元素赋值给e
			Push(S, e);                 //将e压入栈
			if (PosEquare(CurPos, end)) return TRUE;         //判断是否到达终点,如果是返回
			CurPos = NextPos(CurPos, 1);            //移动到下一位置并将移动方向置为右
			Curstep++;                              //当前步数加一
		}
		else
		{
    
                                                 //如果走过
			if (!(StackEmpty(S)))                       //如果栈不空
			{
    
    
				Pop(S, e);							//弹出栈顶元素
				while (e.di == 4 && !StackEmpty(S))		//当当前栈顶元素的当前步数方向为向上并且栈不空
				{
    
    
					MarkPrint(Maze, e.seat);			//将当前位置置为走过但不通
					Pop(S, e);							//弹出
				}
				if (e.di < 4)                   //如果当前位置的方向不为上
				{
    
    
					e.di++; Push(S, e);        //将方向置为下一步的方向,压入栈
					CurPos = NextPos(e.seat, e.di);    //移动到下一位置
				}
			}
		}

	} while (!StackEmpty(S));
	return FALSE;
}

//Stack.cpp
#include "Stack.h"

Status InitStack(SqStack &S) {
    
    
	//初始化一个空栈
	S.base = (SElemType* )malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base)
		exit(ERROR);
	S.top = S.base;
	S.stackSize = STACK_INIT_SIZE;
	return OK;
}

Status GetTop(SqStack S, SElemType &e) {
    
    
	//若栈不空,则用e返回栈顶元素,并返回ok,否则返回ERROR
	if (S.top == S.base)
		return ERROR;
	e = *(S.top - 1);
	return OK;
}

Status Push(SqStack &s, SElemType e) {
    
    
	//将e压入到栈中
	if (s.top - s.base >= s.stackSize) {
    
    
		s.base = (SElemType *)realloc(s.base, (s.stackSize + STACKINCREMENT) * sizeof(SElemType));
		if (!s.base)
			exit(OVERFLOW);
		s.top = s.base + s.stackSize;
		s.stackSize += STACKINCREMENT;
	}
	*s.top++ = e;
	return OK;
}

Status Pop(SqStack &s, SElemType &e) {
    
    
	//若栈不空,则删除S的栈顶元素,用e返回其中值,并返回ok,否则返回ERROR
	if (s.top == s.base)
		return ERROR;
	e = *--s.top;
	return OK;
}

Status StackEmpty(SqStack s) {
    
    
	//若栈为空栈,则返回true,否则返回false
	if (s.base == s.top)
		return TRUE;
	else
		return FALSE;
}

Status DestroyStack(SqStack &s) {
    
    
	//销毁栈,使得栈不存在
	if (s.base) {
    
    
		free(s.base);
		s.base = NULL;
		s.top = NULL;
		s.stackSize = 0;
		return OK;
	}
}

Status ClearStack(SqStack &s) {
    
    
	//清空栈
	if (s.base) {
    
    
		s.top = s.base;
	}
	return OK;
}

int StackLength(SqStack s) {
    
    
	//返回栈的长度
	return s.top - s.base;
}

Status StackTraverse(SqStack s, Status(*visit)(SElemType e)) {
    
    
	while (s.top>s.base)
	{
    
    
		visit(*s.base++);
	}
	printf("\n");
	return OK;
}

Status visit(SElemType e) {
    
    
	printf("%d ", e);
	return OK;
}
//main.cpp
#include "map.h"
int R[10][10] = {
    
    
{
    
    0,0,1,0,0,0,0,1,0,1},
{
    
    1,0,1,0,1,1,0,1,1,0},
{
    
    1,0,0,0,1,1,0,0,0,1},
{
    
    0,1,0,1,1,0,0,1,1,1},
{
    
    0,1,0,0,1,1,0,1,0,0},
{
    
    1,0,1,0,1,1,0,0,1,0},
{
    
    0,1,1,0,0,0,1,0,1,1},
{
    
    0,1,0,1,1,0,0,0,0,0},
{
    
    0,1,1,0,0,1,1,1,1,0},
{
    
    1,0,1,0,1,1,0,0,1,0} };


int main()
{
    
    
	char cmd; int i, j;
	PosType start, end;
	MazeType Maze;
	printf("  ");
	for (i = 1; i <= COL; i++)
		printf("%2d", i);
	printf("\n");

	for (i = 0; i < ROW; i++)
	{
    
    
		printf("%2d", i + 1);
		for (j = 0; j < COL; j++)
			printf("%2d", R[i][j]);
		printf("\n");
	}

	InitMaze(Maze, R, ROW, COL);
	printf("\n迷宫入口坐标:");
	scanf("%d%d", &start.row, &start.col);
	printf("\n迷宫出口坐标:");
	scanf("%d%d", &end.row, &end.col);

	if (MazePath(Maze, start, end))
	{
    
    
		PrintMaze(Maze);
	}
	else
	{
    
    
		printf("\nNO WAY");
	}

	system("pause");

	return 0;
}

The code stack part refers to the Tsinghua data structure, and the stack and map are divided into header files, and then the corresponding files are used for implementation. It is relatively neat, and it is recommended to consider doing so.

Guess you like

Origin blog.csdn.net/qq_32577169/article/details/102754144