Files

830 lines
24 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <iostream>
#include <string>
#include <conio.h>
#include <windows.h>
#include <ctime>
#include <iomanip>
#include <sstream>
#include <fstream>
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
<< "Im 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 << "Heres a friendly tip for you:" << endl
<< "⚠️ Dont 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();
}