1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

CGameState: move two pathfinding-related functions to CPathfinderHelper

Both getMovementCost and getNeighbours have nothing to do with gamestate.
This commit is contained in:
ArseniyShestakov 2015-11-10 02:15:27 +03:00
parent d3c8ca7c1c
commit b2e1ee5363
8 changed files with 111 additions and 113 deletions

View File

@ -421,7 +421,7 @@ float FuzzyHelper::evaluate (Goals::VisitTile & g)
//assert(cb->isInTheMap(g.tile));
float turns = 0;
float distance = cb->getMovementCost(g.hero.h, g.tile);
float distance = CPathfinderHelper::getCost(g.hero.h, g.tile);
if (!distance) //we stand on that tile
turns = 0;
else
@ -530,4 +530,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
void FuzzyHelper::setPriority (Goals::TSubgoal & g)
{
g->setpriority(g->accept(this)); //this enforces returned value is set
}
}

View File

@ -290,11 +290,6 @@ bool CCallback::canMoveBetween(const int3 &a, const int3 &b)
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
}
int CCallback::getMovementCost(const CGHeroInstance * hero, int3 dest)
{
return gs->getMovementCost(hero, hero->visitablePos(), dest, hero->movement);
}
const CPathsInfo * CCallback::getPathsInfo(const CGHeroInstance *h)
{
return cl->getPathsInfo(h);

View File

@ -104,7 +104,6 @@ public:
//client-specific functionalities (pathfinding)
virtual bool canMoveBetween(const int3 &a, const int3 &b);
virtual int getMovementCost(const CGHeroInstance * hero, int3 dest);
virtual int3 getGuardingCreaturePosition(int3 tile);
virtual const CPathsInfo * getPathsInfo(const CGHeroInstance *h);

View File

@ -2061,103 +2061,6 @@ PlayerRelations::PlayerRelations CGameState::getPlayerRelations( PlayerColor col
return PlayerRelations::ENEMIES;
}
void CGameState::getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing)
{
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
//vec.reserve(8); //optimization
for (auto & dir : dirs)
{
const int3 hlp = tile + dir;
if(!map->isInTheMap(hlp))
continue;
const TerrainTile &hlpt = map->getTile(hlp);
// //we cannot visit things from blocked tiles
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
// {
// continue;
// }
if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && dir.x && dir.y) //diagonal move through water
{
int3 hlp1 = tile,
hlp2 = tile;
hlp1.x += dir.x;
hlp2.y += dir.y;
if(map->getTile(hlp1).terType != ETerrainType::WATER || map->getTile(hlp2).terType != ETerrainType::WATER)
continue;
}
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
&& hlpt.terType != ETerrainType::ROCK)
{
vec.push_back(hlp);
}
}
}
int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints, const int &turn, bool checkLast)
{
if(src == dest) //same tile
return 0;
TerrainTile &s = map->getTile(src),
&d = map->getTile(dest);
//get basic cost
int ret = h->getTileCost(d, s, turn);
auto flyBonus = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
auto waterWalkingBonus = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
if(d.blocked && flyBonus)
{
ret *= (100.0 + flyBonus->val) / 100.0;
}
else if(d.terType == ETerrainType::WATER)
{
if(h->boat && s.hasFavourableWinds() && d.hasFavourableWinds()) //Favourable Winds
ret *= 0.666;
else if(!h->boat && waterWalkingBonus)
{
ret *= (100.0 + waterWalkingBonus->val) / 100.0;
}
}
if(src.x != dest.x && src.y != dest.y) //it's diagonal move
{
int old = ret;
ret *= 1.414213;
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
if(ret > remainingMovePoints && remainingMovePoints >= old)
{
return remainingMovePoints;
}
}
int left = remainingMovePoints-ret;
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
{
std::vector<int3> vec;
vec.reserve(8); //optimization
getNeighbours(d, dest, vec, s.terType != ETerrainType::WATER, true);
for(auto & elem : vec)
{
int fcost = getMovementCost(h, dest, elem, left, turn, false);
if(fcost <= left)
{
return ret;
}
}
ret = remainingMovePoints;
}
return ret;
}
void CGameState::apply(CPack *pack)
{
ui16 typ = typeList.getTypeID(pack);

View File

@ -339,8 +339,6 @@ public:
bool isVisible(int3 pos, PlayerColor player);
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing);
int getMovementCost(const CGHeroInstance * h, const int3 &src, const int3 &dest, int remainingMovePoints =- 1, const int &turn = 0, bool checkLast = true);
int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
// ----- getters, setters -----

View File

