1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-02 00:10:22 +02:00

Merge pull request #270 from FeniksFire/develop

Making unit tests for BattleHex and some estetic improvements.
This commit is contained in:
Alexander Shishkin 2017-02-21 23:56:26 +03:00 committed by GitHub
commit 0af7ee393b
6 changed files with 277 additions and 131 deletions

View File

@ -195,14 +195,14 @@ namespace range = boost::range;
/* Typedefs */
/* ---------------------------------------------------------------------------- */
// Integral data types
typedef boost::uint64_t ui64; //unsigned int 64 bits (8 bytes)
typedef boost::uint32_t ui32; //unsigned int 32 bits (4 bytes)
typedef boost::uint16_t ui16; //unsigned int 16 bits (2 bytes)
typedef boost::uint8_t ui8; //unsigned int 8 bits (1 byte)
typedef boost::int64_t si64; //signed int 64 bits (8 bytes)
typedef boost::int32_t si32; //signed int 32 bits (4 bytes)
typedef boost::int16_t si16; //signed int 16 bits (2 bytes)
typedef boost::int8_t si8; //signed int 8 bits (1 byte)
typedef uint64_t ui64; //unsigned int 64 bits (8 bytes)
typedef uint32_t ui32; //unsigned int 32 bits (4 bytes)
typedef uint16_t ui16; //unsigned int 16 bits (2 bytes)
typedef uint8_t ui8; //unsigned int 8 bits (1 byte)
typedef int64_t si64; //signed int 64 bits (8 bytes)
typedef int32_t si32; //signed int 32 bits (4 bytes)
typedef int16_t si16; //signed int 16 bits (2 bytes)
typedef int8_t si8; //signed int 8 bits (1 byte)
// Lock typedefs
typedef boost::lock_guard<boost::mutex> TLockGuard;

View File

