mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-17 11:28:16 +00:00
recruitment as aspect
This commit is contained in:
parent
67517daeee
commit
13a103f640
@ -4,11 +4,16 @@
|
||||
description=Formula AI# this description is, again, needed for MP AI (it shows in AI list under this description
|
||||
version=10703 # no spaces here, version should be parsed as int. This version marker is a sign that ALL snippets of AI are written using new syntax
|
||||
|
||||
[stage]
|
||||
engine=fai
|
||||
name=side_formulas
|
||||
move="recruit('Thief')"
|
||||
[/stage]
|
||||
[aspect]
|
||||
id=recruitment
|
||||
[facet]
|
||||
[value]
|
||||
engine=fai
|
||||
name=side_formulas
|
||||
move="recruit('Thief')"
|
||||
[/value]
|
||||
[/facet]
|
||||
[/aspect]
|
||||
|
||||
[stage] #this is a stage. Each turn is: 'foreach stage in stages, play it'
|
||||
engine=cpp #cpp engine is default engine, so it can be omitted. other engines include fai (formula AI engine). Engine is a thing that parses this config snippet (in this case, 'stage' is parsed by cpp engine).
|
||||
|
@ -60,6 +60,19 @@
|
||||
{DEFAULT_ASPECT_VALUE number_of_possible_recruits_to_force_recruit 3.1}
|
||||
{DEFAULT_ASPECT_VALUE passive_leader no}
|
||||
{DEFAULT_ASPECT_VALUE passive_leader_shares_keep no}
|
||||
[aspect]
|
||||
id=recruitment
|
||||
engine=cpp
|
||||
name=composite_aspect
|
||||
[default]
|
||||
engine=cpp
|
||||
name=standard_aspect
|
||||
[value]
|
||||
engine=cpp
|
||||
name=ai_default::recruitment
|
||||
[/value]
|
||||
[/default]
|
||||
[/aspect]
|
||||
{DEFAULT_ASPECT_VALUE recruitment_ignore_bad_combat no}
|
||||
{DEFAULT_ASPECT_VALUE recruitment_ignore_bad_movement no}
|
||||
{DEFAULT_ASPECT_EMPTY recruitment_pattern}
|
||||
|
@ -214,7 +214,7 @@ public:
|
||||
|
||||
static void cfg_to_value(const config &cfg, ministage &value)
|
||||
{
|
||||
value = ministage(cfg);
|
||||
value = ministage(cfg.child_or_empty("value"));
|
||||
}
|
||||
|
||||
static void value_to_cfg(const ministage &value, config &cfg)
|
||||
@ -765,7 +765,7 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -252,7 +252,7 @@ private:
|
||||
#endif
|
||||
|
||||
|
||||
ai_default::ai_default(default_ai_context &context, const config &cfg) :
|
||||
ai_default::ai_default(ai_context &context, const config &cfg) :
|
||||
game_logic::formula_callable(),
|
||||
cfg_(cfg),
|
||||
recursion_counter_(context.get_recursion_count()),
|
||||
@ -263,15 +263,11 @@ ai_default::ai_default(default_ai_context &context, const config &cfg) :
|
||||
teams_(context.get_info().teams),
|
||||
tod_manager_(context.get_info().tod_manager_),
|
||||
consider_combat_(true),
|
||||
additional_targets_(),
|
||||
unit_movement_scores_(),
|
||||
not_recommended_units_(),
|
||||
unit_combat_scores_(),
|
||||
recruiting_preferred_(0),
|
||||
formula_ai_()
|
||||
{
|
||||
add_ref();
|
||||
init_default_ai_context_proxy(context);
|
||||
init_ai_context_proxy(context);
|
||||
}
|
||||
|
||||
ai_default::~ai_default(){
|
||||
@ -287,10 +283,7 @@ void ai_default::new_turn()
|
||||
invalidate_defensive_position_cache();
|
||||
threats_found_ = false;
|
||||
consider_combat_ = true;
|
||||
additional_targets_.clear();
|
||||
unit_movement_scores_.clear();
|
||||
not_recommended_units_.clear();
|
||||
unit_combat_scores_.clear();
|
||||
clear_additional_targets();
|
||||
invalidate_keeps_cache();
|
||||
unit_stats_cache().clear();
|
||||
}
|
||||
@ -310,8 +303,18 @@ config ai_default::to_config() const
|
||||
}
|
||||
|
||||
|
||||
void ai_default_recruitment_stage::on_create() {
|
||||
stage::on_create();
|
||||
}
|
||||
|
||||
bool ai_default::recruit_usage(const std::string& usage)
|
||||
config ai_default_recruitment_stage::to_config() const
|
||||
{
|
||||
config cfg = stage::to_config();
|
||||
return cfg;
|
||||
}
|
||||
|
||||
|
||||
bool ai_default_recruitment_stage::recruit_usage(const std::string& usage)
|
||||
{
|
||||
raise_user_interact();
|
||||
|
||||
@ -1080,8 +1083,8 @@ bool ai_default::move_to_targets(std::map<map_location, paths>& possible_moves,
|
||||
for(;;) {
|
||||
if(targets.empty()) {
|
||||
targets = find_targets(leader,enemy_dstsrc);
|
||||
targets.insert(targets.end(),additional_targets_.begin(),
|
||||
additional_targets_.end());
|
||||
targets.insert(targets.end(),additional_targets().begin(),
|
||||
additional_targets().end());
|
||||
LOG_AI << "Found " << targets.size() << " targets\n";
|
||||
if(targets.empty()) {
|
||||
return false;
|
||||
@ -1188,9 +1191,10 @@ bool ai_default::move_to_targets(std::map<map_location, paths>& possible_moves,
|
||||
return false;
|
||||
}
|
||||
|
||||
int ai_default::average_resistance_against(const unit_type& a, const unit_type& b) const
|
||||
int ai_default_recruitment_stage::average_resistance_against(const unit_type& a, const unit_type& b) const
|
||||
{
|
||||
int weighting_sum = 0, defense = 0;
|
||||
gamemap &map_ = get_info().map;
|
||||
const std::map<t_translation::t_terrain, size_t>& terrain =
|
||||
map_.get_weighted_terrain_frequencies();
|
||||
|
||||
@ -1266,7 +1270,7 @@ int ai_default::average_resistance_against(const unit_type& a, const unit_type&
|
||||
return sum/weight_sum;
|
||||
}
|
||||
|
||||
int ai_default::compare_unit_types(const unit_type& a, const unit_type& b) const
|
||||
int ai_default_recruitment_stage::compare_unit_types(const unit_type& a, const unit_type& b) const
|
||||
{
|
||||
const int a_effectiveness_vs_b = average_resistance_against(b,a);
|
||||
const int b_effectiveness_vs_a = average_resistance_against(a,b);
|
||||
@ -1277,7 +1281,7 @@ int ai_default::compare_unit_types(const unit_type& a, const unit_type& b) const
|
||||
return a_effectiveness_vs_b - b_effectiveness_vs_a;
|
||||
}
|
||||
|
||||
void ai_default::analyze_potential_recruit_combat()
|
||||
void ai_default_recruitment_stage::analyze_potential_recruit_combat()
|
||||
{
|
||||
if(unit_combat_scores_.empty() == false ||
|
||||
get_recruitment_ignore_bad_combat()) {
|
||||
@ -1288,6 +1292,7 @@ void ai_default::analyze_potential_recruit_combat()
|
||||
|
||||
// Records the best combat analysis for each usage type.
|
||||
std::map<std::string,int> best_usage;
|
||||
unit_map &units_ = get_info().units;
|
||||
|
||||
const std::set<std::string>& recruits = current_team().recruits();
|
||||
std::set<std::string>::const_iterator i;
|
||||
@ -1348,7 +1353,7 @@ namespace {
|
||||
struct target_comparer_distance {
|
||||
target_comparer_distance(const map_location& loc) : loc_(loc) {}
|
||||
|
||||
bool operator()(const ai_default::target& a, const ai_default::target& b) const {
|
||||
bool operator()(const ai::target& a, const ai::target& b) const {
|
||||
return distance_between(a.loc,loc_) < distance_between(b.loc,loc_);
|
||||
}
|
||||
|
||||
@ -1358,8 +1363,25 @@ private:
|
||||
|
||||
}
|
||||
|
||||
void ai_default::analyze_potential_recruit_movements()
|
||||
|
||||
ai_default_recruitment_stage::ai_default_recruitment_stage(ai_context &context, const config &cfg)
|
||||
: stage(context,cfg),
|
||||
cfg_(cfg),
|
||||
unit_movement_scores_(),
|
||||
not_recommended_units_(),
|
||||
unit_combat_scores_()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ai_default_recruitment_stage::~ai_default_recruitment_stage()
|
||||
{
|
||||
}
|
||||
|
||||
void ai_default_recruitment_stage::analyze_potential_recruit_movements()
|
||||
{
|
||||
unit_map &units_ = get_info().units;
|
||||
gamemap &map_ = get_info().map;
|
||||
if(unit_movement_scores_.empty() == false ||
|
||||
get_recruitment_ignore_bad_movement()) {
|
||||
return;
|
||||
@ -1370,7 +1392,7 @@ void ai_default::analyze_potential_recruit_movements()
|
||||
return;
|
||||
}
|
||||
|
||||
const location& start = nearest_keep(leader->first);
|
||||
const map_location& start = nearest_keep(leader->first);
|
||||
if(map_.on_board(start) == false) {
|
||||
return;
|
||||
}
|
||||
@ -1404,7 +1426,7 @@ void ai_default::analyze_potential_recruit_movements()
|
||||
// const temporary_unit_placer placer(units,start,temp_unit);
|
||||
|
||||
// pathfinding ignoring other units and terrain defense
|
||||
const shortest_path_calculator calc(temp_unit,current_team(),get_info().units,teams_,map_,true,true);
|
||||
const shortest_path_calculator calc(temp_unit,current_team(),get_info().units,get_info().teams,map_,true,true);
|
||||
|
||||
int cost = 0;
|
||||
int targets_reached = 0;
|
||||
@ -1469,31 +1491,25 @@ void ai_default::analyze_potential_recruit_movements()
|
||||
|
||||
bool ai_default::do_recruitment()
|
||||
{
|
||||
raise_user_interact();
|
||||
stage_ptr r = get_recruitment(*this);
|
||||
if (r) {
|
||||
return r->play_stage();
|
||||
}
|
||||
ERR_AI << "no recruitment aspect - skipping recruitment" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool ai_default_recruitment_stage::do_play_stage()
|
||||
{
|
||||
const unit_map &units_ = get_info().units;
|
||||
const unit_map::const_iterator leader = units_.find_leader(get_side());
|
||||
if(leader == units_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
raise_user_interact();
|
||||
// Let formula ai to do recruiting first
|
||||
//if (get_recursion_count()<recursion_counter::MAX_COUNTER_VALUE)
|
||||
//{
|
||||
// if (!cfg_["recruitment"].empty()){
|
||||
// if (!formula_ai_){
|
||||
// formula_ai_ptr_ = manager::create_transient_ai(manager::AI_TYPE_FORMULA_AI, cfg_,this);
|
||||
// formula_ai_ = static_cast<formula_ai*> (formula_ai_ptr_.get());
|
||||
// }
|
||||
|
||||
// assert(formula_ai_!=NULL);
|
||||
|
||||
// if (formula_ai_->do_recruitment()) {
|
||||
// LOG_AI << "Recruitment done by formula_ai\n";
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
const location& start_pos = nearest_keep(leader->first);
|
||||
const map_location& start_pos = nearest_keep(leader->first);
|
||||
|
||||
analyze_potential_recruit_movements();
|
||||
analyze_potential_recruit_combat();
|
||||
@ -1505,16 +1521,16 @@ bool ai_default::do_recruitment()
|
||||
// We recruit the initial allocation of scouts
|
||||
// based on how many neutral villages there are
|
||||
// that are closer to us than to other keeps.
|
||||
const std::vector<location>& villages = map_.villages();
|
||||
for(std::vector<location>::const_iterator v = villages.begin(); v != villages.end(); ++v) {
|
||||
const int owner = village_owner(*v,teams_);
|
||||
const std::vector<map_location>& villages = get_info().map.villages();
|
||||
for(std::vector<map_location>::const_iterator v = villages.begin(); v != villages.end(); ++v) {
|
||||
const int owner = village_owner(*v,get_info().teams);
|
||||
if(owner == -1) {
|
||||
const size_t distance = distance_between(start_pos,*v);
|
||||
|
||||
bool closest = true;
|
||||
for(std::vector<team>::const_iterator i = teams_.begin(); i != teams_.end(); ++i) {
|
||||
const int index = i - teams_.begin() + 1;
|
||||
const map_location& loc = map_.starting_position(index);
|
||||
for(std::vector<team>::const_iterator i = get_info().teams.begin(); i != get_info().teams.end(); ++i) {
|
||||
const int index = i - get_info().teams.begin() + 1;
|
||||
const map_location& loc = get_info().map.starting_position(index);
|
||||
if(loc != start_pos && distance_between(loc,*v) < distance) {
|
||||
closest = false;
|
||||
break;
|
||||
@ -1576,6 +1592,7 @@ bool ai_default::do_recruitment()
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void ai_default::move_leader_to_goals( const move_map& enemy_dstsrc)
|
||||
{
|
||||
const config &goal = get_leader_goal();
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "../actions.hpp"
|
||||
#include "../interface.hpp"
|
||||
#include "../contexts.hpp"
|
||||
|
||||
#include "../composite/stage.hpp"
|
||||
#include "../../formula_callable.hpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@ -52,11 +52,64 @@ private:
|
||||
recursion_counter recursion_counter_;
|
||||
};
|
||||
|
||||
class ai_default : public virtual default_ai_context_proxy, public interface, public game_logic::formula_callable {
|
||||
class ai_default_recruitment_stage : public stage {
|
||||
public:
|
||||
ai_default_recruitment_stage(ai_context &context, const config &cfg);
|
||||
virtual ~ai_default_recruitment_stage();
|
||||
void on_create();
|
||||
bool do_play_stage();
|
||||
config to_config() const;
|
||||
private:
|
||||
config cfg_;
|
||||
|
||||
virtual bool recruit_usage(const std::string& usage);
|
||||
|
||||
/**
|
||||
* Analyze all the units that this side can recruit
|
||||
* and rate their movement types.
|
||||
* Ratings will be placed in 'unit_movement_scores_',
|
||||
* with lower scores being better,
|
||||
* and the lowest possible rating being '10'.
|
||||
*/
|
||||
virtual void analyze_potential_recruit_movements();
|
||||
|
||||
std::map<std::string,int> unit_movement_scores_;
|
||||
std::set<std::string> not_recommended_units_;
|
||||
|
||||
/**
|
||||
* Analyze all the units that this side can recruit
|
||||
* and rate their fighting suitability against enemy units.
|
||||
* Ratings will be placed in 'unit_combat_scores_',
|
||||
* with a '0' rating indicating that the unit is 'average' against enemy units,
|
||||
* negative ratings meaning they are poorly suited,
|
||||
* and positive ratings meaning they are well suited.
|
||||
*/
|
||||
virtual void analyze_potential_recruit_combat();
|
||||
|
||||
std::map<std::string,int> unit_combat_scores_;
|
||||
|
||||
/**
|
||||
* Rates two unit types for their suitability against each other.
|
||||
* Returns 0 if the units are equally matched,
|
||||
* a positive number if a is suited against b,
|
||||
* and a negative number if b is suited against a.
|
||||
*/
|
||||
virtual int compare_unit_types(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
/**
|
||||
* calculates the average resistance unit type a has against the attacks of
|
||||
* unit type b.
|
||||
*/
|
||||
virtual int average_resistance_against(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
class ai_default : public virtual ai_context_proxy, public interface, public game_logic::formula_callable {
|
||||
public:
|
||||
typedef map_location location;//will get rid of this later
|
||||
|
||||
ai_default(default_ai_context &context, const config &cfg);
|
||||
ai_default(ai_context &context, const config &cfg);
|
||||
virtual ~ai_default();
|
||||
|
||||
virtual void play_turn();
|
||||
@ -65,16 +118,6 @@ public:
|
||||
virtual config to_config() const;
|
||||
void switch_side(side_number side);
|
||||
|
||||
struct target {
|
||||
enum TYPE { VILLAGE, LEADER, EXPLICIT, THREAT, BATTLE_AID, MASS, SUPPORT };
|
||||
|
||||
target(const location& pos, double val, TYPE target_type=VILLAGE) : loc(pos), value(val), type(target_type)
|
||||
{}
|
||||
location loc;
|
||||
double value;
|
||||
|
||||
TYPE type;
|
||||
};
|
||||
|
||||
virtual variant get_value(const std::string& key) const;
|
||||
virtual void get_inputs(std::vector<game_logic::formula_input>* inputs) const;
|
||||
@ -117,8 +160,6 @@ protected:
|
||||
virtual void move_leader_to_goals(const move_map& enemy_dstsrc);
|
||||
|
||||
|
||||
virtual bool recruit_usage(const std::string& usage);
|
||||
|
||||
virtual bool desperate_attack(const map_location &loc);
|
||||
|
||||
void remove_unit_from_moves(const map_location& u, move_map& srcdst, move_map& dstsrc);
|
||||
@ -156,8 +197,6 @@ protected:
|
||||
|
||||
bool is_accessible(const location& loc, const move_map& dstsrc) const;
|
||||
|
||||
virtual std::vector<target> find_targets(unit_map::const_iterator leader,
|
||||
const move_map& enemy_dstsrc);
|
||||
|
||||
/**
|
||||
* Function to form a group of units suitable for moving along the route, 'route'.
|
||||
@ -192,47 +231,6 @@ protected:
|
||||
std::vector<team>& teams_;
|
||||
tod_manager& tod_manager_;
|
||||
bool consider_combat_;
|
||||
std::vector<target> additional_targets_;
|
||||
|
||||
void add_target(const target& tgt) { additional_targets_.push_back(tgt); }
|
||||
|
||||
/**
|
||||
* Analyze all the units that this side can recruit
|
||||
* and rate their movement types.
|
||||
* Ratings will be placed in 'unit_movement_scores_',
|
||||
* with lower scores being better,
|
||||
* and the lowest possible rating being '10'.
|
||||
*/
|
||||
virtual void analyze_potential_recruit_movements();
|
||||
|
||||
std::map<std::string,int> unit_movement_scores_;
|
||||
std::set<std::string> not_recommended_units_;
|
||||
|
||||
/**
|
||||
* Analyze all the units that this side can recruit
|
||||
* and rate their fighting suitability against enemy units.
|
||||
* Ratings will be placed in 'unit_combat_scores_',
|
||||
* with a '0' rating indicating that the unit is 'average' against enemy units,
|
||||
* negative ratings meaning they are poorly suited,
|
||||
* and positive ratings meaning they are well suited.
|
||||
*/
|
||||
virtual void analyze_potential_recruit_combat();
|
||||
|
||||
std::map<std::string,int> unit_combat_scores_;
|
||||
|
||||
/**
|
||||
* Rates two unit types for their suitability against each other.
|
||||
* Returns 0 if the units are equally matched,
|
||||
* a positive number if a is suited against b,
|
||||
* and a negative number if b is suited against a.
|
||||
*/
|
||||
virtual int compare_unit_types(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
/**
|
||||
* calculates the average resistance unit type a has against the attacks of
|
||||
* unit type b.
|
||||
*/
|
||||
virtual int average_resistance_against(const unit_type& a, const unit_type& b) const;
|
||||
|
||||
/** Functions to deal with keeps. */
|
||||
void evaluate_recruiting_value(const map_location &leader_loc);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../../attack_prediction.hpp"
|
||||
#include "../../foreach.hpp"
|
||||
#include "../../log.hpp"
|
||||
#include "../composite/goal.hpp"
|
||||
|
||||
static lg::log_domain log_ai("ai/general");
|
||||
#define DBG_AI LOG_STREAM(debug, log_ai)
|
||||
@ -214,4 +215,169 @@ const map_location& default_ai_context_impl::suitable_keep(const map_location& l
|
||||
}
|
||||
|
||||
|
||||
std::vector<target> default_ai_context_impl::find_targets(unit_map::const_iterator leader, const move_map& enemy_dstsrc)
|
||||
{
|
||||
log_scope2(log_ai, "finding targets...");
|
||||
unit_map &units_ = get_info().units;
|
||||
gamemap &map_ = get_info().map;
|
||||
std::vector<team> teams_ = get_info().teams;
|
||||
const bool has_leader = leader != units_.end();
|
||||
|
||||
std::vector<target> targets;
|
||||
|
||||
std::map<map_location,paths> friends_possible_moves;
|
||||
move_map friends_srcdst, friends_dstsrc;
|
||||
calculate_possible_moves(friends_possible_moves,friends_srcdst,friends_dstsrc,false,true);
|
||||
|
||||
//if enemy units are in range of the leader, then we target the enemies who are in range.
|
||||
if(has_leader) {
|
||||
const double threat = power_projection(leader->first,enemy_dstsrc);
|
||||
if(threat > 0.0) {
|
||||
//find the location of enemy threats
|
||||
std::set<map_location> threats;
|
||||
|
||||
map_location adj[6];
|
||||
get_adjacent_tiles(leader->first,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
std::pair<move_map::const_iterator,move_map::const_iterator> itors = enemy_dstsrc.equal_range(adj[n]);
|
||||
while(itors.first != itors.second) {
|
||||
if(units_.count(itors.first->second)) {
|
||||
threats.insert(itors.first->second);
|
||||
}
|
||||
|
||||
++itors.first;
|
||||
}
|
||||
}
|
||||
|
||||
assert(threats.empty() == false);
|
||||
|
||||
#ifdef SUOKKO
|
||||
//FIXME: suokko's revision 29531 included this change. Correct?
|
||||
const double value = threat*get_protect_leader()/leader->second.hitpoints();
|
||||
#else
|
||||
const double value = threat/double(threats.size());
|
||||
#endif
|
||||
for(std::set<map_location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
|
||||
LOG_AI << "found threat target... " << *i << " with value: " << value << "\n";
|
||||
targets.push_back(target(*i,value,target::THREAT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double corner_distance = distance_between(map_location(0,0), map_location(map_.w(),map_.h()));
|
||||
double village_value = get_village_value();
|
||||
if(has_leader && get_village_value() > 0.0) {
|
||||
const std::vector<map_location>& villages = map_.villages();
|
||||
for(std::vector<map_location>::const_iterator t =
|
||||
villages.begin(); t != villages.end(); ++t) {
|
||||
|
||||
assert(map_.on_board(*t));
|
||||
bool ally_village = false;
|
||||
for (size_t i = 0; i != teams_.size(); ++i)
|
||||
{
|
||||
if (!current_team().is_enemy(i + 1) && teams_[i].owns_village(*t)) {
|
||||
ally_village = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ally_village)
|
||||
{
|
||||
//Support seems to cause the AI to just 'sit around' a lot, so
|
||||
//only turn it on if it's explicitly enabled.
|
||||
if(get_support_villages()) {
|
||||
double enemy = power_projection(*t, enemy_dstsrc);
|
||||
if (enemy > 0)
|
||||
{
|
||||
enemy *= 1.7;
|
||||
double our = power_projection(*t, friends_dstsrc);
|
||||
double value = village_value * our / enemy;
|
||||
add_target(target(*t, value, target::SUPPORT));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double leader_distance = distance_between(*t, leader->first);
|
||||
double value = village_value * (1.0 - leader_distance / corner_distance);
|
||||
LOG_AI << "found village target... " << *t
|
||||
<< " with value: " << value
|
||||
<< " distance: " << leader_distance << '\n';
|
||||
targets.push_back(target(*t,value,target::VILLAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<goal_ptr>& goals = get_goals();
|
||||
|
||||
//find the enemy leaders and explicit targets
|
||||
unit_map::const_iterator u;
|
||||
for(u = units_.begin(); u != units_.end(); ++u) {
|
||||
|
||||
//is a visible enemy leader
|
||||
if (u->second.can_recruit() && current_team().is_enemy(u->second.side())
|
||||
&& !u->second.invisible(u->first, units_, teams_)) {
|
||||
assert(map_.on_board(u->first));
|
||||
LOG_AI << "found enemy leader (side: " << u->second.side() << ") target... " << u->first << " with value: " << get_leader_value() << "\n";
|
||||
targets.push_back(target(u->first,get_leader_value(),target::LEADER));
|
||||
}
|
||||
|
||||
//explicit targets for this team
|
||||
|
||||
for(std::vector<goal_ptr>::iterator j = goals.begin();
|
||||
j != goals.end(); ++j) {
|
||||
if ((*j)->matches_unit(u)) {
|
||||
LOG_AI << "found explicit target... " << u->first << " with value: " << (*j)->value() << "\n";
|
||||
targets.push_back(target(u->first,(*j)->value(),target::EXPLICIT));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<double> new_values;
|
||||
|
||||
for(std::vector<target>::iterator i = targets.begin();
|
||||
i != targets.end(); ++i) {
|
||||
|
||||
new_values.push_back(i->value);
|
||||
|
||||
for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
|
||||
if(i->loc == j->loc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const double distance = abs(j->loc.x - i->loc.x) +
|
||||
abs(j->loc.y - i->loc.y);
|
||||
new_values.back() += j->value/(distance*distance);
|
||||
}
|
||||
}
|
||||
|
||||
assert(new_values.size() == targets.size());
|
||||
for(size_t n = 0; n != new_values.size(); ++n) {
|
||||
LOG_AI << "target value: " << targets[n].value << " -> " << new_values[n] << "\n";
|
||||
targets[n].value = new_values[n];
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<target>& default_ai_context_impl::additional_targets() const
|
||||
{
|
||||
return additional_targets_;
|
||||
}
|
||||
|
||||
|
||||
void default_ai_context_impl::add_target(const target& t) const
|
||||
{
|
||||
additional_targets_.push_back(t);
|
||||
}
|
||||
|
||||
|
||||
void default_ai_context_impl::clear_additional_targets() const
|
||||
{
|
||||
additional_targets_.clear();
|
||||
}
|
||||
|
||||
|
||||
} //of namespace ai
|
||||
|
@ -34,6 +34,19 @@
|
||||
//============================================================================
|
||||
namespace ai {
|
||||
|
||||
|
||||
struct target {
|
||||
enum TYPE { VILLAGE, LEADER, EXPLICIT, THREAT, BATTLE_AID, MASS, SUPPORT };
|
||||
|
||||
target(const map_location& pos, double val, TYPE target_type=VILLAGE) : loc(pos), value(val), type(target_type)
|
||||
{}
|
||||
map_location loc;
|
||||
double value;
|
||||
|
||||
TYPE type;
|
||||
};
|
||||
|
||||
|
||||
class attack_analysis : public game_logic::formula_callable
|
||||
{
|
||||
public:
|
||||
@ -135,9 +148,22 @@ public:
|
||||
virtual ~default_ai_context();
|
||||
|
||||
|
||||
virtual const std::vector<target>& additional_targets() const = 0;
|
||||
|
||||
|
||||
virtual void add_target(const target& t) const = 0;
|
||||
|
||||
|
||||
virtual void clear_additional_targets() const = 0;
|
||||
|
||||
|
||||
virtual default_ai_context& get_default_ai_context() = 0;
|
||||
|
||||
|
||||
virtual std::vector<target> find_targets(unit_map::const_iterator leader,
|
||||
const move_map& enemy_dstsrc) = 0;
|
||||
|
||||
|
||||
virtual bool multistep_move_possible(const map_location& from,
|
||||
const map_location& to, const map_location& via,
|
||||
const moves_map& possible_moves) const = 0;
|
||||
@ -167,12 +193,37 @@ public:
|
||||
virtual ~default_ai_context_proxy();
|
||||
|
||||
|
||||
virtual const std::vector<target>& additional_targets() const
|
||||
{
|
||||
return target_->additional_targets();
|
||||
}
|
||||
|
||||
|
||||
virtual void add_target(const target& t) const
|
||||
{
|
||||
target_->add_target(t);
|
||||
}
|
||||
|
||||
|
||||
virtual void clear_additional_targets() const
|
||||
{
|
||||
target_->clear_additional_targets();
|
||||
}
|
||||
|
||||
|
||||
virtual default_ai_context& get_default_ai_context()
|
||||
{
|
||||
return target_->get_default_ai_context();
|
||||
}
|
||||
|
||||
|
||||
virtual std::vector<target> find_targets(unit_map::const_iterator leader,
|
||||
const move_map& enemy_dstsrc)
|
||||
{
|
||||
return target_->find_targets(leader,enemy_dstsrc);
|
||||
}
|
||||
|
||||
|
||||
void init_default_ai_context_proxy(default_ai_context &target);
|
||||
|
||||
|
||||
@ -208,7 +259,7 @@ public:
|
||||
|
||||
|
||||
default_ai_context_impl(readwrite_context &context)
|
||||
: recursion_counter_(context.get_recursion_count())
|
||||
: recursion_counter_(context.get_recursion_count()),additional_targets_()
|
||||
{
|
||||
init_readwrite_context_proxy(context);
|
||||
}
|
||||
@ -220,12 +271,25 @@ public:
|
||||
virtual default_ai_context& get_default_ai_context();
|
||||
|
||||
|
||||
virtual const std::vector<target>& additional_targets() const;
|
||||
|
||||
|
||||
virtual void add_target(const target& t) const;
|
||||
|
||||
|
||||
virtual void clear_additional_targets() const;
|
||||
|
||||
|
||||
int get_recursion_count() const
|
||||
{
|
||||
return recursion_counter_.get_count();
|
||||
}
|
||||
|
||||
|
||||
virtual std::vector<target> find_targets(unit_map::const_iterator leader,
|
||||
const move_map& enemy_dstsrc);
|
||||
|
||||
|
||||
virtual bool multistep_move_possible(const map_location& from,
|
||||
const map_location& to, const map_location& via,
|
||||
const moves_map& possible_moves) const;
|
||||
@ -239,6 +303,7 @@ public:
|
||||
|
||||
private:
|
||||
recursion_counter recursion_counter_;
|
||||
mutable std::vector<target> additional_targets_;//@todo: refactor this
|
||||
|
||||
|
||||
};
|
||||
|
@ -96,149 +96,6 @@ private:
|
||||
const bool avoid_enemies_;
|
||||
};
|
||||
|
||||
std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterator leader, const move_map& enemy_dstsrc)
|
||||
{
|
||||
log_scope2(log_ai, "finding targets...");
|
||||
|
||||
const bool has_leader = leader != units_.end();
|
||||
|
||||
std::vector<ai_default::target> targets;
|
||||
|
||||
std::map<location,paths> friends_possible_moves;
|
||||
move_map friends_srcdst, friends_dstsrc;
|
||||
calculate_possible_moves(friends_possible_moves,friends_srcdst,friends_dstsrc,false,true);
|
||||
|
||||
//if enemy units are in range of the leader, then we target the enemies who are in range.
|
||||
if(has_leader) {
|
||||
const double threat = power_projection(leader->first,enemy_dstsrc);
|
||||
if(threat > 0.0) {
|
||||
//find the location of enemy threats
|
||||
std::set<map_location> threats;
|
||||
|
||||
map_location adj[6];
|
||||
get_adjacent_tiles(leader->first,adj);
|
||||
for(size_t n = 0; n != 6; ++n) {
|
||||
std::pair<move_map::const_iterator,move_map::const_iterator> itors = enemy_dstsrc.equal_range(adj[n]);
|
||||
while(itors.first != itors.second) {
|
||||
if(units_.count(itors.first->second)) {
|
||||
threats.insert(itors.first->second);
|
||||
}
|
||||
|
||||
++itors.first;
|
||||
}
|
||||
}
|
||||
|
||||
assert(threats.empty() == false);
|
||||
|
||||
#ifdef SUOKKO
|
||||
//FIXME: suokko's revision 29531 included this change. Correct?
|
||||
const double value = threat*get_protect_leader()/leader->second.hitpoints();
|
||||
#else
|
||||
const double value = threat/double(threats.size());
|
||||
#endif
|
||||
for(std::set<map_location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
|
||||
LOG_AI << "found threat target... " << *i << " with value: " << value << "\n";
|
||||
targets.push_back(target(*i,value,target::THREAT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double corner_distance = distance_between(map_location(0,0), map_location(map_.w(),map_.h()));
|
||||
double village_value = get_village_value();
|
||||
if(has_leader && get_village_value() > 0.0) {
|
||||
const std::vector<location>& villages = map_.villages();
|
||||
for(std::vector<location>::const_iterator t =
|
||||
villages.begin(); t != villages.end(); ++t) {
|
||||
|
||||
assert(map_.on_board(*t));
|
||||
bool ally_village = false;
|
||||
for (size_t i = 0; i != teams_.size(); ++i)
|
||||
{
|
||||
if (!current_team().is_enemy(i + 1) && teams_[i].owns_village(*t)) {
|
||||
ally_village = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ally_village)
|
||||
{
|
||||
//Support seems to cause the AI to just 'sit around' a lot, so
|
||||
//only turn it on if it's explicitly enabled.
|
||||
if(get_support_villages()) {
|
||||
double enemy = power_projection(*t, enemy_dstsrc);
|
||||
if (enemy > 0)
|
||||
{
|
||||
enemy *= 1.7;
|
||||
double our = power_projection(*t, friends_dstsrc);
|
||||
double value = village_value * our / enemy;
|
||||
add_target(target(*t, value, target::SUPPORT));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double leader_distance = distance_between(*t, leader->first);
|
||||
double value = village_value * (1.0 - leader_distance / corner_distance);
|
||||
LOG_AI << "found village target... " << *t
|
||||
<< " with value: " << value
|
||||
<< " distance: " << leader_distance << '\n';
|
||||
targets.push_back(target(*t,value,target::VILLAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<goal_ptr>& goals = get_goals();
|
||||
|
||||
//find the enemy leaders and explicit targets
|
||||
unit_map::const_iterator u;
|
||||
for(u = units_.begin(); u != units_.end(); ++u) {
|
||||
|
||||
//is a visible enemy leader
|
||||
if (u->second.can_recruit() && current_team().is_enemy(u->second.side())
|
||||
&& !u->second.invisible(u->first, units_, teams_)) {
|
||||
assert(map_.on_board(u->first));
|
||||
LOG_AI << "found enemy leader (side: " << u->second.side() << ") target... " << u->first << " with value: " << get_leader_value() << "\n";
|
||||
targets.push_back(target(u->first,get_leader_value(),target::LEADER));
|
||||
}
|
||||
|
||||
//explicit targets for this team
|
||||
|
||||
for(std::vector<goal_ptr>::iterator j = goals.begin();
|
||||
j != goals.end(); ++j) {
|
||||
if ((*j)->matches_unit(u)) {
|
||||
LOG_AI << "found explicit target... " << u->first << " with value: " << (*j)->value() << "\n";
|
||||
targets.push_back(target(u->first,(*j)->value(),target::EXPLICIT));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<double> new_values;
|
||||
|
||||
for(std::vector<target>::iterator i = targets.begin();
|
||||
i != targets.end(); ++i) {
|
||||
|
||||
new_values.push_back(i->value);
|
||||
|
||||
for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
|
||||
if(i->loc == j->loc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const double distance = abs(j->loc.x - i->loc.x) +
|
||||
abs(j->loc.y - i->loc.y);
|
||||
new_values.back() += j->value/(distance*distance);
|
||||
}
|
||||
}
|
||||
|
||||
assert(new_values.size() == targets.size());
|
||||
for(size_t n = 0; n != new_values.size(); ++n) {
|
||||
LOG_AI << "target value: " << targets[n].value << " -> " << new_values[n] << "\n";
|
||||
targets[n].value = new_values[n];
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
map_location ai_default::form_group(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
|
||||
{
|
||||
|
@ -92,8 +92,7 @@ public:
|
||||
return *ai_factories;
|
||||
}
|
||||
|
||||
/* cfg is commented out so far, because ai parameter handling is a mess atm */
|
||||
virtual ai_ptr get_new_instance( default_ai_context &context, const config &cfg) = 0;
|
||||
virtual ai_ptr get_new_instance( ai_context &context, const config &cfg) = 0;
|
||||
|
||||
ai_factory( const std::string &name )
|
||||
{
|
||||
@ -113,7 +112,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual ai_ptr get_new_instance( default_ai_context &context, const config &cfg){
|
||||
virtual ai_ptr get_new_instance( ai_context &context, const config &cfg){
|
||||
ai_ptr a(new AI(context,cfg));
|
||||
a->on_create();
|
||||
return a;
|
||||
|
@ -593,7 +593,7 @@ bool manager::add_ai_for_side( side_number side, const std::string& ai_algorithm
|
||||
}
|
||||
|
||||
|
||||
ai_ptr manager::create_transient_ai(const std::string &ai_algorithm_type, const config &cfg, default_ai_context *ai_context )
|
||||
ai_ptr manager::create_transient_ai(const std::string &ai_algorithm_type, const config &cfg, ai_context *ai_context )
|
||||
{
|
||||
assert(ai_context!=NULL);
|
||||
|
||||
|
@ -40,6 +40,7 @@ class side_context;
|
||||
class readonly_context;
|
||||
class readwrite_context;
|
||||
class default_ai_context;
|
||||
class ai_context;
|
||||
|
||||
class ai_composite;
|
||||
typedef boost::shared_ptr<ai_composite> composite_ai_ptr;
|
||||
@ -357,7 +358,7 @@ public:
|
||||
* @param context context in which this ai is created
|
||||
* @return the reference to the created AI
|
||||
*/
|
||||
static ai_ptr create_transient_ai( const std::string &ai_algorithm_type, const config &cfg, default_ai_context *ai_context);
|
||||
static ai_ptr create_transient_ai( const std::string &ai_algorithm_type, const config &cfg, ai_context *ai_context);
|
||||
|
||||
|
||||
// =======================================================================
|
||||
|
@ -64,6 +64,9 @@ static register_stage_factory<testing_ai_default::candidate_action_evaluation_lo
|
||||
static register_stage_factory<testing_ai_default::fallback_to_other_ai>
|
||||
fallback_to_other_ai_factory("testing_ai_default::fallback");
|
||||
|
||||
static register_stage_factory<ai_default_recruitment_stage>
|
||||
ai_default_recruitment_stage_factory("ai_default::recruitment");
|
||||
|
||||
// =======================================================================
|
||||
// Candidate actions
|
||||
// =======================================================================
|
||||
|
Loading…
x
Reference in New Issue
Block a user