commit f1421805e2d9d02cfbd66cb807bc4a51d09592a0 Author: Amir mohammad Date: Thu Apr 16 00:07:38 2026 +0330 Initial commit on develop branch diff --git a/tamrin2.cpp b/tamrin2.cpp new file mode 100644 index 0000000..ed403b0 --- /dev/null +++ b/tamrin2.cpp @@ -0,0 +1,829 @@ +#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(); +} +