how could I solve 0HH1 with backtracking in c++ - c++

I'm trying to solve this puzzle using backtrack algorithm. In c++
I face the problem that I couldn't apply the backtrack
void try1(int x,int y)
{
int k=-1;
do{
k++ ;
if(check_color(c[k],x,y))
{
h[x][y]=c[k];// c[k]= r or b;
if ( check_full() && check_array() && check_equal() )
{
cout<<"coloring had finished"; cout<<" \n ";
print(h); getch();
}
else
{
if(y==9&&x<9)
{
y = -1; x++;
}
while(y<9 )
{
y=y+1;
if(h[x][y]==' ')
try1(x,y);
/* here should be the backtrack I think
if(q=='n')
{ x--;cout<<h[x][y];
if(h[x][y]=='b'){h[x][y]='r';}
else {h[x][y]='b';}}*/
else if ( y==9 && x<9 ){
y=-1 ;x++ ;
}
}
}
}
} while ( k<1 ) ;
}
could anyone help me???
Ineed all possible solution back tracking

Backtrack algorithm is quite simple. You just pick a move. Check if that move is okay. And then you go to next position. Here is what I think you should write.
void try1(int x,int y)
{
for ( int k = 0; k < 2; ++k ){
h[x][y] = c[k];
if ( is it okay to put this color in this position ){
if ( x == 9 && y == 9 ){ // table is full
// we have found the solution
// print the table
return;
}
// assuming x is the number of current row
// assuming y is the number of current column
// assuming we are filling the matrix from left to right
// and top to bottom
int next_x, next_y;
if ( y == 9 ){
next_y = 0;
next_x = x+1;
} else {
next_y = y+1;
next_x = x;
}
try1(next_x, next_y);
}
h[x][y] = ' '; // clear this place
}
}

Related

Issue with A* pathfinding. Compiles, but acts strangely

