Move source code into source subfolder
This commit is contained in:
parent
870f459f75
commit
d0d3834449
23 changed files with 0 additions and 0 deletions
23
source/CMakeLists.txt
Normal file
23
source/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
|||
cmake_minimum_required( VERSION 2.8.7 )
|
||||
|
||||
# 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" )
|
||||
endif()
|
||||
|
||||
# Subprojects
|
||||
add_subdirectory( ttrts )
|
||||
add_subdirectory( game )
|
||||
add_subdirectory( ui )
|
||||
|
||||
# Auxhilary binaries
|
||||
add_subdirectory( test )
|
||||
add_subdirectory( gen )
|
17
source/game/CMakeLists.txt
Normal file
17
source/game/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
# game project
|
||||
project( game )
|
||||
|
||||
include_directories(
|
||||
../maths
|
||||
)
|
||||
|
||||
# Add the sources
|
||||
set( SOURCES
|
||||
game.cpp
|
||||
unit.cpp
|
||||
order.cpp
|
||||
)
|
||||
|
||||
add_library( game ${SOURCES} )
|
32
source/game/README.md
Normal file
32
source/game/README.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
Game Design
|
||||
=================
|
||||
|
||||
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 receives data on the status of the board.
|
||||
|
||||
Each player must then issue a single command to each unit in their control.
|
||||
|
||||
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.
|
||||
|
||||
Friendly fire is enabled by default
|
||||
|
||||
--------------------------------------------------------
|
||||
|
||||
Units
|
||||
-----
|
||||
|
||||
Currently only one unit, this will be expanded in the future.
|
||||
|
||||
Units have a set of properties, and commands than can be issued.
|
||||
|
||||
All units take one hit to kill.
|
||||
|
||||
##### properties
|
||||
See [the unit header](unit.h) for full details on unit properties
|
||||
|
||||
##### orders
|
||||
Commands take the form of a single char literal.
|
||||
See [the order header](order.h) for details on the orders
|
435
source/game/game.cpp
Normal file
435
source/game/game.cpp
Normal file
|
@ -0,0 +1,435 @@
|
|||
#include "game.h"
|
||||
|
||||
#include <algorithm>
|
||||
#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
|
||||
int CTTRTSGame::IssueOrders( player_id_t player, const std::string& _orders )
|
||||
{
|
||||
COrderVector orderVector;
|
||||
|
||||
// Copy the const orders into a buffer we can edit
|
||||
std::string orders = _orders;
|
||||
|
||||
// Find a line end
|
||||
size_t pos;
|
||||
while ( (pos = orders.find('\n')) != std::string::npos )
|
||||
{
|
||||
// Grab the string up to the line end
|
||||
const std::string sorder = orders.substr(0, pos);
|
||||
|
||||
// Erase all of string up to and including the line end
|
||||
orders.erase(0,pos+1);
|
||||
|
||||
// Create an order from the string and push it back
|
||||
COrder order = GetOrderFromString( sorder );
|
||||
orderVector.push_back(order);
|
||||
}
|
||||
|
||||
// Call our add order by vector method
|
||||
return IssueOrders(player,orderVector);
|
||||
}
|
||||
|
||||
// Issue orders by vector to the game
|
||||
int CTTRTSGame::IssueOrders( player_id_t player, const COrderVector& orders )
|
||||
{
|
||||
// verify all the orders
|
||||
for ( auto order : orders )
|
||||
{
|
||||
// If any order returns non-zero, back out
|
||||
if ( IssueOrder(player,order) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Issue a single order
|
||||
int CTTRTSGame::IssueOrder( player_id_t player, const COrder& order )
|
||||
{
|
||||
// Verify the order
|
||||
if ( VerifyOrder(player,order) )
|
||||
return 1;
|
||||
|
||||
// Get the right unit for the order
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
if ( pair.unit.getID() == order.unit )
|
||||
{
|
||||
pair.order = order;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Unit was not found, return 2
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Verify a position
|
||||
int CTTRTSGame::VerifyPos(uvector2 vec) const
|
||||
{
|
||||
// Simply check if within the bounds of our dimensions for now
|
||||
if ( ( vec.x >= dimensions.x )
|
||||
|| ( vec.y >= dimensions.y ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Get a units new position
|
||||
uvector2 CTTRTSGame::GetNewPosition( const OrderUnitPair& pair ) const
|
||||
{
|
||||
|
||||
// Grab the order
|
||||
switch ( pair.order.command)
|
||||
{
|
||||
// For forward orders, grab in front
|
||||
case command_c::F:
|
||||
return pair.unit.getInFront();
|
||||
break;
|
||||
// For all other orders, just grab the old position
|
||||
default:
|
||||
return pair.unit.getPos();
|
||||
}
|
||||
}
|
||||
|
||||
// Simulate and progress to the next turn
|
||||
// Returns non-zero if simulation failed
|
||||
int CTTRTSGame::SimulateToNextTurn()
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
// Attempt all movement orders
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
switch ( pair.order.command)
|
||||
{
|
||||
case command_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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Vector of units to kill
|
||||
std::vector< unit_id_t > toKill;
|
||||
|
||||
// Attempt all actions
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
switch ( pair.order.command)
|
||||
{
|
||||
case command_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(pair2.unit.getID());
|
||||
pair.order = COrder();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case command_c::L:
|
||||
{
|
||||
// Simply turn left
|
||||
pair.unit.turnLeft();
|
||||
pair.order = COrder();
|
||||
}
|
||||
break;
|
||||
case command_c::R:
|
||||
{
|
||||
// Simply turn right
|
||||
pair.unit.turnRight();
|
||||
pair.order = COrder();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
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 )
|
||||
{
|
||||
// Remove the unit from our alive unit pairs
|
||||
m_OrderUnitPairs.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Clear all orders
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
pair.order = COrder();
|
||||
}
|
||||
|
||||
// Increment the current turn
|
||||
turn++;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
// Add a unit, nonzero return value indicates error
|
||||
int CTTRTSGame::AddUnit( CUnit&& unit )
|
||||
{
|
||||
// Verify the unit
|
||||
if( !unit.valid() )
|
||||
return 1;
|
||||
|
||||
// Verify if the unit can be placed on the current board
|
||||
const uvector2 pos = unit.getPos();
|
||||
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 3;
|
||||
}
|
||||
|
||||
// Add the unit with a blank order
|
||||
m_OrderUnitPairs.push_back( OrderUnitPair(std::move(unit), COrder()) );
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add a units, nonzero return value indicates error
|
||||
int CTTRTSGame::AddUnits( CUnitVector&& units )
|
||||
{
|
||||
CUnitVector::iterator it;
|
||||
|
||||
for ( it = units.begin(); it != units.end(); it++ )
|
||||
{
|
||||
// Attempt the unit add
|
||||
if ( AddUnit( std::move(*it) ) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
// All units added successfully
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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
|
||||
for ( const OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
// Accept if we have the unit
|
||||
if ( pair.unit.getID() == unitID )
|
||||
{
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// for now, as long as the unit exists we can attempt the order
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Get unit by unit ID
|
||||
const CUnit& CTTRTSGame::GetUnitByIDConst( unit_id_t id ) const
|
||||
{
|
||||
for ( const OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
// Attempt the unit add
|
||||
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 )
|
||||
{
|
||||
for ( OrderUnitPair& pair : m_OrderUnitPairs )
|
||||
{
|
||||
// Attempt the unit add
|
||||
if ( pair.unit.getID() )
|
||||
return pair.unit;
|
||||
}
|
||||
|
||||
// Return an invalid unit
|
||||
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;
|
||||
}
|
||||
|
||||
// Get the game information as a string
|
||||
std::string CTTRTSGame::GetStateAsString() const
|
||||
{
|
||||
// Print out the header
|
||||
char header[64];
|
||||
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 += 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;
|
||||
}
|
119
source/game/game.h
Normal file
119
source/game/game.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
#ifndef _GAME_H_
|
||||
#define _GAME_H_
|
||||
|
||||
#include "unit.h"
|
||||
#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
|
||||
{
|
||||
// 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 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
|
||||
};
|
||||
|
||||
// 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:
|
||||
|
||||
// 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);
|
||||
|
||||
// move asignment operator
|
||||
CTTRTSGame& operator=(CTTRTSGame&& game);
|
||||
|
||||
// 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
|
||||
// best practice would be to call with GetNumUnits() == 0
|
||||
Team CheckForWin() const;
|
||||
|
||||
// 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); }
|
||||
inline std::string GetName() const { return name; }
|
||||
|
||||
// Set the turn of the game
|
||||
inline int SetTurn( int in ) { return (turn = in); }
|
||||
|
||||
private:
|
||||
|
||||
// Verify any order or position - non-zero is error
|
||||
int VerifyOrder( player_id_t player, const COrder& order ) const;
|
||||
int VerifyPos( uvector2 vec ) const;
|
||||
|
||||
// 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 );
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
#endif //_GAME_H_
|
25
source/game/gametypes.h
Normal file
25
source/game/gametypes.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef _GAME_TYPES_H_
|
||||
#define _GAME_TYPES_H_
|
||||
|
||||
#include <limits> // std::numeric_limits
|
||||
|
||||
// Type for a team IDs
|
||||
enum class Team : char
|
||||
{
|
||||
Red = 0,
|
||||
Blue,
|
||||
Green,
|
||||
Yellow,
|
||||
NUM_INVALID
|
||||
};
|
||||
|
||||
|
||||
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
|
||||
|
||||
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 unitVis_c unitVis_invalid = std::numeric_limits<unitVis_c>::max();
|
||||
|
||||
#endif //_GAME_TYPES_H_
|
33
source/game/order.cpp
Normal file
33
source/game/order.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include <string.h>
|
||||
#include "order.h"
|
||||
|
||||
// Convert an order to a string
|
||||
std::string GetStringFromOrder(const COrder& order )
|
||||
{
|
||||
static char buff[128];
|
||||
memset(buff,0,sizeof(buff));
|
||||
|
||||
snprintf(buff,128, ORDER_FORMATTER,
|
||||
order.command,
|
||||
order.unit);
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
// Convert a string to an order
|
||||
COrder GetOrderFromString( const std::string& order )
|
||||
{
|
||||
COrder ret;
|
||||
|
||||
char corder;
|
||||
unsigned int unit;
|
||||
|
||||
sscanf(order.c_str(), ORDER_FORMATTER,
|
||||
&corder,
|
||||
&unit);
|
||||
|
||||
ret.command = (command_c)corder;
|
||||
ret.unit = unit;
|
||||
|
||||
return ret;
|
||||
}
|
54
source/game/order.h
Normal file
54
source/game/order.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef _ORDERS_H_
|
||||
#define _ORDERS_H_
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "gametypes.h"
|
||||
|
||||
#define ORDER_FORMATTER "ORDER:%c id:%u"
|
||||
|
||||
// Type for all orders ( as a char )
|
||||
enum class command_c : char
|
||||
{
|
||||
F = 'F',
|
||||
L = 'L',
|
||||
R = 'R',
|
||||
A = 'A',
|
||||
NUM_INVALID
|
||||
};
|
||||
|
||||
// Container for an order
|
||||
struct COrder
|
||||
{
|
||||
// Base constructor makes invalid order
|
||||
COrder()
|
||||
: unit ( unit_id_invalid )
|
||||
, command( command_c::NUM_INVALID )
|
||||
{}
|
||||
|
||||
// Unit order is for
|
||||
unit_id_t unit;
|
||||
|
||||
// Order command issued
|
||||
command_c command;
|
||||
|
||||
// Basic operators
|
||||
inline bool operator==( const COrder& rhs ) const;
|
||||
inline bool operator!=( const COrder& rhs ) const { return !(*this==rhs); }
|
||||
};
|
||||
|
||||
// Simple == operator
|
||||
inline bool COrder::operator== ( const COrder& rhs ) const
|
||||
{
|
||||
return ( unit == rhs.unit ) && ( command == rhs.command);
|
||||
}
|
||||
|
||||
// Typedef a vector of orders
|
||||
typedef std::vector<COrder> COrderVector;
|
||||
|
||||
// string <--> order conversion functions
|
||||
std::string GetStringFromOrder(const COrder& order );
|
||||
COrder GetOrderFromString( const std::string& order );
|
||||
|
||||
#endif //_ORDERS_H_
|
261
source/game/unit.cpp
Normal file
261
source/game/unit.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
#include <string.h>
|
||||
#include "unit.h"
|
||||
|
||||
#include <map> // for std::map
|
||||
|
||||
namespace
|
||||
{
|
||||
// Helper function for generating unique unit ids during static init
|
||||
unit_id_t get_unique_unit_id()
|
||||
{
|
||||
static unit_id_t p = 0;
|
||||
return p++;
|
||||
}
|
||||
|
||||
// Map of visual representation of unit V
|
||||
typedef std::map< dir_t, unitVis_c > dir_to_vis_map;
|
||||
|
||||
// Helper function to get the vis map during static init
|
||||
const dir_to_vis_map& get_vis_map_V()
|
||||
{
|
||||
static const dir_to_vis_map sk_visMap =
|
||||
{
|
||||
{dir_t::N,'^'},
|
||||
{dir_t::E,'>'},
|
||||
{dir_t::S,'v'},
|
||||
{dir_t::W,'<'},
|
||||
};
|
||||
|
||||
return sk_visMap;
|
||||
}
|
||||
}
|
||||
|
||||
// Get a unit from a visual
|
||||
CUnit CUnit::GetUnitFromVis( unitVis_c vis )
|
||||
{
|
||||
CUnit unit;
|
||||
unit.setFromVisual(vis);
|
||||
return 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]"
|
||||
std::string CUnit::GetStringFromUnit(const CUnit& unit )
|
||||
{
|
||||
static char buff[128];
|
||||
memset(buff,0,sizeof(buff));
|
||||
|
||||
snprintf(buff,128, UNIT_FORMATTER,
|
||||
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 CUnit::GetUnitFromString(const std::string& unit )
|
||||
{
|
||||
CUnit ret;
|
||||
|
||||
unsigned int id;
|
||||
int team;
|
||||
unsigned int player;
|
||||
char vis;
|
||||
char dir;
|
||||
unsigned int posx;
|
||||
unsigned int posy;
|
||||
|
||||
sscanf(unit.c_str(), UNIT_FORMATTER,
|
||||
&id,
|
||||
&team,
|
||||
&player,
|
||||
&vis,
|
||||
&dir,
|
||||
&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;
|
||||
}
|
||||
|
||||
// Plain constructor
|
||||
CUnit::CUnit()
|
||||
: unit_id ( get_unique_unit_id() )
|
||||
, team_id ( Team::NUM_INVALID )
|
||||
, unit_vis ( unitVis_invalid )
|
||||
, player_id ( player_id_invalid )
|
||||
, dir ( dir_t::S )
|
||||
, pos ( { ucoord_invalid, ucoord_invalid } )
|
||||
{
|
||||
updateMyVisual();
|
||||
}
|
||||
|
||||
// Move constructor
|
||||
CUnit::CUnit(CUnit&& unit)
|
||||
: unit_id ( std::move(unit.unit_id) )
|
||||
, team_id ( std::move(unit.team_id) )
|
||||
, 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();
|
||||
}
|
||||
|
||||
|
||||
// Move asignment operator
|
||||
CUnit& CUnit::operator=(CUnit&& unit)
|
||||
{
|
||||
unit_id = std::move(unit.unit_id) ;
|
||||
team_id = std::move(unit.team_id) ;
|
||||
player_id = std::move(unit.player_id) ;
|
||||
unit_vis = std::move(unit.unit_vis) ;
|
||||
dir = std::move(unit.dir) ;
|
||||
pos = std::move(unit.pos) ;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Equals operator
|
||||
bool CUnit::operator==(const CUnit& rhs)
|
||||
{
|
||||
return (unit_id == rhs.unit_id)
|
||||
&& (team_id == rhs.team_id)
|
||||
&& (player_id == rhs.player_id)
|
||||
&& (unit_vis == rhs.unit_vis)
|
||||
&& (dir == rhs.dir)
|
||||
&& (pos == rhs.pos);
|
||||
}
|
||||
|
||||
// Update the visual representation of the unit
|
||||
unitVis_c CUnit::updateMyVisual()
|
||||
{
|
||||
// Start at invalid
|
||||
setVisual(unitVis_invalid);
|
||||
|
||||
dir_to_vis_map::const_iterator it = get_vis_map_V().find(dir);
|
||||
|
||||
// If found set to new vis
|
||||
if( it != get_vis_map_V().end() )
|
||||
setVisual(it->second);
|
||||
|
||||
return getVisual();
|
||||
}
|
||||
|
||||
// Set the unit from visual
|
||||
bool CUnit::setFromVisual( const unitVis_c& vis )
|
||||
{
|
||||
dir_to_vis_map::const_iterator it;
|
||||
|
||||
for( it = get_vis_map_V().begin(); it != get_vis_map_V().end(); it++ )
|
||||
{
|
||||
if( it->second == vis )
|
||||
{
|
||||
dir = it->first;
|
||||
updateMyVisual();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
102
source/game/unit.h
Normal file
102
source/game/unit.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#ifndef _UNIT_H_
|
||||
#define _UNIT_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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();
|
||||
|
||||
// Move constructor and move assignment. CUnit cannot be copied
|
||||
CUnit(CUnit&& unit);
|
||||
CUnit& operator=(CUnit&& unit);
|
||||
|
||||
bool operator==(const CUnit& rhs);
|
||||
bool operator!=(const CUnit& rhs) { return !(*this == rhs); }
|
||||
|
||||
// Default dtor
|
||||
~CUnit() = default;
|
||||
|
||||
// Getters for all the members
|
||||
inline const unit_id_t& getID() const { return unit_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; }
|
||||
inline const uvector2& getPos() const { return pos; }
|
||||
|
||||
// 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; }
|
||||
|
||||
// Get the co-ordinate in front of the unit
|
||||
uvector2 getInFront() const;
|
||||
|
||||
// Check unit is valid
|
||||
inline bool valid() const;
|
||||
|
||||
// Set a unit based solely on it's visual
|
||||
bool setFromVisual( const unitVis_c& vis);
|
||||
|
||||
// Orientation methods
|
||||
dir_t turnLeft();
|
||||
dir_t turnRight();
|
||||
dir_t turnAround();
|
||||
|
||||
private:
|
||||
|
||||
// Update my visual must be called when setting direction
|
||||
unitVis_c updateMyVisual();
|
||||
|
||||
// Unit ID
|
||||
unit_id_t unit_id;
|
||||
|
||||
// Visual
|
||||
unitVis_c unit_vis;
|
||||
|
||||
// Team ID
|
||||
Team team_id;
|
||||
|
||||
// Owner ID
|
||||
player_id_t player_id;
|
||||
|
||||
// Direction
|
||||
dir_t dir;
|
||||
|
||||
// Position
|
||||
uvector2 pos;
|
||||
};
|
||||
|
||||
// Typedef for a vector of units
|
||||
typedef std::vector< CUnit > CUnitVector;
|
||||
|
||||
// Simple validation
|
||||
inline bool CUnit::valid() const
|
||||
{
|
||||
return (unit_id != unit_id_invalid )
|
||||
&& (team_id != Team::NUM_INVALID )
|
||||
&& (player_id != player_id_invalid)
|
||||
&& (unit_vis != unitVis_invalid);
|
||||
}
|
||||
|
||||
#endif //_UNIT_H_
|
17
source/gen/CMakeLists.txt
Normal file
17
source/gen/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
# ====================== gen =======================
|
||||
# Project name
|
||||
project( ttrts-gen )
|
||||
|
||||
include_directories(
|
||||
../game
|
||||
../maths
|
||||
)
|
||||
|
||||
set( SOURCES
|
||||
gen.cpp
|
||||
)
|
||||
|
||||
# Add the executable
|
||||
add_executable( ttrts-gen ${SOURCES} )
|
||||
|
||||
target_link_libraries( ttrts-gen game )
|
44
source/gen/gen.cpp
Normal file
44
source/gen/gen.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "game.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
void AddUnitToGame( player_id_t player, Team team, char vis, uvector2 vec, CTTRTSGame& game )
|
||||
{
|
||||
CUnit unit = CUnit::GetUnitFromVis(vis);
|
||||
unit.setPos( vec );
|
||||
unit.setPlayer(player);
|
||||
unit.setTeam(team);
|
||||
game.AddUnit(std::move(unit));
|
||||
}
|
||||
|
||||
void OutputGame( CTTRTSGame& game )
|
||||
{
|
||||
std::ofstream output;
|
||||
output.open (game.GetName() + ".txt");
|
||||
output << game.GetStateAsString();
|
||||
output.close();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Basic 5v5 game
|
||||
{
|
||||
CTTRTSGame game(21, 11);
|
||||
game.SetName("Basic_5_v_5");
|
||||
|
||||
AddUnitToGame(0, Team::Blue, '>', uvector2(1, 1), game);
|
||||
AddUnitToGame(0, Team::Blue, '>', uvector2(1, 3), game);
|
||||
AddUnitToGame(0, Team::Blue, '>', uvector2(1, 5), game);
|
||||
AddUnitToGame(0, Team::Blue, '>', uvector2(1, 7), game);
|
||||
AddUnitToGame(0, Team::Blue, '>', uvector2(1, 9), game);
|
||||
|
||||
AddUnitToGame(1, Team::Red, '<', uvector2(19, 1), game);
|
||||
AddUnitToGame(1, Team::Red, '<', uvector2(19, 3), game);
|
||||
AddUnitToGame(1, Team::Red, '<', uvector2(19, 5), game);
|
||||
AddUnitToGame(1, Team::Red, '<', uvector2(19, 7), game);
|
||||
AddUnitToGame(1, Team::Red, '<', uvector2(19, 9), game);
|
||||
|
||||
OutputGame(game);
|
||||
}
|
||||
}
|
28
source/maths/mathtypes.h
Normal file
28
source/maths/mathtypes.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef _BASETYPES_H_
|
||||
#define _BASETYPES_H_
|
||||
|
||||
#include <limits> // std::numeric_limits
|
||||
|
||||
#include "stdlib.h" // for size_t
|
||||
|
||||
template<class T, size_t N>
|
||||
constexpr size_t _countof(T (&)[N]) { return N; }
|
||||
|
||||
// Coordinate types
|
||||
typedef short coord_t;
|
||||
typedef unsigned short ucoord_t;
|
||||
|
||||
// Invalid values
|
||||
static const coord_t coord_invalid = std::numeric_limits<coord_t>::max();
|
||||
static const ucoord_t ucoord_invalid = std::numeric_limits<ucoord_t>::max();
|
||||
|
||||
// Direction representation
|
||||
enum class dir_t : char
|
||||
{
|
||||
N = 'N',
|
||||
S = 'S',
|
||||
E = 'E',
|
||||
W = 'W'
|
||||
};
|
||||
|
||||
#endif //_BASETYPES_H_
|
84
source/maths/vector2.h
Normal file
84
source/maths/vector2.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
#ifndef _VECTOR2_H_
|
||||
#define _VECTOR2_H_
|
||||
|
||||
#include "mathtypes.h"
|
||||
|
||||
struct uvector2;
|
||||
|
||||
struct vector2
|
||||
{
|
||||
vector2() : x (0), y (0) {}
|
||||
vector2( coord_t _x, coord_t _y )
|
||||
: x(_x)
|
||||
, y(_y)
|
||||
{}
|
||||
|
||||
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
|
||||
{
|
||||
uvector2() : x (0), y (0) {}
|
||||
uvector2( ucoord_t _x, ucoord_t _y )
|
||||
: x(_x)
|
||||
, y(_y)
|
||||
{}
|
||||
|
||||
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 };
|
||||
|
||||
case dir_t::E:
|
||||
return { 1,0 };
|
||||
|
||||
case dir_t::S:
|
||||
return { 0,-1 };
|
||||
|
||||
case dir_t::W:
|
||||
return { -1,0 };
|
||||
|
||||
default:
|
||||
return { 0,0 };
|
||||
}
|
||||
}
|
||||
|
||||
#endif //_VECTOR2_H_
|
0
source/net/CMakeLists.txt
Normal file
0
source/net/CMakeLists.txt
Normal file
0
source/player/CMakeLists.txt
Normal file
0
source/player/CMakeLists.txt
Normal file
19
source/test/CMakeLists.txt
Normal file
19
source/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
# ====================== tests =======================
|
||||
# Project name
|
||||
project( ttrts-test )
|
||||
|
||||
include_directories(
|
||||
../game
|
||||
../maths
|
||||
../ui
|
||||
)
|
||||
|
||||
set( SOURCES
|
||||
test.cpp
|
||||
)
|
||||
|
||||
# Add the executable
|
||||
add_executable( ttrts-test ${SOURCES} )
|
||||
|
||||
target_link_libraries( ttrts-test game ui )
|
214
source/test/test.cpp
Normal file
214
source/test/test.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
#include <iostream> // std::cout
|
||||
|
||||
#include "board.h"
|
||||
#include "order.h"
|
||||
#include "game.h"
|
||||
|
||||
const char* tests()
|
||||
{
|
||||
// Test if we can properly set a unit's visual
|
||||
{
|
||||
CUnit unit;
|
||||
unit.setFromVisual('v');
|
||||
if( unit.getVisual() != 'v' )
|
||||
return "failed to properly create V unit";
|
||||
}
|
||||
|
||||
// Test unique unit IDs
|
||||
{
|
||||
CUnit unit;
|
||||
CUnit unit2;
|
||||
if( unit.getID() == unit2.getID() )
|
||||
return "Unit IDs the same";
|
||||
}
|
||||
|
||||
// Test basic invalid unit conversion
|
||||
{
|
||||
CUnit unit1;
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
// Test custom unit conversion
|
||||
{
|
||||
CUnit unit1;
|
||||
unit1.setFromVisual('v');
|
||||
unit1.setPlayer(0);
|
||||
unit1.setTeam(Team::Green);
|
||||
unit1.setPos( uvector2(5,10) );
|
||||
|
||||
std::string unit1Desc = CUnit::GetStringFromUnit(unit1);
|
||||
CUnit unit2 = CUnit::GetUnitFromString(unit1Desc);
|
||||
|
||||
if ( unit1 != unit2 )
|
||||
return "Failed to convert custom unit to string and back";
|
||||
}
|
||||
|
||||
// Test if we can successfully create a unit from a visual
|
||||
{
|
||||
CUnit unit = CUnit::GetUnitFromVis('v');
|
||||
if( unit.getVisual() != 'v' )
|
||||
return "failed to properly create V unit with factory";
|
||||
}
|
||||
|
||||
// Test if we can successfully convert orders back and forth
|
||||
{
|
||||
COrder order;
|
||||
order.command = command_c::F;
|
||||
order.unit = 10;
|
||||
std::string order_string = GetStringFromOrder(order);
|
||||
COrder order2 = GetOrderFromString(order_string);
|
||||
|
||||
if ( order2 != order )
|
||||
return "failed order string conversion test";
|
||||
}
|
||||
|
||||
// Test of the game can logically handle a blank game
|
||||
{
|
||||
CTTRTSGame game( 15, 10 );
|
||||
if( game.SimulateToNextTurn() )
|
||||
return "Failed to simulate a blank game";
|
||||
|
||||
if( game.GetNumUnits() )
|
||||
return "Game started with non-zero unit number";
|
||||
}
|
||||
|
||||
// Test if the game correctly rejects units placed ontop of others
|
||||
{
|
||||
CTTRTSGame game( 5, 5 );
|
||||
|
||||
{
|
||||
CUnit unit = CUnit::GetUnitFromVis('^');
|
||||
unit.setPos( {2,2} );
|
||||
unit.setPlayer(0);
|
||||
unit.setTeam(Team::Red);
|
||||
|
||||
game.AddUnit(std::move(unit));
|
||||
}
|
||||
|
||||
{
|
||||
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";
|
||||
|
||||
if( game.GetNumUnits() != 1 )
|
||||
return "Game ended up with too many units";
|
||||
}
|
||||
}
|
||||
|
||||
// Test on a small board if a movement command succeeds correctly
|
||||
{
|
||||
CTTRTSGame game( 5, 5 );
|
||||
|
||||
CUnit unit = CUnit::GetUnitFromVis('>');
|
||||
const unit_id_t id = unit.getID();
|
||||
COrder order;
|
||||
|
||||
unit.setPos( {2,2} );
|
||||
unit.setPlayer(0);
|
||||
unit.setTeam(Team::Red);
|
||||
|
||||
if ( game.AddUnit(std::move(unit)) )
|
||||
return "Game failed to add valid unit";
|
||||
|
||||
order.unit = id;
|
||||
order.command = command_c::F;
|
||||
|
||||
if( game.IssueOrder(0,order) )
|
||||
return "Game failed to issue valid order";
|
||||
|
||||
if (game.SimulateToNextTurn() )
|
||||
return "Game failed to simulate valid turn";
|
||||
|
||||
if( game.GetUnitByIDConst(id).getPos() != uvector2{3,2} )
|
||||
return "Simple movement order failed";
|
||||
|
||||
}
|
||||
|
||||
// Test on a tiny board, whether a unit can correctly attack another
|
||||
{
|
||||
CTTRTSGame game( 2, 1 );
|
||||
game.SetName("Test_578");
|
||||
|
||||
unit_id_t id;
|
||||
{
|
||||
CUnit unit = CUnit::GetUnitFromVis('>');
|
||||
id = unit.getID();
|
||||
COrder order;
|
||||
|
||||
unit.setPos( {0,0} );
|
||||
unit.setPlayer(1);
|
||||
unit.setTeam(Team::Blue);
|
||||
|
||||
if ( game.AddUnit(std::move(unit)) )
|
||||
return "Game failed to add valid unit";
|
||||
|
||||
order.unit = id;
|
||||
order.command = command_c::A;
|
||||
|
||||
if( game.IssueOrder(0,order) )
|
||||
return "Game failed to issue valid order";
|
||||
}
|
||||
{
|
||||
CUnit unit = CUnit::GetUnitFromVis('<');
|
||||
|
||||
unit.setPos( {1,0} );
|
||||
unit.setPlayer(2);
|
||||
unit.setTeam(Team::Red);
|
||||
|
||||
if ( game.AddUnit(std::move(unit)) )
|
||||
return "Game failed to add valid unit";
|
||||
}
|
||||
|
||||
game.SimulateToNextTurn();
|
||||
|
||||
if ( game.GetNumUnits() != 1 )
|
||||
return "Game failed to kill a unit when it logically should have";
|
||||
|
||||
if ( game.GetUnitByIndex(0).getDir() != dir_t::E )
|
||||
return "Game killed the wrong unit";
|
||||
|
||||
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";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Main program entry point
|
||||
int main()
|
||||
{
|
||||
std::cout<<"Running tests"<<std::endl;
|
||||
|
||||
const char* res = tests();
|
||||
|
||||
if( res )
|
||||
{
|
||||
std::cout<<"Tests failed - "<<res<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout<<"Tests succeeded"<<std::endl;
|
||||
return 0;
|
||||
};
|
11
source/ttrts/CMakeLists.txt
Normal file
11
source/ttrts/CMakeLists.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
# ====================== ttrts =======================
|
||||
# Project name
|
||||
project( ttrts )
|
||||
|
||||
# Add the sources
|
||||
set( SOURCES
|
||||
main.cpp
|
||||
)
|
||||
|
||||
# Add the executable
|
||||
add_executable( ttrts ${SOURCES} )
|
5
source/ttrts/main.cpp
Normal file
5
source/ttrts/main.cpp
Normal file
|
@ -0,0 +1,5 @@
|
|||
// Main program entry point
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
};
|
19
source/ui/CMakeLists.txt
Normal file
19
source/ui/CMakeLists.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
# game project
|
||||
project( ui )
|
||||
|
||||
include_directories(
|
||||
../maths
|
||||
../game
|
||||
)
|
||||
|
||||
# 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
|
||||
board.cpp
|
||||
)
|
||||
|
||||
add_library( ui ${SOURCES} )
|
43
source/ui/board.cpp
Normal file
43
source/ui/board.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "board.h"
|
||||
|
||||
// ----------------------------------------------
|
||||
|
||||
// Default constructor for the board
|
||||
CBoard::CBoard( unsigned int c, unsigned int r )
|
||||
: cols ( c )
|
||||
, rows ( r )
|
||||
, total ( rows * cols )
|
||||
{
|
||||
board.resize(total,square_empty);
|
||||
}
|
||||
|
||||
|
||||
// constructor
|
||||
CBoard::CBoard( unsigned int c, unsigned int r, vunitVis_c&& b )
|
||||
: cols ( c )
|
||||
, rows ( r )
|
||||
, total ( rows * cols )
|
||||
, board ( std::move(b) )
|
||||
{
|
||||
board.resize(total,square_empty);
|
||||
}
|
||||
|
||||
// print get a slot on the board
|
||||
unitVis_c CBoard::get( const unsigned int c, const unsigned int r ) const
|
||||
{
|
||||
if ( (r >= rows) || (c >= cols) )
|
||||
return square_invalid;
|
||||
|
||||
return board[r*c];
|
||||
}
|
||||
|
||||
// Get a square on the board
|
||||
unitVis_c CBoard::set( const unsigned int c, const unsigned int r , const unitVis_c n )
|
||||
{
|
||||
if ( (r >= rows) || (c >= cols) )
|
||||
return square_invalid;
|
||||
|
||||
unitVis_c old = board[r*c];
|
||||
board[r*c] = n;
|
||||
return old;
|
||||
}
|
54
source/ui/board.h
Normal file
54
source/ui/board.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef _BOARD_H_
|
||||
#define _BOARD_H_
|
||||
|
||||
#include "gametypes.h"
|
||||
#include "mathtypes.h"
|
||||
|
||||
#include <limits> // std::numeric_limits
|
||||
#include <vector> // std::vector
|
||||
|
||||
typedef std::vector< unitVis_c > vunitVis_c;
|
||||
|
||||
// Invalid value for the board square
|
||||
constexpr unitVis_c square_invalid = std::numeric_limits<unitVis_c>::max();
|
||||
constexpr unitVis_c square_empty = ' ';
|
||||
|
||||
// Class to store simple data about a board
|
||||
class CBoard
|
||||
{
|
||||
public:
|
||||
|
||||
const unsigned int cols; // Number of columns
|
||||
const unsigned int rows; // Number of rows
|
||||
const unsigned int total; // Total number of pieces
|
||||
|
||||
// constructor
|
||||
CBoard( unsigned int c, unsigned int r );
|
||||
|
||||
// constructor
|
||||
CBoard( unsigned int c, unsigned int r, vunitVis_c&& b );
|
||||
|
||||
// Default destructor
|
||||
~CBoard() = default;
|
||||
|
||||
// clear the board
|
||||
inline void clear() { fill(square_empty); }
|
||||
|
||||
// fill the board
|
||||
inline void fill(unitVis_c v) { std::fill(board.begin(),board.end(),v); };
|
||||
|
||||
// Get a square on the board
|
||||
unitVis_c get( const unsigned int c, const unsigned int r ) const;
|
||||
|
||||
// Get the full board
|
||||
inline const vunitVis_c& get() const { return board; };
|
||||
|
||||
// Get a square on the board
|
||||
unitVis_c set( const unsigned int c, const unsigned int r , const unitVis_c n );
|
||||
|
||||
private:
|
||||
|
||||
vunitVis_c board; // Board data storage
|
||||
};
|
||||
|
||||
#endif //_BOARD_H_
|
Loading…
Add table
Add a link
Reference in a new issue