Finalise implementation of reading in a game from a string

This commit is contained in:
Marc Di Luzio 2014-12-16 13:13:02 +00:00
parent 002c1e5927
commit a75e6e290d
8 changed files with 178 additions and 125 deletions

View file

@ -3,6 +3,32 @@
#include <algorithm> #include <algorithm>
#include <string.h> #include <string.h>
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 // Interpret a string of orders
int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders ) int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders )
{ {
@ -201,9 +227,6 @@ int CTTRTSGame::SimulateToNextTurn()
{ {
if( (*it).unit.getID() == id ) 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 // Remove the unit from our alive unit pairs
m_OrderUnitPairs.erase(it); m_OrderUnitPairs.erase(it);
break; break;
@ -361,20 +384,52 @@ std::string CTTRTSGame::GetStateAsString() const
{ {
// Print out the header // Print out the header
char header[64]; 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 // Gather unit information
std::string units; std::string units;
for ( const OrderUnitPair& pair : m_OrderUnitPairs ) for ( const OrderUnitPair& pair : m_OrderUnitPairs )
{ {
units += GetStringFromUnit(pair.unit); units += CUnit::GetStringFromUnit(pair.unit);
units += '\n'; units += '\n';
} }
// Append the header and units // Append the header and units
std::string state(header); std::string state(header);
state += '\n'; state += '\n';
state += GAME_HEADER_DELIMITER;
state += units; state += units;
return state; 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;
}

View file

@ -5,6 +5,9 @@
#include "gametypes.h" #include "gametypes.h"
#include "order.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 // Type for order and unit pairs
struct OrderUnitPair struct OrderUnitPair
{ {
@ -20,61 +23,41 @@ struct OrderUnitPair
, order ( o ) , order ( o )
{} {}
// Move asignment operator // Move assignment operator
inline OrderUnitPair& operator=( OrderUnitPair&& rhs ) { this->unit = std::move(rhs.unit);this->order = rhs.order;rhs.order = COrder(); return *this; } inline OrderUnitPair& operator=( OrderUnitPair&& rhs )
{
this->unit = std::move(rhs.unit);
this->order = std::move(rhs.order);
return *this;
}
CUnit unit; // The unit CUnit unit; // The unit
COrder order; // Order for this unit from this turn COrder order; // Order for this unit from this turn
}; };
// Typedef for a vector of these unit pairs // Typedef for a vector of these unit pairs
typedef std::vector< OrderUnitPair > OrderUnitPairVector; 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 class CTTRTSGame
{ {
public: public:
CTTRTSGame( ucoord_t c, ucoord_t r ) // Get the game information as a string
: dimensions( c,r ) static CTTRTSGame CreateFromString( const std::string& input );
, turn (0)
{
} // Constructors
CTTRTSGame( ucoord_t c, ucoord_t r );
CTTRTSGame(CTTRTSGame&& game);
// Default dtor // move asignment operator
~CTTRTSGame() = default; CTTRTSGame& operator=(CTTRTSGame&& game);
// Issue orders to the game, returns non-zero if orders are incorrect // Simulate and progress to the next turn
int IssueOrders( player_id_t player, const std::string& orders ); // Returns non-zero if simulation failed
int IssueOrders( player_id_t player, const COrderVector& orders ); int SimulateToNextTurn();
// 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; }
// Check for a win, returns invalid for no win state reached // Check for a win, returns invalid for no win state reached
// Note: this function will return invalid a draw was reached // Note: this function will return invalid a draw was reached
@ -84,12 +67,39 @@ public:
// Get the game information as a string // Get the game information as a string
std::string GetStateAsString() const; 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: 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; int VerifyOrder( player_id_t player, const COrder& order ) const;
// Verify Position - non-zero is error
int VerifyPos( uvector2 vec ) const; int VerifyPos( uvector2 vec ) const;
// Get a units new position after an order // Get a units new position after an order
@ -98,19 +108,11 @@ private:
// Get unit by unit ID // Get unit by unit ID
CUnit& GetUnitByID( unit_id_t id ); CUnit& GetUnitByID( unit_id_t id );
// Vector to store points to all units std::string name; // Game Name
OrderUnitPairVector m_OrderUnitPairs; unsigned int turn; // Int to store the current turn
uvector2 dimensions; // Dimensions of the game
// List of dead units OrderUnitPairVector m_OrderUnitPairs; // Vector to store all units and orders
CUnitVector m_deadUnits;
// Dimensions of the game
uvector2 dimensions;
// Int to store the current turn
unsigned int turn;
}; };
#define GAME_HEADER_FORMATTER "===== GAME TURN =====\nSIZE:[%u,%u]\nTURN:%u"
#endif //_GAME_H_ #endif //_GAME_H_

View file

@ -13,16 +13,11 @@ enum class Team : char
NUM_INVALID NUM_INVALID
}; };
// Type for player IDs
typedef unsigned char player_id_t;
// Type for unit IDs typedef unsigned char player_id_t; // Type for player IDs
typedef unsigned short unit_id_t; 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<player_id_t>::max(); static const player_id_t player_id_invalid = std::numeric_limits<player_id_t>::max();
static const unit_id_t unit_id_invalid = std::numeric_limits<unit_id_t>::max(); static const unit_id_t unit_id_invalid = std::numeric_limits<unit_id_t>::max();
static const unitVis_c unitVis_invalid = std::numeric_limits<unitVis_c>::max(); static const unitVis_c unitVis_invalid = std::numeric_limits<unitVis_c>::max();

View file

@ -1,8 +1,6 @@
#include <string.h> #include <string.h>
#include "order.h" #include "order.h"
#include "mathtypes.h"
// Convert an order to a string // Convert an order to a string
std::string GetStringFromOrder(const COrder& order ) std::string GetStringFromOrder(const COrder& order )
{ {

View file

@ -6,6 +6,8 @@
#include "gametypes.h" #include "gametypes.h"
#define ORDER_FORMATTER "ORDER:%c id:%u"
// Type for all orders ( as a char ) // Type for all orders ( as a char )
enum class command_c : char enum class command_c : char
{ {
@ -45,8 +47,6 @@ inline bool COrder::operator== ( const COrder& rhs ) const
// Typedef a vector of orders // Typedef a vector of orders
typedef std::vector<COrder> COrderVector; typedef std::vector<COrder> COrderVector;
#define ORDER_FORMATTER "ORDER:%c id:%u"
// string <--> order conversion functions // string <--> order conversion functions
std::string GetStringFromOrder(const COrder& order ); std::string GetStringFromOrder(const COrder& order );
COrder GetOrderFromString( const std::string& order ); COrder GetOrderFromString( const std::string& order );

View file

@ -31,7 +31,7 @@ namespace
} }
// Get a unit from a visual // Get a unit from a visual
CUnit GetUnitFromVis( unitVis_c vis ) CUnit CUnit::GetUnitFromVis( unitVis_c vis )
{ {
CUnit unit; CUnit unit;
unit.setFromVisual(vis); unit.setFromVisual(vis);
@ -40,26 +40,26 @@ CUnit GetUnitFromVis( unitVis_c vis )
// Get a string descriptor of a unit // 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]" // "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]; static char buff[128];
memset(buff,0,sizeof(buff)); memset(buff,0,sizeof(buff));
snprintf(buff,128, UNIT_FORMATTER, snprintf(buff,128, UNIT_FORMATTER,
unit.getID(), unit.unit_id,
(int)unit.getTeam(), (int)unit.team_id,
unit.getPlayer(), unit.player_id,
unit.getVisual(), unit.unit_vis,
unit.getDir(), unit.dir,
unit.getPos().x, unit.pos.x,
unit.getPos().y ); unit.pos.y );
return buff; return buff;
} }
// Get a unit from a string descriptor // 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]" // "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; CUnit ret;
@ -80,12 +80,12 @@ CUnit GetUnitFromString(const std::string& unit )
&posx, &posx,
&posy ); &posy );
ret.setIDForced((unit_id_t)id); ret.unit_id = (unit_id_t)id;
ret.setTeam((Team)team); ret.team_id = (Team)team;
ret.setPlayer((player_id_t)player); ret.player_id = (player_id_t)player;
ret.setVisual((unitVis_c)vis); ret.unit_vis = (unitVis_c)vis;
ret.setDir((dir_t)dir); ret.dir = (dir_t)dir;
ret.setPos(uvector2(posx,posy)); ret.pos = uvector2(posx,posy);
return ret; return ret;
} }

View file

@ -7,11 +7,20 @@
#include "gametypes.h" #include "gametypes.h"
#include "vector2.h" #include "vector2.h"
#define UNIT_FORMATTER "UNIT:%u tm:%u pl:%u vs:%c dr:%c ps:[%u,%u]"
// Base unit type // Base unit type
class CUnit class CUnit
{ {
public: 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 // Constructor
CUnit(); CUnit();
@ -31,28 +40,23 @@ public:
inline const player_id_t& getPlayer() const { return player_id; } inline const player_id_t& getPlayer() const { return player_id; }
inline const unitVis_c& getVisual() const { return unit_vis; } inline const unitVis_c& getVisual() const { return unit_vis; }
inline const dir_t& getDir() const { return dir; } 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 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 in front of the unit
uvector2 getInFront() const;
// Get the co-ordinate infront of the unit
uvector2 getInFront() const;
// Check unit is valid // Check unit is valid
inline bool valid() const; inline bool valid() const;
// Set a unit based solely on it's visual // Set a unit based solely on it's visual
bool setFromVisual( const unitVis_c& vis); bool setFromVisual( const unitVis_c& vis);
// Orientation methods // Orientation methods
dir_t turnLeft(); dir_t turnLeft();
@ -95,13 +99,4 @@ inline bool CUnit::valid() const
&& (unit_vis != unitVis_invalid); && (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_ #endif //_UNIT_H_

View file

@ -26,8 +26,8 @@ const char* tests()
{ {
CUnit unit1; CUnit unit1;
std::string unit1Desc = GetStringFromUnit(unit1); std::string unit1Desc = CUnit::GetStringFromUnit(unit1);
CUnit unit2 = GetUnitFromString(unit1Desc); CUnit unit2 = CUnit::GetUnitFromString(unit1Desc);
if ( unit1 != unit2 ) if ( unit1 != unit2 )
return "Failed to convert an empty unit to string and back"; return "Failed to convert an empty unit to string and back";
@ -41,8 +41,8 @@ const char* tests()
unit1.setTeam(Team::Green); unit1.setTeam(Team::Green);
unit1.setPos( uvector2(5,10) ); unit1.setPos( uvector2(5,10) );
std::string unit1Desc = GetStringFromUnit(unit1); std::string unit1Desc = CUnit::GetStringFromUnit(unit1);
CUnit unit2 = GetUnitFromString(unit1Desc); CUnit unit2 = CUnit::GetUnitFromString(unit1Desc);
if ( unit1 != unit2 ) if ( unit1 != unit2 )
return "Failed to convert custom unit to string and back"; 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 // Test if we can successfully create a unit from a visual
{ {
CUnit unit = GetUnitFromVis('v'); CUnit unit = CUnit::GetUnitFromVis('v');
if( unit.getVisual() != 'v' ) if( unit.getVisual() != 'v' )
return "failed to properly create V unit with factory"; return "failed to properly create V unit with factory";
} }
@ -82,7 +82,7 @@ const char* tests()
CTTRTSGame game( 5, 5 ); CTTRTSGame game( 5, 5 );
{ {
CUnit unit = GetUnitFromVis('^'); CUnit unit = CUnit::GetUnitFromVis('^');
unit.setPos( {2,2} ); unit.setPos( {2,2} );
unit.setPlayer(0); unit.setPlayer(0);
unit.setTeam(Team::Red); unit.setTeam(Team::Red);
@ -91,7 +91,7 @@ const char* tests()
} }
{ {
CUnit unit = GetUnitFromVis('^'); CUnit unit = CUnit::GetUnitFromVis('^');
unit.setPos( {2,2} ); unit.setPos( {2,2} );
unit.setPlayer(0); unit.setPlayer(0);
unit.setTeam(Team::Red); unit.setTeam(Team::Red);
@ -108,7 +108,7 @@ const char* tests()
{ {
CTTRTSGame game( 5, 5 ); CTTRTSGame game( 5, 5 );
CUnit unit = GetUnitFromVis('>'); CUnit unit = CUnit::GetUnitFromVis('>');
const unit_id_t id = unit.getID(); const unit_id_t id = unit.getID();
COrder order; COrder order;
@ -139,7 +139,7 @@ const char* tests()
unit_id_t id; unit_id_t id;
{ {
CUnit unit = GetUnitFromVis('>'); CUnit unit = CUnit::GetUnitFromVis('>');
id = unit.getID(); id = unit.getID();
COrder order; COrder order;
@ -157,7 +157,7 @@ const char* tests()
return "Game failed to issue valid order"; return "Game failed to issue valid order";
} }
{ {
CUnit unit = GetUnitFromVis('<'); CUnit unit = CUnit::GetUnitFromVis('<');
unit.setPos( {1,0} ); unit.setPos( {1,0} );
unit.setPlayer(2); unit.setPlayer(2);
@ -181,7 +181,15 @@ const char* tests()
if ( game.CheckForWin() != Team::Blue ) if ( game.CheckForWin() != Team::Blue )
return "Game failed to recognise a win for the right Team"; return "Game failed to recognise a win for the right Team";
std::cout<<game.GetStateAsString()<<std::endl; std::string game_string = game.GetStateAsString();
CTTRTSGame game2 = CTTRTSGame::CreateFromString(game_string);
std::string game2_string = game2.GetStateAsString();
// Try matching up the game descriptors
if( game_string != game2_string )
return "Generating new game from string failed";
} }
return 0; return 0;