I recently took a stab at the A* search algorithm. I've tried it before to no avail, but I've had a level of success this time. It always finds a path, unless it can't (obviously) and it's USUALLY close to the shortest one. Other times it acts really screwy as in adds one too many times, goes in a zig zag pattern, moves in the wrong direction randomly. It's very strange. Screenshot here.
Code below:
int manhattan( Coord a, Coord b )
{
int x = abs(b.x-a.x);
int y = abs(b.y-a.y);
return x+y;
}
std::vector<Coord> AStar( std::vector< std::vector< int > > grid, Point start, Point end )
{
//The current 'focal' point.
Point *cur;
//The open and closed lists.
std::vector< Point* > closed;
std::vector< Point* > open;
//Start by adding the starting position to the list.
open.push_back( &start );
//Just so it knows whether or not to try and reconstruct a path.
bool error = true;
while( open.size() > 0 )
{
//The current point is the first entry in the open list.
cur = open.at(0);
if( cur->getPos() == end.getPos() )
{
error = false;
break;
}
//Add in all the neighbors of the current point.
for( int y = -1; y <= 1; y++ )
{
for( int x = -1; x <= 1; x++ )
{
int curX = cur->getPos().x+x;
int curY = cur->getPos().y+y;
int movCost = 10;
//If it is a diagonal, make it cost 14 instead of 10.
if( (y == -1 && x == -1)||
(y == 1 && x == -1)||
(y == -1 && x == 1)||
(y == 1 && x == 1))
{
movCost = 14;
//continue;
}
Coord temp( curX, curY );
bool make = true;
//If it is outside the range of the map, continue.
if( curY >= grid.size() ||
curX >= grid.size() )
{
continue;
}
/*
These two loops are to check whether or not the point's neighbors already exist.
This feels really sloppy to me. Please tell me if there is a better way.
*/
for( int i = 0; i < open.size(); i++ )
{
if( temp == open.at(i)->getPos() )
{
make = false;
break;
}
}
for( int i = 0; i < closed.size(); i++ )
{
if( temp == closed.at(i)->getPos() )
{
make = false;
break;
}
}
//If the point in the map is a zero, then it is a wall. Continue.
if( (grid.at(temp.x).at(temp.y) == 0 ) ||
( temp.x<0 || temp.y < 0 ) )
{
continue;
}
//If it is allowed to make a new point, it adds it to the open list.
if( make )
{
int gScore = manhattan( start.getPos(), Coord( curX, curY ) );
int hScore = manhattan( end.getPos(), Coord( curX, curY ) );
int tileCost = grid[curX][curY];
int fScore = gScore+hScore+tileCost;
open.push_back( new Point( curX, curY, fScore, cur ) );
}
}
}
//It then pushes back the current into the closed set as well as erasing it from the open set.
closed.push_back( cur );
open.erase( open.begin() );
//Heapsort works, guranteed. Not sure if it's a stable sort, though. From what I can tell that shouldn't matter, though.
open = heapsort( open );
}
std::vector<Coord> path;
if( error )
{
return path;
}
//Reconstruct a path by tracing through the parents.
while( cur->getParent() != nullptr )
{
path.push_back( cur->getPos() );
cur = cur->getParent();
}
path.push_back( cur->getPos() );
return path;
}
Anyway! Thanks for any help ahead of time! If you want to give me some helpful tips or any other help that would be awesome! Thanks very much! :^)
I can see that you're trying to make diagonals more expensive here:
int movCost = 10;
//If it is a diagonal, make it cost 14 instead of 10.
if( (y == -1 && x == -1)||
(y == 1 && x == -1)||
(y == -1 && x == 1)||
(y == 1 && x == 1))
{
movCost = 14;
//continue;
}
But you don't actually use movCost elsewhere in your code.
Instead, your cost function only uses Manhattan distance:
int gScore = manhattan( start.getPos(), Coord( curX, curY ) );
int hScore = manhattan( end.getPos(), Coord( curX, curY ) );
int tileCost = grid[curX][curY];
int fScore = gScore+hScore+tileCost;
Which explains the diagonally zig-zagging paths:
By the way, there is one more logical error in your code: in A*, the g-cost should be calculated as the actual cost from the start to the current node, not estimated like you have using your manhattan() function. You should be saving the cost along with your points in your open and closed sets.
In future, you should turn on all compiler warnings and don't ignore them. This will catch mistakes that are easy to miss, like unused variables.

A little bug about collision in my program

