The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
stage_rca.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Yurii Chernyi <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * Candidate actions evaluator
17  * @file
18  */
19 
20 #include "ai/default/stage_rca.hpp"
21 
22 #include "ai/manager.hpp"
23 #include "ai/composite/ai.hpp"
24 #include "ai/composite/engine.hpp"
26 #include "ai/composite/rca.hpp"
28 #include "log.hpp"
29 
30 #include "utils/functional.hpp"
31 
32 namespace ai {
33 
34 namespace ai_default_rca {
35 
36 static lg::log_domain log_ai_testing_rca_default("ai/stage/rca");
37 #define DBG_AI_TESTING_RCA_DEFAULT LOG_STREAM(debug, log_ai_testing_rca_default)
38 #define LOG_AI_TESTING_RCA_DEFAULT LOG_STREAM(info, log_ai_testing_rca_default)
39 #define ERR_AI_TESTING_RCA_DEFAULT LOG_STREAM(err, log_ai_testing_rca_default)
40 
42  : stage(context,cfg)
43  , candidate_actions_()
44  , cfg_(cfg)
45 {
46 }
47 
49 {
50  //init the candidate actions
51  for (const config &cfg_element : cfg_.child_range("candidate_action")) {
52  engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
53  }
54 
55  std::function<void(std::vector<candidate_action_ptr>&, const config&)> factory_candidate_actions =
57 
58  register_vector_property(property_handlers(),"candidate_action",candidate_actions_, factory_candidate_actions);
59 
60 }
61 
62 void candidate_action_evaluation_loop::create_candidate_action(std::vector<candidate_action_ptr> &candidate_actions, const config &cfg)
63 {
64  engine::parse_candidate_action_from_config(*this,cfg,std::back_inserter(candidate_actions));
65 }
66 
67 
69 {
70  config cfg = stage::to_config();
72  cfg.add_child("candidate_action",ca->to_config());
73  }
74  return cfg;
75 }
76 
77 
79 public:
81  {
82  return a->get_max_score() > b->get_max_score();
83  }
84 };
85 
87 {
88  LOG_AI_TESTING_RCA_DEFAULT << "Starting candidate action evaluation loop for side "<< get_side() << std::endl;
89 
91  ca->enable();
92  }
93 
94  //sort candidate actions by max_score DESC
95  std::sort(candidate_actions_.begin(),candidate_actions_.end(),desc_sorter_of_candidate_actions());
96 
97  bool executed = false;
98  bool gamestate_changed = false;
99  do {
100  executed = false;
101  double best_score = candidate_action::BAD_SCORE;
102  candidate_action_ptr best_ptr;
103 
104  //Evaluation
105  for (candidate_action_ptr ca_ptr : candidate_actions_) {
106  if (!ca_ptr->is_enabled()){
107  DBG_AI_TESTING_RCA_DEFAULT << "Skipping disabled candidate action: "<< *ca_ptr << std::endl;
108  continue;
109  }
110 
111  if (ca_ptr->get_max_score()<=best_score) {
112  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;
113  break;
114  }
115 
116  DBG_AI_TESTING_RCA_DEFAULT << "Evaluating candidate action: "<< *ca_ptr << std::endl;
117  double score = ca_ptr->evaluate();
118  DBG_AI_TESTING_RCA_DEFAULT << "Evaluated candidate action to score "<< score << " : " << *ca_ptr << std::endl;
119 
120  if (score>best_score) {
121  best_score = score;
122  best_ptr = ca_ptr;
123  }
124  }
125 
126  //Execution
127  if (best_score>candidate_action::BAD_SCORE) {
128  DBG_AI_TESTING_RCA_DEFAULT << "Executing best candidate action: "<< *best_ptr << std::endl;
129  gamestate_observer gs_o;
130  best_ptr->execute();
131  executed = true;
132  if (!gs_o.is_gamestate_changed()) {
133  //this means that this CA has lied to us in evaluate()
134  //we punish it by disabling it
135  DBG_AI_TESTING_RCA_DEFAULT << "Disabling candidate action because it failed to change the game state: "<< *best_ptr << std::endl;
136  best_ptr->disable();
137  //since we don't re-enable at this play_stage, if we disable this CA, other may get the chance to go.
138  } else {
139  gamestate_changed = true;
140  }
141  } else {
142  LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< candidate_action::BAD_SCORE<<std::endl;
143  }
144  } while (executed);
145  LOG_AI_TESTING_RCA_DEFAULT << "Ended candidate action evaluation loop for side "<< get_side() << std::endl;
147  return gamestate_changed;
148 }
149 
151 {
152  std::vector<size_t> tbr; // indexes of elements to be removed
153 
154  for (size_t i = 0; i != candidate_actions_.size(); ++i)
155  {
156  if (candidate_actions_[i]->to_be_removed())
157  {
158  tbr.push_back(i); // so we fill the array with the indexes
159  }
160  }
161 
162  for (size_t i = 0; i != tbr.size(); ++i)
163  {
164  // we should go downwards, so that index shifts don't affect us
165  size_t index = tbr.size() - i - 1; // downcounting for is not possible using unsigned counters, so we hack around
166  std::string path = "stage[" + this->get_id() + "].candidate_action[" + candidate_actions_[tbr[index]]->get_name() + "]";
167 
168  config cfg = config();
169  cfg["path"] = path;
170  cfg["action"] = "delete";
171 
172  ai::manager::modify_active_ai_for_side(this->get_side(), cfg); // we remove the CA
173  }
174 
175 
176 // @note: this code might be more convenient, but is obviously faulty and incomplete, because of iterator invalidation rules
177 // If you see a way to complete it, please contact me(Nephro).
178 // for (std::vector<candidate_action_ptr>::iterator it = candidate_actions_.begin(); it != candidate_actions_.end(); )
179 // {
180 // if ((*it)->to_be_removed())
181 // {
182 // // code to remove a CA
183 // std::string path = "stage[" + this->get_id() + "].candidate_action[" + (*it)->get_name() + "]";
184 //
185 // config cfg = config();
186 // cfg["path"] = path;
187 // cfg["action"] = "delete";
188 //
189 // ai::manager::modify_active_ai_for_side(this->get_side(), cfg);
190 // }
191 // else
192 // {
193 // ++it; // @note: should I modify this to a while loop?
194 // }
195 // }
196 }
197 
199 {
200  return *this;
201 }
202 
204 {
205 }
206 
207 } // end of namespace testing_ai_default
208 
209 } // end of namespace ai
child_itors child_range(const std::string &key)
Definition: config.cpp:613
static lg::log_domain log_ai_testing_rca_default("ai/stage/rca")
bool is_gamestate_changed()
Check if the gamestate has changed since last reset reset is done once on construction, and can be done by hand via reset() method.
property_handler_map & property_handlers()
Definition: component.cpp:133
game_logic::candidate_action_ptr ca_ptr
Definition: ai.cpp:78
virtual std::string get_id() const
Definition: stage.cpp:75
candidate_action_evaluation_loop(ai_context &context, const config &cfg)
Definition: stage_rca.cpp:41
std::vector< candidate_action_ptr > candidate_actions_
Definition: stage_rca.hpp:55
AI Support engine - creating specific ai components from config.
static void register_vector_property(std::map< std::string, property_handler_ptr > &property_handlers, const std::string &property, std::vector< boost::shared_ptr< X > > &values, std::function< void(std::vector< boost::shared_ptr< X > > &, const config &)> construction_factory)
A helper class to observe the game state.
#define LOG_AI_TESTING_RCA_DEFAULT
Definition: stage_rca.cpp:38
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
GLsizei const char ** path
Definition: glew.h:4654
virtual config to_config() const
serialize
Definition: stage.cpp:66
Composite AI with turn sequence which is a vector of stages.
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
config & add_child(const std::string &key)
Definition: config.cpp:743
Managing the AIs lifecycle - headers.
static void modify_active_ai_for_side(ai::side_number side, const config &cfg)
Modifies AI parameters for active AI of the given side.
Definition: manager.cpp:722
static void parse_candidate_action_from_config(rca_context &context, const config &cfg, std::back_insert_iterator< std::vector< candidate_action_ptr > > b)
Definition: engine.cpp:60
candidate action evaluator
GLuint index
Definition: glew.h:1782
bool operator()(const candidate_action_ptr &a, const candidate_action_ptr &b)
Definition: stage_rca.cpp:80
size_t i
Definition: function.cpp:1057
void create_candidate_action(std::vector< candidate_action_ptr > &candidate_actions, const config &cfg)
Definition: stage_rca.cpp:62
static int sort(lua_State *L)
Definition: ltablib.cpp:246
Composite AI component.
bool do_play_stage()
Play the turn - implementation.
Definition: stage_rca.cpp:86
Standard logging facilities (interface).
virtual side_number get_side() const =0
Get the side number.
static const double BAD_SCORE
Definition: rca.hpp:38
#define DBG_AI_TESTING_RCA_DEFAULT
Definition: stage_rca.cpp:37
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLsizei const GLcharARB ** string
Definition: glew.h:4503
candidate action framework