1. 程式人生 > >【C語言】迷宮

【C語言】迷宮

一,涉及知識點
結構體,棧,遞迴
二,實現邏輯
1.定義一個結構體儲存當前位置座標
2.用陣列初始化一個迷宮,1表示可以走,0表示牆,迷宮最後一列都是出口
3.列印迷宮
4.走迷宮方法一:使用棧,通過壓棧出棧回溯;方法二:在棧的基礎上,用遞迴做回溯
5.記錄最短路徑,把路徑壓入棧中,列印最短路徑
三,原始碼
#pragma once
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>

#define ROWS (6)       //行數
#define COLS (6)        //列數
#define MAX_SIZE (100)

//結構體存放座標
typedef struct Position
{
	int x;
	int y;
}Position;
typedef Position StackDataType;
//棧
typedef struct Stack
{
	StackDataType array[MAX_SIZE];
	int top;        //表示當前個數
}Stack;
void StackInit(Stack *pStack)
{
	pStack->top = 0;
}
void StackDestroy(Stack *pStack)
{
	pStack->top = 0;
}
void StackPush(Stack *pStack, StackDataType data)
{
	assert(pStack->top < MAX_SIZE);
	//pStack->top 永遠指向的棧頂後的一個空間
	pStack->array[pStack->top++] = data;
}
void StackPop(Stack *pStack)
{
	assert(pStack->top>0);
	pStack->top--;
}
Position StackTop(Stack *pStack)
{
	assert(pStack->top > 0);
	return pStack->array[pStack->top-1];
}
int StackSize(const Stack *pStack)
{
	return pStack->top;
}
int StackFull(const Stack *pStack)
{
	return pStack->top >= MAX_SIZE;
}
int StackEmpty(const Stack *pStack)
{
	return pStack->top <= 0;
}
void StackCopy(Stack *pDest,Stack *pSrc)
{
	memcpy(pDest->array, pSrc->array, sizeof(StackDataType)*pSrc->top);
	pDest->top = pSrc->top;
}

Stack path;     //當前路徑
Stack min;      //之前的最小路徑

//簡單迷宮
int gMaze[ROWS][COLS] = {
            { 0, 0, 0, 0, 0, 0 },
            { 0, 0, 1, 0, 0, 0 },
            { 0, 0, 1, 0, 0, 0 },
            { 0, 0, 1, 1, 1, 0 },
            { 0, 0, 1, 0, 1, 1 },
            { 0, 0, 1, 0, 0, 0 }
};
//入口
Position gEntry = { 5, 2 };
//判斷是否走到出口,最後一列都是出口
int IsExit(Position pos)
{
	if (pos.y == COLS - 1){
		return 1;
	}
	else {
		return 0;
	}
}
//判斷是否可以走,沒有越界&&值是1
int CanPass(Position pos)
{
	if (pos.x >= ROWS){
		return 0;
	}
	if (pos.y >= COLS){
		return 0;
	}
	return gMaze[pos.x][pos.y] == 1;
}
//列印路徑
void PrintPath(Stack *pStack)
{
	Position at;
	for (int i = 0; i < pStack->top; i++){
		at = pStack->array[i];
		printf("x=%d y=%d\n", at.x, at.y);
	}
}
//列印迷宮
void PrintMaze()
{
	for (int i = 0; i < ROWS;i++){
		for (int j = 0; j < COLS;j++){
			if (gMaze[i][j] == 0)
			{
				printf("■", gMaze[i][j]);
			}
			else if (gMaze[i][j] == 1)
			{
				printf("  ", gMaze[i][j]);
			}
			else if (gMaze[i][j] == 2){
				printf("☆", gMaze[i][j]);
			}
		}
		printf("\n");
	}
	printf("\n\n");
}
//方法二
//呼叫棧做回溯,遞迴
void RunMazeRec(Position at)
{
	Position next;
	StackPush(&path,at);

	//一進來標記我走過了
	gMaze[at.x][at.y] = 2;
	PrintMaze();

	if (IsExit(at)){
		//如果當前路徑(path)小於之前的最小路徑(min),最小路徑是path
		if (StackEmpty(&min) || StackSize(&path) < StackSize(&min)){
			StackCopy(&min, &path);
            //打印出最短路徑
			PrintPath(&path);
		}
	}
	//根據左->上->右->下來嘗試
	//左
	next.x = at.x;
	next.y = at.y - 1;
	if (CanPass(next)){
		RunMazeRec(next);//遞迴
		//PrintMaze();
	}
	//上
	next.x = at.x - 1;
	next.y = at.y;
	if (CanPass(next)){
		RunMazeRec(next);
		//PrintMaze();
	}
	//右
	next.x = at.x;
	next.y = at.y + 1;
	if (CanPass(next)){
		RunMazeRec(next);
		//PrintMaze();
	}
	//下
	next.x = at.x + 1;
	next.y = at.y;
	if (CanPass(next)){
		RunMazeRec(next);
		//PrintMaze();
	}
	//如果at的四周都沒法兒走,at重新置為1
	gMaze[at.x][at.y] = 1;
	StackPop(&path);
	return;   //回溯
}

//方法一
//需要一個棧回溯,壓棧出棧
void RunMaze()
{
	Stack stack;
	StackInit(&stack);
	Position next;
	Position at;
	at.x = gEntry.x;
	at.y = gEntry.y;
	
	while (1){
		//一進來標記我走過了
		gMaze[at.x][at.y] = 2;
		PrintMaze();
		//把當前位置壓入棧中,方便做回溯
		StackPush(&stack, at);

		if (IsExit(at)){
			//如果到了出口,退出
			PrintPath(&stack);
			return;
		}
		//根據左->上->右->下來嘗試
		//左
		next.x = at.x;
		next.y = at.y - 1;
		if (CanPass(next)){
			at.x = next.x;
			at.y = next.y;
			continue;
		}
		//上
		next.x = at.x - 1;
		next.y = at.y;
		if (CanPass(next)){
			at.x = next.x;
			at.y = next.y;
			continue;
		}
		//右
		next.x = at.x;
		next.y = at.y + 1;
		if (CanPass(next)){
			at.x = next.x;
			at.y = next.y;
			continue;
		}
		//下
		next.x = at.x + 1;
		next.y = at.y;
		if (CanPass(next)){
			at.x = next.x;
			at.y = next.y;
			continue;
		}
		//如果四周都沒法兒走,出棧
		StackPop(&stack);
		if (StackEmpty(&stack)){
			printf("沒有出口\n");
			return;
		}
		at = StackTop(&stack);   //回溯
		StackPop(&stack);
	}
}
void testRunMazeRec()
{
	StackInit(&path);
	StackInit(&min);
	PrintMaze();
	RunMazeRec(gEntry);
}
int main()
{
	PrintMaze();
	//RunMaze();  
	testRunMazeRec();
	system("pause");
	return 0;
}