970 lines
26 KiB
C++
970 lines
26 KiB
C++
#include <iostream>
|
|
#include <cmath>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <cstdlib>
|
|
#include <ctime>
|
|
#include <conio.h>
|
|
#include <windows.h>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <cstring>
|
|
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<BOARD_SIZE && board[r][col]=="●") {
|
|
while (r<BOARD_SIZE && board[r][col]=="●") {r++;}
|
|
if (r<BOARD_SIZE && board[r][col]=="○") {return true;}}
|
|
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<BOARD_SIZE && board[row][c]=="●") {
|
|
while (c<BOARD_SIZE && board[row][c]=="●") {c++;}
|
|
if (c<BOARD_SIZE && board[row][c]=="○") {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<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="●") {
|
|
while (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="●") {r++; c++;}
|
|
if (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="○") {return true;}}
|
|
r=row+1;
|
|
c=col-1;
|
|
if (r<BOARD_SIZE && c>=0 && board[r][c]=="●") {
|
|
while (r<BOARD_SIZE && c>=0 && board[r][c]=="●") {r++; c--;}
|
|
if (r<BOARD_SIZE && c>=0 && board[r][c]=="○") {return true;}}
|
|
r=row-1;
|
|
c=col+1;
|
|
if (r>=0 && c<BOARD_SIZE && board[r][c]=="●") {
|
|
while (r>=0 && c<BOARD_SIZE && board[r][c]=="●") {r--; c++;}
|
|
if (r>=0 && c<BOARD_SIZE && board[r][c]=="○") {return true;}}
|
|
r=row-1;
|
|
c=col-1;
|
|
if (r>=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<BOARD_SIZE && board[r][col]=="○") {
|
|
while (r<BOARD_SIZE && board[r][col]=="○") {r++;}
|
|
if (r<BOARD_SIZE && board[r][col]=="●") {return true;}}
|
|
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<BOARD_SIZE && board[row][c]=="○") {
|
|
while (c<BOARD_SIZE && board[row][c]=="○") {c++;}
|
|
if (c<BOARD_SIZE && board[row][c]=="●") {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<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="○") {
|
|
while (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="○") {r++; c++;}
|
|
if (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="●") {return true;}}
|
|
r=row+1;
|
|
c=col-1;
|
|
if (r<BOARD_SIZE && c>=0 && board[r][c]=="○") {
|
|
while (r<BOARD_SIZE && c>=0 && board[r][c]=="○") {r++; c--;}
|
|
if (r<BOARD_SIZE && c>=0 && board[r][c]=="●") {return true;}}
|
|
r=row-1;
|
|
c=col+1;
|
|
if (r>=0 && c<BOARD_SIZE && board[r][c]=="○") {
|
|
while (r>=0 && c<BOARD_SIZE && board[r][c]=="○") {r--; c++;}
|
|
if (r>=0 && c<BOARD_SIZE && board[r][c]=="●") {return true;}}
|
|
r=row-1;
|
|
c=col-1;
|
|
if (r>=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 (r<BOARD_SIZE && board[r][col]=="●") {count++; r++;}
|
|
if (count>0 && r<BOARD_SIZE && board[r][col]=="○") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row+k][col]="○";
|
|
}
|
|
}
|
|
r=row-1;
|
|
count=0;
|
|
while (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 (c<BOARD_SIZE && board[row][c]=="●") {count++; c++;}
|
|
if (count>0 && c<BOARD_SIZE && board[row][c]=="○") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row][col+k]="○";
|
|
}
|
|
}
|
|
c=col-1;
|
|
count=0;
|
|
while (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 (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="●") {count++; r++; c++;}
|
|
if (count>0 && r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="○") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row+k][col+k]="○";
|
|
}
|
|
}
|
|
r=row+1;
|
|
c=col-1;
|
|
count=0;
|
|
while (r<BOARD_SIZE && c>=0 && board[r][c]=="●") {count++; r++; c--;}
|
|
if (count>0 && r<BOARD_SIZE && c>=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 && c<BOARD_SIZE && board[r][c]=="●") {count++; r--; c++;}
|
|
if (count>0 && r>=0 && c<BOARD_SIZE && 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 && 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 (r<BOARD_SIZE && board[r][col]=="○") {count++; r++;}
|
|
if (count>0 && r<BOARD_SIZE && board[r][col]=="●") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row+k][col]="●";
|
|
}
|
|
}
|
|
r=row-1;
|
|
count=0;
|
|
while (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 (c<BOARD_SIZE && board[row][c]=="○") {count++; c++;}
|
|
if (count>0 && c<BOARD_SIZE && board[row][c]=="●") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row][col+k]="●";
|
|
}
|
|
}
|
|
c=col-1;
|
|
count=0;
|
|
while (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 (r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="○") {count++; r++; c++;}
|
|
if (count>0 && r<BOARD_SIZE && c<BOARD_SIZE && board[r][c]=="●") {
|
|
for (k=1; k<=count; k++) {
|
|
board[row+k][col+k]="●";
|
|
}
|
|
}
|
|
r=row+1;
|
|
c=col-1;
|
|
count=0;
|
|
while (r<BOARD_SIZE && c>=0 && board[r][c]=="○") {count++; r++; c--;}
|
|
if (count>0 && r<BOARD_SIZE && c>=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 && c<BOARD_SIZE && board[r][c]=="○") {count++; r--; c++;}
|
|
if (count>0 && r>=0 && c<BOARD_SIZE && 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 && 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<BOARD_SIZE; i++) {
|
|
for (int j = 0; j<BOARD_SIZE; j++) {
|
|
if (possibleMoveB(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];
|
|
|
|
placeB(row, col);
|
|
flipB(row, col);
|
|
return true;
|
|
}
|
|
|
|
|
|
void gameOverW(string& s) {
|
|
int cursorRow = 0;
|
|
int cursorCol = 0;
|
|
|
|
Player blackPlayer;
|
|
Player whitePlayer;
|
|
|
|
blackPlayer.name = "Bot";
|
|
blackPlayer.color = 'B';
|
|
blackPlayer.discs = blackCount();
|
|
|
|
whitePlayer.name = s;
|
|
whitePlayer.color = 'W';
|
|
whitePlayer.discs = whiteCount();
|
|
|
|
string winnerMessage;
|
|
string result;
|
|
|
|
if (whitePlayer.discs > 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<<oldContent;
|
|
//outFile<<" Game Number "<<r<<endl;
|
|
outFile<<"Mode: "<<mode<<endl;
|
|
outFile<<"Black: "<<black.name<<" ("<<black.discs<<" discs)"<<endl;
|
|
outFile<<"White: "<<white.name<<" (" <<white.discs<<" discs)"<<endl;
|
|
outFile<<"Result: "<<result<<endl;
|
|
outFile<<"------------------------"<< endl;
|
|
|
|
outFile.close();
|
|
}
|
|
|
|
|
|
void showHistory() {
|
|
system("cls");
|
|
|
|
ifstream file("History.txt");
|
|
if (!file || file.peek()==EOF) {
|
|
cout<<"No game history found yet.\n\n";
|
|
} else {
|
|
string line;
|
|
while (getline(file, line)) {
|
|
cout<<line<<endl;
|
|
}
|
|
file.close();
|
|
cout<<"\n";
|
|
}
|
|
|
|
cout<<"Press ESC to return to the menu.";
|
|
while (true) {
|
|
int ch=_getch();
|
|
if (ch==ESC) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void help() {
|
|
system("cls");
|
|
|
|
cout<<"========== HOW TO PLAY OTHELLO ==========\n\n";
|
|
cout<<"- Othello is a turn-based game which is played on an 8x8 board.\n";
|
|
cout<<"- Black(○) always goes first.\n";
|
|
cout<<"- A move is valid if it flips at least one opponent disc.\n";
|
|
cout<<"- Discs are flipped when they are trapped between two discs of opposite color.\n";
|
|
cout<<"- If a player has no valid moves, their turn is skipped.\n";
|
|
cout<<"- The game ends when neither player can move.\n\n";
|
|
cout<<"Use ARROW KEYS to move through the board.\n";
|
|
cout<<"Press ENTER to place a disc.\n";
|
|
cout<<"=========================================\n\n";
|
|
cout<<"Press ESC to return to the menu.";
|
|
|
|
while (true) {
|
|
int ch=_getch();
|
|
if (ch==ESC) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void newGame() {
|
|
cout<<"1. Single Player"<<endl;
|
|
cout<<"2. Multiplayer"<<endl;;
|
|
int n;
|
|
string s, t;
|
|
char a;
|
|
cin>>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!"<<endl;
|
|
cout<<"1. New Game"<<endl;
|
|
cout<<"2. Help"<<endl;
|
|
cout<<"3. Game History"<<endl;
|
|
cout<<"4. Exit"<<endl;
|
|
}
|
|
|
|
int main() {
|
|
while (true) {
|
|
menu();
|
|
int choice, r;
|
|
cin>>choice;
|
|
if (choice==1)
|
|
{newGame();}
|
|
else if (choice==2)
|
|
{help();}
|
|
else if (choice == 3)
|
|
{showHistory();}
|
|
else if (choice==4)
|
|
{return 0;}
|
|
}
|
|
} |