recruitment as aspect

This commit is contained in:
Iurii Chernyi 2009-08-12 11:19:17 +00:00
parent 67517daeee
commit 13a103f640
12 changed files with 384 additions and 260 deletions

View File

@ -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).

View File

@ -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}

View File

@ -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;
}

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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);

View File

@ -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);
// =======================================================================

View File

@ -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
// =======================================================================