I'm trying to figure out my problem for an hour.
I'm going to draw what is happening.
char trap = 'Q';
char character = 'L';
....
.Q..
..L.
....
when L moves up and Q moves to right they collide and the program ends. but:
....
.QL.
....
....
when L moves to left and Q moves to right they dont collide the same way as the example above instead, whats happening is:
....
..Q.
....
....
here's my code. sorry for my bad english :(
test if the move is 'w' , 'a' , 's' or 'd' :
void cave::move(int& x, int& y, char m, char unit)
{
if ( m == 'W' || m == 'w' ) // if moves up
{
floor[x][y] = tile;
x -= 1;
for ( unsigned short int x = 0; x < 3; x++ )
{
if ( floor[x][y] == wall && floor[x][y] == trap[x] )
{
x += 1;
trapsMove();
}
}
floor[x][y] = unit;
}
else if ( m == 'A' || m == 'a' ) // if moves to left
{
floor[x][y] = tile;
y -= 1;
for ( unsigned short int x = 0; x < 3; x++ )
{
if ( floor[x][y] == wall && floor[x][y] == trap [x] )
{
y += 1;
trapsMove();
}
}
floor[x][y] = unit;
}
else if ( m == 'S' || m == 's' ) // if moves down
{
floor[x][y] = tile;
x += 1;
for ( unsigned short int x = 0; x < 3; x++ )
{
if ( floor[x][y] == wall && floor[x][y] == trap[x] )
{
x -= 1;
trapsMove();
}
}
floor[x][y] = unit;
}
else if ( m == 'D' || m == 'd' ) // if moves to right
{
floor[x][y] = tile;
y += 1;
for ( unsigned short int x = 0; x < 3; x++ )
{
if ( floor[x][y] == wall && floor[x][y] == trapx] )
{
y -= 1;
trapsMove();
}
}
floor[x][y] = unit;
}
else
control();
return;
}
ai moves function
void cave::trapsMove()
{
int r[3]; // each index will hold the movement of traps
for ( unsigned short int x = 0; x < 3; x++ )
{
r[x] = rand() % 4 + 1;
if ( r[x] == 1 ) // moves up
move(traps_positionX[x],traps_positionY[x],'w',trap[x]);
else if ( r[x] == 2 ) // moves to left
move(traps_positionX[x],traps_positionY[x],'a',trap[x]);
else if ( r[x] == 3 ) // moves down
move(traps_positionX[x],traps_positionY[x],'s',trap[x]);
else if ( r[x] == 4 ) // moves to right
move(traps_positionX[x],traps_positionY[x],'d',trap[x]);
}
return;
}
check if collide
bool cave::collision()
{
for ( unsigned short int x = 0; x < 3; x++ )
{
if ( floor[character_positionX][character_positionY] == trap[x] )
return true;
}
return false;
}
Well it seems from your code that the Trap and Player switch their position.
However the position switch from your Trap (Q) overwrites the Player (L) with a floor tile.
Essentially this happens:
(1) .QL.
(2) .L.. // L and Q inhabit the same tile
(3) ..Q. // Q overwrites L with a '.' tile
Your code suffers from convolution, because you try to either do too much in one function or do it in several different places. This leads to you missing for instance the necessary collision check in the above example.
A better strategy would be to try to structure your program flow. For instance you currently have:
(1) Prompt for a direction
(2) Move player tile
(2a) If player hits a tile which is a Trap or a Wall (typo in your code, must be || instead of &&) move the traps
<-- (2a) is another pitfall where traps can do two moves in a row.
(3) Move the traps
(4) check for collision
(5) repeat from (1)
I think what you wanted was:
(1) Prompt for a direction
(2) Move player tile
(2a) check for collision
(3) Move traps
(3a) check for collision
(6) repeat from (1)
As for the refactoring try to recycle your code. For instance in your move() function the char 'w' (...) only influences the 'x' or 'y' variable. Thus you could write it also as
move(...) {
if((m=='w')||(m=='W')) { y = y+1 }
else if((m=='a')||(m=='A')) { x = x-1 } // same for SD
if(floor[x][y] != wall) {
// set new position to object, if it can't move, just don't set it
}
}
This way you don't have to copy&paste your for-loop with minimal alterations.

Modify an array in spiral way

