So looking at all of the other forums about solving a maze using recursion, none of them had helped me with my issue.
I get a maze from an input file and there is a start and end position. I find the start pos pass the x and y by reference and recursively solve the maze. My issue is that every possible spot in the maze is getting filled with a sign. When only the solution path should be marked (the '#' is what we are to use to show the path of the solution)
Here is what my code outputs when I complie and run:
(2, 1)
Found Exit
|||||||||||
|###|||###|
|#|#####|E|
|||||||||||
(5, 5)
Found Exit
||||||||||||||||
|### |NNNN|N||
|#|#||||N||NNN||
|#|######|||||||
|#||||||#|E## |
|#|||##|#|||#|||
|#|N||#|#####|||
|#|N||#||||||| |
|###### |
||||||||||||||||
(1, 1)
||||||||||
|NNN|| E|
||||||||||
As you can see, the 'N' are where the function found a dead end and needed to backtrack and erase them. The '#' sign is the correct path, it just doesn't erase when backtracking
I believe my issues is the the find_exit function or at_end function
Here is the code:
// "maze.h"
//header file
#include <iostream>
#include <string>
#ifndef MAZE
#define MAZE
using std::cout;
using std::endl;
using std::cin;
using std::string;
/*
Writes to a string array containing:
* the your (the student author’s) Campus Username (at index 0)
* and Student ID# (at index 1).
Takes as input a pre-existing length-2 string array.
*/
void get_identity(string my_id[]);
/**
Use this to help you enumerate the directions.
Gets passed into one function below.
**/
enum direction
{
NORTH,
SOUTH,
EAST,
WEST
};
/**
Creates a dynamically allocated array of strings.
Returns a pointer to that array.
**/
string * build_matrix(int rows);
/**
Fills the matrix with one line per string in the array.
Use the getline method.
Why don't you need to send in cols?
**/
void fill_matrix(string *matrix, int rows);
/**
Print the matrix as in the sample_output.txt
**/
void print_matrix(string *matrix, int rows);
/**
Delete the dynamically allocated array of strings.
Why don't you need to send in cols?
**/
void delete_matrix(string *matrix, int rows);
/**
Finds the starting position of Niobe.
Note: x and y are passed by reference; what does this do for you?
Why don't you need cols here? Hint: not the same reason as last two.
**/
void find_start(string *matrix, int rows, int &x, int &y);
/**
This is the recursive backtracking function you need to write.
It should return true if you found the solution,
and false if there is no solution.
It should leave a trail of # signs along the path to the solution.
Make sure to build your solution with strong emphasis on the pseudocode;
do not try to code it first, first work out the solution on paper/markerboard.
**/
bool find_exit(string *matrix, int x, int y);
/**
Returns true if x and y are the final exit location,
and false otherwise.
**/
bool at_end(string *matrix, int x, int y);
/**
Returns true if the position indexed by x and y is a valid move,
and false otherwise.
What is a valid move?
**/
bool valid_move(string *matrix, int x, int y, direction d);
#endif
#include <fstream>
#include <limits>
using std::ifstream;
void get_identity(string my_id[])
{
my_id[0] = "sra9wb";
my_id[1] = "16781948";
//output
cout << "MST Campus Username: " << my_id[0] << endl;
cout << "Student ID: " << my_id[1] << endl;
}
string *build_matrix(int rows)
{
string *matrix = new string[rows]; //allocating memory for the matrix
return matrix;
}
void fill_matrix(string *matrix, int rows)
{
ifstream file_in("sample_input.txt");
int x = 0;
int y = 0;
bool solved = false;
while (file_in)
{
file_in >> rows;
if (rows == 0)
return;
matrix = build_matrix(rows);
file_in.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); //Grab line until '\n' then toss it
for (int i = 0; i < rows; i++)
{
getline(file_in, matrix[i]);//fillinf matrix with file_in from text file
}
find_start(matrix, rows, x, y);
find_exit(matrix, x, y);
print_matrix(matrix, rows);
cout << endl;
delete_matrix(matrix, rows);
}
}
void print_matrix(string *matrix, int rows)
{
for (int i = 0; i < rows; i++) //increment through the row of the matrix
{
cout << matrix[i] << endl; //print eack row
}
}
void delete_matrix(string *matrix, int rows)
{
delete[] matrix; //delete the matrix
matrix = NULL; //set equal to null for no hanging pointers
}
void find_start(string *matrix, int rows, int &x, int &y)
{
for (int i = 0; i < rows; i++) //increment through the rows
{
string column;
column = matrix[i]; //set the incremented row to string column
for (int j = 0; j < column.length(); j++) //increment through the length of column
{
if (column[j] == 'N') //if the index of column matches N
{
x = i; //x is equal to i because of the 1st for loop
y = j; //y is eqyal to j because of the 1st for loop
}
}
}
cout << "(" << x << ", " << y << ")" << endl;
}
bool find_exit(string *matrix, int x, int y) //first iteration of function passing in coords of N's starting pos
{
//check if we reached the end of the maze
if (at_end(matrix, x, y) == true)
return true;
//sets the starting position to #
matrix[x][y] = 'N';
//recursive search for out goal
if (valid_move(matrix, x, y, NORTH) && find_exit(matrix, x - 1, y))
{
matrix[x][y] = '#';
return true;
}
else if (valid_move(matrix, x, y, SOUTH) && find_exit(matrix, x + 1, y))
{
matrix[x][y] = '#';
return true;
}
else if (valid_move(matrix, x, y, WEST) && find_exit(matrix, x, y - 1))
{
matrix[x][y] = '#';
return true;
}
else if (valid_move(matrix, x, y, EAST) && find_exit(matrix, x, y + 1))
{
matrix[x][y] = '#';
return true;
}
//this line here is meant to print a space when backtracking occurs
// matrix[x][y] = ' ';
// return false;
}
//this function returns true if you are at the end of the maze
bool at_end(string *matrix, int x, int y)
{
if (matrix[x][y] == 'E')
{
cout << "Found Exit" << endl;
return true;
}
else
return false;
}
bool valid_move(string *matrix, int x, int y, direction d)
{
if (d == NORTH)
{
//check if north is clear
if (matrix[x - 1][y] == ' ' || matrix[x - 1][y] == 'E')
return true;
else
return false;
}
else if (d == EAST)
{
//check if EAST is clear
if (matrix[x][y + 1] == ' ' || matrix[x][y + 1] == 'E')
return true;
else
return false;
}
else if (d == SOUTH)
{
//check is south is clear
if (matrix[x + 1][y] == ' ' || matrix[x + 1][y] == 'E')
return true;
else
return false;
}
else if (d == WEST)
{
//check if west is clear
if (matrix[x][y - 1] == ' ' || matrix[x][y - 1] == 'E')
return true;
else
return false;
}
else
return false;
}
//main
// #include "maze.h"
int main()
{
string *matrix = NULL;
int rows = 0;
fill_matrix(matrix, rows);
return 0;
}
The sample_input.txt document goes as follows:
4 11
|||||||||||
| ||| |
|N| |E|
|||||||||||
10 16
||||||||||||||||
| | | ||
| | |||| || ||
| | |||||||
| |||||| |E |
| |||N | ||| |||
| | || | |||
| | || ||||||| |
| |
||||||||||||||||
3 10
||||||||||
|N || E|
||||||||||
0 0
These are the mazes that we are supposed to solve.
Also I am not allowed to edit the header file.
And this is how the output is supposed to look:
Map 0 -- Solution found:
|||||||||||
|###|||###|
|N|#####|E|
|||||||||||
Map 1 -- Solution found:
||||||||||||||||
|### | | ||
|#|#|||| || ||
|#|######|||||||
|#||||||#|E## |
|#|||N#|#|||#|||
|#| ||#|#####|||
|#| ||#||||||| |
|###### |
||||||||||||||||
Map 2 -- No solution found:
||||||||||
|N || E|
||||||||||
//this line here is meant to print a space when backtracking occurs
// matrix[x][y] = ' ';
// return false;
Why don't you just uncomment it? It solves your problem, but you have to add 'N' sign in start point manually after procedure as it replaces it with either '#' or ' ' (but it's easy).
FYI, setting the pointer to NULL (should be nullptr) accomplishes nothing here. The input parameter matrix takes a copy of the pointer ("by-value").
void delete_matrix(string *matrix, int rows)
{
delete[] matrix; //delete the matrix
matrix = NULL; //set equal to null for no hanging pointers
}
Related
I want to make a program to find if a path exists from upper right corner to down left corner in a maze via backtracking. The input numbers are n and m which are the dimensions of rectangular maze and a maze, character '.' means a tile which you can go through and character 'x' means a tile which you cant go through. I have wrote the code, its fairly simple but nothing gets displayed whilst it should display "da" (on Serbian "yes") and "ne" (on Serbian "no").
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
//checking if a position is viable for moving through
bool Safe(int n, int m, int x, int y)
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
if(Safe(n, m, x, y))
{
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = 1;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = 0;
}
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Sample Input:
8 8
.x.....x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
.x.x.x.x
...x.x..
Sample output: da
The problem was that, say if you go from (0, 0) -> (1, 0), then at (1, 0) you can again go back to (0, 0) and this would loop forever. To avoid that, I created a visited array which will have value true if cell (x, y) is already visited, else false.
I have marked where I made the changes with ///////////// change here ///////////// comment
#include <bits/stdc++.h>
using namespace std;
bool maze[20][20]; //defined maze of maximum size 20x20
///////////// change here /////////////
bool visited[20][20];
bool Safe(int n, int m, int x, int y) //checking if a position is viable for moving through
{
if(x >= 0 && x < n && y >= 0 && y < m)
{
if(maze[x][y] == 1) return true;
}
return false;
}
bool Utility(int n, int m, int x, int y) //main utility function
{
if(x == n - 1 && y == m - 1 && maze[x][y] == 1) // base case, end of maze
{
return true;
}
///////////// change here /////////////
if(!visited[x][y] && Safe(n, m, x, y))
{
///////////// change here /////////////
visited[x][y] = true;
if(Safe(n, m, x + 1, y)) // checking if it is viable to move down
{
if(Utility(n, m, x + 1, y))
{
return true;
}
}
if(Safe(n, m, x, y + 1))
{
if(Utility(n, m, x, y + 1)) // checking if it is viable to move right
{
return true;
}
}
if(Safe(n, m, x - 1, y))
{
if(Utility(n, m, x - 1, y)) // checking if it is viable to move up
{
return true;
}
}
if(Safe(n, m, x, y - 1))
{
if(Utility(n, m, x, y - 1)) // checking if it is viable to move left
{
return true;
}
}
}
return false; // returning false
}
int main()
{
int n, m;
cin >> n >> m; // input dimensions of the maze
for(int i = 0; i < n; i++) // input maze
{
for(int j = 0; j < m; j++)
{
char c;
cin >> c;
if(c == '.') //character '.' means a tile which you can go through
{
maze[i][j] = true;
}
else //character 'x' means a tile which you cannot go through
{
maze[i][j] = false;
}
///////////// change here /////////////
visited[i][j] = false;
}
}
if(Utility(n, m, 0, 0)) //printing yes or no
{
cout << "da";
}
else
{
cout << "ne";
}
return 0;
}
Here's the link where I tested it: https://ideone.com/vVqAjF
The problem
I'm new to this sort of programming, and my C++ maze solver is stuck in a loop.
The maze is a simple char 2-D matrix with an asterisk (*) for a valid path square, and a slash (/) for a wall square.
Why doesn't the program stop when it finds a '/'?
# include < iostream >
using namespace std;
char lab[6][6] =
{ { '/','/','/','/','/' },
{ '/','*','/','/','/' },
{ '/','*','*','*','/' },
{ '/','/','*','/','/' },
{ '/','/','*','/','/' },
{ '/','/','*','*','*' } };
int x, y;
void run(char lab[][6], int, int);
bool movU() // Move Up
{
if (lab[x][y - 1] == '*')
return true;
else
return false;
}
bool movR() // Move right
{
if (lab[x + 1][y] == '*')
return true;
else
return false;
}
bool movD() // Move Down
{
if (lab[x][y + 1] == '*')
return true;
else
return false;
}
bool movL() // Move Left
{
if (lab[x - 1][y] == '*')
return true;
else
return false;
}
void run(char lab[][6], int x, int y)
{
if (movU() == true) // I'm getting stuck right here
run(lab, x, y - 1); // Getting negative numbers here
else if (movR() == true)
run(lab, x + 1, y);
else if (movD() == true)
run(lab, x, y + 1);
else if (movL() == true)
run(lab, x - 1, y);
else
cout << "Error" << endl;
}
int main()
{
x = 1, y = 2; // Start position
run(lab, x, y);
return 0;
}
Besides the global scoping problem with x and y, you haven't done anything to keep the subscripts from running over the edge of the maze into random memory locations. As a result, y continues to decrement, and you back up through memory looking for an asterisk. Since you also recur, you continue this until you blow all your stack space.
Also, you don't seem to be comfortable with boolean values yet: you do a lot of extra work to deal with constants true and false, rather than simply using the value of a boolean expression.
I've fixed these items in your code:
# include <iostream>
using namespace std;
char lab[6][6] =
{
{ '/','/','/','/','/' },
{ '/','*','/','/','/' },
{ '/','*','*','*','/' },
{ '/','/','*','/','/' },
{ '/','/','*','/','/' },
{ '/','/','*','*','*' }
};
void run(char lab[][6], int, int);
bool movU(int x, int y) // Move Up
{
return x >= 0 && y >= 1 &&
x < 6 && y < 6 &&
lab[x][y - 1] == '*';
}
bool movR(int x, int y) // Move right
{
return x >= 0 && y >= 0 &&
x < 5 && y < 6 &&
lab[x+1][y] == '*';
}
bool movD(int x, int y) // Move Down
{
return x >= 0 && y >= 0 &&
x < 6 && y < 5 &&
lab[x][y + 1] == '*';
}
bool movL(int x, int y) // Move Left
{
return x >= 1 && y >= 0 &&
x < 6 && y < 6 &&
lab[x-1][y] == '*';
}
void run(char lab[][6], int x, int y)
{
cout << "ENTER run; x = " << x << "\ty = " << y << endl;
if (movU(x, y)) // I'm getting stuck right here
run(lab, x, y - 1); // Getting negative numbers here
else if (movR(x, y))
run(lab, x + 1, y);
else if (movD(x, y))
run(lab, x, y + 1);
else if (movL(x, y))
run(lab, x - 1, y);
else
cout << "Error" << endl;
}
int main()
{
// x = 1, y = 2; // Start position
run(lab, 1, 2);
return 0;
}
This stays within bounds ... and loops until it runs out of stack space. You need to add code to avoid rechecking ground you've already visited. For instance, you can mark the location with another character, such as an underscore.
You also need to recognize when you're done. What marks the maze exit? You'll need a check in your run routine for that.
beginner to C++ and attempting a dungeon crawler beginner task, upon testing one of the classes I found that printing the 2D array works, however if it is edited and printed, it resets and prints original values it was initialised with.
InitGrid is used to initialize the array.
class MAP
{
public:
/*
Difficulty used in number of enemies and traps created.
1-5 Difficulty
| 1 - Too easy | 2 - Easy | 3 - Normal | 4 - Hard | 5 - Insane |
*/
int Difficulty = Hard; //### Temporary, user selection needs implemented ###
int SpawnPos;
int TPosX; //Treasure Postion, used to checkwinstate.
int TPosY; //Treasure Postion, used to checkwinstate.
char Grid[MAPHeight][MAPWidth];
void InitGrid()
{
for (int y = 0; y < 9; y++) //Row loop
{
for (int x = 0; x < 14; x++) //Column loop
{
Grid[y][x] = { '.' };
}
}
}
void PrintMap()
{
for (int y = 0; y < 9; y++) //This loops on the rows.
{
for (int PrintX = 0; PrintX < 14; PrintX++) //This loops on the columns
{
cout << Grid[y][PrintX] << " ";
}
cout << endl;
}
}
void GenerateEnemies()
{
for (int i = 0; i < Difficulty; i++)
{
int TotEnemies = (Difficulty * 1.5);
for (TotEnemies; TotEnemies == 0; TotEnemies--)
{
int x = rand() % (MAPWidth - 1);
int y = rand() % (MAPHeight - 1);
if (Grid[y][x] == '.')
{
Grid[y][x] = '#';
}
else
{
GenerateEnemies();
}
}
}
}
// Generate Enemies
void GenerateTraps()
{
for (int i = 0; i < Difficulty; i++)
{
int TotTraps = (Difficulty * 1.5);
for (TotTraps; TotTraps == 0; TotTraps--)
{
int x = rand() % (MAPWidth - 1);
int y = rand() % (MAPHeight - 1);
if (Grid[y][x] == '.')
{
Grid[y][x] = 'T';
}
else
{
GenerateTraps();
}
}
}
}
void GenerateTreasure()
{
int x = rand() % MAPWidth;
int y = rand() % MAPHeight;
/*
Randomly selects spawn location
uses tmp variables to overwrite
that grid location.
*/
if (Grid[y][x] == '.')
{
Grid[y][x] = 'X';
}
else
{
GenerateTreasure();
}
TPosX = x;
TPosY = y;
}
};
//PLAYER CLASS
class PLAYER : public MAP
{
public:
int Health = (Difficulty * 1.5);
int PPosX;
int PPosY;
char Direction; //Use cin to get user input after map is updated, used in switch case to move player.
void GenerateSpawn()
{
int x = rand() % (MAPWidth - 1);
int y = rand() % (MAPHeight - 1);
/*
Randomly selects spawn location
uses tmp variables to overwrite
that grid location.
*/
Grid[y][x] = 'P';
PPosX = x;
PPosY = y;
}
void AllowMove(int y, int x)
{
if (Grid[y][x] == '.')
{
Grid[y][x] = '#';
}
else if (Grid[y][x] == 'X')
{
//GameWin();
}
else if (Grid[y][x] == '#')
{
//DamagePlayer();
}
else {}
}
void MovePlayer()
{
switch (Direction)
{
case 'w':
{
int x = PPosX;
int y = (PPosY + 1);
void AllowMove(int y, int x);
}
break;
case 'a':
{
int x = (PPosX - 1);
int y = PPosY;
void AllowMove(int y, int x);
}
break;
case 's':
{
int x = (PPosX);
int y = PPosY;
void AllowMove(int y, int x);
}
break;
case 'd':
{
int x = (PPosX + 1);
int y = PPosY;
void AllowMove(int y, int x);
}
break;
default:
cout << "invalid character, try again." << endl;
Sleep(5000);
//Call function to retry
}
}
};
//######### End #########
//Main Function
int main() {
srand(time(NULL)); //Used to seed rand() values.
SetConsoleTitle(TEXT("Dungeon Crawler"));
//Objects
MAP Map;
PLAYER Player;
Map.InitGrid();
Player.GenerateSpawn();
//Map.GenerateTreasure();
//Map.GenerateEnemies();
//Map.GenerateTraps();
Map.PrintMap();
cout << endl;
}
However, when I run these, I get the following image:
I've attempted debugging in visual studio using breakpoints and at some point it does set the grid value to 'P' but I couldn't find where I gets 'reset' for lack of a better term.
char Grid[MAPHeight][MAPWidth]; needs to be moved outside of the class as a global variable. Currently as the PLAYER class inherits from the MAPS class, when GenerateSpawn() edits the Grid that is created specific to the object linked to PLAYER.
When it is a global variable, it is separate, then when edited by GenerateSpawn() and called by void PrintMap() they both use the same Grid.
That way when it is printed to console it correctly prints out the map.
Answered my own question in case someone else stumbles upon this.
I'm trying to create a simple minesweeper game, and have some issues with creating the board. I am using a 2d vector in lieu of a 2d array and am having trouble incrementing the tiles value to see how many mines are adjacent to the tile.
int Boardsize::createBoard() const {
// vector < vector<Tile> > board;
impl->board.resize(getLength(), vector<Tile>(getWidth(), Tile()));
for (int i = 0; i < getMines(); i++) {
int v1 = rand() % getLength();
int v2 = rand() % getWidth();
if (impl->board[v1][v2].getMine() == true) i--;
else {impl->board[v1][v2].setMine(true);
if (v1 - 1 > -1) impl->board[v1-1][v2]++;
if (v1 + 1 < getLength()) impl->board[v1+1][v2]++;
if (v2 - 1 > -1) impl->board[v1][v2-1]++;
if (v2 + 1 < getWidth()) impl->board[v1][v2+1]++;
if ((v1 - 1 > -1) && (v2 - 1 > -1)) impl->board[v1-1][v2-1]++;
if ((v1 - 1 > -1) && (v2 + 1 < getWidth())) impl->board[v1-1][v2+1]++;
if ((v1 + 1 < getLength()) && (v2 - 1 > -1)) impl->board[v1+1][v2-1]++;
if ((v1 + 1 < getLength()) && (v2 + 1 < getWidth())) impl->board[v1+1][v2+1]++;
}
}
}
Values length, width and mines are set ahead of time. The way I intend it to work is "Check if getMine = true, if yes then game over. If no, isRevealed is set to true and the tile shows how many mines are adjacent to the tile. However, I'm getting the error:
error: no 'operator++(int)' declared for postfix '++' [-fpermissive]|
Do I need to set a seperate function to increment the content? I am assuming that the board.resize fills the vector full of 0's.
I appreciate the help.
Here is the "Tile" file's contents:
namespace Minesweeper {
using namespace std;
class Tile::Tilement {
int status;
bool mine;
int Adjmines;
friend class Tile;
public:
Tilement ()
: status(0), mine(false), Adjmines(0)
{
}
};
Tile::Tile() {
cout << "Tile is being created" << endl;
}
Tile::~Tile() {
cout << "Tile is being deleted" << endl;
}
void Tile::setMine(int a) {
tint->mine = true;
}
void Tile::setStatus(int a) {
if ((a == 0) || (a == 1) || (a == 2)) {
tint->status = a;
}
else {
#ifdef DEBUG
cout << "Tile status invalid" << endl;
#endif // DEBUG
throw invalid_argument("Invalid tile status");
}
}
//void Tile::setContent(char r) {
// tint->content = r;
//}
int Tile::getStatus() const {
return tint->status;
}
char Tile::getAdjcount() const {
return tint->Adjmines;
}
char Tile::getMine() const {
return tint->mine;
}
int Tile::setAdjmines(int a) {
a = a++;
}
char Tile::getContent() const {
if (Tile::getMine() == true) {
return tint->mine;
}
else return tint->Adjmines;
}
EDIT: I've changed the incrementations a bit so that they're now like this:
if (v1 - 1 > -1) impl->board[v1-1][v2].incAdjmines; (etc).
And the incAdjmines function looks like this:
int Tile::incAdjmines() {
Adjmines = Adjmines + 1;
}
And...well, the code compiled, if nothing else, but due to some errors in another fragment of code, I can't tell if it works correctly. Thank you all for your help so far.
You are calling ++ on Tile object which seems with no overload for this operator.
You can solve your problem by overloading this operator for Tile class. Or by directly telling which variable you want to increase for example:
impl->board[v1-1][v2].cout_of_things++
I'm trying to write a maze solver using backtracking. It should see whether it's possible to solve a given puzzle from the starting point S to the end point E. The pseudo code can be seen in this link here. My implementation looks like this:
const int N = 8; // global var
bool exploreMaze(char maze[][N], int x, int y)
{
if(y >= 8 || y < 0 || x >= 7 || x < 0) // null char at end of each 1d array
return false;
if(maze[x][y] == '*')
return false;
if(maze[x][y] == 'E')
return true;
maze[x][y] = '*'; // set grid to '*' as to not loop infinitely
if(exploreMaze(maze, x + 1, y))
{
cout << "up" << ", ";
return true;
}
if(exploreMaze(maze, x - 1, y))
{
cout << "down" << ", ";
return true;
}
if(exploreMaze(maze, x, y - 1))
{
cout << "left" << ", ";
return true;
}
if(exploreMaze(maze, x, y + 1))
{
cout << "right" << ", ";
return true;
}
return false;
}
bool isMazeSolvable(char maze[][N])
{
int startX = -1, startY = -1;
for(int i = 0; i < N; i++)
{
for(int j = 0; j < N; j++)
{
if(maze[i][j] == 'S')
startX = i;
startY = j;
}
}
if(startX == -1)
return false;
return exploreMaze(maze, startX, startY);
}
int main()
{
char maze[N][N] = {"*******", " S ", "*******", " E ", "*******",
"*******", "*******", "*******"};
cout << isMazeSolvable(maze);
return 0;
}
The array that I'm testing in main should definitely have no solution, but somehow I'm getting 1(true) as the output. Any ideas?
Your maze '*' is only initialized out in the Y direction by 7 characters, but your maze walker checks out to 8 character. This allows it to walk around the end of your walls.
I added a quick maze print function and changed the exploreMaze to put '.' where it walks. Giving the following output:
Initial maze:
*******
S
*******
E
*******
*******
*******
*******
left, left, left, left, left, up, up, right, right, right, right, right, right,
1
After explore:
*******
.......
*******.
E.....
*******
*******
*******
*******
Soluton: Either change the initializer to use 8 character walls, or change the exploreMaze function to only look 7 characters in the Y direction.
Also note: You are not doing the "backtracking" part of the maze solver, because you mark where you have been but don't clean off your path on your way out of the recursion. Add
maze[x][y] = ' '; // Clear the grid so we can try this spot again in another recursion
to the end of your exploreMaze function