The Battle for Wesnoth  1.15.9+dev
ai.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2018 by David White <dave@whitevine.net>
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 - headers
18  */
19 
20 #include "ai/formula/ai.hpp"
21 
22 #include "ai/formula/callable_objects.hpp" // for unit_callable, etc
23 #include "chat_events.hpp" // for chat_handler, etc
24 #include "display_chat_manager.hpp"
25 #include "formula/function.hpp" // for formula_expression
26 #include "game_board.hpp" // for game_board
27 #include "game_display.hpp" // for game_display
28 #include "log.hpp" // for LOG_STREAM, logger, etc
29 #include "map/map.hpp" // for gamemap
30 #include "pathfind/pathfind.hpp" // for plain_route, etc
31 #include "pathfind/teleport.hpp" // for get_teleport_locations, etc
32 #include "recall_list_manager.hpp" // for recall_list_manager
33 #include "resources.hpp" // for gameboard, teams, units, etc
34 #include "serialization/string_utils.hpp" // for split
35 #include "team.hpp" // for team
36 #include "terrain/filter.hpp" // for terrain_filter
37 #include "time_of_day.hpp" // for time_of_day
38 #include "tod_manager.hpp" // for tod_manager
39 #include "tstring.hpp" // for t_string, operator+
40 #include "units/unit.hpp" // for unit
41 #include "units/formula_manager.hpp" // for unit_formula_manager
42 #include "units/ptr.hpp" // for unit_ptr
43 #include "units/types.hpp"
44 #include "formula/formula.hpp" // for formula_error, formula, etc
45 #include "map/location.hpp" // for map_location, etc
46 #include "ai/actions.hpp" // for recall_result, etc
47 #include "ai/manager.hpp" // for manager
49 #include "ai/composite/stage.hpp" // for stage
50 #include "ai/default/contexts.hpp" // for attack_analysis
51 #include "ai/formula/function_table.hpp" // for ai_function_symbol_table
52 #include "ai/game_info.hpp" // for move_result_ptr, move_map, etc
53 #include "ai/formula/candidates.hpp" // for base_candidate_action, etc
54 #include "utils/variant.hpp"
55 
56 #include <cassert> // for assert
57 #include <ctime> // for time
58 #include <map> // for multimap<>::const_iterator, etc
59 #include <sstream> // for operator<<, basic_ostream, etc
60 #include <stack> // for stack
61 #include <vector> // for vector, allocator, etc
62 
63 static lg::log_domain log_formula_ai("ai/engine/fai");
64 #define DBG_AI LOG_STREAM(debug, log_formula_ai)
65 #define LOG_AI LOG_STREAM(info, log_formula_ai)
66 #define WRN_AI LOG_STREAM(warn, log_formula_ai)
67 #define ERR_AI LOG_STREAM(err, log_formula_ai)
68 
69 using namespace wfl;
70 
71 namespace ai {
72 
74 
76 {
77  ca_ptr new_ca;
78  const t_string &name = rc_action["name"];
79  try {
80  const t_string &type = rc_action["type"];
81 
82  if( type == "movement") {
83  new_ca = std::make_shared<move_candidate_action>(name, type, rc_action, &function_table_);
84  } else if( type == "attack") {
85  new_ca = std::make_shared<attack_candidate_action>(name, type, rc_action, &function_table_);
86  } else {
87  ERR_AI << "Unknown candidate action type: " << type << std::endl;
88  }
89  } catch(const formula_error& e) {
90  handle_exception(e, "Error while registering candidate action '" + name + "'");
91  }
92  return new_ca;
93 }
94 
97 }
98 
100  :
103  ai_ptr_(nullptr),
104  cfg_(cfg),
106  keeps_cache_(),
107  attacks_callable(*this, resources::gameboard->units()),
108 // infinite_loop_guardian_(),
109  vars_(),
110  function_table_(*this)
111 {
113  LOG_AI << "creating new formula ai"<< std::endl;
114 }
115 
117 {
118  handle_exception(e, "Error while parsing formula");
119 }
120 
121 void formula_ai::handle_exception(const formula_error& e, const std::string& failed_operation) const
122 {
123  LOG_AI << failed_operation << ": " << e.formula << std::endl;
124  display_message(failed_operation + ": " + e.formula);
125  //if line number = 0, don't display info about filename and line number
126  if (e.line != 0) {
127  LOG_AI << e.type << " in " << e.filename << ":" << e.line << std::endl;
128  display_message(e.type + " in " + e.filename + ":" + std::to_string(e.line));
129  } else {
130  LOG_AI << e.type << std::endl;
132  }
133 }
134 
135 void formula_ai::display_message(const std::string& msg) const
136 {
137  game_display::get_singleton()->get_chat_manager().add_chat_message(std::time(nullptr), "wfl", get_side(), msg,
139 
140 }
141 
142 formula_ptr formula_ai::create_optional_formula(const std::string& formula_string) const {
143  try{
144  return formula::create_optional_formula(formula_string, &function_table_);
145  }
146  catch(const formula_error& e) {
147  handle_exception(e);
148  return wfl::formula_ptr();
149  }
150 }
151 
153 {
154  ai_ptr_ = context;
155 }
156 
157 std::string formula_ai::evaluate(const std::string& formula_str)
158 {
159  try{
160 
161  formula f(formula_str, &function_table_);
162 
163  map_formula_callable callable(fake_ptr());
164 
165  //formula_debugger fdb;
166  const variant v = f.evaluate(callable,nullptr);
167 
168  if (ai_ptr_) {
169  variant var = variant(this->fake_ptr()).execute_variant(v);
170 
171  if ( !var.is_empty() ) {
172  return "Made move: " + var.to_debug_string();
173  }
174  }
175 
176  return v.to_debug_string();
177  }
178  catch(formula_error& e) {
179  e.line = 0;
180  handle_exception(e);
181  throw;
182  }
183 }
184 
186 {
187  if (!formula_) {
188  throw formula_error("null formula passed to make_action","","formula",0);
189  }
190  LOG_AI << "do move...\n";
191  const variant var = formula_->evaluate(variables);
192  variant res;
193 
194  if (ai_ptr_) {
195  res = variant(this->fake_ptr()).execute_variant(var);
196  } else {
197  ERR_AI << "skipped execution of action because ai context is not set correctly" << std::endl;
198  }
199 
200  return res;
201 }
202 
204  const map_location &dst, unit_map::iterator &unit_it,
205  pathfind::teleport_map& allowed_teleports) const
206 {
207  map_location destination = dst;
208 
209  unit_map &units_ = resources::gameboard->units();
211 
212  unit_map::const_iterator dst_un = units_.find(destination);
213 
214  map_location res;
215 
216  if( dst_un != units_.end() ) {
217  //there is unit standing at dst, let's try to find free hex to move to
218  const map_location::DIRECTION preferred = destination.get_relative_dir(src);
219 
220  int best_rating = 100;//smaller is better
221  const auto adj = get_adjacent_tiles(destination);
222 
223  for(std::size_t n = 0; n < adj.size(); ++n) {
224  if(resources::gameboard->map().on_board(adj[n]) == false) {
225  continue;
226  }
227 
228  if(units_.find(adj[n]) != units_.end()) {
229  continue;
230  }
231 
232  static const std::size_t NDIRECTIONS = map_location::NDIRECTIONS;
233  unsigned int difference = std::abs(static_cast<int>(preferred - n));
234  if(difference > NDIRECTIONS/2) {
235  difference = NDIRECTIONS - difference;
236  }
237 
238  const int rating = difference * 2;
239  if(rating < best_rating || res.valid() == false) {
240  best_rating = rating;
241  res = adj[n];
242  }
243  }
244  }
245 
246  if( res != map_location() ) {
247  destination = res;
248  }
249 
250  pathfind::plain_route route = pathfind::a_star_search(src, destination, 1000.0, calc,
251  resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
252 
253  return route;
254 }
255 
257 {
258  return pathfind::get_teleport_locations(*unit_it, current_team(), true);
259 }
260 
261 void formula_ai::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
262 {
263  function_table_.add_function(name, std::make_shared<user_formula_function>(name, formula, precondition, args));
264 }
265 
266 namespace
267 {
268 template<typename Container>
269 variant villages_from_set(const Container& villages, const std::set<map_location>* exclude = nullptr)
270 {
271  std::vector<variant> vars;
272  for(const map_location& loc : villages) {
273  if(exclude && exclude->count(loc)) {
274  continue;
275  }
276  vars.emplace_back(std::make_shared<location_callable>(loc));
277  }
278 
279  return variant(vars);
280 }
281 
282 // TODO: I have no damn idea what to name this function
283 variant visit_helper(const utils::variant<bool, std::vector<std::string>>& input)
284 {
285  return utils::visit(
286  [](const auto& v) {
287  if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
288  return variant(v);
289  } else {
290  const std::vector<variant> vars(v.begin(), v.end());
291  return variant(vars);
292  }
293  },
294  input);
295 }
296 } // namespace
297 
298 variant formula_ai::get_value(const std::string& key) const
299 {
300  const unit_map& units = resources::gameboard->units();
301 
302  if(key == "aggression")
303  {
304  return variant(get_aggression()*1000,variant::DECIMAL_VARIANT);
305 
306  } else if(key == "avoid")
307  {
308  std::set<map_location> av_locs;
309  get_avoid().get_locations(av_locs);
310  return villages_from_set(av_locs);
311 
312  } else if(key == "caution")
313  {
314  return variant(get_caution()*1000,variant::DECIMAL_VARIANT);
315 
316  } else if(key == "grouping")
317  {
318  return variant(get_grouping());
319 
320  } else if(key == "leader_aggression")
321  {
322  return variant(get_leader_aggression()*1000,variant::DECIMAL_VARIANT);
323 
324  } else if(key == "leader_ignores_keep")
325  {
326  return visit_helper(get_leader_ignores_keep());
327 
328  } else if(key == "leader_value")
329  {
330  return variant(get_leader_value()*1000,variant::DECIMAL_VARIANT);
331 
332  } else if(key == "passive_leader")
333  {
334  return visit_helper(get_passive_leader());
335 
336  } else if(key == "passive_leader_shares_keep")
337  {
338  return visit_helper(get_passive_leader_shares_keep());
339 
340  } else if(key == "recruitment_pattern")
341  {
342  const std::vector<std::string> &rp = get_recruitment_pattern();
343  std::vector<variant> vars;
344  for(const std::string &i : rp) {
345  vars.emplace_back(i);
346  }
347  return variant(vars);
348 
349  } else if(key == "scout_village_targeting")
350  {
351  return variant(get_scout_village_targeting()*1000,variant::DECIMAL_VARIANT);
352 
353  } else if(key == "support_villages")
354  {
355  return variant(get_support_villages());
356 
357  } else if(key == "village_value")
358  {
359  return variant(get_village_value()*1000,variant::DECIMAL_VARIANT);
360 
361  } else if(key == "villages_per_scout")
362  {
364 
365  } else if(key == "attacks")
366  {
367  return get_attacks_as_variant();
368 
369  } else if(key == "turn")
370  {
371  return variant(resources::tod_manager->turn());
372 
373  } else if(key == "time_of_day")
374  {
375  return variant(resources::tod_manager->get_time_of_day().id);
376 
377  } else if(key == "my_side")
378  {
379  return variant(std::make_shared<team_callable>(resources::gameboard->get_team(get_side())));
380 
381  } else if(key == "my_side_number")
382  {
383  return variant(get_side()-1);
384 
385  } else if(key == "teams")
386  {
387  std::vector<variant> vars;
388  for(std::vector<team>::const_iterator i = resources::gameboard->teams().begin(); i != resources::gameboard->teams().end(); ++i) {
389  vars.emplace_back(std::make_shared<team_callable>(*i));
390  }
391  return variant(vars);
392 
393  } else if(key == "allies")
394  {
395  std::vector<variant> vars;
396  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
397  if ( !current_team().is_enemy( i+1 ) )
398  vars.emplace_back(i);
399  }
400  return variant(vars);
401 
402  } else if(key == "enemies")
403  {
404  std::vector<variant> vars;
405  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
406  if ( current_team().is_enemy( i+1 ) )
407  vars.emplace_back(i);
408  }
409  return variant(vars);
410 
411  } else if(key == "my_recruits")
412  {
413  std::vector<variant> vars;
414 
416 
417  const std::set<std::string>& recruits = current_team().recruits();
418  if(recruits.empty()) {
419  return variant(vars);
420  }
421  for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i)
422  {
423  const unit_type *ut = unit_types.find(*i);
424  if (ut)
425  {
426  vars.emplace_back(std::make_shared<unit_type_callable>(*ut));
427  }
428  }
429  return variant(vars);
430 
431  } else if(key == "recruits_of_side")
432  {
433  std::vector<variant> vars;
434  std::vector< std::vector< variant>> tmp;
435 
437 
438  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
439  {
440  std::vector<variant> v;
441  tmp.push_back( v );
442 
443  const std::set<std::string>& recruits = resources::gameboard->teams()[i].recruits();
444  if(recruits.empty()) {
445  continue;
446  }
447  for(std::set<std::string>::const_iterator str_it = recruits.begin(); str_it != recruits.end(); ++str_it)
448  {
449  const unit_type *ut = unit_types.find(*str_it);
450  if (ut)
451  {
452  tmp[i].emplace_back(std::make_shared<unit_type_callable>(*ut));
453  }
454  }
455  }
456 
457  for( std::size_t i = 0; i<tmp.size(); ++i)
458  vars.emplace_back(tmp[i]);
459  return variant(vars);
460 
461  } else if(key == "units")
462  {
463  std::vector<variant> vars;
464  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
465  vars.emplace_back(std::make_shared<unit_callable>(*i));
466  }
467  return variant(vars);
468 
469  } else if(key == "units_of_side")
470  {
471  std::vector<variant> vars;
472  std::vector< std::vector< variant>> tmp;
473  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
474  {
475  std::vector<variant> v;
476  tmp.push_back( v );
477  }
478  for(const unit &u : units) {
479  tmp[u.side() - 1].emplace_back(std::make_shared<unit_callable>(u));
480  }
481  for( std::size_t i = 0; i<tmp.size(); ++i)
482  vars.emplace_back(tmp[i]);
483  return variant(vars);
484 
485  } else if(key == "my_units")
486  {
487  std::vector<variant> vars;
488  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
489  if (i->side() == get_side()) {
490  vars.emplace_back(std::make_shared<unit_callable>(*i));
491  }
492  }
493  return variant(vars);
494 
495  } else if(key == "enemy_units")
496  {
497  std::vector<variant> vars;
498  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
499  if (current_team().is_enemy(i->side())) {
500  if (!i->incapacitated()) {
501  vars.emplace_back(std::make_shared<unit_callable>(*i));
502  }
503  }
504  }
505  return variant(vars);
506 
507  } else if(key == "my_moves")
508  {
509  return variant(std::make_shared<move_map_callable>(get_srcdst(), get_dstsrc(), units));
510 
511  } else if(key == "my_attacks")
512  {
514  } else if(key == "enemy_moves")
515  {
516  return variant(std::make_shared<move_map_callable>(get_enemy_srcdst(), get_enemy_dstsrc(), units));
517 
518  } else if(key == "my_leader")
519  {
521  if(i == units.end()) {
522  return variant();
523  }
524  return variant(std::make_shared<unit_callable>(*i));
525 
526  } else if(key == "recall_list")
527  {
528  std::vector<variant> tmp;
529 
530  for(std::vector<unit_ptr >::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) {
531  tmp.emplace_back(std::make_shared<unit_callable>(**i));
532  }
533 
534  return variant(tmp);
535 
536  } else if(key == "vars")
537  {
538  return variant(vars_.fake_ptr());
539  } else if(key == "keeps")
540  {
541  return get_keeps();
542  } else if(key == "map")
543  {
544  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
545  } else if(key == "villages")
546  {
547  return villages_from_set(resources::gameboard->map().villages());
548  } else if(key == "villages_of_side")
549  {
550  std::vector<variant> vars;
551  for(std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
552  {
553  vars.emplace_back();
554  }
555  for(std::size_t i = 0; i<vars.size(); ++i)
556  {
557  vars[i] = villages_from_set(resources::gameboard->teams()[i].villages());
558  }
559  return variant(vars);
560 
561  } else if(key == "my_villages")
562  {
563  return villages_from_set(current_team().villages());
564 
565  } else if(key == "enemy_and_unowned_villages")
566  {
567  return villages_from_set(resources::gameboard->map().villages(), &current_team().villages());
568  }
569 
570  return variant();
571 }
572 
574 {
575  add_input(inputs, "aggression");
576  add_input(inputs, "leader_aggression");
577  add_input(inputs, "caution");
578  add_input(inputs, "attacks");
579  add_input(inputs, "my_side");
580  add_input(inputs, "teams");
581  add_input(inputs, "turn");
582  add_input(inputs, "time_of_day");
583  add_input(inputs, "keeps");
584  add_input(inputs, "vars");
585  add_input(inputs, "allies");
586  add_input(inputs, "enemies");
587  add_input(inputs, "map");
588  add_input(inputs, "my_attacks");
589  add_input(inputs, "enemy_moves");
590  add_input(inputs, "my_leader");
591  add_input(inputs, "my_recruits");
592  //add_input(inputs, "recall_list");
593  add_input(inputs, "recruits_of_side");
594  add_input(inputs, "units");
595  add_input(inputs, "units_of_side");
596  add_input(inputs, "my_units");
597  add_input(inputs, "enemy_units");
598  add_input(inputs, "villages");
599  add_input(inputs, "my_villages");
600  add_input(inputs, "villages_of_side");
601  add_input(inputs, "enemy_and_unowned_villages");
602 }
603 
604 void formula_ai::set_value(const std::string& key, const variant& value) {
605  vars_.mutate_value(key, value);
606 }
607 
609 {
610  if(keeps_cache_.is_null()) {
611  std::vector<variant> vars;
612  for(std::size_t x = 0; x != std::size_t(resources::gameboard->map().w()); ++x) {
613  for(std::size_t y = 0; y != std::size_t(resources::gameboard->map().h()); ++y) {
614  const map_location loc(x,y);
615  if(resources::gameboard->map().is_keep(loc)) {
616  for(const map_location& adj : get_adjacent_tiles(loc)) {
617  if(resources::gameboard->map().is_castle(adj)) {
618  vars.emplace_back(std::make_shared<location_callable>(loc));
619  break;
620  }
621  }
622  }
623  }
624  }
625  keeps_cache_ = variant(vars);
626  }
627 
628  return keeps_cache_;
629 }
630 
632  if (tiles_adjacent(unit_A,unit_B)) {
633  return true;
634  }
635  move_map::const_iterator i;
636  std::pair<move_map::const_iterator,
637  move_map::const_iterator> unit_moves;
638 
639  unit_moves = get_srcdst().equal_range(unit_A);
640  for(i = unit_moves.first; i != unit_moves.second; ++i) {
641  if (tiles_adjacent((*i).second,unit_B)) {
642  return true;
643  }
644  }
645  return false;
646 }
647 
649  //make sure we don't run out of refcount
650 
651  for(const config &func : cfg_.child_range("function"))
652  {
653  const t_string &name = func["name"];
654  const t_string &inputs = func["inputs"];
655  const t_string &formula_str = func["formula"];
656 
657  std::vector<std::string> args = utils::split(inputs.str());
658  try {
660  create_optional_formula(formula_str),
661  create_optional_formula(func["precondition"]),
662  args);
663  }
664  catch(const formula_error& e) {
665  handle_exception(e, "Error while registering function '" + name + "'");
666  }
667  }
668 
670  if (const config &ai_vars = cfg_.child("vars"))
671  {
672  variant var;
673  for(const config::attribute &i : ai_vars.attribute_range()) {
674  var.serialize_from_string(i.second);
675  vars_.add(i.first, var);
676  }
677  }
678 
679 }
680 
682 {
683  fai_ca->evaluate(this,resources::gameboard->units());
684 
685 }
686 
688 {
689  map_formula_callable callable(fake_ptr());
690  fai_ca->update_callable_map( callable );
691  const_formula_ptr move_formula(fai_ca->get_action());
692  return !make_action(move_formula, callable).is_empty();
693 }
694 
695 #if 0
696 formula_ai::gamestate_change_observer::gamestate_change_observer() :
697  set_var_counter_(), set_unit_var_counter_(), continue_counter_()
698 {
700 }
701 
702 formula_ai::gamestate_change_observer::~gamestate_change_observer() {
704 }
705 
706 void formula_ai::gamestate_change_observer::handle_generic_event(const std::string& /*event_name*/) {
707  set_var_counter_ = 0;
708  set_unit_var_counter_ = 0;
709  continue_counter_ = 0;
710 }
711 
712 //return false if number of calls exceeded MAX_CALLS
713 bool formula_ai::gamestate_change_observer::set_var_check() {
714  if(set_var_counter_ >= MAX_CALLS)
715  return false;
716 
717  set_var_counter_++;
718  return true;
719 }
720 
721 bool formula_ai::gamestate_change_observer::set_unit_var_check() {
722  if(set_unit_var_counter_ >= MAX_CALLS)
723  return false;
724 
725  set_unit_var_counter_++;
726  return true;
727 }
728 
729 bool formula_ai::gamestate_change_observer::continue_check() {
730  if(continue_counter_ >= MAX_CALLS)
731  return false;
732 
733  continue_counter_++;
734  return true;
735 }
736 #endif
737 
739 {
740  if (!cfg_)
741  {
742  return config();
743  }
744  DBG_AI << "formula_ai::to_config(): "<< cfg_<<std::endl;
745  config cfg = cfg_;
746 
747  //formula AI variables
748  cfg.clear_children("vars");
749  if (vars_.empty() == false) {
750  config &ai_vars = cfg.add_child("vars");
751 
752  std::string str;
754  {
755  try {
756  str = i->second.serialize_to_string();
757  } catch(const type_error&) {
758  WRN_AI << "variable ["<< i->first <<"] is not serializable - it will not be persisted across savegames"<<std::endl;
759  continue;
760  }
761  if (!str.empty())
762  {
763  ai_vars[i->first] = str;
764  str.clear();
765  }
766  }
767  }
768 
769  return cfg;
770 }
771 
772 } // end of namespace ai
Defines formula ai.
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
virtual std::string get_grouping() const override
Definition: contexts.hpp:626
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:415
::tod_manager * tod_manager
Definition: resources.cpp:29
virtual const move_map & get_enemy_srcdst() const override
Definition: contexts.hpp:606
virtual int get_villages_per_scout() const override
Definition: contexts.hpp:736
unit_iterator end()
Definition: map.hpp:428
formula_ai(const formula_ai &)=delete
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1222
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:82
const_iterator begin() const
Definition: callable.hpp:269
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:116
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
virtual const unit_map & units() const override
Definition: game_board.hpp:109
Defines formula ai candidate actions - headers.
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:226
void clear_children(T... keys)
Definition: config.hpp:489
This class represents a single unit of a specific type.
Definition: unit.hpp:120
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
std::string formula
Definition: formula.hpp:106
static manager & get_singleton()
Definition: manager.hpp:143
unit_iterator find_leader(int side)
Definition: map.cpp:327
bool execute_candidate_action(wfl::candidate_action_ptr fai_ca)
Execute the fai candidate action.
Definition: ai.cpp:687
const config cfg_
Definition: ai.hpp:153
std::string filename
Definition: formula.hpp:107
virtual double get_leader_value() const override
Definition: contexts.hpp:656
Managing the AI-Game interaction - AI actions and their results.
void display_message(const std::string &msg) const
Definition: ai.cpp:135
static lg::log_domain log_formula_ai("ai/engine/fai")
child_itors child_range(config_key_type key)
Definition: config.cpp:357
wfl::candidate_action_ptr ca_ptr
Definition: ai.cpp:73
attribute_map::value_type attribute
Definition: config.hpp:220
virtual double get_village_value() const override
Definition: contexts.hpp:731
virtual const move_map & get_srcdst() const override
Definition: contexts.hpp:711
virtual config to_config() const
Definition: ai.cpp:738
unit_iterator begin()
Definition: map.hpp:418
std::vector< formula_input > formula_input_vector
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
Definition: types.cpp:1264
Composite AI stages.
unit_type_data unit_types
Definition: types.cpp:1441
std::string evaluate(const std::string &formula_str)
Definition: ai.cpp:157
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
void clear()
Definition: config.cpp:858
virtual wfl::variant get_value(const std::string &key) const override
Definition: ai.cpp:298
void get_locations(std::set< map_location > &locs, bool with_border=false) const
gets all locations on the map that match this filter
Definition: filter.hpp:62
#define WRN_AI
Definition: ai.cpp:66
A single unit type that the player may recruit.
Definition: types.hpp:44
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
void on_create()
Definition: ai.cpp:648
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader() const override
Definition: contexts.hpp:661
bool can_reach_unit(map_location unit_A, map_location unit_B) const
Definition: ai.cpp:631
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event...
Definition: manager.cpp:342
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:252
bool valid() const
Definition: location.hpp:88
void set_value(const std::string &key, const wfl::variant &value) override
Definition: ai.cpp:604
virtual double get_leader_aggression() const override
Definition: contexts.hpp:641
std::string type
Definition: formula.hpp:105
virtual utils::variant< bool, std::vector< std::string > > get_leader_ignores_keep() const override
Definition: contexts.hpp:651
game_board * gameboard
Definition: resources.cpp:20
void serialize_from_string(const std::string &str)
Definition: variant.cpp:629
void evaluate_candidate_action(wfl::candidate_action_ptr fai_ca)
Evaluate the fai candidate action.
Definition: ai.cpp:681
bool is_enemy(int n) const
Definition: team.hpp:251
virtual void add_formula_function(const std::string &name, wfl::const_formula_ptr formula, wfl::const_formula_ptr precondition, const std::vector< std::string > &args)
Definition: ai.cpp:261
virtual const move_map & get_enemy_dstsrc() const override
Definition: contexts.hpp:596
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
virtual const std::vector< std::string > get_recruitment_pattern() const override
Definition: contexts.hpp:696
iterator end()
end iterator
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except it uses the decayed form of V.
Definition: general.hpp:34
wfl::attack_map_callable attacks_callable
Definition: ai.hpp:161
Encapsulates the map of the game.
Definition: location.hpp:37
unit_iterator find(std::size_t id)
Definition: map.cpp:309
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:502
#define LOG_AI
Definition: ai.cpp:65
std::size_t i
Definition: function.cpp:933
formula_callable_ptr fake_ptr()
Definition: callable.hpp:41
virtual const team & current_team() const override
Definition: contexts.hpp:450
virtual void get_inputs(wfl::formula_input_vector &inputs) const override
Definition: ai.cpp:573
wfl::map_formula_callable vars_
Definition: ai.hpp:164
Game information for the AI.
recursion_counter recursion_counter_
Definition: ai.hpp:154
Default AI contexts.
#define DBG_AI
Definition: ai.cpp:64
std::string name
Definition: sdl_ttf.cpp:70
virtual double get_scout_village_targeting() const override
Definition: contexts.hpp:716
#define ERR_AI
Definition: ai.cpp:67
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:396
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:39
int w
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:23
formula_input_vector inputs() const
Definition: callable.hpp:62
config & add_child(config_key_type key)
Definition: config.cpp:471
wfl::candidate_action_ptr load_candidate_action_from_config(const config &cfg)
Definition: ai.cpp:75
void mutate_value(const std::string &key, const variant &value)
Definition: callable.hpp:57
std::shared_ptr< base_candidate_action > candidate_action_ptr
Definition: candidates.hpp:36
display_chat_manager & get_chat_manager()
virtual const move_map & get_dstsrc() const override
Definition: contexts.hpp:591
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:61
std::map< std::string, variant >::const_iterator const_iterator
Definition: callable.hpp:267
virtual double get_aggression() const override
Definition: contexts.hpp:546
virtual const wfl::variant & get_attacks_as_variant() const override
Definition: contexts.hpp:576
const_iterator end() const
Definition: callable.hpp:270
#define f
Definition: contexts.hpp:43
wfl::ai_function_symbol_table function_table_
Definition: ai.hpp:167
std::vector< std::string > split(const config_attribute_value &val)
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:336
Composite AI contexts.
Standard logging facilities (interface).
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units, bool check_vision)
Definition: teleport.cpp:265
static config unit_moves(reports::context &rc, const unit *u, bool is_visible_unit)
Definition: reports.cpp:646
recall_list_manager & recall_list()
Definition: team.hpp:223
void add_function(const std::string &name, formula_function_ptr &&fcn)
Definition: function.cpp:1426
Container associating units to locations.
Definition: map.hpp:97
int get_count() const
Get the current value of the recursion counter.
Definition: contexts.hpp:69
MacOS doesn&#39;t support std::visit when targing MacOS < 10.14 (currently we target 10.11).
virtual bool get_support_villages() const override
Definition: contexts.hpp:726
#define e
pathfind::plain_route shortest_path_calculator(const map_location &src, const map_location &dst, unit_map::iterator &unit_it, pathfind::teleport_map &allowed_teleports) const
Definition: ai.cpp:203
virtual const terrain_filter & get_avoid() const override
Definition: contexts.hpp:581
wfl::variant keeps_cache_
Definition: ai.hpp:160
static void add_input(formula_input_vector &inputs, const std::string &key, FORMULA_ACCESS_TYPE access_type=FORMULA_READ_ONLY)
Definition: callable.hpp:135
int get_recursion_count() const override
Get the value of the recursion counter.
Definition: ai.cpp:95
wfl::formula_ptr create_optional_formula(const std::string &formula_string) const
Create a new formula from the string, using the symbol table which is stored in the AI...
Definition: ai.cpp:142
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
pathfind::teleport_map get_allowed_teleports(unit_map::iterator &unit_it) const
Definition: ai.cpp:256
const std::string & str() const
Definition: tstring.hpp:186
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:185
ai_context * ai_ptr_
Definition: ai.hpp:152
virtual double get_caution() const override
Definition: contexts.hpp:586
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader_shares_keep() const override
Definition: contexts.hpp:666
static map_location::DIRECTION n
This module contains various pathfinding functions and utilities.
void set_ai_context(ai_context *context)
Definition: ai.cpp:152
wfl::variant get_keeps() const
Definition: ai.cpp:608
bool is_empty() const
Definition: variant.cpp:265
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:434
const std::set< std::string > & recruits() const
Definition: team.hpp:231
static game_display * get_singleton()
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:643
std::shared_ptr< formula > formula_ptr
Definition: formula_fwd.hpp:21