The Battle for Wesnoth  1.19.5+dev
candidates.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
3  by Bartosz Waresiak <dragonking@o2.pl>
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  * @file
18  * Defines formula ai candidate actions
19  * */
20 
21 #include "ai/formula/ai.hpp"
23 #include "game_board.hpp"
24 #include "log.hpp"
25 #include "units/unit.hpp"
26 
27 static lg::log_domain log_formula_ai("ai/engine/fai");
28 #define ERR_AI LOG_STREAM(err, log_formula_ai)
29 
30 namespace wfl {
31 
33  const std::string& type, const config& cfg,
34  function_symbol_table* function_table) :
35  name_(name),
36  type_(type),
37  eval_(new formula(cfg["evaluation"], function_table)),
38  action_(new formula(cfg["action"], function_table)),
39  score_(0)
40 {}
41 
43  const formula_callable& callable, const ai::formula_ai* ai)
44 {
45  int res = 0;
46  try {
47  res = (formula::evaluate(formula, callable)).as_int();
48  } catch(const formula_error& e) {
49  ai->handle_exception(e);
50  res = 0;
51  } catch(const type_error& e) {
52  res = 0;
53  ERR_AI << "formula type error while evaluating candidate action: " << e.message;
54  }
55 
56  return res;
57 }
58 
60  const std::string& name, const std::string& type,
61  const config& cfg, function_symbol_table* function_table)
62  : base_candidate_action(name, type, cfg, function_table)
63  , filter_map_()
64 {
65  auto filter_params = cfg.optional_child("filter");
66 
67  if( filter_params ) {
68  for(const auto& [key, value] : filter_params->attribute_range())
69  {
70  const_formula_ptr filter_formula(
71  new formula(value, function_table));
72 
73  filter_map_[key]=filter_formula;
74  }
75  }
76 }
77 
79 {
80  map_formula_callable callable(ai->fake_ptr());
81  callable.add("input", input);
82 
83  return formula::evaluate(formula, callable);
84 
85 }
86 
88  const std::string& type, const config& cfg,
89  function_symbol_table* function_table)
90  : candidate_action_with_filters(name, type, cfg, function_table)
91  , my_unit_()
92 {}
93 
95 {
96  score_ = 0;
97 
98  candidate_action_filters::const_iterator me_filter = filter_map_.find("me");
99 
100  std::vector<variant> unit_vector;
101 
102  for(unit_map::unit_iterator i = units.begin() ; i != units.end() ; ++i)
103  {
104  if (i->side() == ai->get_side() && i->movement_left() > 0) {
105  unit_vector.emplace_back(std::make_shared<unit_callable>(*i));
106  }
107  }
108 
109  variant my_units(unit_vector);
110 
111  variant filtered_units;
112  try {
113  if(me_filter != filter_map_.end() )
114  filtered_units = do_filtering(ai, my_units, me_filter->second);
115  else
116  filtered_units=my_units;
117  }
118  catch(const formula_error& e) {
119  ai->handle_exception(e, "Error while executing filter formula for '" + get_name() + "' Candidate Action");
120  return;
121  }
122 
123  for(variant_iterator i = filtered_units.begin() ; i != filtered_units.end() ; ++i)
124  {
125  map_formula_callable callable(ai->fake_ptr());
126  callable.add("me", *i);
127 
128  int res = execute_formula(eval_, callable, ai);
129 
130  if(res > score_) {
131  score_ = res;
132  my_unit_ = *i;
133  }
134  }
135 }
136 
138 {
139  callable.add("me", my_unit_);
140 }
141 
143  const std::string& type, const config& cfg,
144  function_symbol_table* function_table)
145  : candidate_action_with_filters(name, type, cfg, function_table)
146  , my_unit_()
147  , enemy_unit_()
148 {}
149 
151 {
152  score_ = 0;
153 
154  candidate_action_filters::const_iterator me_filter = filter_map_.find("me");
155  candidate_action_filters::const_iterator target_filter = filter_map_.find("target");
156 
157  std::vector<variant> my_res, enemy_res;
158 
159  for(unit_map::unit_iterator i = units.begin() ; i != units.end() ; ++i)
160  {
161  if (i->side() == ai->get_side())
162  {
163  if (i->attacks_left()) {
164  my_res.emplace_back(std::make_shared<unit_callable>(*i));
165  }
166  } else
167  {
168  if (ai->current_team().is_enemy(i->side()) && !i->incapacitated() && !i->invisible(i->get_location())) {
169  enemy_res.emplace_back(std::make_shared<unit_callable>(*i));
170  }
171  }
172  }
173  variant my_units(my_res);
174  variant enemy_units(enemy_res);
175 
176  variant filtered_my_units, filtered_enemy_units;
177  try {
178  if(me_filter != filter_map_.end() )
179  filtered_my_units = do_filtering(ai, my_units, me_filter->second);
180  else
181  filtered_my_units = my_units;
182 
183  if(target_filter != filter_map_.end() )
184  filtered_enemy_units = do_filtering(ai, enemy_units, target_filter->second);
185  else
186  filtered_enemy_units = enemy_units;
187  }
188  catch(const formula_error& e) {
189  ai->handle_exception(e, "Error while executing filter formula for '" + get_name() + "' Candidate Action");
190  return;
191  }
192 
193  try{
194  if( !(filtered_enemy_units.num_elements() && filtered_my_units.num_elements() ) )
195  return;
196  }
197  catch(const type_error& e) {
198  ERR_AI << "Error while executing filter formulas for '" + get_name() + "' Candidate Action: " << e.message;
199  return;
200  }
201 
202  std::vector<variant> my_units_flt;
203  std::vector<variant> enemy_units_flt;
204 
205  for(variant_iterator i = filtered_my_units.begin() ; i != filtered_my_units.end() ; ++i) {
206  auto u_callable = (*i).try_convert<const unit_callable>();
207  if(!u_callable) {
208  ERR_AI << "ERROR in "<< get_name() << "Candidate Action: Filter formula returned table that does not contain units";
209  return;
210  }
211  my_units_flt.emplace_back(u_callable);
212  }
213 
214  for(variant_iterator i = filtered_enemy_units.begin() ; i != filtered_enemy_units.end() ; ++i) {
215  auto u_callable = (*i).try_convert<const unit_callable>();
216  if(!u_callable) {
217  ERR_AI << "ERROR in "<< get_name() << "Candidate Action: Filter formula returned table that does not contain units";
218  return;
219  }
220  enemy_units_flt.emplace_back(u_callable);
221  }
222 
223  for( std::size_t my_unit = 0 ; my_unit < my_units_flt.size() ; ++my_unit){
224  auto my_unit_callable = my_units_flt[my_unit].convert_to<unit_callable>();
225  for( std::size_t enemy_unit = 0 ; enemy_unit < enemy_units_flt.size() ; ++enemy_unit){
226  auto enemy_unit_callable = enemy_units_flt[enemy_unit].convert_to<unit_callable>();
227  if(ai->can_reach_unit(my_unit_callable->get_location(), enemy_unit_callable->get_location())) {
228 
229  map_formula_callable callable(ai->fake_ptr());
230  callable.add("me", filtered_my_units[my_unit]);
231  callable.add("target", filtered_enemy_units[enemy_unit]);
232 
233  int res = execute_formula(eval_, callable, ai);
234 
235  if(res > score_) {
236  score_ = res;
237  my_unit_ = filtered_my_units[my_unit];
238  enemy_unit_ = filtered_enemy_units[enemy_unit];
239  }
240  }
241  }
242  }
243 }
244 
246 {
247  callable.add("me", my_unit_);
248  callable.add("target", enemy_unit_);
249 }
250 
251 }
#define ERR_AI
Definition: candidates.cpp:28
static lg::log_domain log_formula_ai("ai/engine/fai")
Defines formula ai candidate actions - headers.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:384
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
unit_iterator begin()
Definition: map.hpp:418
attack_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:142
virtual void evaluate(ai::formula_ai *ai, unit_map &units)
Definition: candidates.cpp:150
virtual void update_callable_map(map_formula_callable &callable)
Definition: candidates.cpp:245
const std::string & get_name() const
Definition: candidates.hpp:57
int execute_formula(const const_formula_ptr &formula, const formula_callable &callable, const ai::formula_ai *ai)
Definition: candidates.cpp:42
const_formula_ptr eval_
Definition: candidates.hpp:66
base_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:32
variant do_filtering(ai::formula_ai *ai, variant &input, const_formula_ptr formula)
Definition: candidates.cpp:78
candidate_action_with_filters(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:59
candidate_action_filters filter_map_
Definition: candidates.hpp:77
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:40
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
move_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:87
virtual void update_callable_map(map_formula_callable &callable)
Definition: candidates.cpp:137
virtual void evaluate(ai::formula_ai *ai, unit_map &units)
Definition: candidates.cpp:94
Iterator class for the variant.
Definition: variant.hpp:187
variant_iterator begin() const
Definition: variant.cpp:252
std::size_t num_elements() const
Definition: variant.cpp:267
variant_iterator end() const
Definition: variant.cpp:257
Defines formula ai.
std::size_t i
Definition: function.cpp:1028
Standard logging facilities (interface).
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
Definition: contexts.hpp:43
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
#define e