From 388210c016c711a3cce60d2358bdaf586823eee5 Mon Sep 17 00:00:00 2001 From: Soroush Date: Tue, 14 Apr 2026 12:13:26 +0330 Subject: [PATCH] Initial commit on develop branch --- Othello.cpp | 970 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 970 insertions(+) create mode 100644 Othello.cpp diff --git a/Othello.cpp b/Othello.cpp new file mode 100644 index 0000000..bee8656 --- /dev/null +++ b/Othello.cpp @@ -0,0 +1,970 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; + +struct Player { + string name; + char color; // 'B' or 'W' + int discs; +}; + + +void initialBoard(); +void drawBoard(int cursorRow, int cursorCol, bool blackTurn, bool invalidMove, const string& message); +bool cursor(int& cursorRow, int& cursorCol, bool blackTurn, bool invalidMove, const string& message, bool viewOnly); +bool possibleMoveB(int row, int col); +bool possibleMoveW(int row, int col); +bool hasAnyMoveB(); +bool hasAnyMoveW(); +void placeB(int row, int col); +void placeW(int row, int col); +void flipB(int row, int col); +void flipW(int row, int col); +int blackCount(); +int whiteCount(); +void singlePlayerB(string& s); +bool aiMoveWhite(); +void gameOverB(string& s); +void singlePlayerW(string& s); +bool aiMoveBlack(); +void gameOverW(string& s); +void multiPlayer(string& s, string& t); +void gameOverM(string& s, string& t); +void saveHistory(const string& mode, const Player& black, const Player& white, const string& result); +void showHistory(); +void help(); +void newGame(); +void menu(); + + +char B='B'; //○ +char W='W'; //● +bool blackTurn=true; + + +const int BOARD_SIZE = 8; +string board[BOARD_SIZE][BOARD_SIZE]; + +// Arrow key codes +const int KEY_UP = 72; +const int KEY_DOWN = 80; +const int KEY_LEFT = 75; +const int KEY_RIGHT = 77; +const int ENTER = 13; +const int ESC = 27; + + +void initialBoard() { + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + board[i][j] = " "; + } + } + + board[3][3] = "●"; + board[3][4] = "○"; + board[4][3] = "○"; + board[4][4] = "●"; +} + +void drawBoard(int cursorRow, int cursorCol, bool blackTurn, bool invalidMove, const string& message="") { + SetConsoleOutputCP(CP_UTF8); + system("cls"); + + cout << "┏"; + for (int i = 0; i < BOARD_SIZE; i++) { + cout << "━━━"; + if (i < BOARD_SIZE - 1) {cout << "┳";} + } + cout << "┓\n"; + + for (int i = 0; i < BOARD_SIZE; i++) { + cout << "┃"; + for (int j = 0; j < BOARD_SIZE; j++) { + + bool valid; + if (blackTurn) + {valid = possibleMoveB(i, j);} + else + {valid = possibleMoveW(i, j);} + + if (i == cursorRow && j == cursorCol) { + if (valid) + {cout << "[*]";} + else + {cout << "[" << board[i][j] << "]";} + } + else { + if (valid) + {cout << " * ";} + else + {cout << " " << board[i][j] << " ";} + } + + cout << "┃"; + } + cout << "\n"; + + if (i < BOARD_SIZE - 1) { + cout << "┣"; + for (int j = 0; j < BOARD_SIZE; j++) { + cout << "━━━"; + if (j < BOARD_SIZE - 1) {cout << "╋";} + } + cout << "┫\n"; + } + } + + cout << "┗"; + for (int i = 0; i < BOARD_SIZE; i++) { + cout << "━━━"; + if (i < BOARD_SIZE - 1) {cout << "┻";} + } + cout << "┛\n"; + + + //cout << "\n"; + + cout <<" Black(○): " << blackCount()<< " White(●): " << whiteCount() << "\n"; + + cout << " Turn: "; + if (blackTurn) {cout << "Black(○)\n";} + else {cout << "White(●)\n";} + + cout<<"\n"; + + if (!message.empty()) + {cout << " " << message << "\n\n";} + + + + + else if (invalidMove) + {cout << " Invalid Move!\n\n";} + + else + {cout << "\n\n";} + + + cout << " Press ESC To Return To The Menu "<<"\n"; + +} + +bool cursor(int& cursorRow, int& cursorCol, bool blackTurn, bool invalidMove = false, const string& message = "", bool viewOnly = false) { + while (true) { + drawBoard(cursorRow, cursorCol, blackTurn, invalidMove, message); + + int ch = _getch(); + if (ch == 0 || ch == 224) { + ch = _getch(); + switch (ch) { + case KEY_UP: if (cursorRow > 0) cursorRow--; break; + case KEY_DOWN: if (cursorRow < BOARD_SIZE - 1) cursorRow++; break; + case KEY_LEFT: if (cursorCol > 0) cursorCol--; break; + case KEY_RIGHT: if (cursorCol < BOARD_SIZE - 1) cursorCol++; break; + } + } + else if (ch == ENTER) { + if (!viewOnly) { + return true; + } + + } + else if (ch == ESC) { + return false; + } + } +} + + + +bool possibleMoveB(int row, int col) { + int r, c; + + if (board[row][col]==" ") { + r=row+1; + if (r=0 && board[r][col]=="●") { + while (r>=0 && board[r][col]=="●") {r--;} + if (r>=0 && board[r][col]=="○") {return true;}} + c=col+1; + if (c=0 && board[row][c]=="●") { + while (c>=0 && board[row][c]=="●") {c--;} + if (c>=0 && board[row][c]=="○") {return true;}} + r=row+1; + c=col+1; + if (r=0 && board[r][c]=="●") { + while (r=0 && board[r][c]=="●") {r++; c--;} + if (r=0 && board[r][c]=="○") {return true;}} + r=row-1; + c=col+1; + if (r>=0 && c=0 && c=0 && c=0 && c>=0 && board[r][c]=="●") { + while (r>=0 && c>=0 && board[r][c]=="●") {r--; c--;} + if (r>=0 && c>=0 && board[r][c]=="○") {return true;}} + } + return false; +} + +bool possibleMoveW(int row, int col) { + int r, c; + + if (board[row][col]==" ") { + r=row+1; + if (r=0 && board[r][col]=="○") { + while (r>=0 && board[r][col]=="○") {r--;} + if (r>=0 && board[r][col]=="●") {return true;}} + c=col+1; + if (c=0 && board[row][c]=="○") { + while (c>=0 && board[row][c]=="○") {c--;} + if (c>=0 && board[row][c]=="●") {return true;}} + r=row+1; + c=col+1; + if (r=0 && board[r][c]=="○") { + while (r=0 && board[r][c]=="○") {r++; c--;} + if (r=0 && board[r][c]=="●") {return true;}} + r=row-1; + c=col+1; + if (r>=0 && c=0 && c=0 && c=0 && c>=0 && board[r][c]=="○") { + while (r>=0 && c>=0 && board[r][c]=="○") {r--; c--;} + if (r>=0 && c>=0 && board[r][c]=="●") {return true;}} + } + return false; +} + + +bool hasAnyMoveB() { + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (possibleMoveB(i, j)) {return true;} + } + } + return false; +} + +bool hasAnyMoveW() { + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (possibleMoveW(i, j)) {return true;} + } + } + return false; +} + + +void placeB(int row, int col) { + board[row][col]="○"; +} + +void placeW(int row, int col) { + board[row][col]="●"; +} + + +void flipB(int row, int col) { + int r, c, count, k; + + r=row+1; + count=0; + while (r0 && r=0 && board[r][col]=="●") {count++; r--;} + if (count>0 && r>=0 && board[r][col]=="○") { + for (k=1; k<=count; k++) { + board[row-k][col]="○"; + } + } + c=col+1; + count=0; + while (c0 && c=0 && board[row][c]=="●") {count++; c--;} + if (count>0 && c>=0 && board[row][c]=="○") { + for (k=1; k<=count; k++) { + board[row][col-k]="○"; + } + } + r=row+1; + c=col+1; + count=0; + while (r0 && r=0 && board[r][c]=="●") {count++; r++; c--;} + if (count>0 && r=0 && board[r][c]=="○") { + for (k=1; k<=count; k++) { + board[row+k][col-k]="○"; + } + } + r=row-1; + c=col+1; + count=0; + while (r>=0 && c0 && r>=0 && c=0 && c>=0 && board[r][c]=="●") {count++; r--; c--;} + if (count>0 && r>=0 && c>=0 && board[r][c]=="○") { + for (k=1; k<=count; k++) { + board[row-k][col-k]="○"; + } + } +} + +void flipW(int row, int col) { + int r, c, count, k; + + r=row+1; + count=0; + while (r0 && r=0 && board[r][col]=="○") {count++; r--;} + if (count>0 && r>=0 && board[r][col]=="●") { + for (k=1; k<=count; k++) { + board[row-k][col]="●"; + } + } + c=col+1; + count=0; + while (c0 && c=0 && board[row][c]=="○") {count++; c--;} + if (count>0 && c>=0 && board[row][c]=="●") { + for (k=1; k<=count; k++) { + board[row][col-k]="●"; + } + } + r=row+1; + c=col+1; + count=0; + while (r0 && r=0 && board[r][c]=="○") {count++; r++; c--;} + if (count>0 && r=0 && board[r][c]=="●") { + for (k=1; k<=count; k++) { + board[row+k][col-k]="●"; + } + } + r=row-1; + c=col+1; + count=0; + while (r>=0 && c0 && r>=0 && c=0 && c>=0 && board[r][c]=="○") {count++; r--; c--;} + if (count>0 && r>=0 && c>=0 && board[r][c]=="●") { + for (k=1; k<=count; k++) { + board[row-k][col-k]="●"; + } + } +} + + + +int blackCount() { + int count=0; + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (board[i][j]=="○") {count++;} + } + } + return count; +} + +int whiteCount() { + int count=0; + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (board[i][j]=="●") {count++;} + } + } + return count; +} + + + + +void singlePlayerB(string& s) { + initialBoard(); + int cursorRow = 0, cursorCol = 0; + bool blackTurn = true; + bool invalidMove = false; + string currentMessage = ""; + + while (true) { + + + if (!hasAnyMoveB() && !hasAnyMoveW()) { + gameOverB(s); + return; + } + + + if (blackTurn && !hasAnyMoveB()) { + currentMessage = "Black(○) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=false; + continue; + } + + + if (!blackTurn && !hasAnyMoveW()) { + currentMessage = "White(●) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=true; + continue; + } + + drawBoard(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + + + if (blackTurn) { + + bool pressedEnter = cursor(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + if (!pressedEnter) {return;} + + if (possibleMoveB(cursorRow, cursorCol)) { + placeB(cursorRow, cursorCol); + flipB(cursorRow, cursorCol); + blackTurn = false; + invalidMove = false; + } else { + invalidMove = true; + } + } + + + else { + Sleep(800); + aiMoveWhite(); + blackTurn = true; + } + } +} + + +bool aiMoveWhite() { + int rows[64]; + int cols[64]; + int count = 0; + + for (int i = 0; i < BOARD_SIZE; i++) { + for (int j = 0; j < BOARD_SIZE; j++) { + if (possibleMoveW(i, j)) { + rows[count] = i; + cols[count] = j; + count++; + } + } + } + + if (count == 0) return false; + + int r = rand() % count; + + int row = rows[r]; + int col = cols[r]; + + placeW(row, col); + flipW(row, col); + return true; +} + + +void gameOverB(string& s) { + int cursorRow = 0; + int cursorCol = 0; + + Player blackPlayer; + Player whitePlayer; + + blackPlayer.name = s; + blackPlayer.color = 'B'; + blackPlayer.discs = blackCount(); + + whitePlayer.name = "Bot"; + whitePlayer.color = 'W'; + whitePlayer.discs = whiteCount(); + + string winnerMessage; + string result; + + if (blackPlayer.discs > whitePlayer.discs) { + winnerMessage = "Congrats " + blackPlayer.name + "! You Won!"; + result = blackPlayer.name + " Won";} + else if (whitePlayer.discs > blackPlayer.discs) { + winnerMessage = "You Lost " + blackPlayer.name + ". Better Luck Next Time!"; + result = whitePlayer.name + " Won";} + else { + winnerMessage = "It's a DRAW!"; + result = "Draw";} + + + + saveHistory("Single Player", blackPlayer, whitePlayer, result); + + + + cursor(cursorRow, cursorCol, true, false, winnerMessage, true); + +} + + +void singlePlayerW(string& s) { + initialBoard(); + int cursorRow = 0, cursorCol = 0; + bool blackTurn = true; + bool invalidMove = false; + string currentMessage = ""; + + while (true) { + + + if (!hasAnyMoveB() && !hasAnyMoveW()) { + gameOverW(s); + return; + } + + + if (blackTurn && !hasAnyMoveB()) { + currentMessage = "Black(○) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=false; + continue; + } + + + if (!blackTurn && !hasAnyMoveW()) { + currentMessage = "White(●) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=true; + continue; + } + + drawBoard(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + + + if (!blackTurn) { + + bool pressedEnter = cursor(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + if (!pressedEnter) {return;} + + if (possibleMoveW(cursorRow, cursorCol)) { + placeW(cursorRow, cursorCol); + flipW(cursorRow, cursorCol); + blackTurn = true; + invalidMove = false; + } else { + invalidMove = true; + } + } + + + else { + Sleep(800); + aiMoveBlack(); + blackTurn = false; + } + } +} + + +bool aiMoveBlack() { + int rows[64]; + int cols[64]; + int count=0; + + for (int i = 0; i blackPlayer.discs) { + winnerMessage = "Congrats " + whitePlayer.name + "! You Won!"; + result = whitePlayer.name + " Won";} + else if (blackPlayer.discs > whitePlayer.discs) { + winnerMessage = "You Lost " + whitePlayer.name + ". Better Luck Next Time!"; + result = blackPlayer.name + " Won";} + else { + winnerMessage = "It's a DRAW!"; + result = "Draw";} + + + saveHistory("Single Player", blackPlayer, whitePlayer, result); + + + + cursor(cursorRow, cursorCol, true, false, winnerMessage, true); + +} + + + +void multiPlayer(string& s, string& t) { + initialBoard(); + int cursorRow = 0, cursorCol = 0; + bool blackTurn = true; + bool invalidMove = false; + string currentMessage = ""; + + while (true) { + + if (!hasAnyMoveB() && !hasAnyMoveW()) { + gameOverM(s, t); + return; + } + + + if (blackTurn && !hasAnyMoveB()) { + currentMessage = "Black(○) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=false; + continue; + } + + + if (!blackTurn && !hasAnyMoveW()) { + currentMessage = "White(●) has no valid moves. Skipping Turn..."; + drawBoard(cursorRow, cursorCol, blackTurn, false, currentMessage); + Sleep(2000); + currentMessage = ""; + blackTurn=true; + continue; + } + + + drawBoard(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + + bool pressedEnter = cursor(cursorRow, cursorCol, blackTurn, invalidMove, currentMessage); + + if (!pressedEnter) {return;} + + + invalidMove = false; + currentMessage = ""; + + + bool valid; + if (blackTurn) + {valid = possibleMoveB(cursorRow, cursorCol);} + else + {valid = possibleMoveW(cursorRow, cursorCol);} + + if (valid) { + if (blackTurn) { + placeB(cursorRow, cursorCol); + flipB(cursorRow, cursorCol); + } else { + placeW(cursorRow, cursorCol); + flipW(cursorRow, cursorCol); + } + blackTurn = !blackTurn; + } else { + invalidMove = true; + } + } +} + +void gameOverM(string& s, string& t) { + int cursorRow = 0; + int cursorCol = 0; + + Player blackPlayer; + Player whitePlayer; + + + blackPlayer.name = s; + blackPlayer.color = 'B'; + blackPlayer.discs = blackCount(); + + whitePlayer.name = t; + whitePlayer.color = 'W'; + whitePlayer.discs = whiteCount(); + + string winnerMessage; + string result; + + if (blackPlayer.discs > whitePlayer.discs) { + winnerMessage = "Congrats " + blackPlayer.name + "! You Won!"; + result = blackPlayer.name + " Won";} + else if (blackPlayer.discs < whitePlayer.discs) { + winnerMessage = "Congrats " + whitePlayer.name + "! You Won!"; + result = whitePlayer.name + " Won";} + else { + winnerMessage = "It's a DRAW!"; + result = "Draw";} + + + + saveHistory("Multiplayer", blackPlayer, whitePlayer, result); + + + cursor(cursorRow, cursorCol, true, false, winnerMessage, true); + +} + + +void saveHistory(const string& mode, const Player& black, const Player& white, const string& result) { + + ifstream inFile("History.txt"); + string oldContent; + string line; + while (getline(inFile, line)) { + oldContent += line+"\n"; + } + inFile.close(); + + + ofstream outFile("History.txt"); + if (!outFile) { + cout<<"Error: Could not open History.txt for writing.\n"; + return; + } + + outFile<>n; + if (n==1) { + cout<<"Enter Your Name: "; + cin>>s; + cout<<"Choose Your Color (B/W): "; + cin>>a; + if (a=='B') { + singlePlayerB(s);} + if (a=='W') { + singlePlayerW(s);} + } + if (n==2) { + cout<<"Enter Your Name (P1 as Black): "; + cin>>s; + cout<<"Enter Your Name (P2 as White): "; + cin>>t; + multiPlayer(s, t); + } +} + +void menu() { + system("cls"); + cout<<" Welcome To Othello!"<>choice; + if (choice==1) + {newGame();} + else if (choice==2) + {help();} + else if (choice == 3) + {showHistory();} + else if (choice==4) + {return 0;} + } +} \ No newline at end of file