Files
Othello/othello.cpp
T

673 lines
22 KiB
C++

#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <conio.h>
#include <fstream>
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<unsigned int>(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;
}