1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-21 21:17:49 +02:00
vcmi/AI/Nullkiller/Analyzers/ArmyManager.h
Ivan Savenko f238d89601 NKAI - Prefer giving fast units to scouts
Nullkiller AI will now prefer giving its scout heroes faster units to
optimize their movement points on next turns.

Unit selection logic:
- AI prefers to give 'weak' units that won't affect army strength of main
hero. Unit is considered 'weak' if its level below 4 or if its AI value
is below 1% of total army strength. So AI can give high-tier unit to
scout, but only if main hero already has massive army.

- Within weak units, if hero is moving on terrain with penalty, AI will
always prefer units that are native to this terrain. So on snow AI will
always prefer unit from Tower even if its speed is lower than unit from
another faction.

- Within remaining candidates, AI will prefer unit that will give higher
movement points limit. This also means that in case of H3 rules, all
units with 11+ speed will be viewed as equally good

- If there are multiple units with same speed, AI will prefer unit with
lowest AI value
2025-02-11 16:37:54 +00:00

130 lines
5.1 KiB
C++

/*
* ArmyManager.h, 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
*
*/
#pragma once
#include "../AIUtility.h"
#include "../../../lib/GameConstants.h"
#include "../../../lib/VCMI_Lib.h"
namespace NKAI
{
class Nullkiller;
struct SlotInfo
{
const CCreature * creature;
int count;
uint64_t power;
};
struct ArmyUpgradeInfo
{
std::vector<SlotInfo> resultingArmy;
int64_t upgradeValue = 0;
TResources upgradeCost;
void addArmyToBuy(std::vector<SlotInfo> army);
void addArmyToGet(std::vector<SlotInfo> army);
};
class DLL_EXPORT IArmyManager //: public: IAbstractManager
{
public:
virtual ~IArmyManager() = default;
virtual void update() = 0;
virtual ui64 howManyReinforcementsCanBuy(const CCreatureSet * target, const CGDwelling * source) const = 0;
virtual ui64 howManyReinforcementsCanBuy(
const CCreatureSet * targetArmy,
const CGDwelling * dwelling,
const TResources & availableResources,
uint8_t turn = 0) const = 0;
virtual ui64 howManyReinforcementsCanGet(const CGHeroInstance * hero, const CCreatureSet * source) const = 0;
virtual ui64 howManyReinforcementsCanGet(
const IBonusBearer * armyCarrier,
const CCreatureSet * target,
const CCreatureSet * source,
const TerrainId & armyTerrain) const = 0;
virtual std::vector<SlotInfo> getBestArmy(const IBonusBearer * armyCarrier, const CCreatureSet * target, const CCreatureSet * source, const TerrainId & armyTerrain) const = 0;
virtual std::vector<SlotInfo>::iterator getBestUnitForScout(std::vector<SlotInfo> & army, const TerrainId & armyTerrain) const = 0;
virtual std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const = 0;
virtual std::vector<SlotInfo> toSlotInfo(std::vector<creInfo> creatures) const = 0;
virtual std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const = 0;
virtual std::vector<creInfo> getArmyAvailableToBuy(
const CCreatureSet * hero,
const CGDwelling * dwelling,
TResources availableRes,
uint8_t turn = 0) const = 0;
virtual uint64_t evaluateStackPower(const Creature * creature, int count) const = 0;
virtual SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const = 0;
virtual ArmyUpgradeInfo calculateCreaturesUpgrade(
const CCreatureSet * army,
const CGObjectInstance * upgrader,
const TResources & availableResources) const = 0;
virtual std::shared_ptr<CCreatureSet> getArmyAvailableToBuyAsCCreatureSet(const CGDwelling * dwelling, TResources availableRes) const = 0;
};
class StackUpgradeInfo;
class DLL_EXPORT ArmyManager : public IArmyManager
{
private:
CPlayerSpecificInfoCallback * cb; //this is enough, but we downcast from CCallback
const Nullkiller * ai;
std::map<CreatureID, SlotInfo> totalArmy;
public:
ArmyManager(CPlayerSpecificInfoCallback * CB, const Nullkiller * ai): cb(CB), ai(ai) {}
void update() override;
ui64 howManyReinforcementsCanBuy(const CCreatureSet * target, const CGDwelling * source) const override;
ui64 howManyReinforcementsCanBuy(
const CCreatureSet * targetArmy,
const CGDwelling * dwelling,
const TResources & availableResources,
uint8_t turn = 0) const override;
ui64 howManyReinforcementsCanGet(const CGHeroInstance * hero, const CCreatureSet * source) const override;
ui64 howManyReinforcementsCanGet(const IBonusBearer * armyCarrier, const CCreatureSet * target, const CCreatureSet * source, const TerrainId & armyTerrain) const override;
std::vector<SlotInfo> getBestArmy(const IBonusBearer * armyCarrier, const CCreatureSet * target, const CCreatureSet * source, const TerrainId & armyTerrain) const override;
std::vector<SlotInfo>::iterator getBestUnitForScout(std::vector<SlotInfo> & army, const TerrainId & armyTerrain) const override;
std::vector<SlotInfo> getSortedSlots(const CCreatureSet * target, const CCreatureSet * source) const override;
std::vector<SlotInfo> toSlotInfo(std::vector<creInfo> creatures) const override;
std::vector<creInfo> getArmyAvailableToBuy(const CCreatureSet * hero, const CGDwelling * dwelling) const override;
std::vector<creInfo> getArmyAvailableToBuy(
const CCreatureSet * hero,
const CGDwelling * dwelling,
TResources availableRes,
uint8_t turn = 0) const override;
std::shared_ptr<CCreatureSet> getArmyAvailableToBuyAsCCreatureSet(const CGDwelling * dwelling, TResources availableRes) const override;
uint64_t evaluateStackPower(const Creature * creature, int count) const override;
SlotInfo getTotalCreaturesAvailable(CreatureID creatureID) const override;
ArmyUpgradeInfo calculateCreaturesUpgrade(
const CCreatureSet * army,
const CGObjectInstance * upgrader,
const TResources & availableResources) const override;
private:
std::vector<SlotInfo> convertToSlots(const CCreatureSet * army) const;
std::vector<StackUpgradeInfo> getPossibleUpgrades(const CCreatureSet * army, const CGObjectInstance * upgrader) const;
std::vector<StackUpgradeInfo> getHillFortUpgrades(const CCreatureSet * army) const;
std::vector<StackUpgradeInfo> getDwellingUpgrades(const CCreatureSet * army, const CGDwelling * dwelling) const;
};
}