This is my new version of my Tic Tac Toe game written in C++. I tried to follow community advice by separating I/O from the game logic and view (MCV). The code works great, and I am looking to see if I followed the model control view design pattern correctly.
TicTacToe.h
#ifndef TICTACTOE
#define TICTACTOE
#include<string>
class TicTacToe
{
std::string boardInfo;
char player1;
char player2;
public:
TicTacToe();
~TicTacToe();
void markBoard(const size_t &, const char&);
void setPlayerMark(const char &);
char getMark(const int &);
char checkWin(const int&);
char positionValue(const size_t&);
};
#endif
TicTacToe.cpp
#include "TicTacToe.h"
TicTacToe::TicTacToe()
{
boardInfo = "123456789";
player1 = 'X';
player2 = 'O';
}
TicTacToe::~TicTacToe()
{
}
void TicTacToe::markBoard(const size_t & boardIndex, const char &playerMark) {
boardInfo[boardIndex - 1] = playerMark;
}
// 'X' or 'O' = game win, 'C' = catsgame, and 'N' = no win
char TicTacToe::checkWin(const int &turnCount) {
//winning solutions involving middle square
for (size_t i = 0, k = 8; i <= 3 && k >= 5; i++, k--) {
if (boardInfo[4] == boardInfo[i] && boardInfo[i] == boardInfo[k]) {
return boardInfo[4];
}
}
//remaining winning solutions
if (boardInfo[2] == boardInfo[1] && boardInfo[1] == boardInfo[0]) { return boardInfo[2]; }
if (boardInfo[2] == boardInfo[5] && boardInfo[5] == boardInfo[8]) { return boardInfo[2]; }
if (boardInfo[6] == boardInfo[3] && boardInfo[3] == boardInfo[1]) { return boardInfo[6]; }
if (boardInfo[6] == boardInfo[7] && boardInfo[7] == boardInfo[8]) { return boardInfo[6]; }
//catsgame
int totalTurns = 9; //total possible turns
if (turnCount > totalTurns) { return 'C'; }
return 'N';
}
void TicTacToe::setPlayerMark(const char &mark) {
player1 = mark;
//the other player will always receives opposite mark
switch (mark) {
case 'X': player2 = 'O';
break;
case 'x': player2 = 'o';
break;
case 'O': player2 = 'X';
break;
case 'o': player2 = 'x';
break;
}
}
char TicTacToe::positionValue(const size_t &index) {
return boardInfo[index];
}
char TicTacToe::getMark(const int &player) {
if (player == 1) {
return player1;
}
if (player == 2) {
return player2;
}
return 'N';
}
Game.h
#ifndef GAME
#define GAME
#include <iostream>
#include <limits>
#include "TicTacToe.h"
class Game
{
TicTacToe board1;
public:
Game();
~Game();
void drawBoard();
void turn(int &, TicTacToe &);
void setMarks();
void run();
};
#endif
Game.cpp
#include "Game.h"
Game::Game()
{
}
Game::~Game()
{
}
void Game::drawBoard() {
std::cout << " " << board1.positionValue(0) << " |" << " " << board1.positionValue(1) << " |" << " " << board1.positionValue(2) << "\n";
std::cout << "___|___|___ \n";
std::cout << " " << board1.positionValue(3) << " |" << " " << board1.positionValue(4) << " |" << " " << board1.positionValue(5) << "\n";
std::cout << "___|___|___ \n";
std::cout << " " << board1.positionValue(6) << " |" << " " << board1.positionValue(7) << " |" << " " << board1.positionValue(8) << "\n";
std::cout << " | | ";
}
void Game::turn(int &turnCount, TicTacToe &board1) {
char mark;
size_t spaceChoice;
if (turnCount % 2) {
mark = board1.getMark(1); //player 1's mark
turnCount++;
std::cout << "\nPlayer 1's turn\nChoose space to mark: ";
}
else {
mark = board1.getMark(2); //player 2's mark
turnCount++;
std::cout << "\nPlayer 2's turn\nChoose space to mark: ";
}
bool inputpass = false; //used to check if the input is passed, failed, or not marked
while (!inputpass) {
//tests input type
if (std::cin >> spaceChoice) {
//checks domain
if (spaceChoice > 0 && spaceChoice < 10) {
char check = board1.positionValue(spaceChoice-1); //used to check if space has been marked
if (check != 'X' && check != 'x' && check != 'O' && check != 'o') {
board1.markBoard(spaceChoice, mark);
inputpass = true;
}
else {
std::cout << "\nSPACE ALREADY MARKED\nTry again: ";
}
}
else {
std::cout << "\nINNCORRECT SPACE\nTry agian: ";
}
}
//if the input type fails
else {
std::cout << "\nINCORRECT INPUT TYPE\nTry agian:";
std::cin.clear(); //clears input fail state
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
}
void Game::setMarks() {
char tempMark;
bool inputPass = false;
while (!inputPass) {
if (std::cin >> tempMark) {
if (tempMark == 'X' || tempMark == 'x' || tempMark == 'O' || tempMark == 'o') {
board1.setPlayerMark(tempMark);
inputPass = true;
}
else {
std::cout << "MARK MUST BE X OR O\nTry again: ";
}
}
else {
std::cout << "INCCORECT INPUT TYPE\nTry again: ";
}
}
}
void Game::run() {
std::cout << "Enter wether player 1 is 'X' or 'O': ";
setMarks();
char gameWin = 'N';
int turnCount = 1;
drawBoard();
while (gameWin != 'X' && gameWin != 'x' && gameWin != 'O' && gameWin != 'o' && gameWin != 'C') {
turn(turnCount, board1);
gameWin = board1.checkWin(turnCount);
drawBoard();
}
if (gameWin != 'C') {
std::cout << ((board1.getMark(1) == gameWin) ? "\nThe winner is: Player 1!" : "\nThe winner is: Player 2!");
}
else
std::cout << "\nCATS GAME!";
}
main.cpp
#include <iostream>
#include "Game.h"
void pause();
int main() {
Game game1;
game1.run();
pause();
}
void pause() {
char end;
std::cout << "\nPress any key followed by ENTER to continue...";
std::cin >> end;
}