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.
Related
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
}
}
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.
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 :).
I wrote a basic tic-tac-toe game based on multidimensional arrays. g[3][3]. In my program I have about 9 conditions like the one I am about to show you:
if((g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O))
This is quite insane. I am probably doing something wrong but this is why I am addressing this question. Is there an easier way of representing long and complicated conditions like this? For example couldn't I somehow do:
if(grid.hasXes)
You're probably going about it the wrong way. There are only 3^9, or
19683 possible combinations, so you can convert your grid to an int,
even on a 16 bit machine:
int
asInt( char const (&grid)[3][3] )
{
int results = 0;
for ( int i = 0; i != 3; ++ i ) {
for ( int j = 0; j != 3; ++ j ) {
results *= 3;
switch ( grid[i][j] ) {
case 'X':
results += 1;
break;
case 'Y':
results += 2;
break;
case ' ':
break;
default:
assert(0);
}
}
}
return results;
}
Afterwards, you can use the int to index into a table indicating who won
(if anyone). Alternatively, you can convert just one or the other
player's position into a 9 bit int:
int
asInt( char const (&grid)[3][3], char who )
{
int results = 0;
for ( int i = 0; i != 3; ++ i ) {
for ( int j = 0; j != 3; ++ j ) {
results *= 2;
if ( grid[i][j] == who ) {
++ results;
}
}
}
return results;
}
You can then use a simple linear search into a table, verifying that the
necessary bits are set:
static int const wins[] =
{
0007, 0070, 0700, // rows
0111, 0222, 0444, // columns
0124, 0421 // diagonals
};
class Wins
{
int myToMatch;
public:
Wins( char const (&grid)[3][3], char who )
: myToMatch( asInt( grid, who ) )
{
}
bool operator()( int entry ) const
{
return (entry & myToMatch) == entry;
}
};
Then:
if ( std::find_if( begin( wins ), end( wins ), Wins( grid, 'X' ) )
!= end( wins ) {
// X wins
else if ( std::find_if( begin( wins ), end( wins ), Wins( grid, 'O' ) )
!= end( wins ) {
// O wins
else
// play another turn.
You could even consider keeping the grid as two ints, one per player.
The bit number for a position would be 3 * i + j, and to test if a
move is legal:
bool
isLegal( int gridX, int gridY, int i, int j )
{
return ((gridX | gridY) & (1 << (3 * i + j))) == 0;
}
The simplest -- and most powerful -- way to deal with this kind of issue is simply by extracting the ugly code into a function. That function can be a member of a class, if it's convenient, or simply a free function. In your case, the quick fix could be
bool hasXes(char[3][3] g) {
return (g[0][0] == X && g[0][1] == X && g[0][2] == X) || (g[0][0] == O && g[0][1] == O && g[0][2] == O)
}
Then you can simply write:
if (hasXes(g)) ...
now I got it...
bool check(char *g, int x, int y, int moveX, int moveY, char ch)
{
for (int i(0); i<3; ++i)
{
if ((g+(y*3)+x) != ch) return false;
x += moveX;
y += moveY;
}
return true;
}
you use it like that:
if (check(g, 0, 0, 0, 1, 'O')) //checking O in the first row.
if (check(g, 0, 0, 0, 1, 'X')) //checking X in the first row.
if (check(g, 0, 0, 1, 0, 'O')) //checking O in the first column.
if (check(g, 0, 0, 1, 0, 'X')) //checking X in the first column.
You could write functions to hide the complexity and enhance the readability of your main driver function. For instance, you could check a row or column to see if it it's all equal to X or O.
This should work:
bool found = false;
int i, j;
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
if(g[i][j] == X)
{
found = true;
break;
}
}
if(found == true)
{
break;
}
}
if(found == true)
{
// do something because one of them had X. i, j have the co-ordinates of the first find of it
}
else
{
// none of them had X
}
There may be a way to use a goto as well, though those are heavily discouraged in c++. If you only want a row at a time, only use 1 loop.
One more option to choose from. You can use memcmp if the storage is contiguous
if(!memcmp(g[0],"XXX",3) || !memcmp(g[0],"OOO",3))
In this special case there is also the somewhat simpler comparison:
if(g[0][0] == g[0][1] && g[0][1] == g[0][2])
At least assuming there are only X and O possible. Otherwise this will become
if(g[0][0] == g[0][1] && g[0][1] == g[0][2] && ( g[0][1] == X || g[0][1] == O ) )
Which still is a lot simpler IMHO.
If you cannot simplify like this, use a loop as other have pointed out.
Typesafe comments!
const bool first_is_xful = g[0][0] == X && g[0][1] == X && g[0][2] == X,
second_is_xful = ...;
if (first_is_xful || second_is_xful || ...) ...
Or functions functions:
bool is_xful (int row, ...) ...
...
if (is_ixful(0) || ...
You could count the Xs or try to find them:
Assuming g is a 3 x 3 array, containing characters X or O:
char* end = g + 9;
std::count(g, end, 'X') > 0;
or more efficiently:
char* end = g + 9;
std::find(g, end, 'X') != end;
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).