This is based on my first Tic-Tac-Toe game:
I have come up with different game logic for my game. I would like to know which one is more reliable and effective and how I can improve the whole game.
#include <iostream>
#include <cctype>
#include <algorithm>
#include <functional>
#include <array>
#include <vector>
class TicTacToe
{
public:
bool isFull() const;
void draw() const;
void turn(char player);
bool check(char player) const;
private:
bool fill(char player, int position);
static const std::size_t mDim = 3;
std::array<char, mDim * mDim> grid
{
{
'-', '-', '-',
'-', '-', '-',
'-', '-', '-'
}
};
};
template<std::size_t dim>
struct column : public std::unary_function<int, bool>
{
column(int i)
: colNum(i)
{}
bool operator() (int number)
{
return (number % dim == colNum);
}
int colNum;
};
struct pairCondition
{
int number;
char name;
pairCondition(int number, char name)
: number(number), name(name)
{}
bool operator== (const pairCondition& s) const
{
return name == s.name;
}
};
bool checkCondition(const pairCondition& i, const std::array<int, 3>& a, char player)
{
if (i.number == a[0] || i.number == a[1] || i.number == a[2])
return i.name == player;
else
return i.name != player;
}
bool TicTacToe::fill(char player, int position)
{
if (grid[position] != '-')
return false;
grid[position] = player;
return true;
}
bool TicTacToe::isFull() const
{
return 0 == std::count_if(grid.begin(), grid.end(),
[](const char& i)
{
return i == '-';
});
}
bool TicTacToe::check(char player) const
{
typedef std::function<bool(pairCondition)> func;
// rows
bool row1 = true, row2 = true, row3 = true;
std::array<int, 3> rows1 = { 0, 1, 2 };
std::array<int, 3> rows2 = { 3, 4, 5 };
std::array<int, 3> rows3 = { 6, 7, 8 };
func rowf1 = std::bind(&checkCondition, std::placeholders::_1, rows1, player);
func rowf2 = std::bind(&checkCondition, std::placeholders::_1, rows2, player);
func rowf3 = std::bind(&checkCondition, std::placeholders::_1, rows3, player);
// columns
bool col1 = true, col2 = true, col3 = true;
std::array<int, 3> columns1 = { 0, 3, 6 };
std::array<int, 3> columns2 = { 1, 4, 7 };
std::array<int, 3> columns3 = { 2, 5, 8 };
func colf1 = std::bind(&checkCondition, std::placeholders::_1, columns1, player);
func colf2 = std::bind(&checkCondition, std::placeholders::_1, columns2, player);
func colf3 = std::bind(&checkCondition, std::placeholders::_1, columns3, player);
// diagonals
bool diag1 = true, diag2 = true;
std::array<int, 3> diagonal1 = { 0, 4, 8 };
std::array<int, 3> diagonal2 = { 2, 4, 6 };
func diagf1 = std::bind(&checkCondition, std::placeholders::_1, diagonal1, player);
func diagf2 = std::bind(&checkCondition, std::placeholders::_1, diagonal2, player);
std::vector<pairCondition> v =
{
{ 0, grid[0] }, { 1, grid[1] }, { 2, grid[2] },
{ 3, grid[3] }, { 4, grid[4] }, { 5, grid[5] },
{ 6, grid[6] }, { 7, grid[7] }, { 8, grid[8] }
};
for (const auto& i : v)
{
// rows conditions
row1 &= rowf1(i);
row2 &= rowf2(i);
row3 &= rowf3(i);
// columns conditions
col1 &= colf1(i);
col2 &= colf2(i);
col3 &= colf3(i);
// diagonals conditions
diag1 &= diagf1(i);
diag2 &= diagf2(i);
};
return (row1 || row2 || row3 ||
col1 || col2 || col3 ||
diag1 || diag2);
}
void TicTacToe::draw() const
{
//Creating a onscreen grid
std::cout << ' ';
for (std::size_t i = 1; i <= mDim; ++i)
std::cout << " " << i;
int j = 0;
char A = 'A';
column<mDim>::argument_type input;
for (auto& i : grid)
{
if (column<mDim>(0)(input = j++))
std::cout << "\n " << A++;
std::cout << ' ' << i << ' ';
}
std::cout << "\n\n";
}
void TicTacToe::turn(char player)
{
char row = 0;
char column = 0;
std::size_t position = 0;
bool applied = false;
std::cout << "\n" << player << ": Please play. \n";
while (!applied)
{
std::cout << "Row(1,2,3,...): ";
std::cin >> row;
std::cout << player << ": Column(A,B,C,...): ";
std::cin >> column;
position = mDim * (std::toupper(column) - 'A') + (row - '1');
if (position < grid.size())
{
applied = fill(player, position);
if (!applied)
std::cout << "Already Used. Try Again. \n";
}
else
{
std::cout << "Invalid position. Try again.\n";
}
}
std::cout << "\n\n";
}
class Game
{
public:
Game() = default;
void run();
private:
TicTacToe ttt;
std::array<char, 2> players{ { 'X', 'O' } };
int player = 1;
void resultScreen();
std::function<void()> display = std::bind(&TicTacToe::draw, &ttt);
std::function<void(char)> turn = std::bind(&TicTacToe::turn, &ttt, std::placeholders::_1);
std::function<bool(char)> win = std::bind(&TicTacToe::check, &ttt, std::placeholders::_1);
std::function<bool()> full = std::bind(&TicTacToe::isFull, &ttt);
};
void Game::run()
{
while (!win(players[player]) && !full() )
{
player ^= 1;
display();
turn(players[player]);
}
resultScreen();
}
void Game::resultScreen()
{
display();
if (win)
{
std::cout << "\n" << players[player] << " is the Winner!\n";
}
else
{
std::cout << "\nTie game!\n";
}
}
int main()
{
Game game;
game.run();
}