@ -1,6 +1,3 @@
#include "StdInc.h"
#include "BattleHex.h"
/*
* BattleHex.cpp, part of VCMI engine
*
@ -10,12 +7,78 @@
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "BattleHex.h"
BattleHex::BattleHex() : hex(INVALID) {}
BattleHex::BattleHex(si16 _hex) : hex(_hex) {}
BattleHex::BattleHex(si16 x, si16 y)
{
setXY(x, y);
}
BattleHex::BattleHex(std::pair<si16, si16> xy)
{
setXY(xy);
}
BattleHex::operator si16() const
{
return hex;
}
bool BattleHex::isValid() const
{
return hex >= 0 && hex < GameConstants::BFIELD_SIZE;
}
bool BattleHex::isAvailable() const
{
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH-1;
}
void BattleHex::setX(si16 x)
{
setXY(x, getY());
}
void BattleHex::setY(si16 y)
{
setXY(getX(), y);
}
void BattleHex::setXY(si16 x, si16 y, bool hasToBeValid)
{
if(hasToBeValid)
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
hex = x + y * GameConstants::BFIELD_WIDTH;
}
void BattleHex::setXY(std::pair<si16, si16> xy)
{
setXY(xy.first, xy.second);
}
si16 BattleHex::getX() const
{
return hex % GameConstants::BFIELD_WIDTH;
}
si16 BattleHex::getY() const
{
return hex / GameConstants::BFIELD_WIDTH;
}
std::pair<si16, si16> BattleHex::getXY() const
{
return std::make_pair(getX(), getY());
}
BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
{
si16 x = getX(),
y = getY();
si16 x(getX()), y(getY());
switch(dir)
{
case TOP_LEFT:
@ -39,11 +102,27 @@ BattleHex& BattleHex::moveInDir(EDir dir, bool hasToBeValid)
default:
throw std::runtime_error("Disaster: wrong direction in BattleHex::operator+=!\n");
break;
}
}
return *this;
}
BattleHex &BattleHex::operator+=(BattleHex::EDir dir)
{
return moveInDir(dir);
}
BattleHex BattleHex::movedInDir(BattleHex::EDir dir, bool hasToBeValid) const
{
BattleHex result(*this);
result.moveInDir(dir, hasToBeValid);
return result;
}
BattleHex BattleHex::operator+(BattleHex::EDir dir) const
{
return movedInDir(dir);
}
std::vector<BattleHex> BattleHex::neighbouringTiles() const
{
std::vector<BattleHex> ret;
@ -66,32 +145,29 @@ signed char BattleHex::mutualPosition(BattleHex hex1, BattleHex hex2)
return 0;
if(hex2 == hex1 - ( (hex1/17)%2 ? 17 : 16 )) //top right
return 1;
if(hex2 == hex1 - 1 && hex1%17 != 0) //left
return 5;
if(hex2 == hex1 + 1 && hex1%17 != 16) //right
return 2;
if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
return 4;
if(hex2 == hex1 + ( (hex1/17)%2 ? 17 : 18 )) //bottom right
return 3;
if(hex2 == hex1 + ( (hex1/17)%2 ? 16 : 17 )) //bottom left
return 4;
if(hex2 == hex1 - 1 && hex1%17 != 0) //left
return 5;
return -1;
}
char BattleHex::getDistance(BattleHex hex1, BattleHex hex2)
{
int y1 = hex1.getY(),
y2 = hex2.getY();
{
int y1 = hex1.getY(), y2 = hex2.getY();
// FIXME: Omit floating point arithmetics
int x1 = (int)(hex1.getX() + y1 * 0.5),
x2 = (int)(hex2.getX() + y2 * 0.5);
int x1 = (hex1.getX() + y1 * 0.5), x2 = (hex2.getX() + y2 * 0.5);
int xDst = x2 - x1,
yDst = y2 - y1;
int xDst = x2 - x1, yDst = y2 - y1;
if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
if ((xDst >= 0 && yDst >= 0) || (xDst < 0 && yDst < 0))
return std::max(std::abs(xDst), std::abs(yDst));
return std::abs(xDst) + std::abs(yDst);
}
@ -101,32 +177,21 @@ void BattleHex::checkAndPush(BattleHex tile, std::vector<BattleHex> & ret)
ret.push_back(tile);
}
bool BattleHex::isAvailable() const
{
return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH-1;
}
BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities)
{
std::vector<BattleHex> sortedTiles (possibilities.begin(), possibilities.end()); //set can't be sorted properly :(
BattleHex initialHex = BattleHex(initialPos);
auto compareDistance = [initialHex](const BattleHex left, const BattleHex right) -> bool
{
return initialHex.getDistance (initialHex, left) < initialHex.getDistance (initialHex, right);
};
boost::sort (sortedTiles, compareDistance); //closest tiles at front
int closestDistance = initialHex.getDistance(initialPos, sortedTiles.front()); //sometimes closest tiles can be many hexes away
auto notClosest = [closestDistance, initialPos](const BattleHex here) -> bool
{
return closestDistance < here.getDistance (initialPos, here);
};
vstd::erase_if(sortedTiles, notClosest); //only closest tiles are interesting
auto compareHorizontal = [attackerOwned, initialPos](const BattleHex left, const BattleHex right) -> bool
{
if(left.getX() != right.getX())
@ -142,9 +207,7 @@ BattleHex BattleHex::getClosestTile(bool attackerOwned, BattleHex initialPos, st
return std::abs(left.getY() - initialPos.getY()) < std::abs(right.getY() - initialPos.getY());
}
};
boost::sort (sortedTiles, compareHorizontal);
return sortedTiles.front();
}

View File

@ -1,8 +1,3 @@
#pragma once
#include "GameConstants.h"
/*
* BattleHex.h, part of VCMI engine
*
@ -12,93 +7,51 @@
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include <bits/stl_pair.h>
#include "GameConstants.h"
// for battle stacks' positions
struct DLL_LINKAGE BattleHex
class DLL_LINKAGE BattleHex
{
public:
si16 hex;
static const si16 INVALID = -1;
enum EDir { RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT, TOP_LEFT, TOP_RIGHT };
si16 hex;
BattleHex() : hex(INVALID) {}
BattleHex(si16 _hex) : hex(_hex) {}
operator si16() const { return hex; }
bool isValid() const { return hex >= 0 && hex < GameConstants::BFIELD_SIZE; }
template<typename inttype>
BattleHex(inttype x, inttype y)
{
setXY(x, y);
}
template<typename inttype>
BattleHex(std::pair<inttype, inttype> xy)
{
setXY(xy);
}
template<typename inttype>
void setX(inttype x)
{
setXY(x, getY());
}
template<typename inttype>
void setY(inttype y)
{
setXY(getX(), y);
}
void setXY(si16 x, si16 y, bool hasToBeValid = true)
{
if(hasToBeValid)
assert(x >= 0 && x < GameConstants::BFIELD_WIDTH && y >= 0 && y < GameConstants::BFIELD_HEIGHT);
hex = x + y * GameConstants::BFIELD_WIDTH;
}
template<typename inttype>
void setXY(std::pair<inttype, inttype> xy)
{
setXY(xy.first, xy.second);
}
si16 getY() const { return hex / GameConstants::BFIELD_WIDTH; }
si16 getX() const { return hex % GameConstants::BFIELD_WIDTH; }
std::pair<si16, si16> getXY() const { return std::make_pair(getX(), getY()); }
BattleHex();
BattleHex(si16 _hex);
BattleHex(si16 x, si16 y);
BattleHex(std::pair<si16, si16> xy);
operator si16() const;
bool isValid() const;
bool isAvailable() const; //valid position not in first or last column
void setX(si16 x);
void setY(si16 y);
void setXY(si16 x, si16 y, bool hasToBeValid = true);
void setXY(std::pair<si16, si16> xy);
si16 getX() const;
si16 getY() const;
std::pair<si16, si16> getXY() const;
//moving to direction
BattleHex& moveInDir(EDir dir, bool hasToBeValid = true);
BattleHex& operator+=(EDir dir) { return moveInDir(dir); } //sugar for above
BattleHex& moveInDir(EDir dir, bool hasToBeValid = true);
BattleHex& operator+=(EDir dir); //sugar for above
//generates new BattleHex moved by given dir
BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const
{
BattleHex result(*this);
result.moveInDir(dir, hasToBeValid);
return result;
}
BattleHex operator+(EDir dir) const { return movedInDir(dir); }
BattleHex movedInDir(EDir dir, bool hasToBeValid = true) const;
BattleHex operator+(EDir dir) const;
std::vector<BattleHex> neighbouringTiles() const;
//returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
static signed char mutualPosition(BattleHex hex1, BattleHex hex2);
//returns distance between given hexes
static char getDistance(BattleHex hex1, BattleHex hex2);
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
template <typename Handler> void serialize(Handler &h, const int version)
template <typename Handler>
void serialize(Handler &h, const int version)
{
h & hex;
}
static void checkAndPush(BattleHex tile, std::vector<BattleHex> & ret);
bool isAvailable() const; //valid position not in first or last column
static BattleHex getClosestTile(bool attackerOwned, BattleHex initialPos, std::set<BattleHex> & possibilities); //TODO: vector or set? copying one to another is bad
};
DLL_EXPORT std::ostream & operator<<(std::ostream & os, const BattleHex & hex);

124
test/Battlefield.cpp Normal file
View File

@ -0,0 +1,124 @@
/*
* BattleField.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include <boost/test/unit_test.hpp>
#include "lib/BattleHex.h"
BOOST_AUTO_TEST_SUITE(BattlefieldHex_Suite)
BOOST_AUTO_TEST_CASE(getNeighbouringTiles)
{
BattleHex mainHex;
std::vector<BattleHex> neighbouringTiles;
mainHex.setXY(16,0);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==1);
mainHex.setXY(0,0);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==2);
mainHex.setXY(15,2);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==3);
mainHex.setXY(2,0);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==4);
mainHex.setXY(1,2);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==5);
mainHex.setXY(8,5);
neighbouringTiles = mainHex.neighbouringTiles();
BOOST_TEST(neighbouringTiles.size()==6);
BOOST_REQUIRE(neighbouringTiles.size()==6 && mainHex==93);
BOOST_TEST(neighbouringTiles.at(0)==75);
BOOST_TEST(neighbouringTiles.at(1)==94);
BOOST_TEST(neighbouringTiles.at(2)==110);
BOOST_TEST(neighbouringTiles.at(3)==109);
BOOST_TEST(neighbouringTiles.at(4)==92);
BOOST_TEST(neighbouringTiles.at(5)==76);
}
BOOST_AUTO_TEST_CASE(getDistance)
{
BattleHex firstHex(0,0), secondHex(16,0);
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==16);
firstHex=0, secondHex=170;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==10);
firstHex=16, secondHex=181;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==10);
firstHex=186, secondHex=70;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==17);
firstHex=166, secondHex=39;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==11);
firstHex=25, secondHex=103;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==9);
firstHex=18, secondHex=71;
BOOST_TEST((int)firstHex.getDistance(firstHex,secondHex)==4);
}
BOOST_AUTO_TEST_CASE(mutualPositions)
{
BattleHex firstHex(0,0), secondHex(16,0);
firstHex=86, secondHex=68;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==0);
secondHex=69;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==1);
secondHex=87;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==2);
secondHex=103;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==3);
secondHex=102;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==4);
secondHex=85;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==5);
secondHex=46;
BOOST_TEST((int)firstHex.mutualPosition(firstHex,secondHex)==-1);
}
BOOST_AUTO_TEST_CASE(getClosestTile)
{
BattleHex mainHex(0);
std::set<BattleHex> possibilities;
possibilities.insert(3);
possibilities.insert(170);
possibilities.insert(100);
possibilities.insert(119);
possibilities.insert(186);
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==3);
mainHex = 139;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==119);
mainHex = 16;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==100);
mainHex = 166;
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==186);
mainHex = 76;
BOOST_TEST(mainHex.getClosestTile(false,mainHex,possibilities)==3);
BOOST_TEST(mainHex.getClosestTile(true,mainHex,possibilities)==100);
}
BOOST_AUTO_TEST_CASE(moveEDir)
{
BattleHex mainHex(20);
mainHex.moveInDir(BattleHex::EDir::BOTTOM_RIGHT);
BOOST_TEST(mainHex==37);
mainHex.moveInDir(BattleHex::EDir::RIGHT);
BOOST_TEST(mainHex==38);
mainHex.moveInDir(BattleHex::EDir::TOP_RIGHT);
BOOST_TEST(mainHex==22);
mainHex.moveInDir(BattleHex::EDir::TOP_LEFT);
BOOST_TEST(mainHex==4);
mainHex.moveInDir(BattleHex::EDir::LEFT);
BOOST_TEST(mainHex==3);
mainHex.moveInDir(BattleHex::EDir::BOTTOM_LEFT);
BOOST_TEST(mainHex==20);
}
BOOST_AUTO_TEST_SUITE_END()

View File

@ -1,13 +1,14 @@
cmake_minimum_required(VERSION 2.6)
cmake_minimum_required(VERSION 2.8.7)
project(test)
enable_testing()
include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_HOME_DIRECTORY}/include ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/test)
include_directories(${Boost_INCLUDE_DIRS})
set(test_SRCS
StdInc.cpp
CVcmiTestConfig.cpp
CMapEditManagerTest.cpp
StdInc.cpp
Battlefield.cpp
CVcmiTestConfig.cpp
CMapEditManagerTest.cpp
MapComparer.cpp
CMapFormatTest.cpp
)
@ -22,12 +23,12 @@ cotire(vcmitest)
# Files to copy to the build directory
add_custom_target(vcmitestFiles ALL)
set(vcmitest_FILES
TerrainViewTest.h3m
terrainViewMappings.json
TerrainViewTest.h3m
terrainViewMappings.json
)
foreach(file ${vcmitest_FILES})
add_custom_command(TARGET vcmitestFiles POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_command(TARGET vcmitestFiles POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${file}" ${CMAKE_CURRENT_BINARY_DIR}
)
endforeach()

View File

@ -33,10 +33,15 @@ CVcmiTestConfig::CVcmiTestConfig()
loadDLLClasses();
logGlobal->info("Initialized global test setup.");
/* TEST_DATA_DIR may be wrong, if yes below test don't run,
find your test data folder in your build and change TEST_DATA_DIR for it*/
const std::string TEST_DATA_DIR = "test/";
auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
auto path = boost::filesystem::current_path();
path+= "/" + TEST_DATA_DIR;
if(boost::filesystem::exists(path)){
auto loader = new CFilesystemLoader("test/", TEST_DATA_DIR);
dynamic_cast<CFilesystemList*>(CResourceHandler::get())->addLoader(loader, false);
}
}
CVcmiTestConfig::~CVcmiTestConfig()