Maze solver recording backtracked paths - c++

I've gotten my maze solver program to work but it seems to be including back tracked spaces (places it went to and hit a wall so it had to turn around) in the final solution path that it outputs. Here is an example:
How can I prevent this in my current implementation below:
int dir = 4;
bool visited[Max_Maze][Max_Maze][dir];
for (row = 0; row < size; ++ row)
{
for (col = 0; col < size; ++ col)
{
for (dir = 0; dir < 4; ++ dir)
{
visited[row][col][dir]=false;
}
}
}
bool notSolved = true;
int path = 0;
row = 0;
col = 0;
rowStack.push(row);
colStack.push(col);
while (notSolved)
{
//from perspective of person looking at maze on screen
if (((row-1)>=0)&&(maze[row - 1][col] == 0)&&(visited[row][col][0]==false))
{
// if that space is not out of bounds and if you can go up
// and you have not gone in that direction yet, go up
visited[row][col][0] = true;
row--;
rowStack.push(row);
colStack.push(col);
path++;
}
else if (((col+1)<size)&&(maze[row][col + 1] == 0)&&(visited[row][col][1]==false))
{
//else if you can go right etc., go right
visited[row][col][1] = true;
col++;
rowStack.push(row);
colStack.push(col);
path++;
}
else if (((row+1)<size)&&(maze[row + 1][col] == 0)&&(visited[row][col][2]==false))
{
//else if you can go down etc., go down
visited[row][col][2] = true;
row++;
rowStack.push(row);
colStack.push(col);
path++;
}
else if (((col-1)>=0)&&(maze[row][col - 1] == 0)&&(visited[row][col][3]==false))
{
//else if you can go left etc., go left
visited[row][col][3] = true;
col--;
rowStack.push(row);
colStack.push(col);
path++;
}
else
{
//if stuck
if (path == 0)
{
cout << "No Solution Path" << endl;
notSolved = false;
}
else
{
rowStack.pop();
colStack.pop();
row = rowStack.top();
col = colStack.top();
path--;
}
}
if((maze[row][col] == 0) && (row == (size - 1) && col == (size - 1)))
{
//if we reached an exit
cout << "Solution Path:(in reverse)" << endl;
for (int i = 0; i <= path; i++)
{
cout << "row:" << rowStack.top() << " col:" << colStack.top() << endl;
rowStack.pop();
colStack.pop();
}
notSolved = false;
}
}
Simple fix or total restructuring needed?

As the solver goes right into that dead end, it records that it has "visited right from (R, C)", because your visited array is three dimensional. But it never records that it has "visited left from (R, C + 1)". So it thinks it's fine to move to the same position twice, so long as it doesn't make the exact same move twice (which it doesn't, as it's moving left when it backtracks, not right).
It looks like it will work fine as is if you change visited to be a 2-dimensional array and only record positions, not moves. Then every square you've visited before blocks further movement, but that's okay because if the correct solution requires going back to that square you'll eventually hit the else case enough to pop back to it, and from there three must be a never-visited square to explore.

Without commenting on your specific solution, you might consider redoing as a standard depth first search algorithm, which I think you will agree is somewhat more clear:
boolean dfs (State s) {
if (end_state(s)) {
return true;
}
vector<option_t> options = generate_moves(s);
for (vector<option_t>::iterator it = options.begin();
it != options.end(); it++) {
make_move(s, it);
boolean found = dfs(s);
if (found) {
cout << s << endl;
}
undo_move(s, it);
if (found) return true;
}
return false;
}
As you can see, this will work as long as you can create:
some class State that holds your current maze state
end_state function that knows when State is at a solution
generate_moves function that can find all options for current State
make_move that can apply a move against your state
undo_move that can undo a move against state
you define option_t such that it represents a move option
define operator<< for State
I can tell you that certainly the solution I give you does not have problems with printing backtracked spaces (should be clear also from the code).

Related

Knight's tour problem compilation doesn't end

