Finialise the full game step

Had to rework a ton of code from bad design.
NOTE: FRIENDLY FIRE IS ON >:D
This commit is contained in:
Marc Di Luzio 2014-12-16 13:13:01 +00:00
parent 6fc41914f7
commit aee703b107
7 changed files with 379 additions and 57 deletions

View file

@ -1,5 +1,6 @@
#include "game.h"
#include <algorithm>
// 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 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 )
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

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -14,21 +14,27 @@ public:
CUnit();
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 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:

View file

@ -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); }
};
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_

View file

@ -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";
}
{
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;
}