/* Tic-Tac-Toe Game - This program allows two players to play a game of
tic-tac-toe. It uses a two dimensional char array with three rows and
three columns as the game board. Each element of the array is initialized
with an asterisk (*).
* Displays the contents of the board array.
* Allows player 1 to select a location on the board for an X. The
program asks the user to enter the row and column number.
* Allows player 2 to select a location on the board for an O. The
program asks the user to enter the row and column number.
* Determines whether a player has isWinner, or a tie has occured. If a
player has isWinner, the program declares that player the winner and
end. If a tie has occured, the program says so and end.
Player 1 wins when there are three Xs in a row on the game board. The
Xs can appear in a row, in a column, or diagonally across the board.
A tie occurs when all of the locations on the board are full, but there
is no winner. */
#include "Utility.h"
/* Global Constants: Position x, Position y, Maximum number of turns,
Number of players, Filler */
const int POS_X = 3;
const int POS_Y = 3;
const int MAX_TURNS = 9;
const int NUM_PLAYERS = 2;
const char FILLER = '*';
/* Typedef alias for gameboard array */
typedef char gameBoard[POS_X][POS_Y];
/* Function Prototypes: Main menu, Display menu, Display intro,
Display logo, Get player info (name and play tile), Initialize
gameboard, Get move, Check move (validate the moves), Check
win, Populate highscores, Display winner */
int mainMenu();
void displayMenu();
void displayInstructions();
void displayLogo();
void getPlayerInfo(string &, char &, string &, char &);
void initGameboard(gameBoard board);
void displayGameboard(gameBoard board);
void getMove(gameBoard board, string, string, int &, int &,
char, char, int);
bool checkMove(gameBoard board, int, int);
bool checkWin(const gameBoard board, int, int);
void popHighscores(string [], int [], string, string, int);
void displayHighscores(const string [], const int []);
void displayWinner(string, string, bool, int);
int main()
{
mainMenu();
pauseSystem();
return 0;
}
/* **********************************************************
Definition: displayMenu
This function displays the menu options. On first start of
the game a logo is also displayed when this function is
called.
********************************************************** */
void displayMenu()
{
/* Variable: First start initialized to true (If the game is run
for the first time, the logo is displayed once, and
firstStart gets false */
static bool firstStart = true;
if (firstStart == true)
{
displayLogo();
}
cout << "\n\t\tTIC-TAC-TOE GAME\n\n"
<< "\t\t[1.] INSTRUCTIONS\n"
<< "\t\t[2.] SETUP\n"
<< "\t\t[3.] START GAME\n"
<< "\t\t[4.] HIGHSCORE\n"
<< "\t\t[5.] QUIT\n\n"
<< "\t\tCHOOSE: ";
firstStart = false;
}
/* **********************************************************
Definition: mainMenu
This function provides a basic menu that lets the players
select between the following items:
* Introduction - Gives a basic overview of the game
* Setup - Asks the players for their names and the
play tiles they wish to play with
* Start game
* Highscores
* Quit
********************************************************** */
int mainMenu()
{
/* board is the alias for the gameboard array */
gameBoard board = { };
/* Constants: Introduction, Setup, Start game, Highscore, Quit */
const int INSTRUCTIONS = 1,
SETUP = 2,
START_GAME = 3,
HIGHSCORES = 4,
QUIT = 5;
/* Variables: Menu item, Is win, Index X, Index Y, Tick (counter),
Name player one, Name player two, Play tile player one,
Play tile player two, Player names, Highscores */
int menuItem = 0;
int idxX = 0, idxY = 0;
bool isWin = false;
static int tick = 0;
static string nameP1 = " ",
nameP2 = " ";
static char tileP1 = ' ',
tileP2 = ' ';
static string playerNames[NUM_PLAYERS] = { " ", " " };
static int highScores[NUM_PLAYERS] = { };
do
{
displayMenu();
cin >> menuItem;
while (menuItem < 1 || menuItem > 5)
{
displayMenu();
}
switch (menuItem)
{
case 1:
displayInstructions();
break;
case 2:
getPlayerInfo(nameP1, tileP1, nameP2, tileP2);
break;
case 3:
{
/* Checks whether the players have completed the initial
setup. If so, the gameloop is entered. If they didn't,
the getPlayerInfo function is called. */
if (nameP1 != " " || nameP2 != " " ||
tileP1 != ' ' || tileP2 != ' ')
{
/* Initialize the gameboard */
initGameboard(board);
/* Reset tick to 0 after it has reached MAX_TURNS, or after
each win by either player */
tick = 0;
/* The gameloop runs until either a win or a draw has
been reached. */
do
{
tick += 1;
displayGameboard(board);
getMove(board, nameP1, nameP2, idxX, idxY,
tileP1, tileP2, tick);
isWin = checkWin(board, idxX, idxY);
} while (isWin == false && tick != MAX_TURNS);
if (isWin == true)
{
displayWinner(nameP1, nameP2, isWin, tick);
popHighscores(playerNames, highScores, nameP1,
nameP2, tick);
displayGameboard(board);
}
else if (isWin == false)
{
displayWinner(nameP1, nameP2, isWin, tick);
displayGameboard(board);
}
}
else
{
cout << "\n\t\tPlease complete the setup before "
<< "you start the game!\n";
getPlayerInfo(nameP1, tileP1, nameP2, tileP2);
}
}
break;
case 4:
displayHighscores(playerNames, highScores);
break;
case 5:
cin.clear();
cout << "\n\n\t\t{~REMEMBER: THE ONLY WINNING MOVE IS NOT TO PLAY!~}\n\n"
<< "\t\t\t\tSHUTTING DOWN GAME ...\n\n";
break;
}
} while (menuItem != QUIT);
return 0;
}
/* **********************************************************
Definition: displayLogo
Displays the game logo.
********************************************************** */
void displayLogo()
{
cout << "\n\n\t\t*****" << "\t*****" << "\t*****\n"
<< "\t\t * *" << "\t * * " << "\t*\n"
<< "\t\t *" << "\t * " << "\t*\n"
<< "\t\t *" << "\t * *" << "\t*\n"
<< "\t\t *" << "\t*****" << "\t*****\n\n"
<< "\t\t\t\t*****" << "\t*****" << "\t*****\n"
<< "\t\t\t\t * *" << "\t* *" << "\t*\n"
<< "\t\t\t\t *" << "\t* * *" << "\t*\n"
<< "\t\t\t\t *" << "\t* *" << "\t*\n"
<< "\t\t\t\t *" << "\t* *" << "\t*****\n\n"
<< "\t\t\t\t\t\t*****" << "\t*****" << "\t*****\n"
<< "\t\t\t\t\t\t * * " << "\t* * *" << "\t*\n"
<< "\t\t\t\t\t\t *" << "\t* *" << "\t* *\n"
<< "\t\t\t\t\t\t *" << "\t* * *" << "\t*\n"
<< "\t\t\t\t\t\t *" << "\t*****" << "\t*****\n\n";
}
/* **********************************************************
Definition: displayInstructions
This function reads in and displays the instructions from
"instructions.txt"
********************************************************** */
void displayInstructions()
{
/* Instantiate input file stream object*/
ifstream tttRules;
/* Variable to hold the contents of "instructions.txt" */
string rules = " ";
/* Open: "Instructions.txt" */
tttRules.open("instructions.txt");
/* If the file exists, and was opened successfully, the content is
read in and displayed */
if (tttRules)
{
cout << "\n\n";
while (getline(tttRules, rules) && !tttRules.eof())
{
cout << " " << rules << "\n";
}
}
else
{
cout << "\n\t\tFile Processing Error: 'instructions.txt' could not be opened,\n"
<< "\t\tread-in or processed. Please make sure that the file exists\n"
<< "\t\tand that it is placed in the correct folder. If it exists but is\n"
<< "\t\tis damaged, replace it with the original file provided to you.\n"
<< "\t\tPlease choose quit from the main menu to exit this program.\n\n";
}
/* Close: "instructions.txt" */
tttRules.close();
}
/* **********************************************************
Definition: getPlayerInfo
Asks the players for their names and play tiles they wish
to play with.
********************************************************** */
void getPlayerInfo(string &nameP1, char &tileP1, string &nameP2,
char &tileP2)
{
cout << "\n\t\tName Player One: ";
cin >> nameP1;
cout << "\t\tPlay Tile " << nameP1 << ": ";
cin >> tileP1;
cout << "\n\t\tName Player Two: ";
cin >> nameP2;
cout << "\t\tPlay Tile " << nameP2 << ": ";
cin >> tileP2;
/* Input validation */
while (tileP1 == tileP2)
{
cout << "\n\t\t" << nameP1 << " already selected this tile!\n\n";
cout << "\t\tPlay Tile " << nameP2 << ": ";
cin >> tileP2;
}
}
/* **********************************************************
Definition: initGameboard
This function initializes the board before the game starts
with FILLER ('*').
********************************************************** */
void initGameboard(gameBoard board)
{
/* Variables: Index x, Index y */
int idxX = 0,
idxY = 0;
/* Populate the gameboard with the Filler character */
for (int idxX = 0; idxX < 3; idxX++)
{
for (int idxY = 0; idxY < 3; idxY++)
{
board[idxX][idxY] = FILLER;
}
}
}
/* **********************************************************
Definition: displayGameboard
This function displays the gameboard populated at first
start with FILLER ('*'), and after each move, displaying
the player tiles at the appropriate position.
********************************************************** */
void displayGameboard(gameBoard board)
{
/* Constant: Seperator width */
const int SEP_SIZE = 20;
/* Variables: Index x, Index y (loop counters) */
int idxX = 0, idxY = 0;
for (idxX = 0; idxX < POS_X; ++idxX)
{
cout << "\n\n\n\n";
for (int idxY = 0; idxY < POS_Y; ++idxY)
{
cout <<setw(SEP_SIZE) << right << "| "
<< board[idxX][idxY] << " |";
}
cout << "\n\n\n\n";
}
}
/* **********************************************************
Definition: getMove
This function gets the player moves, and assigns the tile
to a board position if a move is valid.
********************************************************** */
void getMove(gameBoard board, string nameP1, string nameP2,
int &idxX, int &idxY, char tileP1, char tileP2,
int tick)
{
/* Variable: Is valid initialized to false */
bool isValid = false;
/* Tick is used to display whose turn it is */
tick % 2 == 1 ? cout << "\t\tMOVE: " << nameP1 << "\n" :
cout << "\t\tMOVE: " << nameP2 << "\n";
cout << "\n\t\tEnter Position x: ";
cin >> idxX;
cout << "\t\tEnter Position y: ";
cin >> idxY;
/* Validate input */
while (idxX < 0 || idxY < 0 || idxX > 2 || idxY > 2)
{
cout << "\n\t\tInvalid Move!\n";
cout << "\t\tEnter Position x: ";
cin >> idxX;
cout << "\t\tEnter Position y: ";
cin >> idxY;
}
while (isValid = checkMove(board, idxX, idxY) == false)
{
cout << "\n\t\tThis square already is already taken!\n";
cout << "\t\tEnter Position x: ";
cin >> idxX;
cout << "\t\tEnter Position y: ";
cin >> idxY;
}
/* If input is accepted as being correct, the appropriate play
tile is assigned to the gameboard position */
if (isValid = checkMove(board, idxX, idxY) == true)
{
tick % 2 == 1 ? board[idxX][idxY] = tileP1 :
board[idxX][idxY] = tileP2;
}
}
/* **********************************************************
Definition: checkMove
This function validates the moves.
********************************************************** */
bool checkMove(gameBoard board, int idxX, int idxY)
{
bool isValid = false;
board[idxX][idxY] == FILLER ? isValid = true : isValid = false;
return isValid;
}
/* **********************************************************
Definition: checkWin
This function checks whether there is a winner. The first
and second ternary operators check the vertical and the
horizontal board positions, the second to the last checks
diagonal [x+0,0][y+2.2] / [y+2.2][x+0.0] direction, and
the last ternary checks [x+0.2][y+2.0] / [y+2.0][x+0.0]
for a win. If a winner is found, isWin gets true, and is
returned.
********************************************************** */
bool checkWin(const gameBoard board, int idxX, int idxY)
{
bool isWin = 0;
board[0][idxY] == board[1][idxY] && board[0][idxY] == board[2][idxY] ?
isWin = true : isWin = false;
if (isWin == true)
{
return isWin;
}
board[idxX][0] == board[idxX][1] && board[idxX][0] == board[idxX][2] ?
isWin = true : isWin = false;
if (isWin == true)
{
return isWin;
}
board[0][0] != FILLER && board[0][0] == board[1][1] &&
board[1][1] != FILLER && board[1][1] == board[2][2] ?
isWin = true : isWin = false;
if (isWin == true)
{
return isWin;
}
board[0][2] != FILLER && board[0][2] == board[1][1] &&
board[1][1] != FILLER && board[1][1] == board[2][0] ?
isWin = true : isWin = false;
return isWin;
if (isWin == true)
{
return isWin;
}
return 0;
}
/* **********************************************************
Definition: popHighscores
This function accepts the following arrays as arguments:
* nameTable - Stores the player names
* highScore - Stores the number of wins of each player
********************************************************** */
void popHighscores(string nameTable[], int highScore [], string nameP1,
string nameP2, int tick)
{
/* Variables: Score player one, Score player two */
static int scoreP1 = 0,
scoreP2 = 0;
/* Score increments after each win by 1. The player names
and highscores are then stored in the according arrays */
tick % 2 == 1 ? scoreP1 += 1 : scoreP2 += 1;
tick % 2 == 1 ? nameTable[0] = nameP1 : nameTable[1] = nameP2;
tick % 2 == 1 ? highScore[0] = scoreP1 : highScore[1] = scoreP2;
}
/* **********************************************************
definition: displayWinner
This function displays a congratulatory message when a
game has been won by either player. In case of a draw,
the players are notified accordingly.
********************************************************** */
void displayWinner(string nameP1, string nameP2, bool isWin, int tick)
{
if (isWin == true)
{
tick % 2 == 1 ? cout << "\n\n\t\t\tCONGRATULATIONS, " << nameP1
<< "! YOU WON THIS ROUND!\n" :
cout << "\n\n\t\t\tCONGRATULATIONS, " << nameP2
<< "! YOU WON THIS ROUND!\n";
}
else
{
cout << "\n\t\tWE HAVE A DRAW!\n\n";
}
}
/* **********************************************************
Definition: displayHighscores
This function accepts the following arrays as arguments:
* nameTable[] - Contains the player names
* highScore[] - Contains the highscores reached by each
player
If called the Highscores are displayed.
********************************************************** */
void displayHighscores(const string nameTable[], const int highScore[])
{
/* Display: Table header and highscores */
cout << "\n\n\t\tPLAYER NAME: " << "\t\t" << "HIGHSCORE:\n"
<< "\t\t------------" << "\t\t" << "---------\n";
for (unsigned int numScores = 0; numScores < NUM_PLAYERS; ++numScores)
{
cout << "\t\t" << nameTable[numScores] << "\t\t\t"
<< highScore[numScores] << "\n\n";
}
}
Wednesday, March 1, 2017
Programming Challenge 7.18 - Tic-Tac-Toe Game
Example file: instructions.txt
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment