#include #include #include #include #include #include #include using namespace std; struct Player { string name; char color; // 'B' یا 'W' bool isBot; }; const int MAXN = 10; int N = 8; char board[MAXN][MAXN]; //صفحه بازی int dr[8] = {-1,-1,-1,0,0,1,1,1}; int dc[8] = {-1,0,1,-1,1,-1,0,1}; bool inBounds(int r, int c) { return r >= 0 && c >= 0 && r < N && c < N; } void initBoard() { for (int r = 0; r < N; ++r) for (int c = 0; c < N; ++c) board[r][c] = ' '; int mid = N / 2; board[mid - 1][mid - 1] = 'W'; board[mid][mid] = 'W'; board[mid - 1][mid] = 'B'; board[mid][mid - 1] = 'B'; } bool hasFlipsInDir(int r, int c, char me, int dirIndex, int& endR, int& endC) { char opp; if (me == 'B') { opp = 'W'; } else { opp = 'B'; } int nr = r + dr[dirIndex]; int nc = c + dc[dirIndex]; if (!inBounds(nr, nc)) { return false; } if (board[nr][nc] != opp) { return false; } while (inBounds(nr, nc)) { if (board[nr][nc] == opp) { nr = nr + dr[dirIndex]; nc = nc + dc[dirIndex]; } else if (board[nr][nc] == me) { endR = nr; endC = nc; return true; } else { return false; } } return false; } bool isValidMove(int r, int c, char me) { if (!inBounds(r, c) || board[r][c] != ' ') return false; for (int d = 0; d < 8; ++d) { int endR, endC; if (hasFlipsInDir(r, c, me, d, endR, endC)) return true; } return false; } void applyMove(int r, int c, char me) { board[r][c] = me; for (int d = 0; d < 8; ++d) { int endR, endC; if (hasFlipsInDir(r, c, me, d, endR, endC)) { int nr = r + dr[d]; int nc = c + dc[d]; while (!(nr == endR && nc == endC)) { board[nr][nc] = me; nr += dr[d]; nc += dc[d]; } } } } void saveGame(const string& playerBlack, const string& playerWhite, char nextTurn) { ofstream file("save.txt"); if (!file) { cout << "Error saving game!\n"; return; } file << N << "\n" << playerBlack << "\n" << playerWhite << "\n" << nextTurn << "\n"; for (int i = 0; i < N; ++i) { for (int j = 0; j < N; ++j) file << board[i][j]; file << "\n"; } file.close(); } void saveToHistory(const string& pBlack, const string& pWhite, int blackScore, int whiteScore, const string& winner) { ofstream file("history.txt", ios::app); if (!file) { cout << "Error saving to history!\n"; return; } time_t now = time(0); char* dt = ctime(&now); dt[strlen(dt)-1] = '\0'; file << "Date: " << dt << "\n"; file << "Players: " << pBlack << " (Black) vs " << pWhite << " (White)\n"; file << "Score: " << blackScore << " - " << whiteScore << "\n"; file << "Winner: " << winner << "\n"; file << "-----------------------------------\n"; file.close(); } void showGameHistory() { ifstream file("history.txt"); if (!file) { cout << "No game history yet.\n"; return; } cout << "\n=== GAME HISTORY ===\n\n"; string line; while (getline(file, line)) { cout << line << "\n"; } cout << "\n"; file.close(); } bool hasAnyMove(char me) { for (int r = 0; r < N; ++r) for (int c = 0; c < N; ++c) if (isValidMove(r, c, me)) return true; return false; } int countPieces(char piece) { int cnt = 0; for (int r = 0; r < N; ++r) for (int c = 0; c < N; ++c) if (board[r][c] == piece) cnt++; return cnt; } void setColor(int color) { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color); } void printBoardWithHints(char turn, int cursorR = -1, int cursorC = -1) { int blackCount = countPieces('B'); int whiteCount = countPieces('W'); setColor(14); // رنگ زرد روشن برای امتیاز cout << "\nScore -> Black: " << blackCount << " | White: " << whiteCount << "\n"; setColor(10); cout << "\n "; for (int c = 0; c < N; ++c) cout << c + 1 << " "; cout << "\n"; cout << " ┌"; for (int c = 0; c < N; ++c) cout << "───" << (c < N - 1 ? "┬" : ""); cout << "┐\n"; for (int r = 0; r < N; ++r) { cout << r + 1 << " │"; for (int c = 0; c < N; ++c) { if (r == cursorR && c == cursorC) setColor(12); // کرسر قرمز else if (board[r][c] == ' ' && isValidMove(r, c, turn)) setColor(6); else if (board[r][c] == 'B') setColor(8); else if (board[r][c] == 'W') setColor(15); else setColor(10); if (r == cursorR && c == cursorC && board[r][c] == ' ') cout << "[ ]"; else if (board[r][c] == 'B') cout << " ● "; else if (board[r][c] == 'W') cout << " ○ "; else if (board[r][c] == ' ' && isValidMove(r, c, turn)) cout << " * "; else cout << " "; setColor(10); cout << "│"; } cout << "\n"; if (r < N - 1) { cout << " ├"; for (int c = 0; c < N; ++c) cout << "───" << (c < N - 1 ? "┼" : ""); cout << "┤\n"; } } cout << " └"; for (int c = 0; c < N; ++c) cout << "───" << (c < N - 1 ? "┴" : ""); cout << "┘\n"; setColor(7); } void helpScreen() { setColor(6); cout << "\n--- Help ---\n"; setColor(13); cout << "Othello (Reversi) rules summary:\n"; cout << "- Board size can be 6x6, 8x8, or 10x10. Initial center has 2 Black and 2 White discs in a cross.\n"; cout << "- A valid move places a disc on an empty cell that brackets opponent discs\n"; cout << " in at least one direction (horizontal, vertical, or diagonal) between\n"; cout << " the new disc and an existing disc of the mover.\n"; cout << "- All bracketed opponent discs in those directions flip to the mover's color.\n"; cout << "- If a player has no valid moves, they pass. If both cannot move, game ends.\n"; cout << "- Winner is the player with more discs. Symbols: B=Black, W=White, .=empty, *=hint , ●=Black , ○=White\n"; cout << "- During the game, enter 0 0 to save and exit.\n"; setColor(6); cout << "------------\n\n"; setColor(7); } void botMove(char me) { for (int r = 0; r < N; ++r) { for (int c = 0; c < N; ++c) { if (isValidMove(r, c, me)) { applyMove(r, c, me); cout << "Bot placed at: row " << (r + 1) << ", col " << (c + 1) << "\n"; return; } } } } bool loadGame(string& playerBlack, string& playerWhite, char& turn) { ifstream file("save.txt"); if (!file) { cout << "No saved game found.\n"; return false; } int size; file >> size; N = size; file >> ws; getline(file, playerBlack); getline(file, playerWhite); file >> turn; file.ignore(); for (int r = 0; r < N; ++r) for (int c = 0; c < N; ++c) board[r][c] = ' '; for (int r = 0; r < N; ++r) { string line; getline(file, line); for (int c = 0; c < N && c < (int)line.size(); ++c) { board[r][c] = line[c]; } } file.close(); cout << "Game loaded successfully!\n"; return true; } void playGame(bool singlePlayer, bool loadExisting = false) { string playerBlack, playerWhite; char turn = 'B'; int cursorR = 0, cursorC = 0; // موقعیت کرسر if (loadExisting) { if (!loadGame(playerBlack, playerWhite, turn)) { cout << "Starting new game instead.\n"; loadExisting = false; } } if (!loadExisting) { cout << "Choose board size (6 / 8 / 10): "; cin >> N; while (N != 6 && N != 8 && N != 10) { cout << "Invalid size! Choose 6, 8 or 10: "; cin >> N; } cout << "Enter Black player name: "; getline(cin >> ws, playerBlack); if (singlePlayer) playerWhite = "Bot"; else { cout << "Enter White player name: "; getline(cin >> ws, playerWhite); } initBoard(); } while (true) { system("cls"); printBoardWithHints(turn, cursorR, cursorC); cout << "Turn: " << (turn == 'B' ? playerBlack : playerWhite) << " (" << turn << ")" << " | Score: " << countPieces('B') << " - " << countPieces('W') << "\n"; if (!hasAnyMove(turn)) { cout << "No valid moves for " << (turn == 'B' ? "Black" : "White") << ". PASS.\n"; char nextTurn = (turn == 'B') ? 'W' : 'B'; if (!hasAnyMove(nextTurn)) { cout << "No valid moves for both players. Game over.\n"; break; } turn = nextTurn; _getch(); continue; } if (singlePlayer && turn == 'W') { botMove(turn); turn = 'B'; _getch(); continue; } cout << "Use W/A/S/D to move, Enter to place, 0 to save.\n"; char key = _getch(); if (key == 'w' || key == 'W') cursorR = max(0, cursorR - 1); else if (key == 's' || key == 'S') cursorR = min(N - 1, cursorR + 1); else if (key == 'a' || key == 'A') cursorC = max(0, cursorC - 1); else if (key == 'd' || key == 'D') cursorC = min(N - 1, cursorC + 1); else if (key == '\r') // Enter { if (isValidMove(cursorR, cursorC, turn)) { applyMove(cursorR, cursorC, turn); turn = (turn == 'B') ? 'W' : 'B'; } else { cout << "Invalid move!\n"; _getch(); } } else if (key == '0') { saveGame(playerBlack, playerWhite, turn); cout << "Game saved! Returning to main menu.\n"; _getch(); return; } } system("cls"); printBoardWithHints('B'); int black = countPieces('B'); int white = countPieces('W'); cout << "Final count -> Black: " << black << " | White: " << white << "\n"; string winner; if (black > white) winner = playerBlack + " (Black)"; else if (white > black) winner = playerWhite + " (White)"; else winner = "Draw"; cout << "Winner: " << winner << "\n"; saveToHistory(playerBlack, playerWhite, black, white, winner); _getch(); } int main() { SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); int choice; do { setColor(2); cout << "\n-------------------"; setColor(14); cout << "\n--- Main Menu ---\n"; setColor(11); cout << " 1. Two-player game\n"; cout << " 2. Single-player (vs bot)\n"; cout << " 3. Help\n"; cout << " 4. Game History\n"; cout << " 5. Load Game\n"; cout << " 0. Exit\n"; setColor(15); cout << "Select: "; setColor(2); cout << "\n-------------------\n"; setColor(7); cin >> choice; if (choice == 1) { playGame(false); } else if (choice == 2) { playGame(true); } else if (choice == 3) { helpScreen(); }else if (choice == 4) { showGameHistory(); }else if (choice == 5) { playGame(false,true); } else if (choice == 0) { cout << "Goodbye!\n"; } else { cout << "Invalid option.\n"; } } while (choice != 0); return 0; }