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