37 namespace ai_default_rca {
40 #define DBG_AI LOG_STREAM(debug, log_ai_testing_ca_move_to_targets) 41 #define LOG_AI LOG_STREAM(info, log_ai_testing_ca_move_to_targets) 42 #define WRN_AI LOG_STREAM(warn, log_ai_testing_ca_move_to_targets) 43 #define ERR_AI LOG_STREAM(err, log_ai_testing_ca_move_to_targets) 64 double res = move_cost;
95 DBG_AI <<
"removing target "<< t.loc <<
" due to it not on_board" << std::endl;
100 DBG_AI <<
"removing target "<< t.loc <<
" due to value<=0" << std::endl;
104 if (avoid_.match(t.loc)) {
105 DBG_AI <<
"removing target "<< t.loc <<
" due to 'avoid' match" << std::endl;
134 LOG_AI <<
"finding targets...\n";
135 std::vector<target> targets;
137 if(targets.empty()) {
141 LOG_AI <<
"Found " << targets.size() <<
" targets\n";
142 if(targets.empty()) {
147 targets.erase( std::remove_if(targets.begin(),targets.end(),
remove_wrong_targets(*
this)), targets.end() );
149 if(targets.empty()) {
153 LOG_AI <<
"choosing move with " << targets.size() <<
" targets\n";
154 std::pair<map_location,map_location> move =
choose_move(targets);
155 LOG_AI <<
"choose_move ends with " << targets.size() <<
" targets\n";
157 for(std::vector<target>::const_iterator ittg = targets.begin();
158 ittg != targets.end(); ++ittg) {
162 if(move.first.valid() ==
false || move.second.valid() ==
false) {
169 LOG_AI <<
"move: " << move.first <<
" -> " << move.second <<
'\n';
172 if(!move_ptr->is_ok()) {
173 WRN_AI <<
"unexpected outcome of move"<<std::endl;
202 typedef std::multimap<map_location,map_location>::const_iterator multimapItor;
203 std::pair<multimapItor,multimapItor> locRange = dstsrc.equal_range(tg.loc);
204 while (locRange.first != locRange.second) {
205 if (locRange.first->second == u->get_location()) {
213 double rating = tg.
value;
225 if(tg.
type == target::TYPE::SUPPORT) {
226 if (move_cost <= u->movement_left() * 2) {
235 if (u->usage() ==
"scout") {
237 if(tg.
type == target::TYPE::VILLAGE) {
241 std::set<map_location> enemies_guarding;
245 if(enemies_guarding.size() > 1) {
246 rating /= enemies_guarding.size();
269 for(u = units_.
begin(); u != units_.
end(); ++u) {
271 if (u->get_state(
"guardian")) {
272 LOG_AI << u->type_id() <<
" is guardian, staying still\n";
273 return std::pair(u->get_location(), u->get_location());
279 for(u = units_.
begin(); u != units_.
end(); ++u) {
285 if(u == units_.
end()) {
286 LOG_AI <<
"no eligible units found\n";
287 return std::pair<map_location,map_location>();
291 assert(dummy_route.steps.empty() && dummy_route.move_cost == 0);
300 std::vector<rated_target> rated_targets;
303 double max_rating =
rate_target(*tg, u, dstsrc, enemy_dstsrc, dummy_route);
304 rated_targets.emplace_back(tg, max_rating);
314 double best_rating = -1.0;
320 for(; rated_tg != rated_targets.end(); ++rated_tg) {
321 const target& tg = *(rated_tg->tg);
323 LOG_AI <<
"Considering target at: " << tg.loc <<
"\n";
331 const double locStopValue = 500.0;
335 if(real_route.
steps.empty()) {
336 LOG_AI <<
"Can't reach target: " << locStopValue <<
" = " << tg.
value <<
"/" << best_rating <<
"\n";
340 double real_rating =
rate_target(tg, u, dstsrc, enemy_dstsrc, real_route);
344 if(real_rating > best_rating){
345 best_rating = real_rating;
346 best_rated_target = rated_tg;
347 best_route = real_route;
352 best_rating = 0.000000001;
357 if(rated_tg+1 != rated_targets.end() && best_rating >= (rated_tg+1)->max_rating)
362 LOG_AI <<
"choose target...\n";
364 if(best_rated_target == rated_targets.end()) {
365 LOG_AI <<
"no eligible targets found for unit at " << u->get_location() << std::endl;
366 return std::pair(u->get_location(), u->get_location());
369 assert(best_rating >= 0);
377 if(simple_targeting ==
false) {
378 LOG_AI <<
"complex targeting...\n";
380 for(++u; u != units_.
end(); ++u) {
382 u->movement_left() <= 0 || u->get_state(
"guardian") ||
395 const double locStopValue = 500.0;
399 if(cur_route.
steps.empty()) {
403 double rating =
rate_target(*best_target, u, dstsrc, enemy_dstsrc, cur_route);
405 if(best == units_.
end() || rating > best_rating) {
406 best_rating = rating;
408 best_route = cur_route;
412 LOG_AI <<
"done complex targeting...\n";
417 LOG_AI <<
"best unit: " << best->get_location() <<
'\n';
419 assert(best_target != targets.end());
424 if(best_target->type == target::TYPE::SUPPORT) {
427 std::vector<map_location> locs;
428 access_points(srcdst, best->get_location(), best_target->loc, locs);
430 if(locs.empty() ==
false) {
431 LOG_AI <<
"supporting unit at " << best_target->loc.wml_x() <<
"," << best_target->loc.wml_y() <<
"\n";
433 int best_defense = 0;
434 double best_vulnerability = 0.0;
436 for(std::vector<map_location>::const_iterator
i = locs.begin();
i != locs.end(); ++
i) {
437 const int defense = best->defense_modifier(map_.
get_terrain(*
i));
441 if(best_loc.
valid() ==
false || defense < best_defense || (defense == best_defense && vulnerability < best_vulnerability)) {
443 best_defense = defense;
444 best_vulnerability = vulnerability;
448 LOG_AI <<
"returning support...\n";
449 return std::pair(best->get_location(), best_loc);
453 std::map<map_location,pathfind::paths> dummy_possible_moves;
458 bool dangerous =
false;
461 LOG_AI <<
"grouping...\n";
463 int movement = best->movement_left();
465 const bool defensive_grouping =
get_grouping() ==
"defensive";
470 for(std::vector<map_location>::const_iterator
i = best_route.
steps.begin();
i != best_route.
steps.end() && movement > 0; ++
i) {
475 if ((threat >= best->hitpoints() && threat >
power_projection(*
i,fullmove_dstsrc)) ||
481 if(!defensive_grouping) {
486 LOG_AI <<
"done grouping...\n";
490 LOG_AI <<
"dangerous path\n";
491 std::set<map_location> group, enemies;
498 LOG_AI <<
"moving group\n";
503 LOG_AI <<
"group didn't move " << group.size() <<
"\n";
506 return std::pair(best->get_location(), best->get_location());
510 LOG_AI <<
"massing to attack " << best_target->loc.wml_x() <<
"," << best_target->loc.wml_y()
511 <<
" " << our_strength <<
"\n";
513 const double value = best_target->value;
516 const unit& un = *best;
518 targets.erase(best_target);
522 double best_threat = 0.0;
523 int best_distance = 0;
525 const double max_acceptable_threat = un.
hitpoints() / 4.0;
527 std::set<map_location> mass_locations;
529 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = srcdst.equal_range(loc);
530 for(move_map::const_iterator
i = itors.first;
i != itors.second; ++
i) {
536 if(best_loc.
valid() ==
false || (threat < std::max<double>(best_threat,max_acceptable_threat) && distance < best_distance)) {
537 best_loc =
i->second;
538 best_threat = threat;
539 best_distance = distance;
542 if(threat < max_acceptable_threat) {
543 mass_locations.insert(
i->second);
547 for(std::set<map_location>::const_iterator j = mass_locations.begin(); j != mass_locations.end(); ++j) {
549 LOG_AI <<
"found mass-to-attack target... " << *j <<
" with value: " << value*4.0 <<
"\n";
550 targets.emplace_back(*j,value*4.0,target::TYPE::MASS);
551 best_target = targets.end() - 1;
555 return std::pair<map_location,map_location>(loc,best_loc);
559 for(std::vector<map_location>::reverse_iterator ri =
560 best_route.
steps.rbegin(); ri != best_route.
steps.rend(); ++ri) {
564 bool is_dangerous =
false;
566 typedef std::multimap<map_location,map_location>::const_iterator Itor;
567 std::pair<Itor,Itor> its = dstsrc.equal_range(*ri);
568 while(its.first != its.second) {
569 if (its.first->second == best->get_location()) {
570 if(!
should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc,
572 double value = best_target->value - best->cost() / 20.0;
574 if(value > 0.0 && best_target->type != target::TYPE::MASS) {
578 LOG_AI <<
"found reinforcement target... " << its.first->first <<
" with value: " << value*2.0 <<
"\n";
579 targets.emplace_back(its.first->first,value*2.0,target::TYPE::BATTLE_AID);
582 best_target->value = value;
584 targets.erase(best_target);
587 LOG_AI <<
"Moving to " << its.first->first.wml_x() <<
"," << its.first->first.wml_y() <<
"\n";
589 return std::pair<map_location,map_location>(its.first->second,its.first->first);
600 if(best != units_.
end()) {
601 LOG_AI <<
"Could not make good move, staying still\n";
605 targets.emplace_back(best->get_location(), best_target->value);
606 best_target = targets.end() - 1;
607 return std::pair(best->get_location(), best->get_location());
610 LOG_AI <<
"Could not find anywhere to move!\n";
611 return std::pair<map_location,map_location>();
619 if(u_it == units_.
end()) {
625 const std::pair<move_map::const_iterator,move_map::const_iterator> locs = srcdst.equal_range(u);
626 for(move_map::const_iterator
i = locs.first;
i != locs.second; ++
i) {
628 if (static_cast<int>(
distance_between(loc,dst)) <= u_it->total_movement()) {
632 if(rt.
steps.empty() ==
false) {
641 const double a =
rate_group(our_group,battlefield);
642 const double b = std::max<double>(
rate_group(their_group,battlefield),0.01);
648 for(std::vector<map_location>::const_iterator
i = route.begin();
i != route.end(); ++
i) {
650 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(adj);
651 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
652 res.insert(j->second);
665 std::vector<map_location>::const_iterator
i;
666 for(i = route.begin(); i != route.end(); ++
i) {
667 if(units_.
count(*i) > 0) {
671 std::size_t
n = 0, nunits = res.size();
673 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*i);
674 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
675 if(res.count(j->second) != 0) {
679 if(un == units_.
end() || (un->can_recruit() && !
is_keep_ignoring_leader(un->id())) || un->movement_left() < un->total_movement()) {
683 res.insert(j->second);
693 if(i != route.begin()) {
705 const std::vector<map_location>::const_iterator itor = std::find(route.begin(),route.end(),dst);
706 if(itor == route.end()) {
710 LOG_AI <<
"group has " << units.size() <<
" members\n";
714 std::size_t direction = 0;
717 if(itor+1 != route.end()) {
719 }
else if(itor != route.begin()) {
725 direction = std::distance(adj.begin(), std::find(adj.begin(), adj.end(),
next));
728 std::deque<map_location> preferred_moves;
729 preferred_moves.push_back(dst);
731 std::map<map_location,pathfind::paths> possible_moves;
735 bool gamestate_changed =
false;
737 for(std::set<map_location>::const_iterator
i = units.begin();
i != units.end(); ++
i) {
739 if(un == units_.
end()) {
744 int best_defense = -1;
745 for(std::deque<map_location>::const_iterator j = preferred_moves.begin(); j != preferred_moves.end(); ++j) {
746 if(units_.
count(*j)) {
750 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*j);
751 move_map::const_iterator m;
752 for(m = itors.first; m != itors.second; ++m) {
753 if(m->second == *
i) {
758 if(m == itors.second) {
762 int defense = un->defense_modifier(map_.
get_terrain(*j));
763 if(best_loc.
valid() ==
false || defense < best_defense) {
765 best_defense = defense;
769 if(best_loc.
valid()) {
771 gamestate_changed |= move_res->is_gamestate_changed();
774 if (!move_res->is_ok()) {
775 return gamestate_changed;
778 preferred_moves.erase(std::find(preferred_moves.begin(),preferred_moves.end(),best_loc));
782 for(std::size_t
n = 0;
n < adj.size(); ++
n) {
783 if(
n != direction && ((
n+3)%6) != direction && map_.
on_board(adj[
n]) &&
784 units_.
count(adj[n]) == 0 && std::count(preferred_moves.begin(),preferred_moves.end(),adj[
n]) == 0) {
785 preferred_moves.push_front(adj[n]);
786 LOG_AI <<
"added moves: " << adj[
n].wml_x() <<
"," << adj[
n].wml_y() <<
"\n";
790 LOG_AI <<
"Could not move group member to any of " << preferred_moves.size() <<
" locations\n";
794 return gamestate_changed;
802 double strength = 0.0;
803 for(std::set<map_location>::const_iterator
i = group.begin();
i != group.end(); ++
i) {
805 if(u == units_.
end()) {
812 for(std::vector<map_location>::const_iterator j = battlefield.begin(); j != battlefield.end(); ++j) {
816 defense /= battlefield.size();
820 const int attack_strength =
a.num_attacks() *
a.damage();
821 best_attack = std::max<int>(attack_strength, best_attack);
825 strength +=
static_cast<double>(rating);
840 srcdst, enemy_dstsrc).chance_to_hit/100.0;
841 const double proposed_terrain =
846 const double exposure = proposed_terrain - optimal_terrain;
850 return caution*their_power*(1.0+exposure) > our_power;
map_location form_group(const std::vector< map_location > &route, const move_map &dstsrc, std::set< map_location > &res)
move_to_targets_phase(rca_context &context, const config &cfg)
virtual void raise_user_interact() const override
virtual std::string get_grouping() const override
int h() const
Effective map height, in hexes.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
virtual const unit_map & units() const override
This class represents a single unit of a specific type.
int movement_cost(const t_translation::terrain_code &terrain) const
Get the unit's movement cost on a particular terrain.
unit_iterator find_leader(int side)
remove_wrong_targets(const readonly_context &context)
Managing the AI-Game interaction - AI actions and their results.
int hitpoints() const
The current number of hitpoints this unit has.
virtual const move_map & get_srcdst() const override
std::shared_ptr< move_result > move_result_ptr
bool operator()(const rated_target &a, const rated_target &b) const
virtual const gamemap & map() const override
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
static lg::log_domain log_ai_testing_ca_move_to_targets("ai/ca/move_to_targets")
const terrain_filter & avoid_
bool on_board(const map_location &loc) const
Tell if a location is on the map.
double rate_group(const std::set< map_location > &group, const std::vector< map_location > &battlefield) const
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
static double getNoPathValue()
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit's defense on a given terrain.
A small explanation about what's going on here: Each action has access to two game_info objects First...
std::vector< map_location > steps
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
virtual std::vector< target > find_targets(const move_map &enemy_dstsrc)
Structure which holds a single route between one location and another.
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
bool is_allowed_unit(const unit &u) const
Flag indicating whether unit may be used by this candidate action.
std::vector< target >::iterator tg
Composite AI with turn sequence which is a vector of stages.
Encapsulates the map of the game.
const bool avoid_enemies_
double compare_groups(const std::set< map_location > &our_group, const std::set< map_location > &their_group, const std::vector< map_location > &battlefield) const
bool is_enemy(int n) const
virtual const move_map & get_enemy_dstsrc() const override
#define log_scope2(domain, description)
std::size_t count(const map_location &loc) const
int move_cost
Movement cost for reaching the end of the route.
Encapsulates the map of the game.
unit_iterator find(std::size_t id)
bool operator()(const target &t)
int w() const
Effective map width, in hexes.
virtual const team & current_team() const override
int max_hitpoints() const
The max number of hitpoints this unit can have.
attack_itors attacks()
Gets an iterator over this unit's attacks.
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const override
Function which finds how much 'power' a side can attack a certain location with.
virtual double get_scout_village_targeting() const override
virtual side_number get_side() const override
Get the side number.
double rate_target(const target &tg, const unit_map::iterator &u, const move_map &dstsrc, const move_map &enemy_dstsrc, const pathfind::plain_route &rt)
rate a target, but can also return the maximal possible rating by passing a dummy route ...
void enemies_along_path(const std::vector< map_location > &route, const move_map &dstsrc, std::set< map_location > &res)
move_cost_calculator(const unit &u, const gamemap &map, const unit_map &units, const move_map &enemy_dstsrc)
std::shared_ptr< move > move_ptr
Strategic movement routine, for experimentation.
virtual const std::vector< target > & additional_targets() const
virtual const move_map & get_dstsrc() const override
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.
bool move_group(const map_location &dst, const std::vector< map_location > &route, const std::set< map_location > &units)
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
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)
Container associating units to locations.
virtual bool is_keep_ignoring_leader(const std::string &id) const override
const move_map & enemy_dstsrc_
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.
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
rated_target(const std::vector< target >::iterator &t, double r)
virtual double get_caution() const override
static map_location::DIRECTION n
double get_score() const
Get the usual score of the candidate action without re-evaluation.
double cost(const map_location &loc, const double) const
This module contains various pathfinding functions and utilities.
virtual bool get_simple_targeting() const override
bool should_retreat(const map_location &loc, const unit_map::const_iterator &un, const move_map &srcdst, const move_map &dstsrc, const move_map &enemy_dstsrc, double caution)
std::string::const_iterator iterator
void access_points(const move_map &srcdst, const map_location &u, const map_location &dst, std::vector< map_location > &out)
virtual ~move_to_targets_phase()
std::pair< map_location, map_location > choose_move(std::vector< target > &targets)
virtual void execute()
Execute the candidate action.