Board.h
#pragma once
#include <vector>
#include <iostream>
namespace Logs {
inline void announce_winner(char winner) {
std::cout << "Game Over! " << winner << " wins the game\n";
}
inline void draw() {
std::cout << "Game Over! .. Draw\n";
}
inline void already_chosen() {
std::cout << "The cell is already chosen, please try again.\n";
}
inline void prompt_to_play() {
std::cout
<< "Please enter a number between 1 and 9 inclusive that is not chosen\n";
}
inline void invalid_cell() {
std::cout << "Invalid choice. ";
prompt_to_play();
}
inline void current_turn(char player_symbol) {
std::cout << "It's " << player_symbol << " turn\n";
}
inline void another_game() {
std::cout << "Do you want to play another game? Y - N\n";
}
};
class Board {
private:
size_t width, height;
// number of Xs minus number of Os, if +3 X wins, -3 O wins
std::vector<short> difference_row;
std::vector<short> difference_col;
std::vector<short> difference_diagonal;
unsigned moves;
std::vector<std::vector<char>> board;
char player_symbol;
public:
Board();
bool is_full();
void make_move();
void draw();
void reset();
size_t get_width();
size_t get_height();
bool is_game_over();
void increase_moves();
bool is_valid_move(int row, int col);
void update_cell(int row, int col);
void toggle_player();
bool any_winner();
char get_symbol() {
return player_symbol;
}
};
Board.cpp
#include "Board.h"
Board::Board() { Board::reset(); }
void Board::make_move() {
draw();
Logs::current_turn(player_symbol);
Logs::prompt_to_play();
int choice;
std::cin >> choice;
int row_index = (choice - 1) / height;
int col_index = (choice - 1) % width;
if (is_valid_move(row_index, col_index)) {
update_cell(row_index, col_index);
increase_moves();
if (is_game_over()) {
draw();
if (any_winner()) {
Logs::announce_winner(player_symbol);
} else {
Logs::draw();
}
Logs::another_game();
std::string res;
std::cin >> res;
if (tolower(res[0]) == 'y') {
reset();
make_move();
} else {
exit(0);
}
}
} else {
Logs::invalid_cell();
}
make_move();
}
bool Board::is_full() { return moves == width * height; }
void Board::draw() {
for (const auto &row : board) {
for (const auto &cell : row) {
std::cout << cell << " ";
}
std::cout << std::endl;
}
}
void Board::reset() {
width = 3;
height = 3;
board.assign(height, std::vector<char>(width));
char current = '1';
for (auto &row : board) {
for (auto &cell : row) {
cell = current++;
}
}
difference_row = std::vector<short>(3);
difference_col = std::vector<short>(3);
difference_diagonal = std::vector<short>(2);
moves = 0;
player_symbol = 'X';
}
size_t Board::get_height() { return height; }
size_t Board::get_width() { return width; }
bool Board::is_game_over() { return Board::any_winner() || Board::is_full(); }
void Board::increase_moves() {
moves++;
// don't toggle player unless game is over, this will help us to announce
// winner
if (!is_game_over()) {
toggle_player();
}
}
bool Board::is_valid_move(int row, int col) {
return !(row < 0 || row >= height || col < 0 || col >= width ||
board[row][col] == 'X' || board[row][col] == 'O');
}
void Board::update_cell(int row, int col) {
board[row][col] = player_symbol;
int add = (player_symbol == 'X' ? +1 : -1);
difference_row[row] += add;
difference_col[col] += add;
if (row == col) {
difference_diagonal[0] += add;
}
if (row + col == height - 1) {
difference_diagonal[1] += add;
}
}
void Board::toggle_player() {
player_symbol = (player_symbol == 'X' ? 'O' : 'X');
}
bool Board::any_winner() {
for (int i = 0; i < 3; i++) {
if (i < 2 && abs(difference_diagonal[i]) == 3) {
return true;
}
if (abs(difference_row[i]) == 3 || abs(difference_col[i] == 3)) {
return true;
}
}
return false;
}
TicTacToe.h
#pragma once
#include "Board.h"
class TicTacToe {
private:
Board board;
public:
TicTacToe();
void start();
};
TicTacToe.cpp
#include "TicTacToe.h"
TicTacToe::TicTacToe() {
board = Board();
}
void TicTacToe::start() {
while (true) {
board.make_move();
if (board.any_winner()) {
Logs::announce_winner(board.get_symbol());
}
else if (board.is_full()) {
Logs::draw();
}
}
}
main.cpp
#include "TicTacToe.h"
int main() {
TicTacToe tic;
tic.start();
}
I've tried my best to code a multiplayer tic tac toe console program. Here's what I've written. Please, I need a code review, if there's any modifications, advices, etc. to make the code better.