I am trying to make this go through the array in a spiral order. When it finds 2, it should replace it with 0 and the next number in the spiral order should become 2. So, if my array is
000
200
000
is should become
000
020
000
The variable ok tells me if I found that number 2 and simply modifies the next number to 2. Note that it doesn't loop through it. When It reaches the center of the array, it stops and doesn't go backwards or starts over.
Any ideas why it doesn't work? It simply doesn't modify my array at all.
#include<iostream>
using namespace std;
#define ROWS 3
#define COLS 3
int main()
{
int arr[ROWS][COLS] = {{2,0,0},
{0,0,0},
{0,0,0}};
// Four direction counters of current movement
// Horizontal right, vertical bottom, horizontal left and vertical top respectively
int hr, vb, hl, vt, ok=0;
// levl indicates current depth of our imaginary rectangle into array. Starting value is zero
// since we are looping on the boundaries and ending value is the inner most rectangle
int levl;
for (levl=0; levl < COLS - levl; levl++)
{
for(hr=levl; hr < COLS-levl; hr++) // go right
{
if (ok==1)
{
arr[levl][hr] == 2;
ok = 2;
}
if ( (arr[levl][hr] == 2) && (ok == 0) )
{
arr[levl][hr] == 0;
ok = 1;
}
}
for(vb=levl+1; vb < COLS-levl; vb++) // go down
{
if (ok == 1)
{
arr[vb][hr-1] == 2;
ok = 2;
}
if ( (arr[vb][hr-1] == 2) && (ok == 0) )
{
arr[vb][hr-1] == 0;
ok = 1;
}
}
for(hl=vb-1; hl-1 >= levl; hl--) // go left
{
if ( ok == 1)
{
arr[vb-1][hl-1] == 2;
ok = 2;
}
if ( (arr[vb-1][hl-1] == 2) && (ok == 0) )
{
arr[vb-1][hl-1] == 0;
ok = 1;
}
}
for(vt=vb-1; vt-1 > levl; vt--) // go up
{
if (ok == 1)
{
arr[vt-1][hl] == 2;
ok = 2;
}
if ( (arr[vt-1][hl] == 2) && (ok==0) )
{
arr[vt-1][hl] == 0;
ok = 1;
}
}
}
cout << endl;
for(int t = 0;t < 3;t++)
{
for(int u = 0;u < 3;u++)
cout<<arr[t][u]<<" ";
cout<<endl;
}
int a;
cin>>a;
return 0;
}
The reason that your array is not being modified is because you are using "==" instead of "=". So
if ((arr[levl][hr] == 2)&&(ok==0))
{
arr[levl][hr] == 0;
ok=1;
}
should be
if ((arr[levl][hr] == 2)&&(ok==0))
{
arr[levl][hr] = 0;
ok=1;
}
== Is a comparison operator and = assigns the value. Check your code very carefully and make it more readable for you could be able to find easy mistakes like that :).

Placing random numbers in a grid

I need to place numbers within a grid such that it doesn't collide with each other. This number placement should be random and can be horizontal or vertical. The numbers basically indicate the locations of the ships. So the points for the ships should be together and need to be random and should not collide.
I have tried it:
int main()
{
srand(time(NULL));
int Grid[64];
int battleShips;
bool battleShipFilled;
for(int i = 0; i < 64; i++)
Grid[i]=0;
for(int i = 1; i <= 5; i++)
{
battleShips = 1;
while(battleShips != 5)
{
int horizontal = rand()%2;
if(horizontal == 0)
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != j)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row+k)*8+(column)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row+k)*8+(column)] = 1;
battleShipFilled = true;
}
battleShips++;
}
else
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row)*8+(column+k)] = 1;
battleShipFilled = true;
}
battleShips++;
}
}
}
}
But the code i have written is not able to generate the numbers randomly in the 8x8 grid.
Need some guidance on how to solve this. If there is any better way of doing it, please tell me...
How it should look:
What My code is doing:
Basically, I am placing 5 ships, each of different size on a grid. For each, I check whether I want to place it horizontally or vertically randomly. After that, I check whether the surrounding is filled up or not. If not, I place them there. Or I repeat the process.
Important Point: I need to use just while, for loops..
You are much better of using recursion for that problem. This will give your algorithm unwind possibility. What I mean is that you can deploy each ship and place next part at random end of the ship, then check the new placed ship part has adjacent tiles empty and progress to the next one. if it happens that its touches another ship it will due to recursive nature it will remove the placed tile and try on the other end. If the position of the ship is not valid it should place the ship in different place and start over.
I have used this solution in a word search game, where the board had to be populated with words to look for. Worked perfect.
This is a code from my word search game:
bool generate ( std::string word, BuzzLevel &level, CCPoint position, std::vector<CCPoint> &placed, CCSize lSize )
{
std::string cPiece;
if ( word.size() == 0 ) return true;
if ( !level.inBounds ( position ) ) return false;
cPiece += level.getPiece(position)->getLetter();
int l = cPiece.size();
if ( (cPiece != " ") && (word[0] != cPiece[0]) ) return false;
if ( pointInVec (position, placed) ) return false;
if ( position.x >= lSize.width || position.y >= lSize.height || position.x < 0 || position.y < 0 ) return false;
placed.push_back(position);
bool used[6];
for ( int t = 0; t < 6; t++ ) used[t] = false;
int adj;
while ( (adj = HexCoord::getRandomAdjacentUnique(used)) != -1 )
{
CCPoint nextPosition = HexCoord::getAdjacentGridPositionInDirection((eDirection) adj, position);
if ( generate ( word.substr(1, word.size()), level, nextPosition, placed, lSize ) ) return true;
}
placed.pop_back();
return false;
}
CCPoint getRandPoint ( CCSize size )
{
return CCPoint ( rand() % (int)size.width, rand() % (int)size.height);
}
void generateWholeLevel ( BuzzLevel &level,
blockInfo* info,
const CCSize &levelSize,
vector<CCLabelBMFont*> wordList
)
{
for ( vector<CCLabelBMFont*>::iterator iter = wordList.begin();
iter != wordList.end(); iter++ )
{
std::string cWord = (*iter)->getString();
// CCLog("Curront word %s", cWord.c_str() );
vector<CCPoint> wordPositions;
int iterations = 0;
while ( true )
{
iterations++;
//CCLog("iteration %i", iterations );
CCPoint cPoint = getRandPoint(levelSize);
if ( generate (cWord, level, cPoint, wordPositions, levelSize ) )
{
//Place pieces here
for ( int t = 0; t < cWord.size(); t++ )
{
level.getPiece(wordPositions[t])->addLetter(cWord[t]);
}
break;
}
if ( iterations > 1500 )
{
level.clear();
generateWholeLevel(level, info, levelSize, wordList);
return;
}
}
}
}
I might add that shaped used in the game was a honeycomb. Letter could wind in any direction, so the code above is way more complex then what you are looking for I guess, but will provide a starting point.
I will provide something more suitable when I get back home as I don't have enough time now.
I can see a potential infinite loop in your code
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
Here, nothing prevents row from being 0, as it was assignd rand%8 earlier, and k can be assigned a negative value (since j can be positive). Once that happens nothing will end the while loop.
Also, I would recommend re-approaching this problem in a more object oriented way (or at the very least breaking up the code in main() into multiple, shorter functions). Personally I found the code a little difficult to follow.
A very quick and probably buggy example of how you could really clean your solution up and make it more flexible by using some OOP:
enum Orientation {
Horizontal,
Vertical
};
struct Ship {
Ship(unsigned l = 1, bool o = Horizontal) : length(l), orientation(o) {}
unsigned char length;
bool orientation;
};
class Grid {
public:
Grid(const unsigned w = 8, const unsigned h = 8) : _w(w), _h(h) {
grid.resize(w * h);
foreach (Ship * sp, grid) {
sp = nullptr;
}
}
bool addShip(Ship * s, unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) { // if in valid range
if (s->orientation == Horizontal) {
if ((x + s->length) <= _w) { // if not too big
int p = 0; //check if occupied
for (int c1 = 0; c1 < s->length; ++c1) if (grid[y * _w + x + p++]) return false;
p = 0; // occupy if not
for (int c1 = 0; c1 < s->length; ++c1) grid[y * _w + x + p++] = s;
return true;
} else return false;
} else {
if ((y + s->length) <= _h) {
int p = 0; // check
for (int c1 = 0; c1 < s->length; ++c1) {
if (grid[y * _w + x + p]) return false;
p += _w;
}
p = 0; // occupy
for (int c1 = 0; c1 < s->length; ++c1) {
grid[y * _w + x + p] = s;
p += _w;
}
return true;
} else return false;
}
} else return false;
}
void drawGrid() {
for (int y = 0; y < _h; ++y) {
for (int x = 0; x < _w; ++x) {
if (grid.at(y * w + x)) cout << "|S";
else cout << "|_";
}
cout << "|" << endl;
}
cout << endl;
}
void hitXY(unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) {
if (grid[y * _w + x]) cout << "You sunk my battleship" << endl;
else cout << "Nothing..." << endl;
}
}
private:
QVector<Ship *> grid;
unsigned _w, _h;
};
The basic idea is create a grid of arbitrary size and give it the ability to "load" ships of arbitrary length at arbitrary coordinates. You need to check if the size is not too much and if the tiles aren't already occupied, that's pretty much it, the other thing is orientation - if horizontal then increment is +1, if vertical increment is + width.
This gives flexibility to use the methods to quickly populate the grid with random data:
int main() {
Grid g(20, 20);
g.drawGrid();
unsigned shipCount = 20;
while (shipCount) {
Ship * s = new Ship(qrand() % 8 + 2, qrand() %2);
if (g.addShip(s, qrand() % 20, qrand() % 20)) --shipCount;
else delete s;
}
cout << endl;
g.drawGrid();
for (int i = 0; i < 20; ++i) g.hitXY(qrand() % 20, qrand() % 20);
}
Naturally, you can extend it further, make hit ships sink and disappear from the grid, make it possible to move ships around and flip their orientation. You can even use diagonal orientation. A lot of flexibility and potential to harness by refining an OOP based solution.
Obviously, you will put some limits in production code, as currently you can create grids of 0x0 and ships of length 0. It's just a quick example anyway. I am using Qt and therefore Qt containers, but its just the same with std containers.
I tried to rewrite your program in Java, it works as required. Feel free to ask anything that is not clearly coded. I didn't rechecked it so it may have errors of its own. It can be further optimized and cleaned but as it is past midnight around here, I would rather not do that at the moment :)
public static void main(String[] args) {
Random generator = new Random();
int Grid[][] = new int[8][8];
for (int battleShips = 0; battleShips < 5; battleShips++) {
boolean isHorizontal = generator.nextInt(2) == 0 ? true : false;
boolean battleShipFilled = false;
while (!battleShipFilled) {
// Select a random row and column for trial
int row = generator.nextInt(8);
int column = generator.nextInt(8);
while (Grid[row][column] == 1) {
row = generator.nextInt(8);
column = generator.nextInt(8);
}
int lengthOfBattleship = 0;
if (battleShips == 0) // Smallest ship should be of length 2
lengthOfBattleship = (battleShips + 2);
else // Other 4 ships has the length of 2, 3, 4 & 5
lengthOfBattleship = battleShips + 1;
int numberOfCorrectLocation = 0;
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal && row + k > 0 && row + k < 8) {
if (Grid[row + k][column] == 1)
break;
} else if (!isHorizontal && column + k > 0 && column + k < 8) {
if (Grid[row][column + k] == 1)
break;
} else {
break;
}
numberOfCorrectLocation++;
}
if (numberOfCorrectLocation == lengthOfBattleship) {
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal)
Grid[row + k][column] = 1;
else
Grid[row][column + k] = 1;
}
battleShipFilled = true;
}
}
}
}
Some important points.
As #Kindread said in an another answer, the code has an infinite loop condition which must be eliminated.
This algorithm will use too much resources to find a solution, it should be optimized.
Code duplications should be avoided as it will result in more maintenance cost (which might not be a problem for this specific case), and possible bugs.
Hope this answer helps...

