The Battle for Wesnoth  1.17.10+dev
candidates.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2022
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  const config & filter_params = cfg.child("filter");
66 
67  if( filter_params ) {
68  for(const config::attribute& filter_param : filter_params.attribute_range())
69  {
70  const_formula_ptr filter_formula(
71  new formula(filter_param.second, function_table));
72 
73  filter_map_[filter_param.first]=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 }
Defines formula ai.
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
unit_iterator end()
Definition: map.hpp:429
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:117
Defines formula ai candidate actions - headers.
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
const std::string & get_name() const
Definition: candidates.hpp:58
virtual void evaluate(ai::formula_ai *ai, unit_map &units)
Definition: candidates.cpp:94
attribute_map::value_type attribute
Definition: config.hpp:221
unit_iterator begin()
Definition: map.hpp:419
candidate_action_with_filters(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:59
static lg::log_domain log_formula_ai("ai/engine/fai")
const_attr_itors attribute_range() const
Definition: config.cpp:858
virtual void update_callable_map(map_formula_callable &callable)
Definition: candidates.cpp:137
bool can_reach_unit(map_location unit_A, map_location unit_B) const
Definition: ai.cpp:649
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:61
move_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:87
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
variant do_filtering(ai::formula_ai *ai, variant &input, const_formula_ptr formula)
Definition: candidates.cpp:78
virtual void evaluate(ai::formula_ai *ai, unit_map &units)
Definition: candidates.cpp:150
bool is_enemy(int n) const
Definition: team.hpp:231
variant_iterator end() const
Definition: variant.cpp:260
std::size_t i
Definition: function.cpp:967
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
virtual const team & current_team() const override
Definition: contexts.hpp:457
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:403
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
virtual void update_callable_map(map_formula_callable &callable)
Definition: candidates.cpp:245
#define ERR_AI
Definition: candidates.cpp:28
Definition: contexts.hpp:44
variant_iterator begin() const
Definition: variant.cpp:255
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:30
Container associating units to locations.
Definition: map.hpp:98
candidate_action_filters filter_map_
Definition: candidates.hpp:78
std::size_t num_elements() const
Definition: variant.cpp:270
const_formula_ptr eval_
Definition: candidates.hpp:67
#define e
attack_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:142
Iterator class for the variant.
Definition: variant.hpp:186
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
base_candidate_action(const std::string &name, const std::string &type, const config &cfg, function_symbol_table *function_table)
Definition: candidates.cpp:32
int execute_formula(const const_formula_ptr &formula, const formula_callable &callable, const ai::formula_ai *ai)
Definition: candidates.cpp:42