// ==============================================Importing Libraries============================== #include #include #include // cout #include // inputs #include // random #include // time #include // file #include // delay using namespace std; //==============================================Structures & Global variables======================================= int board_size = 8; // --- ANSI Color Codes --- const string RESET = "\033[0m"; const string BLACK_TXT = "\033[30m"; // black text const string RED_TXT = "\033[31m"; // red text const string GREEN_TXT = "\033[32m"; // green text const string YELLOW_TXT = "\033[33m"; // yellow text const string WHITE_TXT = "\033[97m"; // white text const string BG_GREEN = "\033[42m"; // green background const string BG_YELLOW = "\033[43m"; // yellow background const string BG_DEFAULT = "\033[49m"; // default background const string CYAN_TXT = "\033[36m"; const string MAGENTA_TXT = "\033[35m"; const string BOLD = "\033[1m"; const string MARGIN = " "; struct ColorChanger{ int startI, startJ; int endI, endJ; int directionX, directionY; }; struct Game{ int **board; int turn; string player1name; string player2name; bool isSinglePlayerMode; int black_count; int white_count; ColorChanger color_changer; }; struct CellState{ const int empty = 0, black = 1, white = 2; }; Game game; CellState cell_state; int curserI, curserJ; /* history file format: player1name,player1discs,player2name,player2discs,winner,gamedate */ // crowling through a cell's nieghbors int IndX[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; int IndY[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; //=============================================Function prototypes=============================== void ShowBoard(int i, int j); void ShowMenu(); void GameMode(); // single player mode or two player mode void PlayGame(); void PlaceCell(int i, int j); void SwitchTurn(); bool CheckValidTurn(int turn); bool CheckValidMove(int i, int j, bool change_color); void ChangeColor(); void ShowHistory(); void BotMove(); void SelectBoardSize(); void AllocateBoard(); void DeallocateBoard(); //=============================================Main Function===================================== int main(){ system("chcp 65001"); // for showing the unicode characters in terminal srand(static_cast(time(nullptr))); // preparing board for the start of the game game.board = nullptr; ShowMenu(); return 0; } //============================================Functions========================================= // THE GAME void PlayGame(){ // recieving names and declaring turns system("cls"); cout << "\n\n"; cout << MARGIN << BOLD << CYAN_TXT << u8"╔══════════════════════════════════╗" << RESET << endl; cout << MARGIN << BOLD << CYAN_TXT << u8"║ GAME SETUP ║" << RESET << endl; cout << MARGIN << BOLD << CYAN_TXT << u8"╚══════════════════════════════════╝" << RESET << endl; cout << endl; if(!game.isSinglePlayerMode){ // two player mode cout << MARGIN << YELLOW_TXT << "Player 1 Name (Black): " << CYAN_TXT; cin >> game.player1name; cout << RESET << "\n"; cout << MARGIN << YELLOW_TXT << "Player 2 Name (White): " << CYAN_TXT; cin >> game.player2name; cout << RESET; } else{ cout << MARGIN << YELLOW_TXT << "Enter Your Name: " << CYAN_TXT; cin >> game.player1name; cout << RESET; game.player2name = "Bot"; } game.turn = 1; // moving through the board bool running = true; int opposite_turn; while(running){ ShowBoard(curserI, curserJ); if(game.isSinglePlayerMode && game.turn == 2){ Sleep(500); // a delay for palyer to see bot's move BotMove(); SwitchTurn(); } else { char pressed_key = getch(); switch(pressed_key) { case 'w': case 'W': if(curserI > 0) curserI--; break; case 's': case 'S': if(curserI < board_size - 1) curserI++; break; case 'd': case 'D': if(curserJ < board_size - 1) curserJ++; break; case 'a': case 'A': if(curserJ > 0) curserJ--; break; case '\r': // Enter if(CheckValidMove(curserI, curserJ, true)){ PlaceCell(curserI, curserJ); SwitchTurn(); } else{ cout << "\a"; } break; case ' ': // emergency exit running = false; // DeallocateBoard(); break; } } if(!running) break; // end of game or switch turn because of no valid move opposite_turn = (game.turn == 1 ? 2 : 1); bool currentHasMove = CheckValidTurn(game.turn); bool opponentHasMove = CheckValidTurn(opposite_turn); if(!currentHasMove && opponentHasMove){ cout << "\nNo Valid Moves for " << (game.turn == 1 ? game.player1name : game.player2name) << "! Passing turn..."; getch(); SwitchTurn(); } else if(!currentHasMove && !opponentHasMove){ // end of game ShowBoard(-1, -1); time_t now = time(0); string winnerName = "Tie"; if(game.black_count > game.white_count) winnerName = game.player1name; else if(game.black_count < game.white_count) winnerName = game.player2name; cout << "\n========================\n"; if (winnerName == "Tie") cout << " TIE GAME!"; else cout << " WINNER: " << winnerName; cout << "\n========================\n"; ofstream history("history.txt", ios::app); if(history.is_open()){ // AI generated char* dt = ctime(&now); // converting datetime to string // deleting \n from the end of the time string string dateStr = string(dt); if (!dateStr.empty() && dateStr[dateStr.length()-1] == '\n') { dateStr.erase(dateStr.length()-1); } //... history << game.player1name << "," << game.black_count << "," << game.player2name << "," << game.white_count << "," << winnerName << "," << dateStr << endl; history.close(); cout << "Game saved to history." << endl; } else { cout << "Error saving history!" << endl; } cout << "Press any key to exit..."; getch(); running = false; // DeallocateBoard(); // preparing board for the start of the game for(int i = 0; i < board_size; i++){ for(int j = 0; j < board_size; j++){ game.board[i][j] = cell_state.empty; } } game.board[3][3] = cell_state.white; game.board[4][4] = cell_state.white; game.board[3][4] = cell_state.black; game.board[4][3] = cell_state.black; } } DeallocateBoard(); ShowMenu(); } // selecting size of the board (6 or 8 or 10) void SelectBoardSize(){ while(true){ system("cls"); cout << "\n\n"; cout << MARGIN << BOLD << CYAN_TXT << u8"╔══════════════════════════════════╗" << RESET <= 0 && x < board_size && y >= 0 && y < board_size && game.board[x][y] == opponent){ // going on in the same direction while(true){ x += dx; y += dy; if(x < 0 || x >= board_size || y < 0 || y >= board_size) { break; } if(game.board[x][y] == cell_state.empty){ break; } if(game.board[x][y] == myColor){ game.color_changer.startI = curserI; game.color_changer.startJ = curserJ; game.color_changer.endI = x; game.color_changer.endJ = y; game.color_changer.directionX = dx; game.color_changer.directionY = dy; if(change_color) ChangeColor(); // if we are checking the cell for a player move then we change the colors int the same process validMove = true; } } } } return validMove; } // checking if the player can play a move bool CheckValidTurn(int turn){ for(int i = 0; i < board_size; i++){ for(int j = 0; j < board_size; j++){ if(game.board[i][j] == cell_state.empty && CheckValidMove(i, j, false)) return true; } } return false; } // changin cells after a valid move void ChangeColor(){ int opposite_color = (game.turn == 1 ? cell_state.black : cell_state.white); int x = game.color_changer.startI; int y = game.color_changer.startJ; while(true){ x += game.color_changer.directionX; y += game.color_changer.directionY; if(game.board[x][y] != opposite_color){ game.board[x][y] = opposite_color; } else{ break; } } } // showing history (crawling through history.txt file which is considered a database for this game) void ShowHistory(){ system("cls"); cout << "\n\n"; cout << MARGIN << BOLD << CYAN_TXT << u8"╔══════════════════════════════════════════════════════════════╗" << RESET << endl; cout << MARGIN << BOLD << CYAN_TXT << u8"║ GAME HISTORY ARCHIVE ║" << RESET << endl; cout << MARGIN << BOLD << CYAN_TXT << u8"╚══════════════════════════════════════════════════════════════╝" << RESET << endl; cout << endl; ifstream history("history.txt"); if(!history.is_open()){ cout << MARGIN << RED_TXT << "No history found or could not open file." << RESET << endl; cout << "\n" << MARGIN << "Press any key to return..."; getch(); ShowMenu(); return; } cout << MARGIN << YELLOW_TXT << left << setw(12) << "Player 1" << setw(8) << "Score" << setw(12) << "Player 2" << setw(8) << "Score" << setw(12) << "Winner" << setw(20) << "Date" << RESET << endl; cout << MARGIN << CYAN_TXT << u8"──────────────────────────────────────────────────────────────────────" << RESET << endl; string line; string player1, player2, winner, date; string player1discs, player2discs; int splitter[5]; while(getline(history, line)){ for(int i = 0; i < 5; i++){ if(i == 0) splitter[i] = line.find(","); else splitter[i] = line.find(",", splitter[i - 1] + 1); } player1 = line.substr(0, splitter[0]); player1discs = line.substr(splitter[0] + 1, splitter[1] - splitter[0] - 1); player2 = line.substr(splitter[1] + 1, splitter[2] - splitter[1] - 1); player2discs = line.substr(splitter[2] + 1, splitter[3] - splitter[2] - 1); winner = line.substr(splitter[3] + 1, splitter[4] - splitter[3] - 1); date = line.substr(splitter[4] + 1); cout << MARGIN << left << CYAN_TXT << setw(12) << player1 << BOLD << WHITE_TXT << setw(8) << player1discs << RESET << CYAN_TXT << setw(12) << player2 << BOLD << WHITE_TXT << setw(8) << player2discs << RESET << GREEN_TXT << setw(12) << winner << RESET << setw(20) << date << endl; } history.close(); cout << "\n\n" << MARGIN << BG_GREEN << BLACK_TXT << " Press any key to return... " << RESET; getch(); ShowMenu(); } void BotMove(){ if(CheckValidTurn(game.turn)){ // allocating an array for bot's available moves int **availabe_moves = new int*[board_size*board_size]; for(int i = 0; i < (board_size*board_size); i++){ availabe_moves[i] = new int[2]; } // adding available moves to the array int counter = 0; for(int i = 0; i < board_size; i++){ for(int j = 0; j < board_size; j++){ if(CheckValidMove(i, j, false)){ availabe_moves[counter][0] = i; availabe_moves[counter][1] = j; counter++; } } } if (counter > 0) { int randomIndex = rand() % counter; curserI = availabe_moves[randomIndex][0]; curserJ = availabe_moves[randomIndex][1]; CheckValidMove(curserI, curserJ, true); PlaceCell(curserI, curserJ); } // deallocating availabe moves array for(int i = 0; i < board_size*board_size; i++){ delete[] availabe_moves[i]; } delete[] availabe_moves; } else{ SwitchTurn(); } }