@ -143,7 +143,7 @@ void CPathfinder::calculatePaths()
if(!isMovementToDestPossible())
continue;
int cost = gs->getMovementCost(hero, cp->coord, dp->coord, movement);
int cost = CPathfinderHelper::getCost(hero, cp->coord, dp->coord, movement);
int remains = movement - cost;
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
{
@ -156,7 +156,7 @@ void CPathfinder::calculatePaths()
//occurs rarely, when hero with low movepoints tries to leave the road
turnAtNextTile++;
int moveAtNextTile = maxMovePoints(cp);
cost = gs->getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile); //cost must be updated, movement points changed :(
cost = CPathfinderHelper::getCost(hero, cp->coord, dp->coord, moveAtNextTile); //cost must be updated, movement points changed :(
remains = moveAtNextTile - cost;
}
@ -204,7 +204,7 @@ void CPathfinder::addNeighbours(const int3 &coord)
ct = &gs->map->getTile(coord);
std::vector<int3> tiles;
gs->getNeighbours(*ct, coord, tiles, boost::logic::indeterminate, cp->layer == ELayer::SAIL); // TODO: find out if we still need "limitCoastSailing" option
CPathfinderHelper::getNeighbours(gs, *ct, coord, tiles, boost::logic::indeterminate, cp->layer == ELayer::SAIL); // TODO: find out if we still need "limitCoastSailing" option
sTileObj = ct->topVisitableObj(coord == out.hpos);
if(canVisitObject())
{
@ -625,6 +625,100 @@ bool CPathfinder::canVisitObject() const
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
}
void CPathfinderHelper::getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing)
{
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
//vec.reserve(8); //optimization
for (auto & dir : dirs)
{
const int3 hlp = tile + dir;
if(!gs->isInTheMap(hlp))
continue;
const TerrainTile &hlpt = gs->map->getTile(hlp);
// //we cannot visit things from blocked tiles
// if(srct.blocked && !srct.visitable && hlpt.visitable && srct.blockingObjects.front()->ID != HEROI_TYPE)
// {
// continue;
// }
if(srct.terType == ETerrainType::WATER && limitCoastSailing && hlpt.terType == ETerrainType::WATER && dir.x && dir.y) //diagonal move through water
{
int3 hlp1 = tile,
hlp2 = tile;
hlp1.x += dir.x;
hlp2.y += dir.y;
if(gs->map->getTile(hlp1).terType != ETerrainType::WATER || gs->map->getTile(hlp2).terType != ETerrainType::WATER)
continue;
}
if((indeterminate(onLand) || onLand == (hlpt.terType!=ETerrainType::WATER) )
&& hlpt.terType != ETerrainType::ROCK)
{
vec.push_back(hlp);
}
}
}
int CPathfinderHelper::getCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints, const int &turn, const bool &checkLast)
{
if(src == dst) //same tile
return 0;
auto s = h->cb->getTile(src), d = h->cb->getTile(dst);
int ret = h->getTileCost(*d, *s, turn);
auto flyBonus = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
auto waterWalkingBonus = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
if(d->blocked && flyBonus)
{
ret *= (100.0 + flyBonus->val) / 100.0;
}
else if(d->terType == ETerrainType::WATER)
{
if(h->boat && s->hasFavourableWinds() && d->hasFavourableWinds()) //Favourable Winds
ret *= 0.666;
else if(!h->boat && waterWalkingBonus)
{
ret *= (100.0 + waterWalkingBonus->val) / 100.0;
}
}
if(src.x != dst.x && src.y != dst.y) //it's diagonal move
{
int old = ret;
ret *= 1.414213;
//diagonal move costs too much but normal move is possible - allow diagonal move for remaining move points
if(ret > remainingMovePoints && remainingMovePoints >= old)
return remainingMovePoints;
}
int left = remainingMovePoints-ret;
if(checkLast && left > 0 && remainingMovePoints-ret < 250) //it might be the last tile - if no further move possible we take all move points
{
std::vector<int3> vec;
vec.reserve(8); //optimization
getNeighbours(h->cb->gameState(), *d, dst, vec, s->terType != ETerrainType::WATER, true);
for(auto & elem : vec)
{
int fcost = getCost(h, dst, elem, left, turn, false);
if(fcost <= left)
return ret;
}
ret = remainingMovePoints;
}
return ret;
}
int CPathfinderHelper::getCost(const CGHeroInstance * h, const int3 &dst)
{
return getCost(h, h->visitablePos(), dst, h->movement);
}
CGPathNode::CGPathNode(int3 Coord, ELayer Layer)
: coord(Coord), layer(Layer)
{

View File

@ -178,3 +178,12 @@ private:
bool canVisitObject() const;
};
class DLL_LINKAGE CPathfinderHelper
{
public:
static void getNeighbours(CGameState * gs, const TerrainTile &srct, const int3 &tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, const bool &limitCoastSailing);
static int getCost(const CGHeroInstance * h, const int3 &src, const int3 &dst, const int &remainingMovePoints =- 1, const int &turn = 0, const bool &checkLast = true);
static int getCost(const CGHeroInstance * h, const int3 &dst);
};

View File

@ -1764,7 +1764,6 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
}
const TerrainTile t = *gs->getTile(hmpos);
const int cost = gs->getMovementCost(h, h->getPosition(), hmpos, h->movement);
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
@ -1779,8 +1778,9 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
tmh.movePoints = h->movement;
//check if destination tile is available
bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
const bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
const bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
const int cost = CPathfinderHelper::getCost(h, h->getPosition(), hmpos, h->movement);
//it's a rock or blocked and not visitable tile
//OR hero is on land and dest is water and (there is not present only one object - boat)