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