I have found Tic-Tac-Toe source code: Tic Tac Toe in C++
I have rewritten the source code in C++11 as shown below. How can I minimize hardcoding in the game logic?
#include <iostream>
#include <cctype>
#include <algorithm>
#include <functional>
#include <array>
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);
private:
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;
};
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 '-';
});
}
bool TicTacToe::check(char player) const
{
column<mDim>::argument_type input;
// check for row or column wins
bool row1 = true, row2 = true, row3 = true,
col1 = true, col2 = true, col3 = true,
diag1 = true, diag2 = true;
int j = 0;
// columns
std::for_each(grid.begin(), grid.end(),
[&](char i)
{
int x = j++;
if (column<mDim>(0)(input = x))
col1 &= i == player;
if (column<mDim>(1)(input = x))
col2 &= i == player;
if (column<mDim>(2)( input = x))
col3 &= i == player;
});
// diagonals
j = 0;
for (const auto& i : grid)
{
int x = j++;
if (x == 0 || x == 4 || x == 8)
diag1 &= i == player;
if (x == 2 || x == 4 || x == 6)
diag2 &= i == player;
}
if (col1 || col2 || col3 || diag1 || diag2)
return true;
// rows
return std::search_n(grid.begin(), grid.end(), 3, player) != grid.end();
}
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)
{
int x = j++;
if (column<mDim>(0)(input = x ))
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();
void run();
private:
TicTacToe ttt;
std::array<char, 2> players{ { 'X', 'O' } };
int player = 0;
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);
};
Game::Game()
:ttt()
{
}
void Game::run()
{
while (!win(players[player]) && !full())
{
player ^= 1;
display();
turn(players[player]);
}
display();
if (win)
{
std::cout << "\n" << players[player] << " is the Winner!\n";
}
else
{
std::cout << "\nTie game!\n";
}
}
int main()
{
Game game;
game.run();
}