The Battle for Wesnoth  1.19.0-dev
ai.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
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 t_string &name = rc_action["name"];
70  try {
71  const t_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 {
128  game_display::get_singleton()->get_chat_manager().add_chat_message(std::time(nullptr), "wfl", get_side(), msg,
130 
131 }
132 
133 formula_ptr formula_ai::create_optional_formula(const std::string& formula_string) const {
134  try{
135  return formula::create_optional_formula(formula_string, &function_table_);
136  }
137  catch(const formula_error& e) {
139  return wfl::formula_ptr();
140  }
141 }
142 
144 {
145  ai_ptr_ = context;
146 }
147 
148 std::string formula_ai::evaluate(const std::string& formula_str)
149 {
150  try{
151 
152  formula f(formula_str, &function_table_);
153 
154  map_formula_callable callable(fake_ptr());
155 
156  //formula_debugger fdb;
157  const variant v = f.evaluate(callable,nullptr);
158 
159  if (ai_ptr_) {
160  variant var = variant(this->fake_ptr()).execute_variant(v);
161 
162  if ( !var.is_empty() ) {
163  return "Made move: " + var.to_debug_string();
164  }
165  }
166 
167  return v.to_debug_string();
168  }
169  catch(formula_error& e) {
170  e.line = 0;
172  throw;
173  }
174 }
175 
177 {
178  if (!formula_) {
179  throw formula_error("null formula passed to make_action","","formula",0);
180  }
181  LOG_AI << "do move...";
182  const variant var = formula_->evaluate(variables);
183  variant res;
184 
185  if (ai_ptr_) {
186  res = variant(this->fake_ptr()).execute_variant(var);
187  } else {
188  ERR_AI << "skipped execution of action because ai context is not set correctly";
189  }
190 
191  return res;
192 }
193 
195  const map_location &dst, unit_map::iterator &unit_it,
196  pathfind::teleport_map& allowed_teleports) const
197 {
198  map_location destination = dst;
199 
200  unit_map &units_ = resources::gameboard->units();
202 
203  unit_map::const_iterator dst_un = units_.find(destination);
204 
205  map_location res;
206 
207  if( dst_un != units_.end() ) {
208  //there is unit standing at dst, let's try to find free hex to move to
209  const map_location::DIRECTION preferred = destination.get_relative_dir(src);
210 
211  int best_rating = 100;//smaller is better
212  const auto adj = get_adjacent_tiles(destination);
213 
214  for(std::size_t n = 0; n < adj.size(); ++n) {
215  if(resources::gameboard->map().on_board(adj[n]) == false) {
216  continue;
217  }
218 
219  if(units_.find(adj[n]) != units_.end()) {
220  continue;
221  }
222 
223  static const std::size_t NDIRECTIONS = map_location::NDIRECTIONS;
224  unsigned int difference = std::abs(static_cast<int>(preferred - n));
225  if(difference > NDIRECTIONS/2) {
226  difference = NDIRECTIONS - difference;
227  }
228 
229  const int rating = difference * 2;
230  if(rating < best_rating || res.valid() == false) {
231  best_rating = rating;
232  res = adj[n];
233  }
234  }
235  }
236 
237  if( res != map_location() ) {
238  destination = res;
239  }
240 
241  pathfind::plain_route route = pathfind::a_star_search(src, destination,
242  1000.0, calc, resources::gameboard->map().w(),
243  resources::gameboard->map().h(), &allowed_teleports);
244 
245  return route;
246 }
247 
249 {
250  return pathfind::get_teleport_locations(*unit_it, current_team(), true);
251 }
252 
253 void formula_ai::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
254 {
255  function_table_.add_function(name, std::make_shared<user_formula_function>(name, formula, precondition, args));
256 }
257 
258 namespace
259 {
260 template<typename Container>
261 variant villages_from_set(const Container& villages, const std::set<map_location>* exclude = nullptr)
262 {
263  std::vector<variant> vars;
264  for(const map_location& loc : villages) {
265  if(exclude && exclude->count(loc)) {
266  continue;
267  }
268  vars.emplace_back(std::make_shared<location_callable>(loc));
269  }
270 
271  return variant(vars);
272 }
273 
274 // TODO: I have no damn idea what to name this function
275 variant visit_helper(const utils::variant<bool, std::vector<std::string>>& input)
276 {
277  return utils::visit(
278  [](const auto& v) {
279  if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
280  return variant(v);
281  } else {
282  const std::vector<variant> vars(v.begin(), v.end());
283  return variant(vars);
284  }
285  },
286  input);
287 }
288 } // namespace
289 
290 variant formula_ai::get_value(const std::string& key) const
291 {
292  const unit_map& units = resources::gameboard->units();
293 
294  if(key == "aggression")
295  {
296  return variant(get_aggression()*1000,variant::DECIMAL_VARIANT);
297 
298  } else if(key == "allow_ally_villages")
299  {
300  return visit_helper(get_allow_ally_villages());
301 
302  } else if(key == "avoid")
303  {
304  std::set<map_location> av_locs;
305  get_avoid().get_locations(av_locs);
306  return villages_from_set(av_locs);
307 
308  } else if(key == "caution")
309  {
310  return variant(get_caution()*1000,variant::DECIMAL_VARIANT);
311 
312  } else if(key == "grouping")
313  {
314  return variant(get_grouping());
315 
316  } else if(key == "leader_aggression")
317  {
318  return variant(get_leader_aggression()*1000,variant::DECIMAL_VARIANT);
319 
320  } else if(key == "leader_ignores_keep")
321  {
322  return visit_helper(get_leader_ignores_keep());
323 
324  } else if(key == "leader_value")
325  {
326  return variant(get_leader_value()*1000,variant::DECIMAL_VARIANT);
327 
328  } else if(key == "passive_leader")
329  {
330  return visit_helper(get_passive_leader());
331 
332  } else if(key == "passive_leader_shares_keep")
333  {
334  return visit_helper(get_passive_leader_shares_keep());
335 
336  } else if(key == "recruitment_pattern")
337  {
338  const std::vector<std::string> &rp = get_recruitment_pattern();
339  std::vector<variant> vars;
340  for(const std::string &i : rp) {
341  vars.emplace_back(i);
342  }
343  return variant(vars);
344 
345  } else if(key == "retreat_enemy_weight")
346  {
347  return variant(get_retreat_enemy_weight()*1000,variant::DECIMAL_VARIANT);
348 
349  } else if(key == "retreat_factor")
350  {
351  return variant(get_retreat_factor()*1000,variant::DECIMAL_VARIANT);
352 
353  } else if(key == "scout_village_targeting")
354  {
355  return variant(get_scout_village_targeting()*1000,variant::DECIMAL_VARIANT);
356 
357  } else if(key == "support_villages")
358  {
359  return variant(get_support_villages());
360 
361  } else if(key == "village_value")
362  {
363  return variant(get_village_value()*1000,variant::DECIMAL_VARIANT);
364 
365  } else if(key == "villages_per_scout")
366  {
368 
369  } else if(key == "attacks")
370  {
371  return get_attacks_as_variant();
372 
373  } else if(key == "turn")
374  {
375  return variant(resources::tod_manager->turn());
376 
377  } else if(key == "time_of_day")
378  {
379  return variant(resources::tod_manager->get_time_of_day().id);
380 
381  } else if(key == "my_side")
382  {
383  return variant(std::make_shared<team_callable>(resources::gameboard->get_team(get_side())));
384 
385  } else if(key == "my_side_number")
386  {
387  return variant(get_side()-1);
388 
389  } else if(key == "teams")
390  {
391  std::vector<variant> vars;
392  for(std::vector<team>::const_iterator i = resources::gameboard->teams().begin(); i != resources::gameboard->teams().end(); ++i) {
393  vars.emplace_back(std::make_shared<team_callable>(*i));
394  }
395  return variant(vars);
396 
397  } else if(key == "allies")
398  {
399  std::vector<variant> vars;
400  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
401  if ( !current_team().is_enemy( i+1 ) )
402  vars.emplace_back(i);
403  }
404  return variant(vars);
405 
406  } else if(key == "enemies")
407  {
408  std::vector<variant> vars;
409  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
410  if ( current_team().is_enemy( i+1 ) )
411  vars.emplace_back(i);
412  }
413  return variant(vars);
414 
415  } else if(key == "my_recruits")
416  {
417  std::vector<variant> vars;
418 
420 
421  const std::set<std::string>& recruits = current_team().recruits();
422  if(recruits.empty()) {
423  return variant(vars);
424  }
425  for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i)
426  {
427  const unit_type *ut = unit_types.find(*i);
428  if (ut)
429  {
430  vars.emplace_back(std::make_shared<unit_type_callable>(*ut));
431  }
432  }
433  return variant(vars);
434 
435  } else if(key == "recruits_of_side")
436  {
437  std::vector<variant> vars;
438  std::vector< std::vector< variant>> tmp;
439 
441 
442  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
443  {
444  std::vector<variant> v;
445  tmp.push_back( v );
446 
447  const std::set<std::string>& recruits = resources::gameboard->teams()[i].recruits();
448  if(recruits.empty()) {
449  continue;
450  }
451  for(std::set<std::string>::const_iterator str_it = recruits.begin(); str_it != recruits.end(); ++str_it)
452  {
453  const unit_type *ut = unit_types.find(*str_it);
454  if (ut)
455  {
456  tmp[i].emplace_back(std::make_shared<unit_type_callable>(*ut));
457  }
458  }
459  }
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 == "units")
466  {
467  std::vector<variant> vars;
468  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
469  vars.emplace_back(std::make_shared<unit_callable>(*i));
470  }
471  return variant(vars);
472 
473  } else if(key == "units_of_side")
474  {
475  std::vector<variant> vars;
476  std::vector< std::vector< variant>> tmp;
477  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
478  {
479  std::vector<variant> v;
480  tmp.push_back( v );
481  }
482  for(const unit &u : units) {
483  tmp[u.side() - 1].emplace_back(std::make_shared<unit_callable>(u));
484  }
485  for( std::size_t i = 0; i<tmp.size(); ++i)
486  vars.emplace_back(tmp[i]);
487  return variant(vars);
488 
489  } else if(key == "my_units")
490  {
491  std::vector<variant> vars;
492  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
493  if (i->side() == get_side()) {
494  vars.emplace_back(std::make_shared<unit_callable>(*i));
495  }
496  }
497  return variant(vars);
498 
499  } else if(key == "enemy_units")
500  {
501  std::vector<variant> vars;
502  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
503  if (current_team().is_enemy(i->side())) {
504  if (!i->incapacitated()) {
505  vars.emplace_back(std::make_shared<unit_callable>(*i));
506  }
507  }
508  }
509  return variant(vars);
510 
511  } else if(key == "my_moves")
512  {
513  return variant(std::make_shared<move_map_callable>(get_srcdst(), get_dstsrc(), units));
514 
515  } else if(key == "my_attacks")
516  {
518  } else if(key == "enemy_moves")
519  {
520  return variant(std::make_shared<move_map_callable>(get_enemy_srcdst(), get_enemy_dstsrc(), units));
521 
522  } else if(key == "my_leader")
523  {
525  if(i == units.end()) {
526  return variant();
527  }
528  return variant(std::make_shared<unit_callable>(*i));
529 
530  } else if(key == "recall_list")
531  {
532  std::vector<variant> tmp;
533 
534  for(std::vector<unit_ptr >::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) {
535  tmp.emplace_back(std::make_shared<unit_callable>(**i));
536  }
537 
538  return variant(tmp);
539 
540  } else if(key == "vars")
541  {
542  return variant(vars_.fake_ptr());
543  } else if(key == "keeps")
544  {
545  return get_keeps();
546  } else if(key == "map")
547  {
548  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
549  } else if(key == "villages")
550  {
551  return villages_from_set(resources::gameboard->map().villages());
552  } else if(key == "villages_of_side")
553  {
554  std::vector<variant> vars;
555  for(std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
556  {
557  vars.emplace_back();
558  }
559  for(std::size_t i = 0; i<vars.size(); ++i)
560  {
561  vars[i] = villages_from_set(resources::gameboard->teams()[i].villages());
562  }
563  return variant(vars);
564 
565  } else if(key == "my_villages")
566  {
567  return villages_from_set(current_team().villages());
568 
569  } else if(key == "enemy_and_unowned_villages")
570  {
571  return villages_from_set(resources::gameboard->map().villages(), &current_team().villages());
572  }
573  else if(key == "world") {
574  return variant(std::make_shared<gamestate_callable>());
575  }
576 
577  return variant();
578 }
579 
581 {
582  add_input(inputs, "aggression");
583  add_input(inputs, "leader_aggression");
584  add_input(inputs, "caution");
585  add_input(inputs, "attacks");
586  add_input(inputs, "my_side");
587  add_input(inputs, "teams");
588  add_input(inputs, "turn");
589  add_input(inputs, "time_of_day");
590  add_input(inputs, "keeps");
591  add_input(inputs, "vars");
592  add_input(inputs, "allies");
593  add_input(inputs, "enemies");
594  add_input(inputs, "map");
595  add_input(inputs, "my_attacks");
596  add_input(inputs, "enemy_moves");
597  add_input(inputs, "my_leader");
598  add_input(inputs, "my_recruits");
599  //add_input(inputs, "recall_list");
600  add_input(inputs, "recruits_of_side");
601  add_input(inputs, "units");
602  add_input(inputs, "units_of_side");
603  add_input(inputs, "my_units");
604  add_input(inputs, "enemy_units");
605  add_input(inputs, "villages");
606  add_input(inputs, "my_villages");
607  add_input(inputs, "villages_of_side");
608  add_input(inputs, "enemy_and_unowned_villages");
609  add_input(inputs, "world");
610 }
611 
612 void formula_ai::set_value(const std::string& key, const variant& value) {
613  vars_.mutate_value(key, value);
614 }
615 
617 {
618  if(keeps_cache_.is_null()) {
619  std::vector<variant> vars;
620  for(std::size_t x = 0; x != std::size_t(resources::gameboard->map().w()); ++x) {
621  for(std::size_t y = 0; y != std::size_t(resources::gameboard->map().h()); ++y) {
622  const map_location loc(x,y);
623  if(resources::gameboard->map().is_keep(loc)) {
624  for(const map_location& adj : get_adjacent_tiles(loc)) {
625  if(resources::gameboard->map().is_castle(adj)) {
626  vars.emplace_back(std::make_shared<location_callable>(loc));
627  break;
628  }
629  }
630  }
631  }
632  }
633  keeps_cache_ = variant(vars);
634  }
635 
636  return keeps_cache_;
637 }
638 
640  if (tiles_adjacent(unit_A,unit_B)) {
641  return true;
642  }
643  move_map::const_iterator i;
644  std::pair<move_map::const_iterator,
645  move_map::const_iterator> unit_moves;
646 
647  unit_moves = get_srcdst().equal_range(unit_A);
648  for(i = unit_moves.first; i != unit_moves.second; ++i) {
649  if (tiles_adjacent((*i).second,unit_B)) {
650  return true;
651  }
652  }
653  return false;
654 }
655 
657  //make sure we don't run out of refcount
658 
659  for(const config &func : cfg_.child_range("function"))
660  {
661  const t_string &name = func["name"];
662  const t_string &inputs = func["inputs"];
663  const t_string &formula_str = func["formula"];
664 
665  std::vector<std::string> args = utils::split(inputs.str());
666  try {
668  create_optional_formula(formula_str),
669  create_optional_formula(func["precondition"]),
670  args);
671  }
672  catch(const formula_error& e) {
673  handle_exception(e, "Error while registering function '" + name + "'");
674  }
675  }
676 
678  if (const auto ai_vars = cfg_.optional_child("vars"))
679  {
680  variant var;
681  for(const config::attribute &i : ai_vars->attribute_range()) {
682  var.serialize_from_string(i.second);
683  vars_.add(i.first, var);
684  }
685  }
686 
687 }
688 
690 {
691  fai_ca->evaluate(this,resources::gameboard->units());
692 
693 }
694 
696 {
697  map_formula_callable callable(fake_ptr());
698  fai_ca->update_callable_map( callable );
699  const_formula_ptr move_formula(fai_ca->get_action());
700  return !make_action(move_formula, callable).is_empty();
701 }
702 
703 #if 0
704 formula_ai::gamestate_change_observer::gamestate_change_observer() :
705  set_var_counter_(), set_unit_var_counter_(), continue_counter_()
706 {
708 }
709 
710 formula_ai::gamestate_change_observer::~gamestate_change_observer() {
712 }
713 
714 void formula_ai::gamestate_change_observer::handle_generic_event(const std::string& /*event_name*/) {
715  set_var_counter_ = 0;
716  set_unit_var_counter_ = 0;
717  continue_counter_ = 0;
718 }
719 
720 //return false if number of calls exceeded MAX_CALLS
721 bool formula_ai::gamestate_change_observer::set_var_check() {
722  if(set_var_counter_ >= MAX_CALLS)
723  return false;
724 
725  set_var_counter_++;
726  return true;
727 }
728 
729 bool formula_ai::gamestate_change_observer::set_unit_var_check() {
730  if(set_unit_var_counter_ >= MAX_CALLS)
731  return false;
732 
733  set_unit_var_counter_++;
734  return true;
735 }
736 
737 bool formula_ai::gamestate_change_observer::continue_check() {
738  if(continue_counter_ >= MAX_CALLS)
739  return false;
740 
741  continue_counter_++;
742  return true;
743 }
744 #endif
745 
747 {
748  DBG_AI << "formula_ai::to_config(): "<< cfg_;
749  config cfg = cfg_;
750 
751  //formula AI variables
752  cfg.clear_children("vars");
753  if (vars_.empty() == false) {
754  config &ai_vars = cfg.add_child("vars");
755 
756  std::string str;
758  {
759  try {
760  str = i->second.serialize_to_string();
761  } catch(const type_error&) {
762  WRN_AI << "variable ["<< i->first <<"] is not serializable - it will not be persisted across savegames";
763  continue;
764  }
765  if (!str.empty())
766  {
767  ai_vars[i->first] = str;
768  str.clear();
769  }
770  }
771  }
772 
773  return cfg;
774 }
775 
776 } // end of namespace ai
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:253
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:176
bool can_reach_unit(map_location unit_A, map_location unit_B) const
Definition: ai.cpp:639
recursion_counter recursion_counter_
Definition: ai.hpp:152
ai_context * ai_ptr_
Definition: ai.hpp:150
pathfind::teleport_map get_allowed_teleports(unit_map::iterator &unit_it) const
Definition: ai.cpp:248
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:107
wfl::ai_function_symbol_table function_table_
Definition: ai.hpp:165
void evaluate_candidate_action(wfl::candidate_action_ptr fai_ca)
Evaluate the fai candidate action.
Definition: ai.cpp:689
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:133
formula_ai(const formula_ai &)=delete
void set_value(const std::string &key, const wfl::variant &value) override
Definition: ai.cpp:612
wfl::candidate_action_ptr load_candidate_action_from_config(const config &cfg)
Definition: ai.cpp:66
wfl::variant get_keeps() const
Definition: ai.cpp:616
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:194
std::string evaluate(const std::string &formula_str)
Definition: ai.cpp:148
void set_ai_context(ai_context *context)
Definition: ai.cpp:143
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:580
virtual config to_config() const
Definition: ai.cpp:746
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
bool execute_candidate_action(wfl::candidate_action_ptr fai_ca)
Execute the fai candidate action.
Definition: ai.cpp:695
void on_create()
Definition: ai.cpp:656
const config cfg_
Definition: ai.hpp:151
wfl::variant keeps_cache_
Definition: ai.hpp:158
virtual wfl::variant get_value(const std::string &key) const override
Definition: ai.cpp:290
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:375
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:369
static manager & get_singleton()
Definition: manager.hpp:142
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:159
void clear_children(T... keys)
Definition: config.hpp:642
child_itors child_range(config_key_type key)
Definition: config.cpp:273
attribute_map::value_type attribute
Definition: config.hpp:299
void clear()
Definition: config.cpp:831
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:385
config & add_child(config_key_type key)
Definition: config.cpp:441
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:79
virtual const unit_map & units() const override
Definition: game_board.hpp:106
static game_display * get_singleton()
display_chat_manager & get_chat_manager()
iterator end()
end iterator
recall_list_manager & recall_list()
Definition: team.hpp:201
const std::set< std::string > & recruits() const
Definition: team.hpp:209
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 begin()
Definition: map.hpp:418
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:1266
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
Definition: types.cpp:1308
A single unit type that the player may recruit.
Definition: types.hpp:43
@ FULL
Definition: types.hpp:74
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: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: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: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:474
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:502
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:270
::tod_manager * tod_manager
Definition: resources.cpp:29
game_board * gameboard
Definition: resources.cpp:20
std::size_t size(const std::string &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:33
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.
static config unit_moves(const reports::context &rc, const unit *u, bool is_visible_unit)
Definition: reports.cpp:667
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:226
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:1485
MacOS doesn't support std::visit when targing MacOS < 10.14 (currently we target 10....
#define e
#define h
#define f