1145 lines
30 KiB
C++
1145 lines
30 KiB
C++
// --------- HEADERS ----------
|
|
#include <iostream>
|
|
#include <windows.h>
|
|
#include <fstream>
|
|
#include <ctime>
|
|
#include <conio.h>
|
|
using namespace std;
|
|
|
|
// ------- COLORS ---------
|
|
#define RESET "\033[0m"
|
|
#define RED "\033[31m"
|
|
#define GREEN "\033[32m"
|
|
#define CYAN "\033[36m"
|
|
#define BLUE "\033[34m"
|
|
#define YELLOW "\033[33m"
|
|
#define MAGENTA "\033[35m"
|
|
#define WHITE "\033[37m"
|
|
|
|
// ----------------- Function Declarations -----------------
|
|
void WaitForAnyKey();
|
|
string Solid_HollowCircle(char Board[8][8], string player1, string player2); // counts the number of Circles
|
|
void SaveHistory();
|
|
void ShowHistory();
|
|
bool IsEnd(char board[8][8]); // checks if its end of game of not
|
|
void SaveGame(); // saves previous uncompleted game
|
|
bool LoadGame(); // loads previous uncompleted game
|
|
void StartGame(bool isLoaded); // the main strategy
|
|
void DrawBoard();
|
|
void ChangeAll(int x,int y,char p); // returns any legal circle
|
|
bool ValidMove(int x,int y,char p); // check if there is any legal move for current player
|
|
int numofCircles (char board[8][8], char player);
|
|
string CurrentDateTime();
|
|
void DrawMenu(int choice);
|
|
void DrawNewGameMenu(int choice);
|
|
void ModeType(int mode);
|
|
bool HasAnyMove(char p);
|
|
bool IsEndGame();
|
|
void WaitForKeyRelease();
|
|
void ClearInputBuffer();
|
|
|
|
// ----------------- Global Variables -----------------
|
|
char board[8][8];
|
|
bool locked[8][8];
|
|
string menu[5];
|
|
string mod[3];
|
|
char currentPlayer = '1';
|
|
bool movedThisTurn = false;
|
|
string player1, player2;
|
|
bool placedThisTurn = false;
|
|
bool lastTurnWasPass = false;
|
|
bool savedthisgame = false;
|
|
int moveCount = 0;
|
|
int botLevel = 0;
|
|
bool showPassMessage = false;
|
|
string passPlayerName = "";
|
|
|
|
// ----------------- structs ------------------
|
|
struct Move {
|
|
int x, y;
|
|
int score;
|
|
};
|
|
|
|
Move moves[64];
|
|
|
|
COORD cursor = {0, 0};
|
|
|
|
// ------------ bot -----------
|
|
void DrawBotMod(int level) {
|
|
system("cls");
|
|
|
|
string options[4] = { "Easy", "Hard", "Expert", "back" };
|
|
cout << GREEN << " ╔═════════ " << RESET << RED << "BOT MODE" << RESET << GREEN << " ═════════╗\n" << RESET;
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
for (int i = 0; i < 4; i++) {
|
|
|
|
if (i == level) {
|
|
|
|
if (i == 0) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << endl;
|
|
|
|
if (i == 1) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << endl;
|
|
|
|
if (i == 3) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << endl;
|
|
}
|
|
|
|
else {
|
|
|
|
if (i == 0) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 1) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 3) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
}
|
|
}
|
|
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
cout << GREEN << " ╚════════════════════════════╝\n" << RESET;
|
|
|
|
}
|
|
|
|
bool SelectBotLevel() {
|
|
int choice = 0;
|
|
while (true) {
|
|
DrawBotMod(choice);
|
|
char input = _getch();
|
|
|
|
if (input == 'w' || input == 'W') {
|
|
choice--;
|
|
if (choice < 0) choice = 3;
|
|
}
|
|
else if (input == 's' || input == 'S') {
|
|
choice++;
|
|
if (choice > 3) choice = 0;
|
|
}
|
|
else if (input == '\r') { // ENTER
|
|
// ---- BACK ----
|
|
if (choice == 3) {
|
|
ClearInputBuffer();
|
|
|
|
return false;
|
|
}
|
|
|
|
// ---- BOT LEVEL ----
|
|
botLevel = choice + 1;
|
|
|
|
ClearInputBuffer();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
int CountFlips(int x,int y,char p){
|
|
char backup[8][8];
|
|
memcpy(backup, board, sizeof(board));
|
|
|
|
ChangeAll(x,y,p);
|
|
|
|
int before = numofCircles(backup, p);
|
|
int after = numofCircles(board, p);
|
|
|
|
memcpy(board, backup, sizeof(board));
|
|
return after - before;
|
|
}
|
|
|
|
|
|
|
|
void CollectValidMoves(char p){
|
|
moveCount = 0;
|
|
for(int y=0;y<8;y++){
|
|
for(int x=0;x<8;x++){
|
|
if(ValidMove(x,y,p)){
|
|
moves[moveCount].x = x;
|
|
moves[moveCount].y = y;
|
|
moves[moveCount].score = CountFlips(x,y,p);
|
|
moveCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool IsCorner(int x,int y){
|
|
return (x==0||x==7) && (y==0||y==7);
|
|
}
|
|
|
|
bool IsEdge(int x,int y){
|
|
return x==0||x==7||y==0||y==7;
|
|
}
|
|
|
|
void BotMove(int level) {
|
|
|
|
CollectValidMoves('2');
|
|
|
|
// ---------- BOT PASS ----------
|
|
if (moveCount == 0) {
|
|
|
|
showPassMessage = true;
|
|
passPlayerName = player2;
|
|
|
|
DrawBoard();
|
|
Sleep(800);
|
|
|
|
showPassMessage = false;
|
|
|
|
if (lastTurnWasPass) {
|
|
return;
|
|
}
|
|
|
|
lastTurnWasPass = true;
|
|
currentPlayer = '1';
|
|
return;
|
|
}
|
|
|
|
// ---------- BOT HAS MOVE ----------
|
|
|
|
int idx = 0;
|
|
|
|
// LEVEL 1:
|
|
if (level == 1) {
|
|
idx = rand() % moveCount;
|
|
}
|
|
|
|
// LEVEL 2:
|
|
else if (level == 2) {
|
|
int maxScore = -1;
|
|
for (int i = 0; i < moveCount; i++)
|
|
if (moves[i].score > maxScore)
|
|
maxScore = moves[i].score;
|
|
|
|
int best[64], bestCount = 0;
|
|
for (int i = 0; i < moveCount; i++)
|
|
if (moves[i].score == maxScore)
|
|
best[bestCount++] = i;
|
|
|
|
idx = best[rand() % bestCount];
|
|
}
|
|
|
|
// LEVEL 3:
|
|
else if (level == 3) {
|
|
|
|
int corners[64], cCount = 0;
|
|
int edges[64], eCount = 0;
|
|
int best[64], bCount = 0;
|
|
|
|
int maxScore = -1;
|
|
for (int i = 0; i < moveCount; i++)
|
|
if (moves[i].score > maxScore)
|
|
maxScore = moves[i].score;
|
|
|
|
for (int i = 0; i < moveCount; i++) {
|
|
if (IsCorner(moves[i].x, moves[i].y))
|
|
corners[cCount++] = i;
|
|
else if (IsEdge(moves[i].x, moves[i].y))
|
|
edges[eCount++] = i;
|
|
else if (moves[i].score == maxScore)
|
|
best[bCount++] = i;
|
|
}
|
|
|
|
if (cCount > 0) idx = corners[rand() % cCount];
|
|
else if (eCount > 0) idx = edges[rand() % eCount];
|
|
else idx = best[rand() % bCount];
|
|
}
|
|
|
|
// ---------- EXECUTE MOVE ----------
|
|
int x = moves[idx].x;
|
|
int y = moves[idx].y;
|
|
|
|
board[y][x] = '2';
|
|
locked[y][x] = true;
|
|
ChangeAll(x, y, '2');
|
|
|
|
currentPlayer = '1';
|
|
|
|
}
|
|
|
|
// ----------------- Functions -----------------
|
|
|
|
void ClearInputBuffer() {
|
|
while (_kbhit())_getch();
|
|
}
|
|
bool HasAnyMove(char p){
|
|
for(int y=0;y<8;y++)
|
|
for(int x=0;x<8;x++)
|
|
if(ValidMove(x,y,p))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool IsEndGame(){
|
|
return !HasAnyMove('1') && !HasAnyMove('2');
|
|
}
|
|
|
|
|
|
void DrawMenu(int choice) {
|
|
|
|
system("cls");
|
|
string options[5] = { "New Game", "Load Game", "Help", "Game History", "Exit" };
|
|
cout << GREEN << " ╔══════════ " << RESET << RED << "GAME MENU" << RESET << GREEN << " ══════════╗\n" << RESET;
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
for (int i = 0; i < 5; i++) {
|
|
|
|
if (i == choice) {
|
|
if (i == 0) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
if (i == 1) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
if (i == 3) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
if (i == 4) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
}
|
|
else {
|
|
|
|
if (i == 0) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 1) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 3) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
|
|
if (i == 4) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << RESET << endl;
|
|
}
|
|
}
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
cout << GREEN << " ╚═══════════════════════════════╝\n" << RESET;
|
|
|
|
|
|
}
|
|
|
|
void DrawNewGameMenu(int choice) {
|
|
system("cls");
|
|
|
|
string options[3] = { "Single Player", "Two Player", "Back to Menu" };
|
|
cout << GREEN << " ╔════════ " << RESET << RED << "NEW GAME" << RESET << GREEN << " ════════╗\n" << RESET;
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
|
|
for (int i = 0 ; i < 3 ; i++) {
|
|
if (i == choice){
|
|
|
|
if (i == 0) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
|
|
if (i == 1) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ╠" << RESET << MAGENTA << " > " << options[i] << " <" << RESET << GREEN << " ╣" << RESET << endl;
|
|
|
|
}
|
|
else {
|
|
|
|
if (i == 0) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << endl;
|
|
|
|
if (i == 1) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << endl;
|
|
|
|
if (i == 2) cout << GREEN << " ║" << RESET << " " << options[i] << GREEN << " ║" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
cout << GREEN << " ╚══════════════════════════╝\n" << RESET;
|
|
|
|
}
|
|
|
|
// -------------------- Game place --------------------
|
|
void ModeType(int mode) {
|
|
system("cls");
|
|
|
|
if (mode == 1) {
|
|
cout << "Enter your name: ";
|
|
cin >> player1;
|
|
|
|
player2 = "Bot";
|
|
|
|
bool levelSelected = false;
|
|
while (!levelSelected) {
|
|
levelSelected = SelectBotLevel();
|
|
if (!levelSelected) return;
|
|
}
|
|
}
|
|
else if (mode == 2) {
|
|
cout << "Enter Player1 Name: ";
|
|
cin >> player1;
|
|
cout << "Enter Player2 Name: ";
|
|
cin >> player2;
|
|
|
|
}
|
|
|
|
savedthisgame = false;
|
|
StartGame(false);
|
|
}
|
|
|
|
|
|
void DrawBoard() {
|
|
system("cls");
|
|
|
|
cout << GREEN << " ┌─────────────────────────────────┐\n" << RESET;
|
|
|
|
for (int y = 0; y < 8; y++) {
|
|
|
|
cout << GREEN << " │ " << RESET;
|
|
|
|
for (int x = 0; x < 8; x++) {
|
|
|
|
string display;
|
|
if (cursor.X == x && cursor.Y == y) {
|
|
|
|
if (board[y][x] == '_') {
|
|
cout << RED << "[" << RESET << "_" << RED << "]" << RESET ;
|
|
}
|
|
else if (ValidMove(x, y, currentPlayer)) {
|
|
cout << RED << "[*]" << RESET;
|
|
}
|
|
else {
|
|
|
|
cout << RED << "[" << RESET;
|
|
cout << (board[y][x] == '1' ? "●" : "○");
|
|
cout << RED << "]" << RESET;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if (board[y][x] == '1')
|
|
display = "●";
|
|
else if (board[y][x] == '2')
|
|
display = "○";
|
|
else if (ValidMove(x, y, currentPlayer))
|
|
display = string(BLUE) + "*" + RESET;
|
|
else
|
|
display = "_";
|
|
|
|
cout << " " << display << " ";
|
|
}
|
|
|
|
cout << " ";
|
|
}
|
|
cout << GREEN << "│\n" << RESET;
|
|
}
|
|
cout << GREEN << " └─────────────────────────────────┘\n" << RESET;
|
|
|
|
cout << GREEN << " ╔════════╗\n" << RESET;
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
|
|
cout << " ● : " << numofCircles(board, '1') << endl;
|
|
cout << " ○ : " << numofCircles(board, '2') << endl;
|
|
cout << GREEN << " ║ ║\n" << RESET;
|
|
cout << GREEN << " ╚════════╝\n" << RESET;
|
|
cout << "\n Current Player: " << (currentPlayer == '1' ? player1 : player2) << endl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StartGame(bool isLoaded = false) {
|
|
if (!isLoaded) {
|
|
|
|
movedThisTurn = false;
|
|
currentPlayer = '1';
|
|
cursor = {0, 0};
|
|
for (int y = 0; y < 8; y++)
|
|
for (int x = 0; x < 8; x++) {
|
|
board[y][x] = '_';
|
|
locked[y][x] = false;
|
|
}
|
|
board[3][3] = board[4][4] = '2';
|
|
board[3][4] = board[4][3] = '1';
|
|
locked[3][3] = locked[4][4] = locked[3][4] = locked[4][3] = true;
|
|
}
|
|
|
|
DrawBoard();
|
|
|
|
WaitForKeyRelease();
|
|
ClearInputBuffer();
|
|
|
|
bool wPressed=false, aPressed=false, sPressed=false, dPressed=false, enterPressed=false;
|
|
bool spacePressed=false;
|
|
|
|
while(true) {
|
|
bool needRedraw = false;
|
|
|
|
|
|
// ---------- BOT TURN ----------
|
|
if (player2 == "Bot" && currentPlayer == '2') {
|
|
|
|
Sleep(400);
|
|
BotMove(botLevel);
|
|
|
|
lastTurnWasPass = false;
|
|
placedThisTurn = false;
|
|
|
|
DrawBoard();
|
|
WaitForKeyRelease();
|
|
ClearInputBuffer();
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
// Move Cursor
|
|
if ((GetAsyncKeyState('W') & 0x8000) && !wPressed && cursor.Y>0) { cursor.Y--; wPressed=true; needRedraw=true; }
|
|
else if (!(GetAsyncKeyState('W') & 0x8000)) wPressed=false;
|
|
if ((GetAsyncKeyState('S') & 0x8000) && !sPressed && cursor.Y<7) { cursor.Y++; sPressed=true; needRedraw=true; }
|
|
else if (!(GetAsyncKeyState('S') & 0x8000)) sPressed=false;
|
|
if ((GetAsyncKeyState('A') & 0x8000) && !aPressed && cursor.X>0) { cursor.X--; aPressed=true; needRedraw=true; }
|
|
else if (!(GetAsyncKeyState('A') & 0x8000)) aPressed=false;
|
|
if ((GetAsyncKeyState('D') & 0x8000) && !dPressed && cursor.X<7) { cursor.X++; dPressed=true; needRedraw=true; }
|
|
else if (!(GetAsyncKeyState('D') & 0x8000)) dPressed=false;
|
|
|
|
|
|
// ENTER
|
|
if ((GetAsyncKeyState(VK_RETURN) & 0x8000) && !enterPressed) {
|
|
|
|
if (!placedThisTurn) {
|
|
|
|
if (!HasAnyMove(currentPlayer)) {
|
|
|
|
DrawBoard();
|
|
Sleep(1000);
|
|
}
|
|
|
|
if (lastTurnWasPass) {
|
|
|
|
// remove("SaveGame.txt");
|
|
// SaveGame();
|
|
|
|
// WaitForKeyRelease();
|
|
// ClearInputBuffer();
|
|
// break;
|
|
}
|
|
|
|
|
|
lastTurnWasPass = true;
|
|
}
|
|
else {
|
|
|
|
locked[cursor.Y][cursor.X] = true;
|
|
ChangeAll(cursor.X, cursor.Y, currentPlayer);
|
|
|
|
lastTurnWasPass = false;
|
|
placedThisTurn = false;
|
|
|
|
currentPlayer = (currentPlayer=='1')?'2':'1';
|
|
SaveGame();
|
|
}
|
|
|
|
needRedraw = true;
|
|
enterPressed = true;
|
|
}
|
|
else if (!(GetAsyncKeyState(VK_RETURN) & 0x8000)) enterPressed = false;
|
|
|
|
|
|
// SPACE
|
|
if ((GetAsyncKeyState(VK_SPACE) & 0x8000) && !spacePressed) {
|
|
|
|
if (!locked[cursor.Y][cursor.X]) {
|
|
|
|
if (ValidMove(cursor.X, cursor.Y, currentPlayer)) {
|
|
char &cell = board[cursor.Y][cursor.X];
|
|
|
|
if (cell == '_') {
|
|
cell = currentPlayer;
|
|
placedThisTurn = true;
|
|
}
|
|
else if (cell == currentPlayer) {
|
|
cell = '_';
|
|
placedThisTurn = false;
|
|
}
|
|
needRedraw = true;
|
|
|
|
}
|
|
else {
|
|
cout << "\nInvalid move! You must place on a legal cell.\n";
|
|
Sleep(800);
|
|
}
|
|
|
|
}
|
|
else {
|
|
cout << "\nInvalid move! You must place on a legal cell.\n";
|
|
Sleep(800);
|
|
}
|
|
|
|
spacePressed = true;
|
|
}
|
|
else if (!(GetAsyncKeyState(VK_SPACE) & 0x8000)) spacePressed = false;
|
|
|
|
|
|
// ESC
|
|
if ((GetAsyncKeyState(VK_ESCAPE) & 0x8000)) {
|
|
|
|
remove("SaveGame.txt");
|
|
SaveGame();
|
|
WaitForKeyRelease();
|
|
ClearInputBuffer();
|
|
break;
|
|
}
|
|
|
|
|
|
if (needRedraw)
|
|
DrawBoard();
|
|
|
|
bool movesLeft = false;
|
|
for(int y=0;y<8;y++)
|
|
for(int x=0;x<8;x++)
|
|
if(ValidMove(x,y,currentPlayer)) movesLeft=true;
|
|
|
|
if (!movesLeft) {
|
|
cout << " --------passed------";
|
|
Sleep(500);
|
|
currentPlayer = (currentPlayer=='1')?'2':'1';
|
|
}
|
|
|
|
|
|
if (IsEndGame()) { // end of the game
|
|
|
|
if (!savedthisgame) {
|
|
|
|
|
|
SaveHistory();
|
|
system("cls");
|
|
|
|
cout << " << --- " << RED << "GAME IS OVER" << RESET << " --- >>\n";
|
|
|
|
if (numofCircles(board, '1') > numofCircles(board, '2')){
|
|
cout << " PLAYER < " << CYAN << player1 << RESET << " > won!";
|
|
}
|
|
else if (numofCircles(board, '1') < numofCircles(board, '2')){
|
|
cout << " PLAYER < " << CYAN << player2 << RESET << " > won!";
|
|
}
|
|
else if (numofCircles(board, '1') == numofCircles(board, '2')){
|
|
system("cls");
|
|
cout << GREEN << " Equal!" << RESET;
|
|
}
|
|
|
|
cout << RED << "\n PRESS ANY KET TO RETURN TO MENU . . ." << RESET ;
|
|
|
|
WaitForAnyKey();
|
|
|
|
WaitForKeyRelease();
|
|
ClearInputBuffer();
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
Sleep(80);
|
|
|
|
}
|
|
}
|
|
|
|
// ----------------- Remaining Functions -----------------
|
|
void WaitForKeyRelease() {
|
|
while ((GetAsyncKeyState(VK_RETURN) & 0x8000) || (GetAsyncKeyState(VK_SPACE) & 0x8000) ||(GetAsyncKeyState(VK_ESCAPE) & 0x8000)) {
|
|
Sleep(50);
|
|
}
|
|
}
|
|
|
|
void WaitForAnyKey(){
|
|
while(true){
|
|
for(int k=8;k<=190;k++)
|
|
if(GetAsyncKeyState(k)&0x8000) {
|
|
return;
|
|
}
|
|
Sleep(50);
|
|
}
|
|
}
|
|
|
|
string Solid_HollowCircle(char Board[8][8], string player1, string player2) {
|
|
int solid = 0, hollow = 0;
|
|
for (int i = 0; i < 8; i++)
|
|
for (int j = 0; j < 8; j++) {
|
|
if (Board[i][j] == '1') solid++;
|
|
else if (Board[i][j] == '2') hollow++;
|
|
}
|
|
|
|
string res;
|
|
if (solid > hollow)
|
|
res = player1 + " won\n";
|
|
else if (hollow > solid)
|
|
res = player2 + " won\n";
|
|
else
|
|
res = "Equal\n";
|
|
|
|
res += "Solid Circles (●) : " + to_string(solid) + "\n";
|
|
res += "Hollow Circles (○) : " + to_string(hollow) + "\n";
|
|
|
|
return res;
|
|
}
|
|
|
|
string CurrentDateTime() {
|
|
|
|
time_t t = time(0);
|
|
tm now = *localtime(&t);
|
|
|
|
string Date, Times, res;
|
|
|
|
Date = to_string(now.tm_year + 1900) + "-" + to_string(now.tm_mon + 1) + "-" + to_string(now.tm_mday) + " ";
|
|
|
|
Times = to_string(now.tm_hour) + ":" + to_string(now.tm_min) + ":" + to_string(now.tm_sec);
|
|
|
|
res = Date + Times;
|
|
return res;
|
|
}
|
|
|
|
|
|
void SaveHistory() {
|
|
|
|
int p1 = numofCircles(board, '1');
|
|
int p2 = numofCircles(board, '2');
|
|
|
|
string winner;
|
|
if (p1 > p2) winner = player1;
|
|
else if (p2 > p1) winner = player2;
|
|
else winner = "Equal";
|
|
|
|
ofstream file("HistoryGame.txt", ios::app);
|
|
if (!file) return;
|
|
|
|
file << "------------------\n";
|
|
file << "Date: " << CurrentDateTime() << "\n";
|
|
file << "Player 1: " << player1 << "\n";
|
|
file << "Player 2: " << player2 << "\n";
|
|
file << "Score: " << player1 << " (" << p1 << ") - "
|
|
<< player2 << " (" << p2 << ")\n";
|
|
file << "Winner: " << winner << "\n";
|
|
file << "------------------\n";
|
|
|
|
file.close();
|
|
}
|
|
|
|
void ShowHistory() {
|
|
|
|
ifstream file("HistoryGame.txt");
|
|
if (!file) {
|
|
cout << "No game history found!\n";
|
|
return;
|
|
}
|
|
|
|
string lines[2000];
|
|
int count = 0;
|
|
|
|
while (getline(file, lines[count]) && count < 2000)
|
|
count++;
|
|
|
|
file.close();
|
|
|
|
for (int i = count - 1; i >= 0; i--) {
|
|
cout << lines[i] << endl;
|
|
}
|
|
|
|
cout << "\n<<---" << RED << " -- PRESS ANY KEY TO RETURN TO MENU -- " << RESET << "--->>";
|
|
WaitForAnyKey();
|
|
}
|
|
|
|
bool IsEnd(char board[8][8]){
|
|
for(int i=0;i<8;i++)
|
|
for(int j=0;j<8;j++)
|
|
if(board[i][j]=='_')
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void SaveGame(){
|
|
ofstream file("SaveGame.txt");
|
|
if(!file) return;
|
|
file<<currentPlayer<<endl;
|
|
file<<player1<<endl;
|
|
file<<player2<<endl;
|
|
|
|
for(int i=0;i<8;i++){
|
|
for(int j=0;j<8;j++)
|
|
file<<board[i][j]<<" ";
|
|
file<<endl;
|
|
}
|
|
|
|
for(int i=0;i<8;i++){
|
|
for(int j=0;j<8;j++)
|
|
file<<locked[i][j]<<" ";
|
|
file<<endl;
|
|
}
|
|
|
|
file.close();
|
|
}
|
|
|
|
bool LoadGame(){
|
|
|
|
ifstream file("SaveGame.txt");
|
|
if(!file) return false;
|
|
|
|
file >> currentPlayer;
|
|
file.ignore();
|
|
|
|
getline(file, player1);
|
|
getline(file, player2);
|
|
|
|
for(int i=0;i<8;i++)
|
|
for(int j=0;j<8;j++)
|
|
file >> board[i][j];
|
|
|
|
for(int i=0;i<8;i++)
|
|
for(int j=0;j<8;j++)
|
|
file >> locked[i][j];
|
|
|
|
file.close();
|
|
return true;
|
|
}
|
|
|
|
|
|
int numofCircles (char board[8][8], char player) {
|
|
|
|
int number = 0;
|
|
for (int i = 0 ; i < 8 ; i++)
|
|
for (int j = 0 ; j < 8 ; j++)
|
|
if (board[i][j] == player)
|
|
number++;
|
|
|
|
return number;
|
|
}
|
|
|
|
// ---------- Opponent ----------
|
|
char Opponent(char p){
|
|
return (p=='1')?'2':'1';
|
|
}
|
|
|
|
// ---------- Change Functions ----------
|
|
void ChangeRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1;
|
|
|
|
while(i<8&&board[y][i]==op)i++;
|
|
|
|
if(i<8&&board[y][i]==p)
|
|
for(int j=x+1;j<i;j++)
|
|
board[y][j]=p;
|
|
}
|
|
|
|
void ChangeLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1;
|
|
|
|
while(i>=0&&board[y][i]==op)i--;
|
|
|
|
if(i>=0&&board[y][i]==p)
|
|
for(int j=x-1;j>i;j--)
|
|
board[y][j]=p;
|
|
}
|
|
|
|
|
|
void ChangeDown(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=y+1;
|
|
|
|
while(i<8&&board[i][x]==op)i++;
|
|
|
|
if(i<8&&board[i][x]==p)
|
|
for(int j=y+1;j<i;j++)
|
|
board[j][x]=p;
|
|
}
|
|
void ChangeUp(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=y-1;
|
|
|
|
while(i>=0&&board[i][x]==op)i--;
|
|
|
|
if(i>=0&&board[i][x]==p)
|
|
for(int j=y-1;j>i;j--)
|
|
board[j][x]=p;
|
|
}
|
|
|
|
|
|
void ChangeUpRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1,j=y-1;
|
|
|
|
while(i<8&&j>=0&&board[j][i]==op){i++;j--;}
|
|
|
|
if(i<8&&j>=0&&board[j][i]==p){
|
|
int a=x+1,b=y-1;while(a<i&&b>j){board[b][a]=p;a++;b--;}
|
|
}
|
|
}
|
|
|
|
|
|
void ChangeUpLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1,j=y-1;
|
|
|
|
while(i>=0&&j>=0&&board[j][i]==op){i--;j--;}
|
|
|
|
if(i>=0&&j>=0&&board[j][i]==p){
|
|
int a=x-1,b=y-1;
|
|
while(a>i&&b>j){
|
|
board[b][a]=p;
|
|
a--;
|
|
b--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ChangeDownRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1,j=y+1;
|
|
|
|
while(i<8&&j<8&&board[j][i]==op){i++;j++;}
|
|
|
|
if(i<8&&j<8&&board[j][i]==p){
|
|
int a=x+1,b=y+1;
|
|
while(a<i&&b<j){
|
|
board[b][a]=p;
|
|
a++;
|
|
b++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ChangeDownLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1,j=y+1;
|
|
|
|
while(i>=0&&j<8&&board[j][i]==op){i--;j++;}
|
|
|
|
if(i>=0&&j<8&&board[j][i]==p){
|
|
int a=x-1,b=y+1;
|
|
while(a>i&&b<j){
|
|
board[b][a]=p;
|
|
a--;
|
|
b++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ChangeAll(int x,int y,char p){
|
|
ChangeRight(x,y,p); ChangeLeft(x,y,p); ChangeUp(x,y,p); ChangeDown(x,y,p);
|
|
ChangeUpRight(x,y,p); ChangeUpLeft(x,y,p); ChangeDownRight(x,y,p); ChangeDownLeft(x,y,p);
|
|
}
|
|
|
|
// ---------- Check Valid Moves ----------
|
|
bool CheckRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1;
|
|
|
|
if(i>=8||board[y][i]!=op) return false;
|
|
|
|
while(i<8&&board[y][i]==op)i++;
|
|
return (i<8&&board[y][i]==p);
|
|
}
|
|
|
|
|
|
bool CheckLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1;
|
|
|
|
if(i<0||board[y][i]!=op) return false;
|
|
|
|
while(i>=0&&board[y][i]==op)i--;
|
|
|
|
return (i>=0 && board[y][i]==p);
|
|
}
|
|
|
|
|
|
bool CheckDown(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=y+1;
|
|
|
|
if(i>=8||board[i][x]!=op) return false;
|
|
|
|
while(i<8&&board[i][x]==op)i++;
|
|
|
|
return (i<8&&board[i][x]==p);
|
|
}
|
|
|
|
|
|
bool CheckUp(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=y-1;
|
|
|
|
if(i<0||board[i][x]!=op) return false;
|
|
|
|
while(i>=0&&board[i][x]==op)i--;
|
|
|
|
return (i>=0&&board[i][x]==p);
|
|
}
|
|
|
|
|
|
bool CheckUpRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1,j=y-1;
|
|
|
|
if(i>=8||j<0||board[j][i]!=op) return false;
|
|
|
|
while(i<8&&j>=0&&board[j][i]==op){i++;j--;}
|
|
|
|
return (i<8&&j>=0&&board[j][i]==p);
|
|
|
|
}
|
|
|
|
|
|
bool CheckUpLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1,j=y-1;
|
|
|
|
if(i<0||j<0||board[j][i]!=op) return false;
|
|
|
|
while(i>=0&&j>=0&&board[j][i]==op){i--;j--;}
|
|
|
|
return (i>=0&&j>=0&&board[j][i]==p);
|
|
|
|
}
|
|
|
|
|
|
bool CheckDownRight(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x+1,j=y+1;
|
|
|
|
if(i>=8||j>=8||board[j][i]!=op) return false;
|
|
|
|
while(i<8&&j<8&&board[j][i]==op){i++;j++;}
|
|
|
|
return (i<8&&j<8&&board[j][i]==p);
|
|
|
|
}
|
|
|
|
|
|
bool CheckDownLeft(int x,int y,char p){
|
|
|
|
char op=Opponent(p);
|
|
int i=x-1,j=y+1;
|
|
|
|
if(i<0||j>=8||board[j][i]!=op) return false;
|
|
|
|
while(i>=0&&j<8&&board[j][i]==op){i--;j++;}
|
|
|
|
return (i>=0&&j<8&&board[j][i]==p);
|
|
|
|
}
|
|
|
|
|
|
bool ValidMove(int x,int y,char p){
|
|
if(board[y][x]!='_') return false;
|
|
return CheckRight(x,y,p) || CheckLeft(x,y,p) || CheckUp(x,y,p) || CheckDown(x,y,p) ||
|
|
CheckUpRight(x,y,p) || CheckUpLeft(x,y,p) || CheckDownRight(x,y,p) || CheckDownLeft(x,y,p);
|
|
}
|
|
|
|
void EnableANSI() {
|
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
DWORD dwMode = 0;
|
|
GetConsoleMode(hOut, &dwMode);
|
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
|
SetConsoleMode(hOut, dwMode);
|
|
}
|
|
|
|
|
|
// ----- main-------
|
|
int main() {
|
|
|
|
|
|
|
|
EnableANSI();
|
|
SetConsoleOutputCP(CP_UTF8);
|
|
SetConsoleCP(CP_UTF8);
|
|
|
|
int choice = 0;
|
|
while (true) {
|
|
|
|
DrawMenu(choice);
|
|
char input = _getch(); // Get key without enter
|
|
|
|
if (input == 'w' || input == 'W') {
|
|
choice--;
|
|
if (choice < 0) choice = 4;
|
|
}
|
|
else if (input == 's' || input == 'S') {
|
|
choice++;
|
|
if (choice > 4) choice = 0;
|
|
} else if (input == '\r') { // Enter key
|
|
if (choice == 0) { // New Game
|
|
int newChoice = 0;
|
|
while (true) {
|
|
DrawNewGameMenu(newChoice);
|
|
|
|
char newInput = _getch();
|
|
|
|
if (newInput == 'w' || newInput == 'W') {
|
|
newChoice--;
|
|
if (newChoice < 0) newChoice = 2;
|
|
} else if (newInput == 's' || newInput == 'S') {
|
|
newChoice++;
|
|
if (newChoice > 2) newChoice = 0;
|
|
} else if (newInput == '\r') {
|
|
if (newChoice == 0) {
|
|
ModeType(1);
|
|
break;
|
|
}
|
|
else if (newChoice == 1) {
|
|
ModeType(2);
|
|
break;
|
|
}
|
|
else if (newChoice == 2)
|
|
break; // Back to main menu
|
|
}
|
|
}
|
|
}
|
|
else if (choice == 1) {
|
|
|
|
Sleep(800);
|
|
if(!LoadGame()){
|
|
cout << "No unfinished game found!";
|
|
Sleep(1500);
|
|
continue;
|
|
}
|
|
|
|
cursor = {0,0};
|
|
StartGame(true);
|
|
}
|
|
else if (choice == 2) {
|
|
system("cls");
|
|
Sleep(800);
|
|
cout<< " W : up \n S : down \n A : left \n D : right\n"
|
|
<< " SPACE : place the circles\n"
|
|
<< " ENTER : fix the cell && change the turn \n"
|
|
<< " ESC : Close The Game \n"
|
|
<< " <<---" << RED << " -- PRESS ANY KEY TO RETURN TO MENU -- " << RESET << "--->>";
|
|
|
|
WaitForAnyKey();
|
|
}
|
|
else if (choice == 3) {
|
|
|
|
system("cls");
|
|
WaitForKeyRelease();
|
|
ClearInputBuffer();
|
|
|
|
ShowHistory();
|
|
|
|
}
|
|
else if (choice == 4) {
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|