Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
I have tried to come up with a solution to the n-queen problem, through backtracking. I have created a board, and I think I have created functions which checks whether a piece can be placed at position column2 or not, in comparison to a piece at position column1. And I guess I somehow want to loop through the columns, to check if the current piece is in a forbidden position to any of the power pieces already placed at the first row through the current minus one. I haven't done this yet, but I'm just confused at the moment, so I can't really see how I should do it.
Let me share the code I have written so far
// Method for creating chessboard
vector<vector<vector<int>>> create_chessboard(int size_of_board)
{
vector<int> v1;
vector<vector<int>> v2;
vector<vector<vector<int>>> v3;
for (int i = 0; i < size_of_board; i++)
{
for (int j = 0; j < size_of_board; j++)
{
v1.clear();
v1.push_back(i);
v1.push_back(j);
v2.push_back(v1);
}
v3.push_back(v2);
v2.clear();
}
return v3;
}
// Method for visualizing chessboard
void visualize_board(vector<vector<vector<int>>> chess, int dimension_of_board)
{
int i = 1;
for (vector<vector<int>> rows : chess)
{
for (int j = 0; j < dimension_of_board; j++)
{
cout << "(" << rows[j][0] << "," << rows[j][1] << ")" << " ";
}
cout << endl;
}
}
// Method for checking if two coordinates are on the same diagonal
bool check_diagonal(vector<int> coordinate1, vector<int> coordinate2)
{
if(abs(coordinate1[1] - coordinate2[1]) == abs(coordinate1[0] - coordinate2[0]))
{
return true;
}
return false;
}
bool check_column(vector<int> coordinate1, vector<int> coordinate2)
{
if(coordinate1[1] == coordinate2[1])
{
return true;
}
return false;
}
bool check_row(vector<int> coordinate1, vector<int> coordinate2)
{
if (coordinate1[0] == coordinate2[0])
{
return true;
}
return false;
}
bool check_allowed_positions(vector<int> coordinate1, vector<int> coordinate2, int column)
{
if (check_diagonal(coordinate1, coordinate2))
{
return false;
}
if (check_column(coordinate1, coordinate2))
{
return false;
}
if (check_row(coordinate1, coordinate2))
{
return false;
}
return true;
}
vector<vector<int>> solve_nqueen(vector<vector<vector<int>>> board, int dimension_of_board, int row)
{
vector<int> first_element = board[0][0];
vector<vector<int>> solution_space;
if (dimension_of_board == row)
{
cout << "we found a solution!";
}
/*
if (dimension_of_board == row)
{
}
for (int j = 0; j < dimension_of_board; j++)
{
if (check_allowed_positions(board, row, j))
{
do something here
solve_nqueen(board, dimension_of_board, row+1);
}
else
{
do something here;
}
}
return;
*/
return solution_space;
}
I would be really happy if someone could just lay up a few steps I have to take in order to build the solve_nqueen function, and maybe some remarks on how I could do that. If I should complement with some further information, just let me know! I'm happy to elaborate.
I hope this isn't a stupid question, but I have been trying to search the internet for a solution. But I didn't manage to use what I found.
Best wishes,
Joel
There is not always a solution, like e.g. not for 2 queens on 2x2 board, or for 3 queens on a 3x3 board.
This is a well-known problem (which can also be found in the internet). According to this, there is not a simple rule or structure, how you can find a solution. In fact, you could reduce the problem by symmetries, but that is not that simple, too.
Well according to this, you have to loop through all (n out of n x n) solutions, and do all tests for every queen. (In fact, reduce it to half again, by only checking a certain pair of queens, once only - but again that is not much, and such reduction takes some time, too).
Note: Your check routines are correct.
For 8 queens on a 8x8 board, write 8 nested loops from i(x)=0 to 63
(row is i(x)%8 and column is i(x)/8). You also need to check then, if a queen does not sit on queen, but your check routines will already find that. Within second nested loop, you can already check if the first two queens are okay, or otherwise, you do not have to go any deeper, but can already increment the value of first nested loop (move the second queen on a new position).
Also it would be nice, I propose not to write the search for a n-problem, but for a n=8 problem or n=7 problem. (That is easier for the beginning.).
Speed-Ups:
While going deeper into the nested loops, you might hold a quick
record (array) of positions which already did not work for upper
loops (still 64 records to check, but could be written to be faster than doing your check routines again).
Or even better, do the inner loops only through a list from remaining candidates, much less than (n x n) positions.
There should be some more options for speed-ups, which you might find.
Final proposal: do not only wait for the full result to come, but also track, when e.g. you find a valid position of 5 queens, then of 6 queens and so on - which will be more fun then (instead of waiting ages with nothing happening).
A further idea is not to loop, e.g. from 0 to 63 for each queen, but "randomly". Which also might lead to more surprising. For this, mix an array 0 .. 63 to a random order. Then, still do the loop from 0 to 63 but this is just the index to the random vector. Al right? Anyway, it would even be more interesting to create 8 random vectors, for each queen one random vector. If you run this program then, anything could happen ... the first few trials could (theoretically) already deliver a successful result.
If you would like to become super efficient, please note that the queen state on the 8x8 board can be stored in one 64-bit-integer variable (64 times '0' or '1' where '1' means here is queen. Keyword: bitboards). But I didn't mention this in the beginning, because the approach which you started is quite different.
And from that on, you could create 64 bit masks for each queen position, to each position to which a queen can go. Then you only need to do 1 "bitwise AND" operation of two (properly defined) 64-bit variables, like a & b, which replaces your (diagonal-, column-, row-) check routines by only one operation and thus is much faster.
Avoid too many function calls, or use inline.
... an endless list of possible dramatic speed-ups: compiler options, parallelization, better algorithms, avoid cache misses (work on a possibly low amount of memory or access memory in a regular way), ... as usual ...
My best answer, e.g. for 8-queen problem:
queen is between 0 .. 7
queen is between 8 .. 15
queen is between 16 .. 23
queen is between 24 .. 31
queen is between 32 .. 39
queen is between 40 .. 47
queen is between 48 .. 55
queen is between 56 .. 63
because all 8 queens have to be on different rows!
These are the limits of the nested loops then, which gives "only"
8 * 8 * 8 * 8 * 8 * 8 * 8 * 8 = 16777216
possibilities to be checked. This can be quick on modern machines.
Then probably you don't need anything more sophisticated (to which my first answer refers - for the 8x8 queens problem.) Anyway, you could still also keep a record of which column is still free, while diving into the nested loops, which yields a further dramatic cut down of checks.
I wrote some C code (similar to C++) to verify my answer. In fact, it is very fast, much less than a second (real 0m0,004s; user 0m0,003s; sys 0m0,001s). The code finds the correct number of 92 solutions for the 8x8 queens problem.
#include <stdio.h>
int f(int a, int b)
{
int r1, c1, r2, c2, d1, d2;
int flag = 1;
r1 = a / 8;
r2 = b / 8;
c1 = a % 8;
c2 = b % 8;
d1 = r1 - r2;
d2 = c1 - c2;
if( d1 == d2 || d1 == -d2 || c1 == c2 ) flag=0;
return flag;
}
int main()
{
int p0,p1, p2, p3, p4, p5, p6, p7;
int solutions=0;
for(p0=0; p0<8; p0++)
{
for(p1=8; p1<16; p1++)
{
if( f(p0,p1) )
for(p2=16; p2<24; p2++)
{
if( f(p0,p2) && f(p1,p2) )
for(p3=24; p3<32; p3++)
{
if( f(p0,p3) && f(p1,p3) && f(p2,p3) )
for(p4=32; p4<40; p4++)
{
if( f(p0,p4) && f(p1,p4) && f(p2,p4) && f(p3,p4))
for(p5=40; p5<48; p5++)
{
if( f(p0,p5) && f(p1,p5) && f(p2,p5) && f(p3,p5) && f(p4,p5) )
for(p6=48; p6<56; p6++)
{
if( f(p0,p6) && f(p1,p6) && f(p2,p6) && f(p3,p6) && f(p4,p6) && f(p5,p6))
for(p7=56; p7<64; p7++)
{
if( f(p0,p7) && f(p1,p7) && f(p2,p7) && f(p3,p7) && f(p4,p7) && f(p5,p7) && f(p6,p7))
{
solutions++;
// 0 .. 63 integer print
printf("%2i %2i %2i %2i %2i %2i %2i %2i\n",
p0,p1,p2,p3,p4,p5,p6,p7);
// a1 .. h8 chess notation print
//printf("%c%d %c%d %c%d %c%d %c%d %c%d %c%d %c%d\n",
//p0%8+'a', p0/8+1, p1%8+'a', p1/8+1, p2%8+'a', p2/8+1, p3%8+'a', p3/8+1,
//p4%8+'a', p4/8+1, p5%8+'a', p5/8+1, p6%8+'a', p6/8+1, p7%8+'a', p7/8+1);
}
}
}
}
}
}
}
}
}
printf("%i solutions have been found\n",solutions);
return 1;
}
Notes: Subroutine f checks if two queen positions are "ok" with each other (1 means true, 0 means false, in C). An inner loop is only entered, if all already selected positions (in outer loops) are "ok" with each other.
i have a problem with the next question, i need to solve it by using if/else, i wrote the code but i don't know if it's the solve of the question or not:
Write a program in which the user enters the coordinates of the black pawns (a, b) on the chessboard.
The program must determine whether the pawn may move to get to one field (c, d):
1. In the ordinary move;
2. When it "hit" piece or pawn opponent.
Note: Black pawn move on the board from the bottom up.
char CoordinY;
int CoordinX;
if (CoordinY > 'b' && CoordinX <= 1 && CoordinX>8)
{
cout << "Error . . . \n";
}
else
{
if (CoordinX >= 2 && CoordinX <= 8 && CoordinY == 'a' || CoordinY == 'b'*)
{
// arbitrary move:
cout << "will not get to the field (c, d) in the ordinary move.\n";
// when it "hits" enemy's figure or pawn
cout << "will not get to the field (c, d) when ше hit a figure or pawn opponent.\n";
}
else if (CoordinX>1 && CoordinX < 8 && CoordinY == 'b')
{
// arbitrary move
cout << "will not get to the field (c, d) in the ordinary move.\n";
// when it "hits" enemy's figure or pawn
cout << "will not get to the field (c, d) when it hit a figure or pawn opponent.\n";
}
In the answer I assume the following classic chess board and the fact that I am moving white pawn:
It is important because in your problem definition, blacks are moving bottom up, which is incorrect.
In my example, I will use the following variables:
char a, c; int b, d; // E2 - E4 is: a = 'e', b = 2, c = 'e', d = 4.
Arbitrary move
Where can a pawn go with an arbitrary move in chess?
One step ahead
Two steps ahead if it is standing at row 2
So, in general, a pawn at (a; b) can move to (c; d), if they stand in the same row (a == c) AND if it is one step ahead or two steps ahead for b equal to 2.
So, let's implement it:
if (a == c && (d - b == 1 || (d - b == 2 && b == 2)))
cout << "Abitrary move: YES";
} else {
cout << "Arbitrary move: NO";
}
Attack
A pawn can move with an attack if only an enemy is standing in the next row, one cell to the left or to the right:
if ((c == a + 1 || c == a - 1) && (d - b == 1))
cout << "Attack: YES";
} else {
cout << "Attack: NO";
}
Note that this solution is not working for the case which is called en passant (is it more well-known as "битое поле" or "взятие на проходе" in Russian).
This is a solution in pseudocode:
if (d == b - 1) // destination is one square up
if (c == a) // pawn is on a square in the same column as destination
return true; // yes, pawn can move forwards to destination
if (c == a - 1 || c == a + 1) // destination is one square to left or right
return true; // yes, pawn can take a white pawn to move to destination
end if
return false
First we do the check which is true for both cases... is the destination only one step in front (note that in chess pawns can also move two squares on their first turn, but you didn't request that solution so I haven't added it)?
Next we check if the move is either straight ahead, or diagonal.
You might want to check that a,b c,d are all valid chess coordinates to start with, which would prevent illegal moves being marked as ok.
Edit: also I'm assuming that the bottom of the board has a larger 'y' coordinate than the top. If the coordinates are reversed you would check for b + 1 in the first conditional.
I'm just a beginner in C++ and while making a code to create the TicTacToe game I got stuck at the while statement that will push the game to keep going until winning conditions are fulfilled :
while(((table[0][0]!='X')&&(table[1][1]!='X')&&(table[2][2]!='X')))
This is just the diagonal condition (Putting all the conditions will give you eyesore...).
THE PROBLEM IS that this is not working even if the conditions are fulfilled (I'm sure because I use a cout at the end), however when I change && with || the condition work !
I thought maybe because of the != that affect everything ??
EDIT: Minimal Example (I removed the floating point !) :
#include <iostream>
using namespace std;
int main()
{
int tailleX(3),tailleY(3); //The Size of the table.
char table[tailleX][tailleY]; //TictacToe table.
table[0][0]='N';
table[0][1]='N';
table[0][2]='N';
table[1][0]='N';
table[1][1]='N'; //Randomly filling the array to avoid an error
table[1][2]='N';
table[2][0]='N';
table[2][1]='N';
table[2][2]='N';
int coorP1; //The Coordinate of the square (Exp: x=1 , y=2 will be 1.2)
while(((table[0][0]!='X')&&(table[1][1]!='X')&&(table[2][2]!='X'))) //For the minimal example I made just the diagonal condition
{
cout<<"PLAYER1: Enter the coordination to score: (Exemple: 1, 2, 3..) "<<endl;
cin>>coorP1;
switch(coorP1) //Filling the square depending on the coordinates.//I used If because Switch does not work.
{
case 1:
table[0][0]='X';
break;
case 2:
table[0][1]='X';
break;
case 3:
table[0][2]='X';
break;
case 4:
table[1][0]='X';
break;
case 5:
table[1][1]='X';
break;
case 6:
table[1][2]='X';
break;
case 7:
table[2][0]='X';
break;
case 8:
table[2][1]='X';
break;
case 9:
table[2][2]='X';
break;
}
}
cout<<"You won"<<endl;
return 0;
}
The problem here is your test condition. Your loop repeats if you enter 2, 3, 4, 6, 7, or 8. As soon as you enter 1, 5, or 9, the loop exits. If you enter 1, 5, or 9, then one of the diagonal values is set to 'X'. while loops while the condition is true. As soon as the condition evaluates to false, it exits. When you enter 1, 5, or 9, you cause the condition to be false.
Imagine, for a second, that table[0][0] is 'X', table[1][1] is 'N', and table[2][2] is 'N'. In other words, the board looks like this:
X | N | N
--+---+---
N | N | N
--+---+---
N | N | N
Then your test condition is:
table[0][0] != 'X' && table[1][1] != 'X' && table[2][2] != 'X'
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
false true true
If you logically AND these together (as you are with &&), this evaluates to false (which makes sense: false AND true should evaluate to false; only true AND true should evaluate to true).
So what should your test condition be?
What you really want is to do is loop only if the user doesn't have 3 in a row. In other words, check if the user has 3 in a row; if he does not have 3 in a row, then proceed.
We can construct that logical statement as:
// This checks if the user has 3 in a row
table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X'
// We want to check if the user does NOT have 3 in a row,
// so we can negate the above with !
!(table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X')
// With De Morgan's laws, we can simplify this to:
table[0][0] != 'X' || table[1][1] != 'X' || table[2][2] != 'X'
Thus, your looping condition should be one of (they're both equivalent; pick whichever one makes more sense to you):
!(table[0][0] == 'X' && table[1][1] == 'X' && table[2][2] == 'X')
This checks if the user does not have 3 in a row
table[0][0] != 'X' || table[1][1] != 'X' || table[2][2] != 'X'
This checks if the user does not have an 'X' any one of the needed positions. It logically follows that if the user is missing an 'X' in one of these positions, the user cannot have 3 in a row. This is just an application of De Morgan's laws to the previous logical statement.
A critical part of learning to program is learning to avoid doing similar things over and over in your source code. You need to abstract the similar behaviors so they can share one chunk of code. So the computer does all that work, but when writing the source code, you don't do all that work.
Your attempt to build up a giant boolean expression of the game state is an extreme example of how not to program. It is a common beginner mistake (and far from the only example of that beginner mistake in your code). Fixing that giant boolean expression is possible, but it would be terribly counter productive along your path of learning to program. Instead you should take that as an example to learn how to combine and abstract work:
First understand the game concepts: A game state is one of wonX, wonY, draw, inProgress. You could define an enum for those possibilities. Each of the eight lines through the board has the same four possible states, where the game state is wonX or wonY if any line has that state, and the game state is inProgress is no line is wonX or wonY and some line is inProgress.
Because draw combines from individual rline up to board level in the opposite way that wonX or wonY does, the combination operation would be tricky at a high level and easier in the code that also determines line state.
So I suggest writing a function that takes the three values of one line as input and also takes game state accumulator as input, and returns an updated game state. In each round, you would start computing the game state as draw, then call the function for each of 8 lines to update it. If the line is a win for X or Y, then the state would unconditionally change to that. If the line is inProgress, the state would change to that only if the state was draw. If the line is draw, that doesn't change the state (one line in a draw state says nothing about the game state).
Good design would further abstract and combine several more aspects of your code, but the one that is the big problem from your failure to abstract and combine, is as I indicated the step that looks at one line and computes its impact on the state of the whole board.
In general you will find your most powerful tool for abstracting and combining work is to move that chunk of the work into a function (as I described above). Trying to do too much not split out into seperate functions is a major beginner mistake.
I'm writing a Tic Tac Toe Game and I would like to know how I can make an efficient function to check who won. A two dimensional array congaing X's, O's, or blank spaces represents the board.
char CheckWin(const char board[][NUM_COLS], int& sum) // tic tac toe board - IN
{
char tmp;
int lcv;
tmp = ' ';
if (sum == 9)
{
return 'T';
}
else if (sum != 9)
{
if (((tmp = board[1][1]) != ' ' && board[0][0] == tmp && board[2][2] == tmp) || (board[2][0] == tmp && board[0][2] == tmp))
{
return tmp;
}
for (lcv = 0; lcv < 3; lcv++)
{
if ((tmp = board[lcv][0]) != ' ' && board[lcv][1] == tmp && board[lcv][2] == tmp)
{
return tmp;
}
else if ((tmp = board[lcv][0]) != ' ' && board[lcv][1] == tmp && board[lcv][2] == tmp)
{
return tmp;
}
}
}
return 'N';
}
Besides doing something similar to this over and over again, how could I check who won and return an X if X has won, an O if O has one, a T if it's a tie, and N if no one has one yet. Thanks in advance. I'm trying to get familiar with C++ and programming in general still.
EDIT: I just went with the simple method, but I somehow messed it up, anybody know how? It looks like it's not return anything because when I call it in the main after a player picks a row and column(that's working fine), it doesn't output anything
You could convert the array into two nine-bit values, one for the O positions and one for the X position, and a count of blank spaces:
x_mask = 0
y_mask = 0
empty_count = 0
mask = 1
for each square
if x then x_mask |= mask
if y then y_mask |= mask
if empty then empty_count++
mask <<= 1
Then compare the x_mask and y_mask against the eight possible winning combinations:
for each player
for each winning combination
if player_mask & winning_mask == winning_mask then player has won
and then handle the cases neither player has won:
if neither player won
if empty_count == 0
its a tie
else
moves still available
A simple "structured" approach
If you think of the board as:
A B C
D E F
G H I
Then one minimal selection of boxes that any winning layout must touch would be:
A B C
D
G
You can conceive the movement from any of these locations in a winning line in terms of a shift of 0, 1 or -1 positions in each of the X and Y directions. We can list the movements that you'd need to check:
A: (++x) (++x, ++y) (++y)
B: (++y)
C: (++y) (--x, ++y)
D: (++x)
E: (++x)
In C++, you can create a list/vector of the x/y coordinates of the starting points and the +/-/0 x/y movement deltas shown above, then use three nested loops to evaluate each line across the board.
This is considerably more work than just hardcoding the two loops over x and y coordinates and the two diagonals (below), but it's a more algorithmic approach that might appeal intellectually: more like what you might have to do if you were handling a much bigger board.
Obvious brute force approach
For the record, that simpler approach would look like this:
int x;
for (row = 0; row < 3; ++row)
if ((x = board[row][0]) != Empty &&
board[row][1] == x && board[row][2] == x)
return x;
// similar loop for columns...
...
// hardcode diagonals...
if ((x = board[1][1]) != Empty &&
(board[0][0] == x && board[2][2] == x ||
board[2][0] == x && board[0][2] == x))
return x
I suppose you could assign each winning board possibility a number (basically a hash value) and then check if the current board matches any of the values in the table by generating its hash value. On the other hand, I wouldn't suggest spending too much time trying to make the CheckWin function super-efficient. Unless it's being called millions of times or something and needs to be really fast, spend your time on something else--it probably won't be a bottleneck.