I'm working on a project in which I'm utilizing classes to code a tictactoe game. Everything runs smoothly up until the moment i check for winners. The program seems to be finding the winner, but instead of displaying the message, it's exiting immediately. I don't know what could be causing the problem.
This is my first project and I'd like to make it as nice as possible. What do you think is causing the problem?
Any other thoughts/recommendations on what I should improve or fix are accepted.
Below is my class, function definitions and main. I intend to make separate files once im done with the whole thing.
#include <iostream>
#include <string>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class tictactoe {
public:
tictactoe();
//default CTOR, initializes our board and moves counter.
void displayBoard()const;
//displays our board through each iteration.
void getMove(char player);
//asks the user for his move, once received, checks if move is valid
//and if so stores move in board for next iteration.
void playGame();
//creates a loop in order to play the game.
private:
staticconstint BSIZE = 3; //board size
staticconstint maxMoves = 9; //max moves possible in a game of ttt
staticconstint minMovesToWin = 5; //min moves before checking for win
char board[BSIZE][BSIZE]; //our board
int totalMoves; //moves counter
bool checkForWins(char player)const;
//takes in the player sign
//checks board (rows, colums and diagonals) to see if we have foudn a winner
bool checkForDraw()const;
//checks to see if max number of moves has been reached.
// if so it's a tie
void fill_board();
//fills our 3*3 array of blank spaces
char togglePlayer(char player);
//changes the player sign at the end of the turn
};
tictactoe::tictactoe(){
totalMoves = 0;
fill_board();
}
void tictactoe::fill_board() {
for (int row = 0; row < BSIZE; row++) {
for (int col = 0; col < BSIZE;col++) {
board[row][col] = ' ';
}
}
}
void tictactoe::displayBoard()const {
cout << " --------------\n";
for (int row = 0; row < BSIZE; row++) {
cout << " | ";
for (int col = 0; col < BSIZE; col++) {
cout << board[row][col] << " |";
}
cout << "\n --------------\n";
}
}
void tictactoe::getMove(char player){
//variables
string input; //stores our input
char char_entered; //takes the character entered for evaluation
int num_entered, row, col, index; //help set our play on the board.
while (true) {
cout << player << " Where do you want to play? Select a number from 1-9: " << endl;
getline(cin, input);
if (input != "") {
//Since we are checking for a correct move
//we convert string into a cstring for easier comparison.
char_entered = input.c_str()[0];
if (char_entered >= '1' && char_entered <= '9') {
//If the input is between the desired range, convert it into an int.
num_entered = char_entered - '0';
//Use this number to find index and store the move into our board.
index = num_entered - 1; //this way if user enters 1 it means index 0 of board.
//we can use division and the remainder, in order to find the correct row and column.
row = index / 3;
col = index % 3;
//check if the position on the board is empty (correct move), else it's wrong move.
char b_pos = board[row][col];
if (b_pos != 'X' && b_pos != 'O') {
//if correct move, place mark on board and we can move onto the next turn
board[row][col] = player;
totalMoves++;
break;
}
else
cout << "Wrong move. Position is already taken. Try again" << endl;
}
else
cout << "You must enter a number between 1-9 to make your move."
<< "Try again. \n";
}
else
cout << "You must enter something!!" << endl;
}
cout << "Total moves: " << this->totalMoves << endl;
}
char tictactoe::togglePlayer(char player) {
player = player == 'X' ? 'O' : 'X';
return (player);
}
bool tictactoe::checkForWins(char player)const{
//only check for a winner once the min moves to win has been reached.
if (totalMoves >= minMovesToWin) {
//check rows for winner
if (board[0][0] == player && board[0][1] == player && board[0][2] == player) {
returntrue;
}
if (board[1][0] == player && board[1][1] == player && board[1][2] == player)
{
returntrue;
}
if (board[2][0] == player && board[2][1] == player && board[2][2] == player)
{
returntrue;
}
//columns
if (board[0][0] == player && board[1][0] == player && board[2][0] == player)
{
returntrue;
}
if (board[0][1] == player && board[1][1] == player && board[2][1] == player)
{
returntrue;
}
if (board[0][2] == player && board[1][2] == player && board[2][2] == player)
{
returntrue;
}
//Accross
if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
{
returntrue;
}
if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
{
returntrue;
}
}
returnfalse;
}
bool tictactoe::checkForDraw()const{
return totalMoves == maxMoves;
}
void tictactoe::playGame(){
char player = 'X'; //initialize the player.
bool gameOver = false;
//single game iteration
do {
displayBoard();
getMove(player);
if (checkForWins(player)) {
cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
<< player << "WINS!!";
gameOver = true;
}
elseif (checkForDraw()) {
cout << "IT'S A DRAW! Play again!" << endl;
gameOver = true;
}
player = togglePlayer(player);
} while (!gameOver);
displayBoard();
}
int main() {
tictactoe game;
game.playGame();
return 0;
}
When I run it from the shell it worked.
What input did you try ?
--------------
| | | |
--------------
| | | |
--------------
| | | |
--------------
X Where do you want to play? Select a number from 1-9:
1
Total moves: 1
--------------
| X | | |
--------------
| | | |
--------------
| | | |
--------------
O Where do you want to play? Select a number from 1-9:
4
Total moves: 2
--------------
| X | | |
--------------
| O | | |
--------------
| | | |
--------------
X Where do you want to play? Select a number from 1-9:
2
Total moves: 3
--------------
| X |X | |
--------------
| O | | |
--------------
| | | |
--------------
O Where do you want to play? Select a number from 1-9:
5
Total moves: 4
--------------
| X |X | |
--------------
| O |O | |
--------------
| | | |
--------------
X Where do you want to play? Select a number from 1-9:
3
Total moves: 5
*********** WE HAVE A WINNER!! ***********
XWINS!! --------------
| X |X |X |
--------------
| O |O | |
--------------
| | | |
--------------
There is nothing wrong with your program. It works just fine. However, when the program completes, the program closes so fast that you can't see the end of it. You will need to put a pause into your program. There are a couple of ways to do this...
One trick is this line...
1 2
system("pause");
return 0;
Adding a system pause before return 0 will cause a pause. But this method is operating system dependent. It works on a microsoft windows computer.
Another trick...
1 2
cin.get();
return 0;
Putting the get before return 0 will make the program wait for the player to press enter before closing.
Hello, I've continued to add some new things to the game such as a simple rand AI and a menu, and now I've run into a few bugs:
#1 After the user makes the choice for playing vs ai or user and the game starts, it's taking that input and immediately reading it as a player move, it is displaying: "you must enter something!!"
#2 At the end of the playVsAI loop, if the game ends up beign a draw, the board doesnt display the last move made unlike the playGame (play vs human) loop.
Any ideas on how to fix this??
Updated code below!
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
using std::cout;
using std::cin;
using std::endl;
using std::string;
class tictactoe {
public:
tictactoe();
//default CTOR, initializes our board and moves counter.
void displayBoard()const;
//displays our board through each iteration.
void getUserMove(char player);
//asks the user for his move, once received, checks if move is valid
//and if so stores move in board for next iteration.
void compMove(char player);
//simulates the computer move (turn)
void playGame();
//creates a loop in order to play the game.
void playVsAI();
//Simulates a single game iteration vs the computer.
//initialize srand for computer choice.
friendchar menu();
//
friendvoid command();
private:
staticconstint BSIZE = 3; //board size
staticconstint maxMoves = 9; //max moves possible in a game of ttt
staticconstint minMovesToWin = 5; //min moves before checking for win
char board[BSIZE][BSIZE]; //our board
int totalMoves; //moves counter
bool checkForWins(char player)const;
//takes in the player sign
//checks board (rows, colums and diagonals) to see if we have foudn a winner
bool checkForDraw()const;
//checks to see if max number of moves has been reached.
// if so it's a tie
void fill_board();
//fills our 3*3 array of blank spaces
char togglePlayer(char player);
//changes the player sign at the end of the turn
};
tictactoe::tictactoe(){
totalMoves = 0;
fill_board();
}
void tictactoe::fill_board() {
for (int row = 0; row < BSIZE; row++) {
for (int col = 0; col < BSIZE;col++) {
board[row][col] = ' ';
}
}
}
void tictactoe::displayBoard()const {
cout << " --------------\n";
for (int row = 0; row < BSIZE; row++) {
cout << " | ";
for (int col = 0; col < BSIZE; col++) {
cout << board[row][col] << " |";
}
cout << "\n --------------\n";
}
}
void tictactoe::getUserMove(char player){
//variables
string input; //stores our input
char char_entered; //takes the character entered for evaluation
int num_entered, row, col, index; //help set our play on the board.
int player_turn;
if (player == 'X') {
player_turn = 1;
}
else {
player_turn = 2;
}
while (true) {
cout << "Player " << player_turn << " Where do you want to play? Select a number from 1-9: " << endl;
getline(cin, input);
if (input != "") {
//Since we are checking for a correct move
//we convert string into a cstring for easier comparison.
char_entered = input.c_str()[0];
if (char_entered >= '1' && char_entered <= '9') {
//If the input is between the desired range, convert it into an int.
num_entered = char_entered - '0';
//Use this number to find index and store the move into our board.
index = num_entered - 1; //this way if user enters 1 it means index 0 of board.
//we can use division and the remainder, in order to find the correct row and column.
row = index / 3;
col = index % 3;
//check if the position on the board is empty (correct move), else it's wrong move.
char b_pos = board[row][col];
if (b_pos != 'X' && b_pos != 'O') {
//if correct move, place mark on board and we can move onto the next turn
board[row][col] = player;
totalMoves++;
break;
//otherwise let the user know.
}
else
cout << "Wrong move. Position is already taken. Try again" << endl;
}
else
cout << "You must enter a number between 1-9 to make your move."
<< "Try again. \n";
}
else
cout << "You must enter something!!" << endl;
}
cout << "Total moves: " << totalMoves << endl; //no need for this-> since var can be accessed by memfunctions
}
char tictactoe::togglePlayer(char player) {
player = player == 'X' ? 'O' : 'X';
return (player);
}
bool tictactoe::checkForWins(char player)const{
//only check for a winner once the min moves to win has been reached.
if (totalMoves >= minMovesToWin) {
//check rows for winner
if (board[0][0] == player && board[0][1] == player && board[0][2] == player) {
returntrue;
}
if (board[1][0] == player && board[1][1] == player && board[1][2] == player)
{
returntrue;
}
if (board[2][0] == player && board[2][1] == player && board[2][2] == player)
{
returntrue;
}
//columns
if (board[0][0] == player && board[1][0] == player && board[2][0] == player)
{
returntrue;
}
if (board[0][1] == player && board[1][1] == player && board[2][1] == player)
{
returntrue;
}
if (board[0][2] == player && board[1][2] == player && board[2][2] == player)
{
returntrue;
}
//Accross
if (board[0][0] == player && board[1][1] == player && board[2][2] == player)
{
returntrue;
}
if (board[0][2] == player && board[1][1] == player && board[2][0] == player)
{
returntrue;
}
}
returnfalse;
}
bool tictactoe::checkForDraw()const{
return totalMoves == maxMoves;
}
void tictactoe::playGame(){
char player = 'X'; //initialize the player.
bool gameOver = false;
//single game iteration
do {
displayBoard();
getUserMove(player);
if (checkForWins(player)) {
cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
<< player << " WINS!!" << endl;
gameOver = true;
}
elseif (checkForDraw()) {
cout << "IT'S A DRAW! Play again!" << endl;
gameOver = true;
}
player = togglePlayer(player);
} while (gameOver != true);
displayBoard();
}
void tictactoe::compMove(char player) {
srand(time_t(NULL)); //place seed for our rand choice.
while (true) {
int computer_choice = (rand() % 9) + 1;
int row = (computer_choice - 1) / 3;
int col = (computer_choice - 1) % 3;
char bpos = board[row][col]; //position on the board.
//check if position is empty or not
if (bpos == 'X' || bpos == 'O') { //if taken then lets make another choice.
continue;
}
else { //otherwise place comp places its mark!
cout << "Computer will play at: " << computer_choice << endl;
board[row][col] = player;
totalMoves++;
break;
}
}
cout << "Total moves: " << totalMoves << endl;
}
void tictactoe::playVsAI() {
char player = 'X'; //initialize the player.
bool gameOver = false;
//single game iteration vs computer
do {
displayBoard();
getUserMove(player);// human player
if (checkForWins(player)) { //check human win
cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
<< player << " WINS!!" << endl;
gameOver = true;
}
elseif (checkForDraw()) {
cout << "IT'S A DRAW! Play again!" << endl;
gameOver = true;
}
player = togglePlayer(player);
compMove(player); //comp player
if (checkForWins(player)) { //check human win
cout << "\n *********** WE HAVE A WINNER!! ***********" << endl
<< player << " WINS!!" << endl;
gameOver = true;
}
elseif (checkForDraw()) {
cout << "IT'S A DRAW! Play again!" << endl;
gameOver = true;
}
player = togglePlayer(player);
} while (gameOver!= true);
displayBoard();
}
char menu() {
char choice;
cout << "******WELCOME TO TICTACTOE BY EMILIANO G.******" << endl;
cout << "Press 1 to play vs another human player." << endl;
cout << "Press 2 to play vs AI" << endl;
cout << "Press 0 to quit game" << endl;
cin >> choice;
return choice;
}
void command(){
char command;
tictactoe *game;
do {
command = menu();
switch (command) {
case'1':
game = new tictactoe;
game->playGame();
break;
case'2':
game = new tictactoe;
game->playVsAI();
break;
}
system("pause");
} while (command != '0');
exit(0);
}
//menu will initialize and display options to play vs ai or human player.
//depending on choice, it will create an object of the class
//access function playGame if human, playVsAI if user wants to play
//vs ai
//play vs ai ft will initiliaze a srand(time(NULL)) for the pc's move
int main() {
//display menu
command();
//prevents game from exiting too fast and not displaying the winner.
cin.get();
return 0;
}