From aee703b107152528c2aa920678923f34e17616ff Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Tue, 16 Dec 2014 13:13:01 +0000 Subject: [PATCH] Finialise the full game step Had to rework a ton of code from bad design. NOTE: FRIENDLY FIRE IS ON >:D --- game/game.cpp | 171 +++++++++++++++++++++++++++++++++++++++--------- game/game.h | 55 +++++++++++----- game/orders.h | 10 ++- game/unit.cpp | 92 +++++++++++++++++++++++++- game/unit.h | 18 +++-- maths/vector2.h | 59 ++++++++++++++++- test/test.cpp | 31 +++++++-- 7 files changed, 379 insertions(+), 57 deletions(-) diff --git a/game/game.cpp b/game/game.cpp index 8d6f899..701d6ed 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -1,5 +1,6 @@ #include "game.h" +#include // Interpret a string of orders int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders ) @@ -40,34 +41,81 @@ int CTTRTSGame::IssueOrder( player_id_t player, const COrder& order ) if ( VerifyOrder(player,order) ) return 1; - m_orders.push_back(order); + for ( OrderUnitPair& pair : m_OrderUnitPairs ) + { + if ( pair.unit.getID() == order.unit ) + { + pair.order = order; + return 0; + } + } - return 0; + return 1; +} + +// Verify a position +int CTTRTSGame::VerifyPos(uvector2 vec) const +{ + if ( ( vec.x >= dimentions.x ) + || ( vec.y >= dimentions.y ) ) + { + return 1; + } + + return 0; +} + + +// Get a units new position +uvector2 CTTRTSGame::GetNewPosition( const OrderUnitPair& pair ) const +{ + switch ( pair.order.order ) + { + case order_c::F: + return pair.unit.getInFront(); + } + + return { ucoord_invalid,ucoord_invalid }; } // Simulate and progress to the next turn // Returns non-zero if simulation failed int CTTRTSGame::SimulateToNextTurn() { - int error; - - OrderUnitPairVector orderPairs; - - // Grab all movement orders - for ( auto order : m_orders ) - { - const OrderUnitPair pair = { order, GetUnitByID(order.unit) }; - orderPairs.push_back(pair); - } + int error = 0; // Attempt all movement orders - for ( auto pair : orderPairs ) + for ( OrderUnitPair& pair : m_OrderUnitPairs ) { switch ( pair.order.order ) { case order_c::F: { // Verify new unit position will be on the board + uvector2 newpos = GetNewPosition(pair); + + // Verify the position is even available + bool possible = ( VerifyPos(newpos) == 0 ); + + if ( possible ) + { + // If any unit is in this spot, or moving unit moving to said spot, reject this + for ( const OrderUnitPair& pair2 : m_OrderUnitPairs ) + { + if( GetNewPosition(pair2) != newpos ) + { + possible = false; + break; + } + } + } + + // If the movement is still possible + if ( possible ) + { + pair.unit.setPos(newpos); + pair.order = COrder(); + } } break; } @@ -77,29 +125,74 @@ int CTTRTSGame::SimulateToNextTurn() std::vector< unit_id_t > toKill; // Attempt all actions - for ( auto pair : orderPairs ) + for ( OrderUnitPair& pair : m_OrderUnitPairs ) { switch ( pair.order.order ) { case order_c::A: { // Verify that there's a unit in front to attack + uvector2 infront = pair.unit.getInFront(); + + // Check if there's any unit in front + // FRIENDLY FIRE IS ENABLED + for ( const OrderUnitPair& pair2 : m_OrderUnitPairs ) + { + // if the unit is infront of our unit, then add it to the kill list + if( pair2.unit.getPos() == infront ) + { + toKill.push_back(pair.unit.getID()); + pair.order = COrder(); + break; + } + } } break; case order_c::L: + { + pair.unit.turnLeft(); + pair.order = COrder(); + } + break; case order_c::R: - // Nothing needed here, these orders can always be carried out + { + pair.unit.turnRight(); + pair.order = COrder(); + } break; } } + // Sort and erase all duplicates + std::sort( toKill.begin(), toKill.end() ); + toKill.erase( std::unique( toKill.begin(), toKill.end() ), toKill.end() ); + + // Iterate through all kill orders for ( auto id : toKill ) { + // Kill the units + for ( OrderUnitPairVector::iterator it = m_OrderUnitPairs.begin(); + it != m_OrderUnitPairs.end(); + it++ ) + { + 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; + } + } } // Clear all orders - m_orders.resize(0); + for ( OrderUnitPair& pair : m_OrderUnitPairs ) + { + pair.order = COrder(); + } return error; } @@ -114,10 +207,11 @@ int CTTRTSGame::AddUnit( CUnit&& unit ) // Verify if the unit can be placed on the current board const uvector2 pos = unit.getPos(); - if( (pos.x < dimentions.x) && (pos.y < dimentions.y) ) + if( (pos.x >= dimentions.x) || (pos.y >= dimentions.y) ) return 1; - m_allUnits.push_back(std::move(unit)); + // Add the unit with a blank order + m_OrderUnitPairs.push_back( OrderUnitPair(std::move(unit), COrder()) ); return 0; } @@ -141,35 +235,52 @@ int CTTRTSGame::AddUnits( CUnitVector&& units ) // Verify any order int CTTRTSGame::VerifyOrder( player_id_t player, const COrder& order ) const { + int ret = 1; + // Grab the unit ID const unit_id_t unitID = order.unit; - // Attempt to find the unit - bool unitFound = false; - for ( const CUnit& unit : m_allUnits ) + // Attempt to find the unit + for ( const OrderUnitPair& pair : m_OrderUnitPairs ) { - if ( unit.getID() == unitID ) + if ( pair.unit.getID() == unitID ) { - unitFound = true; + ret = 0; break; } } // for now, as long as the unit exists we can attempt the order - return unitFound; + return ret; } - // Get unit by unit ID -const CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) const +const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const { - CUnitVector::const_iterator it; + CUnitVector::iterator it; - for ( const CUnit& unit : m_allUnits ) + for ( const OrderUnitPair& pair : m_OrderUnitPairs ) { // Attempt the unit add - if ( unit.getID() ) - return unit; + if ( pair.unit.getID() ) + return pair.unit; + } + + // Return an invalid unit + static CUnit invalid_unit; + return invalid_unit; +} + +// Get unit by unit ID +CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) +{ + CUnitVector::iterator it; + + for ( OrderUnitPair& pair : m_OrderUnitPairs ) + { + // Attempt the unit add + if ( pair.unit.getID() ) + return pair.unit; } // Return an invalid unit diff --git a/game/game.h b/game/game.h index c13024e..2ea176a 100644 --- a/game/game.h +++ b/game/game.h @@ -12,8 +12,27 @@ typedef std::vector< CUnit > CUnitVector; // Type for order and unit pairs struct OrderUnitPair { - const COrder& order; - const CUnit& unit; + // Straight up move constructor + OrderUnitPair( OrderUnitPair&& other ) + : unit ( std::move(other.unit) ) + , order ( other.order ) + { + + } + + // Multi parameter constructor + OrderUnitPair( CUnit&& u, COrder o ) + : unit ( std::move(u) ) + , order ( o ) + { + + } + + // Move asignment operator + inline OrderUnitPair& operator=( OrderUnitPair&& rhs ) { *this = std::move(rhs); return *this; } + + CUnit unit; + COrder order; }; typedef std::vector< OrderUnitPair > OrderUnitPairVector; @@ -48,36 +67,42 @@ public: int AddUnits( CUnitVector&& units ); // Get the number of units - inline unsigned int GetNumUnits() const { return m_allUnits.size(); } + 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_allUnits[i]; } + inline const CUnit& GetUnitByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].unit; } // Get unit by unit ID - const CUnit& GetUnitByID( unit_id_t id ) const; - - // Get the number of order - inline unsigned int GetNumOrders() const { return m_orders.size(); } + const CUnit& GetUnitByIDConst( unit_id_t id ) const; // Get orders by index as above - inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_orders[i]; } + inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; } // Get dimentions inline const uvector2& GetDimentions() const { return dimentions; } private: - // Verify any order + // Verify any order - non-zero is error int VerifyOrder( player_id_t player, const COrder& order ) const; - // Verify any order + // Verify any order - non-zero is error int VerifyUnit( const CUnit& unit ) const; - // Vector to store points to all units - CUnitVector m_allUnits; + // Verify Position - non-zero is error + int VerifyPos( uvector2 vec ) const; - // Orders to execute this turn - COrderVector m_orders; + // Get a units new position after an order + uvector2 GetNewPosition( const OrderUnitPair& pair ) const; + + // 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 dimentions; diff --git a/game/orders.h b/game/orders.h index 400f2b3..4961af7 100644 --- a/game/orders.h +++ b/game/orders.h @@ -14,7 +14,8 @@ enum class order_c : char F = 'F', L = 'L', R = 'R', - A = 'A' + A = 'A', + INVALID }; // Movement orders @@ -34,6 +35,13 @@ static const order_c sk_actionOrders[] = // Container for an order struct COrder { + COrder() + : unit ( unit_id_invalid ) + , order ( order_c::INVALID ) + { + + } + // Unit order is for unit_id_t unit; diff --git a/game/unit.cpp b/game/unit.cpp index 30bc711..d70d0a7 100644 --- a/game/unit.cpp +++ b/game/unit.cpp @@ -36,6 +36,7 @@ CUnit::CUnit() , player_id ( player_id_invalid ) , unit_vis ( unitVis_invalid ) , dir ( dir_t::S ) +, pos ( { ucoord_invalid, ucoord_invalid } ) { updateMyVisual(); }; @@ -47,6 +48,7 @@ CUnit::CUnit(CUnit&& unit) , player_id ( std::move(unit.player_id) ) , unit_vis ( std::move(unit.unit_vis) ) , dir ( std::move(unit.dir) ) +, pos ( std::move(unit.pos) ) { updateMyVisual(); } @@ -81,7 +83,7 @@ bool CUnit::setFromVisual( const unitVis_c& vis ) { if( it->second == vis ) { - dir == it->first; + dir = it->first; updateMyVisual(); return true; } @@ -90,3 +92,91 @@ bool CUnit::setFromVisual( const unitVis_c& vis ) // No matching direction to visual return false; } + +// Turn unit left +dir_t CUnit::turnLeft() +{ + switch( dir ) + { + case dir_t::N: + dir = dir_t::W; + break; + + case dir_t::E: + dir = dir_t::N; + break; + + case dir_t::S: + dir = dir_t::E; + break; + + case dir_t::W: + dir = dir_t::S; + break; + } + + updateMyVisual(); + + return getDir(); +} + +// Turn unit right +dir_t CUnit::turnRight() +{ + switch( dir ) + { + case dir_t::N: + dir = dir_t::E; + break; + + case dir_t::E: + dir = dir_t::S; + break; + + case dir_t::S: + dir = dir_t::W; + break; + + case dir_t::W: + dir = dir_t::N; + break; + } + + updateMyVisual(); + + return getDir(); +} + +// Turn unit around +dir_t CUnit::turnAround() +{ + switch( dir ) + { + case dir_t::N: + dir = dir_t::S; + break; + + case dir_t::E: + dir = dir_t::W; + break; + + case dir_t::S: + dir = dir_t::N; + break; + + case dir_t::W: + dir = dir_t::E; + break; + } + + updateMyVisual(); + + return getDir(); +} + +// Get the co-ordinate infront of the unit +uvector2 CUnit::getInFront() const +{ + vector2 delta = vecFromDir(dir); + return pos + delta; +} diff --git a/game/unit.h b/game/unit.h index cc211c8..ebd5852 100644 --- a/game/unit.h +++ b/game/unit.h @@ -13,22 +13,28 @@ class CUnit public: CUnit(); - CUnit(CUnit&& unit); + CUnit(CUnit&& unit); + CUnit& operator=(CUnit&& unit) { *this = std::move(unit); return *this; } ~CUnit() = default; inline const unit_id_t& getID() const { return unit_id; } inline const team_id_t& getTeam() const { return team_id; } 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; } // Return non-zero values on error - inline int setTeam(const team_id_t& v) { return (v == team_id_invalid) ? -1 : (( team_id = v ), 0); } - inline int setPlayer(const player_id_t& v) { return (v == player_id_invalid) ? -1 : (( player_id = v ), 0); } - inline int setVisual(const unitVis_c& v) { return (v == unitVis_invalid) ? -1 : (( unit_vis = v ), 0); } + inline int setTeam(const team_id_t& v) { return (v == team_id_invalid) ? -1 : (( team_id = v ), 0); } + inline int setPlayer(const player_id_t& v) { return (v == player_id_invalid) ? -1 : (( player_id = v ), 0); } + inline int setVisual(const unitVis_c& v) { return (v == unitVis_invalid) ? -1 : (( unit_vis = v ), 0); } + 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; } + // Get the co-ordinate infront of the unit + uvector2 getInFront() const; + // Check unit is valid inline bool valid() const; @@ -38,6 +44,10 @@ public: // Factory function for creating units from a visual static CUnit getUnitFromVis( unitVis_c vis ); + dir_t turnLeft(); + dir_t turnRight(); + dir_t turnAround(); + protected: diff --git a/maths/vector2.h b/maths/vector2.h index fe00dec..9be4019 100644 --- a/maths/vector2.h +++ b/maths/vector2.h @@ -3,16 +3,73 @@ #include "mathtypes.h" +struct uvector2; + struct vector2 { coord_t x; coord_t y; + + inline vector2 operator-() const { return { (coord_t)-x, (coord_t)-y }; } + + inline operator uvector2() const; + + // vec + inline vector2 operator+(const vector2& rhs) const { return { (coord_t)(rhs.x + x) , (coord_t)(rhs.y + y) }; } + inline vector2 operator-(const vector2& rhs) const { return *this + (-rhs); } + + inline const vector2& operator+=(const vector2& rhs) { *this = *this+rhs; return *this; } + inline const vector2& operator-=(const vector2& rhs) { return *this+=(-rhs); } + + inline bool operator==(const vector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); } + inline bool operator!=(const vector2& rhs) const { return !(*this==rhs); } }; struct uvector2 { ucoord_t x; ucoord_t y; + + // Implicit conversion to vector 2 if needed + inline operator vector2() const { return { (coord_t)x, (coord_t)y }; } + + inline uvector2 operator-() const { return { (ucoord_t)-x, (ucoord_t)-y }; } + + // uvec + inline uvector2 operator+(const uvector2& rhs) const { return { (ucoord_t)(rhs.x + x) , (ucoord_t)(rhs.y + y) }; } + inline uvector2 operator-(const uvector2& rhs) const { return *this + (-rhs); } + + inline const uvector2& operator+=(const uvector2& rhs) { *this = *this+rhs; return *this; } + inline const uvector2& operator-=(const uvector2& rhs) { return *this+=(-rhs); } + + inline bool operator==(const uvector2& rhs) const { return ( rhs.x == x) && ( rhs.y == y); } + inline bool operator!=(const uvector2& rhs) const { return !(*this==rhs); } }; -#endif //_VECTOR2_H_ \ No newline at end of file +inline vector2::operator uvector2() const { return { (ucoord_t)x, (ucoord_t)y }; } + +inline vector2 vecFromDir( dir_t dir ) +{ + switch( dir ) + { + case dir_t::N: + return { 0,1 }; + break; + + case dir_t::E: + return { 1,0 }; + break; + + case dir_t::S: + return { 0,-1 }; + break; + + case dir_t::W: + return { -1,0 }; + break; + } + + return { 0,0 }; +} + +#endif //_VECTOR2_H_ diff --git a/test/test.cpp b/test/test.cpp index c4b5864..b236270 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -68,13 +68,34 @@ const char* tests() if( game.SimulateToNextTurn() ) return "Failed to simulate a blank game"; - if( game.GetNumOrders() ) - return "Game started with non-zero order number"; - - if( game.GetNumUnits() ) - return "Game started with non-zero unit number"; + if( game.GetNumUnits() ) + return "Game started with non-zero unit number"; } + { + CTTRTSGame game( 5, 5 ); + + CUnit unit = CUnit::getUnitFromVis('>'); + const unit_id_t id = unit.getID(); + COrder order; + + unit.setPos( {2,2} ); + unit.setPlayer(0); + + game.AddUnit(std::move(unit)); + + order.unit = id; + order.order = order_c::F; + + game.IssueOrder(0,order); + + game.SimulateToNextTurn(); + + if( game.GetUnitByIDConst(id).getPos() != uvector2{3,2} ) + return "Simple movement order failed"; + + } + return nullptr; }