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