LCOV - code coverage report
Current view: top level - server - GameEngine.cpp (source / functions) Hit Total Coverage
Test: code-coverage.info.cleaned Lines: 106 142 74.6 %
Date: 2023-01-28 00:08:57 Functions: 15 16 93.8 %

          Line data    Source code
       1             : #include <server.hpp>
       2             : #include <algorithm>
       3             : #include <random>
       4             : #include <iomanip>
       5             : #include <iostream>
       6             : 
       7             : #define MAX_PLAYERS 2
       8             : 
       9             : using namespace server;
      10             : 
      11           1 : GameEngine::GameEngine(std::vector<std::shared_ptr<GameEngine>> &games, std::shared_ptr<shared::Player> player)
      12             : {
      13           1 :     gameId = GameEngine::generateRandomId(games);
      14           1 :     gameMap = std::make_shared<shared::Map>();
      15           1 :     players.push_back(player);
      16           1 : }
      17             : 
      18           1 : bool GameEngine::addPlayer(std::shared_ptr<shared::Player> player)
      19             : {
      20           1 :     if (isPublic && (players.size() < MAX_PLAYERS))
      21             :     {
      22           1 :         players.push_back(player);
      23             :     }
      24             :     else
      25             :     {
      26           0 :         return false;
      27             :     }
      28             : 
      29           1 :     if (players.size() == MAX_PLAYERS)
      30             :     {
      31           1 :         std::cout << "Tous les joueurs sont connectés\n"
      32           1 :                   << std::endl;
      33           1 :         std::thread gameThread(&GameEngine::runGame, this);
      34           1 :         gameThread.detach();
      35           1 :     }
      36           1 :     return true;
      37             : }
      38             : 
      39           1 : void GameEngine::askClientToPlayARule(std::shared_ptr<shared::Player> player, shared::RuleArgsStruct &ruleArgs)
      40             : {
      41             : 
      42           1 :     shared::Rules rules;
      43             :     do
      44             :     {
      45           1 :         std::unique_lock<std::mutex> lock(player->qAndA.sharedDataMutex);
      46           1 :         player->qAndA.question = "playturn\n";
      47           1 :         lock.unlock();
      48           1 :         askClient(player);
      49             : 
      50           0 :         lock.lock();
      51           0 :         binary.castToObject(player->qAndA.answer, ruleArgs);
      52           0 :         lock.unlock();
      53             : 
      54           0 :         ruleArgs.gameMap = this->gameMap;
      55           0 :         ruleArgs.currentPlayer = player;
      56             : 
      57           0 :     } while (!(rules.runTheRule(ruleArgs)));
      58           0 : }
      59             : 
      60           1 : void GameEngine::runGame() // rename rungame
      61             : {
      62           1 :     std::cout << "start game" << std::endl;
      63           1 :     std::cout << "map initialized" << std::endl;
      64           1 :     std::string message = "chat ";
      65           1 :     message += getTime() + " ";
      66           1 :     message += "Game started\n";
      67           1 :     sendToEveryone(message);
      68             :     while (true) // TODO: add condition to stop the game (victory of a player)
      69             :     {
      70           1 :         for (auto player : players)
      71             :         {
      72           1 :             std::cout << "start of turn of player: " << player->getName() << std::endl;
      73           1 :             shared::RuleArgsStruct ruleArgs;
      74           1 :             askClientToPlayARule(player, ruleArgs);
      75             : 
      76           0 :             ruleArgs.playerName = player->getName();
      77             : 
      78           0 :             std::string struc;
      79           0 :             binary.castToBinary(ruleArgs, struc);
      80           0 :             sendToEveryone(struc, true);
      81           0 :         }
      82           0 :     }
      83           0 : }
      84             : 
      85           3 : std::vector<std::shared_ptr<shared::Player>> &GameEngine::getPlayers()
      86             : {
      87           3 :     return players;
      88             : }
      89             : 
      90           1 : std::string GameEngine::generateRandomId(const std::vector<std::shared_ptr<GameEngine>> &games)
      91             : {
      92           1 :     static const std::string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      93           1 :     static std::mt19937 generator(std::random_device{}());
      94           1 :     static std::uniform_int_distribution<std::string::size_type> distribution(0, alphabet.size() - 1);
      95             : 
      96           1 :     std::string id;
      97             :     do
      98             :     {
      99           1 :         id.resize(6);
     100           1 :         std::generate(id.begin(), id.end(), [&]
     101           6 :                       { return alphabet[distribution(generator)]; });
     102           1 :     } while (std::any_of(games.begin(), games.end(), [&](const auto &game)
     103           0 :                          { return game->getId() == id; }));
     104           1 :     return id;
     105           0 : }
     106             : 
     107           6 : std::string GameEngine::getId()
     108             : {
     109           6 :     return gameId;
     110             : }
     111             : 
     112           5 : void GameEngine::processClientRequest(std::string requestString, std::shared_ptr<shared::Player> player)
     113             : {
     114           5 :     std::vector<std::string> requestComponents = splitString(requestString, ' ');
     115           5 :     if (requestComponents.size() < 1)
     116             :     {
     117           0 :         return;
     118             :     }
     119             : 
     120           5 :     std::string command = requestComponents[0];
     121             : 
     122           5 :     std::string response = "response error: invalid command\n";
     123           5 :     if (command.find("getstate") == 0)
     124             :     {
     125           0 :         response = "response" + player->getName() + " is connected\n";
     126             :     }
     127           5 :     else if (command.find("chat") == 0)
     128             :     {
     129           0 :         requestString = requestString.substr(5);
     130           0 :         std::string message = "chat ";
     131           0 :         message += getTime() + " ";
     132           0 :         message += player->getName() + " " + requestString + "\n";
     133           0 :         sendToEveryone(message);
     134           0 :         response = "response ok\n";
     135           0 :     }
     136           5 :     else if (command.find("getmap") == 0)
     137             :     {
     138           2 :         if (gameMap == nullptr)
     139             :         {
     140           0 :             response = "error: map not initialized\n";
     141             :         }
     142             :         else
     143             :         {
     144           2 :             binary.castToBinary(*gameMap, response);
     145           2 :             binary.send(player, response);
     146           2 :             return;
     147             :         }
     148             :     }
     149           3 :     else if (command.find("setmapparam") == 0)
     150             :     {
     151           3 :         if (requestComponents.size() == 3)
     152             :         {
     153           3 :             std::string param = requestComponents[1];
     154           3 :             std::string value = requestComponents[2];
     155           3 :             response = setMapParam(param, value) ? "response ok\n" : "response error: invalid parameter\n";
     156           3 :         }
     157             :     }
     158             : 
     159           3 :     std::lock_guard<std::mutex> lock(player->socketWriteMutex);
     160           3 :     boost::asio::write(player->getSocket(), boost::asio::buffer(response));
     161           9 : }
     162             : 
     163           3 : bool GameEngine::setMapParam(std::string &param, std::string &value)
     164             : {
     165             :     int paramValue;
     166             :     try
     167             :     {
     168           3 :         paramValue = std::stoi(value);
     169             :     }
     170           0 :     catch (std::exception &e)
     171             :     {
     172           0 :         return false;
     173           0 :     }
     174           3 :     if (param.find("width") == 0)
     175             :     {
     176           1 :         gameMap->setMapWidth(paramValue);
     177             :     }
     178           2 :     else if (param.find("height") == 0)
     179             :     {
     180           1 :         gameMap->setMapHeight(paramValue);
     181             :     }
     182           1 :     else if (param.find("generate") == 0)
     183             :     {
     184           1 :         gameMap->generateRandomMap(paramValue);
     185             :     }
     186             :     else
     187             :     {
     188           0 :         return false;
     189             :     }
     190           3 :     return true;
     191             : }
     192             : 
     193           5 : std::vector<std::string> GameEngine::splitString(std::string str, char delimiter)
     194             : {
     195           5 :     std::vector<std::string> components;
     196           5 :     std::stringstream ss(str);
     197           5 :     std::string component;
     198          16 :     while (std::getline(ss, component, delimiter))
     199             :     {
     200          11 :         components.push_back(component);
     201             :     }
     202          10 :     return components;
     203           5 : }
     204             : 
     205           1 : void GameEngine::askClient(std::shared_ptr<shared::Player> player)
     206             : {
     207           1 :     std::unique_lock<std::mutex> responseLock(player->qAndA.sharedDataMutex);
     208           1 :     player->qAndA.answerReady = false;
     209             :     {
     210           1 :         std::lock_guard<std::mutex> lock(player->socketWriteMutex);
     211           1 :         boost::asio::write(player->getSocket(), boost::asio::buffer(player->qAndA.question));
     212           1 :     }
     213             : 
     214           1 :     player->qAndA.condition.wait(responseLock, [&]
     215           1 :                                  { return player->qAndA.answerReady; });
     216             : 
     217           0 :     std::string response = player->qAndA.answer;
     218           0 :     player->qAndA.answerReady = false;
     219           0 : }
     220             : 
     221           2 : void GameEngine::sendToEveryone(std::string message, bool isBinary)
     222             : {
     223           6 :     for (auto &player : players)
     224             :     {
     225           4 :         if (!isBinary && player->connectedToSocket.load())
     226             :         {
     227           4 :             std::lock_guard<std::mutex> lock(player->socketWriteMutex);
     228           4 :             boost::asio::write(player->getSocket(), boost::asio::buffer(message));
     229           4 :         }
     230           0 :         else if (player->connectedToSocket.load())
     231             :         {
     232           0 :             binary.send(player, message, false);
     233             :         }
     234             :     }
     235           2 : }
     236             : 
     237             : /*!
     238             :  * @brief This function return the time under a string format
     239             :  * For example, if the time is 1:34pm, the function will return "13:34"
     240             :  * @return std::string
     241             :  */
     242           4 : std::string GameEngine::getTime()
     243             : {
     244           4 :     std::time_t t = std::time(nullptr);
     245           4 :     std::tm tm = *std::localtime(&t);
     246           4 :     std::stringstream ss;
     247           4 :     ss << std::put_time(&tm, "%H:%M");
     248           8 :     return ss.str();
     249           4 : }

Generated by: LCOV version 1.14