The Battle for Wesnoth  1.17.0-dev
ai.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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 << std::endl;
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),
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"<< std::endl;
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 << std::endl;
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 << std::endl;
129  display_message(e.type + " in " + e.filename + ":" + std::to_string(e.line));
130  } else {
131  LOG_AI << e.type << std::endl;
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) {
148  handle_exception(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;
181  handle_exception(e);
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...\n";
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" << std::endl;
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, 1000.0, calc,
252  resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
253 
254  return route;
255 }
256 
258 {
259  return pathfind::get_teleport_locations(*unit_it, current_team(), true);
260 }
261 
262 void formula_ai::add_formula_function(const std::string& name, const_formula_ptr formula, const_formula_ptr precondition, const std::vector<std::string>& args)
263 {
264  function_table_.add_function(name, std::make_shared<user_formula_function>(name, formula, precondition, args));
265 }
266 
267 namespace
268 {
269 template<typename Container>
270 variant villages_from_set(const Container& villages, const std::set<map_location>* exclude = nullptr)
271 {
272  std::vector<variant> vars;
273  for(const map_location& loc : villages) {
274  if(exclude && exclude->count(loc)) {
275  continue;
276  }
277  vars.emplace_back(std::make_shared<location_callable>(loc));
278  }
279 
280  return variant(vars);
281 }
282 
283 // TODO: I have no damn idea what to name this function
284 variant visit_helper(const utils::variant<bool, std::vector<std::string>>& input)
285 {
286  return utils::visit(
287  [](const auto& v) {
288  if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
289  return variant(v);
290  } else {
291  const std::vector<variant> vars(v.begin(), v.end());
292  return variant(vars);
293  }
294  },
295  input);
296 }
297 } // namespace
298 
299 variant formula_ai::get_value(const std::string& key) const
300 {
301  const unit_map& units = resources::gameboard->units();
302 
303  if(key == "aggression")
304  {
305  return variant(get_aggression()*1000,variant::DECIMAL_VARIANT);
306 
307  } else if(key == "avoid")
308  {
309  std::set<map_location> av_locs;
310  get_avoid().get_locations(av_locs);
311  return villages_from_set(av_locs);
312 
313  } else if(key == "caution")
314  {
315  return variant(get_caution()*1000,variant::DECIMAL_VARIANT);
316 
317  } else if(key == "grouping")
318  {
319  return variant(get_grouping());
320 
321  } else if(key == "leader_aggression")
322  {
323  return variant(get_leader_aggression()*1000,variant::DECIMAL_VARIANT);
324 
325  } else if(key == "leader_ignores_keep")
326  {
327  return visit_helper(get_leader_ignores_keep());
328 
329  } else if(key == "leader_value")
330  {
331  return variant(get_leader_value()*1000,variant::DECIMAL_VARIANT);
332 
333  } else if(key == "passive_leader")
334  {
335  return visit_helper(get_passive_leader());
336 
337  } else if(key == "passive_leader_shares_keep")
338  {
339  return visit_helper(get_passive_leader_shares_keep());
340 
341  } else if(key == "recruitment_pattern")
342  {
343  const std::vector<std::string> &rp = get_recruitment_pattern();
344  std::vector<variant> vars;
345  for(const std::string &i : rp) {
346  vars.emplace_back(i);
347  }
348  return variant(vars);
349 
350  } else if(key == "retreat_enemy_weight")
351  {
352  return variant(get_retreat_enemy_weight()*1000,variant::DECIMAL_VARIANT);
353 
354  } else if(key == "retreat_factor")
355  {
356  return variant(get_retreat_factor()*1000,variant::DECIMAL_VARIANT);
357 
358  } else if(key == "scout_village_targeting")
359  {
360  return variant(get_scout_village_targeting()*1000,variant::DECIMAL_VARIANT);
361 
362  } else if(key == "support_villages")
363  {
364  return variant(get_support_villages());
365 
366  } else if(key == "village_value")
367  {
368  return variant(get_village_value()*1000,variant::DECIMAL_VARIANT);
369 
370  } else if(key == "villages_per_scout")
371  {
373 
374  } else if(key == "attacks")
375  {
376  return get_attacks_as_variant();
377 
378  } else if(key == "turn")
379  {
380  return variant(resources::tod_manager->turn());
381 
382  } else if(key == "time_of_day")
383  {
384  return variant(resources::tod_manager->get_time_of_day().id);
385 
386  } else if(key == "my_side")
387  {
388  return variant(std::make_shared<team_callable>(resources::gameboard->get_team(get_side())));
389 
390  } else if(key == "my_side_number")
391  {
392  return variant(get_side()-1);
393 
394  } else if(key == "teams")
395  {
396  std::vector<variant> vars;
397  for(std::vector<team>::const_iterator i = resources::gameboard->teams().begin(); i != resources::gameboard->teams().end(); ++i) {
398  vars.emplace_back(std::make_shared<team_callable>(*i));
399  }
400  return variant(vars);
401 
402  } else if(key == "allies")
403  {
404  std::vector<variant> vars;
405  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
406  if ( !current_team().is_enemy( i+1 ) )
407  vars.emplace_back(i);
408  }
409  return variant(vars);
410 
411  } else if(key == "enemies")
412  {
413  std::vector<variant> vars;
414  for( std::size_t i = 0; i < resources::gameboard->teams().size(); ++i) {
415  if ( current_team().is_enemy( i+1 ) )
416  vars.emplace_back(i);
417  }
418  return variant(vars);
419 
420  } else if(key == "my_recruits")
421  {
422  std::vector<variant> vars;
423 
425 
426  const std::set<std::string>& recruits = current_team().recruits();
427  if(recruits.empty()) {
428  return variant(vars);
429  }
430  for(std::set<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i)
431  {
432  const unit_type *ut = unit_types.find(*i);
433  if (ut)
434  {
435  vars.emplace_back(std::make_shared<unit_type_callable>(*ut));
436  }
437  }
438  return variant(vars);
439 
440  } else if(key == "recruits_of_side")
441  {
442  std::vector<variant> vars;
443  std::vector< std::vector< variant>> tmp;
444 
446 
447  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
448  {
449  std::vector<variant> v;
450  tmp.push_back( v );
451 
452  const std::set<std::string>& recruits = resources::gameboard->teams()[i].recruits();
453  if(recruits.empty()) {
454  continue;
455  }
456  for(std::set<std::string>::const_iterator str_it = recruits.begin(); str_it != recruits.end(); ++str_it)
457  {
458  const unit_type *ut = unit_types.find(*str_it);
459  if (ut)
460  {
461  tmp[i].emplace_back(std::make_shared<unit_type_callable>(*ut));
462  }
463  }
464  }
465 
466  for( std::size_t i = 0; i<tmp.size(); ++i)
467  vars.emplace_back(tmp[i]);
468  return variant(vars);
469 
470  } else if(key == "units")
471  {
472  std::vector<variant> vars;
473  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
474  vars.emplace_back(std::make_shared<unit_callable>(*i));
475  }
476  return variant(vars);
477 
478  } else if(key == "units_of_side")
479  {
480  std::vector<variant> vars;
481  std::vector< std::vector< variant>> tmp;
482  for( std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
483  {
484  std::vector<variant> v;
485  tmp.push_back( v );
486  }
487  for(const unit &u : units) {
488  tmp[u.side() - 1].emplace_back(std::make_shared<unit_callable>(u));
489  }
490  for( std::size_t i = 0; i<tmp.size(); ++i)
491  vars.emplace_back(tmp[i]);
492  return variant(vars);
493 
494  } else if(key == "my_units")
495  {
496  std::vector<variant> vars;
497  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
498  if (i->side() == get_side()) {
499  vars.emplace_back(std::make_shared<unit_callable>(*i));
500  }
501  }
502  return variant(vars);
503 
504  } else if(key == "enemy_units")
505  {
506  std::vector<variant> vars;
507  for(unit_map::const_iterator i = units.begin(); i != units.end(); ++i) {
508  if (current_team().is_enemy(i->side())) {
509  if (!i->incapacitated()) {
510  vars.emplace_back(std::make_shared<unit_callable>(*i));
511  }
512  }
513  }
514  return variant(vars);
515 
516  } else if(key == "my_moves")
517  {
518  return variant(std::make_shared<move_map_callable>(get_srcdst(), get_dstsrc(), units));
519 
520  } else if(key == "my_attacks")
521  {
523  } else if(key == "enemy_moves")
524  {
525  return variant(std::make_shared<move_map_callable>(get_enemy_srcdst(), get_enemy_dstsrc(), units));
526 
527  } else if(key == "my_leader")
528  {
530  if(i == units.end()) {
531  return variant();
532  }
533  return variant(std::make_shared<unit_callable>(*i));
534 
535  } else if(key == "recall_list")
536  {
537  std::vector<variant> tmp;
538 
539  for(std::vector<unit_ptr >::const_iterator i = current_team().recall_list().begin(); i != current_team().recall_list().end(); ++i) {
540  tmp.emplace_back(std::make_shared<unit_callable>(**i));
541  }
542 
543  return variant(tmp);
544 
545  } else if(key == "vars")
546  {
547  return variant(vars_.fake_ptr());
548  } else if(key == "keeps")
549  {
550  return get_keeps();
551  } else if(key == "map")
552  {
553  return variant(std::make_shared<gamemap_callable>(*resources::gameboard));
554  } else if(key == "villages")
555  {
556  return villages_from_set(resources::gameboard->map().villages());
557  } else if(key == "villages_of_side")
558  {
559  std::vector<variant> vars;
560  for(std::size_t i = 0; i<resources::gameboard->teams().size(); ++i)
561  {
562  vars.emplace_back();
563  }
564  for(std::size_t i = 0; i<vars.size(); ++i)
565  {
566  vars[i] = villages_from_set(resources::gameboard->teams()[i].villages());
567  }
568  return variant(vars);
569 
570  } else if(key == "my_villages")
571  {
572  return villages_from_set(current_team().villages());
573 
574  } else if(key == "enemy_and_unowned_villages")
575  {
576  return villages_from_set(resources::gameboard->map().villages(), &current_team().villages());
577  }
578 
579  return variant();
580 }
581 
583 {
584  add_input(inputs, "aggression");
585  add_input(inputs, "leader_aggression");
586  add_input(inputs, "caution");
587  add_input(inputs, "attacks");
588  add_input(inputs, "my_side");
589  add_input(inputs, "teams");
590  add_input(inputs, "turn");
591  add_input(inputs, "time_of_day");
592  add_input(inputs, "keeps");
593  add_input(inputs, "vars");
594  add_input(inputs, "allies");
595  add_input(inputs, "enemies");
596  add_input(inputs, "map");
597  add_input(inputs, "my_attacks");
598  add_input(inputs, "enemy_moves");
599  add_input(inputs, "my_leader");
600  add_input(inputs, "my_recruits");
601  //add_input(inputs, "recall_list");
602  add_input(inputs, "recruits_of_side");
603  add_input(inputs, "units");
604  add_input(inputs, "units_of_side");
605  add_input(inputs, "my_units");
606  add_input(inputs, "enemy_units");
607  add_input(inputs, "villages");
608  add_input(inputs, "my_villages");
609  add_input(inputs, "villages_of_side");
610  add_input(inputs, "enemy_and_unowned_villages");
611 }
612 
613 void formula_ai::set_value(const std::string& key, const variant& value) {
614  vars_.mutate_value(key, value);
615 }
616 
618 {
619  if(keeps_cache_.is_null()) {
620  std::vector<variant> vars;
621  for(std::size_t x = 0; x != std::size_t(resources::gameboard->map().w()); ++x) {
622  for(std::size_t y = 0; y != std::size_t(resources::gameboard->map().h()); ++y) {
623  const map_location loc(x,y);
624  if(resources::gameboard->map().is_keep(loc)) {
625  for(const map_location& adj : get_adjacent_tiles(loc)) {
626  if(resources::gameboard->map().is_castle(adj)) {
627  vars.emplace_back(std::make_shared<location_callable>(loc));
628  break;
629  }
630  }
631  }
632  }
633  }
634  keeps_cache_ = variant(vars);
635  }
636 
637  return keeps_cache_;
638 }
639 
641  if (tiles_adjacent(unit_A,unit_B)) {
642  return true;
643  }
644  move_map::const_iterator i;
645  std::pair<move_map::const_iterator,
646  move_map::const_iterator> unit_moves;
647 
648  unit_moves = get_srcdst().equal_range(unit_A);
649  for(i = unit_moves.first; i != unit_moves.second; ++i) {
650  if (tiles_adjacent((*i).second,unit_B)) {
651  return true;
652  }
653  }
654  return false;
655 }
656 
658  //make sure we don't run out of refcount
659 
660  for(const config &func : cfg_.child_range("function"))
661  {
662  const t_string &name = func["name"];
663  const t_string &inputs = func["inputs"];
664  const t_string &formula_str = func["formula"];
665 
666  std::vector<std::string> args = utils::split(inputs.str());
667  try {
669  create_optional_formula(formula_str),
670  create_optional_formula(func["precondition"]),
671  args);
672  }
673  catch(const formula_error& e) {
674  handle_exception(e, "Error while registering function '" + name + "'");
675  }
676  }
677 
679  if (const auto ai_vars = cfg_.optional_child("vars"))
680  {
681  variant var;
682  for(const config::attribute &i : ai_vars->attribute_range()) {
683  var.serialize_from_string(i.second);
684  vars_.add(i.first, var);
685  }
686  }
687 
688 }
689 
691 {
692  fai_ca->evaluate(this,resources::gameboard->units());
693 
694 }
695 
697 {
698  map_formula_callable callable(fake_ptr());
699  fai_ca->update_callable_map( callable );
700  const_formula_ptr move_formula(fai_ca->get_action());
701  return !make_action(move_formula, callable).is_empty();
702 }
703 
704 #if 0
705 formula_ai::gamestate_change_observer::gamestate_change_observer() :
706  set_var_counter_(), set_unit_var_counter_(), continue_counter_()
707 {
709 }
710 
711 formula_ai::gamestate_change_observer::~gamestate_change_observer() {
713 }
714 
715 void formula_ai::gamestate_change_observer::handle_generic_event(const std::string& /*event_name*/) {
716  set_var_counter_ = 0;
717  set_unit_var_counter_ = 0;
718  continue_counter_ = 0;
719 }
720 
721 //return false if number of calls exceeded MAX_CALLS
722 bool formula_ai::gamestate_change_observer::set_var_check() {
723  if(set_var_counter_ >= MAX_CALLS)
724  return false;
725 
726  set_var_counter_++;
727  return true;
728 }
729 
730 bool formula_ai::gamestate_change_observer::set_unit_var_check() {
731  if(set_unit_var_counter_ >= MAX_CALLS)
732  return false;
733 
734  set_unit_var_counter_++;
735  return true;
736 }
737 
738 bool formula_ai::gamestate_change_observer::continue_check() {
739  if(continue_counter_ >= MAX_CALLS)
740  return false;
741 
742  continue_counter_++;
743  return true;
744 }
745 #endif
746 
748 {
749  if (!cfg_)
750  {
751  return config();
752  }
753  DBG_AI << "formula_ai::to_config(): "<< cfg_<<std::endl;
754  config cfg = cfg_;
755 
756  //formula AI variables
757  cfg.clear_children("vars");
758  if (vars_.empty() == false) {
759  config &ai_vars = cfg.add_child("vars");
760 
761  std::string str;
763  {
764  try {
765  str = i->second.serialize_to_string();
766  } catch(const type_error&) {
767  WRN_AI << "variable ["<< i->first <<"] is not serializable - it will not be persisted across savegames"<<std::endl;
768  continue;
769  }
770  if (!str.empty())
771  {
772  ai_vars[i->first] = str;
773  str.clear();
774  }
775  }
776  }
777 
778  return cfg;
779 }
780 
781 } // end of namespace ai
Defines formula ai.
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:656
virtual std::string get_grouping() const override
Definition: contexts.hpp:631
::tod_manager * tod_manager
Definition: resources.cpp:30
virtual const move_map & get_enemy_srcdst() const override
Definition: contexts.hpp:611
virtual int get_villages_per_scout() const override
Definition: contexts.hpp:751
unit_iterator end()
Definition: map.hpp:429
formula_ai(const formula_ai &)=delete
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1262
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:85
const_iterator begin() const
Definition: callable.hpp:276
void handle_exception(const wfl::formula_error &e) const
Definition: ai.cpp:117
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
virtual const unit_map & units() const override
Definition: game_board.hpp:112
Defines formula ai candidate actions - headers.
DIRECTION get_relative_dir(const map_location &loc, map_location::RELATIVE_DIR_MODE mode) const
Definition: location.cpp:227
void clear_children(T... keys)
Definition: config.hpp:557
This class represents a single unit of a specific type.
Definition: unit.hpp:121
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:40
std::string formula
Definition: formula.hpp:107
static manager & get_singleton()
Definition: manager.hpp:145
unit_iterator find_leader(int side)
Definition: map.cpp:328
bool execute_candidate_action(wfl::candidate_action_ptr fai_ca)
Execute the fai candidate action.
Definition: ai.cpp:696
const config cfg_
Definition: ai.hpp:154
std::string filename
Definition: formula.hpp:108
virtual double get_leader_value() const override
Definition: contexts.hpp:661
Managing the AI-Game interaction - AI actions and their results.
void display_message(const std::string &msg) const
Definition: ai.cpp:136
static lg::log_domain log_formula_ai("ai/engine/fai")
child_itors child_range(config_key_type key)
Definition: config.cpp:344
wfl::candidate_action_ptr ca_ptr
Definition: ai.cpp:74
attribute_map::value_type attribute
Definition: config.hpp:222
virtual double get_village_value() const override
Definition: contexts.hpp:746
virtual const move_map & get_srcdst() const override
Definition: contexts.hpp:716
virtual config to_config() const
Definition: ai.cpp:747
unit_iterator begin()
Definition: map.hpp:419
std::vector< formula_input > formula_input_vector
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
Definition: types.cpp:1304
Composite AI stages.
unit_type_data unit_types
Definition: types.cpp:1481
std::string evaluate(const std::string &formula_str)
Definition: ai.cpp:158
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
virtual double get_retreat_factor() const override
Definition: contexts.hpp:726
void clear()
Definition: config.cpp:920
virtual wfl::variant get_value(const std::string &key) const override
Definition: ai.cpp:299
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
#define WRN_AI
Definition: ai.cpp:67
A single unit type that the player may recruit.
Definition: types.hpp:45
void add_chat_message(const std::time_t &time, const std::string &speaker, int side, const std::string &msg, events::chat_handler::MESSAGE_TYPE type, bool bell)
void on_create()
Definition: ai.cpp:657
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader() const override
Definition: contexts.hpp:666
bool can_reach_unit(map_location unit_A, map_location unit_B) const
Definition: ai.cpp:640
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:61
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
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:132
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
bool valid() const
Definition: location.hpp:89
void set_value(const std::string &key, const wfl::variant &value) override
Definition: ai.cpp:613
virtual double get_leader_aggression() const override
Definition: contexts.hpp:646
std::string type
Definition: formula.hpp:106
virtual utils::variant< bool, std::vector< std::string > > get_leader_ignores_keep() const override
Definition: contexts.hpp:656
game_board * gameboard
Definition: resources.cpp:21
void serialize_from_string(const std::string &str)
Definition: variant.cpp:632
void evaluate_candidate_action(wfl::candidate_action_ptr fai_ca)
Evaluate the fai candidate action.
Definition: ai.cpp:690
bool is_enemy(int n) const
Definition: team.hpp:255
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:262
virtual const move_map & get_enemy_dstsrc() const override
Definition: contexts.hpp:601
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
virtual const std::vector< std::string > get_recruitment_pattern() const override
Definition: contexts.hpp:701
utils::optional_reference< config > optional_child(config_key_type key, int n=0)
Euivalent to child, but returns an empty optional if the nth child was not found. ...
Definition: config.cpp:445
iterator end()
end iterator
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed throgh std::decay first.
Definition: general.hpp:33
wfl::attack_map_callable attacks_callable
Definition: ai.hpp:162
virtual double get_retreat_enemy_weight() const override
Definition: contexts.hpp:721
Encapsulates the map of the game.
Definition: location.hpp:38
unit_iterator find(std::size_t id)
Definition: map.cpp:310
bool tiles_adjacent(const map_location &a, const map_location &b)
Function which tells if two locations are adjacent.
Definition: location.cpp:503
#define LOG_AI
Definition: ai.cpp:66
std::size_t i
Definition: function.cpp:967
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
virtual const team & current_team() const override
Definition: contexts.hpp:455
virtual void get_inputs(wfl::formula_input_vector &inputs) const override
Definition: ai.cpp:582
wfl::map_formula_callable vars_
Definition: ai.hpp:165
Game information for the AI.
recursion_counter recursion_counter_
Definition: ai.hpp:155
Default AI contexts.
#define DBG_AI
Definition: ai.cpp:65
virtual double get_scout_village_targeting() const override
Definition: contexts.hpp:731
#define ERR_AI
Definition: ai.cpp:68
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:401
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
int w
std::shared_ptr< const formula > const_formula_ptr
Definition: formula_fwd.hpp:24
formula_input_vector inputs() const
Definition: callable.hpp:63
config & add_child(config_key_type key)
Definition: config.cpp:514
wfl::candidate_action_ptr load_candidate_action_from_config(const config &cfg)
Definition: ai.cpp:76
void mutate_value(const std::string &key, const variant &value)
Definition: callable.hpp:58
std::shared_ptr< base_candidate_action > candidate_action_ptr
Definition: candidates.hpp:37
display_chat_manager & get_chat_manager()
virtual const move_map & get_dstsrc() const override
Definition: contexts.hpp:596
bool is_null() const
Functions to test the type of the internal value.
Definition: variant.hpp:62
std::map< std::string, variant >::const_iterator const_iterator
Definition: callable.hpp:274
virtual double get_aggression() const override
Definition: contexts.hpp:551
virtual const wfl::variant & get_attacks_as_variant() const override
Definition: contexts.hpp:581
const_iterator end() const
Definition: callable.hpp:277
#define f
Definition: contexts.hpp:44
wfl::ai_function_symbol_table function_table_
Definition: ai.hpp:168
std::vector< std::string > split(const config_attribute_value &val)
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:369
Composite AI contexts.
Standard logging facilities (interface).
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units, bool check_vision)
Definition: teleport.cpp:270
static config unit_moves(reports::context &rc, const unit *u, bool is_visible_unit)
Definition: reports.cpp:657
recall_list_manager & recall_list()
Definition: team.hpp:227
void add_function(const std::string &name, formula_function_ptr &&fcn)
Definition: function.cpp:1460
Container associating units to locations.
Definition: map.hpp:98
int get_count() const
Get the current value of the recursion counter.
Definition: contexts.hpp:70
MacOS doesn&#39;t support std::visit when targing MacOS < 10.14 (currently we target 10.11).
virtual bool get_support_villages() const override
Definition: contexts.hpp:741
#define e
pathfind::plain_route shortest_path_calculator(const map_location &src, const map_location &dst, unit_map::iterator &unit_it, pathfind::teleport_map &allowed_teleports) const
Definition: ai.cpp:204
virtual const terrain_filter & get_avoid() const override
Definition: contexts.hpp:586
wfl::variant keeps_cache_
Definition: ai.hpp:161
static void add_input(formula_input_vector &inputs, const std::string &key, FORMULA_ACCESS_TYPE access_type=FORMULA_READ_ONLY)
Definition: callable.hpp:136
int get_recursion_count() const override
Get the value of the recursion counter.
Definition: ai.cpp:96
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
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator &calc, const std::size_t width, const std::size_t height, const teleport_map *teleports, bool border)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
pathfind::teleport_map get_allowed_teleports(unit_map::iterator &unit_it) const
Definition: ai.cpp:257
const std::string & str() const
Definition: tstring.hpp:191
wfl::variant make_action(wfl::const_formula_ptr formula_, const wfl::formula_callable &variables)
Definition: ai.cpp:186
ai_context * ai_ptr_
Definition: ai.hpp:153
virtual double get_caution() const override
Definition: contexts.hpp:591
virtual utils::variant< bool, std::vector< std::string > > get_passive_leader_shares_keep() const override
Definition: contexts.hpp:671
static map_location::DIRECTION n
This module contains various pathfinding functions and utilities.
void set_ai_context(ai_context *context)
Definition: ai.cpp:153
wfl::variant get_keeps() const
Definition: ai.cpp:617
bool is_empty() const
Definition: variant.cpp:266
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:439
const std::set< std::string > & recruits() const
Definition: team.hpp:235
static game_display * get_singleton()
std::string to_debug_string(bool verbose=false, formula_seen_stack *seen=nullptr) const
Definition: variant.cpp:646
std::shared_ptr< formula > formula_ptr
Definition: formula_fwd.hpp:22