Could anyone point the flaw in the code?
The idea that I used is backtracking with recurrence and I would like to stick to this way of sloving the given problem. When the variable moves is <= 60 couple of answers are printed instantly though the program is still running. If moves = 61,62 it takes couple of minutes to print some solutions and if moves = 63 no solution is printed within 15 mins in both cases the program is still running.
Here is the code:
//checking on which move was the square visited
int board[8][8] = {{1,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
int x = 0;//x and y coordinate of the knight's placement
int y = 0;
//move knight by
int move_to[8][8] = {{1,2},{-1,-2},{-1,2},{1,-2},{2,1},{-2,-1},{-2,1},{2,-1}};
//how many moves have been done
int moves = 0;
void solve()
{
//printing one solution
if(moves==63)
{
for(int k = 0; k < 8; k++)
{
for(int n = 0; n < 8; n++)
cout << setw(2) << board[k][n] << " ";
cout << "\n";
}
cout << "--------------------\n";
return;
}
else
{
for(int i = 0; i < 8; i++)
{
//checking if knight is not leaving the board
if(x+move_to[i][0]<0 || x+move_to[i][0]>7 || y+move_to[i][1]<0 ||
y+move_to[i][1]>7 || board[x+move_to[i][0]][y+move_to[i][1]]>0)
continue;
//moving theknight
x+=move_to[i][0];
y+=move_to[i][1];
//increasing the moves count
moves++;
//marking the square to be visited
board[x][y] = moves+1;
//backtracking
solve();
board[x][y] = 0;
x-=move_to[i][0];
y-=move_to[i][1];
moves--;
}
}
}
int main()
{
solve();
return 0;
}
I remember this problem from study. I do not fix them but I change initial position then the first path is found faster (that is how I passed this lab ;P). It is normal because
the number of path is too big.
But you can:
choose from move_to in random order
use multiple threads
Other hand you can read about "Constraint Programming"

Vectors with binary search in c++

My code doesn't seem to work and I cannot understand why.
When the user enters a number to search for its location it doesn't show anything. If anyone could explain it to me I would greatly appreciate it.
void Array::binarySearch(vector<int> vect)
{
int search_val;
int high = (int)vect.size();
int low = 0;
int mid = 0;
bool found = false;
cout << "Enter Number to search : ";
cin>>search_val;
while (low <= high && !found) {
mid = (high + low)/2;
if (search_val > vect[mid]) {
low = mid + 1;
} else if (search_val < vect[mid]) {
high = mid - 1;
} else {
cout << "Number you entered " << search_val << " was found in position " << mid << endl;
found = true;
}
}
if (!found) {
cout << " The value isn't found " << endl;
}
}
sorted algo:
void Array::arrSort(vector<int> vect)
{
for (unsigned int i = 0; i < vect.size()-1; i++)
{
for (unsigned int j = 0; j < vect.size()-i-1; j++)
{
if (vect[j] > vect[j+1])
{
int x = vect[j+1];
vect[j+1] = vect[j];
vect[j] = x;
}
}
}
cout<<"Sorted output is "<<endl;
printArr(vect);
}
Your arrSort function takes its parameter by value, so it receives (and sorts) a copy of the original array.
To sort the array you're passing in, take the parameter by reference:
void Array::arrSort(vector<int> &vect)
As someone has pointed out, you must ensure that you are performing binary search on a sorted array. Perhaps, you should build and test each algorithm separately to ensure correctness before combining them together.
Check out std::sort to get your binary search function working, then work on your sort function––or vice versa.
Also, if you have found the item you are looking for say, vect[mid] == search_val you can go ahead and return true (or print like you've done) and terminate the algorithm.

Tic Tac Toe: Evaluating Heuristic Value of a Node

Pardon me if this question already exists, I've searched a lot but I haven't gotten the answer to the question I want to ask. So, basically, I'm trying to implement a Tic-Tac-Toe AI that uses the Minimax algorithm to make moves.
However, one thing I don't get is, that when Minimax is used on an empty board, the value returned is always 0 (which makes sense because the game always ends in a draw if both players play optimally).
So Minimax always chooses the first tile as the best move when AI is X (since all moves return 0 as value). Same happens for the second move and it always chooses the second tile instead. How can I fix this problem to make my AI pick the move with the higher probability of winning? Here is the evaluation and Minimax function I use (with Alpha-Beta pruning):
int evaluate(char board[3][3], char AI)
{
for (int row = 0; row<3; row++)
{
if (board[row][0] != '_' && board[row][0] == board[row][1] && board[row][1] == board[row][2])
{
if (board[row][0]==AI)
{
return +10;
}
else
{
return -10;
}
}
}
for (int col = 0; col<3; col++)
{
if (board[0][col] != '_' && board[0][col] == board[1][col] && board[1][col] == board[2][col])
{
if (board[0][col]==AI)
{
return +10;
}
else
{
return -10;
}
}
}
if (board[1][1] != '_' && ((board[0][0]==board[1][1] && board[1][1]==board[2][2]) || (board[0][2]==board[1][1] && board[1][1]==board[2][0])))
{
if (board[1][1]==AI)
{
return +10;
}
else
{
return -10;
}
}
return 0;
}
int Minimax(char board[3][3], bool AITurn, char AI, char Player, int depth, int alpha, int beta)
{
bool breakout = false;
int score = evaluate(board, AI);
if(score == 10)
{
return score - depth;
}
else if(score == -10)
{
return score + depth;
}
else if(NoTilesEmpty(board))
{
return 0;
}
if(AITurn == true)
{
int bestvalue = -1024;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j<3; j++)
{
if(board[i][j] == '_')
{
board[i][j] = AI;
bestvalue = max(bestvalue, Minimax(board, false, AI, Player, depth+1, alpha, beta));
alpha = max(bestvalue, alpha);
board[i][j] = '_';
if(beta <= alpha)
{
breakout = true;
break;
}
}
}
if(breakout == true)
{
break;
}
}
return bestvalue;
}
else if(AITurn == false)
{
int bestvalue = +1024;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j<3; j++)
{
if(board[i][j] == '_')
{
board[i][j] = Player;
bestvalue = min(bestvalue, Minimax(board, true, AI, Player, depth+1, alpha, beta));
beta = min(bestvalue, beta);
board[i][j] = '_';
if(beta <= alpha)
{
breakout = true;
break;
}
}
}
if(breakout == true)
{
break;
}
}
return bestvalue;
}
}
Minimax assumes optimal play, so maximizing "probability of winning" is not a meaningful notion: Since the other player can force a draw but cannot force a win, they will always force a draw. If you want to play optimally against a player who is not perfectly rational (which, of course, is one of the only two ways to win*), you'll need to assume some probability distribution over the opponent's moves and use something like ExpectMinimax, where with some probability the opponent's move is overridden by a random mistake. Alternatively, you can deliberately restrict the ply of the minimax search, using a heuristic for the opponent's play beyond a certain depth (but still searching the game tree for your own moves.)
* The other one is not to play.
Organize your code into smaller routines so that it looks tidier and easier to debug. Apart from the recursive minimax function, an all-possible-valid-move generation function and a robust evaluation sub-routine are essential ( which seems lacking here).
For example, at the beginning of the game, the evaluation algorithm should return a non-zero score, every position should have a relative scoring index ( eg middle position may have slightly higher weightage than the corners).
Your minimax boundary condition - return if there is no empty cell positions ; is flawed as it will evaluate even when a winning/losing move occurred in the preceding ply. Such conditions will aggravate in more complex AI games.
If you are new to minimax, you can find plenty of ready to compile sample codes on CodeReview

sudoku,recursive function solves half the puzzle

I'm working on a Sudoku solver, and my program is having trouble recursing backwards when it has exhausted its outputs.
I have four functions that do the check:
scolumn, srow, sbox. Each one will return false if the number already exists in the column row or box respectively.
bool sudoku::solve(int row, int column)
{
if(column == 9)
{
column = 0;
row +=1;
}
if(puzzle[row][column] != 0)
{
solve(row, column + 1);
return false;
}
else
{
for(int n = 0; n < 10; n ++)
{
if(srow(column, n) && scolumn(row,n) && sbox(row, column, n)
{
puzzle[row][column] = n;
if(!solve(row, column + 1);
table[row][column] = 0;
}
}
puzzle[row][column] = 0;// if not commented out then infinite loop
}
return false
}
the problem with it is that if its at 9 and there is no next choice, it will not backtrack correctly.
There are a number of problems with your code, as people have observed in the comments.
This answer summarises some of them:
1) As #n.m. said, you should not be trying '0' as a valid choice in a cell. That will be the cause of some infinite looping, no doubt.
2) As you have observed, you don't know how the recursion finishes. The answer is that when you get to the last cell, and you find a value that works in it, you are supposed to return true. This is what is supposed to break the for(n) loop: that loop is saying "try each number until the call of solve to the right of this cell succeeds'. Success is measured by your routine returning true.
Since you try every number (n) in the current cell, no matter whether or not the call to the solve on its right works ... it's not going to work.
You'll know that you're more on the right track when:
You can see the place in your code where you return true when you discover that you can put a number in the last cell (9,9)
You can see how it is that you stop trying numbers (n=0..9) when the call to the right succeeds.
Given int puzzle[9][9], and your srow, scol, and sbox functions:
bool sudoku::solve(int row, int column) //to solve entire puzzle, call with parameters 0 and 0
{
int cell;
//ignore all nonzero cells (zero = empty)
while (row < 9 && puzzle[row][column] != 0)
{
column++;
if (column == 9)
{
row++;
column = 0;
}
}
if (row == 9) return true; //puzzle is already solved
//try values 1-9 inclusive. If successful, then return true
for (cell = 1; cell <= 9; cell++)
{
puzzle[row][column] = cell;
if (srow(row) &&
scol(column) &&
sbox(row-row%3, column-column%3) &&
solve(row, column)) //recursion!!
{
return true;
}
}
//if no value works, reset the cell and return false.
puzzle[row][column] = 0;
return false;
}

