#include #include #include #include #include #include #include #include using namespace std; const int KEY_UP = 72; const int KEY_DOWN = 80; const int KEY_ENTER = 13; const int N = 8; const int dx[8] = { -1,-1,-1,0,0,1,1,1 }; const int dy[8] = { -1,0,1,-1,1,-1,0,1 }; const string EMPTY = " "; const string BLACK = u8"\u25CB"; const string WHITE = u8"\u25CF"; int selX = 3, selY = 3; string board[N][N]; bool blackTurn = true; string name[2]; string box1 = u8"\u250C"; // گوشه بالا چپ string box2 = u8"\u2510"; // گوشه بالا راست string box3 = u8"\u2514"; // گوشه پایین چپ string box4 = u8"\u2518"; // گوشه پایین راست string box5 = u8"\u2500"; // خط افقی string box6 = u8"\u2502"; // خط عمودی string box7 = u8"\u252C"; // ┬ string box8 = u8"\u2534"; // ┴ string box9 = u8"\u251C"; // ├ string box10 = u8"\u2524"; // ┤ string box11 = u8"\u253C"; // ┼ const string RESET = "\033[0m"; const string GREENDARK = "\033[42m"; const string BROWN = "\033[38;5;94m"; const string YELLOW = "\033[93m"; const string BLUE = "\033[1;36m"; const string RED = "\033[1;31m"; const string GREEN = "\033[92m"; struct { string name1; string name2; string winner; string time; int count1; int count2; } gamehistory; // menu int ShowMenu(); int ShowMenuTadadPlayer(); int Endmenu(); void Help(); void ShowGameHistory(); // game void DrawBoard(); bool Inside(int y, int x); bool CanFlip(int y, int x, int dirY, int dirX, const string me, const string opp); bool ValidMove(int y, int x, const string me, const string opp); void ApplyMove(int y, int x, const string me, const string opp); void FirstBoard(); bool HaveValidMove(string me, string opp); // game history int CountPlayer(string Color); string GetCurrentDateTime(); void SaveGameHistory(); // bot int GoodPoints(int x, int y); int CountFlips(int x, int y, const string me, const string opp); int FindBestScore(int x, int y, const string me, const string opp); void DEMONKING(); bool BadPoints(int x, int y); int main () { startProgram: int CountMenu, CountMenuTadadPlayer, countplayer1, countplayer2,end; bool running = true, End = false; string Winner, Time; SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); SetConsoleOutputCP(65001); CountMenu = ShowMenu(); if (CountMenu == 5) { exit(0); } else if (CountMenu == 4) { cout << BLUE << "Do good and throw it into the Tigris; God will return it to you in the desert." << RESET; cout << endl << endl << RED << "6219_8618_7708_8780" << RESET; cout << endl << endl << BLUE << "Don't be a fucking Jew!!" << endl << "(This is a joke.)"<< RESET; char key = _getch(); if (key == 27) goto startProgram; } else if (CountMenu == 2) { Help(); char key = _getch(); if (key == 27) goto startProgram; } else if (CountMenu == 3) { ShowGameHistory(); char key = _getch(); if (key == 27) goto startProgram; } else if ( CountMenu == 0) { CountMenuTadadPlayer = ShowMenuTadadPlayer(); if( CountMenuTadadPlayer == 1) { cout << RED << "Player1 Name:" << RESET; cin >> name[0]; cout << RED << "Player2 Name:" << RESET; cin >> name[1]; startProgram1: selX = 3; selY = 3; blackTurn = true; End = false; FirstBoard(); while (true) { DrawBoard(); char key = _getch(); if (key == 27) break; if ((key == 'w' || key == 'W') && selY > 0) selY--; if ((key == 's' || key == 'S') && selY < 7) selY++; if ((key == 'a' || key == 'A') && selX > 0) selX--; if ((key == 'd' || key == 'D') && selX < 7) selX++; if (key == KEY_ENTER) { const string me = blackTurn ? BLACK : WHITE; const string opp = blackTurn ? WHITE : BLACK; if (ValidMove(selY, selX, me, opp)) { ApplyMove(selY, selX, me, opp); bool curHas = HaveValidMove(me, opp); blackTurn = !blackTurn; const string nextme = blackTurn ? BLACK : WHITE; const string nextopp = blackTurn ? WHITE : BLACK; bool nextHas = HaveValidMove(nextme, nextopp); if (!nextHas) { cout << RED << "PASS" << RESET; Sleep(3000); blackTurn = !blackTurn; } if (!curHas && !nextHas) { DrawBoard(); Sleep(3000); End = true; } if( End == true) { countplayer1 = CountPlayer(BLACK); countplayer2 = CountPlayer(WHITE); if( countplayer1 == countplayer2) { Winner = "Draw"; } else if (countplayer1 > countplayer2) { Winner = name[0]; } else { Winner = name[1]; } Time = GetCurrentDateTime(); gamehistory.name1 = name[0]; gamehistory.name2 = name[1]; gamehistory.count1 = countplayer1; gamehistory.count2 = countplayer2; gamehistory.winner = Winner; gamehistory.time = Time; SaveGameHistory(); end = Endmenu(); if( end == 0) goto startProgram1; if( end == 1) goto startProgram; if( end == 2) return 0; } } } } } else { cout << RED << "Player Name:" << RESET; cin >> name[0]; name[1] = "Demon King "; startProgram2: selX = 3; selY = 3; blackTurn = true; End = false; FirstBoard(); while (true) { DrawBoard(); char key = _getch(); if (key == 27) break; if ((key == 'w' || key == 'W') && selY > 0) selY--; if ((key == 's' || key == 'S') && selY < 7) selY++; if ((key == 'a' || key == 'A') && selX > 0) selX--; if ((key == 'd' || key == 'D') && selX < 7) selX++; if (key == KEY_ENTER) { const string me = blackTurn ? BLACK : WHITE; const string opp = blackTurn ? WHITE : BLACK; if (ValidMove(selY, selX, me, opp)) { ApplyMove(selY, selX, me, opp); DrawBoard(); blackTurn = !blackTurn; if (!blackTurn) { if (HaveValidMove(WHITE, BLACK)) { Sleep(1000); DEMONKING(); } else { cout << RED << "PASS" << RESET; Sleep(2000); } blackTurn = true; } const string nextme = blackTurn ? BLACK : WHITE; const string nextopp = blackTurn ? WHITE : BLACK; bool curHas = HaveValidMove(me, opp); bool nextHas = HaveValidMove(nextme, nextopp); if (!nextHas) { cout << RED << "PASS" << RESET; Sleep(3000); blackTurn = !blackTurn; } if (!curHas && !nextHas) { DrawBoard(); Sleep(3000); End = true; } if( End == true) { countplayer1 = CountPlayer(BLACK); countplayer2 = CountPlayer(WHITE); if( countplayer1 == countplayer2) { Winner = "Draw"; } else if (countplayer1 > countplayer2) { Winner = name[0]; } else { Winner = name[1]; } Time = GetCurrentDateTime(); gamehistory.name1 = name[0]; gamehistory.name2 = name[1]; gamehistory.count1 = countplayer1; gamehistory.count2 = countplayer2; gamehistory.winner = Winner; gamehistory.time = Time; SaveGameHistory(); end = Endmenu(); if( end == 0) goto startProgram2; if( end == 1) goto startProgram; if( end == 2) exit(0); } } } } } } } int ShowMenu() // این تابع منوی اولیه بازی رو نشون می ده { string menuItems[6] = {"New Game","Load Game","Help","Game History","Donate","Exit"}; int itemCount = 6; int selectedItem = 0; bool running = true; while (running) { system("cls"); cout << BLUE << box1; for (int i = 0; i < 25; i++) cout << box5; cout << box2 << endl; for (int i = 0; i < itemCount; i++) { cout << box6; if ( i == selectedItem) { cout << RESET << RED << " > " << menuItems[i]; for(int s = 0; s < 22 - menuItems[i].length();s++) cout << RESET << " "; cout << BLUE << box6 << endl; } else { cout << RESET << " " << RED << menuItems[i] << RESET; for (int s = 0; s < 22 - menuItems[i].length(); s++) cout << " "; cout << BLUE << box6 << endl; } } cout << box3; for (int i = 0; i < 25; i++) cout << box5; cout << box4 << RESET << endl; int key = _getch(); if (key == 224) { key = _getch(); if ( key == KEY_UP) { selectedItem = (selectedItem - 1 + itemCount) % itemCount; } else if ( key == KEY_DOWN) { selectedItem = (selectedItem + 1) % itemCount; } } else if (key == KEY_ENTER) { system("cls"); return selectedItem; } } return 0; } int ShowMenuTadadPlayer() // این تابع منوی تعداد پلیر نشون می ده { string menuItems[5] = {"Singleplayer","Multiplayer"}; int itemCount = 2; int selectedItem = 0; bool running = true; while (running) { system("cls"); for (int i = 0; i < itemCount; i++) { if ( i == selectedItem) { cout << RED <<" > " << menuItems[i] << RESET << endl; } else { cout << " " << RED << menuItems[i] << RESET << endl; } } int key = _getch(); if (key == 224) { key = _getch(); if ( key == KEY_UP) { selectedItem = (selectedItem - 1 + itemCount) % itemCount; } else if ( key == KEY_DOWN) { selectedItem = (selectedItem + 1) % itemCount; } } else if (key == KEY_ENTER) { system("cls"); return selectedItem; } } return 0; } void FirstBoard() // تابع 4 مهره اول بازی رسم می کنه { for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) board[i][j] = EMPTY; board[3][3] = WHITE; board[3][4] = BLACK; board[4][3] = BLACK; board[4][4] = WHITE; } void DrawBoard() // این تابع برد بازی نشون می ده و هعی اپدیت میشه { system("cls"); cout << YELLOW << "Turn: " << (blackTurn ? name[0] : name[1]) << RESET << "\n\n"; cout << BROWN << box1; for (int i = 0; i < 7; i++) cout << box5 << box5 << box5 << box7; cout << box5 << box5 << box5 << box2 << RESET << endl; for (int i = 0; i < 8; i++) { cout << BROWN << box6 << RESET; for (int j = 0; j < 8; j++) { string cell = board[i][j]; if (i == selY && j == selX) { if (cell != " ") cout << GREENDARK << "[" << cell << "]" << RESET; else cout << GREENDARK << "[ ]" << RESET; } else { if (cell != " ") cout << GREENDARK << " " << cell << " " << RESET; else cout << GREENDARK << " " << RESET; } cout << BROWN << box6 << RESET; } cout << endl; if (i != 7) { cout << BROWN << box9; for (int k = 0; k < 7; k++) cout << box5 << box5 << box5 << box11; cout << box5 << box5 << box5 << box10 << RESET << endl; } } cout << BROWN << box3; for (int i = 0; i < 7; i++) cout << box5 << box5 << box5 << box8; cout << box5 << box5 << box5 << box4 << RESET << endl; } bool Inside(int y, int x) // این تابع بررسی می کنه که حرکت کاربر از برد خارج نشه { return x >= 0 && x < N && y >= 0 && y < N; } bool CanFlip(int y, int x, int dirY, int dirX, const string me, const string opp) // این تابع نشون می ده ایا مهره گذاشته شده مهره ای رو بر می گردونه یا خیر { y += dirY; x += dirX; if (!Inside(y, x) || board[y][x] != opp) return false; while (Inside(y, x)) { if (board[y][x] == EMPTY) return false; if (board[y][x] == me) return true; y += dirY; x += dirX; } return false; } bool ValidMove(int y, int x, const string me, const string opp) // این تابع نشون می ده که ایا مهره گذاشته شده حرکتش درست هست یاه خیر { if (board[y][x] != EMPTY) return false; for (int i = 0; i < 8; i++) if (CanFlip(y, x, dy[i], dx[i], me, opp)) return true; return false; } void ApplyMove(int y, int x, const string me, const string opp) // این تابع تغییرات صفحه رو ایجاد می کنه { board[y][x] = me; for (int i = 0; i < 8; i++) { if (CanFlip(y, x, dy[i], dx[i], me, opp)) { int ny = y + dy[i], nx = x + dx[i]; while (board[ny][nx] == opp) { board[ny][nx] = me; ny += dy[i]; nx += dx[i]; } } } } bool HaveValidMove(string me, string opp) // این تابع چک می کنه که ایا بازیکن هنوز حرکتی داره یا خیر { for (int k = 0; k < N; k++) { for (int h = 0; h < N; h++) { if (board[k][h] == EMPTY) { for (int i = 0; i < 8; i++) { if (CanFlip(k, h, dy[i], dx[i], me, opp)) { return true; } } } } } return false; } string GetCurrentDateTime()// این تابع تاریخ و زمان از سیستم می گیره و خروجی می ده { time_t now = time(nullptr); tm localTime; localtime_s(&localTime, &now); stringstream ss; ss << put_time(&localTime, "%Y/%m/%d %H:%M:%S"); return ss.str(); } void SaveGameHistory() // این تابع اطلاعات بازی رو خروجی می ده { const string filename = "Game History.txt"; ifstream inFile(filename); string oldContent; string line; if (inFile) { while (getline(inFile, line)) { oldContent += line + "\n"; } inFile.close(); } ofstream outFile(filename); outFile << "\033[38;5;94m" << "| " << RESET << "Player1: " << BLUE << gamehistory.name1 << RESET << "\033[38;5;94m" << " | " << RESET << "Player2: " << BLUE << gamehistory.name2 << RESET << "\033[38;5;94m" << " | " << RESET << "Winner: " << (gamehistory.winner == "Draw" ? "\033[96mDraw" : GREEN + gamehistory.winner) << RESET << u8"\U0001F3C6" << "\033[38;5;94m" << " | " << RESET << "\033[90m" << "Black: " << gamehistory.count1 << u8"\U0001F468\U0001F3FF" << " | White: " << gamehistory.count2 << u8"\U0001F468\U0001F3FB" << " | Time: " << gamehistory.time << u8"\U0001F552" << RESET << endl; outFile << oldContent; outFile.close(); } int Endmenu() // این تابع منوی پایانی بازی نشون می ده { string menuItems[3] = {"Try Again","Main Menu","Exit"}; int itemCount = 3; int selectedItem = 0; bool running = true; while (running) { system("cls"); cout << BLUE << box1; for (int i = 0; i < 25; i++) cout << box5; cout << box2 << endl; cout << box6 << RESET << RED << " Winner:" << RESET << GREEN << gamehistory.winner << RESET; for(int s = 0; s < 15 - gamehistory.winner.length();s++) cout << " "; cout << BLUE << box6 << endl; for (int i = 0; i < itemCount ; i++) { cout << box6; if ( i == selectedItem ) { cout << RED << " > " << menuItems[i] << RESET; for(int s = 0; s < 22 - menuItems[i].length();s++) cout << " "; cout << BLUE << box6 << endl; } else { cout << RESET << " " << RED << menuItems[i] << RESET; for (int s = 0; s < 22 - menuItems[i].length(); s++) cout << " "; cout << BLUE << box6 << endl; } } cout << box3; for (int i = 0; i < 25; i++) cout << box5; cout << box4 << RESET << endl; int key = _getch(); if (key == 224) { key = _getch(); if ( key == KEY_UP) { selectedItem = (selectedItem - 1 + itemCount) % itemCount; } else if ( key == KEY_DOWN) { selectedItem = (selectedItem + 1) % itemCount; } } else if (key == KEY_ENTER) { system("cls"); return selectedItem; } } return 0; } int CountPlayer(string Color) //این تابع تعداد مهره های هر بازیکن می شمارد { int count =0; for ( int i = 0; i < N; i++) { for(int j = 0; j < N; j++) { if(board[i][j] == Color) count++; } } return count; } int CountFlips(int x, int y, const string me, const string opp) // این تابع بررسی می کنه که هر حرکت چند تا رو می تونه بر گردونه { if (board[y][x] != EMPTY) return 0; int total = 0; for (int d = 0; d < 8; d++) { int nx = x + dx[d]; int ny = y + dy[d]; int cnt = 0; while (Inside(ny, nx) && board[ny][nx] == opp) { cnt++; nx += dx[d]; ny += dy[d]; } if (cnt > 0 && Inside(ny, nx) && board[ny][nx] == me) total += cnt; } return total; } int GoodPoints(int x, int y) // یکی سری نقاط توی بازی اهمیت بیشتری داره برای حرکت ربات اگر ربات اون حرکت انجام بده بهش امتیاز می ده { if ((x == 0 || x == 7) && (y == 0 || y == 7)) return 100; if (x == 0 || x == 7 || y == 0 || y == 7) return 20; return 5; } bool BadPoints(int x, int y) // این تابع مثل تابع قبل فقط نقاط منفی مشخص می کنه { return (x == 1 && y == 1) || (x == 6 && y == 1) || (x == 1 && y == 6) || (x == 6 && y == 6); } int FindBestScore(int x, int y,const string me, const string opp) // این تابع میاد با استفاده از 3 تابع قبل نقاطی که بهش داده میشه رو امتیازشون بررسی می کنه { if (!ValidMove(y, x, me, opp)) return -100; int flips = CountFlips(x, y, me, opp); if (flips == 0) return -100; int score = 0; score += flips * 10; score += GoodPoints(x, y); if (BadPoints(x, y)) score -= 50; return score; } void DEMONKING() // این تابع مال ربات که با تابع قبل میاد بهترین حرکت ممکن انتخاب می کنه { const string me = WHITE; const string opp = BLACK; int bestscore = -100; int bestx = -1, besty = -1; for (int y = 0; y < N; y++) { for (int x = 0; x < N; x++) { int score = FindBestScore(x, y, me, opp); if (score > bestscore) { bestscore = score; bestx = x; besty = y; } } } if (bestx != -1 && ValidMove(besty, bestx, me, opp)) { ApplyMove(besty, bestx, me, opp); } } void Help() // این تابع بخش کمک بازی رو نشون می ده { cout << "Hello! How are you? 👋" << endl << "I’m here to help you enjoy the game more easily and have a better experience." << endl << "First of all, the game has two modes:" << endl << "🎮 Single Player (Play against the AI)" << endl << "👥 Multiplayer (Two players)" << endl << "Here’s a friendly tip for you:" << endl << "⚠️ Don’t underestimate the AI — sometimes it can be really scary!" << endl << endl << "In both modes, you can move around the board using the W, A, S, D keys." << endl << "To place your piece and confirm your move, press ENTER." << endl << "If your move is not placed, it means that move is not valid according to the game rules." << endl << endl << "You can press ESC at any time to exit the game." << endl << "To save your game, press CTRL + SAVE." << endl << endl << "✨ I wish you an amazing and unforgettable Othello experience." << endl << "Good luck, and have fun! 🎯🖤⚪" << endl; } void ShowGameHistory() // این تابع گیم هیستوری نشون می ده { ifstream file("Game History.txt"); if (!file) { cout << "First start a Game" << endl; } string line; while (getline(file, line)) { cout << line << endl; } file.close(); }