-
C++ & Tic Tac Toe
First I'll apologize for any repeat threads. I'm new to using forums and after searching around I don't see any other way. I've done the following tic-tac-toe program for C++ (2 players), and I can't seem to get it to move to the get_move function. Can you see where I messed something up? It's been 6 hours and I'm going code blind. Thanks. (I also don't think I did the "tags" correctly. Sorry.
It initializes the gamefield with "*", then moves in an "X" or "O".
Code:
#include <iostream>
#include <string>
using namespace std;
char board[3][3]; //tic tac toe board
bool gameover;
int player;
void init_board();
void disp_board();
void get_move();
void checkwin();
void win(bool);
int main()
{
gameover = false;
player = 1;
system("color f4");
system("cls");
cout << ("Tic Tac Toe.\n");
cout << ("Player 1 (X) - Player 2 (O)\n\n");
init_board();
disp_board();
while (gameover == false);
{
get_move();
disp_board();
checkwin();
}
return 0;
}
//Initialize board
void init_board(void)
{
int i, j;
for(i=0; i<3; i++)
for(j=0; j<3; j++) board[i][j] = '*';
}
//Display board
void disp_board()
{
cout << " Coordinates \n";
cout << " 1 2 3 \n";
cout << " | | \n";
cout << " 1 " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 2 " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 3 " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << endl;
cout << " | | \n\n";
}
//Get a player's move
void get_move()
{
int x = 0, y = 0;
cout << "Player " << player << ", enter X,Y coordinates for your move: ";
cin >> board[x][y];
x--;
y--;
if(board[x][y]!= '*')
{
cout << ("Invalid move, try again.\n");
get_move();
}
if ((board[0][0]) && (board[0][0] == '*'))
{
board[0][0] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[0][1]) && (board[0][1] == '*'))
{
board[0][1] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[0][2]) && (board[0][2] == '*'))
{
board[0][2] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[1][0]) && (board[1][0] == '*'))
{
board[1][0] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[1][1]) && (board[1][1] == '*'))
{
board[1][1] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[1][2]) && (board[1][2] == '*'))
{
board[1][2] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[2][0]) && (board[2][0] == '*'))
{
board[2][0] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[2][1]) && (board[2][1] == '*'))
{
board[2][1] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
if ((board[2][2]) && (board[2][2] == '*'))
{
board[2][2] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
}
//Check for winner
void checkwin()
{
int i;
//check rows
for(i=0; i<3; i++)
if(board[i][0]==board[i][1] && board[i][0]==board[i][2]) win(true);
//check columns
for(i=0; i<3; i++)
if(board[0][i]==board[1][i] && board[0][i]==board[2][i]) win(true);
//check diagonals
if(board[0][0]==board[1][1] && board[1][1]==board[2][2]) win(true);
else if (board[0][2]==board[1][1] && board[1][1]==board[2][0]) win(true);
//no winner yet
else win(false);
}
void win(bool x)
{
if (x == true)
{
player = (player == 1) ? 2 : 1;
cout << "Player " << player << " Won!!!" << endl << endl;
}
else cout << "Tie Game!" << endl << endl;
gameover = true;
system("pause");
}
-
Your gameover variable is initialized to false so, you can't access the while loop anyways as you are not changing it's value anywhere in the two programs, called before the loop....
-
yes, but ...
... the loop is supposed to execute if gameover is false. I'll try changing it around to a do-while loop instead so it will at least iterate once then. I'll let you know. Thanks Mr. 777
-
Sure but as gameover variable is false so it will never allow your program to enter and execute those modules inside the loop unitl the value is changed to true..
Anyways, depending upon your requirements, you can change it to do-while but i don't think if it's a generic or efficient way of solving this problem. Think differently and logically and you'll get many different ways..
Anyways, i'll be waiting for your new code. Good luck with that.
-
Seeing as how you've used this repeatedly:
Code:
player = (player == 1) ? 2 : 1;
I thought I'd share that the sam can be achieved more efficiently like this:Or in general, you can toggle between two values by subtracing the current value from the sum of both values. Or where it is necessary to avoid overflow, you can simply XOR the current value with the XOR of both values, which works just as well if not better. I.e.
Code:
value = (VALUE1 ^ VALUE2) ^ value;
In this case VALUE1 is 1 and VALUE2 is 2, so that's 1^2 which equals 3.
An even better option for your code would be to toggle player between 'X' and 'O', rather than between 1 and 2, which makes other stuff easier also.
Code:
player = ('X'^'O')^player;
-
> cout << "Player " << player << ", enter X,Y coordinates for your move: ";
> cin >> board[x][y];
Perhaps you should just do
cin >> x >> y;
You asked for coordinates didn't you?
-
No, i think he just asked for that why his/her written function is not executing as the provided loop is not even allowing his/her program to execute some of the functions, mainly specified in his/her problem.
Once he/she will be able to move ahead from this problem, he/she may assure further errors.
-
>>while (gameover == false);
Suspicious? Remove the semicolon.
>>cin >> board[x][y];
Is this a good idea= You're always placing the move into 0, 0. But that's not where the player wants to put the move necessarily.
>>if ((board[0][0]) && (board[0][0] == '*'))
I am thinking you meant
if ((board[0][0] == '*') && (board[0][0] == '*'))
Although it doesn't really matter, because I fail to see the point of those if statements anyway. What do they do? You're supposed to check if the move is valid or not. That is, check if valid coordinates was entered, and if the space is not occupied.
-
OMG Elysia - jeepers...semicolon! Told you I was code blind. That may be it, but as Mr. 777 said, I may stumble into others...
iMalc - we haven't discovered the "value = (VALUE1 ^ VALUE2) ^ value;" yet in class, so it would not be prudent to throw that in yet. I'll remember that for future though.
Thanks all for your great suggestions. I'll repost in a few....
-
Ok, so here's a cleaned-up version. Problem is - I can't get the checkwin function to execute properly. If I place it in either the do-while loop after I get the user input or within the get_move function - it doesn't work. in the do-while loop it only lets you put in one 'x' or 'o', then says tie. I believe it did the same thing in the get_move function as well. The program runs fine without it, except it doesn't declare a winner. Any ideas?
Code:
#include <iostream>
#include <string>
using namespace std;
char board[3][3]; //tic tac toe board
bool gameover;
int player;
void init_board();
void disp_board();
void get_move();
void checkwin();
int main()
{
gameover = false;
player = 1;
system("color f4");
init_board();
do {
disp_board();
get_move();
system("cls");
} while (gameover == false);
system("pause");
return 0;
}
//initialize board
void init_board()
{
int i, j;
for(i=0; i<3; i++)
for(j=0; j<3; j++) board[i][j] = '*';
}
//Display board
void disp_board()
{
cout << ("Tic Tac Toe.\n");
cout << ("Player 1 (X) - Player 2 (O)\n\n");
cout << " Coordinates \n";
cout << " 0 1 2 \n";
cout << " | | \n";
cout << " 0 " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 1 " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 2 " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << endl;
cout << " | | \n\n";
}
//Get player move
void get_move()
{
int x = 0, y = 0;
cout << "Player " << player << ", enter X,Y coordinates for your move: ";
cin >> x >> y;
if (board[x][y] == '*')
{
board[x][y] = (player == 1) ? 'X' : 'O';
player = (player == 1) ? 2 : 1;
}
else
{
cout << ("\nInvalid move, try again.\n\n");
get_move();
}
}
//Check if winner
void checkwin()
{
if (gameover == false)
{
// Check Rows
for (int i=0; i<3; i++)
if (board [i][0] == board [i][1] && board [i][0] == board [i][2] && board [i][0] != '*')
{
player = (player == 1) ? 2 : 1;
cout << "Player " << player << " Won!!!" << endl << endl;
}
// Check Columns
for (int i=0; i<3; i++)
if (board [0][i] == board [1][i] && board [0][i] == board [2][i] && board [0][i] != '*')
{
player = (player == 1) ? 2 : 1;
cout << "Player " << player << " Won!!!" << endl << endl;
}
// Check Diagonals
if (board [0][0] == board [1][1] && board [1][1] == board [2][2] && board [1][1] != '*')
{
player = (player == 1) ? 2 : 1;
cout << "Player " << player << " Won!!!" << endl << endl;
}
if (board [0][2] == board [1][1] && board [1][1] == board [2][0] && board [1][1] != '*')
{
player = (player == 1) ? 2 : 1;
cout << "Player " << player << " Won!!!" << endl << endl;
}
// Check if no winner
if (board [0][0] != '*' && board [0][1] != '*' && board [0][2] != '*' &&
board [1][0] != '*' && board [1][1] != '*' && board [1][2] != '*' &&
board [2][0] != '*' && board [2][1] != '*' && board [2][2] != '*')
cout << "It's a tie!" << endl << endl;
gameover = true;
}
else gameover = false;
system("pause");
}
-
If would be better if you had something like
bool checkwin ( char player )
So you could call it with say
if ( checkwin('X') ) // player X wins!
You then don't need to have a lot of checks for * inside all your code.
-
Because you are not calling checkwin() either from main() or any of your defined functions.....
-
solved
Here is my clean version: I went a different way with the checkwin. Thanks all who helped.
Code:
#include <iostream>
#include <string>
using namespace std;
char board[3][3]; //tic tac toe board
bool gameover = false;
int player = 1;
void init_board();
void disp_board();
void get_move();
bool checkwin();
int main()
{
system("color f4");
init_board();
do {
system("cls");
disp_board();
get_move();
} while (gameover == false);
system("pause");
return 0;
}
//initialize board
void init_board()
{
int i, j;
for(i=0; i<3; i++)
for(j=0; j<3; j++) board[i][j] = '*';
}
//Display board
void disp_board()
{
cout << ("Tic Tac Toe.\n");
cout << ("Player 1 (X) - Player 2 (O)\n\n");
cout << " Coordinates \n";
cout << " 0 1 2 \n";
cout << " | | \n";
cout << " 0 " << board[0][0] << " | " << board[0][1] << " | " << board[0][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 1 " << board[1][0] << " | " << board[1][1] << " | " << board[1][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 2 " << board[2][0] << " | " << board[2][1] << " | " << board[2][2] << endl;
cout << " | | \n\n";
}
//Get player move
void get_move()
{
int x = 0, y = 0;
cout << "Player " << player << ", enter X,Y coordinates for your move: ";
cin >> x >> y;
if (board[x][y] == '*')
{
board[x][y] = (player == 1) ? 'X' : 'O';
checkwin();
player = 3 - player;
}
else
{
cout << ("\nInvalid move, try again.\n\n");
get_move();
}
}
//Check if winner
bool checkwin()
{
if ((board[0][0] == 'X' && board[0][1] == 'X' && board[0][2] == 'X')||
(board[1][0] == 'X' && board[1][1] == 'X' && board[1][2] == 'X')||
(board[2][0] == 'X' && board[2][1] == 'X' && board[2][2] == 'X')||
(board[0][0] == 'X' && board[1][0] == 'X' && board[2][0] == 'X')||
(board[0][1] == 'X' && board[1][1] == 'X' && board[2][1] == 'X')||
(board[0][2] == 'X' && board[1][2] == 'X' && board[2][2] == 'X')||
(board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X')||
(board[2][0] == 'X' && board[1][1] == 'X' && board[0][2] == 'X'))
{
cout << "\nPlayer 1 wins!\n\n";
gameover = true;
}
else if ((board[0][0] == 'O' && board[0][1] == 'O' && board[0][2] == 'O')||
(board[1][0] == 'O' && board[1][1] == 'O' && board[1][2] == 'O')||
(board[2][0] == 'O' && board[2][1] == 'O' && board[2][2] == 'O')||
(board[0][0] == 'O' && board[1][0] == 'O' && board[2][0] == 'O')||
(board[0][1] == 'O' && board[1][1] == 'O' && board[2][1] == 'O')||
(board[0][2] == 'O' && board[1][2] == 'O' && board[2][2] == 'O')||
(board[0][0] == 'O' && board[1][1] == 'O' && board[2][2] == 'O')||
(board[2][0] == 'O' && board[1][1] == 'O' && board[0][2] == 'O'))
{
cout << "\nPlayer 2 wins!\n\n";
gameover = true;
}
else if ((board[0][0] != '*' && board[0][1] != '*' && board[0][2] != '*')&&
(board[1][0] != '*' && board[1][1] != '*' && board[1][2] != '*')&&
(board[2][0] != '*' && board[2][1] != '*' && board[2][2] != '*'))
{
cout << "\nSorry it's a tie\n\n!!";
gameover = true;
}
return gameover;
system("pause");
}
-
I don't mean to claim that my style is the only way, but I restyled your code to show you an alternative. Some of the indentation and other miscellaneous things look sloppy to me:
Code:
#include <iostream>
#include <string>
using namespace std;
struct GameData
{
char mBoard[3][3]; // tic tac toe board
bool mGameover;
int mPlayer;
};
bool CheckCombo(char a, char b, char c);
bool CheckWin(GameData& gd);
void DisplayBoard(GameData& gd);
void GetMove(GameData& gd);
void InitBoard(GameData& gd);
int main()
{
//system("color f4");
GameData gd;
gd.mGameover = false;
gd.mPlayer = 1;
InitBoard(gd);
do
{
//system("cls");
cout << endl << endl;
DisplayBoard(gd);
GetMove(gd);
}
while (gd.mGameover == false);
//system("pause");
return 0;
}
void DisplayBoard(GameData& gd)
{
cout << "Tic Tac Toe.\n";
cout << "Player 1 (X) - Player 2 (O)\n\n";
cout << " Coordinates \n";
cout << " 0 1 2 \n";
cout << " | | \n";
cout << " 0 " << gd.mBoard[0][0] << " | " << gd.mBoard[0][1];
cout << " | " << gd.mBoard[0][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 1 " << gd.mBoard[1][0] << " | " << gd.mBoard[1][1];
cout << " | " << gd.mBoard[1][2] << endl;
cout << " _____|_____|_____\n";
cout << " | | \n";
cout << " 2 " << gd.mBoard[2][0] << " | " << gd.mBoard[2][1];
cout << " | " << gd.mBoard[2][2] << endl;
cout << " | | \n\n";
}
bool CheckCombo(char a, char b, char c)
{
return (a == 'X' || a == 'O') && (a == b) && (b == c);
}
bool CheckWin(GameData& gd)
{
// Horizontal
for (int i = 0; i != 3; ++i)
{
if (CheckCombo(gd.mBoard[i][0], gd.mBoard[i][1], gd.mBoard[i][2]))
{
cout << "\nPlayer " << (gd.mBoard[i][0] == 'X' ? 1 : 2) << " wins!\n\n";
cout << "Horizontal, i: " << i << endl;
cout << gd.mBoard[i][0] << gd.mBoard[i][1] << gd.mBoard[i][2] << endl;
gd.mGameover = true;
return gd.mGameover;
}
}
// Vertical
for (int j = 0; j != 3; ++j)
{
if (CheckCombo(gd.mBoard[0][j], gd.mBoard[1][j], gd.mBoard[2][j]))
{
cout << "\nPlayer " << (gd.mBoard[0][j] == 'X' ? 1 : 2) << " wins!\n\n";
cout << "Vertical, j: " << j << endl;
cout << gd.mBoard[0][j] << gd.mBoard[1][j] << gd.mBoard[2][j] << endl;
gd.mGameover = true;
return gd.mGameover;
}
}
bool couldBeTie = true;
for (int i = 0; i != 3 && couldBeTie; ++i)
for (int j = 0; j != 3 && couldBeTie; ++j)
couldBeTie &= (gd.mBoard[i][j] != '*');
if (couldBeTie)
{
cout << "\nSorry it's a tie!!\n\n";
gd.mGameover = true;
return gd.mGameover;
}
return gd.mGameover;
}
void GetMove(GameData& gd)
{
int x = 0, y = 0;
cout << "Player " << gd.mPlayer << ", enter X,Y coordinates for your move: ";
cin >> x >> y;
if (gd.mBoard[x][y] == '*')
{
gd.mBoard[x][y] = (gd.mPlayer == 1) ? 'X' : 'O';
CheckWin(gd);
gd.mPlayer = 3 - gd.mPlayer;
}
else
{
cout << ("\nInvalid move, try again.\n\n");
GetMove(gd);
}
}
void InitBoard(GameData& gd)
{
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
gd.mBoard[i][j] = '*';
}
I've also commented out the system() calls because they don't work on my linux machine. Consider avoiding these to make your code more portable though.
One of the things I did too was to put your global variables in a struct and pass them around by reference. Of course, a better solution would be to have a class handling the game and those globals would become member variables instead, but I take it you haven't covered classes yet so I decided not to go with that option.
Another thing I decided not to do was replace your board array with std::vectors, but again, I take it you haven't covered that so I just left the static arrays.
-
Looks like you missed the diagonal win checks Mozza.
The best way to check for wins in TTT is to define an array of the win positions.
Code:
const int wins[][3] = {{0,1,2},{3,4,5},{6,7,8},{0,3,6},{1,4,7},{2,5,8},{0,4,8},{2,4,6}};
Of course you'd need to use a 1D array for the board, which you'd find produces much shorter code anyway.
Lookup tables FTW!