Initial commit on develop branch
This commit is contained in:
@@ -0,0 +1,83 @@
|
|||||||
|
#include "codes/Database/GameHistoryManager.h"
|
||||||
|
#include "codes/Structures/Config.h"
|
||||||
|
#include "codes/ConfigModifier.h"
|
||||||
|
#include "codes/GameMaster.h"
|
||||||
|
#include "codes/GameReporter.h"
|
||||||
|
#include "codes/GameReviewer.h"
|
||||||
|
#include "codes/Helper.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
Config::initialize();
|
||||||
|
syncGameHistoryWithLimit();
|
||||||
|
|
||||||
|
int chosenOption = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Welcome to Othello game!" << std::endl
|
||||||
|
<< (chosenOption == 0 ? " > ":" ") << " new game" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " > ":" ") << " load game" << std::endl
|
||||||
|
<< (chosenOption == 2 ? " > ":" ") << " help" << std::endl
|
||||||
|
<< (chosenOption == 3 ? " > ":" ") << " games history" << std::endl
|
||||||
|
<< (chosenOption == 4 ? " > ":" ") << " settings" << std::endl
|
||||||
|
<< (chosenOption == 5 ? " > ":" ") << " exit" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption > 0)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption < 5)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
executeGameMaster(false);
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
executeGameMaster(true);
|
||||||
|
}
|
||||||
|
else if (chosenOption == 2)
|
||||||
|
{
|
||||||
|
executeHelper();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 3)
|
||||||
|
{
|
||||||
|
executeGameReporter();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 4)
|
||||||
|
{
|
||||||
|
executeConfigModifier();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 5)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
#include "ConfigModifier.h"
|
||||||
|
#include "Database/ConfigManager.h"
|
||||||
|
#include "Database/GameHistoryManager.h"
|
||||||
|
#include <conio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <limits>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool madeChanges = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleGameHistoryLimit();
|
||||||
|
void handleBoardSize();
|
||||||
|
void handlShowAvailablePlacesToPieces();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void executeConfigModifier()
|
||||||
|
{
|
||||||
|
int chosenOption = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "current setting are:" << std::endl
|
||||||
|
<< "The number of games inside game history: " << getGameHistoryLimit() << std::endl
|
||||||
|
<< "The size of the board: " << getBoardSize() << std::endl
|
||||||
|
<< "Show available places for pieces: " << (getShowAvailablePlacesForPieces() ? "Yes":"No") << std::endl << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Which of these properties do you wish to change?" << std::endl;
|
||||||
|
|
||||||
|
std::cout << (chosenOption == 0 ? " >":" ") << " The number of games inside game history" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " >":" ") << " The size of the board" << std::endl
|
||||||
|
<< (chosenOption == 2 ? " >":" ") << " Showing avaibale places for pieces" << std::endl
|
||||||
|
<< (chosenOption == 3 ? " >":" ") << " Apply the changes and exit" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption > 0)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption < 3)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
handleGameHistoryLimit();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
handleBoardSize();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 2)
|
||||||
|
{
|
||||||
|
handlShowAvailablePlacesToPieces();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 3)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
if (madeChanges == false) std::cout << "No changes has been made\nPress any key to continue";
|
||||||
|
else if (madeChanges == true) std::cout << "Please restart the game for changes to be applied to the game\nPress any key to continue";
|
||||||
|
|
||||||
|
getch();
|
||||||
|
system("cls");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleGameHistoryLimit()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "the current value of the number of games inside game history is "
|
||||||
|
<< getGameHistoryLimit() << std::endl
|
||||||
|
<< "Please set the new value: " << std::endl;
|
||||||
|
|
||||||
|
int newValue;
|
||||||
|
|
||||||
|
std::cin >> newValue;
|
||||||
|
|
||||||
|
if (getGameHistoryLimit() == newValue)
|
||||||
|
{
|
||||||
|
return handleGameHistoryLimit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue > 100)
|
||||||
|
{
|
||||||
|
std::cout << "Inputed number is too big, you might face slow loading when recieving reports or loading games"
|
||||||
|
<< std::endl << "Do you procced? [Y/N]" << std::endl;
|
||||||
|
|
||||||
|
char procceded;
|
||||||
|
std::cin >> procceded;
|
||||||
|
|
||||||
|
if (!(procceded == 'Y' || procceded == 'y'))
|
||||||
|
{
|
||||||
|
return handleGameHistoryLimit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyGameHistoryLimit(newValue);
|
||||||
|
syncGameHistoryWithLimit();
|
||||||
|
std::cout << "Change has been made\nPress any key to continue";
|
||||||
|
getch();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleBoardSize()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "the current value of the size of the board is "
|
||||||
|
<< getBoardSize() << std::endl
|
||||||
|
<< "Please set the new value: " << std::endl;
|
||||||
|
|
||||||
|
int newValue;
|
||||||
|
|
||||||
|
std::cin >> newValue;
|
||||||
|
|
||||||
|
if (getBoardSize() == newValue)
|
||||||
|
{
|
||||||
|
return handleBoardSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue > 50)
|
||||||
|
{
|
||||||
|
std::cout << "Inputed number is too big, please set a number lower than or equal to 50\nPress any key to continue" << std::endl;
|
||||||
|
|
||||||
|
getch();
|
||||||
|
|
||||||
|
return handleBoardSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newValue % 2 == 1)
|
||||||
|
{
|
||||||
|
std::cout << "Board size cannot be an odd number, please set an even number\nPress any key to continue";
|
||||||
|
|
||||||
|
getch();
|
||||||
|
|
||||||
|
return handleBoardSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
modifyBoardSize(newValue);
|
||||||
|
std::cout << "Change has been made\nPress any key to continue";
|
||||||
|
getch();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handlShowAvailablePlacesToPieces()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
bool curValue = getShowAvailablePlacesForPieces();
|
||||||
|
|
||||||
|
std::cout << (curValue ?
|
||||||
|
"Currently, you will see available places for putting your piece durning the game":
|
||||||
|
"Currently, you won't see available places for putting your piece durning the game"
|
||||||
|
) << std::endl;
|
||||||
|
|
||||||
|
std::cout << "Do you proceed to change the behavour? [Y/N]" << std::endl;
|
||||||
|
|
||||||
|
char procceded;
|
||||||
|
std::cin >> procceded;
|
||||||
|
|
||||||
|
if (!(procceded == 'Y' || procceded == 'y'))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
madeChanges = true;
|
||||||
|
if (curValue)
|
||||||
|
{
|
||||||
|
modifyShowAvailablePlacesForPieces(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
modifyShowAvailablePlacesForPieces(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Change has been made\nPress any key to continue";
|
||||||
|
getch();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void executeConfigModifier();
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
GAME_HISTORY_LIMIT = 100
|
||||||
|
BOARD_SIZE = 8
|
||||||
|
BOARD_COLOR = black
|
||||||
|
BOARD_BORDER_COLOR = white
|
||||||
|
SOUND = 0
|
||||||
|
SHOW_AVAILABLE_PLACES_FOR_PIECES = 1
|
||||||
|
HINT = 0
|
||||||
|
HINT_LIMIT = 3
|
||||||
|
}
|
||||||
@@ -0,0 +1,201 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include "../Utilities/StrToInt.h"
|
||||||
|
#include "../utilities/IntToStr.h"
|
||||||
|
#include "ConfigManager.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string getElementOfConfig(int index);
|
||||||
|
int getGameHistoryLimit();
|
||||||
|
int getBoardSize();
|
||||||
|
std::string getBoardColor();
|
||||||
|
std::string getBoardBorderColor();
|
||||||
|
bool getSound();
|
||||||
|
bool getShowAvailablePlacesForPieces();
|
||||||
|
bool getHint();
|
||||||
|
int getHintLimit();
|
||||||
|
void modifyElementOfConfig(int index, string newValue);
|
||||||
|
void modifyGameHistoryLimit(int);
|
||||||
|
void modifyBoardSize(int);
|
||||||
|
void modifyBoardColor(std::string);
|
||||||
|
void modifyBoardBorderColor(std::string);
|
||||||
|
void modifySound(bool);
|
||||||
|
void modifyShowAvailablePlacesForPieces(bool);
|
||||||
|
void modifyHint(bool);
|
||||||
|
void modifyHintLimit(int);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
string getElementOfConfig(int index)
|
||||||
|
{
|
||||||
|
if (index > 7)
|
||||||
|
{
|
||||||
|
throw 2; // out of bond
|
||||||
|
}
|
||||||
|
|
||||||
|
ifstream file ("codes/Database/Config.txt");
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read the file
|
||||||
|
}
|
||||||
|
|
||||||
|
string line;
|
||||||
|
|
||||||
|
for (int i{0}; i <= index + 1; i++)
|
||||||
|
{
|
||||||
|
getline(file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
int startingIndex = line.find("=") + 2;
|
||||||
|
string result = line.substr(startingIndex, line.size());
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyElementOfConfig(int index, string newValue)
|
||||||
|
{
|
||||||
|
if (index > 7)
|
||||||
|
{
|
||||||
|
throw 2; // out of bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream fileToRead("codes/Database/Config.txt");
|
||||||
|
if (!fileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read the file
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string lines[10];
|
||||||
|
|
||||||
|
for (int i{0}; i < 10; i++)
|
||||||
|
{
|
||||||
|
getline(fileToRead, lines[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileToRead.close();
|
||||||
|
|
||||||
|
string targetLine = lines[index + 1];
|
||||||
|
int startingIndex = targetLine.find("=") + 2;
|
||||||
|
targetLine = targetLine.substr(0, startingIndex) + newValue;
|
||||||
|
lines[index + 1] = targetLine;
|
||||||
|
|
||||||
|
std::ofstream fileToWrite ("codes/Database/Config.txt");
|
||||||
|
if (!fileToWrite.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read the file
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::string l : lines)
|
||||||
|
{
|
||||||
|
fileToWrite << l << "\n";
|
||||||
|
}
|
||||||
|
fileToWrite.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getGameHistoryLimit()
|
||||||
|
{
|
||||||
|
return strToInt(getElementOfConfig(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getBoardSize()
|
||||||
|
{
|
||||||
|
return strToInt(getElementOfConfig(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string getBoardColor()
|
||||||
|
{
|
||||||
|
return getElementOfConfig(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string getBoardBorderColor()
|
||||||
|
{
|
||||||
|
return getElementOfConfig(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool getSound()
|
||||||
|
{
|
||||||
|
int intBool = strToInt(getElementOfConfig(4));
|
||||||
|
return static_cast<bool>(intBool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool getShowAvailablePlacesForPieces()
|
||||||
|
{
|
||||||
|
int intBool = strToInt(getElementOfConfig(5));
|
||||||
|
return static_cast<bool>(intBool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool getHint()
|
||||||
|
{
|
||||||
|
int intBool = strToInt(getElementOfConfig(6));
|
||||||
|
return static_cast<bool>(intBool);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getHintLimit()
|
||||||
|
{
|
||||||
|
return strToInt(getElementOfConfig(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyGameHistoryLimit(int gameHistoryLimit)
|
||||||
|
{
|
||||||
|
modifyElementOfConfig(0, intToStr(gameHistoryLimit));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyBoardSize(int boardSize)
|
||||||
|
{
|
||||||
|
modifyElementOfConfig(1, intToStr(boardSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyBoardColor(string color)
|
||||||
|
{
|
||||||
|
modifyElementOfConfig(2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyBoardBorderColor(string color)
|
||||||
|
{
|
||||||
|
modifyElementOfConfig(3, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifySound(bool sound)
|
||||||
|
{
|
||||||
|
int soundToSave = static_cast<int>(sound);
|
||||||
|
modifyElementOfConfig(4, intToStr(soundToSave));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyShowAvailablePlacesForPieces(bool newValue)
|
||||||
|
{
|
||||||
|
int newValueToSave = static_cast<int>(newValue);
|
||||||
|
modifyElementOfConfig(5, intToStr(newValueToSave));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyHint(bool hint)
|
||||||
|
{
|
||||||
|
int hintToSave = static_cast<int>(hint);
|
||||||
|
modifyElementOfConfig(6, intToStr(hintToSave));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void modifyHintLimit(int hintLimit)
|
||||||
|
{
|
||||||
|
modifyElementOfConfig(7, intToStr(hintLimit));
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int getGameHistoryLimit();
|
||||||
|
int getBoardSize();
|
||||||
|
std::string getBoardColor();
|
||||||
|
std::string getBoardBorderColor();
|
||||||
|
bool getSound();
|
||||||
|
bool getShowAvailablePlacesForPieces();
|
||||||
|
bool getHint();
|
||||||
|
int getHintLimit();
|
||||||
|
|
||||||
|
void modifyGameHistoryLimit(int);
|
||||||
|
void modifyBoardSize(int);
|
||||||
|
void modifyBoardColor(std::string);
|
||||||
|
void modifyBoardBorderColor(std::string);
|
||||||
|
void modifySound(bool);
|
||||||
|
void modifyShowAvailablePlacesForPieces(bool);
|
||||||
|
void modifyHint(bool);
|
||||||
|
void modifyHintLimit(int);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[0][.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|W|B|.|.|.|.|.|.|W|B|B|.|.|.|.|.|W|B|W|.|.|.|.|.|B|.|.|.|.|.|.|B|W|.|.|.|.|.|.|.|.|.|.|.|.|.][2Player][ramtin|W][farzad|W][W][0]
|
||||||
|
[1][.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|W|B|.|.|.|.|.|B|B|B|B|.|.|.|.|W|W|W|W|.|.|.|.|.|.|B|B|W|.|.|.|.|W|B|B|.|.|.|.|.|.|.|.|.|.|.][2Player][ramtin|W][farzad|B][B][0]
|
||||||
|
[2][W|W|W|W|W|W|W|W|W|B|B|B|B|W|B|W|W|W|W|W|B|B|W|W|W|B|W|W|W|W|B|W|W|B|W|W|W|W|B|W|W|W|W|W|B|W|W|W|W|B|B|B|W|W|W|W|W|W|W|W|W|W|B|W][1Player][ramtin|B][Hard Bot|3][W][2]
|
||||||
@@ -0,0 +1,391 @@
|
|||||||
|
// a saved game will follow this patter:
|
||||||
|
// [gameId][.|.|.|.][1Player][PlayerName|PlayerColor][BotName or PlayerName|BotColor or PlayerColor]['B'][0] and winner at the end
|
||||||
|
// GameBoard mode Player1 Player2 or Bot current turn
|
||||||
|
|
||||||
|
#include "../Structures/Config.h"
|
||||||
|
#include "../Structures/SinglePlayerGame.h"
|
||||||
|
#include "../Structures/MultiPlayerGame.h"
|
||||||
|
#include "../Utilities/StrToInt.h"
|
||||||
|
#include "../Utilities/IntSqrt.h"
|
||||||
|
#include "../Utilities/StrToSymbol.h"
|
||||||
|
#include "GameHistoryManager.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// file managing
|
||||||
|
void writeTempoToGameHistory();
|
||||||
|
void updateLine(int lineIndex, std::string str);
|
||||||
|
void addLine(std::string str);
|
||||||
|
void freeLastLine();
|
||||||
|
|
||||||
|
// internal uses
|
||||||
|
int getLinesCount();
|
||||||
|
std::string getProperty(int propertyId, std::string game);
|
||||||
|
int getGameId(std::string game);
|
||||||
|
int getSavedBoardElementCount(std::string board);
|
||||||
|
|
||||||
|
// adding data
|
||||||
|
void saveGame(SinglePlayerGame* game);
|
||||||
|
void saveGame(MultiPlayerGame* game);
|
||||||
|
|
||||||
|
// extracting data
|
||||||
|
std::string getGameById(int gameId);
|
||||||
|
int getLineIndexById(int gameId);
|
||||||
|
std::string getLineByLineIndex(int lineIndex);
|
||||||
|
|
||||||
|
// external uses
|
||||||
|
SinglePlayerGame getSinglePlayerGame(int id);
|
||||||
|
MultiPlayerGame getMultiPlayerGame(int id);
|
||||||
|
void syncGameHistoryWithLimit();
|
||||||
|
int getFirstGameId();
|
||||||
|
int getLastGameId();
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------- file managing --------------------------------------------------------------
|
||||||
|
void writeTempoToGameHistory()
|
||||||
|
{
|
||||||
|
std::ifstream tempoFileToRead("codes/Database/tempo.txt");
|
||||||
|
std::ofstream GameHistoryToWrite("codes/Database/GameHistory.txt");
|
||||||
|
|
||||||
|
if (!GameHistoryToWrite.is_open() && !tempoFileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (getline(tempoFileToRead, line))
|
||||||
|
{
|
||||||
|
GameHistoryToWrite << line << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
tempoFileToRead.close();
|
||||||
|
GameHistoryToWrite.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void freeLastLine()
|
||||||
|
{
|
||||||
|
std::ifstream GameHistoryToRead("codes/Database/GameHistory.txt");
|
||||||
|
std::ofstream tempoFileToWrite("codes/Database/tempo.txt");
|
||||||
|
|
||||||
|
if (!GameHistoryToRead.is_open() && !tempoFileToWrite.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
getline(GameHistoryToRead, line); // skipping the first line
|
||||||
|
|
||||||
|
while (getline(GameHistoryToRead, line))
|
||||||
|
{
|
||||||
|
tempoFileToWrite << line << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
tempoFileToWrite.close();
|
||||||
|
GameHistoryToRead.close();
|
||||||
|
|
||||||
|
writeTempoToGameHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void updateLine(int lineIndex, std::string str)
|
||||||
|
{
|
||||||
|
std::ifstream GameHistoryToRead("codes/Database/GameHistory.txt");
|
||||||
|
std::ofstream tempoFileToWrite("codes/Database/tempo.txt");
|
||||||
|
|
||||||
|
if (!GameHistoryToRead.is_open() && !tempoFileToWrite.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
int curLineIndex = 0;
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while (getline(GameHistoryToRead, line))
|
||||||
|
{
|
||||||
|
if (curLineIndex == lineIndex)
|
||||||
|
{
|
||||||
|
tempoFileToWrite << str << "\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tempoFileToWrite << line << "\n";
|
||||||
|
}
|
||||||
|
curLineIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempoFileToWrite.close();
|
||||||
|
GameHistoryToRead.close();
|
||||||
|
|
||||||
|
writeTempoToGameHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addLine(std::string str)
|
||||||
|
{
|
||||||
|
std::ofstream GameHistory("codes/Database/GameHistory.txt", std::ios::app);
|
||||||
|
|
||||||
|
GameHistory << str << "\n";
|
||||||
|
|
||||||
|
GameHistory.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------- internal use -----------------------------------------------
|
||||||
|
int getLinesCount()
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileToRead("codes/Database/GameHistory.txt");
|
||||||
|
|
||||||
|
if (!fileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
while (getline(fileToRead, line))
|
||||||
|
{
|
||||||
|
if (!line.empty()) count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string getProperty(int propertyId, std::string game)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < propertyId; i++)
|
||||||
|
{
|
||||||
|
int endingIndex = game.find("]");
|
||||||
|
game = game.substr(endingIndex + 1, game.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int EndingIndex = game.find("]");
|
||||||
|
std::string property = game.substr(
|
||||||
|
1, EndingIndex - 1
|
||||||
|
);
|
||||||
|
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getGameId(std::string game)
|
||||||
|
{
|
||||||
|
return strToInt(getProperty(0, game));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void syncGameHistoryWithLimit()
|
||||||
|
// has to be called when limit changes, so GameHistory.txt stays within its new limit
|
||||||
|
{
|
||||||
|
int curCount = getLinesCount();
|
||||||
|
int limit = Config::getInstance() -> GAME_HISTORY_LIMIT;
|
||||||
|
|
||||||
|
if (curCount > limit)
|
||||||
|
{
|
||||||
|
int toRemove = curCount - limit;
|
||||||
|
|
||||||
|
for (int i = 0; i < toRemove; i++)
|
||||||
|
{
|
||||||
|
freeLastLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getSavedBoardElementCount(std::string board)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (char element : board)
|
||||||
|
{
|
||||||
|
if (element == '|') count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//--------------------------------------------- adding data --------------------------------------------------
|
||||||
|
void saveGame(SinglePlayerGame* game)
|
||||||
|
{
|
||||||
|
int thisGameId = game -> id;
|
||||||
|
std::string gameToSave = game -> retrieveGame();
|
||||||
|
|
||||||
|
int lineIndex = getLineIndexById(thisGameId);
|
||||||
|
|
||||||
|
if (lineIndex == -1)
|
||||||
|
{
|
||||||
|
addLine(gameToSave);
|
||||||
|
syncGameHistoryWithLimit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateLine(lineIndex, gameToSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void saveGame(MultiPlayerGame* game)
|
||||||
|
{
|
||||||
|
int thisGameId = game -> id;
|
||||||
|
std::string gameToSave = game -> retrieveGame();
|
||||||
|
|
||||||
|
int lineIndex = getLineIndexById(thisGameId);
|
||||||
|
|
||||||
|
if (lineIndex == -1)
|
||||||
|
{
|
||||||
|
addLine(gameToSave);
|
||||||
|
syncGameHistoryWithLimit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateLine(lineIndex, gameToSave);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------- extraxting data --------------------------------------------------
|
||||||
|
std::string getGameById(int gameId)
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileToRead("codes/Database/GameHistory.txt");
|
||||||
|
|
||||||
|
if (!fileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
while (getline(fileToRead, line))
|
||||||
|
{
|
||||||
|
if (getGameId(line) == gameId)
|
||||||
|
{
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int getLineIndexById(int gameId)
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileToRead("codes/Database/GameHistory.txt");
|
||||||
|
|
||||||
|
if (!fileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
while (getline(fileToRead, line))
|
||||||
|
{
|
||||||
|
if (getGameId(line) == gameId)
|
||||||
|
{
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string getLineByLineIndex(int lineIndex)
|
||||||
|
{
|
||||||
|
std::string line;
|
||||||
|
std::ifstream fileToRead("codes/Database/GameHistory.txt");
|
||||||
|
|
||||||
|
if (!fileToRead.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // faild to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
int linesCount = getLinesCount();
|
||||||
|
for (int i = 0; i < linesCount; i++)
|
||||||
|
{
|
||||||
|
getline(fileToRead, line);
|
||||||
|
if (i == lineIndex) return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
//-------------------------------------------- external uses -----------------------------------------
|
||||||
|
int getFirstGameId()
|
||||||
|
{
|
||||||
|
int liensCount = getLinesCount();
|
||||||
|
|
||||||
|
if (liensCount == 0) return -1; // file is empty
|
||||||
|
|
||||||
|
std::string game = getLineByLineIndex(0);
|
||||||
|
return getGameId(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLastGameId()
|
||||||
|
{
|
||||||
|
int liensCount = getLinesCount();
|
||||||
|
|
||||||
|
if (liensCount == 0) return -1; // file is empty
|
||||||
|
|
||||||
|
std::string game = getLineByLineIndex(liensCount - 1);
|
||||||
|
return getGameId(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SinglePlayerGame getSinglePlayerGame(int id)
|
||||||
|
{
|
||||||
|
std::string savedGame = getGameById(id);
|
||||||
|
|
||||||
|
std::string savedBoard = getProperty(1, savedGame);
|
||||||
|
int boardSize = intSqrt(
|
||||||
|
getSavedBoardElementCount(savedBoard)
|
||||||
|
);
|
||||||
|
Board board {boardSize};
|
||||||
|
board.loadBoard(savedBoard);
|
||||||
|
|
||||||
|
Player player {"", 0};
|
||||||
|
player.loadPlayer(getProperty(3, savedGame));
|
||||||
|
|
||||||
|
Bot bot {"", 0};
|
||||||
|
bot.loadBot(getProperty(4, savedGame));
|
||||||
|
|
||||||
|
char turn = strToSymbol(getProperty(5, savedGame));
|
||||||
|
|
||||||
|
SinglePlayerGame game {&board, &player, &bot, turn};
|
||||||
|
|
||||||
|
game.id = id;
|
||||||
|
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MultiPlayerGame getMultiPlayerGame(int id)
|
||||||
|
{
|
||||||
|
std::string savedGame = getGameById(id);
|
||||||
|
|
||||||
|
std::string savedBoard = getProperty(1, savedGame);
|
||||||
|
int boardSize = intSqrt(
|
||||||
|
getSavedBoardElementCount(savedBoard)
|
||||||
|
);
|
||||||
|
Board board {boardSize};
|
||||||
|
board.loadBoard(savedBoard);
|
||||||
|
|
||||||
|
Player player1 {"", 0};
|
||||||
|
player1.loadPlayer(getProperty(3, savedGame));
|
||||||
|
|
||||||
|
Player player2 {"", 0};
|
||||||
|
player2.loadPlayer(getProperty(4, savedGame));
|
||||||
|
|
||||||
|
char turn = strToSymbol(getProperty(5, savedGame));
|
||||||
|
|
||||||
|
MultiPlayerGame game {&board, &player1, &player2, turn};
|
||||||
|
|
||||||
|
game.id = id;
|
||||||
|
|
||||||
|
return game;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "../Structures/MultiPlayerGame.h"
|
||||||
|
#include "../Structures/SinglePlayerGame.h"
|
||||||
|
|
||||||
|
void saveGame(SinglePlayerGame* game);
|
||||||
|
void saveGame(MultiPlayerGame* game);
|
||||||
|
SinglePlayerGame getSinglePlayerGame(int id);
|
||||||
|
MultiPlayerGame getMultiPlayerGame(int id);
|
||||||
|
std::string getGameById(int gameId);
|
||||||
|
void syncGameHistoryWithLimit();
|
||||||
|
std::string getProperty(int propertyId, std::string game);
|
||||||
|
int getSavedBoardElementCount(std::string board);
|
||||||
|
int getGameId(std::string game);
|
||||||
|
int getFirstGameId();
|
||||||
|
int getLastGameId();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
1 3 B
|
||||||
|
1 4 W
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#include "../Structures/Move.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void clearGameLog();
|
||||||
|
void addLog(Move move);
|
||||||
|
int countLogs();
|
||||||
|
Move getLog(int logIndex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void clearGameLog()
|
||||||
|
{
|
||||||
|
std::ofstream file ("codes/Database/GameLog.txt", std::ios::trunc);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void addLog(Move move)
|
||||||
|
{
|
||||||
|
std::ofstream file("codes/Database/GameLog.txt", std::ios::app);
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read file
|
||||||
|
}
|
||||||
|
|
||||||
|
file << move.retrieveMove() << "\n";
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int countLogs()
|
||||||
|
{
|
||||||
|
int logCount = 0;
|
||||||
|
std::ifstream file("codes/Database/GameLog.txt");
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
while(std::getline(file, line))
|
||||||
|
{
|
||||||
|
if (line.empty()) continue;
|
||||||
|
|
||||||
|
logCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Move getLog(int logIndex)
|
||||||
|
{
|
||||||
|
std::ifstream file ("codes/Database/GameLog.txt");
|
||||||
|
if (!file.is_open())
|
||||||
|
{
|
||||||
|
throw 1; // failed to read the file
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
|
||||||
|
for (int i{0}; i <= logIndex; i++)
|
||||||
|
{
|
||||||
|
std::getline(file, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
Move move{0, 0, '0'};
|
||||||
|
|
||||||
|
move.loadMove(line);
|
||||||
|
|
||||||
|
return move;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Structures/Move.h"
|
||||||
|
|
||||||
|
void clearGameLog();
|
||||||
|
void addLog(Move move);
|
||||||
|
int countLogs();
|
||||||
|
Move getLog(int logIndex);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[0][.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|W|B|.|.|.|.|.|.|W|B|B|.|.|.|.|.|W|B|W|.|.|.|.|.|B|.|.|.|.|.|.|B|W|.|.|.|.|.|.|.|.|.|.|.|.|.][2Player][ramtin|W][farzad|W][W][0]
|
||||||
|
[1][.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|W|B|.|.|.|.|.|B|B|B|B|.|.|.|.|W|W|W|W|.|.|.|.|.|.|B|B|W|.|.|.|.|W|B|B|.|.|.|.|.|.|.|.|.|.|.][2Player][ramtin|W][farzad|B][B][0]
|
||||||
|
[2][W|W|W|W|W|W|W|W|W|B|B|B|B|W|B|W|W|W|W|W|B|B|W|W|W|B|W|W|W|W|B|W|W|B|W|W|W|W|B|W|W|W|W|W|B|W|W|W|W|B|B|B|W|W|W|W|W|W|W|W|W|W|B|W][1Player][ramtin|B][Hard Bot|3][W][2]
|
||||||
@@ -0,0 +1,483 @@
|
|||||||
|
#include <windows.h>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <limits>
|
||||||
|
#include "GameMaster.h"
|
||||||
|
#include "Database/GameLogManager.h"
|
||||||
|
#include "GameReviewer.h"
|
||||||
|
#include "Database/GameHistoryManager.h"
|
||||||
|
#include "Structures/Board.h"
|
||||||
|
#include "Structures/Player.h"
|
||||||
|
#include "Structures/Bot.h"
|
||||||
|
#include "Structures/SinglePlayerGame.h"
|
||||||
|
#include "Structures/MultiPlayerGame.h"
|
||||||
|
#include "Structures/Config.h"
|
||||||
|
#include "Utilities/outputDecoratedSavedGame.h"
|
||||||
|
#include "Utilities/GetSavedBoardSize.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
void handleLoadGame();
|
||||||
|
void handleNewGame();
|
||||||
|
void loadSinglePlayerGame(int gameId);
|
||||||
|
void loadMultiPlayerGame(int gameId);
|
||||||
|
void handleSinglePlayerNewGame();
|
||||||
|
void handleMultiPlayerNewGame();
|
||||||
|
|
||||||
|
void executeGameMaster(bool loadGameMode)
|
||||||
|
{
|
||||||
|
clearGameLog(); // emptying GameLog for the new game
|
||||||
|
|
||||||
|
if (loadGameMode) handleLoadGame();
|
||||||
|
else handleNewGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleLoadGame()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "You've chosen to load a previous unfinished game\n"
|
||||||
|
<< "Previous unfunished games are: \n";
|
||||||
|
|
||||||
|
int startingGameId = getFirstGameId();
|
||||||
|
int lastGameId = getLastGameId();
|
||||||
|
|
||||||
|
if (startingGameId == -1)
|
||||||
|
{
|
||||||
|
std::cout << "\n There are no games inside game history\n Press any key to continue";
|
||||||
|
getch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = startingGameId; i <= lastGameId; i++)
|
||||||
|
{
|
||||||
|
if (getProperty(6, getGameById(i)) == "0")
|
||||||
|
{
|
||||||
|
outputDecoratedSavedGame(getGameById(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int gameId;
|
||||||
|
std::string wantedGame;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::cout << "\n Please type the id of the game you wish to continue playing: ";
|
||||||
|
|
||||||
|
std::cin >> gameId;
|
||||||
|
|
||||||
|
std::string savedGame = getGameById(gameId);
|
||||||
|
|
||||||
|
if (getProperty(6, savedGame) != "0")
|
||||||
|
{
|
||||||
|
std::cout << "The id entered belong to a finished game, please choose an id from the given list\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wantedGame = savedGame;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getProperty(2, wantedGame) == "1Player")
|
||||||
|
{
|
||||||
|
loadSinglePlayerGame(gameId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loadMultiPlayerGame(gameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void loadSinglePlayerGame(int gameId)
|
||||||
|
{
|
||||||
|
int id = getSinglePlayerGame(gameId).id;
|
||||||
|
Board board = *(getSinglePlayerGame(gameId).GameBoard);
|
||||||
|
Player player = *(getSinglePlayerGame(gameId).Player1);
|
||||||
|
Bot bot = *(getSinglePlayerGame(gameId).GameBot);
|
||||||
|
char CurrentTurnColor = getSinglePlayerGame(gameId).CurrentTurnColor;
|
||||||
|
|
||||||
|
SinglePlayerGame game {&board, &player, &bot, CurrentTurnColor};
|
||||||
|
game.id = id;
|
||||||
|
game.Winner = 0;
|
||||||
|
game.mode = "1Player";
|
||||||
|
|
||||||
|
game.start();
|
||||||
|
|
||||||
|
std::cout << "\n The game has finished, Press any key to continue" << std::endl;
|
||||||
|
|
||||||
|
getch();
|
||||||
|
|
||||||
|
game.GameBoard -> deleteBoardMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void loadMultiPlayerGame(int gameId)
|
||||||
|
{
|
||||||
|
int id = getMultiPlayerGame(gameId).id;
|
||||||
|
Board board = *(getMultiPlayerGame(gameId).GameBoard);
|
||||||
|
Player player1 = *(getMultiPlayerGame(gameId).Player1);
|
||||||
|
Player player2 = *(getMultiPlayerGame(gameId).Player2);
|
||||||
|
char CurrentTurnColor = getMultiPlayerGame(gameId).CurrentTurnColor;
|
||||||
|
|
||||||
|
MultiPlayerGame game {&board, &player1, &player2, CurrentTurnColor};
|
||||||
|
game.id = id;
|
||||||
|
game.Winner = 0;
|
||||||
|
game.mode = "2Player";
|
||||||
|
|
||||||
|
game.start();
|
||||||
|
|
||||||
|
std::cout << "\n The game has finished, Press any key to continue" << std::endl;
|
||||||
|
|
||||||
|
getch();
|
||||||
|
|
||||||
|
game.GameBoard -> deleteBoardMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleNewGame()
|
||||||
|
{
|
||||||
|
int chosenOption = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << (chosenOption == 0 ? " > ":" ") << " Single Player" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " > ":" ") << " MultiPlayer" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
handleSinglePlayerNewGame();
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
handleMultiPlayerNewGame();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleSinglePlayerNewGame()
|
||||||
|
{
|
||||||
|
Bot bot{"0", 0};
|
||||||
|
|
||||||
|
int chosenOption = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Please choose the difficulty: \n"
|
||||||
|
<< (chosenOption == 0 ? " > ":" ") << " Easy" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " > ":" ") << " Medium" << std::endl
|
||||||
|
<< (chosenOption == 2 ? " > ":" ") << " Hard" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption != 0)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption != 2)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
bot.difficulty = 1;
|
||||||
|
bot.name = "Easy Bot";
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
bot.difficulty = 2;
|
||||||
|
bot.name = "Medium Bot";
|
||||||
|
}
|
||||||
|
else if (chosenOption == 2)
|
||||||
|
{
|
||||||
|
bot.difficulty = 3;
|
||||||
|
bot.name = "Hard Bot";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player{"0", 'W'};
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::cout << "Please set your name: ";
|
||||||
|
std::cin >> name;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
if (name.find("|") != -1 || name.find("[") != -1 || name.find("]") != -1)
|
||||||
|
{
|
||||||
|
std::cout << "One day you will die"
|
||||||
|
<< "\nSome poeple will attend your funeral only for the food"
|
||||||
|
<< "\nYour friends will hang out again after 1 month"
|
||||||
|
<< "\nYour kids will go to work casually after 2 months"
|
||||||
|
<< "\nYour wife/husband will laugh with a comedy movie after 6 month"
|
||||||
|
<< "\nEventually, your name will be forgotten and memories of you fade away"
|
||||||
|
<< "\nYet some poeple like you think they can escape this fact by putting | or [ or ] inside their names"
|
||||||
|
<< "\nYou guys think noone is going to forget your name because they be like:"
|
||||||
|
<< "\n Damn bro this guy has a | or [ or ] inside their name! I'm going to remember this name till my last breath"
|
||||||
|
<< "\nLet's be real, nobody will say that unless they're high and high poeple can't remember anything more than 5 seconds"
|
||||||
|
<< "\nSo stop annoying me and choose a name without | or [ or ]"
|
||||||
|
<< "\nNow click any freaking key to continue...";
|
||||||
|
|
||||||
|
getch();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
player.name = name;
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
chosenOption = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Please choose your color\n"
|
||||||
|
<< (chosenOption == 0 ? " > ":" ") << " Black" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " > ":" ") << " White" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
player.color = 'B';
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
player.color = 'W';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
Board board{Config::instance -> BOARD_SIZE};
|
||||||
|
|
||||||
|
board.newGameSetup();
|
||||||
|
|
||||||
|
SinglePlayerGame game{&board, &player, &bot, 'B'};
|
||||||
|
|
||||||
|
game.start();
|
||||||
|
|
||||||
|
std::cout << "\n The game has finished, would you like to see the replay? [Y/N]" << std::endl;
|
||||||
|
|
||||||
|
char procceded;
|
||||||
|
std::cin >> procceded;
|
||||||
|
|
||||||
|
if (procceded == 'Y' || procceded == 'y')
|
||||||
|
{
|
||||||
|
executeGameReviewer(*game.GameBoard);
|
||||||
|
}
|
||||||
|
|
||||||
|
game.GameBoard -> deleteBoardMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void handleMultiPlayerNewGame()
|
||||||
|
{
|
||||||
|
Player player1{"0", 'W'};
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::cout << "Player1, Please set your name: ";
|
||||||
|
std::cin >> name;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
if (name.find("|") != -1 || name.find("[") != -1 || name.find("]") != -1)
|
||||||
|
{
|
||||||
|
std::cout << "One day you will die"
|
||||||
|
<< "\nSome poeple will attend your funeral only for the food"
|
||||||
|
<< "\nYour friends will hang out again after 1 month"
|
||||||
|
<< "\nYour kids will go to work casually after 2 months"
|
||||||
|
<< "\nYour wife/husband will laugh with a comedy movie after 6 month"
|
||||||
|
<< "\nEventually, your name will be forgotten and memories of you fade away"
|
||||||
|
<< "\nYet some poeple like you think they can escape this fact by putting | or [ or ] inside their names"
|
||||||
|
<< "\nYou guys think noone is going to forget your name because they be like:"
|
||||||
|
<< "\n Damn bro this guy has a | or [ or ] inside their name! I'm going to remember this name till my last breath"
|
||||||
|
<< "\nLet's be real, nobody will say that unless they're high and high poeple can't remember anything more than 5 seconds"
|
||||||
|
<< "\nSo stop annoying me and choose a name without | or [ or ]"
|
||||||
|
<< "\nNow click any freaking key to continue...";
|
||||||
|
|
||||||
|
getch();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
player1.name = name;
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chosenOption = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Player1, please choose your color\n"
|
||||||
|
<< (chosenOption == 0 ? " > ":" ") << " Black" << std::endl
|
||||||
|
<< (chosenOption == 1 ? " > ":" ") << " White" << std::endl;
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
chosenOption--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
chosenOption++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userInput == 13)
|
||||||
|
{
|
||||||
|
if (chosenOption == 0)
|
||||||
|
{
|
||||||
|
player1.color = 'B';
|
||||||
|
}
|
||||||
|
else if (chosenOption == 1)
|
||||||
|
{
|
||||||
|
player1.color = 'W';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player2{"0", 'W'};
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::cout << "Player2, Please set your name: ";
|
||||||
|
std::cin >> name;
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
if (name.find("|") != -1 || name.find("[") != -1 || name.find("]") != -1)
|
||||||
|
{
|
||||||
|
std::cout << "One day you will die"
|
||||||
|
<< "\nSome poeple will attend your funeral only for the food"
|
||||||
|
<< "\nYour friends will hang out again after 1 month"
|
||||||
|
<< "\nYour kids will go to work casually after 2 months"
|
||||||
|
<< "\nYour wife/husband will laugh with a comedy movie after 6 month"
|
||||||
|
<< "\nEventually, your name will be forgotten and memories of you fade away"
|
||||||
|
<< "\nYet some poeple like you think they can escape this fact by putting | or [ or ] inside their names"
|
||||||
|
<< "\nYou guys think noone is going to forget your name because they be like:"
|
||||||
|
<< "\n Damn bro this guy has a | or [ or ] inside their name! I'm going to remember this name till my last breath"
|
||||||
|
<< "\nLet's be real, nobody will say that unless they're high and high poeple can't remember anything more than 5 seconds"
|
||||||
|
<< "\nSo stop annoying me and choose a name without | or [ or ]"
|
||||||
|
<< "\nNow click any freaking key to continue...";
|
||||||
|
|
||||||
|
getch();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
player2.name = name;
|
||||||
|
player2.color = (player1.color == 'W' ? 'B':'W');
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
Board board{Config::getInstance() -> BOARD_SIZE};
|
||||||
|
|
||||||
|
board.newGameSetup();
|
||||||
|
|
||||||
|
MultiPlayerGame game{&board, &player1, &player2, 'B'};
|
||||||
|
|
||||||
|
game.start();
|
||||||
|
|
||||||
|
std::cout << "\n The game has finished, would you like to see the replay? [Y/N]" << std::endl;
|
||||||
|
|
||||||
|
char procceded;
|
||||||
|
std::cin >> procceded;
|
||||||
|
|
||||||
|
if (procceded == 'Y' || procceded == 'y')
|
||||||
|
{
|
||||||
|
executeGameReviewer(*game.GameBoard);
|
||||||
|
}
|
||||||
|
|
||||||
|
game.GameBoard -> deleteBoardMemory();
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void executeGameMaster(bool loadGameMode);
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <conio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include "GameReporter.h"
|
||||||
|
#include "Structures/Config.h"
|
||||||
|
#include "DataBase/GameHistoryManager.h"
|
||||||
|
#include "Utilities/outputDecoratedSavedGame.h"
|
||||||
|
|
||||||
|
|
||||||
|
void executeGameReporter()
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Here is the history of the last "
|
||||||
|
<< Config::getInstance() -> GAME_HISTORY_LIMIT
|
||||||
|
<< " Played Games" << std::endl
|
||||||
|
<< "If you wish to change the number of saved games inside the history, you can change this number inside settings section of the game";
|
||||||
|
|
||||||
|
int firstId = getFirstGameId();
|
||||||
|
int lastId = getLastGameId();
|
||||||
|
|
||||||
|
if (firstId == -1)
|
||||||
|
{
|
||||||
|
std::cout << "\n There are no games inside game history\n Press any key to continue";
|
||||||
|
getch();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int id = lastId; id >= firstId; id--)
|
||||||
|
{
|
||||||
|
outputDecoratedSavedGame(getGameById(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nPress any key to continue";
|
||||||
|
getch();
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void executeGameReporter();
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#include "GameReviewer.h"
|
||||||
|
#include "Database/GameLogManager.h"
|
||||||
|
#include "Structures/Move.h"
|
||||||
|
#include "Structures/Board.h"
|
||||||
|
#include "conio.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
void executeGameReviewer(Board board)
|
||||||
|
{
|
||||||
|
board.CursorX = -1;
|
||||||
|
board.CursorY = -1;
|
||||||
|
|
||||||
|
int logsCount = countLogs();
|
||||||
|
|
||||||
|
int logId = -1;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
std::cout << "Press any key for next move, ESC to exit...\n";
|
||||||
|
|
||||||
|
|
||||||
|
if (logId == -1)
|
||||||
|
{
|
||||||
|
board.newGameSetup();
|
||||||
|
board.prepareBoardForMove('W');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Move move = getLog(logId);
|
||||||
|
board.putPiece(move.x, move.y, move.color);
|
||||||
|
if (move.color == 'B')
|
||||||
|
{
|
||||||
|
board.prepareBoardForMove('W');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
board.prepareBoardForMove('B');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
board.display();
|
||||||
|
|
||||||
|
int userInput = _getch();
|
||||||
|
|
||||||
|
if(userInput == 27)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (logId == logsCount - 1)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
logId++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Structures/Board.h"
|
||||||
|
|
||||||
|
void executeGameReviewer(Board board);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#include "Helper.h"
|
||||||
|
#include "Structures/Board.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void executeHelper()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void executeHelper();
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
#include "Config.h"
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Move.h"
|
||||||
|
#include "../Database/GameLogManager.h"
|
||||||
|
#include "../Utilities/SymbolToStr.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------- Constructor & deconstructor ----------------------------------------
|
||||||
|
|
||||||
|
Board::Board(int boardSize)
|
||||||
|
// grid holds the matrix used for game logic
|
||||||
|
// validMovesGrid is only used to show valid moves
|
||||||
|
// display grid is used to potentially combine grid and validMovesGrid for displaying the board
|
||||||
|
{
|
||||||
|
BoardSize = boardSize;
|
||||||
|
|
||||||
|
grid = new char*[boardSize];
|
||||||
|
for (int i = 0; i < boardSize; ++i) {
|
||||||
|
grid[i] = new char[boardSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
validMovesGrid = new char*[boardSize];
|
||||||
|
for (int i = 0; i < boardSize; ++i) {
|
||||||
|
validMovesGrid[i] = new char[boardSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
displayGrid = new char*[boardSize];
|
||||||
|
for (int i = 0; i < boardSize; ++i) {
|
||||||
|
displayGrid[i] = new char[boardSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < boardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < boardSize; x++)
|
||||||
|
{
|
||||||
|
grid[y][x] = '.';
|
||||||
|
validMovesGrid[y][x] = '.';
|
||||||
|
displayGrid[y][x] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::deleteBoardMemory()
|
||||||
|
// when the game is over and maybe GameReviewer was executed
|
||||||
|
// this method has to be called to free up the allocated memory
|
||||||
|
// a destructor could do the job too
|
||||||
|
{
|
||||||
|
for (int i = 0; i < BoardSize; ++i)
|
||||||
|
{
|
||||||
|
delete[] grid[i];
|
||||||
|
}
|
||||||
|
delete[] grid;
|
||||||
|
|
||||||
|
for (int i = 0; i < BoardSize; ++i)
|
||||||
|
{
|
||||||
|
delete[] validMovesGrid[i];
|
||||||
|
}
|
||||||
|
delete[] validMovesGrid;
|
||||||
|
|
||||||
|
for (int i = 0; i < BoardSize; ++i)
|
||||||
|
{
|
||||||
|
delete[] displayGrid[i];
|
||||||
|
}
|
||||||
|
delete[] displayGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------- Database & pre-game operations ------------------------------------
|
||||||
|
|
||||||
|
std::string Board::retrieveBoard()
|
||||||
|
// turns grid into string format to be saved inside database
|
||||||
|
// this string can be used to create a grid using loadBoard method
|
||||||
|
{
|
||||||
|
int size = BoardSize * BoardSize + BoardSize;
|
||||||
|
std::string result = "";
|
||||||
|
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
result += symbolToStr(grid[y][x]);
|
||||||
|
|
||||||
|
if (!(y == BoardSize-1 && x == BoardSize-1))
|
||||||
|
{
|
||||||
|
result += "|";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::newGameSetup()
|
||||||
|
// grid represents the starting state of the board when playing a new game
|
||||||
|
// called for board before passing its pointer for creating a SinglePlayerGame/MultiPlayerGame instance
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
grid[y][x] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
grid[BoardSize/2 - 1][BoardSize/2 - 1] = 'W';
|
||||||
|
grid[BoardSize/2][BoardSize/2] = 'W';
|
||||||
|
grid[BoardSize/2][BoardSize/2 - 1] = 'B';
|
||||||
|
grid[BoardSize/2 - 1][BoardSize/2] = 'B';
|
||||||
|
|
||||||
|
updateDisplayGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::loadBoard(std::string Board)
|
||||||
|
// recreates grid based on a string inside database
|
||||||
|
// this string is created by retrieveBoard method
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
grid[y][x] = static_cast<char>(Board[index]);
|
||||||
|
index += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplayGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------- grid and game operations -----------------------------------------
|
||||||
|
|
||||||
|
void Board::prepareBoardForMove(char thisTurnColor)
|
||||||
|
// this method has to be called when a valid move is made
|
||||||
|
// updated displayGrid with the latest changes in grid
|
||||||
|
// validMovesGrid will find valid moves based on the new grid
|
||||||
|
// if user has chosen to see valid moves inside the board (SHOW_AVAILABLE_PLACES_FOR_PIECES is set to true)
|
||||||
|
// then they are putted inside the displayGrid (combining grid and validMovesGrid)
|
||||||
|
{
|
||||||
|
updateDisplayGrid();
|
||||||
|
prepareValidMovesGrid(thisTurnColor);
|
||||||
|
if (Config::getInstance() -> SHOW_AVAILABLE_PLACES_FOR_PIECES)
|
||||||
|
putValidMoves();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::flip(int x, int y)
|
||||||
|
// changes the color of the piece inside the given coordinates
|
||||||
|
{
|
||||||
|
if (grid[y][x] == 'B')
|
||||||
|
grid[y][x] = 'W';
|
||||||
|
else if (grid[y][x] == 'W')
|
||||||
|
grid[y][x] = 'B';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::putPiece(int x, int y, char color)
|
||||||
|
{
|
||||||
|
grid[y][x] = color;
|
||||||
|
|
||||||
|
Move move(x, y, color);
|
||||||
|
addLog(move);
|
||||||
|
|
||||||
|
// each comnination of coresponding elements represent a diraction
|
||||||
|
// left-up & left & left-down & up & down & right-uo & right & right-down
|
||||||
|
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
|
||||||
|
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
|
||||||
|
|
||||||
|
for (int d = 0; d < 8; ++d)
|
||||||
|
{
|
||||||
|
int flips = countFlipsInDirection(x, y, dx[d], dy[d], color);
|
||||||
|
|
||||||
|
if (flips > 0)
|
||||||
|
{
|
||||||
|
int xc = x + dx[d];
|
||||||
|
int yc = y + dy[d];
|
||||||
|
|
||||||
|
for (int step = 0; step < flips; ++step)
|
||||||
|
{
|
||||||
|
flip(xc, yc);
|
||||||
|
xc += dx[d];
|
||||||
|
yc += dy[d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Board::countBlack()
|
||||||
|
// counts the black pieces of the Board
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (grid[y][x] == 'B') count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Board::countWhite()
|
||||||
|
// counts the white pieces of the Board
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (grid[y][x] == 'W') count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------------------ validGrid operations --------------------------------------------
|
||||||
|
|
||||||
|
int Board::countValidMoves()
|
||||||
|
// returns the number of valid moves that can be made for the current turn
|
||||||
|
// should be called when validMovesGrid is created for the turn
|
||||||
|
// in a nutshell, after prepareBoardForMove method is called
|
||||||
|
// used to decide of a game has to end
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (validMovesGrid[y][x] == 'O') count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int Board::isValid(int x, int y, char color)
|
||||||
|
// returns the number of gains (opponent pieces fliped) if a piece with the given color is put in the given coords
|
||||||
|
// if it returns 0, then the move is inValid
|
||||||
|
// used as the primary parameter for the medium bot
|
||||||
|
{
|
||||||
|
if (grid[y][x] != '.') return 0;
|
||||||
|
|
||||||
|
int totalFlips = 0;
|
||||||
|
|
||||||
|
// each comnination of coresponding elements represent a diraction
|
||||||
|
// left-up & left & left-down & up & down & right-uo & right & right-down
|
||||||
|
const int dx[] = {-1, -1, -1, 0, 0, 1, 1, 1};
|
||||||
|
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
|
||||||
|
|
||||||
|
for (int d = 0; d < 8; d++)
|
||||||
|
{
|
||||||
|
totalFlips += countFlipsInDirection(x, y, dx[d], dy[d], color);
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalFlips;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Board::countFlipsInDirection(int x, int y, int dx, int dy, char color)
|
||||||
|
// counts the number of flips happened by putting a piece with the given color inside the given coordinates
|
||||||
|
// dx and dy represent the direction and more specificly, the steps of x and y
|
||||||
|
{
|
||||||
|
char oppColor = (color == 'B' ? 'W' : 'B');
|
||||||
|
|
||||||
|
int flips = 0;
|
||||||
|
int xc = x + dx;
|
||||||
|
int yc = y + dy;
|
||||||
|
|
||||||
|
|
||||||
|
while ((xc >= 0 && xc < BoardSize) && (yc >= 0 && yc < BoardSize) && grid[yc][xc] == oppColor)
|
||||||
|
{
|
||||||
|
flips++;
|
||||||
|
xc += dx;
|
||||||
|
yc += dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if loop doesn't meet a same colored piece, one of x coords or y coords will get out of bond
|
||||||
|
// or the element loop breaked for is whether a '.' (empty place)
|
||||||
|
if ((xc < 0 || xc == BoardSize) || (yc < 0 || yc == BoardSize) || grid[yc][xc] != color)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return flips;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::resetValidMovesGrid()
|
||||||
|
// clears validGrid elements to empty places
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
validMovesGrid[y][x] = '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::prepareValidMovesGrid(char color)
|
||||||
|
// first ValidMovesGrid resets itself so previous data won't interupt the process
|
||||||
|
// then check each place in grid, if it's valid, it'll put O inside the coresponding coordinates inside itself
|
||||||
|
{
|
||||||
|
resetValidMovesGrid();
|
||||||
|
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (isValid(x, y, color) != 0)
|
||||||
|
validMovesGrid[y][x] = 'O';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------- display and displayGrid operations -----------------------------------------
|
||||||
|
void Board::updateDisplayGrid()
|
||||||
|
// displayGrid be copied based on the elements (pieces) inside grid
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
displayGrid[y][x] = grid[y][x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::putValidMoves()
|
||||||
|
// validMovesGrid has the valid moves coordinates inside itself
|
||||||
|
// by calling this method, displayGrid will mark valid moves which
|
||||||
|
// validMovesGrid marks
|
||||||
|
{
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (validMovesGrid[y][x] == 'O')
|
||||||
|
{
|
||||||
|
displayGrid[y][x] = 'O';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Board::display()
|
||||||
|
// outputs displayGrid with viasual decorations
|
||||||
|
{
|
||||||
|
std::cout << " ";
|
||||||
|
for (int i = 1; i <= BoardSize; i++)
|
||||||
|
{
|
||||||
|
std::cout << i << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
std::cout << " ";
|
||||||
|
std::cout << (char)201;
|
||||||
|
for (int i = 0; i < BoardSize; i++)
|
||||||
|
{
|
||||||
|
std::cout << (char)205 << (char)205 << (char)205;
|
||||||
|
}
|
||||||
|
std::cout << (char)187 << std::endl;
|
||||||
|
|
||||||
|
for (int y = 0; y < BoardSize; y++)
|
||||||
|
{
|
||||||
|
std::cout << y + 1 << " " << (char)186;
|
||||||
|
for (int x = 0; x < BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (y == CursorY && x == CursorX) std::cout << "[";
|
||||||
|
else std::cout << " ";
|
||||||
|
|
||||||
|
char element = displayGrid[y][x];
|
||||||
|
if (element == 'W') // white piece
|
||||||
|
{
|
||||||
|
std::cout << 'X';
|
||||||
|
}
|
||||||
|
else if (element == 'B') // black piece
|
||||||
|
{
|
||||||
|
std::cout << 'O';
|
||||||
|
}
|
||||||
|
else if (element == '.') // empty space
|
||||||
|
{
|
||||||
|
std::cout << ' ';
|
||||||
|
}
|
||||||
|
else if (element == 'O') // valid move
|
||||||
|
{
|
||||||
|
std::cout << (char)249; // ∙
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y == CursorY && x == CursorX) std::cout << "]";
|
||||||
|
else std::cout << " ";
|
||||||
|
}
|
||||||
|
std::cout << (char)186 << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << " ";
|
||||||
|
std::cout << (char)200;
|
||||||
|
for (int i = 0; i < BoardSize; i++)
|
||||||
|
{
|
||||||
|
std::cout << (char)205 << (char)205 << (char)205;
|
||||||
|
}
|
||||||
|
std::cout << (char)188 << std::endl;
|
||||||
|
}
|
||||||
|
// (char)186 = ║ (char)200 = ╚ (char)188 = ╝ (char)205 = ═ (char)206 = ╦ (char)202 = ╩ (char)187 = ╗ (char)201 = ╔
|
||||||
|
// (char)79 = O
|
||||||
|
// (char)254 = ■
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Board
|
||||||
|
{
|
||||||
|
int BoardSize;
|
||||||
|
char** grid;
|
||||||
|
char** validMovesGrid;
|
||||||
|
char** displayGrid;
|
||||||
|
int CursorX = 0;
|
||||||
|
int CursorY = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Board(int boardSize);
|
||||||
|
void deleteBoardMemory();
|
||||||
|
std::string retrieveBoard();
|
||||||
|
void newGameSetup();
|
||||||
|
void loadBoard(std::string Board);
|
||||||
|
void prepareBoardForMove(char thisTurnColor);
|
||||||
|
void putPiece(int x, int y, char color);
|
||||||
|
int countBlack();
|
||||||
|
int countWhite();
|
||||||
|
int isValid(int x, int y, char color);
|
||||||
|
int countValidMoves();
|
||||||
|
void display();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void flip(int x, int y);
|
||||||
|
int countFlipsInDirection(int x, int y, int dx, int dy, char color);
|
||||||
|
void resetValidMovesGrid();
|
||||||
|
void prepareValidMovesGrid(char color);
|
||||||
|
void updateDisplayGrid();
|
||||||
|
void putValidMoves();
|
||||||
|
};
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
#include "Bot.h"
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Move.h"
|
||||||
|
#include "../Utilities/IntToStr.h"
|
||||||
|
#include "../Utilities/StrToInt.h"
|
||||||
|
#include <string>
|
||||||
|
#include <random>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bot::Bot(std::string name, int difficulty)
|
||||||
|
{
|
||||||
|
this -> name = name;
|
||||||
|
this -> difficulty = difficulty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Move Bot::suggestMove(Board& board, char color)
|
||||||
|
// the fucntion called by GameMaster when it's bot's turn to move
|
||||||
|
// this function should be called when prepareBoardForMove is called
|
||||||
|
// so bot will work as expected
|
||||||
|
{
|
||||||
|
if (difficulty == 1) // easy
|
||||||
|
{
|
||||||
|
return suggestEasyMove(board, color);
|
||||||
|
}
|
||||||
|
else if (difficulty == 2) // medium
|
||||||
|
{
|
||||||
|
return suggestMediumMove(board, color);
|
||||||
|
}
|
||||||
|
else if (difficulty == 3) // hard
|
||||||
|
{
|
||||||
|
return suggestHardMove(board, color);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return suggestMediumMove(board, color); // fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Move Bot::suggestEasyMove(Board& board, char color)
|
||||||
|
// the decision a bot would make in easy mode
|
||||||
|
// the act is based on a random choice
|
||||||
|
{
|
||||||
|
int validMovesCount = board.countValidMoves();
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_int_distribution<int> distrib(0, validMovesCount-1);
|
||||||
|
int randomNumber = distrib(gen);
|
||||||
|
|
||||||
|
int moveNumber = 0;
|
||||||
|
for (int y = 0; y < board.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < board.BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (board.validMovesGrid[y][x] == 'O')
|
||||||
|
{
|
||||||
|
if (moveNumber == randomNumber)
|
||||||
|
{
|
||||||
|
Move move{x, y, color};
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
moveNumber++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Move Bot::suggestMediumMove(Board& board, char color)
|
||||||
|
// the decision a bot would make in medium mode
|
||||||
|
// the act is based on how much gain each move will have
|
||||||
|
// the move with the most gain is made
|
||||||
|
{
|
||||||
|
int moveX, moveY;
|
||||||
|
int maxGain = 0;
|
||||||
|
|
||||||
|
for (int y = 0; y < board.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < board.BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (board.validMovesGrid[y][x] == 'O')
|
||||||
|
{
|
||||||
|
int gain = board.isValid(x, y, color);
|
||||||
|
if (gain > maxGain)
|
||||||
|
{
|
||||||
|
moveY = y;
|
||||||
|
moveX = x;
|
||||||
|
maxGain = gain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Move move{moveX, moveY, color};
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Move Bot::suggestHardMove(Board& board, char color)
|
||||||
|
// the decision a bot would make in hard mode
|
||||||
|
{
|
||||||
|
char oppColor = (color == 'W' ? 'B':'W');
|
||||||
|
int index = 0;
|
||||||
|
int validMovesCount = board.countValidMoves();
|
||||||
|
|
||||||
|
Move moves[validMovesCount];
|
||||||
|
|
||||||
|
for (int y = 0; y < board.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < board.BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (board.validMovesGrid[y][x] == 'O')
|
||||||
|
{
|
||||||
|
Move move {x, y, color};
|
||||||
|
moves[index] = move;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Move bestMove = moves[0];
|
||||||
|
int bestScore = INT_MIN;
|
||||||
|
for (int i = 0; i < validMovesCount; i++)
|
||||||
|
{
|
||||||
|
Move move = moves[i];
|
||||||
|
|
||||||
|
Board dummyBoard {board.BoardSize};
|
||||||
|
|
||||||
|
deepCopy(board, dummyBoard);
|
||||||
|
|
||||||
|
dummyBoard.putPiece(move.x, move.y, move.color);
|
||||||
|
dummyBoard.prepareBoardForMove(oppColor);
|
||||||
|
|
||||||
|
int score = minimax(oppColor, dummyBoard, false, color); // start minimizing since its user's turn
|
||||||
|
|
||||||
|
if (score > bestScore)
|
||||||
|
{
|
||||||
|
bestScore = score;
|
||||||
|
bestMove = move;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bestMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string Bot::retrieveBot()
|
||||||
|
// turns Bot structure into a string to be saved inside database
|
||||||
|
// this string will be loaded using loadBot method
|
||||||
|
{
|
||||||
|
return name + "|" + intToStr(difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Bot::loadBot(std::string bot)
|
||||||
|
// fills Bot's properties according to the given string
|
||||||
|
// this string is bot's informating saved inside database
|
||||||
|
// this string was made using retrieveBot method
|
||||||
|
{
|
||||||
|
int seperatorIndex = bot.find("|");
|
||||||
|
name = bot.substr(0, seperatorIndex);
|
||||||
|
difficulty = strToInt(bot.substr(seperatorIndex + 1, bot.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------- minimax algorithm ----------------------------------------------------
|
||||||
|
int Bot::ratePlacement(int x, int y, int boardSize)
|
||||||
|
// Board is passed by refrence for time optimization
|
||||||
|
// if we put a piece with these information, what score would the piece get
|
||||||
|
// for the coordinates itselves
|
||||||
|
{
|
||||||
|
// corners
|
||||||
|
if ((x == boardSize - 1 || x == 0) && (y == boardSize - 1 || y == 0))
|
||||||
|
return 100;
|
||||||
|
|
||||||
|
// leading to corner moves:
|
||||||
|
else if (
|
||||||
|
(x == boardSize - 2 && y == 1) ||
|
||||||
|
(x == boardSize - 2 && y == boardSize - 2) ||
|
||||||
|
(x == 1 && y == 1) ||
|
||||||
|
(x == 1 && y == boardSize - 2)
|
||||||
|
)
|
||||||
|
return -50;
|
||||||
|
else if (
|
||||||
|
(x == boardSize - 2 && y == boardSize - 1) ||
|
||||||
|
(x == boardSize - 2 && y == 0) ||
|
||||||
|
(x == 1 && y == 0) ||
|
||||||
|
(x == 1 && y == boardSize - 1) ||
|
||||||
|
(x == boardSize - 1 && y == 1) ||
|
||||||
|
(x == boardSize - 1 && y == boardSize - 2) ||
|
||||||
|
(x == 0 && y == 1) ||
|
||||||
|
(x == 0 && y == boardSize - 2)
|
||||||
|
)
|
||||||
|
return -30;
|
||||||
|
|
||||||
|
// edges (corners and corner neighbour already handled)
|
||||||
|
else if (x == 0 || x == boardSize - 1 || y == 0 || y == boardSize - 1)
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
// center
|
||||||
|
else if (
|
||||||
|
(x == boardSize/2 && y == boardSize/2) ||
|
||||||
|
(x == boardSize/2 && y == boardSize/2 - 1) ||
|
||||||
|
(x == boardSize/2 - 1 && y == boardSize/2) ||
|
||||||
|
(x == boardSize/2 - 1 && y == boardSize/2 - 1)
|
||||||
|
)
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
// other places have no value on their own
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Bot::rateBoard(Board& board, char botColor)
|
||||||
|
{
|
||||||
|
char oppColor = (botColor == 'W' ? 'B':'W');
|
||||||
|
|
||||||
|
Board dummyBoard {board.BoardSize};
|
||||||
|
deepCopy(board, dummyBoard);
|
||||||
|
|
||||||
|
int botScore = 0, playerScore = 0;
|
||||||
|
|
||||||
|
// possible moves rating
|
||||||
|
dummyBoard.prepareBoardForMove(botColor);
|
||||||
|
botScore += dummyBoard.countValidMoves();
|
||||||
|
|
||||||
|
dummyBoard.prepareBoardForMove(oppColor);
|
||||||
|
botScore -= dummyBoard.countValidMoves();
|
||||||
|
|
||||||
|
// greedy strategy
|
||||||
|
int blackCount = dummyBoard.countBlack();
|
||||||
|
int whiteCount = dummyBoard.countWhite();
|
||||||
|
|
||||||
|
if (botColor == 'B')
|
||||||
|
{
|
||||||
|
botScore += blackCount;
|
||||||
|
botScore -= whiteCount;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
botScore -= blackCount;
|
||||||
|
botScore += whiteCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// placement score
|
||||||
|
for (int y = 0; y < board.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x =0; x < board.BoardSize; x++)
|
||||||
|
{
|
||||||
|
char element = board.grid[y][x];
|
||||||
|
|
||||||
|
if (element == 'W' || element == 'B')
|
||||||
|
{
|
||||||
|
int score = ratePlacement(x, y, board.BoardSize);
|
||||||
|
|
||||||
|
if (element == botColor)
|
||||||
|
{
|
||||||
|
botScore += score;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
botScore -= score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return botScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Bot::minimax(char color, Board dummyBoard, bool isMaxAgent, char botColor, int depth, int upFloor, int downFloor)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
int validMovesCount = dummyBoard.countValidMoves();
|
||||||
|
|
||||||
|
if (depth == 3 || validMovesCount == 0)
|
||||||
|
{
|
||||||
|
return rateBoard(dummyBoard, botColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
Move moves[validMovesCount];
|
||||||
|
|
||||||
|
for (int y = 0; y < dummyBoard.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < dummyBoard.BoardSize; x++)
|
||||||
|
{
|
||||||
|
if (dummyBoard.validMovesGrid[y][x] == 'O')
|
||||||
|
{
|
||||||
|
Move move {x, y, color};
|
||||||
|
moves[index] = move;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMaxAgent) // maximizing
|
||||||
|
{
|
||||||
|
int curMax = INT_MIN;
|
||||||
|
|
||||||
|
// for each valid move in this turn
|
||||||
|
for (int i = 0; i < validMovesCount; i++)
|
||||||
|
{
|
||||||
|
Move move = moves[i];
|
||||||
|
|
||||||
|
Board newBoard{dummyBoard.BoardSize};
|
||||||
|
|
||||||
|
deepCopy(dummyBoard, newBoard);
|
||||||
|
newBoard.putPiece(move.x, move.y, move.color);
|
||||||
|
newBoard.prepareBoardForMove(move.color == 'B' ? 'W':'B');
|
||||||
|
|
||||||
|
int minAgentAnswer = minimax((move.color == 'B' ? 'W':'B'), newBoard, false, botColor, depth + 1, upFloor, downFloor);
|
||||||
|
|
||||||
|
curMax = std::max(curMax, minAgentAnswer);
|
||||||
|
upFloor = std::max(upFloor, curMax);
|
||||||
|
|
||||||
|
if (upFloor >= downFloor) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
else // minimizing
|
||||||
|
{
|
||||||
|
int curMin = INT_MAX;
|
||||||
|
|
||||||
|
// for each valid move in this turn
|
||||||
|
for (int i = 0; i < validMovesCount; i++)
|
||||||
|
{
|
||||||
|
Move move = moves[i];
|
||||||
|
|
||||||
|
Board newBoard{dummyBoard.BoardSize};
|
||||||
|
|
||||||
|
deepCopy(dummyBoard, newBoard);
|
||||||
|
newBoard.putPiece(move.x, move.y, move.color);
|
||||||
|
newBoard.prepareBoardForMove(move.color == 'B' ? 'W':'B');
|
||||||
|
|
||||||
|
int maxAgentAnswer = minimax((move.color == 'B' ? 'W':'B'), newBoard, true, botColor, depth + 1, upFloor, downFloor);
|
||||||
|
|
||||||
|
curMin = std::min(curMin, maxAgentAnswer);
|
||||||
|
downFloor = std::min(downFloor, curMin);
|
||||||
|
|
||||||
|
if (upFloor >= downFloor) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return curMin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Bot::deepCopy(Board& board, Board& newBoard)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < board.BoardSize; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < board.BoardSize; x++)
|
||||||
|
{
|
||||||
|
newBoard.grid[y][x] = board.grid[y][x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Move.h"
|
||||||
|
|
||||||
|
struct Bot
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
int difficulty;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Bot(std::string name, int difficulty);
|
||||||
|
Move suggestMove(Board& board, char color);
|
||||||
|
std::string retrieveBot();
|
||||||
|
void loadBot(std::string bot);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Move suggestEasyMove(Board& borad, char color);
|
||||||
|
Move suggestMediumMove(Board& board, char color);
|
||||||
|
Move suggestHardMove(Board& board, char color);
|
||||||
|
int ratePlacement(int x, int y, int boardSize);
|
||||||
|
int rateBoard(Board& board, char botColor);
|
||||||
|
int minimax(char color, Board dummyBoard, bool isMaxAgent, char botColor, int depth = 0, int upFloor = INT_MIN, int downFloor = INT_MAX);
|
||||||
|
void deepCopy(Board& board, Board& newBoard);
|
||||||
|
};
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#include "../Database/ConfigManager.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
Config* Config::instance = nullptr;
|
||||||
|
|
||||||
|
Config::Config()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
GAME_HISTORY_LIMIT = getGameHistoryLimit();
|
||||||
|
BOARD_SIZE = getBoardSize();
|
||||||
|
BOARD_COLOR = getBoardColor();
|
||||||
|
BOARD_BORDER_COLOR = getBoardBorderColor();
|
||||||
|
SOUND = getSound();
|
||||||
|
SHOW_AVAILABLE_PLACES_FOR_PIECES = getShowAvailablePlacesForPieces();
|
||||||
|
HINT = getHint();
|
||||||
|
HINT_LIMIT = getHintLimit();
|
||||||
|
}
|
||||||
|
catch (int errorCode)
|
||||||
|
{
|
||||||
|
if (errorCode == 1)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
std::cout << "An error acoured while opening Config.txt \nPerhaps another program is using it\nPress any key to continue";
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
|
else if (errorCode == 2)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
std::cout << "the inputed index is out of the bond of Config, the last index is 7\nPress any key to continue";
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
std::cout << "Unexpected error acoured\nPress any key to continue";
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Config* Config::getInstance()
|
||||||
|
{
|
||||||
|
if (!instance)
|
||||||
|
throw 3; // config not initialized
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Config::initialize()
|
||||||
|
{
|
||||||
|
if (!instance)
|
||||||
|
instance = new Config();
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Config
|
||||||
|
{
|
||||||
|
static Config* instance;
|
||||||
|
|
||||||
|
int GAME_HISTORY_LIMIT;
|
||||||
|
int BOARD_SIZE;
|
||||||
|
std::string BOARD_COLOR;
|
||||||
|
std::string BOARD_BORDER_COLOR;
|
||||||
|
bool SOUND;
|
||||||
|
bool SHOW_AVAILABLE_PLACES_FOR_PIECES;
|
||||||
|
bool HINT;
|
||||||
|
int HINT_LIMIT;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Config();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Config* getInstance();
|
||||||
|
static void initialize();
|
||||||
|
};
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#include "Move.h"
|
||||||
|
#include "../Utilities/StrToInt.h"
|
||||||
|
#include "../Utilities/IntToStr.h"
|
||||||
|
#include "../Utilities/StrToSymbol.h"
|
||||||
|
#include "../Utilities/SymbolToStr.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
Move::Move()
|
||||||
|
{
|
||||||
|
this -> x = 0;
|
||||||
|
this -> y = 0;
|
||||||
|
this -> color = 'B';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Move::Move(int x, int y, char color)
|
||||||
|
{
|
||||||
|
this -> x = x;
|
||||||
|
this -> y = y;
|
||||||
|
this -> color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Move::retrieveMove()
|
||||||
|
{
|
||||||
|
return intToStr(x) + " " + intToStr(y) + " " + symbolToStr(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move::loadMove(std::string move)
|
||||||
|
{
|
||||||
|
int xLastIndex = move.find(" ");
|
||||||
|
std::string x = move.substr(0, xLastIndex);
|
||||||
|
move = move.substr(xLastIndex + 1, move.size());
|
||||||
|
|
||||||
|
int yLastIndex = move.find(" ");
|
||||||
|
std::string y = move.substr(0, yLastIndex);
|
||||||
|
move = move.substr(yLastIndex + 1, move.size());
|
||||||
|
|
||||||
|
std::string color = move.substr(0, move.size());
|
||||||
|
|
||||||
|
this -> x = strToInt(x);
|
||||||
|
this -> y = strToInt(y);
|
||||||
|
this -> color = strToSymbol(color);
|
||||||
|
};
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Move
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
char color;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Move(int x, int y, char color);
|
||||||
|
Move();
|
||||||
|
std::string retrieveMove();
|
||||||
|
void loadMove(std::string move);
|
||||||
|
};
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
#include "../Database/GameHistoryManager.h"
|
||||||
|
#include "../Database/GameLogManager.h"
|
||||||
|
#include "../Utilities/IntToStr.h"
|
||||||
|
#include "../Utilities/SymbolToStr.h"
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "MultiPlayerGame.h"
|
||||||
|
#include <conio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
MultiPlayerGame::MultiPlayerGame(Board* GameBoard, Player* Player1, Player* Player2, char CurrentTurnColor)
|
||||||
|
{
|
||||||
|
int lastId = getLastGameId();
|
||||||
|
|
||||||
|
this -> id = lastId + 1;
|
||||||
|
this -> GameBoard = GameBoard;
|
||||||
|
this -> mode = "2Player";
|
||||||
|
this -> Player1 = Player1;
|
||||||
|
this -> Player2 = Player2;
|
||||||
|
this -> CurrentTurnColor = CurrentTurnColor;
|
||||||
|
this -> Winner = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MultiPlayerGame::changeTurn()
|
||||||
|
{
|
||||||
|
if (CurrentTurnColor == 'B')
|
||||||
|
{
|
||||||
|
CurrentTurnColor = 'W';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentTurnColor = 'B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MultiPlayerGame::start()
|
||||||
|
{
|
||||||
|
clearGameLog();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
system("cls");
|
||||||
|
std::cout << (CurrentTurnColor == Player1 -> color ? Player2 -> name + "it's your turn" : Player2 -> name + "it's your turn") << std::endl;
|
||||||
|
|
||||||
|
(*GameBoard).display();
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorY != 0)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorY--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorY != GameBoard -> BoardSize - 1)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorY++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('a') || userInput == 75)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorX != 0)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorX--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('d') || userInput == 77)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorX != GameBoard -> BoardSize - 1)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorX++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == 13)
|
||||||
|
{
|
||||||
|
if ( (*GameBoard).validMovesGrid[GameBoard -> CursorY][GameBoard -> CursorX] == 'O')
|
||||||
|
{
|
||||||
|
(*GameBoard).putPiece(GameBoard -> CursorX, GameBoard -> CursorY, CurrentTurnColor);
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ((*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ( (*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MultiPlayerGame::end()
|
||||||
|
{
|
||||||
|
int blackCount = (*GameBoard).countBlack();
|
||||||
|
int whiteCount = (*GameBoard).countWhite();
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
(*GameBoard).display();
|
||||||
|
|
||||||
|
std::cout << "\nFinal Score: Black: " << blackCount
|
||||||
|
<< " | White: " << whiteCount << "\n\n";
|
||||||
|
|
||||||
|
if (blackCount > whiteCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Player1->color == 'B')
|
||||||
|
{
|
||||||
|
Winner = 1;
|
||||||
|
std::cout << "Congratulations " << Player1->name << "! You won!\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 2;
|
||||||
|
std::cout << "Congratulations " << Player2->name << "! You won!\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (whiteCount > blackCount)
|
||||||
|
{
|
||||||
|
if (Player1->color == 'W')
|
||||||
|
{
|
||||||
|
Winner = 1;
|
||||||
|
std::cout << "Congratulations " << Player1->name << "! You won!\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 2;
|
||||||
|
std::cout << "You lost. The bot won.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 3; // Draw
|
||||||
|
std::cout << "It's a draw!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MultiPlayerGame::save()
|
||||||
|
// saves the game inside GameHistory.txt
|
||||||
|
{
|
||||||
|
saveGame(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string MultiPlayerGame::retrieveGame()
|
||||||
|
// turns current Game instance into a string
|
||||||
|
// this string can be turned into a Game instance via loadGame method
|
||||||
|
{
|
||||||
|
std::string idToSave = intToStr(id);
|
||||||
|
std::string boardToSave = (*GameBoard).retrieveBoard();
|
||||||
|
std::string player1ToSave = Player1 -> retrievePlayer();
|
||||||
|
std::string player2ToSave = Player2 -> retrievePlayer();
|
||||||
|
std::string currentTurnToSave = symbolToStr(CurrentTurnColor);
|
||||||
|
std::string winnerToSave = intToStr(Winner);
|
||||||
|
|
||||||
|
return "[" + idToSave + "]["
|
||||||
|
+ boardToSave + "]["
|
||||||
|
+ mode + "]["
|
||||||
|
+ player1ToSave + "]["
|
||||||
|
+ player2ToSave + "]["
|
||||||
|
+ currentTurnToSave + "]["
|
||||||
|
+ winnerToSave + "]";
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct MultiPlayerGame
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
Board* GameBoard;
|
||||||
|
std::string mode;
|
||||||
|
Player* Player1;
|
||||||
|
Player* Player2;
|
||||||
|
char CurrentTurnColor;
|
||||||
|
int Winner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MultiPlayerGame(Board* GameBoard, Player* Player1, Player* Player2, char CurrentTurnColor);
|
||||||
|
void start();
|
||||||
|
std::string retrieveGame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void end();
|
||||||
|
void save();
|
||||||
|
void changeTurn();
|
||||||
|
};
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include <string>
|
||||||
|
#include "Player.h"
|
||||||
|
#include "../Utilities/SymbolToStr.h"
|
||||||
|
#include "../Utilities/StrToSymbol.h"
|
||||||
|
|
||||||
|
|
||||||
|
Player::Player(std::string name, char color)
|
||||||
|
{
|
||||||
|
this -> name = name;
|
||||||
|
this -> color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Player::retrievePlayer()
|
||||||
|
{
|
||||||
|
return name + "|" + symbolToStr(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::loadPlayer(std::string player)
|
||||||
|
{
|
||||||
|
int speratorIndex = player.find("|");
|
||||||
|
|
||||||
|
std::string name = player.substr(0, speratorIndex);
|
||||||
|
std::string color = player.substr(speratorIndex + 1, player.size());
|
||||||
|
|
||||||
|
this -> name = name;
|
||||||
|
this -> color = strToSymbol(color);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct Player
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
char color;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Player(std::string name, char color);
|
||||||
|
std::string retrievePlayer();
|
||||||
|
void loadPlayer(std::string player);
|
||||||
|
};
|
||||||
@@ -0,0 +1,213 @@
|
|||||||
|
#include "../Database/GameHistoryManager.h"
|
||||||
|
#include "../Database/GameLogManager.h"
|
||||||
|
#include "../Utilities/IntToStr.h"
|
||||||
|
#include "../Utilities/SymbolToStr.h"
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Bot.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "SinglePlayerGame.h"
|
||||||
|
#include <conio.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
|
||||||
|
SinglePlayerGame::SinglePlayerGame(Board *GameBoard, Player* Player1, Bot* GameBot, char CurrentTurnColor)
|
||||||
|
{
|
||||||
|
int lastId = getLastGameId();
|
||||||
|
|
||||||
|
this -> id = lastId + 1;
|
||||||
|
this -> GameBoard = GameBoard;
|
||||||
|
this -> mode = "1Player";
|
||||||
|
this -> Player1 = Player1;
|
||||||
|
this -> GameBot = GameBot;
|
||||||
|
this -> CurrentTurnColor = CurrentTurnColor;
|
||||||
|
this -> Winner = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SinglePlayerGame::changeTurn()
|
||||||
|
{
|
||||||
|
if (CurrentTurnColor == 'B')
|
||||||
|
{
|
||||||
|
CurrentTurnColor = 'W';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CurrentTurnColor = 'B';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SinglePlayerGame::start()
|
||||||
|
{
|
||||||
|
clearGameLog();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (CurrentTurnColor != Player1 -> color) // Bot turn
|
||||||
|
{
|
||||||
|
Move botMove = GameBot -> suggestMove( (*GameBoard), CurrentTurnColor);
|
||||||
|
GameBoard -> putPiece(botMove.x, botMove.y, CurrentTurnColor);
|
||||||
|
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ( (*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ( (*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
|
||||||
|
(*GameBoard).display();
|
||||||
|
|
||||||
|
int userInput = getch();
|
||||||
|
|
||||||
|
if (userInput == static_cast<int>('w') || userInput == 72)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorY != 0)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorY--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('s') || userInput == 80)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorY != GameBoard -> BoardSize - 1)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorY++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('a') || userInput == 75)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorX != 0)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorX--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == static_cast<int>('d') || userInput == 77)
|
||||||
|
{
|
||||||
|
if (GameBoard -> CursorX != GameBoard -> BoardSize - 1)
|
||||||
|
{
|
||||||
|
GameBoard -> CursorX++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (userInput == 13)
|
||||||
|
{
|
||||||
|
if ( (*GameBoard).validMovesGrid[GameBoard -> CursorY][GameBoard -> CursorX] == 'O')
|
||||||
|
{
|
||||||
|
(*GameBoard).putPiece(GameBoard -> CursorX, GameBoard -> CursorY, CurrentTurnColor);
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ((*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
changeTurn();
|
||||||
|
(*GameBoard).prepareBoardForMove(CurrentTurnColor);
|
||||||
|
this -> save();
|
||||||
|
|
||||||
|
if ( (*GameBoard).countValidMoves() == 0)
|
||||||
|
{
|
||||||
|
end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SinglePlayerGame::end()
|
||||||
|
{
|
||||||
|
int blackCount = (*GameBoard).countBlack();
|
||||||
|
int whiteCount = (*GameBoard).countWhite();
|
||||||
|
|
||||||
|
system("cls");
|
||||||
|
(*GameBoard).display();
|
||||||
|
|
||||||
|
std::cout << "\nFinal Score: Black: " << blackCount
|
||||||
|
<< " | White: " << whiteCount << "\n\n";
|
||||||
|
|
||||||
|
if (blackCount > whiteCount)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Player1->color == 'B')
|
||||||
|
{
|
||||||
|
Winner = 1;
|
||||||
|
std::cout << "Congratulations " << Player1->name << "! You won!\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 2;
|
||||||
|
std::cout << "You lost. The bot won.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (whiteCount > blackCount)
|
||||||
|
{
|
||||||
|
if (Player1->color == 'W')
|
||||||
|
{
|
||||||
|
Winner = 1;
|
||||||
|
std::cout << "Congratulations " << Player1->name << "! You won!\n";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 2;
|
||||||
|
std::cout << "You lost. The bot won.\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Winner = 3; // Draw
|
||||||
|
std::cout << "It's a draw!\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SinglePlayerGame::save()
|
||||||
|
// saves the game inside GameHistory.txt
|
||||||
|
{
|
||||||
|
saveGame(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string SinglePlayerGame::retrieveGame()
|
||||||
|
// turns current Game instance into a string
|
||||||
|
// this string can be turned into a Game instance via loadGame method
|
||||||
|
{
|
||||||
|
std::string idToSave = intToStr(id);
|
||||||
|
std::string boardToSave = (*GameBoard).retrieveBoard();
|
||||||
|
std::string playerToSave = Player1 -> retrievePlayer();
|
||||||
|
std::string botToSave = GameBot -> retrieveBot();
|
||||||
|
std::string currentTurnToSave = symbolToStr(CurrentTurnColor);
|
||||||
|
std::string winnerToSave = intToStr(Winner);
|
||||||
|
|
||||||
|
return "[" + idToSave + "]["
|
||||||
|
+ boardToSave + "]["
|
||||||
|
+ mode + "]["
|
||||||
|
+ playerToSave + "]["
|
||||||
|
+ botToSave + "]["
|
||||||
|
+ currentTurnToSave + "]["
|
||||||
|
+ winnerToSave + "]";
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Board.h"
|
||||||
|
#include "Bot.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct SinglePlayerGame
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
Board* GameBoard;
|
||||||
|
std::string mode;
|
||||||
|
Player* Player1;
|
||||||
|
Bot* GameBot;
|
||||||
|
char CurrentTurnColor;
|
||||||
|
int Winner;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SinglePlayerGame(Board* GameBoard, Player* Player1, Bot* GameBot, char CurrentTurnColor);
|
||||||
|
void start();
|
||||||
|
std::string retrieveGame();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void end();
|
||||||
|
void save();
|
||||||
|
void changeTurn();
|
||||||
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include "../Database/GameHistoryManager.h"
|
||||||
|
#include "IntSqrt.h"
|
||||||
|
#include "GetSavedBoardSize.h"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int getSavedBoardSize(std::string board)
|
||||||
|
{
|
||||||
|
int elementCount = getSavedBoardElementCount(board);
|
||||||
|
return intSqrt(elementCount);
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int getSavedBoardSize(std::string board);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include "IntSqrt.h"
|
||||||
|
|
||||||
|
int intSqrt(int number)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < 100000000; i++)
|
||||||
|
{
|
||||||
|
if (i * i == number) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int intSqrt(int);
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#include <string>
|
||||||
|
#include "IntToStr.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char getChar(int digit);
|
||||||
|
int getDigitsCount(int number);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::string intToStr(int number)
|
||||||
|
{
|
||||||
|
int numberLen = getDigitsCount(number);
|
||||||
|
|
||||||
|
char result[numberLen];
|
||||||
|
|
||||||
|
for (int i = numberLen - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
result[i] = getChar(number % 10);
|
||||||
|
number /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string resultStr = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < numberLen; i++)
|
||||||
|
{
|
||||||
|
resultStr += result[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char getChar(int digit)
|
||||||
|
{
|
||||||
|
switch (digit)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return '0';
|
||||||
|
case 1:
|
||||||
|
return '1';
|
||||||
|
case 2:
|
||||||
|
return '2';
|
||||||
|
case 3:
|
||||||
|
return '3';
|
||||||
|
case 4:
|
||||||
|
return '4';
|
||||||
|
case 5:
|
||||||
|
return '5';
|
||||||
|
case 6:
|
||||||
|
return '6';
|
||||||
|
case 7:
|
||||||
|
return '7';
|
||||||
|
case 8:
|
||||||
|
return '8';
|
||||||
|
case 9:
|
||||||
|
return '9';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getDigitsCount(int number)
|
||||||
|
{
|
||||||
|
if (number == 0) return 1;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while(number != 0)
|
||||||
|
{
|
||||||
|
number /= 10;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string intToStr(int);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "Print.h"
|
||||||
|
|
||||||
|
void print(std::string subject, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++) std::cout << subject;
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void print(std::string subject, int count);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#include <string>
|
||||||
|
#include "StrToInt.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int getNumber(char digit);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// turns a string containing digits into a integer
|
||||||
|
int strToInt(std::string number)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
while (number != "")
|
||||||
|
{
|
||||||
|
result = result*10 + getNumber((char) number[0]);
|
||||||
|
number = number.substr(1, number.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getNumber(char digit)
|
||||||
|
{
|
||||||
|
switch (digit)
|
||||||
|
{
|
||||||
|
case '0':
|
||||||
|
return 0;
|
||||||
|
case '1':
|
||||||
|
return 1;
|
||||||
|
case '2':
|
||||||
|
return 2;
|
||||||
|
case '3':
|
||||||
|
return 3;
|
||||||
|
case '4':
|
||||||
|
return 4;
|
||||||
|
case '5':
|
||||||
|
return 5;
|
||||||
|
case '6':
|
||||||
|
return 6;
|
||||||
|
case '7':
|
||||||
|
return 7;
|
||||||
|
case '8':
|
||||||
|
return 8;
|
||||||
|
case '9':
|
||||||
|
return 9;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
int strToInt(std::string number);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
char strToSymbol(std::string character)
|
||||||
|
{
|
||||||
|
if (character == "W")
|
||||||
|
{
|
||||||
|
return 'W';
|
||||||
|
}
|
||||||
|
else if (character == "B")
|
||||||
|
{
|
||||||
|
return 'B';
|
||||||
|
}
|
||||||
|
else if (character == ".")
|
||||||
|
{
|
||||||
|
return '.';
|
||||||
|
}
|
||||||
|
else if (character == "X")
|
||||||
|
{
|
||||||
|
return 'X';
|
||||||
|
}
|
||||||
|
else if (character == "O")
|
||||||
|
{
|
||||||
|
return 'O';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
char strToSymbol(std::string character);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string symbolToStr(char character)
|
||||||
|
{
|
||||||
|
if (character == 'W')
|
||||||
|
{
|
||||||
|
return "W";
|
||||||
|
}
|
||||||
|
else if (character == 'B')
|
||||||
|
{
|
||||||
|
return "B";
|
||||||
|
}
|
||||||
|
else if (character == '.')
|
||||||
|
{
|
||||||
|
return ".";
|
||||||
|
}
|
||||||
|
else if (character == 'X')
|
||||||
|
{
|
||||||
|
return "X";
|
||||||
|
}
|
||||||
|
else if (character == 'O')
|
||||||
|
{
|
||||||
|
return "O";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string symbolToStr(char);
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
#include "../Database/GameHistoryManager.h"
|
||||||
|
#include "../Utilities/IntToStr.h"
|
||||||
|
#include "../Structures/Board.h"
|
||||||
|
#include "../Structures/Player.h"
|
||||||
|
#include "../Structures/Bot.h"
|
||||||
|
#include "../Structures/SinglePlayerGame.h"
|
||||||
|
#include "../Structures/MultiPlayerGame.h"
|
||||||
|
#include "GetSavedBoardSize.h"
|
||||||
|
#include "Print.h"
|
||||||
|
#include "outputDecoratedSavedGame.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void outputDecoratedSavedSinglePlayerGame(std::string savedGame);
|
||||||
|
void outputDecoratedSavedMultiPlayerGame(std::string savedGame);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void outputDecoratedSavedGame(std::string savedGame)
|
||||||
|
{
|
||||||
|
std::string gameMode = getProperty(2, savedGame);
|
||||||
|
|
||||||
|
if (gameMode == "1Player")
|
||||||
|
{
|
||||||
|
return outputDecoratedSavedSinglePlayerGame(savedGame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return outputDecoratedSavedMultiPlayerGame(savedGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void outputDecoratedSavedSinglePlayerGame(std::string savedGame)
|
||||||
|
{
|
||||||
|
int id = getGameId(savedGame);
|
||||||
|
Board board = *(getSinglePlayerGame(id).GameBoard);
|
||||||
|
Player player = *(getSinglePlayerGame(id).Player1);
|
||||||
|
Bot bot = *(getSinglePlayerGame(id).GameBot);
|
||||||
|
char CurrentTurnColor = getSinglePlayerGame(id).CurrentTurnColor;
|
||||||
|
int Winner = getSinglePlayerGame(id).Winner;
|
||||||
|
|
||||||
|
SinglePlayerGame game {&board, &player, &bot, CurrentTurnColor};
|
||||||
|
game.id = id;
|
||||||
|
game.Winner = Winner;
|
||||||
|
game.mode = "1Player";
|
||||||
|
game.GameBoard -> CursorX = -1;
|
||||||
|
game.GameBoard -> CursorY = -1;
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "{\n id = " << intToStr(game.id) << "\n";
|
||||||
|
|
||||||
|
std::cout << " game board = { \n";
|
||||||
|
game.GameBoard -> display();
|
||||||
|
|
||||||
|
std::cout << " mode = single player\n";
|
||||||
|
|
||||||
|
std::cout << " Player = {\n"
|
||||||
|
<< " name = " << game.Player1 -> name << std::endl
|
||||||
|
<< " color = " << (game.Player1 -> color == 'W' ? "White":"Black") << std::endl
|
||||||
|
<< " }\n";
|
||||||
|
|
||||||
|
|
||||||
|
int botDifficulty = game.GameBot -> difficulty;
|
||||||
|
std::string difficultyToOutput = (
|
||||||
|
botDifficulty == 1 ?
|
||||||
|
"easy" : botDifficulty == 2 ?
|
||||||
|
"medium" : "hard"
|
||||||
|
);
|
||||||
|
std::cout << " Bot = {\n"
|
||||||
|
<< " difficulty = " << difficultyToOutput << std::endl
|
||||||
|
<< " }\n";
|
||||||
|
|
||||||
|
int winner = game.Winner;
|
||||||
|
std::string winnerToOutput = (
|
||||||
|
winner == 0 ?
|
||||||
|
"The game is unfinished" : winner == 1 ?
|
||||||
|
"Player has won this game" : winner == 2 ?
|
||||||
|
"Bot has won this game" : "The game resulted in a draw"
|
||||||
|
);
|
||||||
|
std::cout << " " << winnerToOutput << "\n}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void outputDecoratedSavedMultiPlayerGame(std::string savedGame)
|
||||||
|
{
|
||||||
|
int id = getGameId(savedGame);
|
||||||
|
Board board = *(getMultiPlayerGame(id).GameBoard);
|
||||||
|
Player player1 = *(getMultiPlayerGame(id).Player1);
|
||||||
|
Player player2 = *(getMultiPlayerGame(id).Player2);
|
||||||
|
char CurrentTurnColor = getMultiPlayerGame(id).CurrentTurnColor;
|
||||||
|
int Winner = getMultiPlayerGame(id).Winner;
|
||||||
|
|
||||||
|
MultiPlayerGame game {&board, &player1, &player2, CurrentTurnColor};
|
||||||
|
game.id = id;
|
||||||
|
game.Winner = Winner;
|
||||||
|
game.mode = "2Player";
|
||||||
|
game.GameBoard -> CursorX = -1;
|
||||||
|
game.GameBoard -> CursorY = -1;
|
||||||
|
|
||||||
|
std::cout << "{\n id = " << intToStr(game.id) << "\n";
|
||||||
|
|
||||||
|
std::cout << " game board = { \n";
|
||||||
|
game.GameBoard -> display();
|
||||||
|
|
||||||
|
std::cout << " mode = Multiplayer\n";
|
||||||
|
|
||||||
|
std::cout << " Player1 = {\n"
|
||||||
|
<< " name = " << game.Player1 -> name << std::endl
|
||||||
|
<< " color = " << (game.Player1 -> color == 'W' ? "White":"Black") << std::endl
|
||||||
|
<< " }\n";
|
||||||
|
|
||||||
|
std::cout << " Player2 = {\n"
|
||||||
|
<< " name = " << game.Player2 -> name << std::endl
|
||||||
|
<< " color = " << (game.Player2 -> color == 'W' ? "White":"Black") << std::endl
|
||||||
|
<< " }\n";
|
||||||
|
|
||||||
|
int winner = game.Winner;
|
||||||
|
std::string winnerToOutput = (
|
||||||
|
winner == 0 ?
|
||||||
|
"The game is unfinished" : winner == 1 ?
|
||||||
|
"Player1 has won this game" : winner == 2 ?
|
||||||
|
"Player2 has won this game" : "The game resulted in a draw"
|
||||||
|
);
|
||||||
|
std::cout << " " << winnerToOutput << "\n}\n";
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
void outputDecoratedSavedGame(std::string savedGame);
|
||||||
Binary file not shown.
Reference in New Issue
Block a user