BFS maze help c++

I am attempting to make a maze-solver using a Breadth-first search, and mark the shortest path using a character '*'
The maze is actually just a bunch of text. The maze consists of an n x n grid, consisting of "#" symbols that are walls, and periods "." representing the walkable area/paths. An 'S' denotes start, 'F' is finish. Right now, this function does not seem to be finding the solution (it thinks it has the solution even when one is impossible). I am checking the four neighbors, and if they are 'unfound' (-1) they are added to the queue to be processed.
The maze works on several mazes, but not on this one:
...###.#....
##.#...####.
...#.#.#....
#.####.####.
#F..#..#.##.
###.#....#S.
#.#.####.##.
....#.#...#.
.####.#.#.#.
........#...
What could be missing in my logic?
int mazeSolver(char *maze, int rows, int cols)
{
int start = 0;
int finish = 0;
for (int i=0;i<rows*cols;i++) {
if (maze[i] == 'S') { start=i; }
if (maze[i] == 'F') { finish=i; }
}
if (finish==0 || start==0) { return -1; }
char* bfsq;
bfsq = new char[rows*cols]; //initialize queue array
int head = 0;
int tail = 0;
bool solved = false;
char* prd;
prd = new char[rows*cols]; //initialize predecessor array
for (int i=0;i<rows*cols;i++) {
prd[i] = -1;
}
prd[start] = -2; //set the start location
bfsq[tail] = start;
tail++;
int delta[] = {-cols,-1,cols,+1}; // North, West, South, East neighbors
while(tail>head) {
int front = bfsq[head];
head++;
for (int i=0; i<4; i++) {
int neighbor = front+delta[i];
if (neighbor/cols < 0 || neighbor/cols >= rows || neighbor%cols < 0 || neighbor%cols >= cols) {
continue;
}
if (prd[neighbor] == -1 && maze[neighbor]!='#') {
prd[neighbor] = front;
bfsq[tail] = neighbor;
tail++;
if (maze[neighbor] == 'F') { solved = true; }
}
}
}
if (solved == true) {
int previous = finish;
while (previous != start) {
maze[previous] = '*';
previous = prd[previous];
}
maze[finish] = 'F';
return 1;
}
else { return 0; }
delete [] prd;
delete [] bfsq;
}
Iterating through neighbours can be significantly simplified(I know this is somewhat similar to what kobra suggests but it can be improved further). I use a moves array defining the x and y delta of the given move like so:
int moves[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};
Please note that not only tis lists all the possible moves from a given cell but it also lists them in clockwise direction which is useful for some problems.
Now to traverse the array I use a std::queue<pair<int,int> > This way the current position is defined by the pair of coordinates corresponding to it. Here is how I cycle through the neighbours of a gien cell c:
pair<int,int> c;
for (int l = 0;l < 4/*size of moves*/;++l){
int ti = c.first + moves[l][0];
int tj = c.second + moves[l][1];
if (ti < 0 || ti >= n || tj < 0 || tj >= m) {
// This move goes out of the field
continue;
}
// Do something.
}
I know this code is not really related to your code, but as I am teaching this kind of problems trust me a lot of students were really thankful when I showed them this approach.
Now back to your question - you need to start from the end position and use prd array to find its parent, then find its parent's parent and so on until you reach a cell with negative parent. What you do instead considers all the visited cells and some of them are not on the shortest path from S to F.
You can break once you set solved = true this will optimize the algorithm a bit.
I personally think you always find a solution because you have no checks for falling off the field. (the if (ti < 0 || ti >= n || tj < 0 || tj >= m) bit in my code).
Hope this helps you and gives you some tips how to improve your coding.
A few comments:
You can use queue container in c++, its much more easier in use
In this task you can write something like that:
int delta[] = {-1, cols, 1 -cols};
And then you simple can iterate through all four sides, you shouldn't copy-paste the same code.
You will have problems with boundaries of your array. Because you are not checking it.
When you have founded finish you should break from cycle
And in last cycle you have an error. It will print * in all cells in which you have been (not only in the optimal way). It should look:
while (finish != start)
{
maze[finish] = '*';
finish = prd[finish];
}
maze[start] = '*';
And of course this cycle should in the last if, because you don't know at that moment have you reach end or not
PS And its better to clear memory which you have allocate in function