From a75e6e290d3412a3c49a883b6d4eff3c07ee50f9 Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Tue, 16 Dec 2014 13:13:02 +0000 Subject: [PATCH] Finalise implementation of reading in a game from a string --- game/game.cpp | 65 ++++++++++++++++++++++++-- game/game.h | 116 ++++++++++++++++++++++++----------------------- game/gametypes.h | 11 ++--- game/order.cpp | 2 - game/order.h | 4 +- game/unit.cpp | 32 ++++++------- game/unit.h | 43 ++++++++---------- test/test.cpp | 30 +++++++----- 8 files changed, 178 insertions(+), 125 deletions(-) diff --git a/game/game.cpp b/game/game.cpp index 253f0a4..c3d8df4 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -3,6 +3,32 @@ #include #include +CTTRTSGame::CTTRTSGame( ucoord_t c, ucoord_t r ) +: dimensions( c,r ) +, turn (0), name ( "Custom_Game" ) +{ + +} + +// Move constructor +CTTRTSGame::CTTRTSGame(CTTRTSGame&& game) +: m_OrderUnitPairs(std::move(game.m_OrderUnitPairs)) +, dimensions(std::move(game.dimensions)) +, turn(std::move(game.turn)) +, name(std::move(game.name)) +{ + +} + +CTTRTSGame& CTTRTSGame::operator=(CTTRTSGame&& game) +{ + m_OrderUnitPairs = std::move(game.m_OrderUnitPairs); + dimensions = std::move(game.dimensions); + turn = std::move(game.turn); + name = std::move(game.name); + return *this; +} + // Interpret a string of orders int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders ) { @@ -201,9 +227,6 @@ int CTTRTSGame::SimulateToNextTurn() { if( (*it).unit.getID() == id ) { - // Add the dead unit to our dead unit list - m_deadUnits.push_back(std::move((*it).unit)); - // Remove the unit from our alive unit pairs m_OrderUnitPairs.erase(it); break; @@ -361,20 +384,52 @@ std::string CTTRTSGame::GetStateAsString() const { // Print out the header char header[64]; - snprintf(header, 512, GAME_HEADER_FORMATTER , turn, dimensions.x, dimensions.y ); + snprintf(header, 512, GAME_HEADER_FORMATTER , name.c_str(), dimensions.x, dimensions.y, turn ); // Gather unit information std::string units; for ( const OrderUnitPair& pair : m_OrderUnitPairs ) { - units += GetStringFromUnit(pair.unit); + units += CUnit::GetStringFromUnit(pair.unit); units += '\n'; } // Append the header and units std::string state(header); state += '\n'; + state += GAME_HEADER_DELIMITER; state += units; return state; +} + +// Get the game information as a string +CTTRTSGame CTTRTSGame::CreateFromString( const std::string& input ) +{ + size_t headerEnd = input.find(GAME_HEADER_DELIMITER); + + std::string header = input.substr(0, headerEnd); + std::string units = input.substr(headerEnd + strlen(GAME_HEADER_DELIMITER)); + + // Grab information from the header + char buf[64]; + unsigned int turn; + unsigned int sizex; + unsigned int sizey; + sscanf(header.c_str(), GAME_HEADER_FORMATTER, buf, &sizex, &sizey, &turn ); + + CTTRTSGame game(sizex,sizey); + game.SetName(buf); + game.SetTurn(turn); + + // For each line, construct a unit + size_t pos; + while ( ( pos = units.find('\n') ) != std::string::npos ) + { + std::string unit_string = units.substr(0,pos); + units.erase(0,pos+1); + game.AddUnit(CUnit::GetUnitFromString(unit_string)); + } + + return game; } \ No newline at end of file diff --git a/game/game.h b/game/game.h index 7527768..fad3b68 100644 --- a/game/game.h +++ b/game/game.h @@ -5,6 +5,9 @@ #include "gametypes.h" #include "order.h" +#define GAME_HEADER_FORMATTER "===== %s =====\nSIZE:[%u,%u]\nTURN:%u" +#define GAME_HEADER_DELIMITER "~~~~\n" + // Type for order and unit pairs struct OrderUnitPair { @@ -20,61 +23,41 @@ struct OrderUnitPair , order ( o ) {} - // Move asignment operator - inline OrderUnitPair& operator=( OrderUnitPair&& rhs ) { this->unit = std::move(rhs.unit);this->order = rhs.order;rhs.order = COrder(); return *this; } + // Move assignment operator + inline OrderUnitPair& operator=( OrderUnitPair&& rhs ) + { + this->unit = std::move(rhs.unit); + this->order = std::move(rhs.order); + return *this; + } - CUnit unit; // The unit - COrder order; // Order for this unit from this turn + CUnit unit; // The unit + COrder order; // Order for this unit from this turn }; // Typedef for a vector of these unit pairs typedef std::vector< OrderUnitPair > OrderUnitPairVector; +// Full TTRTS Game class +// Stores information about the game +// Can convert from a string or to a string class CTTRTSGame { public: - CTTRTSGame( ucoord_t c, ucoord_t r ) - : dimensions( c,r ) - , turn (0) - { + // Get the game information as a string + static CTTRTSGame CreateFromString( const std::string& input ); - } + // Constructors + CTTRTSGame( ucoord_t c, ucoord_t r ); + CTTRTSGame(CTTRTSGame&& game); - // Default dtor - ~CTTRTSGame() = default; + // move asignment operator + CTTRTSGame& operator=(CTTRTSGame&& game); - // Issue orders to the game, returns non-zero if orders are incorrect - int IssueOrders( player_id_t player, const std::string& orders ); - int IssueOrders( player_id_t player, const COrderVector& orders ); - - // Issue a single order, returns non-zero for rejection - int IssueOrder( player_id_t player, const COrder& order ); - - // Simulate and progress to the next turn - // Returns non-zero if simulation failed - int SimulateToNextTurn(); - - // Add a unit, nonzero return value indicates error - int AddUnit( CUnit&& unit ); - - // Add a units, nonzero return value indicates error - int AddUnits( CUnitVector&& units ); - - // Get the number of units - inline unsigned int GetNumUnits() const { return m_OrderUnitPairs.size(); } - - // Get unit by index as above (not unit ID) - inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].unit; } - - // Get unit by unit ID - const CUnit& GetUnitByIDConst( unit_id_t id ) const; - - // Get orders by index as above - inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; } - - // Get dimensions - inline const uvector2 &GetDimensions() const { return dimensions; } + // Simulate and progress to the next turn + // Returns non-zero if simulation failed + int SimulateToNextTurn(); // Check for a win, returns invalid for no win state reached // Note: this function will return invalid a draw was reached @@ -83,13 +66,40 @@ public: // Get the game information as a string std::string GetStateAsString() const; + + // Issue orders to the game, returns non-zero if orders are incorrect + int IssueOrders( player_id_t player, const std::string& orders ); + int IssueOrders( player_id_t player, const COrderVector& orders ); + int IssueOrder( player_id_t player, const COrder& order ); + + // Add a units to the game, nonzero return value indicates error + int AddUnit( CUnit&& unit ); + int AddUnits( CUnitVector&& units ); + + // Get the number of units + inline unsigned int GetNumUnits() const { return m_OrderUnitPairs.size(); } + + // Get unit and orderby index as above (not unit ID) + inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].unit; } + inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; } + + // Get a unit by it's ID + const CUnit& GetUnitByIDConst( unit_id_t id ) const; + + // Get dimensions + inline const uvector2 &GetDimensions() const { return dimensions; } + + // Set the game name + // NOTE: Names with spaces not allowed + inline std::string SetName( const std::string& in ) { return (name = in); } + + // Set the turn of the game + inline int SetTurn( int in ) { return (turn = in); } private: - // Verify any order - non-zero is error + // Verify any order or position - non-zero is error int VerifyOrder( player_id_t player, const COrder& order ) const; - - // Verify Position - non-zero is error int VerifyPos( uvector2 vec ) const; // Get a units new position after an order @@ -98,19 +108,11 @@ private: // Get unit by unit ID CUnit& GetUnitByID( unit_id_t id ); - // Vector to store points to all units - OrderUnitPairVector m_OrderUnitPairs; - - // List of dead units - CUnitVector m_deadUnits; - - // Dimensions of the game - uvector2 dimensions; - - // Int to store the current turn - unsigned int turn; + std::string name; // Game Name + unsigned int turn; // Int to store the current turn + uvector2 dimensions; // Dimensions of the game + OrderUnitPairVector m_OrderUnitPairs; // Vector to store all units and orders }; -#define GAME_HEADER_FORMATTER "===== GAME TURN =====\nSIZE:[%u,%u]\nTURN:%u" #endif //_GAME_H_ diff --git a/game/gametypes.h b/game/gametypes.h index b988a48..b603cf9 100644 --- a/game/gametypes.h +++ b/game/gametypes.h @@ -13,16 +13,11 @@ enum class Team : char NUM_INVALID }; -// Type for player IDs -typedef unsigned char player_id_t; -// Type for unit IDs -typedef unsigned short unit_id_t; +typedef unsigned char player_id_t; // Type for player IDs +typedef unsigned short unit_id_t; // Type for unit IDs +typedef char unitVis_c; // Typedef for unit visual representations -// Typedef for unit visual representations -typedef char unitVis_c; - -// Invalid data for above types static const player_id_t player_id_invalid = std::numeric_limits::max(); static const unit_id_t unit_id_invalid = std::numeric_limits::max(); static const unitVis_c unitVis_invalid = std::numeric_limits::max(); diff --git a/game/order.cpp b/game/order.cpp index 731b3fc..8bd95a9 100644 --- a/game/order.cpp +++ b/game/order.cpp @@ -1,8 +1,6 @@ #include #include "order.h" -#include "mathtypes.h" - // Convert an order to a string std::string GetStringFromOrder(const COrder& order ) { diff --git a/game/order.h b/game/order.h index b35719b..77250fc 100644 --- a/game/order.h +++ b/game/order.h @@ -6,6 +6,8 @@ #include "gametypes.h" +#define ORDER_FORMATTER "ORDER:%c id:%u" + // Type for all orders ( as a char ) enum class command_c : char { @@ -45,8 +47,6 @@ inline bool COrder::operator== ( const COrder& rhs ) const // Typedef a vector of orders typedef std::vector COrderVector; -#define ORDER_FORMATTER "ORDER:%c id:%u" - // string <--> order conversion functions std::string GetStringFromOrder(const COrder& order ); COrder GetOrderFromString( const std::string& order ); diff --git a/game/unit.cpp b/game/unit.cpp index c9b917a..d7470d0 100644 --- a/game/unit.cpp +++ b/game/unit.cpp @@ -31,7 +31,7 @@ namespace } // Get a unit from a visual -CUnit GetUnitFromVis( unitVis_c vis ) +CUnit CUnit::GetUnitFromVis( unitVis_c vis ) { CUnit unit; unit.setFromVisual(vis); @@ -40,26 +40,26 @@ CUnit GetUnitFromVis( unitVis_c vis ) // Get a string descriptor of a unit // "U id:[unit_id] team:[team_id] player:[player_id] vis:[unit_vis] dir:[dir] pos:[pos.x],[pos.y]" -std::string GetStringFromUnit(const CUnit& unit ) +std::string CUnit::GetStringFromUnit(const CUnit& unit ) { static char buff[128]; memset(buff,0,sizeof(buff)); snprintf(buff,128, UNIT_FORMATTER, - unit.getID(), - (int)unit.getTeam(), - unit.getPlayer(), - unit.getVisual(), - unit.getDir(), - unit.getPos().x, - unit.getPos().y ); + unit.unit_id, + (int)unit.team_id, + unit.player_id, + unit.unit_vis, + unit.dir, + unit.pos.x, + unit.pos.y ); return buff; } // Get a unit from a string descriptor // "U id:[unit_id] team:[team_id] player:[player_id] vis:[unit_vis] dir:[dir] pos:[pos.x],[pos.y]" -CUnit GetUnitFromString(const std::string& unit ) +CUnit CUnit::GetUnitFromString(const std::string& unit ) { CUnit ret; @@ -80,12 +80,12 @@ CUnit GetUnitFromString(const std::string& unit ) &posx, &posy ); - ret.setIDForced((unit_id_t)id); - ret.setTeam((Team)team); - ret.setPlayer((player_id_t)player); - ret.setVisual((unitVis_c)vis); - ret.setDir((dir_t)dir); - ret.setPos(uvector2(posx,posy)); + ret.unit_id = (unit_id_t)id; + ret.team_id = (Team)team; + ret.player_id = (player_id_t)player; + ret.unit_vis = (unitVis_c)vis; + ret.dir = (dir_t)dir; + ret.pos = uvector2(posx,posy); return ret; } diff --git a/game/unit.h b/game/unit.h index 61162e3..cd9cff7 100644 --- a/game/unit.h +++ b/game/unit.h @@ -7,11 +7,20 @@ #include "gametypes.h" #include "vector2.h" +#define UNIT_FORMATTER "UNIT:%u tm:%u pl:%u vs:%c dr:%c ps:[%u,%u]" + // Base unit type class CUnit { public: + // Factory function for creating units from a visual + static CUnit GetUnitFromVis( unitVis_c vis ); + + // Unit <--> string conversion functions + static std::string GetStringFromUnit(const CUnit& unit ); + static CUnit GetUnitFromString(const std::string& unit ); + // Constructor CUnit(); @@ -31,28 +40,23 @@ public: inline const player_id_t& getPlayer() const { return player_id; } inline const unitVis_c& getVisual() const { return unit_vis; } inline const dir_t& getDir() const { return dir; } - - inline Team setTeam(const Team & v) { return (team_id = v); } - inline player_id_t setPlayer(const player_id_t& v) { return ( player_id = v ); } - inline unitVis_c setVisual(const unitVis_c& v) { return ( unit_vis = v ); } - - // Set unit direction - inline dir_t setDir(const dir_t& v) { return (dir = v); } - inline const uvector2& getPos() const { return pos; } - inline void setPos(const uvector2& v) { pos = v; } + // Set + inline Team setTeam(const Team & v) { return (team_id = v); } + inline player_id_t setPlayer(const player_id_t& v) { return ( player_id = v ); } + inline unitVis_c setVisual(const unitVis_c& v) { return ( unit_vis = v ); } + inline dir_t setDir(const dir_t& v) { return (dir = v); } + inline void setPos(const uvector2& v) { pos = v; } - inline const unit_id_t& setIDForced(const unit_id_t& v) { return (unit_id = v); } - - // Get the co-ordinate infront of the unit - uvector2 getInFront() const; + // Get the co-ordinate in front of the unit + uvector2 getInFront() const; // Check unit is valid - inline bool valid() const; + inline bool valid() const; // Set a unit based solely on it's visual - bool setFromVisual( const unitVis_c& vis); + bool setFromVisual( const unitVis_c& vis); // Orientation methods dir_t turnLeft(); @@ -95,13 +99,4 @@ inline bool CUnit::valid() const && (unit_vis != unitVis_invalid); } - -// Factory function for creating units from a visual -CUnit GetUnitFromVis( unitVis_c vis ); - -// Unit <--> string conversion functions -#define UNIT_FORMATTER "UNIT:%u tm:%u pl:%u vs:%c dr:%c ps:[%u,%u]" -std::string GetStringFromUnit(const CUnit& unit ); -CUnit GetUnitFromString(const std::string& unit ); - #endif //_UNIT_H_ diff --git a/test/test.cpp b/test/test.cpp index 8637e03..903ecc1 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -26,8 +26,8 @@ const char* tests() { CUnit unit1; - std::string unit1Desc = GetStringFromUnit(unit1); - CUnit unit2 = GetUnitFromString(unit1Desc); + std::string unit1Desc = CUnit::GetStringFromUnit(unit1); + CUnit unit2 = CUnit::GetUnitFromString(unit1Desc); if ( unit1 != unit2 ) return "Failed to convert an empty unit to string and back"; @@ -41,8 +41,8 @@ const char* tests() unit1.setTeam(Team::Green); unit1.setPos( uvector2(5,10) ); - std::string unit1Desc = GetStringFromUnit(unit1); - CUnit unit2 = GetUnitFromString(unit1Desc); + std::string unit1Desc = CUnit::GetStringFromUnit(unit1); + CUnit unit2 = CUnit::GetUnitFromString(unit1Desc); if ( unit1 != unit2 ) return "Failed to convert custom unit to string and back"; @@ -50,7 +50,7 @@ const char* tests() // Test if we can successfully create a unit from a visual { - CUnit unit = GetUnitFromVis('v'); + CUnit unit = CUnit::GetUnitFromVis('v'); if( unit.getVisual() != 'v' ) return "failed to properly create V unit with factory"; } @@ -82,7 +82,7 @@ const char* tests() CTTRTSGame game( 5, 5 ); { - CUnit unit = GetUnitFromVis('^'); + CUnit unit = CUnit::GetUnitFromVis('^'); unit.setPos( {2,2} ); unit.setPlayer(0); unit.setTeam(Team::Red); @@ -91,7 +91,7 @@ const char* tests() } { - CUnit unit = GetUnitFromVis('^'); + CUnit unit = CUnit::GetUnitFromVis('^'); unit.setPos( {2,2} ); unit.setPlayer(0); unit.setTeam(Team::Red); @@ -108,7 +108,7 @@ const char* tests() { CTTRTSGame game( 5, 5 ); - CUnit unit = GetUnitFromVis('>'); + CUnit unit = CUnit::GetUnitFromVis('>'); const unit_id_t id = unit.getID(); COrder order; @@ -139,7 +139,7 @@ const char* tests() unit_id_t id; { - CUnit unit = GetUnitFromVis('>'); + CUnit unit = CUnit::GetUnitFromVis('>'); id = unit.getID(); COrder order; @@ -157,7 +157,7 @@ const char* tests() return "Game failed to issue valid order"; } { - CUnit unit = GetUnitFromVis('<'); + CUnit unit = CUnit::GetUnitFromVis('<'); unit.setPos( {1,0} ); unit.setPlayer(2); @@ -181,7 +181,15 @@ const char* tests() if ( game.CheckForWin() != Team::Blue ) return "Game failed to recognise a win for the right Team"; - std::cout<