ai/manager.cpp

Go to the documentation of this file.
00001 /* $Id: manager.cpp 53075 2012-02-16 05:45:21Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2009 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /**
00017  * Managing the AI lifecycle and interface for the rest of Wesnoth
00018  * @file
00019  */
00020 
00021 #include "composite/ai.hpp"
00022 #include "configuration.hpp"
00023 #include "contexts.hpp"
00024 #include "default/ai.hpp"
00025 #include "manager.hpp"
00026 #include "formula/ai.hpp"
00027 #include "registry.hpp"
00028 #include "../game_events.hpp"
00029 #include "../foreach.hpp"
00030 #include "../log.hpp"
00031 #include "../serialization/string_utils.hpp"
00032 #include "composite/component.hpp"
00033 
00034 #include <map>
00035 #include <stack>
00036 #include <vector>
00037 #include "composite/engine.hpp"
00038 
00039 namespace ai {
00040 
00041 const std::string manager::AI_TYPE_COMPOSITE_AI = "composite_ai";
00042 const std::string manager::AI_TYPE_SAMPLE_AI = "sample_ai";
00043 const std::string manager::AI_TYPE_IDLE_AI = "idle_ai";
00044 const std::string manager::AI_TYPE_FORMULA_AI = "formula_ai";
00045 const std::string manager::AI_TYPE_DEFAULT = "default";
00046 
00047 
00048 static lg::log_domain log_ai_manager("ai/manager");
00049 #define DBG_AI_MANAGER LOG_STREAM(debug, log_ai_manager)
00050 #define LOG_AI_MANAGER LOG_STREAM(info, log_ai_manager)
00051 #define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
00052 
00053 static lg::log_domain log_ai_mod("ai/mod");
00054 #define DBG_AI_MOD LOG_STREAM(debug, log_ai_mod)
00055 #define LOG_AI_MOD LOG_STREAM(info, log_ai_mod)
00056 #define WRN_AI_MOD LOG_STREAM(warn, log_ai_mod)
00057 #define ERR_AI_MOD LOG_STREAM(err, log_ai_mod)
00058 
00059 holder::holder( side_number side, const config &cfg )
00060     : ai_(), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), default_ai_context_(NULL), side_(side), cfg_(cfg)
00061 {
00062     DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder" << std::endl;
00063 }
00064 
00065 
00066 void holder::init( side_number side )
00067 {
00068     if (side_context_ == NULL) {
00069         side_context_ = new side_context_impl(side,cfg_);
00070     } else {
00071         side_context_->set_side(side);
00072     }
00073     if (readonly_context_ == NULL){
00074         readonly_context_ = new readonly_context_impl(*side_context_,cfg_);
00075         readonly_context_->on_readonly_context_create();
00076     }
00077     if (readwrite_context_ == NULL){
00078         readwrite_context_ = new readwrite_context_impl(*readonly_context_,cfg_);
00079     }
00080     if (default_ai_context_ == NULL){
00081         default_ai_context_ = new default_ai_context_impl(*readwrite_context_,cfg_);
00082     }
00083     if (!this->ai_){
00084         ai_ = boost::shared_ptr<ai_composite>(new ai_composite(*default_ai_context_,cfg_));
00085     }
00086 
00087     if (this->ai_) {
00088         ai_->on_create();
00089         foreach (config &mod_ai, cfg_.child_range("modify_ai")) {
00090             if (!mod_ai.has_attribute("side")) {
00091                 mod_ai["side"] = side;
00092             }
00093             modify_ai(mod_ai);
00094         }
00095         cfg_.clear_children("modify_ai");
00096 
00097         std::vector<engine_ptr> engines = ai_->get_engines();
00098         for (std::vector<engine_ptr>::iterator it = engines.begin(); it != engines.end(); ++it)
00099         {
00100             (*it)->set_ai_context(&(ai_->get_ai_context()));
00101         }
00102 
00103     } else {
00104         ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!" << std::endl;
00105     }
00106 
00107 }
00108 
00109 holder::~holder()
00110 {
00111     if (this->ai_) {
00112         LOG_AI_MANAGER << describe_ai() << "Managed AI will be deleted" << std::endl;
00113     }
00114     delete this->default_ai_context_;
00115     delete this->readwrite_context_;
00116     delete this->readonly_context_;
00117     delete this->side_context_;
00118 }
00119 
00120 
00121 interface& holder::get_ai_ref()
00122 {
00123     if (!this->ai_) {
00124         this->init(this->side_);
00125     }
00126     assert(this->ai_);
00127 
00128     return *this->ai_;
00129 }
00130 
00131 
00132 void holder::modify_ai_config_old( const config::const_child_itors &ai_parameters)
00133 {
00134     // only handle aspects
00135     // transform ai_parameters to new-style config
00136 
00137     config cfg;
00138     configuration::upgrade_aspect_configs_from_1_07_02_to_1_07_03(this->side_,ai_parameters,cfg);
00139     //at this point we have a single config which contains [aspect][facet] tags
00140     DBG_AI_MANAGER << "after transforming [modify_side][ai] into new syntax, config contains:"<< std::endl << cfg << std::endl;
00141 
00142     if (this->readonly_context_ == NULL) {
00143         // if not initialized, append that config to the bottom of base cfg
00144         // then, merge aspects with the same id
00145         cfg_.merge_with(cfg);
00146         cfg_.merge_children_by_attribute("aspect","id");
00147     } else {
00148         // else run 'add_facet' command on each [aspect][facet]
00149         foreach (const config &cfg_a, cfg.child_range("aspect")) {
00150             foreach (const config &cfg_f, cfg_a.child_range("facet")) {
00151                 readonly_context_->add_facet(cfg_a["id"],cfg_f);
00152             }
00153         }
00154     }
00155 }
00156 
00157 
00158 void holder::modify_ai(const config &cfg)
00159 {
00160     if (!this->ai_) {
00161         // if not initialized, initialize now.
00162         get_ai_ref();
00163     }
00164     const std::string &act = cfg["action"];
00165     LOG_AI_MOD << "side "<< side_ << "        [modify_ai] "<<act<<" \""<<cfg["path"]<<"\""<<std::endl;
00166     DBG_AI_MOD << std::endl << cfg << std::endl;
00167     DBG_AI_MOD << "side "<< side_ << " before [modify_ai]"<<std::endl << to_config() << std::endl;
00168     bool res = false;
00169     if (act == "add") {
00170         res = component_manager::add_component(&*this->ai_,cfg["path"],cfg);
00171     } else if (act == "change") {
00172         res = component_manager::change_component(&*this->ai_,cfg["path"],cfg);
00173     } else if (act == "delete") {
00174         res = component_manager::delete_component(&*this->ai_,cfg["path"]);
00175     } else if (act == "try_delete") {
00176         res = component_manager::delete_component(&*this->ai_,cfg["path"]);
00177         if (!res) {
00178             LOG_AI_MOD << "[modify_ai] "<<act<<" failed, ignoring because it's a try_delete"<< std::endl;
00179             res = true;
00180         }
00181     } else {
00182         ERR_AI_MOD << "modify_ai tag has invalid 'action' attribute " << act << std::endl;
00183     }
00184     DBG_AI_MOD << "side "<< side_ << "  after [modify_ai]"<<act<<std::endl << to_config() << std::endl;
00185     if (!res) {
00186         LOG_AI_MOD << "[modify_ai] "<<act<<" failed"<< std::endl;
00187     } else {
00188         LOG_AI_MOD << "[modify_ai] "<<act<<" success"<< std::endl;
00189     }
00190 
00191 }
00192 
00193 config holder::to_config() const
00194 {
00195     if (!this->ai_) {
00196         return cfg_;
00197     } else {
00198         config cfg = ai_->to_config();
00199         cfg["version"] = "10703";
00200         if (this->side_context_!=NULL) {
00201             cfg.merge_with(this->side_context_->to_side_context_config());
00202         }
00203         if (this->readonly_context_!=NULL) {
00204             cfg.merge_with(this->readonly_context_->to_readonly_context_config());
00205         }
00206         if (this->readwrite_context_!=NULL) {
00207             cfg.merge_with(this->readwrite_context_->to_readwrite_context_config());
00208         }
00209         if (this->default_ai_context_!=NULL) {
00210             cfg.merge_with(this->default_ai_context_->to_default_ai_context_config());
00211         }
00212 
00213         return cfg;
00214     }
00215 }
00216 
00217 
00218 
00219 const std::string holder::describe_ai()
00220 {
00221     std::string sidestr = lexical_cast<std::string>(this->side_);
00222 
00223     if (this->ai_!=NULL) {
00224         return this->ai_->describe_self()+std::string(" for side ")+sidestr+std::string(" : ");
00225     } else {
00226         return std::string("not initialized ai with id=[")+cfg_["id"]+std::string("] for side ")+sidestr+std::string(" : ");
00227     }
00228 }
00229 
00230 
00231 const std::string holder::get_ai_overview()
00232 {
00233     if (!this->ai_) {
00234         get_ai_ref();
00235     }
00236     std::stringstream s;
00237     s << "aggression:  " << this->ai_->get_aggression() << std::endl;
00238     s << "attack_depth:  " << this->ai_->get_attack_depth() << std::endl;
00239     s << "caution:  " << this->ai_->get_caution() << std::endl;
00240     s << "grouping:  " << this->ai_->get_grouping() << std::endl;
00241     s << "leader_aggression:  " << this->ai_->get_leader_aggression() << std::endl;
00242     s << "leader_value:  " << this->ai_->get_leader_value() << std::endl;
00243     s << "number_of_possible_recruits_to_force_recruit:  " << this->ai_->get_number_of_possible_recruits_to_force_recruit() << std::endl;
00244     s << "passive_leader:  " << this->ai_->get_passive_leader() << std::endl;
00245     s << "passive_leader_shares_keep:  " << this->ai_->get_passive_leader_shares_keep() << std::endl;
00246     s << "recruitment_ignore_bad_combat:  " << this->ai_->get_recruitment_ignore_bad_combat() << std::endl;
00247     s << "recruitment_ignore_bad_movement:  " << this->ai_->get_recruitment_ignore_bad_movement() << std::endl;
00248 //  s << "recruitment_pattern:  ";
00249 //  for(std::vector<std::string>::const_iterator i =  this->ai_->get_recruitment_pattern().begin(); i !=  this->ai_->get_recruitment_pattern().end(); ++i) {
00250 //      if(i != this->ai_->get_recruitment_pattern().begin())
00251 //          s << ",";
00252 //
00253 //      s << *i;
00254 //  }
00255 //  s << std::endl;
00256     s << "scout_village_targeting:  " << this->ai_->get_scout_village_targeting() << std::endl;
00257     s << "simple_targeting:  " << this->ai_->get_simple_targeting() << std::endl;
00258     s << "support_villages:  " << this->ai_->get_support_villages() << std::endl;
00259     s << "village_value:  " << this->ai_->get_village_value() << std::endl;
00260     s << "villages_per_scout:  " << this->ai_->get_villages_per_scout() << std::endl;
00261     return s.str();
00262 }
00263 
00264 
00265 
00266 const std::string holder::get_ai_structure()
00267 {
00268     if (!this->ai_) {
00269         get_ai_ref();
00270     }
00271     return component_manager::print_component_tree(&*this->ai_,"");
00272 }
00273 
00274 
00275 const std::string holder::get_ai_identifier() const
00276 {
00277     return cfg_["id"];
00278 }
00279 
00280 // =======================================================================
00281 // LIFECYCLE
00282 // =======================================================================
00283 
00284 
00285 manager::AI_map_of_stacks manager::ai_map_;
00286 game_info *manager::ai_info_;
00287 events::generic_event manager::user_interact_("ai_user_interact");
00288 events::generic_event manager::sync_network_("ai_sync_network");
00289 events::generic_event manager::gamestate_changed_("ai_gamestate_changed");
00290 events::generic_event manager::turn_started_("ai_turn_started");
00291 events::generic_event manager::recruit_list_changed_("ai_recruit_list_changed");
00292 events::generic_event manager::map_changed_("ai_map_changed");
00293 int manager::last_interact_ = 0;
00294 int manager::num_interact_ = 0;
00295 
00296 
00297 void manager::set_ai_info(const game_info& i)
00298 {
00299     if (ai_info_!=NULL){
00300         clear_ai_info();
00301     }
00302     ai_info_ = new game_info(i);
00303     registry::init();
00304 }
00305 
00306 
00307 void manager::clear_ai_info(){
00308     delete ai_info_;
00309     ai_info_ = NULL;
00310 }
00311 
00312 
00313 void manager::add_observer( events::observer* event_observer){
00314     user_interact_.attach_handler(event_observer);
00315     sync_network_.attach_handler(event_observer);
00316     turn_started_.attach_handler(event_observer);
00317     gamestate_changed_.attach_handler(event_observer);
00318 }
00319 
00320 
00321 void manager::remove_observer(events::observer* event_observer){
00322     user_interact_.detach_handler(event_observer);
00323     sync_network_.detach_handler(event_observer);
00324     turn_started_.detach_handler(event_observer);
00325     gamestate_changed_.detach_handler(event_observer);
00326 }
00327 
00328 
00329 void manager::add_gamestate_observer( events::observer* event_observer){
00330     gamestate_changed_.attach_handler(event_observer);
00331     turn_started_.attach_handler(event_observer);
00332     map_changed_.attach_handler(event_observer);
00333 }
00334 
00335 
00336 void manager::remove_gamestate_observer(events::observer* event_observer){
00337     gamestate_changed_.detach_handler(event_observer);
00338     turn_started_.detach_handler(event_observer);
00339     map_changed_.detach_handler(event_observer);
00340 }
00341 
00342 
00343 
00344 void manager::add_map_changed_observer( events::observer* event_observer )
00345 {
00346     map_changed_.attach_handler(event_observer);
00347 }
00348 
00349 
00350 void manager::add_recruit_list_changed_observer( events::observer* event_observer )
00351 {
00352     recruit_list_changed_.attach_handler(event_observer);
00353 }
00354 
00355 
00356 void manager::add_turn_started_observer( events::observer* event_observer )
00357 {
00358     turn_started_.attach_handler(event_observer);
00359 }
00360 
00361 
00362 void manager::remove_recruit_list_changed_observer( events::observer* event_observer )
00363 {
00364     recruit_list_changed_.detach_handler(event_observer);
00365 }
00366 
00367 
00368 void manager::remove_map_changed_observer( events::observer* event_observer )
00369 {
00370     map_changed_.detach_handler(event_observer);
00371 }
00372 
00373 
00374 void manager::remove_turn_started_observer( events::observer* event_observer )
00375 {
00376     turn_started_.detach_handler(event_observer);
00377 }
00378 
00379 void manager::raise_user_interact() {
00380         const int interact_time = 30;
00381         const int time_since_interact = SDL_GetTicks() - last_interact_;
00382         if(time_since_interact < interact_time) {
00383                 return;
00384         }
00385 
00386     ++num_interact_;
00387         user_interact_.notify_observers();
00388 
00389         last_interact_ = SDL_GetTicks();
00390 
00391 }
00392 
00393 void manager::raise_sync_network() {
00394     sync_network_.notify_observers();
00395 }
00396 
00397 
00398 void manager::raise_gamestate_changed() {
00399     gamestate_changed_.notify_observers();
00400 }
00401 
00402 
00403 void manager::raise_turn_started() {
00404     turn_started_.notify_observers();
00405 }
00406 
00407 
00408 void manager::raise_recruit_list_changed() {
00409     recruit_list_changed_.notify_observers();
00410 }
00411 
00412 
00413 void manager::raise_map_changed() {
00414     map_changed_.notify_observers();
00415 }
00416 
00417 
00418 // =======================================================================
00419 // EVALUATION
00420 // =======================================================================
00421 
00422 const std::string manager::evaluate_command( side_number side, const std::string& str )
00423 {
00424     //insert new command into history
00425     history_.push_back(command_history_item(history_item_counter_++,str));
00426 
00427     //prune history - erase 1/2 of it if it grows too large
00428     if (history_.size()>MAX_HISTORY_SIZE){
00429         history_.erase(history_.begin(),history_.begin()+MAX_HISTORY_SIZE/2);
00430         LOG_AI_MANAGER << "AI MANAGER: pruned history" << std::endl;
00431     }
00432 
00433     if (!should_intercept(str)){
00434         interface& ai = get_active_ai_for_side(side);
00435         raise_gamestate_changed();
00436         return ai.evaluate(str);
00437     }
00438 
00439     return internal_evaluate_command(side,str);
00440 }
00441 
00442 
00443 bool manager::should_intercept( const std::string& str )
00444 {
00445     if (str.length()<1) {
00446         return false;
00447     }
00448     if (str.at(0)=='!'){
00449         return true;
00450     }
00451     if (str.at(0)=='?'){
00452         return true;
00453     }
00454     return false;
00455 
00456 }
00457 
00458 std::deque< command_history_item > manager::history_;
00459 long manager::history_item_counter_ = 1;
00460 
00461 //this is stub code to allow testing of basic 'history', 'repeat-last-command', 'add/remove/replace ai' capabilities.
00462 //yes, it doesn't look nice. but it is usable.
00463 //to be refactored at earliest opportunity
00464 ///@todo 1.9 extract to separate class which will use fai or lua parser
00465 const std::string manager::internal_evaluate_command( side_number side, const std::string& str ){
00466     const int MAX_HISTORY_VISIBLE = 30;
00467 
00468     //repeat last command
00469     if (str=="!") {
00470             //this command should not be recorded in history
00471             if (!history_.empty()){
00472                 history_.pop_back();
00473                 history_item_counter_--;
00474             }
00475 
00476             if (history_.empty()){
00477                 return "AI MANAGER: empty history";
00478             }
00479             return evaluate_command(side, history_.back().get_command());//no infinite loop since '!' commands are not present in history
00480     };
00481     //show last command
00482     if (str=="?") {
00483         //this command should not be recorded in history
00484         if (!history_.empty()){
00485             history_.pop_back();
00486             history_item_counter_--;
00487         }
00488 
00489         if (history_.empty()){
00490             return "AI MANAGER: History is empty";
00491         }
00492 
00493         int n = std::min<int>( MAX_HISTORY_VISIBLE, history_.size() );
00494         std::stringstream strstream;
00495         strstream << "AI MANAGER: History - last "<< n <<" commands:\n";
00496         std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
00497 
00498         for (int cmd_id=n; cmd_id>0; --cmd_id){
00499             strstream << j->get_number() << "    :" << j->get_command() << '\n';
00500             ++j;//this is *reverse* iterator
00501         }
00502 
00503         return strstream.str();
00504     };
00505 
00506 
00507     std::vector< std::string > cmd = utils::parenthetical_split(str, ' ',"'","'");
00508 
00509     if (cmd.size()==3){
00510         //!add_ai side file
00511         if (cmd.at(0)=="!add_ai"){
00512             side_number side = lexical_cast<side_number>(cmd.at(1));
00513             std::string file = cmd.at(2);
00514             if (add_ai_for_side_from_file(side,file,false)){
00515                 return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
00516             } else {
00517                 return std::string("AI MANAGER: failed attempt to add AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
00518             }
00519         }
00520         //!replace_ai side file
00521         if (cmd.at(0)=="!replace_ai"){
00522             side_number side = lexical_cast<side_number>(cmd.at(1));
00523             std::string file = cmd.at(2);
00524             if (add_ai_for_side_from_file(side,file,true)){
00525                     return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
00526             } else {
00527                     return std::string("AI MANAGER: failed attempt to add AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
00528             }
00529         }
00530 
00531     } else if (cmd.size()==2){
00532         //!remove_ai side
00533         if (cmd.at(0)=="!remove_ai"){
00534             side_number side = lexical_cast<side_number>(cmd.at(1));
00535             remove_ai_for_side(side);
00536             return std::string("AI MANAGER: made an attempt to remove AI for side ")+lexical_cast<std::string>(side);
00537         }
00538         if (cmd.at(0)=="!"){
00539             //this command should not be recorded in history
00540             if (!history_.empty()){
00541                 history_.pop_back();
00542                 history_item_counter_--;
00543             }
00544 
00545             int command = lexical_cast<int>(cmd.at(1));
00546             std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
00547             //yes, the iterator could be precisely positioned (since command numbers go 1,2,3,4,..). will do it later.
00548             while ( (j!=history_.rend()) && (j->get_number()!=command) ){
00549                 ++j;// this is *reverse* iterator
00550             }
00551             if (j!=history_.rend()){
00552                 return evaluate_command(side,j->get_command());//no infinite loop since '!' commands are not present in history
00553             }
00554             return "AI MANAGER: no command with requested number found";
00555         }
00556     } else if (cmd.size()==1){
00557         if (cmd.at(0)=="!help") {
00558             return
00559                 "known commands:\n"
00560                 "!    - repeat last command (? and ! do not count)\n"
00561                 "! NUMBER    - repeat numbered command\n"
00562                 "?    - show a history list\n"
00563                 "!add_ai TEAM FILE    - add a AI to side (0 - command AI, N - AI for side #N) from file\n"
00564                 "!remove_ai TEAM    - remove AI from side (0 - command AI, N - AI for side #N)\n"
00565                 "!replace_ai TEAM FILE    - replace AI of side (0 - command AI, N - AI for side #N) from file\n"
00566                 "!help    - show this help message";
00567         }
00568     }
00569 
00570 
00571     return "AI MANAGER: nothing to do";
00572 }
00573 
00574 // =======================================================================
00575 // ADD, CREATE AIs, OR LIST AI TYPES
00576 // =======================================================================
00577 
00578 ///@todo 1.9 add error reporting
00579 bool manager::add_ai_for_side_from_file( side_number side, const std::string& file, bool replace )
00580 {
00581     config cfg;
00582     if (!configuration::get_side_config_from_file(file,cfg)){
00583         ERR_AI_MANAGER << " unable to read [SIDE] config for side "<< side << "from file [" << file <<"]"<< std::endl;
00584         return false;
00585     }
00586     return add_ai_for_side_from_config(side,cfg,replace);
00587 }
00588 
00589 
00590 bool manager::add_ai_for_side_from_config( side_number side, const config& cfg, bool replace ){
00591     config parsed_cfg;
00592     configuration::parse_side_config(side, cfg, parsed_cfg);
00593 
00594     if (replace) {
00595         remove_ai_for_side(side);
00596     }
00597 
00598     holder new_holder(side,parsed_cfg);
00599     std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
00600     ai_stack_for_specific_side.push(new_holder);
00601     return true;
00602 }
00603 
00604 
00605 ///@todo 1.9 add error reporting
00606 bool manager::add_ai_for_side( side_number side, const std::string& ai_algorithm_type, bool replace )
00607 {
00608     if (replace) {
00609         remove_ai_for_side (side);
00610     }
00611     config cfg;
00612     cfg["ai_algorithm"] = ai_algorithm_type;
00613     holder new_holder(side,cfg);
00614     std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
00615     ai_stack_for_specific_side.push(new_holder);
00616     return true;
00617 }
00618 
00619 
00620 ai_ptr manager::create_transient_ai(const std::string &ai_algorithm_type, const config &cfg, ai_context *ai_context )
00621 {
00622     assert(ai_context!=NULL);
00623 
00624     //to add your own ai, register it in registry,cpp
00625     ai_factory::factory_map::iterator aii = ai_factory::get_list().find(ai_algorithm_type);
00626     if (aii == ai_factory::get_list().end()){
00627         aii = ai_factory::get_list().find("");
00628         if (aii == ai_factory::get_list().end()){
00629             throw game::game_error("no default ai set!");
00630         }
00631     }
00632     LOG_AI_MANAGER << "Creating new AI of type [" << ai_algorithm_type << "]"<< std::endl;
00633     ai_ptr new_ai = aii->second->get_new_instance(*ai_context,cfg);
00634     return new_ai;
00635 }
00636 
00637 
00638 // =======================================================================
00639 // REMOVE
00640 // =======================================================================
00641 
00642 void manager::remove_ai_for_side( side_number side )
00643 {
00644     std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
00645     if (!ai_stack_for_specific_side.empty()){
00646         ai_stack_for_specific_side.pop();
00647     }
00648 }
00649 
00650 
00651 void manager::remove_all_ais_for_side( side_number side )
00652 {
00653     std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
00654 
00655     //clear the stack. std::stack doesn't have a '.clear()' method to do it
00656     while (!ai_stack_for_specific_side.empty()){
00657             ai_stack_for_specific_side.pop();
00658     }
00659 }
00660 
00661 
00662 void manager::clear_ais()
00663 {
00664     ai_map_.clear();
00665 }
00666 
00667 // =======================================================================
00668 // Work with active AI parameters
00669 // =======================================================================
00670 
00671 void manager::modify_active_ai_config_old_for_side ( side_number side, const config::const_child_itors &ai_parameters )
00672 {
00673     get_active_ai_holder_for_side(side).modify_ai_config_old(ai_parameters);
00674 }
00675 
00676 
00677 void manager::modify_active_ai_for_side ( side_number side, const config &cfg )
00678 {
00679     if (ai_info_==NULL) {
00680         //replay ?
00681         return;
00682     }
00683     get_active_ai_holder_for_side(side).modify_ai(cfg);
00684 }
00685 
00686 
00687 std::string manager::get_active_ai_overview_for_side( side_number side)
00688 {
00689     return get_active_ai_holder_for_side(side).get_ai_overview();
00690 }
00691 
00692 
00693 std::string manager::get_active_ai_structure_for_side( side_number side)
00694 {
00695     return get_active_ai_holder_for_side(side).get_ai_structure();
00696 }
00697 
00698 
00699 std::string manager::get_active_ai_identifier_for_side( side_number side )
00700 {
00701     return get_active_ai_holder_for_side(side).get_ai_identifier();
00702 }
00703 
00704 
00705 config manager::to_config( side_number side )
00706 {
00707     return get_active_ai_holder_for_side(side).to_config();
00708 }
00709 
00710 
00711 game_info& manager::get_active_ai_info_for_side( side_number /*side*/ )
00712 {
00713     return *ai_info_;
00714 }
00715 
00716 
00717 game_info& manager::get_ai_info()
00718 {
00719     return *ai_info_;
00720 }
00721 
00722 
00723 // =======================================================================
00724 // PROXY
00725 // =======================================================================
00726 
00727 void manager::play_turn( side_number side ){
00728     last_interact_ = 0;
00729     num_interact_ = 0;
00730     const int turn_start_time = SDL_GetTicks();
00731     /*hack. @todo 1.9 rework via extended event system*/
00732     get_ai_info().recent_attacks.clear();
00733     interface& ai_obj = get_active_ai_for_side(side);
00734     game_events::fire("ai turn");
00735     raise_turn_started();
00736     ai_obj.new_turn();
00737     ai_obj.play_turn();
00738     const int turn_end_time= SDL_GetTicks();
00739     DBG_AI_MANAGER << "side " << side << ": number of user interactions: "<<num_interact_<<std::endl;
00740     DBG_AI_MANAGER << "side " << side << ": total turn time: "<<turn_end_time - turn_start_time << " ms "<< std::endl;
00741 }
00742 
00743 
00744 // =======================================================================
00745 // PRIVATE
00746 // =======================================================================
00747 // =======================================================================
00748 // AI STACKS
00749 // =======================================================================
00750 std::stack<holder>& manager::get_or_create_ai_stack_for_side( side_number side )
00751 {
00752     AI_map_of_stacks::iterator iter = ai_map_.find(side);
00753     if (iter!=ai_map_.end()){
00754         return iter->second;
00755     }
00756     return ai_map_.insert(std::make_pair(side, std::stack<holder>())).first->second;
00757 }
00758 
00759 // =======================================================================
00760 // AI HOLDERS
00761 // =======================================================================
00762 holder& manager::get_active_ai_holder_for_side( side_number side )
00763 {
00764     std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
00765 
00766     if (!ai_stack_for_specific_side.empty()){
00767         return ai_stack_for_specific_side.top();
00768     } else {
00769         config cfg = configuration::get_default_ai_parameters();
00770         holder new_holder(side, cfg);
00771         ai_stack_for_specific_side.push(new_holder);
00772         return ai_stack_for_specific_side.top();
00773     }
00774 }
00775 
00776 // =======================================================================
00777 // AI POINTERS
00778 // =======================================================================
00779 
00780 interface& manager::get_active_ai_for_side( side_number side )
00781 {
00782     return get_active_ai_holder_for_side(side).get_ai_ref();
00783 }
00784 
00785 
00786 // =======================================================================
00787 // MISC
00788 // =======================================================================
00789 
00790 } //end of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Tue May 22 2012 01:03:34 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs