From 93a48a6baebf79b90efbb057269e759697882e48 Mon Sep 17 00:00:00 2001 From: Arefe Date: Mon, 13 Apr 2026 13:52:54 +0330 Subject: [PATCH] inital commit on develop branch --- othello.cpp | 672 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 672 insertions(+) create mode 100644 othello.cpp diff --git a/othello.cpp b/othello.cpp new file mode 100644 index 0000000..23f0cdc --- /dev/null +++ b/othello.cpp @@ -0,0 +1,672 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +// کامنت ها برای اینه که تو صورت سوال گفته شده کد باید کامنت گذاری شده باشه +struct game +{ + string name1; + string name2; + int countB; + int countW; + string result; + string date; + string time; +}; +string board[8][8]; +int moves[64][2]; +int countPass = 0; +int countW; +int countB; +//تابعی که بررسی میکنه یک جهت دارای حداقل یک مهره حریف و بعد از اون حداقل یک خودیه یا نه +bool checkDirection(string board[8][8], int row, int col, string color,int drow,int dcol) +{ + string opponent; + if (color == "●") + { + opponent = "○"; + } + else + { + opponent = "●"; + } + int currentRow = row + drow; + int currentCol = col + dcol; + if (currentRow < 0 || currentRow >= 8 || currentCol < 0 || currentCol >= 8) + { + return false; + } + //چک اینکه مهره کناری حتما حریف باشه + if (board[currentRow][currentCol] != opponent) + { + return false; + } + while (currentRow >= 0 && currentRow < 8 && currentCol >= 0 && currentCol < 8) + { + if (board[currentRow][currentCol] == opponent) + { + currentRow += drow; + currentCol += dcol; + } + else if (board[currentRow][currentCol] == color) + { + return true; + } + else + { + break; + } + } + return false; +} +//بررسی میکنه حداقل یه جهت با شرایطی که تو کامنت بالایی گفتم وجود داره یا نه +bool existsValidDirection(string board[8][8], int row, int col, string color) +{ + int d[] = {-1, 0, 1}; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + if (i == 1 && j == 1) + { + continue; + } + if (checkDirection(board, row, col, color, d[i], d[j]) == true) + { + return true; + } + } + } + return false; +} +//بررسی میکنه شرایط برای گذاشتن مهره توی اون خونه انتخاب شده هست یا نه +bool isValidMove(string board[8][8], int row, int col, string color) +{ + if (board[row][col] == " " && existsValidDirection(board, row, col, color) == true) + { + return true; + } + return false; +} +//تمام خونه هایی که میشه توش با توجه به شرایط مهره گذاشت رو پیدا و شمارش میکنه +void findValidMoves(string board[8][8], string color, int moves[][2], int& count) +{ + //int& برای اینه که وقتی تابع رو صدا زدیم و کارش رو انجام داد مقدار count بیرون از تابع تغییر نکنه + //راحتتر این بود که int عادی بذاریم و بعد count رو برگردونیم ولی خب. + count = 0; + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + if (isValidMove(board, i, j, color) == true ) + { + moves[count][0] = i; + moves[count][1] = j; + count++; + } + } + } +} +//به طور رندوم یکی از خونه های معتبر رو انتخاب میکنه +int chooseMove(int count) +{ + int randomNum = rand() % count; + return randomNum; +} +//توی خونه انتخاب شده مهره میذاره و مهره های محاصره شده حریف رو تبدیل میکنه به مهره های خودی +void applyMove(string board[8][8], int row, int col, string color) +{ + int d[] = {-1, 0, 1}; + string opponent = (color == "●") ? "○" : "●"; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + if (i == 1 && j == 1) + { + continue; + } + if (checkDirection(board, row, col, color, d[i], d[j])) + { + int currentRow = row + d[i]; + int currentCol = col + d[j]; + + while (board[currentRow][currentCol] == opponent) + { + board[currentRow][currentCol] = color; + currentRow += d[i]; + currentCol += d[j]; + } + } + } + } + board[row][col] = color; +} +//صفحه بازی رو توی یه جدول چاپ میکنه +void printBoard(string board[8][8], int cursorRow, int cursorCol) +{ + + cout << "┌"; + for (int col = 0; col < 8; col++) + { + cout << "─"; + if (col != 7) + { + cout << "┬"; + } + else + { + cout << "┐"; + } + } + cout << endl; + for (int row = 0; row < 8; row++) + { + cout << "│"; + for (int col = 0; col < 8; col++) + { + //به خاطر شرط پایین وقتی به کرسرها -1 بدیم صفحه بدون کرسر چاپ میشه + if (row == cursorRow && col == cursorCol) + { + if (board[row][col] == " ") + { + cout << "*"; + } + else + { + cout << board[row][col]; + } + } + else + { + cout << board[row][col]; + } + cout << "│"; + } + cout << endl; + if (row != 7) + { + cout << "├"; + for (int col = 0; col < 8; col++) + { + cout << "─"; + if (col != 7) + { + cout << "┼"; + } + else + { + cout << "┤"; + } + } + cout << endl; + } + } + cout << "└"; + for (int col = 0; col < 8; col++) + { + cout << "─"; + if (col != 7) + { + cout << "┴"; + } + else + { + cout << "┘"; + } + } + cout << endl; +} +//با استفاده از تابع های تعریف و پیاده سازی شده، تمام کارایی که ربات باید توی نوبتش انجام بده رو انجام میده +bool robotTurn(string board[8][8], string color) +{ + int count = 0; + findValidMoves(board, color, moves, count); + system("cls"); + if (count == 0) + { + //برای اینکه صفحه بدون کرسر چاپ بشه + printBoard(board, -1, -1); + return false; + } + else + { + int chosenMove = chooseMove(count); + int row = moves[chosenMove][0]; + int col = moves[chosenMove][1]; + applyMove(board, row, col, color); + printBoard(board, -1, -1); + return true; + } +} +//کلیدهایی که کاربر برای حرکت روی صفحه بازی میزنه رو شناسایی میکنه و کرسر رو نشون میده. +//با استفاده از تابع های تعریف و پیاده سازی شده، وقتی بازیکن خونه موردنظرش رو انتخاب کرد +//اگر خونه دارای شرایط لازم وجود نداشت پیام پاس میده یا اگر خونه نامعتبر بود اخطار میده +//اگر معتبر بود مهره های محاصره شده حریف رو تبدیل میکنه به مهره های خودی و مهره رو توی خونه انتخاب شده میذاره +bool humanTurn(string board[8][8],string name, string turn) +{ + int count = 0; + bool isSelected = false; + int row; + int col; + int cursorRow = 0; + int cursorCol = 0; + findValidMoves(board, turn, moves, count); + if (count == 0) + { + system("cls"); + cout << "Pass" << endl << "Press any key to continue." << endl; + getch(); + return false; + } + while (!isSelected) + { + system("cls"); + printBoard(board, cursorRow, cursorCol); + cout << "Turn: " << turn << endl; + char key = getch(); + if (key == 'w') + { + cursorRow--; + if (cursorRow < 0) cursorRow = 0; + } + else if (key == 'a') + { + cursorCol--; + if (cursorCol < 0) cursorCol = 0; + } + else if (key == 's') + { + cursorRow++; + if (cursorRow > 7) cursorRow = 7; + } + else if (key == 'd') + { + cursorCol++; + if (cursorCol > 7) cursorCol = 7; + } + if (key == '\r') + { + if (isValidMove(board, cursorRow, cursorCol, turn)) + { + row = cursorRow; + col = cursorCol; + isSelected = true; + } + else + { + cout << "Invalid move!" << endl << "Press any key to choose again." << endl; + getch(); + } + } + } + applyMove(board, row, col, turn); + return true; +} + + + +int main() +{ + srand(static_cast(time(nullptr))); + bool running = true; + string color = "●"; + int choice = 0; + int capacity = 10; + int size; + game* history; + history = new game[capacity]; + ifstream file("history.txt"); + size = 0; + game temp; + //تا وقتی به ته فایل نرسیده + while (!file.eof()) + { + file >> temp.name1 >> temp.name2 >> temp.countB >> temp.countW >> temp.result >> temp.date >> temp.time; + if (file.eof()) break; + if (size == capacity) + { + int newCapacity = capacity * 2; + game* newHistory = new game[newCapacity]; + for (int i = 0; i < size; i++) + { + newHistory[i] = history[i]; + } + delete[] history; + history = newHistory; + capacity = newCapacity; + } + history[size] = temp; // بازی رو که خوند میریزه تو آرایه + size++; + } + file.close(); + while (running) + { + cout << "1) New Game" << endl; + cout << "2) Help" << endl; + cout << "3) Game History" << endl; + cout << "4) Exit" << endl; + cin >> choice; + //بازی جدید + if (choice == 1) + { + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + board[i][j]= " "; + } + } + board[3][3] = "○"; + board[4][4] = "○"; + board[3][4] = "●"; + board[4][3] = "●"; + int players; + cout << "1) Single Player" << endl; + cout << "2) Two Player" << endl; + cin >> players; + cin.ignore(); + if (players == 1) + { + //بازی یک نفره. حریف بازیکن ربات است + string name; + cout << "Enter your name:"; + cin >> name; + cout << "The game starts with " << name << " (●)." << endl; + cout << "Use keys w/a/s/d to move and Enter to apply." << endl; + cout << "Press any key to start." << endl; + getch(); + string playerColor = "●"; + string robotColor = "○"; + string turn = playerColor; + countPass = 0; + int cursorRow = 0; + int cursorCol = 0; + + while (countPass < 2) + { + //نوبت بازیکن + if (turn == "●") + { + + + if (humanTurn(board, name, playerColor) == true) + { + countPass = 0; + } + else + { + countPass++; + } + turn = robotColor; + } + //نوبت ربات + else if (turn == "○") + { + if (robotTurn(board, robotColor) == true) + { + countPass = 0; + } + else + { + countPass++; + } + turn = playerColor; + } + } + //شمارش مهره ها + countW = 0; + countB = 0; + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + if (board[i][j] == "○") + { + countW++; + } + else if (board[i][j] == "●") + { + countB++; + } + } + } + system("cls"); + cout << "Game over." << endl; + cout << "Black: " << countB << endl; + cout << "White: " << countW << endl; + if (countW > countB) + { + cout << "White won!" << endl; + } + else if (countB > countW) + { + cout << "Black won!" << endl; + } + if (countW == countB) + { + cout << "The game is drawn" << endl; + } + //فرایند ذخیره تاریخچه + game currentGame; + currentGame.name1 = name; + currentGame.name2 = "computer"; + currentGame.countB = countB; + currentGame.countW = countW; + if (countB > countW) + currentGame.result = "Black"; + else if (countW > countB) + currentGame.result = "White"; + else + currentGame.result = "Draw"; + //کمک از ai: + time_t now = time(nullptr); + tm* localtm = localtime(&now); + string currentDate = to_string(localtm->tm_mday) + "/" + + to_string(localtm->tm_mon + 1) + "/" + + to_string(localtm->tm_year + 1900); + string currentTime = to_string(localtm->tm_hour) + ":" + + to_string(localtm->tm_min) + ":" + + to_string(localtm->tm_sec); + currentGame.date = currentDate; + currentGame.time = currentTime; + if (size == capacity) + { + int newCapacity = capacity * 2; + game* newHistory = new game[newCapacity]; + for (int i = 0; i < size; i++) + { + newHistory[i] = history[i]; + } + delete[] history; + history = newHistory; + capacity = newCapacity; + } + history[size] = currentGame; + size++; + } + else if (players == 2) + { + //بازی دونفره + string name1, name2; + cout << "Enter players' names:"; + cin.ignore(); + getline(cin, name1); + getline(cin, name2); + cout << "The game starts with Black (●)." << endl; + cout << "Use keys w/a/s/d to move and Enter to apply." << endl; + cout << "Press any key to start."; + getch(); + string playerColorb = "●"; + string playerColorw = "○"; + string turn = playerColorb; + int countb = 0; + int countw = 0; + int cursorRow = 0; + int cursorCol = 0; + countPass = 0; + bool gameOver = false; + while (countPass < 2) + { + + if (turn == "●") + { + if (humanTurn(board, name1, playerColorb) == true) + { + countPass = 0; + } + else + { + countPass++; + } + turn = playerColorw; + } + + else if (turn == "○") + { + if (humanTurn(board, name2, playerColorw) == true) + { + countPass = 0; + } + else + { + countPass++; + } + turn = playerColorb; + } + } + countW = 0; + countB = 0; + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + if (board[i][j] == "○") + { + countW++; + } + else if (board[i][j] == "●") + { + countB++; + } + } + } + gameOver = true; + system("cls"); + cout << "Game over." << endl; + cout << "Black: " << countB << endl; + cout << "White: " << countW << endl; + if (countW > countB) + { + cout << "White won!" << endl; + } + else if (countB > countW) + { + cout << "Black won!" << endl; + } + if (countW == countB) + { + cout << "The game is drawn" << endl; + } + game currentGame; + currentGame.name1 = name1; + currentGame.name2 = name2; + currentGame.countB = countB; + currentGame.countW = countW; + if (countB > countW) + currentGame.result = "Black"; + else if (countW > countB) + currentGame.result = "White"; + else + currentGame.result = "Draw"; + //کمک از ai: + time_t now = time(nullptr); + tm* localtm = localtime(&now); + string currentDate = to_string(localtm->tm_mday) + "/" + + to_string(localtm->tm_mon + 1) + "/" + + to_string(localtm->tm_year + 1900); + string currentTime = to_string(localtm->tm_hour) + ":" + + to_string(localtm->tm_min) + ":" + + to_string(localtm->tm_sec); + currentGame.date = currentDate; + currentGame.time = currentTime; + if (size == capacity) + { + int newCapacity = capacity * 2; + game* newHistory = new game[newCapacity]; + for (int i = 0; i < size; i++) + { + newHistory[i] = history[i]; + } + delete[] history; + history = newHistory; + capacity = newCapacity; + } + history[size] = currentGame; + size++; + } + } + //راهنما + else if (choice == 2) + { + cout << "keys: " << endl; + cout << "w: up" << endl << "a: left" << endl << "s: down" << endl << "d: right" << endl << "Enter: to place" << endl; + cout << "In single-player mode, after you move, the robot plays immediately, then it's your turn again. Don't get confused!" << endl; + cout << "Othello is a two-player board game played on an 8*8 grid. " << + "Players take turns placing discs on the board, with one side black and the other white." << + " A move is valid if it traps one or more of the opponent's discs between the new disc and another disc of the same color, " << + " causing the trapped discs to flip." << + " The game ends when no valid moves remain, " << + "and the player with the most discs on the board wins." << endl; + } + //نمایش تاریخچه + else if (choice == 3) + { + if (size == 0) + { + cout << "No game history found." << endl; + } + else + { + for (int i = 0; i < size; i++) + { + cout << i + 1 << "." << history[i].name1 << " vs " << history[i].name2 + << " / score: " << history[i].countB << "-" << history[i].countW + << " / winner: " << history[i].result << " / date: " << history[i].date << " / time: " << history[i].time<< endl; + } + } + } + //خروج از بازی + else if (choice == 4) + { + running = false; + break; + } + else + { + cout << "invalid choice." << endl; + } + } + //نوشتن تاریخچه در فایل + ofstream outfile("history.txt"); + if (!outfile.is_open()) + { + cout << "Cannot open history.txt for writing!" << endl; + } + for (int i = 0; i < size; i++) + { + outfile << history[i].name1 << " " << history[i].name2 << " " + << history[i].countB << " " << history[i].countW << " " + << history[i].result << " " << history[i].date << " " + << history[i].time << endl; + } + outfile.close(); + delete[] history; + return 0; +} +