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