The Battle for Wesnoth  1.15.3+dev
ca.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Yurii Chernyi <terraninfo@terraninfo.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  * Default AI (Testing)
17  * @file
18  */
19 
20 #include "ai/default/ca.hpp"
21 #include "ai/actions.hpp"
22 #include "ai/manager.hpp"
23 #include "ai/composite/engine.hpp"
24 #include "ai/composite/rca.hpp"
25 #include "ai/composite/stage.hpp"
26 #include "game_board.hpp"
27 #include "game_classification.hpp"
28 #include "game_data.hpp"
29 #include "log.hpp"
30 #include "map/map.hpp"
31 #include "resources.hpp"
32 #include "team.hpp"
33 #include "units/unit.hpp"
34 #include "pathfind/pathfind.hpp"
35 #include "pathfind/teleport.hpp"
36 
37 #include <numeric>
38 #include <boost/dynamic_bitset.hpp>
39 
40 #include <SDL2/SDL_timer.h>
41 
42 static lg::log_domain log_ai_testing_ai_default("ai/ca/testing_ai_default");
43 #define DBG_AI_TESTING_AI_DEFAULT LOG_STREAM(debug, log_ai_testing_ai_default)
44 #define LOG_AI_TESTING_AI_DEFAULT LOG_STREAM(info, log_ai_testing_ai_default)
45 #define WRN_AI_TESTING_AI_DEFAULT LOG_STREAM(warn, log_ai_testing_ai_default)
46 #define ERR_AI_TESTING_AI_DEFAULT LOG_STREAM(err, log_ai_testing_ai_default)
47 
48 
49 namespace ai {
50 
51 namespace ai_default_rca {
52 
53 //==============================================================
54 
55 goto_phase::goto_phase( rca_context &context, const config &cfg )
56  : candidate_action(context,cfg)
57  , move_()
58 {
59 }
60 
62 {
63 }
64 
66 {
67  // Execute goto-movements - first collect gotos in a list
68  std::vector<map_location> gotos;
69  unit_map &units_ = resources::gameboard->units();
70  const gamemap &map_ = resources::gameboard->map();
71 
72  for(unit_map::iterator ui = units_.begin(); ui != units_.end(); ++ui) {
73  if (ui->get_goto() == ui->get_location()) {
74  ui->set_goto(map_location());
75  } else if (ui->side() == get_side() && map_.on_board(ui->get_goto())) {
76  gotos.push_back(ui->get_location());
77  }
78  }
79 
80  for(std::vector<map_location>::const_iterator g = gotos.begin(); g != gotos.end(); ++g) {
81  unit_map::const_iterator ui = units_.find(*g);
82  // passive_leader: never moves or attacks
83  if(ui->can_recruit() && is_passive_leader(ui->id())){
84  continue;
85  }
86  // end of passive_leader
87 
88  if(!is_allowed_unit(*ui)){
89  continue;
90  }
91 
93 
95 
97  route = pathfind::a_star_search(ui->get_location(), ui->get_goto(), 10000.0, calc, map_.w(), map_.h(), &allowed_teleports);
98 
99  if (!route.steps.empty()){
100  move_ = check_move_action(ui->get_location(), route.steps.back(), true, true);
101  } else {
102  // there is no direct path (yet)
103  // go to the nearest hex instead.
104  // maybe a door will open later or something
105 
106  int closest_distance = -1;
107  std::pair<map_location,map_location> closest_move;
108  for(move_map::const_iterator i = get_dstsrc().begin(); i != get_dstsrc().end(); ++i) {
109  if(i->second != ui->get_location()) {
110  continue;
111  }
112  int distance = distance_between(i->first,ui->get_goto());
113  if(closest_distance == -1 || distance < closest_distance) {
114  closest_distance = distance;
115  closest_move = *i;
116  }
117  }
118  if(closest_distance != -1) {
119  move_ = check_move_action(ui->get_location(), closest_move.first);
120  } else {
121  continue;
122  }
123  }
124 
125  if (move_->is_ok()) {
126  return get_score();
127  }
128  }
129 
130  return BAD_SCORE;
131 }
132 
134 {
135  if (!move_) {
136  return;
137  }
138 
139  move_->execute();
140  if (!move_->is_ok()){
141  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
142  }
143 
144  // In some situations, a theoretically possible path is blocked by allies,
145  // resulting in the unit not moving. In this case, we remove all remaining
146  // movement from the unit in order to prevent blacklisting of the CA.
147  if (!move_->is_gamestate_changed()){
148  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute did not move unit; removing moves instead" << std::endl;
149  stopunit_result_ptr stopunit = check_stopunit_action(move_->get_unit_location(), true, false);
150  stopunit->execute();
151  }
152 }
153 
154 
155 //==============================================================
156 
158  : candidate_action(context,cfg),best_analysis_(),choice_rating_(-1000.0)
159 {
160 }
161 
163 {
164 }
165 
167 {
168  const unit_map &units_ = resources::gameboard->units();
169  std::vector<std::string> options = get_recruitment_pattern();
170 
171  choice_rating_ = -1000.0;
172  int ticks = SDL_GetTicks();
173 
174  const std::vector<attack_analysis> analysis = get_attacks(); //passive_leader: in aspect_attacks::analyze_targets()
175 
176  int time_taken = SDL_GetTicks() - ticks;
177  LOG_AI_TESTING_AI_DEFAULT << "took " << time_taken << " ticks for " << analysis.size()
178  << " positions. Analyzing...\n";
179 
180  ticks = SDL_GetTicks();
181 
182  const int max_sims = 50000;
183  int num_sims = analysis.empty() ? 0 : max_sims/analysis.size();
184  if(num_sims < 20)
185  num_sims = 20;
186  if(num_sims > 40)
187  num_sims = 40;
188 
189  LOG_AI_TESTING_AI_DEFAULT << "simulations: " << num_sims << "\n";
190 
191  const int max_positions = 30000;
192  const int skip_num = analysis.size()/max_positions;
193 
194  std::vector<attack_analysis>::const_iterator choice_it = analysis.end();
195  for(std::vector<attack_analysis>::const_iterator it = analysis.begin();
196  it != analysis.end(); ++it) {
197 
198  if(skip_num > 0 && ((it - analysis.begin())%skip_num) && it->movements.size() > 1)
199  continue;
200 
201  // This is somewhat inefficient. It would be faster to exclude these attacks
202  // in get_attacks() above, but the CA filter information is not available inside
203  // the attacks aspect code. Providing the filtering here is only done for consistency
204  // with other CAs though, the recommended method of filtering attacks is via
205  // 'filter_own' of the attacks aspect.
206  bool skip_attack = false;
207  for(std::size_t i = 0; i != it->movements.size(); ++i) {
208  const unit_map::const_iterator u = units_.find(it->movements[i].first);
209  if (!is_allowed_unit(*u)) {
210  skip_attack = true;
211  break;
212  }
213  }
214  if (skip_attack)
215  continue;
216 
217  const double rating = it->rating(get_aggression(),*this);
218  LOG_AI_TESTING_AI_DEFAULT << "attack option rated at " << rating << " ("
219  << (it->uses_leader ? get_leader_aggression() : get_aggression()) << ")\n";
220 
221  if(rating > choice_rating_) {
222  choice_it = it;
223  choice_rating_ = rating;
224  }
225  }
226 
227  time_taken = SDL_GetTicks() - ticks;
228  LOG_AI_TESTING_AI_DEFAULT << "analysis took " << time_taken << " ticks\n";
229 
230 
231  // suokko tested the rating against current_team().caution()
232  // Bad mistake -- the AI became extremely reluctant to attack anything.
233  // Documenting this in case someone has this bright idea again...*don't*...
234  if(choice_rating_ > 0.0) {
235  best_analysis_ = *choice_it;
236  return get_score();
237  } else {
238  return BAD_SCORE;
239  }
240 }
241 
243 {
244  assert(choice_rating_ > 0.0);
245  map_location from = best_analysis_.movements[0].first;
246  map_location to = best_analysis_.movements[0].second;
247  map_location target_loc = best_analysis_.target;
248 
249  if (from!=to) {
250  move_result_ptr move_res = execute_move_action(from,to,false);
251  if (!move_res->is_ok()) {
252  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok, move failed" << std::endl;
253  return;
254  }
255  }
256 
257  attack_result_ptr attack_res = check_attack_action(to, target_loc, -1);
258  if (!attack_res->is_ok()) {
259  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok, attack cancelled" << std::endl;
260  } else {
261  attack_res->execute();
262  if (!attack_res->is_ok()) {
263  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok, attack failed" << std::endl;
264  }
265  }
266 
267 }
268 
269 //==============================================================
270 
272  : candidate_action(context,cfg), auto_remove_(), dst_(), id_(), move_()
273 {
274 }
275 
277 {
278 }
279 
281 {
282 
283  const config &goal = get_leader_goal();
284  //passive leader can reach a goal
285  if (!goal) {
286  LOG_AI_TESTING_AI_DEFAULT << get_name() << "No goal found\n";
287  return BAD_SCORE;
288  }
289 
290  if (goal.empty()) {
291  LOG_AI_TESTING_AI_DEFAULT << get_name() << "Empty goal found\n";
292  return BAD_SCORE;
293  }
294 
295  double max_risk = goal["max_risk"].to_double(1 - get_caution());
296  auto_remove_ = goal["auto_remove"].to_bool();
297 
299  if (!dst_.valid()) {
300  ERR_AI_TESTING_AI_DEFAULT << "Invalid goal: "<<std::endl<<goal;
301  return BAD_SCORE;
302  }
303 
304  const unit_map &units_ = resources::gameboard->units();
305  const std::vector<unit_map::const_iterator> leaders = units_.find_leaders(get_side());
306  if (leaders.empty()) {
307  return BAD_SCORE;
308  }
309 
310  const unit* leader = nullptr;
311  for (const unit_map::const_iterator& l_itor : leaders) {
312  if (!l_itor->incapacitated() && l_itor->movement_left() > 0 && is_allowed_unit(*l_itor)) {
313  leader = &(*l_itor);
314  break;
315  }
316  }
317 
318  if (leader == nullptr) {
319  WRN_AI_TESTING_AI_DEFAULT << "Leader not found" << std::endl;
320  return BAD_SCORE;
321  }
322 
323  id_ = goal["id"].str();
324  if (leader->get_location() == dst_) {
325  //goal already reached
326  if (auto_remove_ && !id_.empty()) {
327  remove_goal(id_);
328  } else {
329  move_ = check_move_action(leader->get_location(), leader->get_location(), !auto_remove_);//we do full moves if we don't want to remove goal
330  if (move_->is_ok()) {
331  return get_score();
332  } else {
333  return BAD_SCORE;
334  }
335  }
336  }
337 
339  const pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(*leader, current_team());
340  pathfind::plain_route route = a_star_search(leader->get_location(), dst_, 1000.0, calc,
341  resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
342  if(route.steps.empty()) {
343  LOG_AI_TESTING_AI_DEFAULT << "route empty";
344  return BAD_SCORE;
345  }
346 
347  const pathfind::paths leader_paths(*leader, false, true, current_team());
348 
349  std::map<map_location,pathfind::paths> possible_moves;
350  possible_moves.emplace(leader->get_location(), leader_paths);
351 
352  map_location loc;
353  for (const map_location &l : route.steps)
354  {
355  if (leader_paths.destinations.contains(l) &&
356  power_projection(l, get_enemy_dstsrc()) < leader->hitpoints() * max_risk)
357  {
358  loc = l;
359  }
360  }
361 
362  if(loc.valid()) {
363  move_ = check_move_action(leader->get_location(), loc, false);
364  if (move_->is_ok()) {
365  return get_score();
366  }
367  }
368  return BAD_SCORE;
369 
370 }
371 
373 {
374  move_->execute();
375  if (!move_->is_ok()){
376  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
377  }
378  if (move_->get_unit_location()==dst_) {
379  //goal already reached
380  if (auto_remove_ && !id_.empty()) {
381  remove_goal(id_);
382  }
383  }
384 }
385 
386 void move_leader_to_goals_phase::remove_goal(const std::string &id)
387 {
388  config mod_ai;
389  mod_ai["side"] = get_side();
390  mod_ai["path"] = "aspect[leader_goal].facet["+id+"]";
391  mod_ai["action"] = "delete";
393 }
394 
395 //==============================================================
396 
398  : candidate_action(context,cfg),move_()
399 {
400 
401 }
402 
404 {
405 
406 }
407 
409 {
410  if (is_keep_ignoring_leader("")) {
411  return BAD_SCORE;
412  }
413 
414  // 1. Collect all leaders in a list
415  // 2. Get the suitable_keep for each leader
416  // 3. Choose the leader with the nearest suitable_keep (and which still have moves)
417  // 4. If leader can reach this keep in 1 turn -> set move_ to there
418  // 5. If not -> Calculate the best move_ (use a-star search)
419  // 6. Save move_ for execution
420 
421  // 1.
422  const unit_map &units_ = resources::gameboard->units();
423  const std::vector<unit_map::const_iterator> leaders = units_.find_leaders(get_side());
424  if (leaders.empty()) {
425  return BAD_SCORE;
426  }
427 
428  // 2. + 3.
429  const unit* best_leader = nullptr;
430  map_location best_keep;
431  int shortest_distance = 99999;
432 
433  for (const unit_map::const_iterator& leader : leaders) {
434  if (leader->incapacitated() || leader->movement_left() == 0 || !is_allowed_unit(*leader) || is_keep_ignoring_leader(leader->id()) || (is_passive_leader(leader->id()) && !is_passive_keep_sharing_leader(leader->id()))) {
435  continue;
436  }
437 
438  // Find where the leader can move
439  const ai::moves_map &possible_moves = get_possible_moves();
440  const ai::moves_map::const_iterator& p_it = possible_moves.find(leader->get_location());
441  if (p_it == possible_moves.end()) {
442  return BAD_SCORE;
443  }
444  const pathfind::paths leader_paths = p_it->second;
445 
446  const map_location& keep = suitable_keep(leader->get_location(), leader_paths);
447  if (keep == map_location::null_location() || keep == leader->get_location()) {
448  continue;
449  }
450 
452 
453  const pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(*leader, current_team());
454 
455  pathfind::plain_route route;
456  route = pathfind::a_star_search(leader->get_location(), keep, 10000.0, calc, resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
457 
458  if (!route.steps.empty() || route.move_cost < shortest_distance) {
459  best_leader = &(*leader);
460  best_keep = keep;
461  shortest_distance = route.move_cost;
462  }
463  }
464 
465  if (best_leader == nullptr) {
466  return BAD_SCORE;
467  }
468 
469  // 4.
470  const unit* leader = best_leader;
471  const map_location keep = best_keep;
472  const pathfind::paths leader_paths(*leader, false, true, current_team());
474  const pathfind::teleport_map allowed_teleports = pathfind::get_teleport_locations(*leader, current_team());
475 
476  if (leader_paths.destinations.contains(keep) && units_.count(keep) == 0) {
477  move_ = check_move_action(leader->get_location(), keep, false);
478  if (move_->is_ok()) {
479  return get_score();
480  }
481  }
482 
483  // 5.
484  // The leader can't move to his keep, try to move to the closest location
485  // to the keep where there are no enemies in range.
486  // Make a map of the possible locations the leader can move to,
487  // ordered by the distance from the keep.
488  typedef std::multimap<int, map_location> ordered_locations;
489  ordered_locations moves_toward_keep;
490 
491  pathfind::plain_route route;
492  route = pathfind::a_star_search(leader->get_location(), keep, 10000.0, calc, resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
493 
494  // find next hop
496  int next_hop_cost = 0;
497  for (const map_location& step : route.steps) {
498  if (leader_paths.destinations.contains(step)) {
499  next_hop = step;
500  next_hop_cost += leader->movement_cost(resources::gameboard->map().get_terrain(step));
501  } else {
502  break;
503  }
504  }
505  if (next_hop == map_location::null_location()) {
506  return BAD_SCORE;
507  }
508  //define the next hop to have the lowest cost (0)
509  moves_toward_keep.emplace(0, next_hop);
510 
511  for (const pathfind::paths::step &dest : leader_paths.destinations) {
512  if (!units_.find(dest.curr).valid()) {
513  route = pathfind::a_star_search(dest.curr, next_hop, 10000.0, calc,
514  resources::gameboard->map().w(), resources::gameboard->map().h(), &allowed_teleports);
515  if (route.move_cost < next_hop_cost) {
516  moves_toward_keep.emplace(route.move_cost, dest.curr);
517  }
518  }
519  }
520 
521  // Find the first location which we can move to,
522  // without the threat of enemies.
523  for (const ordered_locations::value_type& pair : moves_toward_keep) {
524  const map_location& loc = pair.second;
525  if (get_enemy_dstsrc().count(loc) == 0) {
526  move_ = check_move_action(leader->get_location(), loc, true);
527  if (move_->is_ok()) {
528  return get_score();
529  }
530  }
531  }
532  return BAD_SCORE;
533 }
534 
536 {
537  move_->execute();
538  if (!move_->is_ok()) {
539  LOG_AI_TESTING_AI_DEFAULT << get_name() <<"::execute not ok" << std::endl;
540  }
541 }
542 
543 //==============================================================
544 
546  : candidate_action(context,cfg)
547  , keep_loc_()
548  , leader_loc_()
549  , best_leader_loc_()
550  , debug_(false)
551  , moves_()
552 {
553 }
554 
556 {
557 }
558 
560 {
561  moves_.clear();
564  if (!moves_.empty()) {
565  return get_score();
566  }
567  return BAD_SCORE;
568 }
569 
570 
572 {
573  unit_map &units_ = resources::gameboard->units();
574  unit_map::const_iterator leader = units_.find_leader(get_side());
575  // Move all the units to get villages, however move the leader last,
576  // so that the castle will be cleared if it wants to stop to recruit along the way.
577  std::pair<map_location,map_location> leader_move;
578 
579  for(tmoves::const_iterator i = moves_.begin(); i != moves_.end(); ++i) {
580 
581  if(leader != units_.end() && leader->get_location() == i->second) {
582  leader_move = *i;
583  } else {
584  if (resources::gameboard->find_visible_unit(i->first, current_team()) == units_.end()) {
585  move_result_ptr move_res = execute_move_action(i->second,i->first,true);
586  if (!move_res->is_ok()) {
587  return;
588  }
589 
590  const map_location loc = move_res->get_unit_location();
591  leader = units_.find_leader(get_side());
592  const unit_map::const_iterator new_unit = units_.find(loc);
593 
594  if (new_unit != units_.end() &&
595  power_projection(i->first, get_enemy_dstsrc()) >= new_unit->hitpoints() / 4.0)
596  {
597  LOG_AI_TESTING_AI_DEFAULT << "found support target... " << new_unit->get_location() << '\n';
598  }
599  }
600  }
601  }
602 
603  if(leader_move.second.valid()) {
604  if((resources::gameboard->find_visible_unit(leader_move.first , current_team()) == units_.end())
605  && resources::gameboard->map().is_village(leader_move.first)) {
606  move_result_ptr move_res = execute_move_action(leader_move.second,leader_move.first,true);
607  if (!move_res->is_ok()) {
608  return;
609  }
610  }
611  }
612 
613  return;
614 }
615 
617  const move_map& dstsrc, const move_map& enemy_dstsrc,
618  unit_map::const_iterator &leader)
619 {
620  DBG_AI_TESTING_AI_DEFAULT << "deciding which villages we want...\n";
621  unit_map &units_ = resources::gameboard->units();
622  const int ticks = SDL_GetTicks();
624  if(leader != units_.end()) {
625  keep_loc_ = nearest_keep(leader->get_location());
626  leader_loc_ = leader->get_location();
627  } else {
630  }
631 
633 
634  // Find our units who can move.
635  treachmap reachmap;
636  for(unit_map::const_iterator u_itor = units_.begin();
637  u_itor != units_.end(); ++u_itor) {
638  if(u_itor->can_recruit() && is_passive_leader(u_itor->id())){
639  continue;
640  }
641  if(u_itor->side() == get_side() && u_itor->movement_left() && is_allowed_unit(*u_itor)) {
642  reachmap.emplace(u_itor->get_location(), std::vector<map_location>());
643  }
644  }
645 
646 
647  DBG_AI_TESTING_AI_DEFAULT << reachmap.size() << " units found who can try to capture a village.\n";
648 
649  find_villages(reachmap, moves_, dstsrc, enemy_dstsrc);
650 
651  treachmap::iterator itor = reachmap.begin();
652  while(itor != reachmap.end()) {
653  if(itor->second.empty()) {
654  itor = remove_unit(reachmap, moves_, itor);
655  } else {
656  ++itor;
657  }
658  }
659 
660  if(!reachmap.empty()) {
661  DBG_AI_TESTING_AI_DEFAULT << reachmap.size() << " units left after removing the ones who "
662  "can't reach a village, send the to the dispatcher.\n";
663 
664  dump_reachmap(reachmap);
665 
666  dispatch(reachmap, moves_);
667  } else {
668  DBG_AI_TESTING_AI_DEFAULT << "No more units left after removing the ones who can't reach a village.\n";
669  }
670 
671  LOG_AI_TESTING_AI_DEFAULT << "Village assignment done: " << (SDL_GetTicks() - ticks)
672  << " ms, resulted in " << moves_.size() << " units being dispatched.\n";
673 
674 }
675 
677  treachmap& reachmap,
678  tmoves& moves,
679  const std::multimap<map_location,map_location>& dstsrc,
680  const std::multimap<map_location,map_location>& enemy_dstsrc)
681 
682 {
683  std::map<map_location, double> vulnerability;
684 
685  std::size_t min_distance = 100000;
686  const gamemap &map_ = resources::gameboard->map();
687  std::vector<team> &teams_ = resources::gameboard->teams();
688 
689  // When a unit is dispatched we need to make sure we don't
690  // dispatch this unit a second time, so store them here.
691  std::vector<map_location> dispatched_units;
692  for(std::multimap<map_location, map_location>::const_iterator
693  j = dstsrc.begin();
694  j != dstsrc.end(); ++j) {
695 
696  const map_location &current_loc = j->first;
697 
698  if(j->second == leader_loc_) {
699  const std::size_t distance = distance_between(keep_loc_, current_loc);
700  if(distance < min_distance) {
701  min_distance = distance;
702  best_leader_loc_ = current_loc;
703  }
704  }
705 
706  if(std::find(dispatched_units.begin(), dispatched_units.end(),
707  j->second) != dispatched_units.end()) {
708  continue;
709  }
710 
711  if(map_.is_village(current_loc) == false) {
712  continue;
713  }
714 
715  bool want_village = true, owned = false;
716  for(std::size_t n = 0; n != teams_.size(); ++n) {
717  owned = teams_[n].owns_village(current_loc);
718  if(owned && !current_team().is_enemy(n+1)) {
719  want_village = false;
720  }
721 
722  if(owned) {
723  break;
724  }
725  }
726 
727  if(want_village == false) {
728  continue;
729  }
730 
731  // If it is a neutral village, and we have no leader,
732  // then the village is of no use to us, and we don't want it.
733  if(!owned && leader_loc_ == map_location::null_location()) {
734  continue;
735  }
736 
737  double threat = 0.0;
738  const std::map<map_location,double>::const_iterator vuln = vulnerability.find(current_loc);
739  if(vuln != vulnerability.end()) {
740  threat = vuln->second;
741  } else {
742  threat = power_projection(current_loc,enemy_dstsrc);
743  vulnerability.emplace(current_loc, threat);
744  }
745 
747  if (u == resources::gameboard->units().end() || u->get_state("guardian") || !is_allowed_unit(*u) || (u->can_recruit() && is_passive_leader(u->id()))) {
748  continue;
749  }
750 
751  const unit &un = *u;
752  //FIXME: suokko turned this 2:1 to 1.5:1.0.
753  //and dropped the second term of the multiplication. Is that better?
754  //const double threat_multipler = (current_loc == leader_loc?2:1) * current_team().caution() * 10;
755  if(un.hitpoints() < (threat*2*un.defense_modifier(map_.get_terrain(current_loc)))/100) {
756  continue;
757  }
758 
759  // If the next and previous destination differs from our current destination,
760  // we're the only one who can reach the village -> dispatch.
761  std::multimap<map_location, map_location>::const_iterator next = j;
762  ++next; // j + 1 fails
763  const bool at_begin = (j == dstsrc.begin());
764  std::multimap<map_location, map_location>::const_iterator prev = j; //FIXME seems not to work
765  if(!at_begin) {
766  --prev;
767  }
768 #if 1
769  if((next == dstsrc.end() || next->first != current_loc)
770  && (at_begin || prev->first != current_loc)) {
771 
772  move_result_ptr move_check_res = check_move_action(j->second,j->first,true);
773  if (move_check_res->is_ok()) {
774  DBG_AI_TESTING_AI_DEFAULT << "Dispatched unit at " << j->second << " to village " << j->first << '\n';
775  moves.emplace_back(j->first, j->second);
776  }
777  reachmap.erase(j->second);
778  dispatched_units.push_back(j->second);
779  continue;
780  }
781 #endif
782  reachmap[j->second].push_back(current_loc);
783  }
784 
785  DBG_AI_TESTING_AI_DEFAULT << moves.size() << " units already dispatched, "
786  << reachmap.size() << " left to evaluate.\n";
787 }
788 
790 {
791  DBG_AI_TESTING_AI_DEFAULT << "Starting simple dispatch.\n";
792 
793  // we now have a list with units with the villages they can reach.
794  // keep trying the following steps as long as one of them changes
795  // the state.
796  // 1. Dispatch units who can reach 1 village (if more units can reach that
797  // village only one can capture it, so use the first in the list.)
798  // 2. Villages which can only be reached by one unit get that unit dispatched
799  // to them.
800  std::size_t village_count = 0;
801  bool dispatched = true;
802  while(dispatched) {
803  dispatched = false;
804 
805  if(dispatch_unit_simple(reachmap, moves)) {
806  dispatched = true;
807  } else {
808  if(reachmap.empty()) {
809  DBG_AI_TESTING_AI_DEFAULT << "dispatch_unit_simple() found a final solution.\n";
810  break;
811  } else {
812  DBG_AI_TESTING_AI_DEFAULT << "dispatch_unit_simple() couldn't dispatch more units.\n";
813  }
814  }
815 
816  if(dispatch_village_simple(reachmap, moves, village_count)) {
817  dispatched = true;
818  } else {
819  if(reachmap.empty()) {
820  DBG_AI_TESTING_AI_DEFAULT << "dispatch_village_simple() found a final solution.\n";
821  break;
822  } else {
823  DBG_AI_TESTING_AI_DEFAULT << "dispatch_village_simple() couldn't dispatch more units.\n";
824  }
825  }
826 
827  if(!reachmap.empty() && dispatched) {
828  DBG_AI_TESTING_AI_DEFAULT << reachmap.size() << " unit(s) left restarting simple dispatching.\n";
829 
830  dump_reachmap(reachmap);
831  }
832  }
833 
834  if(reachmap.empty()) {
835  DBG_AI_TESTING_AI_DEFAULT << "No units left after simple dispatcher.\n";
836  return;
837  }
838 
839  DBG_AI_TESTING_AI_DEFAULT << reachmap.size() << " units left for complex dispatch with "
840  << village_count << " villages left.\n";
841 
842  dump_reachmap(reachmap);
843 
844  dispatch_complex(reachmap, moves, village_count);
845 }
846 
847 // Returns need further processing
848 // false Nothing has been modified or no units left
850 {
851  bool result = false;
852 
853  treachmap::iterator itor = reachmap.begin();
854  while(itor != reachmap.end()) {
855  if(itor->second.size() == 1) {
856  const map_location village = itor->second[0];
857  result = true;
858 
859  DBG_AI_TESTING_AI_DEFAULT << "Dispatched unit at " << itor->first << " to village " << village << '\n';
860  moves.emplace_back(village, itor->first);
861  reachmap.erase(itor++);
862 
863  if(remove_village(reachmap, moves, village)) {
864  itor = reachmap.begin();
865  }
866 
867  } else {
868  ++itor;
869  }
870  }
871 
872  // Test special cases.
873  if(reachmap.empty()) {
874  // We're done.
875  return false;
876  }
877 
878  if(reachmap.size() == 1) {
879  // One unit left.
880  DBG_AI_TESTING_AI_DEFAULT << "Dispatched _last_ unit at " << reachmap.begin()->first
881  << " to village " << reachmap.begin()->second[0] << '\n';
882 
883  moves.emplace_back(reachmap.begin()->second[0], reachmap.begin()->first);
884 
885  reachmap.clear();
886  // We're done.
887  return false;
888  }
889 
890  return result;
891 }
892 
894  treachmap& reachmap, tmoves& moves, std::size_t& village_count)
895 {
896 
897  bool result = false;
898  bool dispatched = true;
899  while(dispatched) {
900  dispatched = false;
901 
902  // build the reverse map
903  std::map<map_location /*village location*/,
904  std::vector<map_location /* units that can reach it*/>>reversemap;
905 
906  treachmap::const_iterator itor = reachmap.begin();
907  for(;itor != reachmap.end(); ++itor) {
908 
909  for(std::vector<map_location>::const_iterator
910  v_itor = itor->second.begin();
911  v_itor != itor->second.end(); ++v_itor) {
912 
913  reversemap[*v_itor].push_back(itor->first);
914 
915  }
916  }
917 
918  village_count = reversemap.size();
919 
920  itor = reversemap.begin();
921  while(itor != reversemap.end()) {
922  if(itor->second.size() == 1) {
923  // One unit can reach this village.
924  const map_location village = itor->first;
925  dispatched = true;
926  result = true;
927 
928  DBG_AI_TESTING_AI_DEFAULT << "Dispatched unit at " << itor->second[0] << " to village " << itor->first << '\n';
929  moves.emplace_back(itor->first, itor->second[0]);
930 
931  reachmap.erase(itor->second[0]);
932  remove_village(reachmap, moves, village);
933  // Get can go to some trouble to remove the unit from the other villages
934  // instead we abort this loop end do a full rebuild on the map.
935  break;
936  } else {
937  ++itor;
938  }
939  }
940  }
941 
942  return result;
943 }
944 
946  treachmap& reachmap, tmoves& moves, const map_location& village)
947 {
948  bool result = false;
949  treachmap::iterator itor = reachmap.begin();
950  while(itor != reachmap.end()) {
951  itor->second.erase(std::remove(itor->second.begin(), itor->second.end(), village), itor->second.end());
952  if(itor->second.empty()) {
953  result = true;
954  itor = remove_unit(reachmap, moves, itor);
955  } else {
956  ++itor;
957  }
958  }
959  return result;
960 }
961 
963  treachmap& reachmap, tmoves& moves, treachmap::iterator unit)
964 {
965  assert(unit->second.empty());
966 
967  if(unit->first == leader_loc_ && best_leader_loc_ != map_location::null_location()) {
968  DBG_AI_TESTING_AI_DEFAULT << "Dispatch leader at " << leader_loc_ << " closer to the keep at "
969  << best_leader_loc_ << '\n';
970 
971  moves.emplace_back(best_leader_loc_, leader_loc_);
972  }
973 
974  reachmap.erase(unit++);
975  return unit;
976 }
977 
979  treachmap& reachmap, tmoves& moves, const std::size_t village_count)
980 {
981  // ***** ***** Init and dispatch if every unit can reach every village.
982 
983  const std::size_t unit_count = reachmap.size();
984  // The maximum number of villages we can capture with the available units.
985  const std::size_t max_result = unit_count < village_count ? unit_count : village_count;
986 
987  assert(unit_count >= 2 && village_count >= 2);
988 
989  // Every unit can reach every village.
990  if(unit_count == 2 && village_count == 2) {
991  DBG_AI_TESTING_AI_DEFAULT << "Every unit can reach every village for 2 units, dispatch them.\n";
992  full_dispatch(reachmap, moves);
993  return;
994  }
995 
996  std::vector<map_location> units(unit_count);
997  std::vector<std::size_t> villages_per_unit(unit_count);
998  std::vector<map_location> villages;
999  std::vector<std::size_t> units_per_village(village_count);
1000 
1001  // We want to test the units, the ones who can reach the least
1002  // villages first so this is our lookup map.
1003  std::multimap<std::size_t /* villages_per_unit value*/,
1004  std::size_t /*villages_per_unit index*/> unit_lookup;
1005 
1006  std::vector</*unit*/boost::dynamic_bitset</*village*/>> matrix(reachmap.size(), boost::dynamic_bitset<>(village_count));
1007 
1008  treachmap::const_iterator itor = reachmap.begin();
1009  for(std::size_t u = 0; u < unit_count; ++u, ++itor) {
1010  units[u] = itor->first;
1011  villages_per_unit[u] = itor->second.size();
1012  unit_lookup.emplace(villages_per_unit[u], u);
1013 
1014  assert(itor->second.size() >= 2);
1015 
1016  for(std::size_t v = 0; v < itor->second.size(); ++v) {
1017 
1018  std::size_t v_index;
1019  // find the index of the v in the villages
1020  std::vector<map_location>::const_iterator v_itor =
1021  std::find(villages.begin(), villages.end(), itor->second[v]);
1022  if(v_itor == villages.end()) {
1023  v_index = villages.size(); // will be the last element after push_back.
1024  villages.push_back(itor->second[v]);
1025  } else {
1026  v_index = v_itor - villages.begin();
1027  }
1028 
1029  units_per_village[v_index]++;
1030 
1031  matrix[u][v_index] = true;
1032  }
1033  }
1034  for(std::vector<std::size_t>::const_iterator upv_it = units_per_village.begin();
1035  upv_it != units_per_village.end(); ++upv_it) {
1036 
1037  assert(*upv_it >=2);
1038  }
1039 
1040  if(debug_) {
1041  // Print header
1042  std::cerr << "Reach matrix:\n\nvillage";
1043  std::size_t u, v;
1044  for(v = 0; v < village_count; ++v) {
1045  std::cerr << '\t' << villages[v];
1046  }
1047  std::cerr << "\ttotal\nunit\n";
1048 
1049  // Print data
1050  for(u = 0; u < unit_count; ++u) {
1051  std::cerr << units[u];
1052 
1053  for(v = 0; v < village_count; ++v) {
1054  std::cerr << '\t' << matrix[u][v];
1055  }
1056  std::cerr << "\t" << villages_per_unit[u] << '\n';
1057  }
1058 
1059  // Print footer
1060  std::cerr << "total";
1061  for(v = 0; v < village_count; ++v) {
1062  std::cerr << '\t' << units_per_village[v];
1063  }
1064  std::cerr << '\n';
1065  }
1066 
1067  // Test the special case, everybody can reach all villages
1068  const bool reach_all = ((village_count == unit_count)
1069  && (std::accumulate(villages_per_unit.begin(), villages_per_unit.end(), std::size_t())
1070  == (village_count * unit_count)));
1071 
1072  if(reach_all) {
1073  DBG_AI_TESTING_AI_DEFAULT << "Every unit can reach every village, dispatch them\n";
1074  full_dispatch(reachmap, moves);
1075  reachmap.clear();
1076  return;
1077  }
1078 
1079  // ***** ***** Find a square
1080  std::multimap<std::size_t /* villages_per_unit value*/, std::size_t /*villages_per_unit index*/>
1081  ::const_iterator src_itor = unit_lookup.begin();
1082 
1083  while(src_itor != unit_lookup.end() && src_itor->first == 2) {
1084 
1085  for(std::multimap<std::size_t, std::size_t>::const_iterator
1086  dst_itor = unit_lookup.begin();
1087  dst_itor != unit_lookup.end(); ++ dst_itor) {
1088 
1089  // avoid comparing us with ourselves.
1090  if(src_itor == dst_itor) {
1091  continue;
1092  }
1093 
1094  boost::dynamic_bitset<> result = matrix[src_itor->second] & matrix[dst_itor->second];
1095  std::size_t matched = result.count();
1096 
1097  // we found a solution, dispatch
1098  if(matched == 2) {
1099  // Collect data
1100  std::size_t first = result.find_first();
1101  std::size_t second = result.find_next(first);
1102 
1103  const map_location village1 = villages[first];
1104  const map_location village2 = villages[second];
1105 
1106  const bool perfect = (src_itor->first == 2 &&
1107  dst_itor->first == 2 &&
1108  units_per_village[first] == 2 &&
1109  units_per_village[second] == 2);
1110 
1111  // Dispatch
1112  DBG_AI_TESTING_AI_DEFAULT << "Found a square.\nDispatched unit at " << units[src_itor->second]
1113  << " to village " << village1 << '\n';
1114  moves.emplace_back(village1, units[src_itor->second]);
1115 
1116  DBG_AI_TESTING_AI_DEFAULT << "Dispatched unit at " << units[dst_itor->second]
1117  << " to village " << village2 << '\n';
1118  moves.emplace_back(village2, units[dst_itor->second]);
1119 
1120  // Remove the units
1121  reachmap.erase(units[src_itor->second]);
1122  reachmap.erase(units[dst_itor->second]);
1123 
1124  // Evaluate and start correct function.
1125  if(perfect) {
1126  // We did a perfect dispatch 2 units who could visit 2 villages.
1127  // This means we didn't change the assertion for this functions
1128  // so call ourselves recursively, and finish afterwards.
1129  DBG_AI_TESTING_AI_DEFAULT << "Perfect dispatch, do complex again.\n";
1130  dispatch_complex(reachmap, moves, village_count - 2);
1131  return;
1132  } else {
1133  // We did a not perfect dispatch but we did modify things
1134  // so restart dispatching.
1135  DBG_AI_TESTING_AI_DEFAULT << "NON Perfect dispatch, do dispatch again.\n";
1136  remove_village(reachmap, moves, village1);
1137  remove_village(reachmap, moves, village2);
1138  dispatch(reachmap, moves);
1139  return;
1140  }
1141  }
1142  }
1143 
1144  ++src_itor;
1145  }
1146 
1147  // ***** ***** Do all permutations.
1148  // Now walk through all possible permutations
1149  // - test whether the suggestion is possible
1150  // - does it result in max_villages
1151  // - dispatch and ready
1152  // - is it's result better as the last best
1153  // - store
1154  std::vector<std::pair<map_location, map_location>> best_result;
1155 
1156  // Bruteforcing all possible permutations can result in a slow game.
1157  // So there needs to be a balance between the best possible result and
1158  // not too slow. From the test (at the end of the file) a good number is
1159  // picked. In general we shouldn't reach this point too often if we do
1160  // there are a lot of villages which are unclaimed and a lot of units
1161  // to claim them.
1162  const std::size_t max_options = 8;
1163  if(unit_count >= max_options && village_count >= max_options) {
1164 
1165  DBG_AI_TESTING_AI_DEFAULT << "Too many units " << unit_count << " and villages "
1166  << village_count<<" found, evaluate only the first "
1167  << max_options << " options;\n";
1168 
1169  std::vector<std::size_t> perm (max_options, 0);
1170  for(std::size_t i =0; i < max_options; ++i) {
1171  perm[i] = i;
1172  }
1173  while(std::next_permutation(perm.begin(), perm.end())) {
1174 
1175  // Get result for current permutation.
1176  std::vector<std::pair<map_location,map_location>> result;
1177  for(std::size_t u = 0; u < max_options; ++u) {
1178  if(matrix[u][perm[u]]) {
1179  result.emplace_back(villages[perm[u]], units[u]);
1180 
1181  }
1182  }
1183  if(result.size() == max_result) {
1184  best_result.swap(result);
1185  break;
1186  }
1187 
1188  if(result.size() > best_result.size()) {
1189  best_result.swap(result);
1190  }
1191  }
1192  // End of loop no optimal found, assign the best
1193  moves.insert(moves.end(), best_result.begin(), best_result.end());
1194 
1195  // Clean up the reachmap for dispatched units.
1196  for(const auto& unit_village_pair : best_result) {
1197  reachmap.erase(unit_village_pair.second);
1198  }
1199 
1200  // Try to dispatch whatever is left
1201  dispatch(reachmap, moves);
1202  return;
1203 
1204  } else if(unit_count <= village_count) {
1205 
1206  DBG_AI_TESTING_AI_DEFAULT << "Unit major\n";
1207 
1208  std::vector<std::size_t> perm (unit_count, 0);
1209  for(std::size_t i =0; i < unit_count; ++i) {
1210  perm[i] = i;
1211  }
1212  while(std::next_permutation(perm.begin(), perm.end())) {
1213  // Get result for current permutation.
1214  std::vector<std::pair<map_location,map_location>> result;
1215  for(std::size_t u = 0; u < unit_count; ++u) {
1216  if(matrix[u][perm[u]]) {
1217  result.emplace_back(villages[perm[u]], units[u]);
1218 
1219  }
1220  }
1221  if(result.size() == max_result) {
1222  moves.insert(moves.end(), result.begin(), result.end());
1223  reachmap.clear();
1224  return;
1225  }
1226 
1227  if(result.size() > best_result.size()) {
1228  best_result.swap(result);
1229  }
1230  }
1231  // End of loop no optimal found, assign the best
1232  moves.insert(moves.end(), best_result.begin(), best_result.end());
1233 
1234  // clean up the reachmap we need to test whether the leader is still there
1235  // and if so remove him manually to get him dispatched.
1236  for(const auto& unit_village_pair : best_result) {
1237  reachmap.erase(unit_village_pair.second);
1238  }
1239  treachmap::iterator unit = reachmap.find(leader_loc_);
1240  if(unit != reachmap.end()) {
1241  unit->second.clear();
1242  remove_unit(reachmap, moves, unit);
1243  }
1244  reachmap.clear();
1245 
1246  } else {
1247 
1248  DBG_AI_TESTING_AI_DEFAULT << "Village major\n";
1249 
1250  std::vector<std::size_t> perm (village_count, 0);
1251  for(std::size_t i =0; i < village_count; ++i) {
1252  perm[i] = i;
1253  }
1254  while(std::next_permutation(perm.begin(), perm.end())) {
1255  // Get result for current permutation.
1256  std::vector<std::pair<map_location,map_location>> result;
1257  for(std::size_t v = 0; v < village_count; ++v) {
1258  if(matrix[perm[v]][v]) {
1259  result.emplace_back(villages[v], units[perm[v]]);
1260 
1261  }
1262  }
1263  if(result.size() == max_result) {
1264  moves.insert(moves.end(), result.begin(), result.end());
1265  reachmap.clear();
1266  return;
1267  }
1268 
1269  if(result.size() > best_result.size()) {
1270  best_result.swap(result);
1271  }
1272  }
1273  // End of loop no optimal found, assigne the best
1274  moves.insert(moves.end(), best_result.begin(), best_result.end());
1275 
1276  // clean up the reachmap we need to test whether the leader is still there
1277  // and if so remove him manually to get him dispatched.
1278  for(const auto& unit_village_pair : best_result) {
1279  reachmap.erase(unit_village_pair.second);
1280  }
1281  treachmap::iterator unit = reachmap.find(leader_loc_);
1282  if(unit != reachmap.end()) {
1283  unit->second.clear();
1284  remove_unit(reachmap, moves, unit);
1285  }
1286  reachmap.clear();
1287  }
1288 }
1289 
1291 {
1292  treachmap::const_iterator itor = reachmap.begin();
1293  for(std::size_t i = 0; i < reachmap.size(); ++i, ++itor) {
1294  DBG_AI_TESTING_AI_DEFAULT << "Dispatched unit at " << itor->first
1295  << " to village " << itor->second[i] << '\n';
1296  moves.emplace_back(itor->second[i], itor->first);
1297  }
1298 }
1299 
1301 {
1302  if(!debug_) {
1303  return;
1304  }
1305 
1306  for(treachmap::const_iterator itor =
1307  reachmap.begin(); itor != reachmap.end(); ++itor) {
1308 
1309  std::cerr << "Reachlist for unit at " << itor->first;
1310 
1311  if(itor->second.empty()) {
1312  std::cerr << "\tNone";
1313  }
1314 
1315  for(std::vector<map_location>::const_iterator
1316  v_itor = itor->second.begin();
1317  v_itor != itor->second.end(); ++v_itor) {
1318 
1319  std::cerr << '\t' << *v_itor;
1320  }
1321  std::cerr << '\n';
1322 
1323  }
1324 }
1325 
1326 //==============================================================
1327 
1329  : candidate_action(context,cfg),move_()
1330 {
1331 }
1332 
1334 {
1335 }
1336 
1338 {
1339  // Find units in need of healing.
1340  unit_map &units_ = resources::gameboard->units();
1341  unit_map::iterator u_it = units_.begin();
1342  for(; u_it != units_.end(); ++u_it) {
1343  unit &u = *u_it;
1344 
1345  if(u.can_recruit() && is_passive_leader(u.id())){
1346  continue;
1347  }
1348 
1349  // If the unit is on our side, has lost as many or more than
1350  // 1/2 round worth of healing, and doesn't regenerate itself,
1351  // then try to find a vacant village for it to rest in.
1352  if(u.side() == get_side() &&
1355  !u.get_ability_bool("regenerate") && is_allowed_unit(*u_it))
1356  {
1357  // Look for the village which is the least vulnerable to enemy attack.
1358  typedef std::multimap<map_location,map_location>::const_iterator Itor;
1359  std::pair<Itor,Itor> it = get_srcdst().equal_range(u_it->get_location());
1360  double best_vulnerability = 100000.0;
1361  // Make leader units more unlikely to move to vulnerable villages
1362  const double leader_penalty = (u.can_recruit()?2.0:1.0);
1363  Itor best_loc = it.second;
1364  while(it.first != it.second) {
1365  const map_location& dst = it.first->second;
1366  if (resources::gameboard->map().gives_healing(dst) && (units_.find(dst) == units_.end() || dst == u_it->get_location())) {
1367  const double vuln = power_projection(dst, get_enemy_dstsrc());
1368  DBG_AI_TESTING_AI_DEFAULT << "found village with vulnerability: " << vuln << "\n";
1369  if(vuln < best_vulnerability) {
1370  best_vulnerability = vuln;
1371  best_loc = it.first;
1372  DBG_AI_TESTING_AI_DEFAULT << "chose village " << dst << '\n';
1373  }
1374  }
1375 
1376  ++it.first;
1377  }
1378 
1379  // If we have found an eligible village,
1380  // and we can move there without expecting to get whacked next turn:
1381  if(best_loc != it.second && best_vulnerability*leader_penalty < u.hitpoints()) {
1382  move_ = check_move_action(best_loc->first,best_loc->second,true);
1383  if (move_->is_ok()) {
1384  return get_score();
1385  }
1386  }
1387  }
1388  }
1389 
1390  return BAD_SCORE;
1391 }
1392 
1394 {
1395  LOG_AI_TESTING_AI_DEFAULT << "moving unit to village for healing...\n";
1396  move_->execute();
1397  if (!move_->is_ok()){
1398  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
1399  }
1400 }
1401 
1402 //==============================================================
1403 
1405  : candidate_action(context,cfg), move_()
1406 {
1407 }
1408 
1410 {
1411 }
1412 
1414 {
1415 
1416 
1417  // Get versions of the move map that assume that all units are at full movement
1418  const unit_map& units_ = resources::gameboard->units();
1419 
1420  //unit_map::const_iterator leader = units_.find_leader(get_side());
1421  std::vector<unit_map::const_iterator> leaders = units_.find_leaders(get_side());
1422  std::map<map_location,pathfind::paths> dummy_possible_moves;
1423 
1424  move_map fullmove_srcdst;
1425  move_map fullmove_dstsrc;
1426  calculate_possible_moves(dummy_possible_moves, fullmove_srcdst, fullmove_dstsrc,
1427  false, true, &get_avoid());
1428 
1429  /*adjacent_loc_array_t leader_adj;
1430  if(leader != units_.end()) {
1431  get_adjacent_tiles(leader->get_location(), leader_adj.data());
1432  }*/
1433  //int leader_adj_count = 0;
1434  std::vector<map_location> leaders_adj_v;
1435  for (unit_map::const_iterator leader : leaders) {
1436  adjacent_loc_array_t tmp_leader_adj;
1437  get_adjacent_tiles(leader->get_location(), tmp_leader_adj.data());
1438  for (map_location &loc : tmp_leader_adj) {
1439  bool found = false;
1440  for (map_location &new_loc : leaders_adj_v) {
1441  if(new_loc == loc){
1442  found = true;
1443  break;
1444  }
1445  }
1446  if(!found){
1447  leaders_adj_v.push_back(loc);
1448  }
1449  }
1450  }
1451  //leader_adj_count = leaders_adj_v.size();
1452 
1453 
1454  for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
1455  if (i->side() == get_side() &&
1456  i->movement_left() == i->total_movement() &&
1457  //leaders.find(*i) == leaders.end() && //unit_map::const_iterator(i) != leader &&
1458  std::find(leaders.begin(), leaders.end(), i) == leaders.end() &&
1459  !i->incapacitated() && is_allowed_unit(*i))
1460  {
1461  // This unit still has movement left, and is a candidate to retreat.
1462  // We see the amount of power of each side on the situation,
1463  // and decide whether it should retreat.
1464  if(should_retreat(i->get_location(), i, fullmove_srcdst, fullmove_dstsrc, get_caution())) {
1465 
1466  bool can_reach_leader = false;
1467 
1468  // Time to retreat. Look for the place where the power balance
1469  // is most in our favor.
1470  // If we can't find anywhere where we like the power balance,
1471  // just try to get to the best defensive hex.
1472  typedef move_map::const_iterator Itor;
1473  std::pair<Itor,Itor> itors = get_srcdst().equal_range(i->get_location());
1474  map_location best_pos, best_defensive(i->get_location());
1475 
1476  double best_rating = -1000.0;
1477  int best_defensive_rating = i->defense_modifier(resources::gameboard->map().get_terrain(i->get_location()))
1478  - (resources::gameboard->map().is_village(i->get_location()) ? 10 : 0);
1479  while(itors.first != itors.second) {
1480 
1481  //if(leader != units_.end() && std::count(leader_adj,
1482  // leader_adj + 6, itors.first->second)) {
1483  if(std::find(leaders_adj_v.begin(), leaders_adj_v.end(), itors.first->second) != leaders_adj_v.end()){
1484 
1485  can_reach_leader = true;
1486  break;
1487  }
1488 
1489  // We rate the power balance of a hex based on our power projection
1490  // compared to theirs, multiplying their power projection by their
1491  // chance to hit us on the hex we're planning to flee to.
1492  const map_location& hex = itors.first->second;
1493  const int defense = i->defense_modifier(resources::gameboard->map().get_terrain(hex));
1494  const double our_power = power_projection(hex,get_dstsrc());
1495  const double their_power = power_projection(hex,get_enemy_dstsrc()) * static_cast<double>(defense)/100.0;
1496  const double rating = our_power - their_power;
1497  if(rating > best_rating) {
1498  best_pos = hex;
1499  best_rating = rating;
1500  }
1501 
1502  // Give a bonus for getting to a village.
1503  const int modified_defense = defense - (resources::gameboard->map().is_village(hex) ? 10 : 0);
1504 
1505  if(modified_defense < best_defensive_rating) {
1506  best_defensive_rating = modified_defense;
1507  best_defensive = hex;
1508  }
1509 
1510  ++itors.first;
1511  }
1512 
1513  // If the unit is in range of its leader, it should
1514  // never retreat -- it has to defend the leader instead.
1515  if(can_reach_leader) {
1516  continue;
1517  }
1518 
1519  if(!best_pos.valid()) {
1520  best_pos = best_defensive;
1521  }
1522 
1523  if(best_pos.valid()) {
1524  move_ = check_move_action(i->get_location(), best_pos, true);
1525  if (move_->is_ok()) {
1526  return get_score();
1527  }
1528  }
1529  }
1530  }
1531  }
1532 
1533  return BAD_SCORE;
1534 }
1535 
1537 {
1538  move_->execute();
1539  if (!move_->is_ok()){
1540  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
1541  }
1542 }
1543 
1544 
1545 
1546 bool retreat_phase::should_retreat(const map_location& loc, const unit_map::const_iterator& un, const move_map &srcdst, const move_map &dstsrc, double caution)
1547 {
1548  const move_map &enemy_dstsrc = get_enemy_dstsrc();
1549 
1550  if(caution <= 0.0) {
1551  return false;
1552  }
1553 
1554  double optimal_terrain = best_defensive_position(un->get_location(), dstsrc,
1555  srcdst, enemy_dstsrc).chance_to_hit/100.0;
1556  const double proposed_terrain =
1557  un->defense_modifier(resources::gameboard->map().get_terrain(loc)) / 100.0;
1558 
1559  // The 'exposure' is the additional % chance to hit
1560  // this unit receives from being on a sub-optimal defensive terrain.
1561  const double exposure = proposed_terrain - optimal_terrain;
1562 
1563  const double our_power = power_projection(loc,dstsrc);
1564  const double their_power = power_projection(loc,enemy_dstsrc);
1565  return caution*their_power*(1.0+exposure) > our_power;
1566 }
1567 
1568 
1569 //==============================================================
1570 
1572  : candidate_action(context,cfg)
1573 {
1574 }
1575 
1576 
1578 {
1579 }
1580 
1582 {
1583  ERR_AI_TESTING_AI_DEFAULT << get_name() << ": evaluate - not yet implemented" << std::endl;
1584  return BAD_SCORE;
1585 }
1586 
1587 
1588 
1590 {
1591  ERR_AI_TESTING_AI_DEFAULT << get_name() << ": execute - not yet implemented" << std::endl;
1592 }
1593 
1594 //==============================================================
1595 
1597  :candidate_action(context, cfg)
1598 {
1599 }
1600 
1602 {
1603 }
1604 
1606 {
1607  bool have_active_leader = false;
1608  std::vector<unit_map::unit_iterator> ai_leaders = resources::gameboard->units().find_leaders(get_side());
1609  for (unit_map::unit_iterator &ai_leader : ai_leaders) {
1610  if (!is_passive_leader(ai_leader->id()) || is_passive_keep_sharing_leader(ai_leader->id())) {
1611  have_active_leader = true;
1612  break;
1613  }
1614  }
1615  if(!have_active_leader) {
1616  return BAD_SCORE;
1617  }
1618 
1619  bool allied_leaders_available = false;
1620  for(team &tmp_team : resources::gameboard->teams()) {
1621  if(!current_team().is_enemy(tmp_team.side())){
1622  std::vector<unit_map::unit_iterator> allied_leaders = resources::gameboard->units().find_leaders(get_side());
1623  if (!allied_leaders.empty()){
1624  allied_leaders_available = true;
1625  break;
1626  }
1627  }
1628  }
1629  if(allied_leaders_available){
1630  return get_score();
1631  }
1632  return BAD_SCORE;
1633 }
1634 
1636 {
1637  //get all AI leaders
1638  std::vector<unit_map::unit_iterator> ai_leaders = resources::gameboard->units().find_leaders(get_side());
1639 
1640  //calculate all possible moves (AI + allies)
1641  typedef std::map<map_location, pathfind::paths> path_map;
1642  path_map possible_moves;
1643  move_map friends_srcdst, friends_dstsrc;
1644  calculate_moves(resources::gameboard->units(), possible_moves, friends_srcdst, friends_dstsrc, false, true);
1645 
1646  //check for each ai leader if he should move away from his keep
1647  for (unit_map::unit_iterator &ai_leader : ai_leaders) {
1648  if(!ai_leader.valid() || !is_allowed_unit(*ai_leader) || (is_passive_leader(ai_leader->id()) && !is_passive_keep_sharing_leader(ai_leader->id()))) {
1649  //This can happen if wml killed or moved a leader during a movement events of another leader
1650  continue;
1651  }
1652  //only if leader is on a keep
1653  const map_location &keep = ai_leader->get_location();
1654  if ( !resources::gameboard->map().is_keep(keep) ) {
1655  continue;
1656  }
1657  map_location recruit_loc = pathfind::find_vacant_castle(*ai_leader);
1658  if(!resources::gameboard->map().on_board(recruit_loc)){
1659  continue;
1660  }
1661  bool friend_can_reach_keep = false;
1662 
1663  //for each leader, check if he's allied and can reach our keep
1664  for(path_map::const_iterator i = possible_moves.begin(); i != possible_moves.end(); ++i){
1665  const unit_map::const_iterator itor = resources::gameboard->units().find(i->first);
1666  assert(itor.valid());
1667  team &leader_team = resources::gameboard->get_team(itor->side());
1668  if(itor != resources::gameboard->units().end() && itor->can_recruit() && itor->side() != get_side() && (leader_team.total_income() + leader_team.gold() > leader_team.minimum_recruit_price())){
1669  pathfind::paths::dest_vect::const_iterator tokeep = i->second.destinations.find(keep);
1670  if(tokeep != i->second.destinations.end()){
1671  friend_can_reach_keep = true;
1672  break;
1673  }
1674  }
1675  }
1676  //if there's no allied leader who can reach the keep, check next ai leader
1677  if(friend_can_reach_keep){
1678  //determine the best place the ai leader can move to
1679  map_location best_move;
1680  int defense_modifier = 100;
1681  for(pathfind::paths::dest_vect::const_iterator i = possible_moves[keep].destinations.begin()
1682  ; i != possible_moves[keep].destinations.end()
1683  ; ++i){
1684 
1685  //calculate_moves() above uses max. moves -> need to check movement_left of leader here
1686  if(distance_between(i->curr, keep) <= 3
1687  && static_cast<int>(distance_between(i->curr, keep)) <= ai_leader->movement_left()){
1688 
1689  int tmp_def_mod = ai_leader->defense_modifier(resources::gameboard->map().get_terrain(i->curr));
1690  if(tmp_def_mod < defense_modifier){
1691  defense_modifier = tmp_def_mod;
1692  best_move = i->curr;
1693  }
1694  }
1695  }
1696  //only move if there's a place with a good defense
1697  if(defense_modifier < 100){
1698  move_result_ptr move = check_move_action(keep, best_move, true);
1699  if(move->is_ok()){
1700  move->execute();
1701  if (!move->is_ok()){
1702  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
1703  }else{
1704  ai_leader->set_goto(keep);
1705  }
1706  // This is needed for sides with multiple leaders, in case a WML event does something
1707  // or to account for a leader having previously been moved by this CA execution
1708  possible_moves.clear();
1709  calculate_moves(resources::gameboard->units(), possible_moves, friends_srcdst, friends_dstsrc, false, true);
1710  }else{
1711  LOG_AI_TESTING_AI_DEFAULT << get_name() << "::execute not ok" << std::endl;
1712  }
1713  }
1714  }
1715  ai_leader->remove_movement_ai();
1716  }
1717  //ERR_AI_TESTING_AI_DEFAULT << get_name() << ": evaluate - not yet implemented" << std::endl;
1718 }
1719 
1720 
1721 //==============================================================
1722 
1723 
1724 } //end of namespace testing_ai_default
1725 
1726 } //end of namespace ai
void remove()
Removes a tip.
Definition: tooltip.cpp:189
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:242
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:372
virtual attack_result_ptr check_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon) override
Definition: contexts.hpp:545
int h() const
Effective map height, in hexes.
Definition: map.hpp:128
std::vector< unit_iterator > find_leaders(int side)
Definition: map.cpp:357
unit_iterator end()
Definition: map.hpp:429
move_result_ptr move_
Definition: ca.hpp:44
virtual const attacks_vector & get_attacks() const override
Definition: contexts.hpp:663
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:92
std::vector< std::pair< map_location, map_location > > tmoves
Definition: ca.hpp:133
std::shared_ptr< stopunit_result > stopunit_result_ptr
Definition: game_info.hpp:86
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:114
virtual const map_location & nearest_keep(const map_location &loc) const override
Definition: contexts.hpp:940
This class represents a single unit of a specific type.
Definition: unit.hpp:129
void dispatch(treachmap &reachmap, tmoves &moves)
Dispatches all units to their best location.
Definition: ca.cpp:789
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit&#39;s movement cost on a particular terrain.
Definition: unit.hpp:1419
map_location find_vacant_castle(const unit &leader)
Wrapper for find_vacant_tile() when looking for a vacant castle tile near a leader.
Definition: pathfind.cpp:119
goto_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:55
static manager & get_singleton()
Definition: manager.hpp:151
map_location best_leader_loc_
The best possible location for our leader if it can&#39;t reach a village.
Definition: ca.hpp:124
bool get_state(const std::string &state) const
Check if the unit is affected by a status effect.
Definition: unit.cpp:1353
virtual stopunit_result_ptr check_stopunit_action(const map_location &unit_location, bool remove_movement=true, bool remove_attacks=false) override
Definition: contexts.hpp:569
unit_iterator find_leader(int side)
Definition: map.cpp:329
void dump_reachmap(treachmap &reachmap)
Shows which villages every unit can reach (debug function).
Definition: ca.cpp:1300
Managing the AI-Game interaction - AI actions and their results.
int hitpoints() const
The current number of hitpoints this unit has.
Definition: unit.hpp:493
leader_shares_keep_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:1596
map_location keep_loc_
Location of the keep the closest to our leader.
Definition: ca.hpp:118
virtual const move_map & get_srcdst() const override
Definition: contexts.hpp:833
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:166
std::shared_ptr< move_result > move_result_ptr
Definition: game_info.hpp:84
map_location target
Definition: contexts.hpp:85
virtual const gamemap & map() const override
Definition: game_board.hpp:109
dest_vect destinations
Definition: pathfind.hpp:99
unit_iterator begin()
Definition: map.hpp:419
The unit is poisoned - it loses health each turn.
Definition: unit.hpp:855
Composite AI stages.
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:1337
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:408
AI Support engine - creating specific ai components from config.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:377
-file sdl_utils.hpp
std::shared_ptr< attack_result > attack_result_ptr
Definition: game_info.hpp:81
move_leader_to_keep_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:397
retreat_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:1404
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:559
#define ERR_AI_TESTING_AI_DEFAULT
Definition: ca.cpp:46
Default AI (Testing)
bool remove_village(treachmap &reachmap, tmoves &moves, const map_location &village)
Removes a village for all units, returns true if anything is deleted.
Definition: ca.cpp:945
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:1635
game_data * gamedata
Definition: resources.cpp:22
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:1413
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:309
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
Definition: game_info.hpp:42
std::map< map_location, pathfind::paths > moves_map
The standard way in which a map of possible movement routes to location is recorded.
Definition: game_info.hpp:45
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit&#39;s defense on a given terrain.
Definition: unit.cpp:1647
const config & options()
Definition: game.cpp:593
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
static lg::log_domain log_ai_testing_ai_default("ai/ca/testing_ai_default")
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
team & get_team(int i)
Definition: game_board.hpp:104
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:280
const std::string & id() const
Gets this unit&#39;s id.
Definition: unit.hpp:371
std::vector< map_location > steps
Definition: pathfind.hpp:134
bool should_retreat(const map_location &loc, const unit_map::const_iterator &un, const move_map &srcdst, const move_map &dstsrc, double caution)
Definition: ca.cpp:1546
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:535
Structure which holds a single route between one location and another.
Definition: pathfind.hpp:131
void dispatch_complex(treachmap &reachmap, tmoves &moves, const std::size_t village_count)
Dispatches the units to a village after the simple dispatching failed.
Definition: ca.cpp:978
map_location curr
Definition: pathfind.hpp:87
const defensive_position & best_defensive_position(const map_location &unit, const move_map &dstsrc, const move_map &srcdst, const move_map &enemy_dstsrc) const override
Definition: contexts.hpp:613
bool is_allowed_unit(const unit &u) const
Flag indicating whether unit may be used by this candidate action.
Definition: rca.cpp:93
bool valid() const
Definition: location.hpp:93
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:1581
virtual double get_leader_aggression() const override
Definition: contexts.hpp:748
game_board * gameboard
Definition: resources.cpp:20
boost::dynamic_bitset<> dynamic_bitset
Encapsulates the map of the game.
Definition: map.hpp:36
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:1605
bool is_enemy(int n) const
Definition: team.hpp:243
virtual bool is_passive_leader(const std::string &id) const override
Definition: contexts.hpp:880
virtual const move_map & get_enemy_dstsrc() const override
Definition: contexts.hpp:694
leader_control_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:1571
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:815
std::size_t count(const map_location &loc) const
Definition: map.hpp:414
void modify_active_ai_for_side(ai::side_number side, const config &cfg)
Modifies AI parameters for active AI of the given side.
Definition: manager.cpp:671
std::array< map_location, 6 > adjacent_loc_array_t
Definition: location.hpp:170
logger & debug()
Definition: log.cpp:96
bool dont_log(const log_domain &domain) const
Definition: log.hpp:123
int move_cost
Movement cost for reaching the end of the route.
Definition: pathfind.hpp:136
#define DBG_AI_TESTING_AI_DEFAULT
Definition: ca.cpp:43
bool dispatch_village_simple(treachmap &reachmap, tmoves &moves, std::size_t &village_count)
Definition: ca.cpp:893
Encapsulates the map of the game.
Definition: location.hpp:42
map_location leader_loc_
Locaton of our leader.
Definition: ca.hpp:121
unit_iterator find(std::size_t id)
Definition: map.cpp:311
get_healing_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:1328
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
Definition: abilities.cpp:144
bool debug_
debug log level for AI enabled?
Definition: ca.hpp:127
int w() const
Effective map width, in hexes.
Definition: map.hpp:125
virtual const map_location & suitable_keep(const map_location &leader_location, const pathfind::paths &leader_paths) const override
get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return near...
Definition: contexts.hpp:977
std::size_t i
Definition: function.cpp:933
bool dispatch_unit_simple(treachmap &reachmap, tmoves &moves)
Dispatches all units who can reach one village.
Definition: ca.cpp:849
virtual const team & current_team() const override
Definition: contexts.hpp:530
int max_hitpoints() const
The max number of hitpoints this unit can have.
Definition: unit.hpp:499
double g
Definition: astarsearch.cpp:64
std::vector< std::pair< map_location, map_location > > movements
Definition: contexts.hpp:86
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
Definition: unit.hpp:606
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const override
Function which finds how much &#39;power&#39; a side can attack a certain location with.
Definition: contexts.hpp:791
std::string id_
Definition: rca.hpp:144
#define LOG_AI_TESTING_AI_DEFAULT
Definition: ca.cpp:44
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:571
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:471
virtual move_result_ptr check_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false) override
Definition: contexts.hpp:550
std::map< map_location, std::vector< map_location > > treachmap
Definition: ca.hpp:130
virtual bool is_passive_keep_sharing_leader(const std::string &id) const override
Definition: contexts.hpp:885
virtual std::string get_name() const
Get the name of the candidate action (useful for debug purposes)
Definition: rca.hpp:99
void get_villages(const move_map &dstsrc, const move_map &enemy_dstsrc, unit_map::const_iterator &leader)
Definition: ca.cpp:616
#define next(ls)
Definition: llex.cpp:32
void full_dispatch(treachmap &reachmap, tmoves &moves)
Dispatches all units to a village, every unit can reach every village.
Definition: ca.cpp:1290
treachmap::iterator remove_unit(treachmap &reachmap, tmoves &moves, treachmap::iterator unit)
Removes a unit which can&#39;t reach any village anymore.
Definition: ca.cpp:962
bool is_village(const map_location &loc) const
Definition: map.cpp:65
virtual const move_map & get_dstsrc() const override
Definition: contexts.hpp:688
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:557
get_villages_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:545
virtual double get_aggression() const override
Definition: contexts.hpp:632
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:1589
virtual void calculate_possible_moves(std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr) const override
Definition: contexts.hpp:579
bool find(E event, F functor)
Tests whether an event handler is available.
map_location prev
Definition: astarsearch.cpp:65
const map_location & get_location() const
The current map location this unit is at.
Definition: unit.hpp:1336
bool contains(const map_location &) const
Definition: pathfind.cpp:520
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:260
Object which contains all the possible locations a unit can move to, with associated best routes to t...
Definition: pathfind.hpp:70
static const map_location & null_location()
Definition: location.hpp:85
static const double BAD_SCORE
Definition: rca.hpp:32
Container associating units to locations.
Definition: map.hpp:99
virtual bool is_keep_ignoring_leader(const std::string &id) const override
Definition: contexts.hpp:875
virtual void calculate_moves(const unit_map &units, std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr, bool see_all=false) const override
Definition: contexts.hpp:587
int side() const
The side this unit belongs to.
Definition: unit.hpp:334
virtual const terrain_filter & get_avoid() const override
Definition: contexts.hpp:676
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: ca.cpp:65
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:1393
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:68
virtual move_result_ptr execute_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false) override
Definition: contexts.hpp:1027
combat_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:157
bool valid() const
Definition: map.hpp:276
virtual double get_caution() const override
Definition: contexts.hpp:682
static map_location::DIRECTION n
double get_score() const
Get the usual score of the candidate action without re-evaluation.
Definition: rca.cpp:77
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:133
virtual void execute()
Execute the candidate action.
Definition: ca.cpp:1536
#define WRN_AI_TESTING_AI_DEFAULT
Definition: ca.cpp:45
This module contains various pathfinding functions and utilities.
void remove_goal(const std::string &id)
Definition: ca.cpp:386
virtual const moves_map & get_possible_moves() const override
Definition: contexts.hpp:785
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
virtual config get_leader_goal() const override
Definition: contexts.hpp:755
bool empty() const
Definition: config.cpp:884
void find_villages(treachmap &reachmap, tmoves &moves, const std::multimap< map_location, map_location > &dstsrc, const std::multimap< map_location, map_location > &enemy_dstsrc)
Definition: ca.cpp:676
move_leader_to_goals_phase(rca_context &context, const config &cfg)
Definition: ca.cpp:271
candidate action framework
attack_analysis best_analysis_
Definition: ca.hpp:60