The Battle for Wesnoth  1.19.13+dev
stage_rca.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2025
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 
56  [this](auto& candidate_actions, const config& cfg) {
57  engine::parse_candidate_action_from_config(*this, cfg, std::back_inserter(candidate_actions));
58  });
59 }
60 
62 {
63  config cfg = stage::to_config();
65  cfg.add_child("candidate_action",ca->to_config());
66  }
67  return cfg;
68 }
69 
70 
72 public:
74  {
75  return a->get_max_score() > b->get_max_score();
76  }
77 };
78 
80 {
81  LOG_AI_TESTING_RCA_DEFAULT << "Starting candidate action evaluation loop for side "<< get_side();
82 
84  ca->enable();
85  }
86 
87  //sort candidate actions by max_score DESC
89 
90  bool executed = false;
91  bool gamestate_changed = false;
92  do {
93  executed = false;
94  double best_score = candidate_action::BAD_SCORE;
95  candidate_action_ptr best_ptr;
96 
97  //Evaluation
99  if (!ca_ptr->is_enabled()){
100  DBG_AI_TESTING_RCA_DEFAULT << "Skipping disabled candidate action: "<< *ca_ptr;
101  continue;
102  }
103 
104  if (ca_ptr->get_max_score()<=best_score) {
105  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();
106  break;
107  }
108 
109  DBG_AI_TESTING_RCA_DEFAULT << "Evaluating candidate action: "<< *ca_ptr;
110  double score = ca_ptr->evaluate();
111  DBG_AI_TESTING_RCA_DEFAULT << "Evaluated candidate action to score "<< score << " : " << *ca_ptr;
112 
113  if (score>best_score) {
114  best_score = score;
115  best_ptr = ca_ptr;
116  }
117  }
118 
119  //Execution
120  if (best_score>candidate_action::BAD_SCORE) {
121  DBG_AI_TESTING_RCA_DEFAULT << "Executing best candidate action: "<< *best_ptr;
122  gamestate_observer gs_o;
123  best_ptr->execute();
124  executed = true;
125  if (!gs_o.is_gamestate_changed()) {
126  //this means that this CA has lied to us in evaluate()
127  //we punish it by disabling it
128  DBG_AI_TESTING_RCA_DEFAULT << "Disabling candidate action because it failed to change the game state: "<< *best_ptr;
129  best_ptr->disable();
130  //since we don't re-enable at this play_stage, if we disable this CA, other may get the chance to go.
131  } else {
132  gamestate_changed = true;
133  }
134  } else {
135  LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< candidate_action::BAD_SCORE;
136  }
137  } while (executed);
138  LOG_AI_TESTING_RCA_DEFAULT << "Ended candidate action evaluation loop for side "<< get_side();
140  return gamestate_changed;
141 }
142 
144 {
145  std::vector<std::size_t> tbr; // indexes of elements to be removed
146 
147  for (std::size_t i = 0; i != candidate_actions_.size(); ++i)
148  {
149  if (candidate_actions_[i]->to_be_removed())
150  {
151  tbr.push_back(i); // so we fill the array with the indexes
152  }
153  }
154 
155  for (std::size_t i = 0; i != tbr.size(); ++i)
156  {
157  // we should go downwards, so that index shifts don't affect us
158  std::size_t index = tbr.size() - i - 1; // downcounting for is not possible using unsigned counters, so we hack around
159  std::string path = "stage[" + this->get_id() + "].candidate_action[" + candidate_actions_[tbr[index]]->get_name() + "]";
160 
161  config cfg = config();
162  cfg["path"] = path;
163  cfg["action"] = "delete";
164 
165  ai::manager::get_singleton().modify_active_ai_for_side(this->get_side(), cfg); // we remove the CA
166  }
167 
168 
169 // @note: this code might be more convenient, but is obviously faulty and incomplete, because of iterator invalidation rules
170 // If you see a way to complete it, please contact me(Nephro).
171 // for (std::vector<candidate_action_ptr>::iterator it = candidate_actions_.begin(); it != candidate_actions_.end(); )
172 // {
173 // if ((*it)->to_be_removed())
174 // {
175 // // code to remove a CA
176 // std::string path = "stage[" + this->get_id() + "].candidate_action[" + (*it)->get_name() + "]";
177 //
178 // config cfg = config();
179 // cfg["path"] = path;
180 // cfg["action"] = "delete";
181 //
182 // ai::manager::get_singleton().modify_active_ai_for_side(this->get_side(), cfg);
183 // }
184 // else
185 // {
186 // ++it; // @note: should I modify this to a while loop?
187 // }
188 // }
189 }
190 
192 {
193  return *this;
194 }
195 
197 {
198 }
199 
200 } // end of namespace testing_ai_default
201 
202 } // 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:79
bool operator()(const candidate_action_ptr &a, const candidate_action_ptr &b) const
Definition: stage_rca.cpp:73
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:158
child_itors child_range(config_key_type key)
Definition: config.cpp:268
config & add_child(config_key_type key)
Definition: config.cpp:436
AI Support engine - creating specific ai components from config.
std::size_t i
Definition: function.cpp:1032
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
static void register_vector_property(property_handler_map &property_handlers, const std::string &property, std::vector< std::shared_ptr< X >> &values, Factory &&construction_factory)
std::shared_ptr< candidate_action > candidate_action_ptr
Definition: rca.hpp:145
std::string path
Definition: filesystem.cpp:106
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