[CPPHTP7 NOTES] CH8. POINTERS(5) - Maze Traversal

(Exercise 8.16 Maze Traversal) This exercise takes me quite a long time to finish. It is about travelling from an entrance of a maze to find the exit. The book introduces a famous algorithm to travelse maze - the wall follower, which is also known as the left-hand rule or the right-hand rule


Imagine you are in the maze. What you need to do is just keeping your right hand(okay, left hand, if you prefer) on the wall on your right(or left). Then, you keep walking with your right hand on the wall. Eventually, you will arrive at either the exit (or the entrance) of the maze. This algorithm cannot gurantee a shortest path, but it work well when the entrance and exit areat the edge of the maze. (Why do we have this condition? It is because a loop may be formed if the entrance or exit is not at the edge, when the barriers are not connected to outermost wall!)


In my implementation, I use some special techniques to improve the readibility. For example, I use a struct State to record the current state of the maze walker, which include his x-coordinate, y-coordinate and the direction he is facing. To facilitate the use of array subsrcipts, the y-coordinate is reversed so walking to the south is increasing y but not decreasing it. Also, I use an enum Direction to represent the four directions: north, east, south and west. Using enum is quite tricky as you can see how I control the walker to turn left or right by manipulating the variable of type Direction. Functions are also used extensively to avoid repetition of codes.


Okay, time to show my code. Hope you enjoy reading it. And I also encourage you to test it in your computer. You may modify the maze or the position of the entrance and exit to see what happen! If you find any bugs or have any doubts, please feel free to contact me!

// 8.16 Maze Traversal
#include <iostream>
using namespace std;

const int mazeSize = 12;

enum Direction { north, east, south, west }; // for readability

struct State
{
	int x;
	int y;
	Direction front;
};

void printMaze( char maze[][mazeSize+1] );
void look( Direction front, int &x, int &y ); // look at the front and store the square's index in x and y
void advance( State &myState, int nextX, int nextY, char ¤tSquare, char &nextSquare );
bool mazeTraverse( char maze[][mazeSize+1], State& myState, State& startState ); // false when no exit

int main()
{
	char maze[][mazeSize+1] // +1 as there is a '\0' at the end of each string
	= {
		{"############"},
		{"#...#......#"},
		{"..#.#.####.#"},
		{"###.#....#.#"},
		{"#....###.#.."},
		{"####.#.#.#.#"},
		{"#..#.#.#.#.#"},
		{"##.#.#.#.#.#"},
		{"#........#.#"},
		{"######.###.#"},
		{"#......#...#"},
		{"############"}
	};

	State start = { 11, 4, west };
	State current = start;
	maze[start.y][start.x] = 'X';
	printMaze( maze );

	bool hasExit = mazeTraverse( maze, current, start );
	if( hasExit ) cout << "The exit of the maze has been found!" << endl;
	else cout << "Oops! You return to the entrance again!" << endl;

	return 0;
}

bool mazeTraverse( char maze[][mazeSize+1], State& myState, State& startState )
{
	Direction right = (Direction)((myState.front+1) % 4);
	int frontX = myState.x;
	int frontY = myState.y;
	int rightX = myState.x;
	int rightY = myState.y;

	look( right, rightX, rightY ); // find the index of right square

	// see if there is a wall on the right
	if( maze[rightY][rightX] == '#' ) // try to follow the wall
	{
		look( myState.front, frontX, frontY );

		// check whether the exit or entry is reached
		if( frontX < 0 || frontX >= mazeSize || frontY < 0 || frontY >= mazeSize )
		{
			if( myState.x == startState.x && myState.y == startState.y ) return false;
			else return true;
		}

		if( maze[frontY][frontX] == '#' ) // wall at the front
		{
			myState.front = (Direction)((myState.front+4-1) % 4); // turn left
		}
		else // no wall at the front
		{
			advance( myState, frontX, frontY, maze[myState.y][myState.x], maze[frontY][frontX] );
			printMaze( maze );
		}
	}
	else // no wall on right, turn right and advance
	{
		myState.front = right;
		look( myState.front, frontX, frontY );

		advance( myState, frontX, frontY, maze[myState.y][myState.x], maze[frontY][frontX] );
		printMaze( maze );
	}

	return mazeTraverse( maze, myState, startState ); // next decision
}

void printMaze( char maze[][mazeSize+1] )
{
	static bool firstPrint = true;
	static bool promptToContinue = false;

	for( int i=0; i<mazeSize; i++ )
	{
		for( int j=0; j<mazeSize; j++ )
		{
			cout << maze[i][j];
		}
		cout << endl;
	}
	cout << endl;

	if( firstPrint )
	{
		char answer;
		cout << "We are going to solve the maze!" << endl;
		cout << "Do you want to watch it step by step?" << endl;
		cout << "Enter Y if you want, or N otherwise: ";
		cin >> answer;
		if( answer == 'Y' || answer == 'y' )
			promptToContinue = true;
		cout << endl;
		firstPrint = false;
	}
	else if( promptToContinue )
	{
		char anything[10];
		cout << "Input any character to continue: ";
		cin >> anything;
	}
}

void look( Direction front, int &x, int &y )
{
	int pastX = x;
	int pastY = y;
	switch( front )
	{
		case north:
			y--;
			break;
		case east:
			x++;
			break;
		case west:
			x--;
			break;
		case south:
			y++;
			break;
		default:
			cerr << "Error - Invalid direction" << endl;
	};
}

void advance( State &myState, int nextX, int nextY, char ¤tSquare, char &nextSquare )
{
	if( nextSquare == 'X' )
		currentSquare = '.'; // clear the current square from the path

	myState.x = nextX;
	myState.y = nextY;
	nextSquare = 'X'; // mark as current path
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值