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