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