Files
2026-04-14 09:40:49 +00:00

493 lines
13 KiB
C++

#include <iostream>
#include <string>
#include <fstream>
#include <cstring>
#include <ctime>
#include <windows.h>
#include <conio.h>
using namespace std;
struct Player
{
string name;
char color; // 'B' یا 'W'
bool isBot;
};
const int MAXN = 10;
int N = 8;
char board[MAXN][MAXN];
//صفحه بازی
int dr[8] =
{-1,-1,-1,0,0,1,1,1};
int dc[8] =
{-1,0,1,-1,1,-1,0,1};
bool inBounds(int r, int c)
{
return r >= 0 && c >= 0 && r < N && c < N;
}
void initBoard()
{
for (int r = 0; r < N; ++r)
for (int c = 0; c < N; ++c)
board[r][c] = ' ';
int mid = N / 2;
board[mid - 1][mid - 1] = 'W';
board[mid][mid] = 'W';
board[mid - 1][mid] = 'B';
board[mid][mid - 1] = 'B';
}
bool hasFlipsInDir(int r, int c, char me, int dirIndex, int& endR, int& endC)
{
char opp;
if (me == 'B')
{
opp = 'W';
} else
{
opp = 'B';
}
int nr = r + dr[dirIndex];
int nc = c + dc[dirIndex];
if (!inBounds(nr, nc))
{
return false;
}
if (board[nr][nc] != opp)
{
return false;
}
while (inBounds(nr, nc))
{
if (board[nr][nc] == opp)
{
nr = nr + dr[dirIndex];
nc = nc + dc[dirIndex];
}
else if (board[nr][nc] == me)
{
endR = nr;
endC = nc;
return true;
}
else
{
return false;
}
}
return false;
}
bool isValidMove(int r, int c, char me)
{
if (!inBounds(r, c) || board[r][c] != ' ')
return false;
for (int d = 0; d < 8; ++d)
{
int endR, endC;
if (hasFlipsInDir(r, c, me, d, endR, endC)) return true;
}
return false;
}
void applyMove(int r, int c, char me)
{
board[r][c] = me;
for (int d = 0; d < 8; ++d)
{
int endR, endC;
if (hasFlipsInDir(r, c, me, d, endR, endC))
{
int nr = r + dr[d];
int nc = c + dc[d];
while (!(nr == endR && nc == endC))
{
board[nr][nc] = me;
nr += dr[d];
nc += dc[d];
}
}
}
}
void saveGame(const string& playerBlack, const string& playerWhite, char nextTurn)
{
ofstream file("save.txt");
if (!file)
{
cout << "Error saving game!\n";
return;
}
file << N << "\n" << playerBlack << "\n" << playerWhite << "\n" << nextTurn << "\n";
for (int i = 0; i < N; ++i)
{
for (int j = 0; j < N; ++j) file << board[i][j];
file << "\n";
}
file.close();
}
void saveToHistory(const string& pBlack, const string& pWhite, int blackScore, int whiteScore, const string& winner)
{
ofstream file("history.txt", ios::app);
if (!file)
{
cout << "Error saving to history!\n";
return;
}
time_t now = time(0);
char* dt = ctime(&now);
dt[strlen(dt)-1] = '\0';
file << "Date: " << dt << "\n";
file << "Players: " << pBlack << " (Black) vs " << pWhite << " (White)\n";
file << "Score: " << blackScore << " - " << whiteScore << "\n";
file << "Winner: " << winner << "\n";
file << "-----------------------------------\n";
file.close();
}
void showGameHistory()
{
ifstream file("history.txt");
if (!file) {
cout << "No game history yet.\n";
return;
}
cout << "\n=== GAME HISTORY ===\n\n";
string line;
while (getline(file, line)) {
cout << line << "\n";
}
cout << "\n";
file.close();
}
bool hasAnyMove(char me)
{
for (int r = 0; r < N; ++r)
for (int c = 0; c < N; ++c)
if (isValidMove(r, c, me)) return true;
return false;
}
int countPieces(char piece)
{
int cnt = 0;
for (int r = 0; r < N; ++r)
for (int c = 0; c < N; ++c)
if (board[r][c] == piece) cnt++;
return cnt;
}
void setColor(int color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
void printBoardWithHints(char turn, int cursorR = -1, int cursorC = -1)
{
int blackCount = countPieces('B');
int whiteCount = countPieces('W');
setColor(14); // رنگ زرد روشن برای امتیاز
cout << "\nScore -> Black: " << blackCount << " | White: " << whiteCount << "\n";
setColor(10);
cout << "\n ";
for (int c = 0; c < N; ++c)
cout << c + 1 << " ";
cout << "\n";
cout << " ┌";
for (int c = 0; c < N; ++c)
cout << "───" << (c < N - 1 ? "┬" : "");
cout << "┐\n";
for (int r = 0; r < N; ++r)
{
cout << r + 1 << " │";
for (int c = 0; c < N; ++c)
{
if (r == cursorR && c == cursorC) setColor(12); // کرسر قرمز
else if (board[r][c] == ' ' && isValidMove(r, c, turn)) setColor(6);
else if (board[r][c] == 'B') setColor(8);
else if (board[r][c] == 'W') setColor(15);
else setColor(10);
if (r == cursorR && c == cursorC && board[r][c] == ' ') cout << "[ ]";
else if (board[r][c] == 'B') cout << " ● ";
else if (board[r][c] == 'W') cout << " ○ ";
else if (board[r][c] == ' ' && isValidMove(r, c, turn)) cout << " * ";
else cout << " ";
setColor(10);
cout << "│";
}
cout << "\n";
if (r < N - 1)
{
cout << " ├";
for (int c = 0; c < N; ++c)
cout << "───" << (c < N - 1 ? "┼" : "");
cout << "┤\n";
}
}
cout << " └";
for (int c = 0; c < N; ++c)
cout << "───" << (c < N - 1 ? "┴" : "");
cout << "┘\n";
setColor(7);
}
void helpScreen()
{
setColor(6);
cout << "\n--- Help ---\n";
setColor(13);
cout << "Othello (Reversi) rules summary:\n";
cout << "- Board size can be 6x6, 8x8, or 10x10. Initial center has 2 Black and 2 White discs in a cross.\n";
cout << "- A valid move places a disc on an empty cell that brackets opponent discs\n";
cout << " in at least one direction (horizontal, vertical, or diagonal) between\n";
cout << " the new disc and an existing disc of the mover.\n";
cout << "- All bracketed opponent discs in those directions flip to the mover's color.\n";
cout << "- If a player has no valid moves, they pass. If both cannot move, game ends.\n";
cout << "- Winner is the player with more discs. Symbols: B=Black, W=White, .=empty, *=hint , ●=Black , ○=White\n";
cout << "- During the game, enter 0 0 to save and exit.\n";
setColor(6);
cout << "------------\n\n";
setColor(7);
}
void botMove(char me)
{
for (int r = 0; r < N; ++r)
{
for (int c = 0; c < N; ++c)
{
if (isValidMove(r, c, me))
{
applyMove(r, c, me);
cout << "Bot placed at: row " << (r + 1) << ", col " << (c + 1) << "\n";
return;
}
}
}
}
bool loadGame(string& playerBlack, string& playerWhite, char& turn)
{
ifstream file("save.txt");
if (!file) {
cout << "No saved game found.\n";
return false;
}
int size;
file >> size;
N = size;
file >> ws;
getline(file, playerBlack);
getline(file, playerWhite);
file >> turn;
file.ignore();
for (int r = 0; r < N; ++r)
for (int c = 0; c < N; ++c)
board[r][c] = ' ';
for (int r = 0; r < N; ++r)
{
string line;
getline(file, line);
for (int c = 0; c < N && c < (int)line.size(); ++c)
{
board[r][c] = line[c];
}
}
file.close();
cout << "Game loaded successfully!\n";
return true;
}
void playGame(bool singlePlayer, bool loadExisting = false)
{
string playerBlack, playerWhite;
char turn = 'B';
int cursorR = 0, cursorC = 0; // موقعیت کرسر
if (loadExisting)
{
if (!loadGame(playerBlack, playerWhite, turn))
{
cout << "Starting new game instead.\n";
loadExisting = false;
}
}
if (!loadExisting)
{
cout << "Choose board size (6 / 8 / 10): ";
cin >> N;
while (N != 6 && N != 8 && N != 10)
{
cout << "Invalid size! Choose 6, 8 or 10: ";
cin >> N;
}
cout << "Enter Black player name: ";
getline(cin >> ws, playerBlack);
if (singlePlayer)
playerWhite = "Bot";
else
{
cout << "Enter White player name: ";
getline(cin >> ws, playerWhite);
}
initBoard();
}
while (true)
{
system("cls");
printBoardWithHints(turn, cursorR, cursorC);
cout << "Turn: " << (turn == 'B' ? playerBlack : playerWhite)
<< " (" << turn << ")"
<< " | Score: " << countPieces('B') << " - " << countPieces('W') << "\n";
if (!hasAnyMove(turn))
{
cout << "No valid moves for " << (turn == 'B' ? "Black" : "White") << ". PASS.\n";
char nextTurn = (turn == 'B') ? 'W' : 'B';
if (!hasAnyMove(nextTurn))
{
cout << "No valid moves for both players. Game over.\n";
break;
}
turn = nextTurn;
_getch();
continue;
}
if (singlePlayer && turn == 'W')
{
botMove(turn);
turn = 'B';
_getch();
continue;
}
cout << "Use W/A/S/D to move, Enter to place, 0 to save.\n";
char key = _getch();
if (key == 'w' || key == 'W') cursorR = max(0, cursorR - 1);
else if (key == 's' || key == 'S') cursorR = min(N - 1, cursorR + 1);
else if (key == 'a' || key == 'A') cursorC = max(0, cursorC - 1);
else if (key == 'd' || key == 'D') cursorC = min(N - 1, cursorC + 1);
else if (key == '\r') // Enter
{
if (isValidMove(cursorR, cursorC, turn))
{
applyMove(cursorR, cursorC, turn);
turn = (turn == 'B') ? 'W' : 'B';
}
else
{
cout << "Invalid move!\n";
_getch();
}
}
else if (key == '0')
{
saveGame(playerBlack, playerWhite, turn);
cout << "Game saved! Returning to main menu.\n";
_getch();
return;
}
}
system("cls");
printBoardWithHints('B');
int black = countPieces('B');
int white = countPieces('W');
cout << "Final count -> Black: " << black << " | White: " << white << "\n";
string winner;
if (black > white) winner = playerBlack + " (Black)";
else if (white > black) winner = playerWhite + " (White)";
else winner = "Draw";
cout << "Winner: " << winner << "\n";
saveToHistory(playerBlack, playerWhite, black, white, winner);
_getch();
}
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
int choice;
do
{
setColor(2);
cout << "\n-------------------";
setColor(14);
cout << "\n--- Main Menu ---\n";
setColor(11);
cout << " 1. Two-player game\n";
cout << " 2. Single-player (vs bot)\n";
cout << " 3. Help\n";
cout << " 4. Game History\n";
cout << " 5. Load Game\n";
cout << " 0. Exit\n";
setColor(15);
cout << "Select: ";
setColor(2);
cout << "\n-------------------\n";
setColor(7);
cin >> choice;
if (choice == 1)
{
playGame(false);
} else if (choice == 2)
{
playGame(true);
} else if (choice == 3)
{
helpScreen();
}else if (choice == 4)
{
showGameHistory();
}else if (choice == 5)
{
playGame(false,true);
}
else if (choice == 0)
{
cout << "Goodbye!\n";
} else {
cout << "Invalid option.\n";
}
} while (choice != 0);
return 0;
}