improve performance of AiEnemyUnitsInDistance

This commit is contained in:
Tim Felgentreff 2022-06-27 18:26:13 +02:00
parent 300db83ef4
commit f7c12a74f0
3 changed files with 34 additions and 22 deletions

View file

@ -459,8 +459,8 @@ extern int AiFindWall(AiForce *force);
/// Plan the an attack
/// Send explorers around the map
extern void AiSendExplorers();
/// Enemy units in distance
extern int AiEnemyUnitsInDistance(const CPlayer &player, const CUnitType *type,
/// Check if there are enemy units in a given range (optionally of type)
extern bool AiEnemyUnitsInDistance(const CPlayer &player, const CUnitType *type,
const Vec2i &pos, unsigned range);
//

View file

@ -169,18 +169,20 @@ static int AiCheckUnitTypeCosts(const CUnitType &type)
return AiCheckCosts(type.Stats[AiPlayer->Player->Index].Costs);
}
template <bool ignoreVisibility = false>
class IsAEnemyUnitOf
{
public:
explicit IsAEnemyUnitOf(const CPlayer &_player) : player(&_player) {}
bool operator()(const CUnit *unit) const
{
return unit->IsVisibleAsGoal(*player) && unit->IsEnemy(*player);
return (ignoreVisibility || unit->IsVisibleAsGoal(*player)) && unit->IsEnemy(*player);
}
private:
const CPlayer *player;
};
template <bool ignoreVisibility = false>
class IsAEnemyUnitWhichCanCounterAttackOf
{
public:
@ -189,7 +191,7 @@ public:
{}
bool operator()(const CUnit *unit) const
{
return unit->IsVisibleAsGoal(*player)
return (ignoreVisibility || unit->IsVisibleAsGoal(*player))
&& unit->IsEnemy(*player)
&& CanTarget(*unit->Type, *type);
}
@ -199,42 +201,42 @@ private:
};
/**
** Enemy units in distance.
** Check if there are enemy units in a given range.
**
** @param player Find enemies of this player
** @param type Optional unit type to check if enemy can target this
** @param pos location
** @param range Distance range to look.
**
** @return Number of enemy units.
** @return If there are any enemy units in the range
*/
int AiEnemyUnitsInDistance(const CPlayer &player,
const CUnitType *type, const Vec2i &pos, unsigned range)
bool AiEnemyUnitsInDistance(const CPlayer &player,
const CUnitType *type, const Vec2i &pos, unsigned range)
{
const Vec2i offset(range, range);
std::vector<CUnit *> units;
if (type == NULL) {
Select(pos - offset, pos + offset, units, IsAEnemyUnitOf(player));
Select<1>(pos - offset, pos + offset, units, IsAEnemyUnitOf<true>(player));
return static_cast<int>(units.size());
} else {
const Vec2i typeSize(type->TileWidth - 1, type->TileHeight - 1);
const IsAEnemyUnitWhichCanCounterAttackOf pred(player, *type);
const IsAEnemyUnitWhichCanCounterAttackOf<true> pred(player, *type);
Select(pos - offset, pos + typeSize + offset, units, pred);
Select<1>(pos - offset, pos + typeSize + offset, units, pred);
return static_cast<int>(units.size());
}
}
/**
** Enemy units in distance.
** Check if there are enemy units in a given range.
**
** @param unit Find in distance for this unit.
** @param range Distance range to look.
**
** @return Number of enemy units.
** @return If there are any enemy units in the range
*/
int AiEnemyUnitsInDistance(const CUnit &unit, unsigned range)
bool AiEnemyUnitsInDistance(const CUnit &unit, unsigned range)
{
return AiEnemyUnitsInDistance(*unit.Player, unit.Type, unit.tilePos, range);
}

View file

@ -221,12 +221,14 @@ void Select(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &units)
void SelectFixed(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &units);
void SelectAroundUnit(const CUnit &unit, int range, std::vector<CUnit *> &around);
template <typename Pred>
template <int selectMax = 0, typename Pred>
void SelectFixed(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &units, Pred pred)
{
Assert(Map.Info.IsPointOnMap(ltPos));
Assert(Map.Info.IsPointOnMap(rbPos));
Assert(units.empty());
units.reserve(selectMax << 1);
int max = selectMax || INT_MAX;
for (Vec2i posIt = ltPos; posIt.y != rbPos.y + 1; ++posIt.y) {
for (posIt.x = ltPos.x; posIt.x != rbPos.x + 1; ++posIt.x) {
@ -236,9 +238,17 @@ void SelectFixed(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &u
for (size_t i = 0; i != cache.size(); ++i) {
CUnit &unit = *cache[i];
if (unit.CacheLock == 0 && pred(&unit)) {
unit.CacheLock = 1;
units.push_back(&unit);
if ((selectMax == 1 || unit.CacheLock == 0) && pred(&unit)) {
if (selectMax == 1) {
units.push_back(&unit);
return;
} else {
unit.CacheLock = 1;
units.push_back(&unit);
if (--max == 0) {
break;
}
}
}
}
}
@ -248,25 +258,25 @@ void SelectFixed(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &u
}
}
template <typename Pred>
template <int selectMax = 0, typename Pred>
void SelectAroundUnit(const CUnit &unit, int range, std::vector<CUnit *> &around, Pred pred)
{
const Vec2i offset(range, range);
const Vec2i typeSize(unit.Type->TileWidth - 1, unit.Type->TileHeight - 1);
Select(unit.tilePos - offset,
Select<selectMax>(unit.tilePos - offset,
unit.tilePos + typeSize + offset, around,
MakeAndPredicate(IsNotTheSameUnitAs(unit), pred));
}
template <typename Pred>
template <int selectMax = 0, typename Pred>
void Select(const Vec2i &ltPos, const Vec2i &rbPos, std::vector<CUnit *> &units, Pred pred)
{
Vec2i minPos = ltPos;
Vec2i maxPos = rbPos;
Map.FixSelectionArea(minPos, maxPos);
SelectFixed(minPos, maxPos, units, pred);
SelectFixed<selectMax>(minPos, maxPos, units, pred);
}
template <typename Pred>