I'm trying to change my Maze traversal recursive coding part into a while loop

Here's my code.
#include <iostream>
using namespace std;
enum Direction { EAST, NORTH, WEST, SOUTH };
const int size = 12;
int xStart = 2; int yStart = 0;
char *maze2[ ] = {
"############",
"#...#......#",
"..#.#.####.#",
"###.#....#.#",
"#....###.#..",
"####.#.#.#.#",
"#..#.#.#.#.#",
"##.#.#.#.#.#",
"#........#.#",
"######.###.#",
"#......#...#",
"############",
};
void printMaze ( char maze[][ size ] );
void mazeTraverse( char maze[][ size ], int x, int y, int direction );
int main()
{
char maze[ size ][ size ];
for (int x = 0; x < size; x++ )
for (int y = 0; y < size; y++)
maze[ x ][ y ] = maze2[ x ][ y ];
printMaze( maze );
mazeTraverse( maze, xStart, yStart, EAST);
}
void printMaze ( char maze[][ size ] )
{
for ( int x = 0; x < size; x++)
{
for ( int y = 0; y < size; y++)
cout << maze[ x ][ y ];
cout << endl;
}
cout << endl;
cout << "\nHit return to see next move\n";
cin.get();
}
bool validMove( char maze[][ size ], int x, int y )
{
return x >= 0 && x < size && y >= 0 && y < size && maze[x][y] != '#';
}
bool coordsAreEdge( int x, int y )
{
return x== 0 || x== size - 1 || y == 0 || y== size - 1;
}
void mazeTraverse( char maze[][ size ], int x, int y, int direction )
{
maze[ x ][ y ] = 'x';
printMaze( maze );
if (coordsAreEdge(x, y) && (x != xStart || y!= yStart ))
{
cout <<"\nMaze successfully exited!\n\n";
return;
}else{
for ( int move = direction, count = 0; count < 4;
count++, move++, move %=4 )
{
int nextX; int nextY;
switch ( move )
{
case SOUTH: nextX = x + 1; nextY = y; break;
case EAST: nextX = x; nextY = y + 1; break;
case NORTH: nextX = x - 1; nextY = y; break;
case WEST: nextX = x; nextY = y - 1; break;
default: ;
}
if (validMove( maze, nextX, nextY ))
{
//Recursion move part 1
//mazeTraverse ( maze, nextX , nextY, (move + 3)%4 );
return;
}
}
}
}
I'm trying to make my void mazeTraverse function a while loop, instead of the recursion and I'm stuck.
Create a struct to hold X, Y and direction (the three things that change between calls). We'll call that struct State;
Create a std::stack<State> object. Push the current values of X,Y, direction onto the stack before you change them, pop them after you do your work.
hence
while(.....)
{
push state
Do work of mazeTraverse
pop state
}
It would've been nice if you described how the traversal works. If I'm not reading the code wrong, you are basically moving south/east/north/west on any position that doesn't contain a # and is within the bounds of the matrix.
You can do this iteratively by using a BF search: http://en.wikipedia.org/wiki/Breadth-first_search or, applied to a matrix, the Lee algorithm: http://en.wikipedia.org/wiki/Lee_algorithm which can be efficiently implemented using a FIFO queue, which I describe how to do here: Change FloodFill-Algorithm to get Voronoi Territory for two data points?
Your validMove function will stay the same: you add a position to the queue only if that position is valid. Basically all checks stay the same, just that you use a FIFO queue to hold your states instead of an implicit stack.
You could use a breadth-first search instead using a standard queue and while loop.
typedef pair<int, int> Point;
queue<Point> path;
Point start(xStart, yStart);
path.push(start);
const int move_x[] = {-1, 0, 1, 0};
const int move_y[] = {0, -1, 0, 1};
while (!path.empty())
{
Point p = path.front();
int x = p.first, y = p.second;
maze[x][y] = 'x';
path.pop();
if (coordsAreEdge(x,y) && p != start)
{
// Finished
break;
}
for (int i = 0; i < 4; ++i)
{
int newx = x + move_x[i];
int newy = y + move_y[i];
if (validMove(maze, newx, newy))
path.push(Point(newx, newy));
}
}
That should do the trick. Note that it's untested though.
You can improve its performance by using A* instead, but that's a little more complex. Let me know if you need to find the shortest path from this code as well.
EDIT: Note that if you change the queue to a stack (and change path.front() to path.top()) then you'll get a depth-first search (DFS) instead, which is what your code does. The DFS, however, doesn't find the shortest path (if that is necessary).