ai/testing/stage_rca.cpp

Go to the documentation of this file.
00001 /* $Id: stage_rca.cpp 52533 2012-01-07 02:35:17Z 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  * Candidate actions evaluator
00018  * @file
00019  */
00020 
00021 #include "stage_rca.hpp"
00022 
00023 #include "../manager.hpp"
00024 #include "../composite/ai.hpp"
00025 #include "../composite/engine.hpp"
00026 #include "../composite/property_handler.hpp"
00027 #include "../gamestate_observer.hpp"
00028 #include "../../foreach.hpp"
00029 #include "../../log.hpp"
00030 
00031 #include <boost/bind.hpp>
00032 
00033 namespace ai {
00034 
00035 namespace testing_ai_default {
00036 
00037 static lg::log_domain log_ai_testing_rca_default("ai/stage/rca");
00038 #define DBG_AI_TESTING_RCA_DEFAULT LOG_STREAM(debug, log_ai_testing_rca_default)
00039 #define LOG_AI_TESTING_RCA_DEFAULT LOG_STREAM(info, log_ai_testing_rca_default)
00040 #define ERR_AI_TESTING_RCA_DEFAULT LOG_STREAM(err, log_ai_testing_rca_default)
00041 
00042 candidate_action_evaluation_loop::candidate_action_evaluation_loop( ai_context &context, const config &cfg)
00043     : stage(context,cfg)
00044     , candidate_actions_()
00045     , cfg_(cfg)
00046 {
00047 }
00048 
00049 void candidate_action_evaluation_loop::on_create()
00050 {
00051     //init the candidate actions
00052     foreach(const config &cfg_element, cfg_.child_range("candidate_action")){
00053         engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
00054     }
00055 
00056     boost::function2<void, std::vector<candidate_action_ptr>&, const config&> factory_candidate_actions =
00057         boost::bind(&testing_ai_default::candidate_action_evaluation_loop::create_candidate_action,*this,_1,_2);
00058 
00059     register_vector_property(property_handlers(),"candidate_action",candidate_actions_, factory_candidate_actions);
00060 
00061 }
00062 
00063 void candidate_action_evaluation_loop::create_candidate_action(std::vector<candidate_action_ptr> &candidate_actions, const config &cfg)
00064 {
00065     engine::parse_candidate_action_from_config(*this,cfg,std::back_inserter(candidate_actions));
00066 }
00067 
00068 
00069 config candidate_action_evaluation_loop::to_config() const
00070 {
00071     config cfg = stage::to_config();
00072     foreach(candidate_action_ptr ca, candidate_actions_){
00073         cfg.add_child("candidate_action",ca->to_config());
00074     }
00075     return cfg;
00076 }
00077 
00078 
00079 class desc_sorter_of_candidate_actions {
00080 public:
00081     bool operator()(const candidate_action_ptr &a, const candidate_action_ptr &b)
00082     {
00083         return a->get_max_score() > b->get_max_score();
00084     }
00085 };
00086 
00087 bool candidate_action_evaluation_loop::do_play_stage()
00088 {
00089     LOG_AI_TESTING_RCA_DEFAULT << "Starting candidate action evaluation loop for side "<< get_side() << std::endl;
00090 
00091     foreach(candidate_action_ptr ca, candidate_actions_){
00092         ca->enable();
00093     }
00094 
00095     //sort candidate actions by max_score DESC
00096     std::sort(candidate_actions_.begin(),candidate_actions_.end(),desc_sorter_of_candidate_actions());
00097 
00098     bool executed = false;
00099     bool gamestate_changed = false;
00100     do {
00101         executed = false;
00102         double best_score = candidate_action::BAD_SCORE;
00103         candidate_action_ptr best_ptr;
00104 
00105         //Evaluation
00106         foreach(candidate_action_ptr ca_ptr, candidate_actions_){
00107             if (!ca_ptr->is_enabled()){
00108                 DBG_AI_TESTING_RCA_DEFAULT << "Skipping disabled candidate action: "<< *ca_ptr << std::endl;
00109                 continue;
00110             }
00111 
00112             if (ca_ptr->get_max_score()<=best_score) {
00113                 DBG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop because current score "<<best_score<<" is greater than the upper bound of score for remaining candidate actions "<< ca_ptr->get_max_score()<< std::endl;
00114                 break;
00115             }
00116 
00117             DBG_AI_TESTING_RCA_DEFAULT << "Evaluating candidate action: "<< *ca_ptr << std::endl;
00118             double score = ca_ptr->evaluate();
00119             DBG_AI_TESTING_RCA_DEFAULT << "Evaluated candidate action to score "<< score << " : " << *ca_ptr << std::endl;
00120 
00121             if (score>best_score) {
00122                 best_score = score;
00123                 best_ptr = ca_ptr;
00124             }
00125         }
00126 
00127         //Execution
00128         if (best_score>candidate_action::BAD_SCORE) {
00129             DBG_AI_TESTING_RCA_DEFAULT << "Executing best candidate action: "<< *best_ptr << std::endl;
00130             gamestate_observer gs_o;
00131             best_ptr->execute();
00132             executed = true;
00133             if (!gs_o.is_gamestate_changed()) {
00134                 //this means that this CA has lied to us in evaluate()
00135                 //we punish it by disabling it
00136                 DBG_AI_TESTING_RCA_DEFAULT << "Disabling candidate action because it failed to change the game state: "<< *best_ptr << std::endl;
00137                 best_ptr->disable();
00138                 //since we don't re-enable at this play_stage, if we disable this CA, other may get the chance to go.
00139             } else {
00140                 gamestate_changed = true;
00141             }
00142         } else {
00143             LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< candidate_action::BAD_SCORE<<std::endl;
00144         }
00145     } while (executed);
00146     LOG_AI_TESTING_RCA_DEFAULT << "Ended candidate action evaluation loop for side "<< get_side() << std::endl;
00147     remove_completed_cas();
00148     return gamestate_changed;
00149 }
00150 
00151 void candidate_action_evaluation_loop::remove_completed_cas()
00152 {
00153     std::vector<size_t> tbr; // indexes of elements to be removed
00154 
00155     for (size_t i = 0; i != candidate_actions_.size(); ++i)
00156     {
00157         if (candidate_actions_[i]->to_be_removed())
00158         {
00159             tbr.push_back(i); // so we fill the array with the indexes
00160         }
00161     }
00162 
00163     for (size_t i = 0; i != tbr.size(); ++i)
00164     {
00165         // we should go downwards, so that index shifts don't affect us
00166         size_t index = tbr.size() - i - 1; // downcounting for is not possible using unsigned counters, so we hack around
00167         std::string path = "stage[" + this->get_id() + "].candidate_action[" + candidate_actions_[tbr[index]]->get_name() + "]";
00168 
00169         config cfg = config();
00170         cfg["path"] = path;
00171         cfg["action"] = "delete";
00172 
00173         ai::manager::modify_active_ai_for_side(this->get_side(), cfg); // we remove the CA
00174     }
00175 
00176 
00177 // @note: this code might be more convenient, but is obviously faulty and incomplete, because of iterator invalidation rules
00178 //    If you see a way to complete it, please contact me(Nephro).
00179 //  for (std::vector<candidate_action_ptr>::iterator it = candidate_actions_.begin(); it != candidate_actions_.end(); )
00180 //  {
00181 //      if ((*it)->to_be_removed())
00182 //      {
00183 //          // code to remove a CA
00184 //          std::string path = "stage[" + this->get_id() + "].candidate_action[" + (*it)->get_name() + "]";
00185 //
00186 //          config cfg = config();
00187 //          cfg["path"] = path;
00188 //          cfg["action"] = "delete";
00189 //
00190 //          ai::manager::modify_active_ai_for_side(this->get_side(), cfg);
00191 //      }
00192 //      else
00193 //      {
00194 //          ++it; // @note: should I modify this to a while loop?
00195 //      }
00196 //  }
00197 }
00198 
00199 rca_context& candidate_action_evaluation_loop::get_rca_context()
00200 {
00201     return *this;
00202 }
00203 
00204 candidate_action_evaluation_loop::~candidate_action_evaluation_loop()
00205 {
00206 }
00207 
00208 } // end of namespace testing_ai_default
00209 
00210 } // end of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:02:45 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs