use json serialization everywhere (staged for adding socket functionality)

This commit is contained in:
eay 2023-08-28 08:05:30 -07:00
parent 4b80878d33
commit cfcd99b0db
6 changed files with 115 additions and 79 deletions

View File

@ -1,3 +1,6 @@
azool: azool:
mkdir -p bin mkdir -p bin
g++ src/*.cc -I./include -o bin/azool -Werror -Weffc++ -std=c++11 g++ src/*.cc -I./include -o bin/azool -Werror -Weffc++ -std=c++11 -DBOOST_ALLOW_DEPRECATED_HEADERS -DBOOST_BIND_GLOBAL_PLACEHOLDERS
clean:
rm bin/*

View File

@ -18,17 +18,17 @@ public:
GameBoard(int nPlayers=2); GameBoard(int nPlayers=2);
friend std::ostream& operator<<(std::ostream& out, const GameBoard& board); friend std::ostream& operator<<(std::ostream& out, const GameBoard& board);
bool validFactoryRequest(int factoryIdx, azool::TileColor color); bool validFactoryRequest(int factoryIdx, azool::TileColor color) const;
bool takeTilesFromFactory(int factoryIdx, azool::TileColor color, int& numTiles); bool takeTilesFromFactory(int factoryIdx, azool::TileColor color, int& numTiles);
bool takeTilesFromPool(azool::TileColor color, int& numTiles, bool& poolPenalty); bool takeTilesFromPool(azool::TileColor color, int& numTiles, bool& poolPenalty);
void returnTilesToBag(int numTiles, azool::TileColor color); void returnTilesToBag(int numTiles, azool::TileColor color);
void dealTiles(); void dealTiles();
void handleRequest(std::stringstream); std::string handleRequest(const std::string&);
boost::property_tree::ptree serializeBoard() const; boost::property_tree::ptree serializeBoard() const;
int numFactories() { int numFactories() {
return tileFactories.size(); return tileFactories.size();
} }
bool endOfRound() { bool endOfRound() const {
// round ends when the pool and tile factories are empty // round ends when the pool and tile factories are empty
for (int ii = 0; ii < azool::NUMCOLORS; ++ii) { for (int ii = 0; ii < azool::NUMCOLORS; ++ii) {
if (pool[ii] > 0) return false; if (pool[ii] > 0) return false;

View File

@ -15,6 +15,7 @@ public:
void placeTiles(int rowIdx, azool::TileColor color, int numTiles); void placeTiles(int rowIdx, azool::TileColor color, int numTiles);
void endRound(bool& fullRow); void endRound(bool& fullRow);
void finalizeScore(); void finalizeScore();
std::string sendRequest(const std::string&);
int getScore() const { int getScore() const {
return myScore; return myScore;
} }
@ -22,6 +23,7 @@ public:
bool tookPenalty() const { bool tookPenalty() const {
return myTookPoolPenaltyThisRound; return myTookPoolPenaltyThisRound;
} }
int getScorePenalty() const;
const std::string getPlayerName() const { const std::string getPlayerName() const {
return myName; return myName;
} }

View File

@ -42,7 +42,7 @@ std::ostream& operator<<(std::ostream& out, const GameBoard& board) {
return out; return out;
} }
bool GameBoard::validFactoryRequest(int factoryIdx, azool::TileColor color) { bool GameBoard::validFactoryRequest(int factoryIdx, azool::TileColor color) const {
// check if color exists on specified factory // check if color exists on specified factory
bool retVal = factoryIdx < tileFactories.size() and bool retVal = factoryIdx < tileFactories.size() and
factoryIdx > -1 and factoryIdx > -1 and
@ -141,7 +141,8 @@ pt::ptree GameBoard::serializeBoard() const {
return outTree; return outTree;
} // GameBoard::serializeBoard } // GameBoard::serializeBoard
void GameBoard::handleRequest(std::stringstream iss) { std::string GameBoard::handleRequest(const std::string& instring) {
std::stringstream iss(instring);
pt::ptree inTree; pt::ptree inTree;
pt::read_json(iss, inTree); pt::read_json(iss, inTree);
pt::ptree outTree; pt::ptree outTree;
@ -190,7 +191,9 @@ void GameBoard::handleRequest(std::stringstream iss) {
outTree.put("req_type", req_type); // include request type in returned data outTree.put("req_type", req_type); // include request type in returned data
std::stringstream oss; std::stringstream oss;
pt::write_json(oss, outTree); pt::write_json(oss, outTree);
// send oss over socket std::string output = oss.str();
return output;
// send output string over socket
} // GameBoard::handleRequest } // GameBoard::handleRequest
void GameBoard::resetBoard() { void GameBoard::resetBoard() {

View File

@ -2,6 +2,8 @@
#include <iostream> #include <iostream>
#include <cstring> #include <cstring>
#include <sstream> #include <sstream>
#include <boost/property_tree/json_parser.hpp>
namespace pt = boost::property_tree;
Player::Player(GameBoard* const board, std::string name) : Player::Player(GameBoard* const board, std::string name) :
myGrid(), myGrid(),
@ -41,17 +43,24 @@ bool Player::checkValidMove(azool::TileColor color, int rowIdx) const {
} // Player::checkValidMove } // Player::checkValidMove
bool Player::takeTilesFromFactory(int factoryIdx, azool::TileColor color, int rowIdx) { bool Player::takeTilesFromFactory(int factoryIdx, azool::TileColor color, int rowIdx) {
// pt::ptree request; // checkValidMove first - can't undo request to boardptr
// request.put("req_type", azool::REQ_TYPE_DRAW_FROM_POOL); if (!checkValidMove(color, rowIdx)) {
// request.put("tile_color", color); return false;
// request.put("factory_idx", factoryIdx); }
// std::stringstream oss; pt::ptree request;
// pt::write_json(request, oss); request.put("req_type", azool::REQ_TYPE_DRAW_FROM_FACTORY);
// send request to board request.put("tile_color", color);
// recieve response request.put("factory_idx", factoryIdx);
int numTiles = 0; std::stringstream oss;
if (checkValidMove(color, rowIdx) and pt::write_json(oss, request);
myBoardPtr->takeTilesFromFactory(factoryIdx, color, numTiles)) { // send request to board, recieve response
std::stringstream iss(sendRequest(oss.str()));
pt::ptree response;
pt::read_json(iss, response);
// std::cout << iss.str() << std::endl;
bool success = response.get<bool>("success", false);
int numTiles = response.get<int>("num_tiles_returned", 0);
if (success) {
placeTiles(rowIdx, color, numTiles); placeTiles(rowIdx, color, numTiles);
return true; return true;
} }
@ -60,22 +69,22 @@ bool Player::takeTilesFromFactory(int factoryIdx, azool::TileColor color, int ro
bool Player::takeTilesFromPool(azool::TileColor color, int rowIdx) { bool Player::takeTilesFromPool(azool::TileColor color, int rowIdx) {
// call game board -> takeTilesFromPool // call game board -> takeTilesFromPool
int numTiles = 0;
bool poolPenalty = false;
if (!checkValidMove(color, rowIdx)) { if (!checkValidMove(color, rowIdx)) {
return false; return false;
} }
// pt::ptree request; pt::ptree request;
// request.put("req_type", azool::REQ_TYPE_DRAW_FROM_POOL); request.put("req_type", azool::REQ_TYPE_DRAW_FROM_POOL);
// request.put("tile_color", color); request.put("tile_color", color);
// std::stringstream oss; std::stringstream oss;
// pt::write_json(request, oss); pt::write_json(oss, request);
// send request to board // send request to board, recieve response
// recieve response std::stringstream iss(sendRequest(oss.str()));
// bool success = inTree.get<bool>("success"); pt::ptree response;
// int numTiles = inTree.get<int>("num_tiles_returned"); pt::read_json(iss, response);
// bool poolPenalty = inTree.get<bool>("pool_penalty"); bool success = response.get<bool>("success", false);
if (!myBoardPtr->takeTilesFromPool(color, numTiles, poolPenalty)) { int numTiles = response.get<int>("num_tiles_returned", 0);
bool poolPenalty = response.get<bool>("pool_penalty", false);
if (!success) {
return false; // couldn't get that tile from the pool return false; // couldn't get that tile from the pool
} }
if (poolPenalty) { if (poolPenalty) {
@ -115,23 +124,22 @@ void Player::endRound(bool& fullRow) {
myGrid[rowIdx][col] = true; myGrid[rowIdx][col] = true;
myScore += scoreTile(rowIdx, col); myScore += scoreTile(rowIdx, col);
// return extra tiles -- rowIdx = the number of leftover tiles // return extra tiles -- rowIdx = the number of leftover tiles
// pt::ptree request; pt::ptree request;
// request.put("req_type", azool::REQ_TYPE_RETURN_TO_BAG); request.put("req_type", azool::REQ_TYPE_RETURN_TO_BAG);
// request.put("num_tiles_returned", rowIdx); request.put("num_tiles_returned", rowIdx);
// request.put("tile_color", myRows[rowIdx].second); request.put("tile_color", myRows[rowIdx].second);
// send request to gameboard std::stringstream oss;
myBoardPtr->returnTilesToBag(rowIdx, myRows[rowIdx].second); pt::write_json(oss, request);
// send request to gameboard...don't care abt response here (?)
sendRequest(oss.str());
// myBoardPtr->returnTilesToBag(rowIdx, myRows[rowIdx].second);
// reset rows for next turn // reset rows for next turn
myRows[rowIdx].first = 0; myRows[rowIdx].first = 0;
myRows[rowIdx].second = azool::NONE; myRows[rowIdx].second = azool::NONE;
} }
} }
if (myNumPenaltiesForRound >= PenaltyPoints.size()) { myScore -= getScorePenalty();
myScore -= PenaltyPoints[PenaltyPoints.size() - 1]; myScore = std::max(myScore, 0); // let's not allow negatives
}
else {
myScore -= PenaltyPoints[myNumPenaltiesForRound];
}
// reset for next turn // reset for next turn
// FOR THIS REASON // FOR THIS REASON
// main loop needs to check who took penalty BEFORE calling this function // main loop needs to check who took penalty BEFORE calling this function
@ -156,6 +164,12 @@ void Player::endRound(bool& fullRow) {
} // iter over rows in grid } // iter over rows in grid
} // Player::endRound } // Player::endRound
int Player::getScorePenalty() const {
if (myNumPenaltiesForRound >= PenaltyPoints.size()) {
return PenaltyPoints[PenaltyPoints.size() - 1];
}
return PenaltyPoints[myNumPenaltiesForRound];
}
int Player::scoreTile(int tileRow, int tileCol) { int Player::scoreTile(int tileRow, int tileCol) {
// search horizontally and vertically for points // search horizontally and vertically for points
int tileScore = 1; int tileScore = 1;
@ -258,7 +272,7 @@ void Player::finalizeScore() {
std::string Player::printMyBoard() const { std::string Player::printMyBoard() const {
// pt::ptree request; // pt::ptree request;
// request.put("req_type", REQ_TYPE_GET_BOARD); // request.put("req_type", azool::REQ_TYPE_GET_BOARD);
std::ostringstream oss; std::ostringstream oss;
oss << "*******************************\n"; oss << "*******************************\n";
oss << "PLAYER: " << myName << "\n"; oss << "PLAYER: " << myName << "\n";
@ -293,24 +307,25 @@ std::string Player::printMyBoard() const {
} // iterate over rows } // iterate over rows
oss << "Penalties: " << myNumPenaltiesForRound << "\n"; oss << "Penalties: " << myNumPenaltiesForRound << "\n";
oss << "Score: " << myScore << "\n"; oss << "Score: " << myScore << "\n";
oss << "-------------------------------\n";
return oss.str(); return oss.str();
// TODO(feature) - print penalty tiles (?) // TODO(feature) - print penalty tiles (?)
} // Player::printMyBoard } // Player::printMyBoard
bool Player::discardFromFactory(int factoryIdx, azool::TileColor color) { bool Player::discardFromFactory(int factoryIdx, azool::TileColor color) {
int numTiles = -1; pt::ptree request;
// pt::ptree request; request.put("req_type", azool::REQ_TYPE_DRAW_FROM_FACTORY);
// request.put("req_type", azool::REQ_TYPE_DRAW_FROM_FACTORY); request.put("factory_idx", factoryIdx);
// request.put("factory_idx", factoryIdx); request.put("tile_color", color);
// request.put("tile_color", color); std::stringstream oss;
// std::stringstream oss; pt::write_json(oss, request);
// pt::write_json(request, oss); // send request to board, recieve response
// send request to board std::stringstream iss(sendRequest(oss.str()));
// recieve response pt::ptree response;
// bool success = inTree.get<bool>("success"); pt::read_json(iss, response);
// int numTiles = inTree.get<int>("num_tiles_returned"); bool success = response.get<bool>("success", false);
// if (success) myNumPenaltiesForRound += numTiles; int numTiles = response.get<int>("num_tiles_returned", 0);
if (myBoardPtr->takeTilesFromFactory(factoryIdx, color, numTiles)) { if (success) {
myNumPenaltiesForRound += numTiles; myNumPenaltiesForRound += numTiles;
return true; return true;
} }
@ -318,19 +333,19 @@ bool Player::discardFromFactory(int factoryIdx, azool::TileColor color) {
} // Player::discardFromFactory } // Player::discardFromFactory
bool Player::discardFromPool(azool::TileColor color) { bool Player::discardFromPool(azool::TileColor color) {
// pt::ptree request; pt::ptree request;
// request.put("req_type", azool::REQ_TYPE_DRAW_FROM_POOL); request.put("req_type", azool::REQ_TYPE_DRAW_FROM_POOL);
// request.put("tile_color", color); request.put("tile_color", color);
// std::stringstream oss; std::stringstream oss;
// pt::write_json(request, oss); pt::write_json(oss, request);
// send request to board // send request to board, recieve response
// recieve response std::stringstream iss(sendRequest(oss.str()));
// bool success = inTree.get<bool>("success"); pt::ptree response;
// int numTiles = inTree.get<int>("num_tiles_returned"); pt::read_json(iss, response);
// bool poolPenalty = inTree.get<bool>("pool_penalty"); bool success = response.get<bool>("success", false);
bool poolPenalty = false; int numTiles = response.get<int>("num_tiles_returned", 0);
int numTiles = -1; bool poolPenalty = response.get<bool>("pool_penalty", false);
if (myBoardPtr->takeTilesFromPool(color, numTiles, poolPenalty)) { if (success) {
if (poolPenalty) { if (poolPenalty) {
myNumPenaltiesForRound++; myNumPenaltiesForRound++;
} }
@ -340,6 +355,12 @@ bool Player::discardFromPool(azool::TileColor color) {
return false; return false;
} // Player::discardFromPool } // Player::discardFromPool
std::string Player::sendRequest(const std::string& inStr) {
// do the socket stuff here
std::string rxStr = myBoardPtr->handleRequest(inStr);
return rxStr;
} // Player::sendRequest
namespace { namespace {
int promptForFactoryIdx(int maxFactIdx) { int promptForFactoryIdx(int maxFactIdx) {
static const char* promptFactoryIdxDraw = "Which factory? enter index\n"; static const char* promptFactoryIdxDraw = "Which factory? enter index\n";
@ -393,12 +414,19 @@ int promptForRow() {
void Player::takeTurn() { void Player::takeTurn() {
// print game board, handle user input // print game board, handle user input
// pt::ptree request; pt::ptree request;
// request.put("req_type", REQ_TYPE_GET_BOARD); request.put("req_type", azool::REQ_TYPE_GET_BOARD);
// bool endOfRound = inTree.get<bool>("end_of_round"); std::stringstream reqss;
// // max idx for input - users use 1-indexing pt::write_json(reqss, request);
// int maxFactIdx = inTree.get<int>("num_factories"); // send request to board, recieve response
if (myBoardPtr->endOfRound()) return; std::stringstream iss(sendRequest(reqss.str()));
pt::ptree response;
pt::read_json(iss, response);
bool endOfRound = response.get<bool>("end_of_round");
// max idx for input - users use 1-indexing
int maxFactIdx = response.get<int>("num_factories");
if (endOfRound) return;
std::cout << *myBoardPtr << "\n\n";
std::cout << printMyBoard(); std::cout << printMyBoard();
static const char* promptDrawInput = "What would you like to do?\n" static const char* promptDrawInput = "What would you like to do?\n"
"[f] take from factory " "[f] take from factory "
@ -416,7 +444,7 @@ void Player::takeTurn() {
char drawType; char drawType;
std::cin >> drawType; std::cin >> drawType;
if (drawType == 'f') { if (drawType == 'f') {
int factIdx = promptForFactoryIdx(myBoardPtr->numFactories()); int factIdx = promptForFactoryIdx(maxFactIdx);
// draw from factory // draw from factory
if (factIdx == -1) { if (factIdx == -1) {
std::cout << invalidEntryMessage << std::flush; std::cout << invalidEntryMessage << std::flush;
@ -463,7 +491,7 @@ void Player::takeTurn() {
char discardFrom = '\0'; char discardFrom = '\0';
std::cin >> discardFrom; std::cin >> discardFrom;
if (discardFrom == 'f') { if (discardFrom == 'f') {
int factIdx = promptForFactoryIdx(myBoardPtr->numFactories()); int factIdx = promptForFactoryIdx(maxFactIdx);
// draw from factory // draw from factory
if (factIdx == -1) { if (factIdx == -1) {
std::cout << invalidEntryMessage << std::flush; std::cout << invalidEntryMessage << std::flush;

View File

@ -26,7 +26,7 @@ void playGame(GameBoard* game) {
secondPlayer->takeTurn(); secondPlayer->takeTurn();
} }
// check who took penalty // check who took penalty
// needs to be done before claling player->endRound() // needs to be done before calling player->endRound()
if (players[0]->tookPenalty()) { if (players[0]->tookPenalty()) {
firstPlayer = players[0]; firstPlayer = players[0];
secondPlayer = players[1]; secondPlayer = players[1];