mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-26 18:59:45 +00:00
AI Refactoring - hierarchial AI contexts,
...a step needed for easier writing of composite ai components.
This commit is contained in:
parent
901ad63e5a
commit
4d1ea0035a
205
src/ai/ai.cpp
205
src/ai/ai.cpp
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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_;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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];
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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(), ¤t_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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user