AI Refactoring - hierarchial AI contexts,

...a step needed for easier writing of composite ai components.
This commit is contained in:
Iurii Chernyi 2009-05-21 00:18:13 +00:00
parent 901ad63e5a
commit 4d1ea0035a
19 changed files with 712 additions and 271 deletions

View File

@ -46,14 +46,26 @@ static lg::log_domain log_ai("ai/general");
typedef util::array<map_location,6> adjacent_tiles_array;
idle_ai::idle_ai(int side, bool master) : ai_readwrite_context(side,master)
idle_ai::idle_ai(ai::readwrite_context &context) : ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count())
{
}
std::string idle_ai::describe_self(){
std::string idle_ai::describe_self()
{
return "[idle_ai]";
}
void idle_ai::switch_side(ai::side_number side)
{
set_side(side);
}
int idle_ai::get_recursion_count() const
{
return recursion_counter_.get_count();
}
void idle_ai::play_turn()
{
game_events::fire("ai turn");
@ -61,11 +73,12 @@ void idle_ai::play_turn()
/** Sample ai, with simple strategy. */
class sample_ai : public ai_readwrite_context {
class sample_ai : public ai::readwrite_context_proxy, public ai_interface {
public:
sample_ai(int side, bool master) : ai_readwrite_context(side,master) {}
sample_ai(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count()) {}
void play_turn() {
virtual void play_turn() {
game_events::fire("ai turn");
do_attacks();
get_villages();
@ -73,31 +86,36 @@ public:
do_recruitment();
}
std::string describe_self(){
virtual std::string describe_self(){
return "[sample_ai]";
}
virtual int get_recursion_count() const
{
return recursion_counter_.get_count();
}
protected:
void do_attacks() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
std::map<map_location,paths> possible_moves;
ai::move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(unit_map::const_iterator i = get_info().units.begin(); i != get_info().units.end(); ++i) {
if(current_team().is_enemy(i->second.side())) {
location adjacent_tiles[6];
map_location adjacent_tiles[6];
get_adjacent_tiles(i->first,adjacent_tiles);
int best_defense = -1;
std::pair<location,location> best_movement;
std::pair<map_location,map_location> best_movement;
for(size_t n = 0; n != 6; ++n) {
typedef move_map::const_iterator Itor;
typedef ai::move_map::const_iterator Itor;
std::pair<Itor,Itor> range = dstsrc.equal_range(adjacent_tiles[n]);
while(range.first != range.second) {
const location& dst = range.first->first;
const location& src = range.first->second;
const map_location& dst = range.first->first;
const map_location& src = range.first->second;
const unit_map::const_iterator un = get_info().units.find(src);
const t_translation::t_terrain terrain = get_info().map.get_terrain(dst);
@ -130,11 +148,11 @@ protected:
}
void get_villages() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
std::map<map_location,paths> possible_moves;
ai::move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
for(ai::move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
if(get_info().map.is_village(i->first) && current_team().owns_village(i->first) == false) {
move_unit(i->second,i->first,possible_moves);
get_villages();
@ -154,14 +172,14 @@ protected:
if(leader == get_info().units.end())
return;
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
std::map<map_location,paths> possible_moves;
ai::move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
int closest_distance = -1;
std::pair<location,location> closest_move;
std::pair<map_location,map_location> closest_move;
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
for(ai::move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
const int distance = distance_between(i->first,leader->first);
if(closest_distance == -1 || distance < closest_distance) {
closest_distance = distance;
@ -175,6 +193,11 @@ protected:
}
}
void switch_side(ai::side_number side){
set_side(side);
}
bool do_recruitment() {
const std::set<std::string>& options = current_team().recruits();
if (!options.empty()) {
@ -190,10 +213,16 @@ protected:
}
return false;
}
private:
ai::recursion_counter recursion_counter_;
};
ai::ai(int side, bool master) :
ai_readwrite_context(side,master),
ai_default::ai_default(ai::readwrite_context &context) :
ai::side_context_proxy(context),
ai::readonly_context_proxy(context),
ai::readwrite_context_proxy(context),
game_logic::formula_callable(),
recursion_counter_(context.get_recursion_count()),
defensive_position_cache_(),
threats_found_(false),
attacks_(),
@ -216,13 +245,18 @@ ai::ai(int side, bool master) :
{
}
ai::~ai(){
ai_default::~ai_default(){
if (formula_ai_!=NULL) {
delete formula_ai_;
}
}
void ai::new_turn()
void ai_default::switch_side(ai::side_number side){
set_side(side);
}
void ai_default::new_turn()
{
defensive_position_cache_.clear();
threats_found_ = false;
@ -242,11 +276,16 @@ void ai::new_turn()
ai_interface::new_turn();
}
std::string ai::describe_self(){
std::string ai_default::describe_self(){
return "[default_ai]";
}
bool ai::recruit_usage(const std::string& usage)
int ai_default::get_recursion_count() const
{
return recursion_counter_.get_count();
}
bool ai_default::recruit_usage(const std::string& usage)
{
raise_user_interact();
@ -316,14 +355,14 @@ bool ai::recruit_usage(const std::string& usage)
WRN_AI << warning;
// Uncommented until the recruitment limiting macro can be fixed to not trigger this warning.
//lg::wml_error << warning;
return current_team().remove_recruitment_pattern_entry(usage);
return current_team_w().remove_recruitment_pattern_entry(usage);
}
return false;
}
bool ai::multistep_move_possible(const location& from,
const location& to, const location& via,
const std::map<location,paths>& possible_moves) const
bool ai_default::multistep_move_possible(const map_location& from,
const map_location& to, const map_location& via,
const std::map<map_location,paths>& possible_moves) const
{
const unit_map::const_iterator i = units_.find(from);
if(i != units_.end()) {
@ -331,7 +370,7 @@ bool ai::multistep_move_possible(const location& from,
LOG_AI << "when seeing if leader can move from "
<< from << " -> " << to
<< " seeing if can detour to keep at " << via << '\n';
const std::map<location,paths>::const_iterator moves = possible_moves.find(from);
const std::map<map_location,paths>::const_iterator moves = possible_moves.find(from);
if(moves != possible_moves.end()) {
LOG_AI << "found leader moves..\n";
@ -363,10 +402,10 @@ bool ai::multistep_move_possible(const location& from,
return false;
}
map_location ai::move_unit(location from, location to, std::map<location,paths>& possible_moves)
map_location ai_default::move_unit(map_location from, map_location to, ai::moves_map& possible_moves)
{
std::map<location,paths> temp_possible_moves;
std::map<location,paths>* possible_moves_ptr = &possible_moves;
ai::moves_map temp_possible_moves;
ai::moves_map* possible_moves_ptr = &possible_moves;
const unit_map::const_iterator i = units_.find(from);
if(i != units_.end() && i->second.can_recruit()) {
@ -377,7 +416,7 @@ map_location ai::move_unit(location from, location to, std::map<location,paths>&
// If we can make it back to the keep and then to our original destination, do so.
if(multistep_move_possible(from,to,start_pos,possible_moves)) {
from = ai_readwrite_context::move_unit(from,start_pos,possible_moves);
from = readwrite_context_proxy::move_unit(from,start_pos,possible_moves);
if(from != start_pos) {
return from;
}
@ -399,7 +438,7 @@ map_location ai::move_unit(location from, location to, std::map<location,paths>&
}
if(units_.count(to) == 0 || from == to) {
const location res = ai_readwrite_context::move_unit(from,to,*possible_moves_ptr);
const map_location res = readwrite_context_proxy::move_unit(from,to,*possible_moves_ptr);
if(res != to) {
// We've been ambushed; find the ambushing unit and attack them.
adjacent_tiles_array locs;
@ -422,9 +461,9 @@ map_location ai::move_unit(location from, location to, std::map<location,paths>&
}
}
bool ai::attack_close(const map_location& loc) const
bool ai_default::attack_close(const map_location& loc) const
{
for(std::set<location>::const_iterator i = attacks_.begin(); i != attacks_.end(); ++i) {
for(std::set<map_location>::const_iterator i = attacks_.begin(); i != attacks_.end(); ++i) {
if(distance_between(*i,loc) < 4) {
return true;
}
@ -433,15 +472,15 @@ bool ai::attack_close(const map_location& loc) const
return false;
}
void ai::attack_enemy(const location& attacking_unit, const location& target,
void ai_default::attack_enemy(const map_location& attacking_unit, const map_location& target,
int att_weapon, int def_weapon)
{
attacks_.insert(attacking_unit);
ai_readwrite_context::attack_enemy(attacking_unit,target,att_weapon,def_weapon);
readwrite_context_proxy::attack_enemy(attacking_unit,target,att_weapon,def_weapon);
}
void ai::remove_unit_from_moves(const map_location& loc, move_map& srcdst, move_map& dstsrc)
void ai_default::remove_unit_from_moves(const map_location& loc, move_map& srcdst, move_map& dstsrc)
{
srcdst.erase(loc);
for(move_map::iterator i = dstsrc.begin(); i != dstsrc.end(); ) {
@ -468,7 +507,7 @@ struct protected_item {
}
void ai::find_threats()
void ai_default::find_threats()
{
if(threats_found_) {
return;
@ -529,7 +568,7 @@ void ai::find_threats()
}
}
void ai::play_turn()
void ai_default::play_turn()
{
// Protect against a memory over commitment:
/**
@ -546,7 +585,7 @@ void ai::play_turn()
}
}
void ai::evaluate_recruiting_value(unit_map::iterator leader)
void ai_default::evaluate_recruiting_value(unit_map::iterator leader)
{
if (recruiting_preferred_ == 2)
{
@ -560,10 +599,10 @@ void ai::evaluate_recruiting_value(unit_map::iterator leader)
float free_slots = 0.0f;
const float gold = current_team().gold();
const float unit_price = current_team().average_recruit_price();
const float unit_price = current_team_w().average_recruit_price();
if (map_.is_keep(leader->first))
{
std::set<location> checked_hexes;
std::set<map_location> checked_hexes;
checked_hexes.insert(leader->first);
free_slots = count_free_hexes_in_castle(leader->first, checked_hexes);
} else {
@ -581,7 +620,7 @@ void ai::evaluate_recruiting_value(unit_map::iterator leader)
" limit: " << current_team().num_pos_recruits_to_force() << "\n";
}
void ai::do_move()
void ai_default::do_move()
{
log_scope2(log_ai, "doing ai move");
@ -745,7 +784,7 @@ void ai::do_move()
}
}
bool ai::do_combat(std::map<map_location,paths>& possible_moves, const move_map& srcdst,
bool ai_default::do_combat(std::map<map_location,paths>& possible_moves, const move_map& srcdst,
const move_map& dstsrc, const move_map& enemy_srcdst, const move_map& enemy_dstsrc)
{
int ticks = SDL_GetTicks();
@ -806,14 +845,14 @@ bool ai::do_combat(std::map<map_location,paths>& possible_moves, const move_map&
// Bad mistake -- the AI became extremely reluctant to attack anything.
// Documenting this in case someone has this bright idea again...*don't*...
if(choice_rating > 0.0) {
location from = choice_it->movements[0].first;
location to = choice_it->movements[0].second;
location target_loc = choice_it->target;
map_location from = choice_it->movements[0].first;
map_location to = choice_it->movements[0].second;
map_location target_loc = choice_it->target;
// Never used:
// const unit_map::const_iterator tgt = units_.find(target_loc);
const location arrived_at = move_unit(from,to,possible_moves);
const map_location arrived_at = move_unit(from,to,possible_moves);
if(arrived_at != to || units_.find(to) == units_.end()) {
WRN_AI << "unit moving to attack has ended up unexpectedly at "
<< arrived_at << " when moving to " << to << " from " << from << '\n';
@ -843,7 +882,7 @@ bool ai::do_combat(std::map<map_location,paths>& possible_moves, const move_map&
}
bool ai::get_healing(std::map<map_location,paths>& possible_moves,
bool ai_default::get_healing(std::map<map_location,paths>& possible_moves,
const move_map& srcdst, const move_map& enemy_dstsrc)
{
// Find units in need of healing.
@ -900,7 +939,7 @@ bool ai::get_healing(std::map<map_location,paths>& possible_moves,
return false;
}
bool ai::should_retreat(const map_location& loc, const unit_map::const_iterator un,
bool ai_default::should_retreat(const map_location& loc, const unit_map::const_iterator un,
const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc,
double caution)
{
@ -922,7 +961,7 @@ bool ai::should_retreat(const map_location& loc, const unit_map::const_iterator
return caution*their_power*(1.0+exposure) > our_power;
}
bool ai::retreat_units(std::map<map_location,paths>& possible_moves,
bool ai_default::retreat_units(std::map<map_location,paths>& possible_moves,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_dstsrc, unit_map::const_iterator leader)
{
@ -1033,7 +1072,7 @@ bool ai::retreat_units(std::map<map_location,paths>& possible_moves,
return false;
}
bool ai::move_to_targets(std::map<map_location, paths>& possible_moves,
bool ai_default::move_to_targets(std::map<map_location, paths>& possible_moves,
move_map& srcdst, move_map& dstsrc, const move_map& enemy_dstsrc,
unit_map::const_iterator leader)
{
@ -1153,7 +1192,7 @@ bool ai::move_to_targets(std::map<map_location, paths>& possible_moves,
return false;
}
int ai::average_resistance_against(const unit_type& a, const unit_type& b) const
int ai_default::average_resistance_against(const unit_type& a, const unit_type& b) const
{
int weighting_sum = 0, defense = 0;
const std::map<t_translation::t_terrain, size_t>& terrain =
@ -1231,7 +1270,7 @@ int ai::average_resistance_against(const unit_type& a, const unit_type& b) const
return sum/weight_sum;
}
int ai::compare_unit_types(const unit_type& a, const unit_type& b) const
int ai_default::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);
@ -1242,7 +1281,7 @@ int ai::compare_unit_types(const unit_type& a, const unit_type& b) const
return a_effectiveness_vs_b - b_effectiveness_vs_a;
}
void ai::analyze_potential_recruit_combat()
void ai_default::analyze_potential_recruit_combat()
{
if(unit_combat_scores_.empty() == false ||
utils::string_bool(current_team().ai_parameters()["recruitment_ignore_bad_combat"])) {
@ -1313,7 +1352,7 @@ namespace {
struct target_comparer_distance {
target_comparer_distance(const map_location& loc) : loc_(loc) {}
bool operator()(const ai::target& a, const ai::target& b) const {
bool operator()(const ai_default::target& a, const ai_default::target& b) const {
return distance_between(a.loc,loc_) < distance_between(b.loc,loc_);
}
@ -1323,7 +1362,7 @@ private:
}
void ai::analyze_potential_recruit_movements()
void ai_default::analyze_potential_recruit_movements()
{
if(unit_movement_scores_.empty() == false ||
utils::string_bool(current_team().ai_parameters()["recruitment_ignore_bad_movement"])) {
@ -1433,7 +1472,7 @@ void ai::analyze_potential_recruit_movements()
}
}
bool ai::do_recruitment()
bool ai_default::do_recruitment()
{
const unit_map::const_iterator leader = units_.find_leader(get_side());
if(leader == units_.end()) {
@ -1442,11 +1481,11 @@ bool ai::do_recruitment()
raise_user_interact();
// Let formula ai to do recruiting first
if (get_master())
if (get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE)
{
if (!current_team().ai_parameters()["recruitment"].empty()){
if (formula_ai_ == NULL){
formula_ai_ = static_cast<formula_ai*>(ai_manager::create_transient_ai(ai_manager::AI_TYPE_FORMULA_AI, get_side(),false));
formula_ai_ = static_cast<formula_ai*>(ai_manager::create_transient_ai(ai_manager::AI_TYPE_FORMULA_AI, this));
}
assert(formula_ai_ != NULL);
@ -1541,7 +1580,7 @@ bool ai::do_recruitment()
return ret;
}
void ai::move_leader_to_goals( const move_map& enemy_dstsrc)
void ai_default::move_leader_to_goals( const move_map& enemy_dstsrc)
{
const config &goal = current_team().ai_parameters().child("leader_goal");
@ -1596,7 +1635,7 @@ void ai::move_leader_to_goals( const move_map& enemy_dstsrc)
}
}
void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
void ai_default::move_leader_after_recruit(const move_map& /*srcdst*/,
const move_map& /*dstsrc*/, const move_map& enemy_dstsrc)
{
@ -1717,7 +1756,7 @@ void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
}
}
bool ai::leader_can_reach_keep()
bool ai_default::leader_can_reach_keep()
{
const unit_map::iterator leader = units_.find_leader(get_side());
if(leader == units_.end() || leader->second.incapacitated()) {
@ -1740,7 +1779,7 @@ bool ai::leader_can_reach_keep()
return leader_paths.destinations.contains(start_pos);
}
int ai::rate_terrain(const unit& u, const map_location& loc)
int ai_default::rate_terrain(const unit& u, const map_location& loc)
{
const t_translation::t_terrain terrain = map_.get_terrain(loc);
const int defense = u.defense_modifier(terrain);
@ -1770,7 +1809,7 @@ int ai::rate_terrain(const unit& u, const map_location& loc)
return rating;
}
const ai::defensive_position& ai::best_defensive_position(const map_location& loc,
const ai_default::defensive_position& ai_default::best_defensive_position(const map_location& loc,
const move_map& dstsrc, const move_map& srcdst, const move_map& enemy_dstsrc)
{
const unit_map::const_iterator itor = units_.find(loc);
@ -1816,7 +1855,7 @@ const ai::defensive_position& ai::best_defensive_position(const map_location& lo
return defensive_position_cache_[loc];
}
bool ai::is_accessible(const location& loc, const move_map& dstsrc) const
bool ai_default::is_accessible(const location& loc, const move_map& dstsrc) const
{
map_location adj[6];
get_adjacent_tiles(loc,adj);
@ -1830,7 +1869,7 @@ bool ai::is_accessible(const location& loc, const move_map& dstsrc) const
}
const std::set<map_location>& ai::keeps()
const std::set<map_location>& ai_default::keeps()
{
if(keeps_.empty()) {
// Generate the list of keeps:
@ -1855,7 +1894,7 @@ const std::set<map_location>& ai::keeps()
return keeps_;
}
const map_location& ai::nearest_keep(const map_location& loc)
const map_location& ai_default::nearest_keep(const map_location& loc)
{
const std::set<map_location>& keeps = this->keeps();
if(keeps.empty()) {
@ -1876,7 +1915,7 @@ const map_location& ai::nearest_keep(const map_location& loc)
return *res;
}
const std::set<map_location>& ai::avoided_locations()
const std::set<map_location>& ai_default::avoided_locations()
{
if(avoid_.empty()) {
foreach (const config &av, current_team().ai_parameters().child_range("avoid"))
@ -1894,7 +1933,7 @@ const std::set<map_location>& ai::avoided_locations()
return avoid_;
}
int ai::attack_depth()
int ai_default::attack_depth()
{
if(attack_depth_ > 0) {
return attack_depth_;
@ -1905,8 +1944,22 @@ int ai::attack_depth()
return attack_depth_;
}
variant ai_default::get_value(const std::string& key) const
{
if(key == "map") {
return variant(new gamemap_callable(get_info().map));
}
return variant();
}
variant ai::attack_analysis::get_value(const std::string& key) const
void ai_default::get_inputs(std::vector<game_logic::formula_input>* inputs) const
{
using game_logic::FORMULA_READ_ONLY;
inputs->push_back(game_logic::formula_input("map", FORMULA_READ_ONLY));
}
variant ai_default::attack_analysis::get_value(const std::string& key) const
{
using namespace game_logic;
if(key == "target") {
@ -1961,7 +2014,7 @@ variant ai::attack_analysis::get_value(const std::string& key) const
}
}
void ai::attack_analysis::get_inputs(std::vector<game_logic::formula_input>* inputs) const
void ai_default::attack_analysis::get_inputs(std::vector<game_logic::formula_input>* inputs) const
{
using namespace game_logic;
inputs->push_back(formula_input("target", FORMULA_READ_ONLY));

View File

@ -20,28 +20,36 @@
#include "../global.hpp"
#include "../actions.hpp"
#include "ai_interface.hpp"
#include "contexts.hpp"
#include "../formula_callable.hpp"
class formula_ai;
/** A trivial ai that sits around doing absolutely nothing. */
class idle_ai : public ai_readwrite_context {
class idle_ai : public ai::readwrite_context_proxy, public ai_interface {
public:
idle_ai(int side, bool master);
idle_ai(ai::readwrite_context &context);
void play_turn();
virtual std::string describe_self();
void switch_side(ai::side_number side);
int get_recursion_count() const;
private:
ai::recursion_counter recursion_counter_;
};
class ai : public ai_readwrite_context {
class ai_default : public virtual ai::readwrite_context_proxy, public ai_interface, public game_logic::formula_callable {
public:
typedef ai::move_map move_map;
typedef map_location location;//will get rid of this later
ai(int side, bool master);
virtual ~ai();
ai_default(ai::readwrite_context &context);
virtual ~ai_default();
virtual void play_turn();
virtual void new_turn();
virtual std::string describe_self();
void switch_side(ai::side_number side);
struct target {
enum TYPE { VILLAGE, LEADER, EXPLICIT, THREAT, BATTLE_AID, MASS, SUPPORT };
@ -72,14 +80,21 @@ public:
void invalidate_defensive_position_cache() { defensive_position_cache_.clear(); }
virtual variant get_value(const std::string& key) const;
virtual void get_inputs(std::vector<game_logic::formula_input>* inputs) const;
bool leader_can_reach_keep();
/** Return true iff there has been another attack this turn 'close' to this one. */
/** Return true if there has been another attack this turn 'close' to this one. */
bool attack_close(const location& loc) const;
/** get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return nearest occupied that can be reached in 1 turn, if none - return nearest keep, if none - return null_location */
const map_location& suitable_keep( const location& leader_location, const paths& leader_paths );
/** get the recursion counter */
int get_recursion_count() const;
private:
ai::recursion_counter recursion_counter_;
protected:
std::map<location,defensive_position> defensive_position_cache_;
@ -175,11 +190,11 @@ public:
void analyze(const gamemap& map, unit_map& units,
const std::vector<team>& teams,
const gamestatus& status,
class ai& ai_obj,
class ai_default& ai_obj,
const move_map& dstsrc, const move_map& srcdst,
const move_map& enemy_dstsrc, double aggression);
double rating(double aggression, class ai& ai_obj) const;
double rating(double aggression, class ai_default& ai_obj) const;
variant get_value(const std::string& key) const;
void get_inputs(std::vector<game_logic::formula_input>* inputs) const;

View File

@ -20,15 +20,24 @@
#ifndef AI_AI2_HPP_INCLUDED
#define AI_AI2_HPP_INCLUDED
#include "ai_interface.hpp"
#include "contexts.hpp"
class ai2 : public ai_readwrite_context
{
class ai2 : public ai::readwrite_context_proxy, public ai_interface {
public:
ai2(int side, bool master) : ai_readwrite_context(side, master)
ai2(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context),recursion_counter_(context.get_recursion_count())
{}
virtual ~ai2() {}
virtual void play_turn() {}
virtual void switch_side(ai::side_number side){
set_side(side);
}
int get_recursion_count() const{
return recursion_counter_.get_count();
}
private:
ai::recursion_counter recursion_counter_;
};

View File

@ -669,50 +669,50 @@ std::ostream &operator<<(std::ostream &s, ai_stopunit_result const &r) {
// STATELESS INTERFACE TO AI ACTIONS
// =======================================================================
std::auto_ptr< ai_attack_result > ai_actions::execute_attack_action( unsigned int side,
ai_attack_result_ptr ai_actions::execute_attack_action( unsigned int side,
bool execute,
const map_location& attacker_loc,
const map_location& defender_loc,
int attacker_weapon)
{
std::auto_ptr< ai_attack_result > ai_action(new ai_attack_result(side,attacker_loc,defender_loc,attacker_weapon));
ai_attack_result_ptr ai_action(new ai_attack_result(side,attacker_loc,defender_loc,attacker_weapon));
execute ? ai_action->execute() : ai_action->check_before();
return ai_action;
}
std::auto_ptr< ai_move_result > ai_actions::execute_move_action( unsigned int side,
ai_move_result_ptr ai_actions::execute_move_action( unsigned int side,
bool execute,
const map_location& from,
const map_location& to,
bool remove_movement)
{
std::auto_ptr< ai_move_result > ai_action(new ai_move_result(side,from,to,remove_movement));
ai_move_result_ptr ai_action(new ai_move_result(side,from,to,remove_movement));
execute ? ai_action->execute() : ai_action->check_before();
return ai_action;
}
std::auto_ptr< ai_recruit_result > ai_actions::execute_recruit_action( unsigned int side,
ai_recruit_result_ptr ai_actions::execute_recruit_action( unsigned int side,
bool execute,
const std::string& unit_name,
const map_location& where)
{
std::auto_ptr< ai_recruit_result > ai_action(new ai_recruit_result(side,unit_name,where));
ai_recruit_result_ptr ai_action(new ai_recruit_result(side,unit_name,where));
execute ? ai_action->execute() : ai_action->check_before();
return ai_action;
}
std::auto_ptr< ai_stopunit_result > ai_actions::execute_stopunit_action( unsigned int side,
ai_stopunit_result_ptr ai_actions::execute_stopunit_action( unsigned int side,
bool execute,
const map_location& unit_location,
bool remove_movement,
bool remove_attacks)
{
std::auto_ptr< ai_stopunit_result > ai_action(new ai_stopunit_result(side,unit_location,remove_movement,remove_attacks));
ai_stopunit_result_ptr ai_action(new ai_stopunit_result(side,unit_location,remove_movement,remove_attacks));
execute ? ai_action->execute() : ai_action->check_before();
return ai_action;

View File

@ -240,6 +240,11 @@ std::ostream &operator<<(std::ostream &s, ai_move_result const &r);
std::ostream &operator<<(std::ostream &s, ai_recruit_result const &r);
std::ostream &operator<<(std::ostream &s, ai_stopunit_result const &r);
typedef boost::shared_ptr<ai_attack_result> ai_attack_result_ptr;
typedef boost::shared_ptr<ai_move_result> ai_move_result_ptr;
typedef boost::shared_ptr<ai_recruit_result> ai_recruit_result_ptr;
typedef boost::shared_ptr<ai_stopunit_result> ai_stopunit_result_ptr;
class ai_actions {
public:
@ -260,7 +265,7 @@ public:
* @retval possible result: attacker and/or defender are invalid
* @retval possible result: attacker doesn't have the specified weapon
*/
static std::auto_ptr<ai_attack_result> execute_attack_action( unsigned int side,
static ai_attack_result_ptr execute_attack_action( unsigned int side,
bool execute,
const map_location& attacker_loc,
const map_location& defender_loc,
@ -279,7 +284,7 @@ static std::auto_ptr<ai_attack_result> execute_attack_action( unsigned int side,
* @retval possible result: move is interrupted
* @retval possible result: move is impossible
*/
static std::auto_ptr<ai_move_result > execute_move_action( unsigned int side,
static ai_move_result_ptr execute_move_action( unsigned int side,
bool execute,
const map_location& from,
const map_location& to,
@ -298,7 +303,7 @@ static std::auto_ptr<ai_move_result > execute_move_action( unsigned int side,
* @retval possible_result: no free space on keep
* @retval possible_result: not enough gold
*/
static std::auto_ptr<ai_recruit_result> execute_recruit_action( unsigned int side,
static ai_recruit_result_ptr execute_recruit_action( unsigned int side,
bool execute,
const std::string& unit_name,
const map_location& where );
@ -315,7 +320,7 @@ static std::auto_ptr<ai_recruit_result> execute_recruit_action( unsigned int sid
* @retval possible_result: something wrong
* @retval possible_result: nothing to do
*/
static std::auto_ptr<ai_stopunit_result> execute_stopunit_action( unsigned int side,
static ai_stopunit_result_ptr execute_stopunit_action( unsigned int side,
bool execute,
const map_location& unit_location,
bool remove_movement,
@ -325,5 +330,7 @@ static std::auto_ptr<ai_stopunit_result> execute_stopunit_action( unsigned int s
};
//@todo 1.7 Add an ai action to set a goto on a unit
//@todo 1.7 Add an ai action to send a chat message to a player
#endif

View File

@ -32,7 +32,7 @@ static lg::log_domain log_ai("ai/attack");
const int max_positions = 10000;
/** Analyze possibility of attacking target on 'loc'. */
void ai::do_attack_analysis(
void ai_default::do_attack_analysis(
const location& loc,
const move_map& srcdst, const move_map& dstsrc,
const move_map& fullmove_srcdst, const move_map& fullmove_dstsrc,
@ -296,10 +296,10 @@ void ai::do_attack_analysis(
}
void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
void ai_default::attack_analysis::analyze(const gamemap& map, unit_map& units,
const std::vector<team>& teams,
const gamestatus& status,
class ai& ai_obj,
class ai_default& ai_obj,
const move_map& dstsrc, const move_map& srcdst,
const move_map& enemy_dstsrc, double aggression)
{
@ -512,7 +512,7 @@ void ai::attack_analysis::analyze(const gamemap& map, unit_map& units,
}
}
double ai::attack_analysis::rating(double aggression, ai& ai_obj) const
double ai_default::attack_analysis::rating(double aggression, ai_default& ai_obj) const
{
if(leader_threat) {
aggression = 1.0;
@ -598,7 +598,7 @@ double ai::attack_analysis::rating(double aggression, ai& ai_obj) const
return value;
}
std::vector<ai::attack_analysis> ai::analyze_targets(
std::vector<ai_default::attack_analysis> ai_default::analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
)
@ -651,7 +651,7 @@ std::vector<ai::attack_analysis> ai::analyze_targets(
return res;
}
double ai::power_projection(const map_location& loc, const move_map& dstsrc, bool use_terrain) const
double ai_default::power_projection(const map_location& loc, const move_map& dstsrc, bool use_terrain) const
{
map_location used_locs[6];
int ratings[6];
@ -762,7 +762,7 @@ double ai::power_projection(const map_location& loc, const move_map& dstsrc, bo
* There is no real hope for us: we should try to do some damage to the enemy.
* We can spend some cycles here, since it's rare.
*/
bool ai::desperate_attack(const map_location &loc)
bool ai_default::desperate_attack(const map_location &loc)
{
const unit &u = units_.find(loc)->second;
LOG_AI << "desperate attack by '" << u.type_id() << "' " << loc << "\n";

View File

@ -179,7 +179,7 @@ namespace dfool {
}
unit_memory_.write(ai_mem);
current_team().set_ai_memory(ai_mem);
current_team_w().set_ai_memory(ai_mem);
return;
}
@ -239,11 +239,11 @@ namespace dfool {
bool dfool_ai::moveto(const config &o, unit_map::const_iterator m)
{
location target(atoi(o["target_x"].c_str()) - 1, atoi(o["target_y"].c_str()) - 1);
map_location target(atoi(o["target_x"].c_str()) - 1, atoi(o["target_y"].c_str()) - 1);
LOG_AI << "\tmoving to:(" << target.x << ',' << target.y << ")\n";
if(m->second.movement_left()){
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
ai::moves_map possible_moves;
ai::move_map srcdst, dstsrc;
unit_map known_units;
// unit_memory_.known_map(known_units, get_info().state.turn());
@ -257,10 +257,10 @@ bool dfool_ai::moveto(const config &o, unit_map::const_iterator m)
calculate_moves(known_units,possible_moves,srcdst,dstsrc,false,false,NULL,true);
int closest_distance = -1;
std::pair<location,location> closest_move;
std::pair<map_location,map_location> closest_move;
/** @todo 2.0 This undoubtedly could be done more cleanly */
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
for(ai::move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
// Must restrict move_map to only unit that is moving.
if(i->second==m->first){
const int distance = distance_between(target,i->first);

View File

@ -22,6 +22,7 @@
#include "../global.hpp"
#include "ai_interface.hpp"
#include "contexts.hpp"
#include "../map_location.hpp"
#include "../unit_map.hpp"
@ -98,15 +99,22 @@ namespace dfool {
* does not target units that it has not "seen",
* and does not make decisions based on unseen units.
*/
class dfool_ai : public ai_readwrite_context {
class dfool_ai : public ai::readwrite_context_proxy, public ai_interface {
public:
dfool_ai(int side, bool master) : ai_readwrite_context(side, master), unit_memory_(current_team().ai_memory()){}
void play_turn();
virtual std::string describe_self();
dfool_ai(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count()), unit_memory_(current_team().ai_memory()){}
void play_turn();
virtual std::string describe_self();
virtual int get_recursion_count() const{
return recursion_counter_.get_count();
}
private:
ai::recursion_counter recursion_counter_;
// std::map<std::string,target> target_map_;
unit_list all_units();
unit_list visible_units();
void switch_side(ai::side_number /*side*/)
{}
unit_list my_units();
unit_list filter_units(const config& filter,unit_list& ul, unit_map& um);
bool moveto(const config &o, unit_map::const_iterator m);

View File

@ -21,32 +21,14 @@
#define AI_AI_INTERFACE_HPP_INCLUDED
#include "../formula_callable.hpp"
#include "game_info.hpp"
class side_context {
public:
side_context(int side) : side_(side) {}
virtual ~side_context() {}
/** get the 1-based side number which is controlled by this AI */
int get_side() const { return side_;}
/** Set the side */
virtual void set_side(int side) { side_ = side; }
private:
int side_;
};
class ai_interface : public side_context {
class ai_interface {
public:
/**
* The constructor.
*/
ai_interface(unsigned int side, bool master) : side_context(side), master_(master) {
ai_interface() {
}
virtual ~ai_interface() {}
@ -63,8 +45,7 @@ public:
virtual void new_turn() {
}
/** get the 'master' flag of the AI. 'master' AI is the top-level-AI. */
bool get_master() const { return master_;}
virtual void switch_side(ai::side_number side) = 0;
/** Evaluate */
virtual std::string evaluate(const std::string& /*str*/)
@ -73,8 +54,6 @@ public:
/** Describe self*/
virtual std::string describe_self() const;
private:
bool master_;
};
#endif

View File

@ -22,6 +22,7 @@
#include "ai_configuration.hpp"
#include "ai_manager.hpp"
#include "ai_dfool.hpp"
#include "contexts.hpp"
#include "formula_ai.hpp"
#include "../game_events.hpp"
#include "../game_preferences.hpp"
@ -48,7 +49,7 @@ static lg::log_domain log_ai_manager("ai/manager");
#define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
ai_holder::ai_holder( int side, const std::string& ai_algorithm_type )
: ai_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
: ai_(NULL), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
{
DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder" << std::endl;
}
@ -57,6 +58,17 @@ ai_holder::ai_holder( int side, const std::string& ai_algorithm_type )
void ai_holder::init( int side )
{
LOG_AI_MANAGER << describe_ai() << "Preparing to create new managed master AI" << std::endl;
if (side_context_ == NULL) {
side_context_ = new ai::side_context_impl(side);
} else {
side_context_->set_side(side);
}
if (readonly_context_ == NULL){
readonly_context_ = new ai::readonly_context_impl(*side_context_);
}
if (readwrite_context_ == NULL){
readwrite_context_ = new ai::readwrite_context_impl(*readonly_context_);
}
this->ai_ = create_ai(side);
if (this->ai_ == NULL) {
ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!" << std::endl;
@ -69,8 +81,11 @@ ai_holder::~ai_holder()
{
if (this->ai_ != NULL) {
LOG_AI_MANAGER << describe_ai() << "Managed AI will be deleted" << std::endl;
delete this->ai_;
}
delete this->ai_;
delete this->readwrite_context_;
delete this->readonly_context_;
delete this->side_context_;
}
@ -181,8 +196,9 @@ bool ai_holder::is_mandate_ok()
ai_interface* ai_holder::create_ai( int side )
{
assert (side > 0);
//@note: ai_params and ai_algorithm_type are supposed to be set before calling init( );
return ai_manager::create_transient_ai(ai_algorithm_type_,side,true);
assert (readwrite_context_!=NULL);
//@note: ai_params, contexts, and ai_algorithm_type are supposed to be set before calling init( );
return ai_manager::create_transient_ai(ai_algorithm_type_,readwrite_context_);
}
@ -523,42 +539,45 @@ bool ai_manager::add_ai_for_side( int side, const std::string& ai_algorithm_type
}
ai_interface* ai_manager::create_transient_ai( const std::string& ai_algorithm_type, int side, bool master )
ai_interface* ai_manager::create_transient_ai( const std::string &ai_algorithm_type, ai::readwrite_context *rw_context )
{
assert(rw_context!=NULL);
//@todo 1.7 modify this code to use a 'factory lookup' pattern -
//a singleton which holds a map<string,ai_factory> of all functors which can create AIs.
//a singleton which holds a map<string,ai_factory_ptr> of all functors which can create AIs.
//this will allow individual AI implementations to 'register' themselves.
//: To add an AI of your own, put
// if(ai_algorithm_type == "my_ai") {
// LOG_AI_MANAGER << "Creating new AI of type [" << "my_ai" << "]"<< std::endl;
// return new my_ai(side,master);
// return new my_ai(rw_context);
// }
// at the top of this function
//if(ai_algorithm_type == ai_manager::AI_TYPE_SAMPLE_AI) {
// LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
// return new sample_ai(side,master);
// return new sample_ai(*rw_context);
//}
if(ai_algorithm_type == ai_manager::AI_TYPE_IDLE_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
return new idle_ai(side,master);
return new idle_ai(*rw_context);
}
if(ai_algorithm_type == ai_manager::AI_TYPE_FORMULA_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_FORMULA_AI << "]"<< std::endl;
return new formula_ai(side,master);
return new formula_ai(*rw_context);
}
if(ai_algorithm_type == ai_manager::AI_TYPE_DFOOL_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_DFOOL_AI << "]"<< std::endl;
return new dfool::dfool_ai(side,master);
return new dfool::dfool_ai(*rw_context);
}
if(ai_algorithm_type == ai_manager::AI_TYPE_AI2) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_AI2 << "]"<< std::endl;
return new ai2(side,master);
return new ai2(*rw_context);
}
if (!ai_algorithm_type.empty() && ai_algorithm_type != ai_manager::AI_TYPE_DEFAULT) {
@ -566,7 +585,7 @@ ai_interface* ai_manager::create_transient_ai( const std::string& ai_algorithm_t
}
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_DEFAULT << "]"<< std::endl;
return new ai(side,master);
return new ai_default(*rw_context);
}
std::vector<std::string> ai_manager::get_available_ais()

View File

@ -24,6 +24,7 @@
#define AI_AI_MANAGER_HPP_INCLUDED
#include "../global.hpp"
#include "contexts.hpp"
#include "game_info.hpp"
#include <map>
@ -73,7 +74,10 @@ public:
bool is_mandate_ok();
private:
ai_interface* ai_;
ai_interface *ai_;
ai::side_context *side_context_;
ai::readonly_context *readonly_context_;
ai::readwrite_context *readwrite_context_;
std::string ai_algorithm_type_;
config ai_effective_parameters_;
config ai_global_parameters_;
@ -262,12 +266,10 @@ public:
* Returns a pointer to a new AI. It is the sole responsibility of the caller
* to manage its lifetime.
* @param ai_algorithm_type type of AI algorithm to create
* @param side side number (1-based)
* @param master should this AI be a master AI ? Only master AIs are
* allowed to fallback. If you are not sure, pick false here.
* @param context context in which this ai is created
* @return the reference to the created AI
*/
static ai_interface* create_transient_ai( const std::string& ai_algorithm_type, int side, bool master = false);
static ai_interface* create_transient_ai( const std::string& ai_algorithm_type, ai::readwrite_context *rw_context);
/**

View File

@ -91,7 +91,7 @@ private:
const bool avoid_enemies_;
};
std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const move_map& enemy_dstsrc)
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...");
@ -182,7 +182,7 @@ std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const
}
}
std::vector<team::target>& team_targets = current_team().targets();
std::vector<team::target>& team_targets = current_team_w().targets();
//find the enemy leaders and explicit targets
unit_map::const_iterator u;
@ -233,7 +233,7 @@ std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const
return targets;
}
map_location ai::form_group(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
map_location ai_default::form_group(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
{
if(route.empty()) {
return location();
@ -274,7 +274,7 @@ map_location ai::form_group(const std::vector<location>& route, const move_map&
return *i;
}
void ai::enemies_along_path(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
void ai_default::enemies_along_path(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
{
for(std::vector<location>::const_iterator i = route.begin(); i != route.end(); ++i) {
map_location adj[6];
@ -288,7 +288,7 @@ void ai::enemies_along_path(const std::vector<location>& route, const move_map&
}
}
bool ai::move_group(const location& dst, const std::vector<location>& route, const std::set<location>& units)
bool ai_default::move_group(const location& dst, const std::vector<location>& route, const std::set<location>& units)
{
const std::vector<location>::const_iterator itor = std::find(route.begin(),route.end(),dst);
if(itor == route.end()) {
@ -388,7 +388,7 @@ bool ai::move_group(const location& dst, const std::vector<location>& route, con
return res;
}
double ai::rate_group(const std::set<location>& group, const std::vector<location>& battlefield) const
double ai_default::rate_group(const std::set<location>& group, const std::vector<location>& battlefield) const
{
double strength = 0.0;
for(std::set<location>::const_iterator i = group.begin(); i != group.end(); ++i) {
@ -420,14 +420,14 @@ double ai::rate_group(const std::set<location>& group, const std::vector<locatio
return strength;
}
double ai::compare_groups(const std::set<location>& our_group, const std::set<location>& their_group, const std::vector<location>& battlefield) const
double ai_default::compare_groups(const std::set<location>& our_group, const std::set<location>& their_group, const std::vector<location>& battlefield) const
{
const double a = rate_group(our_group,battlefield);
const double b = std::max<double>(rate_group(their_group,battlefield),0.01);
return a/b;
}
std::pair<map_location,map_location> ai::choose_move(std::vector<target>& targets, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc)
std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>& targets, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc)
{
log_scope2(log_ai, "choosing move");
@ -531,7 +531,7 @@ std::pair<map_location,map_location> ai::choose_move(std::vector<target>& target
if(tg->type == target::VILLAGE) {
if(current_team().ai_parameters().has_attribute("scout_village_targetting")) {
rating *= lexical_cast_default<int>(current_team().ai_parameters()["scout_village_targetting"],3);
lg::wml_error << "[ai] the 'scout_village_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'scout_village_targeting' instead\n";
lg::wml_error << "[ai_default] the 'scout_village_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'scout_village_targeting' instead\n";
}
else {
rating *= lexical_cast_default<int>(current_team().ai_parameters()["scout_village_targeting"],3);
@ -566,7 +566,7 @@ std::pair<map_location,map_location> ai::choose_move(std::vector<target>& target
bool simple_targeting = false;
if(current_team().ai_parameters().has_attribute("simple_targetting")) {
simple_targeting = utils::string_bool(current_team().ai_parameters()["simple_targetting"]);
lg::wml_error << "[ai] the 'simple_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'simple_targeting' instead\n";
lg::wml_error << "[ai_default] the 'simple_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'simple_targeting' instead\n";
}
else {
simple_targeting = utils::string_bool(current_team().ai_parameters()["simple_targeting"]);
@ -844,7 +844,7 @@ std::pair<map_location,map_location> ai::choose_move(std::vector<target>& target
return std::pair<location,location>();
}
void ai::access_points(const move_map& srcdst, const location& u, const location& dst, std::vector<location>& out)
void ai_default::access_points(const move_map& srcdst, const location& u, const location& dst, std::vector<location>& out)
{
const unit_map::const_iterator u_it = units_.find(u);
if(u_it == units_.end()) {
@ -866,7 +866,7 @@ void ai::access_points(const move_map& srcdst, const location& u, const location
}
}
const map_location& ai::suitable_keep(const map_location& leader_location, const paths& leader_paths){
const map_location& ai_default::suitable_keep(const map_location& leader_location, const paths& leader_paths){
if (map_.is_keep(leader_location)) {
return leader_location; //if leader already on keep, then return leader_location
}
@ -908,7 +908,7 @@ const map_location& ai::suitable_keep(const map_location& leader_location, const
return nearest_keep(leader_location); // return nearest keep
}
void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
void ai_default::move_leader_to_keep(const move_map& enemy_dstsrc)
{
const unit_map::iterator leader = units_.find_leader(get_side());
if(leader == units_.end() || leader->second.incapacitated()) {
@ -957,7 +957,7 @@ void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
}
}
int ai::count_free_hexes_in_castle(const map_location& loc, std::set<map_location>& checked_hexes)
int ai_default::count_free_hexes_in_castle(const map_location& loc, std::set<map_location>& checked_hexes)
{
int ret = 0;
location adj[6];

View File

@ -15,7 +15,7 @@
/**
* @file ai/ai_village.cpp
* The village capturing part of the AI.
* ai::get_villages and ai::find_villages are based on ai::get_villages in ai.cpp
* ai_default::get_villages and ai_default::find_villages are based on ai_default::get_villages in ai.cpp
*/
#include "../global.hpp"
@ -151,7 +151,7 @@ static void full_dispatch(treachmap& reachmap, tmoves& moves);
/** Shows which villages every unit can reach (debug function). */
static void dump_reachmap(treachmap& reachmap);
bool ai::get_villages(std::map<map_location,paths>& possible_moves,
bool ai_default::get_villages(std::map<map_location,paths>& possible_moves,
const move_map& dstsrc, const move_map& enemy_dstsrc,
unit_map::iterator &leader)
{
@ -255,7 +255,7 @@ bool ai::get_villages(std::map<map_location,paths>& possible_moves,
return false;
}
void ai::find_villages(
void ai_default::find_villages(
treachmap& reachmap,
tmoves& moves,
const std::multimap<map_location,map_location>& dstsrc,

View File

@ -45,65 +45,91 @@ static lg::log_domain log_ai("ai/general");
// =======================================================================
//
// =======================================================================
namespace ai {
int side_context_impl::get_recursion_count() const
{
return recursion_counter_.get_count();
}
void ai_readonly_context::raise_user_interact() const
int readonly_context_impl::get_recursion_count() const
{
return recursion_counter_.get_count();
}
int readwrite_context_impl::get_recursion_count() const
{
return recursion_counter_.get_count();
}
void readonly_context_impl::raise_user_interact() const
{
ai_manager::raise_user_interact();
}
void ai_readwrite_context::raise_unit_recruited() const
void readwrite_context_impl::raise_unit_recruited() const
{
ai_manager::raise_unit_recruited();
}
void ai_readwrite_context::raise_unit_moved() const
void readwrite_context_impl::raise_unit_moved() const
{
ai_manager::raise_unit_moved();
}
void ai_readwrite_context::raise_enemy_attacked() const
void readwrite_context_impl::raise_enemy_attacked() const
{
ai_manager::raise_enemy_attacked();
}
std::auto_ptr<ai_attack_result> ai_readwrite_context::execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
ai_attack_result_ptr readwrite_context_impl::execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return ai_actions::execute_attack_action(get_side(),true,attacker_loc,defender_loc,attacker_weapon);
}
std::auto_ptr<ai_attack_result> ai_readonly_context::check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
ai_attack_result_ptr readonly_context_impl::check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return ai_actions::execute_attack_action(get_side(),false,attacker_loc,defender_loc,attacker_weapon);
}
std::auto_ptr<ai_move_result> ai_readwrite_context::execute_move_action(const map_location& from, const map_location& to, bool remove_movement){
ai_move_result_ptr readwrite_context_impl::execute_move_action(const map_location& from, const map_location& to, bool remove_movement){
return ai_actions::execute_move_action(get_side(),true,from,to,remove_movement);
}
std::auto_ptr<ai_move_result> ai_readonly_context::check_move_action(const map_location& from, const map_location& to, bool remove_movement){
ai_move_result_ptr readonly_context_impl::check_move_action(const map_location& from, const map_location& to, bool remove_movement){
return ai_actions::execute_move_action(get_side(),false,from,to,remove_movement);
}
std::auto_ptr<ai_recruit_result> ai_readwrite_context::execute_recruit_action(const std::string& unit_name, const map_location &where){
ai_recruit_result_ptr readwrite_context_impl::execute_recruit_action(const std::string& unit_name, const map_location &where){
return ai_actions::execute_recruit_action(get_side(),true,unit_name,where);
}
std::auto_ptr<ai_recruit_result> ai_readonly_context::check_recruit_action(const std::string& unit_name, const map_location &where){
ai_recruit_result_ptr readonly_context_impl::check_recruit_action(const std::string& unit_name, const map_location &where){
return ai_actions::execute_recruit_action(get_side(),false,unit_name,where);
}
std::auto_ptr<ai_stopunit_result> ai_readwrite_context::execute_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
ai_stopunit_result_ptr readwrite_context_impl::execute_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
return ai_actions::execute_stopunit_action(get_side(),true,unit_location,remove_movement,remove_attacks);
}
std::auto_ptr<ai_stopunit_result> ai_readonly_context::check_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
ai_stopunit_result_ptr readonly_context_impl::check_stopunit_action(const map_location& unit_location, bool remove_movement, bool remove_attacks){
return ai_actions::execute_stopunit_action(get_side(),false,unit_location,remove_movement,remove_attacks);
}
bool ai_readwrite_context::recruit(const std::string& unit_name, map_location loc)
bool readwrite_context_impl::recruit(const std::string& unit_name, map_location loc)
{
const std::set<std::string>& recruits = current_team().recruits();
@ -146,7 +172,7 @@ bool ai_readwrite_context::recruit(const std::string& unit_name, map_location lo
if(recruit_err.empty()) {
statistics::recruit_unit(new_unit);
current_team().spend_gold(u->second.cost());
current_team_w().spend_gold(u->second.cost());
// Confirm the transaction - i.e. don't undo recruitment
replay_guard.confirm_transaction();
@ -174,27 +200,25 @@ bool ai_readwrite_context::recruit(const std::string& unit_name, map_location lo
}
}
const ai_game_info& ai_readonly_context::get_info() const{
const ai_game_info& readonly_context_impl::get_info() const{
return ai_manager::get_active_ai_info_for_side(get_side());
}
ai_game_info& ai_readwrite_context::get_info(){
ai_game_info& readwrite_context_impl::get_info_w(){
return ai_manager::get_active_ai_info_for_side(get_side());
}
const ai_game_info& ai_readwrite_context::get_info() const{
return ai_manager::get_active_ai_info_for_side(get_side());
}
void ai_readonly_context::diagnostic(const std::string& msg)
void readonly_context_impl::diagnostic(const std::string& msg)
{
if(game_config::debug) {
get_info().disp.set_diagnostic(msg);
}
}
void ai_readonly_context::log_message(const std::string& msg)
void readonly_context_impl::log_message(const std::string& msg)
{
if(game_config::debug) {
get_info().disp.add_chat_message(time(NULL), "ai", get_side(), msg,
@ -203,7 +227,7 @@ void ai_readonly_context::log_message(const std::string& msg)
}
map_location ai_readwrite_context::move_unit(map_location from, map_location to,
map_location readwrite_context_impl::move_unit(map_location from, map_location to,
std::map<map_location,paths>& possible_moves)
{
const map_location loc = move_unit_partial(from,to,possible_moves);
@ -220,10 +244,11 @@ map_location ai_readwrite_context::move_unit(map_location from, map_location to,
return loc;
}
map_location ai_readwrite_context::move_unit_partial(map_location from, map_location to,
map_location readwrite_context_impl::move_unit_partial(map_location from, map_location to,
std::map<map_location,paths>& possible_moves)
{
LOG_AI << "ai_readwrite_context::move_unit " << from << " -> " << to << '\n';
LOG_AI << "readwrite_context_impl::move_unit " << from << " -> " << to << '\n';
assert(to.valid() && to.x <= MAX_MAP_AREA && to.y <= MAX_MAP_AREA);
// Stop the user from issuing any commands while the unit is moving.
const events::command_disabler disable_commands;
@ -384,14 +409,15 @@ map_location ai_readwrite_context::move_unit_partial(map_location from, map_loca
return to;
}
void ai_readonly_context::calculate_possible_moves(std::map<map_location,paths>& res, move_map& srcdst,
void readonly_context_impl::calculate_possible_moves(std::map<map_location,paths>& res, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement,
const std::set<map_location>* remove_destinations) const
{
calculate_moves(get_info().units,res,srcdst,dstsrc,enemy,assume_full_movement,remove_destinations);
}
void ai_readonly_context::calculate_moves(const unit_map& units, std::map<map_location,paths>& res, move_map& srcdst,
void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_location,paths>& res, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement,
const std::set<map_location>* remove_destinations,
bool see_all
@ -473,7 +499,7 @@ void ai_readonly_context::calculate_moves(const unit_map& units, std::map<map_lo
}
void ai_readwrite_context::attack_enemy(const map_location u,
void readwrite_context_impl::attack_enemy(const map_location u,
const map_location target, int weapon, int def_weapon)
{
// Stop the user from issuing any commands while the unit is attacking
@ -536,16 +562,4 @@ void ai_readwrite_context::attack_enemy(const map_location u,
raise_enemy_attacked();
}
variant ai_readonly_context::get_value(const std::string& key) const
{
if(key == "map") {
return variant(new gamemap_callable(get_info().map));
}
return variant();
}
void ai_readonly_context::get_inputs(std::vector<game_logic::formula_input>* inputs) const
{
using game_logic::FORMULA_READ_ONLY;
inputs->push_back(game_logic::formula_input("map", FORMULA_READ_ONLY));
}
} //of namespace ai

View File

@ -24,7 +24,7 @@
class game_display;
class gamemap;
#include "ai_interface.hpp"
#include "ai_actions.hpp"
#include "game_info.hpp"
#include "../game_display.hpp"
#include "../gamestatus.hpp"
@ -36,24 +36,324 @@ class ai_move_result;
class ai_recruit_result;
class ai_stopunit_result;
class ai_readonly_context: public game_logic::formula_callable, public ai_interface {
namespace ai {
// recursion counter
class recursion_counter {
public:
/** A convenient typedef for the often used 'location' object. */
typedef map_location location;
recursion_counter(int counter)
: counter_(counter++)
{
if (counter > MAX_COUNTER_VALUE ) {
throw game::game_error("maximum recursion depth reached!");
}
}
/** The standard way in which a map of possible moves is recorded. */
typedef std::multimap<location,location> move_map;
int get_count() const{
return counter_;
}
static const int MAX_COUNTER_VALUE = 100;//max recursion depth
private:
int counter_;
};
/** The standard way in which a map of possible movement routes to location is recorded*/
typedef std::map<location,paths> moves_map;
// side context
class side_context;
class side_context{
public:
virtual side_number get_side() const = 0;
virtual void set_side(side_number side) = 0;
virtual ~side_context(){}
side_context() {}
virtual side_context& get_side_context() = 0;
virtual int get_recursion_count() const = 0;
};
class readonly_context;
class readonly_context : public virtual side_context {
public:
readonly_context(){}
virtual ~readonly_context(){}
virtual readonly_context& get_readonly_context() = 0;
virtual const team& current_team() const = 0;
virtual void diagnostic(const std::string& msg) = 0;
virtual void log_message(const std::string& msg) = 0;
virtual ai_attack_result_ptr check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon) = 0;
virtual ai_move_result_ptr check_move_action(const map_location& from, const map_location& to, bool remove_movement=true) = 0;
virtual ai_recruit_result_ptr check_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location) = 0;
virtual ai_stopunit_result_ptr check_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false) = 0;
virtual void calculate_possible_moves(std::map<map_location,paths>& possible_moves,
move_map& srcdst, move_map& dstsrc, bool enemy,
bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL) const = 0;
virtual void calculate_moves(const unit_map& units,
std::map<map_location,paths>& possible_moves, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL,
bool see_all=false) const = 0;
const virtual ai_game_info& get_info() const = 0;
virtual void raise_user_interact() const = 0;
};
class readwrite_context;
class readwrite_context : public virtual readonly_context {
public:
readwrite_context(){}
virtual ~readwrite_context(){}
virtual readwrite_context& get_readwrite_context() = 0;
virtual ai_attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon) = 0;
virtual ai_move_result_ptr execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true) = 0;
virtual ai_recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location) = 0;
virtual ai_stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false) = 0;
virtual team& current_team_w() = 0;
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon) = 0;
virtual map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves) = 0;
virtual map_location move_unit_partial(map_location from, map_location to, std::map<map_location,paths>& possible_moves) = 0;
virtual bool recruit(const std::string& unit_name, map_location loc=map_location()) = 0;
virtual void raise_unit_recruited() const = 0;
virtual void raise_unit_moved() const = 0;
virtual void raise_enemy_attacked() const = 0;
virtual ai_game_info& get_info_w() = 0;
};
//proxies
class side_context_proxy : public virtual side_context {
public:
side_context_proxy(side_context& target)
:target_(target.get_side_context())
{
}
virtual ~side_context_proxy(){}
virtual side_number get_side() const
{
return target_.get_side();
}
virtual void set_side(side_number side)
{
return target_.set_side(side);
}
virtual side_context& get_side_context()
{
return target_.get_side_context();
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
}
private:
side_context& target_;
};
class readonly_context_proxy : public virtual readonly_context, public virtual side_context_proxy {
public:
readonly_context_proxy(readonly_context &target)
: side_context_proxy(target.get_side_context()), target_(target.get_readonly_context())
{
}
virtual ~readonly_context_proxy() {}
virtual readonly_context& get_readonly_context()
{
return target_.get_readonly_context();
}
virtual const team& current_team() const{
return target_.current_team();
}
virtual void diagnostic(const std::string& msg){
target_.diagnostic(msg);
}
virtual void log_message(const std::string& msg){
target_.log_message(msg);
}
virtual ai_attack_result_ptr check_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon) {
return target_.check_attack_action(attacker_loc, defender_loc, attacker_weapon);
}
virtual ai_move_result_ptr check_move_action(const map_location &from, const map_location &to, bool remove_movement=true){
return target_.check_move_action(from, to, remove_movement);
}
virtual ai_recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where = map_location::null_location){
return target_.check_recruit_action(unit_name, where);
}
virtual ai_stopunit_result_ptr check_stopunit_action(const map_location &unit_location, bool remove_movement = true, bool remove_attacks = false){
return target_.check_stopunit_action(unit_location, remove_movement, remove_attacks);
}
virtual void calculate_possible_moves(std::map<map_location,paths>& possible_moves,
move_map& srcdst, move_map& dstsrc, bool enemy,
bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL) const{
target_.calculate_possible_moves(possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations);
}
virtual void calculate_moves(const unit_map& units,
std::map<map_location,paths>& possible_moves, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL,
bool see_all=false) const{
target_.calculate_moves(units, possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations, see_all);
}
const virtual ai_game_info& get_info() const{
return target_.get_info();
}
virtual void raise_user_interact() const{
target_.raise_user_interact();
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
}
private:
readonly_context& target_;
};
class readwrite_context_proxy : public virtual readwrite_context, public virtual readonly_context_proxy {
public:
readwrite_context_proxy(readwrite_context &target)
: side_context_proxy(target.get_side_context()), readonly_context_proxy(target.get_readonly_context()),target_(target.get_readwrite_context())
{
}
virtual readwrite_context& get_readwrite_context()
{
return target_.get_readwrite_context();
}
virtual ai_attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return target_.execute_attack_action(attacker_loc,defender_loc,attacker_weapon);
}
virtual ai_move_result_ptr execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true)
{
return target_.execute_move_action(from, to, remove_movement);
}
virtual ai_recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location){
return target_.execute_recruit_action(unit_name,where);
}
virtual ai_stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false){
return target_.execute_stopunit_action(unit_location,remove_movement,remove_attacks);
}
virtual team& current_team_w(){
return target_.current_team_w();
}
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon){
target_.attack_enemy(u, target, att_weapon, def_weapon);
}
virtual map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves){
return target_.move_unit(from, to, possible_moves);
}
virtual map_location move_unit_partial(map_location from, map_location to, std::map<map_location,paths>& possible_moves){
return target_.move_unit_partial(from, to, possible_moves);
}
virtual bool recruit(const std::string& unit_name, map_location loc=map_location()){
return target_.recruit(unit_name, loc);
}
virtual void raise_unit_recruited() const{
target_.raise_unit_recruited();
}
virtual void raise_unit_moved() const{
target_.raise_unit_moved();
}
virtual void raise_enemy_attacked() const{
target_.raise_enemy_attacked();
}
virtual ai_game_info& get_info_w() {
return target_.get_info_w();
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
}
private:
readwrite_context& target_;
};
//implementation
class side_context_impl : public side_context {
public:
side_context_impl(side_number side)
: side_(side), recursion_counter_(0)
{
}
virtual ~side_context_impl(){}
virtual side_number get_side() const
{
return side_;
}
virtual void set_side(side_number side)
{
side_ = side;
}
virtual side_context& get_side_context()
{
return *this;
}
virtual int get_recursion_count() const;
private:
side_number side_;
recursion_counter recursion_counter_;
};
//@todo: public game_logic::formula_callable
class readonly_context_impl : public virtual side_context_proxy, public readonly_context {
public:
/**
* The constructor.
*/
ai_readonly_context(unsigned int side, bool master) : ai_interface(side,master) {
add_ref(); //this class shouldn't be reference counted.
readonly_context_impl( side_context &context )
: side_context_proxy(context), recursion_counter_(context.get_recursion_count())
{
//add_ref(); //this class shouldn't be reference counted.
}
virtual ~readonly_context_impl() {}
/**
* Unwrap - this class is not a proxy, so return *this
*/
virtual readonly_context& get_readonly_context()
{
return *this;
}
virtual ~ai_readonly_context() {}
/** Return a reference to the 'team' object for the AI. */
const team& current_team() const { return get_info().teams[get_side()-1]; }
@ -76,7 +376,7 @@ public:
* @retval possible result: attacker and/or defender are invalid
* @retval possible result: attacker doesn't have the specified weapon
*/
std::auto_ptr<ai_attack_result> check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon);
ai_attack_result_ptr check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon);
/**
@ -89,7 +389,7 @@ public:
* @retval possible result: move is interrupted
* @retval possible result: move is impossible
*/
std::auto_ptr<ai_move_result> check_move_action(const map_location& from, const map_location& to, bool remove_movement=true);
ai_move_result_ptr check_move_action(const map_location& from, const map_location& to, bool remove_movement=true);
/**
@ -102,7 +402,7 @@ public:
* @retval possible_result: no free space on keep
* @retval possible_result: not enough gold
*/
std::auto_ptr<ai_recruit_result> check_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location);
ai_recruit_result_ptr check_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location);
/**
@ -114,7 +414,7 @@ public:
* @retval possible_result: something wrong
* @retval possible_result: nothing to do
*/
std::auto_ptr<ai_stopunit_result> check_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false);
ai_stopunit_result_ptr check_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false);
/**
@ -167,14 +467,22 @@ public:
*/
void raise_user_interact() const;
virtual void get_inputs(std::vector<game_logic::formula_input>* inputs) const;
virtual int get_recursion_count() const;
virtual variant get_value(const std::string& key) const;
private:
recursion_counter recursion_counter_;
};
class ai_readwrite_context : public ai_readonly_context {
class readwrite_context_impl : public virtual side_context_proxy, public virtual readonly_context_proxy, public readwrite_context {
public:
/**
* Unwrap - this class is not a proxy, so return *this
*/
virtual readwrite_context& get_readwrite_context()
{
return *this;
}
/**
@ -188,7 +496,7 @@ public:
* @retval possible result: attacker and/or defender are invalid
* @retval possible result: attacker doesn't have the specified weapon
*/
std::auto_ptr<ai_attack_result> execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon);
virtual ai_attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon);
/**
@ -201,7 +509,7 @@ public:
* @retval possible result: move is interrupted
* @retval possible result: move is impossible
*/
std::auto_ptr<ai_move_result> execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true);
virtual ai_move_result_ptr execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true);
/**
@ -214,7 +522,7 @@ public:
* @retval possible_result: no free space on keep
* @retval possible_result: not enough gold
*/
std::auto_ptr<ai_recruit_result> execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location);
virtual ai_recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location);
/**
@ -226,12 +534,11 @@ public:
* @retval possible_result: something wrong
* @retval possible_result: nothing to do
*/
std::auto_ptr<ai_stopunit_result> execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false);
virtual ai_stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false);
/** Return a reference to the 'team' object for the AI. */
team& current_team() { return get_info().teams[get_side()-1]; }
const team& current_team() const { return get_info().teams[get_side()-1]; }
virtual team& current_team_w() { return get_info_w().teams[get_side()-1]; }
/**
* This function should be called to attack an enemy.
@ -247,7 +554,7 @@ public:
* @param def_weapon The number of the weapon (0-based) which should be used
* by the defender. (It must be a valid weapon of the defender.)
*/
void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon);
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon);
/**
* This function should be called to move a unit.
@ -260,7 +567,7 @@ public:
* @param possible_moves The map of possible moves, as obtained from
* 'calculate_possible_moves'.
*/
map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves);
virtual map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves);
/**
* @deprecated
@ -289,16 +596,25 @@ public:
/**
* The constructor.
*/
ai_readwrite_context(unsigned int side, bool master) : ai_readonly_context(side,master){
readwrite_context_impl(readonly_context &context)
: side_context_proxy(context), readonly_context_proxy(context), recursion_counter_(context.get_recursion_count())
{
}
virtual ~ai_readwrite_context() {}
virtual ~readwrite_context_impl() {}
/**
* Functions to retrieve the 'info' object.
* Used by derived classes to discover all necessary game information.
*/
const virtual ai_game_info& get_info() const;
virtual ai_game_info& get_info();
virtual ai_game_info& get_info_w();
virtual int get_recursion_count() const;
private:
recursion_counter recursion_counter_;
};
} //end of namespace ai
#endif

View File

@ -572,7 +572,7 @@ public:
private:
variant execute(const formula_callable& variables) const {
variant attack = args()[0]->evaluate(variables);
ai::attack_analysis* analysis = convert_variant<ai::attack_analysis>(attack);
ai_default::attack_analysis* analysis = convert_variant<ai_default::attack_analysis>(attack);
unit_map units_with_moves(ai_.get_info().units);
typedef std::pair<map_location, map_location> mv;
foreach (const mv &m, analysis->movements) {
@ -1073,8 +1073,8 @@ private:
}
const map_location& loc = convert_variant<location_callable>(res)->loc();
const formula_ai::move_map& srcdst = ai_.srcdst();
typedef formula_ai::move_map::const_iterator Itor;
const ai::move_map& srcdst = ai_.srcdst();
typedef ai::move_map::const_iterator Itor;
std::pair<Itor,Itor> range = srcdst.equal_range(loc);
for(Itor i = range.first; i != range.second; ++i) {
@ -1096,7 +1096,7 @@ private:
variant execute(const formula_callable& variables) const {
std::vector<variant> vars;
variant dstsrc_var = args()[0]->evaluate(variables);
const ai::move_map& dstsrc = convert_variant<move_map_callable>(dstsrc_var)->dstsrc();
const ai_default::move_map& dstsrc = convert_variant<move_map_callable>(dstsrc_var)->dstsrc();
std::pair<ai::move_map::const_iterator,ai::move_map::const_iterator> range =
dstsrc.equal_range(convert_variant<location_callable>(args()[1]->evaluate(variables))->loc());
while(range.first != range.second) {
@ -1517,6 +1517,10 @@ std::string formula_ai::describe_self(){
return "[formula_ai]";
}
int formula_ai::get_recursion_count() const{
return recursion_counter_.get_count();
}
namespace game_logic {
expression_ptr ai_function_symbol_table::create_function(const std::string &fn,
@ -1596,8 +1600,12 @@ expression_ptr ai_function_symbol_table::create_function(const std::string &fn,
}
formula_ai::formula_ai(int side, bool master) :
ai(side,master),
formula_ai::formula_ai(ai::readwrite_context &context) :
side_context_proxy(context),
readonly_context_proxy(context),
readwrite_context_proxy(context),
ai_default(context),
recursion_counter_(context.get_recursion_count()),
recruit_formula_(),
move_formula_(),
outcome_positions_(),
@ -1699,7 +1707,7 @@ formula_ptr formula_ai::create_optional_formula(const std::string& formula_strin
void formula_ai::new_turn()
{
move_maps_valid_ = false;
ai::new_turn();
ai_default::new_turn();
}
void formula_ai::play_turn()
@ -1892,9 +1900,9 @@ void formula_ai::prepare_move() const
bool formula_ai::make_action(game_logic::const_formula_ptr formula_, const game_logic::formula_callable& variables)
{
if(!formula_) {
if(get_master()) {
if(get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE) {
LOG_AI << "Falling back to default AI.\n";
util::scoped_ptr< ai_interface > fallback( ai_manager::create_transient_ai(ai_manager::AI_TYPE_DEFAULT, get_side(),false));
util::scoped_ptr< ai_interface > fallback( ai_manager::create_transient_ai(ai_manager::AI_TYPE_DEFAULT, this));
if (fallback != NULL){
fallback->play_turn();
}
@ -2058,7 +2066,7 @@ bool formula_ai::execute_variant(const variant& var, bool commandline)
const move_callable* move = try_convert_variant<move_callable>(*i);
const move_partial_callable* move_partial = try_convert_variant<move_partial_callable>(*i);
const attack_callable* attack = try_convert_variant<attack_callable>(*i);
const ai::attack_analysis* attack_analysis = try_convert_variant<ai::attack_analysis>(*i);
const ai_default::attack_analysis* attack_analysis = try_convert_variant<ai_default::attack_analysis>(*i);
const recruit_callable* recruit_command = try_convert_variant<recruit_callable>(*i);
const set_var_callable* set_var_command = try_convert_variant<set_var_callable>(*i);
const set_unit_var_callable* set_unit_var_command = try_convert_variant<set_unit_var_callable>(*i);
@ -2210,8 +2218,7 @@ bool formula_ai::execute_variant(const variant& var, bool commandline)
} else if(i->is_string() && (i->as_string() == "end_turn" || i->as_string() == "end" ) ) {
return false;
} else if(fallback_command) {
if (get_master())
{
if(get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE) {
if(fallback_command->key() == "human")
{
//we want give control of the side to human for the rest of this turn
@ -2219,7 +2226,7 @@ bool formula_ai::execute_variant(const variant& var, bool commandline)
} else
{
LOG_AI << "Explicit fallback to: " << fallback_command->key() << std::endl;
util::scoped_ptr< ai_interface > fallback ( ai_manager::create_transient_ai(fallback_command->key(), get_side(),false));
util::scoped_ptr< ai_interface > fallback ( ai_manager::create_transient_ai(fallback_command->key(), this));
if(fallback != NULL) {
fallback->play_turn();
}
@ -2494,7 +2501,7 @@ variant formula_ai::get_value(const std::string& key) const
return villages_from_set(get_info().map.villages(), &current_team().villages());
}
return ai_readonly_context::get_value(key);
return ai_default::get_value(key);
}
void formula_ai::get_inputs(std::vector<formula_input>* inputs) const
@ -2524,7 +2531,7 @@ void formula_ai::get_inputs(std::vector<formula_input>* inputs) const
inputs->push_back(game_logic::formula_input("villages_of_side", FORMULA_READ_ONLY));
inputs->push_back(game_logic::formula_input("enemy_and_unowned_villages", FORMULA_READ_ONLY));
ai_readonly_context::get_inputs(inputs);
ai_default::get_inputs(inputs);
}
variant formula_ai::get_keeps() const

View File

@ -63,17 +63,15 @@ private:
}
class formula_ai : public ai {
class formula_ai : public ai_default, public virtual ai::readwrite_context_proxy {
public:
explicit formula_ai(int side, bool master);
explicit formula_ai(ai::readwrite_context &context);
virtual ~formula_ai() {};
virtual void play_turn();
virtual void new_turn();
virtual std::string describe_self();
using ai_readwrite_context::get_info;
using ai_readwrite_context::current_team;
using ai_readonly_context::move_map;
using ai_default::move_map;
const move_map& srcdst() const { if(!move_maps_valid_) { prepare_move(); } return srcdst_; }
@ -101,13 +99,15 @@ public:
variant get_keeps() const;
int get_recursion_count() const;
const variant& get_keeps_cache() const { return keeps_cache_; }
// Check if given unit can reach another unit
bool can_reach_unit(unit_map::const_unit_iterator unit_A,
unit_map::const_unit_iterator unit_B) const;
const std::map<location,paths>& get_possible_moves() const { prepare_move(); return possible_moves_; }
const std::map<map_location,paths>& get_possible_moves() const { prepare_move(); return possible_moves_; }
void handle_exception(game_logic::formula_error& e) const;
void handle_exception(game_logic::formula_error& e, const std::string& failed_operation) const;
@ -130,6 +130,7 @@ public:
private:
ai::recursion_counter recursion_counter_;
void display_message(const std::string& msg) const;
bool do_recruitment();
bool make_action(game_logic::const_formula_ptr formula_, const game_logic::formula_callable& variables);
@ -141,7 +142,7 @@ private:
std::vector<variant> outcome_positions_;
mutable std::map<location,paths> possible_moves_;
mutable std::map<map_location,paths> possible_moves_;
void prepare_move() const;
@ -155,7 +156,7 @@ private:
game_logic::ai_function_symbol_table function_table;
game_logic::candidate_action_manager candidate_action_manager_;
friend class ai;
friend class ai_default;
};
#endif

View File

@ -31,6 +31,17 @@ class gamemap;
* that an AI might need access to, in order to make and implement its
* decisions.
*/
namespace ai {
typedef unsigned int side_number;
/** The standard way in which a map of possible moves is recorded. */
typedef std::multimap<map_location,map_location> move_map;
/** The standard way in which a map of possible movement routes to location is recorded*/
typedef std::map<map_location,paths> moves_map;
} //of namespace ai
class ai_game_info {
public:

View File

@ -161,7 +161,7 @@ public:
{ info_.current_player = player; }
size_t average_recruit_price();
float num_pos_recruits_to_force()
float num_pos_recruits_to_force() const
{ return info_.number_of_possible_recruits_to_force_recruit; }
const std::set<std::string>& recruits() const
{ return info_.can_recruit; }