#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
const string PLAYER1 = "X";
const string PLAYER2 = "O";
const string EMPTY = " ";
const string FILENAME = "tic-tac-toe-results.txt";
// function prototypes
void print_board(const vector<vector<string>>& board);
bool is_valid_move(const vector<vector<string>>& board, int row, int col);
bool is_game_over(const vector<vector<string>>& board);
string get_winner(const vector<vector<string>>& board);
void save_result(const string& result);
int main() {
int size = 0;
cout << "Enter size of the field (minimum 3, maximum 10): ";
cin >> size;
// validate user input
if (size < 3 || size > 10) {
cout << "Invalid size. Please enter a number between 3 and 10." << endl;
return 1;
}
// initialize board
vector<vector<string>> board(size, vector<string>(size, EMPTY));
// game loop
string current_player = PLAYER1;
bool exit_game = false;
while (!is_game_over(board) && !exit_game) {
// print board
print_board(board);
// get player's move
int row = -1, col = -1;
while (!is_valid_move(board, row, col)) {
cout << current_player << "'s turn. Enter row and column to place your symbol (e.g. 1 2), or enter 'exit' to end the game: ";
string input;
getline(cin, input);
if (input == "exit") {
exit_game = true;
break;
}
else {
row = input[0] - '1';
col = input[2] - '1';
}
}
// make move
if (!exit_game) {
board[row][col] = current_player;
// switch to next player
current_player = (current_player == PLAYER1) ? PLAYER2 : PLAYER1;
}
}
// print final board and result
print_board(board);
if (exit_game) {
cout << "Game ended by user." << endl;
save_result("Game ended by user.");
}
else {
string winner = get_winner(board);
if (winner == "") {
cout << "Game ended in a tie." << endl;
save_result("Tie");
}
else {
cout << "Congratulations! " << winner << " wins!" << endl;
save_result(winner + " wins");
}
}
return 0;
}
void print_board(const vector<vector<string>>& board) {
int size = board.size();
cout << " ";
for (int i = 1; i <= size; i++) {
cout << i << " ";
}
cout << endl;
for (int row = 0; row < size; row++) {
cout << row + 1 << " ";
for (int col = 0; col < size; col++) {
cout << board[row][col] << " ";
}
cout << endl;
}
}
bool is_valid_move(const vector<vector<string>>& board, int row, int col) {
int size = board.size();
if (row < 0 || row >= size || col < 0 || col >= size) {
return false;
}
if (board[row][col] != EMPTY) {
return false;
}
return true;
}
bool is_game_over(const vector<vector<string>>& board) {
// check for rows
for (const auto& row : board) {
string first_cell = row[0];
if (first_cell == EMPTY) {
continue;
}
bool all_equal = true;
for (const auto& cell : row) {
if (cell != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return true;
}
}
// check for columns
int size = board.size();
for (int col = 0; col < size; col++) {
string first_cell = board[0][col];
if (first_cell == EMPTY) {
continue;
}
bool all_equal = true;
for (int row = 1; row < size; row++) {
if (board[row][col] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return true;
}
}
// check for diagonal 1
string first_cell = board[0][0];
if (first_cell != EMPTY) {
bool all_equal = true;
for (int i = 1; i < size; i++) {
if (board[i][i] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return true;
}
}
// check for diagonal 2
first_cell = board[0][size - 1];
if (first_cell != EMPTY) {
bool all_equal = true;
for (int i = 1; i < size; i++) {
if (board[i][size - 1 - i] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return true;
}
}
// check for tie
for (const auto& row : board) {
for (const auto& cell : row) {
if (cell == EMPTY) {
return false;
}
}
}
return true;
}
string get_winner(const vector<vector<string>>& board) { // check for rows for (const auto& row : board) { string first_cell = row[0]; if (first_cell == EMPTY) { continue; } bool all_equal = true; for (const auto& cell : row) { if (cell != first_cell) { all_equal = false; break; } } if (all_equal) { return first_cell; } }
// check for columns
int size = board.size();
for (int col = 0; col < size; col++) {
string first_cell = board[0][col];
if (first_cell == EMPTY) {
continue;
}
bool all_equal = true;
for (int row = 1; row < size; row++) {
if (board[row][col] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return first_cell;
}
}
// check for diagonal 1
string first_cell = board[0][0];
if (first_cell != EMPTY) {
bool all_equal = true;
for (int i = 1; i < size; i++) {
if (board[i][i] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return first_cell;
}
}
// check for diagonal 2
first_cell = board[0][size - 1];
if (first_cell != EMPTY) {
bool all_equal = true;
for (int i = 1; i < size; i++) {
if (board[i][size - 1 - i] != first_cell) {
all_equal = false;
break;
}
}
if (all_equal) {
return first_cell;
}
}
return "";
}
void save_result(const string& result) { ofstream fout(FILENAME, ios::app); if (fout.is_open()) { fout << result << endl; fout.close(); } }