|
-
December 24th, 2014, 12:55 PM
#1
Creating a good computer AI for a tic tac toe game.
I'm almost done with this little mini project that I've been doing for a couple of days and I was wondering how I can go about creating a computer AI given the way that I structured my code. Also, suggestions how I can make my code look better is always welcomed.
main.cpp
Code:
#include <iostream>
#include "Board.h"
#include <limits>
#include <cctype>
using namespace std;
int main()
{
// Welcoming message.
cout << "Welcome users to my very own tic-tac-toe game. " << endl;
// Object to access the class functions
Board process;
char response1; // A variable to gather input from player1 if they want to quit the game or not
char response2; // A variable to gather input from player2 if they want to quit the game or not
int tileCounter = 0; // Represents how many tiles have been used.
int playerWins1 = 0; // How many times player1 won a match.
int PlayerLose1 = 0; // How many times Player1 lost a match.
int playerLose2 = 0; // How many times player 2 lost a match.
int playerWins2 = 0; // How many times player2 won a match.
int tie = 0; // How many times a match ended up in a tie.
while(toupper(response1) != 'N' || toupper(response2) != 'N')
{
process.choosingLetter(); // Players choose their letter for the game.
cout << endl << endl;
process.draw(); // Creates the board.
tileCounter = 0; // reinitializes after each game.
// Game loop
// If there are no 3 matches, keep playing.
while(!process.isGameOver(tileCounter,playerWins1,PlayerLose1, playerWins2, playerLose2, tie)) // If there are no 3 matches, keep playing.
{
cout << endl;
process.playerMove1(); // Outputs player1's move.
cout << endl << endl << endl;
process.draw(); // Call the board again to see the changes.
cout << endl;
tileCounter++;
if(process.isGameOver(tileCounter,playerWins1,PlayerLose1, playerWins2, playerLose2, tie) == true)
{
break;
}
process.playerMove2(); // Outputs player2's move.
cout << endl << endl;
process.draw();
tileCounter++;
}
process.playAgain(response1, response2);
}
process.scoreBoard(playerWins1,PlayerLose1, playerWins2, playerLose2, tie);
return 0;
}
board.h
Code:
#ifndef BOARD_H
#define BOARD_H
class Board
{
public:
Board();
void draw();
void choosingLetter();
void playerMove1();
void playerMove2();
void playerInputCheck1();
void playerInputCheck2();
void playerLocationCheck1();
void playerLocationCheck2();
bool isGameOver(int &, int &, int &, int &, int &, int &);
void refresh();
void playAgain(char &, char &);
void scoreBoard(int &, int &, int &, int &, int &);
private:
char board[3][3];
char PlayerLetter1; // The letter that player 1 will be.
char PlayerLetter2; // The letter that player 2 will be
std::string playerInput1; // Input from player1.
std::string playerInput2; // Input from player2.
};
#endif
board.cpp
Code:
#include <iostream>
#include <limits>
#include "Board.h"
using namespace std;
Board::Board()
{
for(unsigned int i = 0; i < 3; i++)
for(unsigned int j = 0; j < 3; j++)
board[i][j] = ' ';
}
void Board::draw()
{
for(unsigned int i = 0; i < 3; i++)
{
cout << "\t\t";
for(unsigned int j = 0; j < 3; j++)
{
// Display the board.
cout << "|" << board[i][j] << "|";
}
cout << endl; // Create a space between each row and column.
}
}
void Board::choosingLetter()
{
// Prompt the user to choose the letter X or O
cout << "\nPlayer 1, which letter would you like to start as? X or O? ";
cout << endl;
cout << "\n*Note X or O are the only acceptable inputs. ";
cin >> PlayerLetter1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
// Check for valid input.
while(PlayerLetter1 != 'X' && PlayerLetter1 != 'O')
{
cerr << "\nError, invalid input. ";
cin >> PlayerLetter1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
// If player 1 chooses X, then player2 will be O and vice versa.
if(PlayerLetter1 == 'X')
PlayerLetter2 = 'O';
else if(PlayerLetter1 == 'O')
PlayerLetter2 = 'X';
}
void Board::playerMove1()
{
cout << endl;
// Commands that dictates where the letter will be placed.
cout << "\t\t" << "Legend Key" << endl << endl;
cout << "UL=UpperLeft UC=UpperCenter UR=UpperRight " << endl;
cout << "LC=LeftCenter MC=MiddleCenter RC=RightCenter " << endl;
cout << "BL=BottomLeft BM=BottomMiddle BR=BottomRight " << endl;
cout << endl;
// Prompting Player1.
cout << "\nPlayer 1, pick a field. ";
// Checks for valid letter placement and non duplicate locations.
playerLocationCheck1();
}
void Board::playerMove2()
{
cout << endl;
// Commands that dictates where the letter will be placed.
cout << "\t\t" << "Legend Key" << endl << endl;
cout << "UL=UpperLeft UC=UpperCenter UR=UpperRight " << endl;
cout << "LC=LeftCenter MC=MiddleCenter RC=RightCenter " << endl;
cout << "BL=BottomLeft BM=BottomMiddle BR=BottomRight " << endl;
cout << endl;
// Prompting Player2.
cout << "\nPlayer 2, pick a field. ";
// Checks for valid letter placement and non duplicate locations.
playerLocationCheck2();
}
void Board::playerInputCheck1()
{
cin >> playerInput1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
while(playerInput1 != "UL" && playerInput1 != "UC" && playerInput1 != "UR"
&& playerInput1 != "LC" && playerInput1 != "MC" && playerInput1 != "RC"
&& playerInput1 != "BL" && playerInput1 != "BM" && playerInput1 != "BR")
{
cerr << "\nError, unknown command entered. Read the legend key. ";
cin >> playerInput1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
void Board::playerInputCheck2()
{
cin >> playerInput2;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
while(playerInput2 != "UL" && playerInput2 != "UC" && playerInput2 != "UR"
&& playerInput2 != "LC" && playerInput2 != "MC" && playerInput2 != "RC"
&& playerInput2 != "BL" && playerInput2 != "BM" && playerInput2 != "BR")
{
cerr << "\nError, unknown command entered. Read the legend key. ";
cin >> playerInput2;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}
void Board::playerLocationCheck1()
{
bool isEmpty;
while(!isEmpty)
{
// Checks for valid commands.
playerInputCheck1();
if(playerInput1=="UL" && (board[0][0] != 'X' && board[0][0] != 'O'))
{
board[0][0] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="UC" && (board[0][1] != 'X' && board[0][1] != 'O'))
{
board[0][1] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="UR" && (board[0][2] != 'X' && board[0][2] != 'O'))
{
board[0][2] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="LC" && (board[1][0] != 'X' && board[1][0] != 'O'))
{
board[1][0] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="MC" && (board[1][1] != 'X' && board[1][1] != 'O'))
{
board[1][1] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="RC" && (board[1][2] != 'X' && board[1][2] != 'O'))
{
board[1][2] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="BL" && (board[2][0] != 'X' && board[2][0] != 'O'))
{
board[2][0] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="BM" && (board[2][1] != 'X' && board[2][1] != 'O'))
{
board[2][1] = PlayerLetter1;
isEmpty = true;
}
else if(playerInput1=="BR" && (board[2][2] != 'X' && board[2][2] != 'O'))
{
board[2][2] = PlayerLetter1;
isEmpty = true;
}
else
{
cerr << "\nError, this position has already been taken Try again. ";
isEmpty = false;
}
}
}
void Board::playerLocationCheck2()
{
bool isEmpty;
while(!isEmpty)
{
// Checks for valid commands.
playerInputCheck2();
if(playerInput2=="UL" && (board[0][0] != 'X' && board[0][0] != 'O'))
{
board[0][0] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="UC" && (board[0][1] != 'X' && board[0][1] != 'O'))
{
board[0][1] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="UR" && (board[0][2] != 'X' && board[0][2] != 'O'))
{
board[0][2] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="LC" && (board[1][0] != 'X' && board[1][0] != 'O'))
{
board[1][0] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="MC" && (board[1][1] != 'X' && board[1][1] != 'O'))
{
board[1][1] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="RC" && (board[1][2] != 'X' && board[1][2] != 'O'))
{
board[1][2] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="BL" && (board[2][0] != 'X' && board[2][0] != 'O'))
{
board[2][0] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="BM" && (board[2][1] != 'X' && board[2][1] != 'O'))
{
board[2][1] = PlayerLetter2;
isEmpty = true;
}
else if(playerInput2=="BR" && (board[2][2] != 'X' && board[2][2] != 'O'))
{
board[2][2] = PlayerLetter2;
isEmpty = true;
}
else
{
cerr << "\nError, this position has already been taken Try again. ";
isEmpty = false;
}
}
}
bool Board::isGameOver(int &tileCounter, int &playerWins1, int &PlayerLose1, int &playerWins2, int &playerLose2, int &tie)
{
bool gameOver1 = false; // If there are 3 X's.
bool gameOver2 = false; // If there are 3 O's.
bool tieGame = false; // If there are no more tiles.
bool noGameOver; // If there are no 3 X's or 3 O's.
if(board[0][0] == 'X' && board[0][1] == 'X' && board [0][2] == 'X')
{
gameOver1 = true;
}
else if(board[1][0] == 'X' && board[1][1] == 'X' && board [1][2] == 'X')
{
gameOver1 = true;
}
else if(board[2][0] == 'X' && board[2][1] == 'X' && board [2][2] == 'X')
{
gameOver1 = true;
}
else if(board[0][0] == 'X' && board[1][0] == 'X' && board [2][0] == 'X')
{
gameOver1 = true;
}
else if(board[0][1] == 'X' && board[1][1] == 'X' && board [2][1] == 'X')
{
gameOver1 = true;
}
else if(board[0][2] == 'X' && board[1][2] == 'X' && board [2][2] == 'X')
{
gameOver1 = true;
}
else if(board[0][0] == 'X' && board[1][1] == 'X' && board [1][2] == 'X')
{
gameOver1 = true;
}
else if(board[0][2] == 'X' && board[1][1] == 'X' && board [2][0] == 'X')
{
gameOver1 = true;
}
else if(board[0][0] == 'O' && board[0][1] == 'O' && board [0][2] == 'O')
{
gameOver2 = true;
}
else if(board[1][0] == 'O' && board[1][1] == 'O' && board [1][2] == 'O')
{
gameOver2 = true;
}
else if(board[2][0] == 'O' && board[2][1] == 'O' && board [2][2] == 'O')
{
gameOver2 = true;
}
else if(board[0][0] == 'O' && board[1][0] == 'O' && board [2][0] == 'O')
{
gameOver2 = true;
}
else if(board[0][1] == 'O' && board[1][1] == 'O' && board [2][1] == 'O')
{
gameOver2 = true;
}
else if(board[0][2] == 'O' && board[1][2] == 'O' && board [2][2] == 'O')
{
gameOver2 = true;
}
else if(board[0][0] == 'O' && board[1][1] == 'O' && board [1][2] == 'O')
{
gameOver2 = true;
}
else if(board[0][2] == 'O' && board[1][1] == 'O' && board [2][0] == 'O')
{
gameOver2 = true;
}
if(gameOver1 == true)
{
if(PlayerLetter1 == 'X')
{
playerWins1++;
playerLose2++;
cout << "Game over! Player 1 is the victor! " << endl;
return gameOver1;
}
else if(PlayerLetter2 == 'X')
{
playerWins2++;
PlayerLose1++;
cout << "Game over! Player 2 is the victor! " << endl;
return gameOver1;
}
}
else if(gameOver2 == true)
{
if(PlayerLetter1 == 'O')
{
playerWins1++;
playerLose2++;
cout << "Game over! Player 1 is the victor! " << endl;
return gameOver2;
}
else if(PlayerLetter2 == 'O')
{
playerWins2++;
PlayerLose1++;
cout << "Game over! Player 2 is the victor! " << endl;
return gameOver2;
}
}
else if(tileCounter == 9)
{
tie++;
tieGame = true;
cout << "Tie game! No one wins! " << endl;
return tieGame;
}
else if(gameOver1 && gameOver2 == false)
{
noGameOver = false;
}
return noGameOver;
}
void Board::refresh()
{
char newTile = ' '; // gets rid of all the X's and O's
for(unsigned int i = 0; i < 3; i++)
for(unsigned int j = 0; j < 3; j++)
board[i][j] = newTile;
}
void Board::playAgain(char &playerResponse1, char &playerResponse2)
{
cout << "\n\nWould you like to play again player1? [y/n] ";
cin >> playerResponse1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
while(toupper(playerResponse1) != 'Y' && toupper(playerResponse1) != 'N')
{
cerr << "\nError, Invalid response. ";
cin >> playerResponse1;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
cout << "\n\nWould you like to play again player2? [y/n] ";
cin >> playerResponse2;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
while(toupper(playerResponse2) != 'Y' && toupper(playerResponse2) != 'N')
{
cerr << "\nError, Invalid response. ";
cin >> playerResponse2;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
if(toupper(playerResponse1) == 'Y' && toupper(playerResponse2) == 'Y')
{
cout << "\n\nCreating a new board to play on. " << endl;
refresh(); // refreshes the board.
}
else
cout << "\n\nThanks for playing! " << endl << endl << endl;
}
void Board::scoreBoard(int &playerWins1, int &PlayerLose1, int &playerWins2, int &playerLose2, int &tie)
{
cout << "\t\t\tScoreBoard " << endl << endl;
cout << "--------------------------------------------------------------" << endl;
cout << " \t\tWins\t\tLosses " << endl << endl;
cout << "player 1: " << "\t\t\t" << playerWins1 << "\t\t" << PlayerLose1 << endl;
cout << "player 2: " << "\t\t\t" << playerWins2 << "\t\t" << playerLose2 << endl << endl;
cout << "Number of tie games: " << tie << endl;
cout << "--------------------------------------------------------------" << endl;
}
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|