diff --git a/CMakeLists.txt b/CMakeLists.txt index 7666aaa..bf5de03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,13 @@ cmake_minimum_required( VERSION 2.8.7 ) -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11 -Wall -Wno-reorder" ) +# Use c++1y (14) +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++1y" ) + +# Turn on all warnings +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-reorder" ) + +# Turn off reorder warnings as they're kind of irrelevant +set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-reorder" ) if( CMAKE_BUILD_TYPE MATCHES "Debug" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g" ) diff --git a/README.md b/README.md index da359ed..4c2c2a1 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ We aim to create a simple terminal based rts where a user can program an AI to c 5. repeat until an end state is reached 4. once game is finished, host and clients disconnect and a winner is notified -*see [the game directory](game) for full game rules* +*see [game](game) for full game rules* ------------------------------------------------------------------------------------ ## Source @@ -48,7 +48,7 @@ Wrapper for user interface for the terminal, this only really needs three stages * Initialise the game with settings and connect the clients * Run the game simulation to it's conclusion * Display the game result -* Acsii Colour wrapper for separate teams +* ASCII Colour wrapper for separate teams ##### maths simple maths library for 2D calculations and types diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 79b8f0a..56140be 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -7,9 +7,6 @@ include_directories( ../maths ) -# Set to use c++11, because we're cool like that -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11" ) - # Add the sources set( SOURCES game.cpp diff --git a/game/README.md b/game/README.md index 53a2077..f04313e 100644 --- a/game/README.md +++ b/game/README.md @@ -1,13 +1,13 @@ ttrts Game Design ================= -The game takes place in a series of simultanious turns on an arbitrarilly sized 2D board. +The game takes place in a series of simultaneous turns on an arbitrarily sized 2D board. -Each player is in control of a set number of starting units, each turn recieves data on the status of the board. +Each player is in control of a set number of starting units, each turn receives data on the status of the board. -Each player must then issue a single command to each unit in thier control. +Each player must then issue a single command to each unit in their control. -The engine then takes all commands, evaluates all movement first simultaniously, then all other commands. +The engine then takes all commands, evaluates all movement first simultaneously, then all other commands. All attempted movement to the same square by two or more units will fail. diff --git a/game/game.cpp b/game/game.cpp index ef0f4f2..8f4e988 100644 --- a/game/game.cpp +++ b/game/game.cpp @@ -1,6 +1,7 @@ #include "game.h" #include +#include // Interpret a string of orders int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders ) @@ -68,8 +69,8 @@ int CTTRTSGame::IssueOrder( player_id_t player, const COrder& order ) int CTTRTSGame::VerifyPos(uvector2 vec) const { // Simply check if within the bounds of our dimensions for now - if ( ( vec.x >= dimentions.x ) - || ( vec.y >= dimentions.y ) ) + if ( ( vec.x >= dimensions.x ) + || ( vec.y >= dimensions.y ) ) { return 1; } @@ -224,20 +225,19 @@ int CTTRTSGame::SimulateToNextTurn() int CTTRTSGame::AddUnit( CUnit&& unit ) { // Verify the unit - const int val = unit.valid(); - if( val ) - return val; + if( !unit.valid() ) + return 1; // 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) ) - return 1; + if( (pos.x >= dimensions.x) || (pos.y >= dimensions.y) ) + return 2; // If any unit's position matches, reject this for ( const OrderUnitPair& pair: m_OrderUnitPairs ) { if( pair.unit.getPos() == unit.getPos() ) - return 2; + return 3; } // Add the unit with a blank order @@ -315,3 +315,40 @@ CUnit& CTTRTSGame::GetUnitByID( unit_id_t id ) static CUnit invalid_unit; return invalid_unit; } + +// Check if we have a win state +Team CTTRTSGame::CheckForWin() const +{ + // Array of units for each Team + unsigned int units[(int) Team::NUM_INVALID]; + memset(units,0,sizeof(units)); + + // Count up all the units for each Team + for ( const OrderUnitPair& pair : m_OrderUnitPairs ) + { + const int team = (int)pair.unit.getTeam(); + units[team] += 1; + } + + // Default winning Team to invalid (no win) + Team winningTeam = Team::NUM_INVALID; + + // For each of the teams + for ( unsigned int i = 0; i < _countof(units); i++ ) + { + // if there are still units in this Team, and the winning Team hasn't been set + if( units[i] > 0 && winningTeam == Team::NUM_INVALID ) + { + winningTeam = (Team)i; + } + // Otherwise, if there are units in this Team and the winning Team HAS been set + else if ( units[i] > 0 ) + { + // Set back to invalid and break out of the loop + winningTeam = Team::NUM_INVALID; + break; + } + } + + return winningTeam; +} \ No newline at end of file diff --git a/game/game.h b/game/game.h index 9142265..f58d071 100644 --- a/game/game.h +++ b/game/game.h @@ -35,7 +35,7 @@ class CTTRTSGame public: CTTRTSGame( ucoord_t c, ucoord_t r ) - : dimentions( {c,r} ) + : dimensions( c,r ) { } @@ -72,17 +72,19 @@ public: // Get orders by index as above inline const COrder& GetOrdersByIndex( unsigned int i ) const { return m_OrderUnitPairs[i].order; } - // Get dimentions - inline const uvector2& GetDimentions() const { return dimentions; } + // Get dimensions + inline const uvector2 &GetDimensions() const { return dimensions; } + + // Check for a win, returns invalid for no win state reached + // Note: this function will return invalid a draw was reached + // best practice would be to call with GetNumUnits() == 0 + Team CheckForWin() const; private: // Verify any order - non-zero is error int VerifyOrder( player_id_t player, const COrder& order ) const; - // Verify any order - non-zero is error - int VerifyUnit( const CUnit& unit ) const; - // Verify Position - non-zero is error int VerifyPos( uvector2 vec ) const; @@ -99,7 +101,7 @@ private: CUnitVector m_deadUnits; // Dimensions of the game - uvector2 dimentions; + uvector2 dimensions; }; #endif //_GAME_H_ diff --git a/game/gametypes.h b/game/gametypes.h index 903ac9a..b988a48 100644 --- a/game/gametypes.h +++ b/game/gametypes.h @@ -4,25 +4,27 @@ #include // std::numeric_limits // Type for a team IDs -typedef unsigned short team_id_t; +enum class Team : char +{ + Red = 0, + Blue, + Green, + Yellow, + NUM_INVALID +}; // Type for player IDs -typedef unsigned short player_id_t; +typedef unsigned char player_id_t; // Type for unit IDs typedef unsigned short unit_id_t; -// Type for the unit type-id -typedef char unitType_c; - // Typedef for unit visual representations typedef char unitVis_c; // Invalid data for above types -static const team_id_t team_id_invalid = std::numeric_limits::max(); 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 unitType_c unitType_invalid = std::numeric_limits::max(); static const unitVis_c unitVis_invalid = std::numeric_limits::max(); #endif //_GAME_TYPES_H_ \ No newline at end of file diff --git a/game/orders.cpp b/game/orders.cpp index 514ee51..836d4e8 100644 --- a/game/orders.cpp +++ b/game/orders.cpp @@ -24,7 +24,7 @@ COrder GetOrderFromString( const std::string& _order ) { const std::string order_unit = order.substr(0, pos); - ret.unit = atoi( order_unit.c_str() ); + ret.unit = (unit_id_t)atoi( order_unit.c_str() ); // Erase everything up to and including the delimiter order.erase(0, pos + 1); diff --git a/game/orders.h b/game/orders.h index 28ee471..558682f 100644 --- a/game/orders.h +++ b/game/orders.h @@ -15,7 +15,7 @@ enum class order_c : char L = 'L', R = 'R', A = 'A', - INVALID + NUM_INVALID }; // Container for an order @@ -24,7 +24,7 @@ struct COrder // Base constructor makes invalid order COrder() : unit ( unit_id_invalid ) - , order ( order_c::INVALID ) + , order ( order_c::NUM_INVALID ) {} // Unit order is for diff --git a/game/unit.cpp b/game/unit.cpp index b69d36d..5b52713 100644 --- a/game/unit.cpp +++ b/game/unit.cpp @@ -32,7 +32,7 @@ namespace // Plain constructor CUnit::CUnit() : unit_id ( get_unique_unit_id() ) -, team_id ( team_id_invalid ) +, team_id ( Team::NUM_INVALID ) , unit_vis ( unitVis_invalid ) , player_id ( player_id_invalid ) , dir ( dir_t::S ) diff --git a/game/unit.h b/game/unit.h index 346131d..4c6d13f 100644 --- a/game/unit.h +++ b/game/unit.h @@ -24,15 +24,14 @@ public: // Getters for all the members inline const unit_id_t& getID() const { return unit_id; } - inline const team_id_t& getTeam() const { return team_id; } + inline const Team & 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 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); } @@ -69,7 +68,7 @@ private: unitVis_c unit_vis; // Team ID - team_id_t team_id; + Team team_id; // Owner ID player_id_t player_id; @@ -88,7 +87,7 @@ typedef std::vector< CUnit > CUnitVector; inline bool CUnit::valid() const { return (unit_id != unit_id_invalid ) - && (team_id != team_id_invalid ) + && (team_id != Team::NUM_INVALID ) && (player_id != player_id_invalid) && (unit_vis != unitVis_invalid); } diff --git a/maths/vector2.h b/maths/vector2.h index 9be4019..6552807 100644 --- a/maths/vector2.h +++ b/maths/vector2.h @@ -7,6 +7,11 @@ struct uvector2; struct vector2 { + vector2( coord_t _x, coord_t _y ) + : x(_x) + , y(_y) + {} + coord_t x; coord_t y; @@ -27,6 +32,11 @@ struct vector2 struct uvector2 { + uvector2( ucoord_t _x, ucoord_t _y ) + : x(_x) + , y(_y) + {} + ucoord_t x; ucoord_t y; @@ -54,22 +64,19 @@ inline vector2 vecFromDir( dir_t 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 }; + default: + return { 0,0 }; + } } #endif //_VECTOR2_H_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ef211e..c212c3a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -13,9 +13,6 @@ set( SOURCES test.cpp ) -# Set to use c++11, because we're cool like that -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11" ) - # Add the executable add_executable( ttrts-test ${SOURCES} ) diff --git a/test/test.cpp b/test/test.cpp index c506e68..1306d1e 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -59,6 +59,7 @@ const char* tests() CUnit unit = CUnit::getUnitFromVis('^'); unit.setPos( {2,2} ); unit.setPlayer(0); + unit.setTeam(Team::Red); game.AddUnit(std::move(unit)); } @@ -67,6 +68,7 @@ const char* tests() CUnit unit = CUnit::getUnitFromVis('^'); unit.setPos( {2,2} ); unit.setPlayer(0); + unit.setTeam(Team::Red); if( !game.AddUnit(std::move(unit)) ) return "Game should have rejected unit placed on the same spot"; @@ -86,6 +88,7 @@ const char* tests() unit.setPos( {2,2} ); unit.setPlayer(0); + unit.setTeam(Team::Red); if ( game.AddUnit(std::move(unit)) ) return "Game failed to add valid unit"; @@ -115,7 +118,8 @@ const char* tests() COrder order; unit.setPos( {0,0} ); - unit.setPlayer(0); + unit.setPlayer(1); + unit.setTeam(Team::Blue); if ( game.AddUnit(std::move(unit)) ) return "Game failed to add valid unit"; @@ -130,7 +134,8 @@ const char* tests() CUnit unit = CUnit::getUnitFromVis('<'); unit.setPos( {1,0} ); - unit.setPlayer(1); + unit.setPlayer(2); + unit.setTeam(Team::Red); if ( game.AddUnit(std::move(unit)) ) return "Game failed to add valid unit"; @@ -146,6 +151,9 @@ const char* tests() if ( game.GetUnitByIndex(0).getID() != id ) return "Game killed the wrong unit"; + + if ( game.CheckForWin() != Team::Blue ) + return "Game failed to recognise a win for the right Team"; } return 0; diff --git a/ttrts/CMakeLists.txt b/ttrts/CMakeLists.txt index e1dd18b..8258be5 100644 --- a/ttrts/CMakeLists.txt +++ b/ttrts/CMakeLists.txt @@ -7,8 +7,5 @@ set( SOURCES main.cpp ) -# Set to use c++11, because we're cool like that -set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --std=c++11" ) - # Add the executable add_executable( ttrts ${SOURCES} ) \ No newline at end of file