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