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)
66 double res = move_cost;
98 DBG_AI <<
"removing target "<< t.
loc <<
" due to it not on_board" << std::endl;
103 DBG_AI <<
"removing target "<< t.
loc <<
" due to value<=0" << std::endl;
108 DBG_AI <<
"removing target "<< t.
loc <<
" due to 'avoid' match" << std::endl;
140 LOG_AI <<
"finding targets...\n";
141 std::vector<target> targets;
143 if(targets.empty()) {
147 LOG_AI <<
"Found " << targets.size() <<
" targets\n";
148 if(targets.empty()) {
153 targets.erase( std::remove_if(targets.begin(),targets.end(),
remove_wrong_targets(*
this)), targets.end() );
155 if(targets.empty()) {
159 LOG_AI <<
"choosing move with " << targets.size() <<
" targets\n";
162 LOG_AI <<
"choose_move ends with " << targets.size() <<
" targets\n";
164 for(std::vector<target>::const_iterator ittg = targets.begin();
165 ittg != targets.end(); ++ittg) {
169 if(move.first.valid() ==
false || move.second.valid() ==
false) {
176 LOG_AI <<
"move: " << move.first <<
" -> " << move.second <<
'\n';
179 if(!move_ptr->is_ok()) {
180 WRN_AI <<
"unexpected outcome of move"<<std::endl;
214 typedef std::multimap<map_location,map_location>::const_iterator multimapItor;
215 std::pair<multimapItor,multimapItor> locRange = dstsrc.equal_range(tg.
loc);
216 while (locRange.first != locRange.second) {
217 if (locRange.first->second == u->get_location()) {
225 double rating = tg.
value;
237 if(tg.
type == target::TYPE::SUPPORT) {
238 if (move_cost <= u->movement_left() * 2) {
247 if (u->usage() ==
"scout") {
249 if(tg.
type == target::TYPE::VILLAGE) {
253 std::set<map_location> enemies_guarding;
257 if(enemies_guarding.size() > 1) {
258 rating /= enemies_guarding.size();
283 for(u = units_.
begin(); u != units_.
end(); ++u) {
289 if(u == units_.
end()) {
290 LOG_AI <<
"no eligible units found\n";
291 return std::pair<map_location,map_location>();
295 if (u->get_state(
"guardian")) {
296 LOG_AI << u->type_id() <<
" is guardian, staying still\n";
297 return std::make_pair(u->get_location(), u->get_location());
308 std::vector<rated_target> rated_targets;
311 double max_rating =
rate_target(*tg, u, dstsrc, enemy_dstsrc, dummy_route);
312 rated_targets.push_back(
rated_target(tg, max_rating) );
322 double best_rating = -1.0;
328 for(; rated_tg != rated_targets.end(); ++rated_tg) {
329 const target& tg = *(rated_tg->tg);
331 LOG_AI <<
"Considering target at: " << tg.
loc <<
"\n";
339 const double locStopValue = 500.0;
343 if(real_route.
steps.empty()) {
344 LOG_AI <<
"Can't reach target: " << locStopValue <<
" = " << tg.
value <<
"/" << best_rating <<
"\n";
348 double real_rating =
rate_target(tg, u, dstsrc, enemy_dstsrc, real_route);
352 if(real_rating > best_rating){
353 best_rating = real_rating;
354 best_rated_target = rated_tg;
355 best_route = real_route;
360 best_rating = 0.000000001;
365 if(rated_tg+1 != rated_targets.end() && best_rating >= (rated_tg+1)->max_rating)
370 LOG_AI <<
"choose target...\n";
372 if(best_rated_target == rated_targets.end()) {
373 LOG_AI <<
"no eligible targets found for unit at " << u->get_location() << std::endl;
374 return std::make_pair(u->get_location(), u->get_location());
377 assert(best_rating >= 0);
385 if(simple_targeting ==
false) {
386 LOG_AI <<
"complex targeting...\n";
388 for(++u; u != units_.
end(); ++u) {
390 u->movement_left() <= 0 || u->get_state(
"guardian") ||
406 const double locStopValue = 500.0;
410 if(cur_route.
steps.empty()) {
414 double rating =
rate_target(*best_target, u, dstsrc, enemy_dstsrc, cur_route);
416 if(best == units_.
end() || rating > best_rating) {
417 best_rating = rating;
419 best_route = cur_route;
423 LOG_AI <<
"done complex targeting...\n";
428 LOG_AI <<
"best unit: " << best->get_location() <<
'\n';
430 assert(best_target != targets.end());
434 if(best_target->type == target::TYPE::SUPPORT) {
437 std::vector<map_location> locs;
438 access_points(srcdst, best->get_location(), best_target->loc, locs);
440 if(locs.empty() ==
false) {
441 LOG_AI <<
"supporting unit at " << best_target->loc.x + 1 <<
"," << best_target->loc.y + 1 <<
"\n";
443 int best_defense = 0;
444 double best_vulnerability = 0.0;
446 for(std::vector<map_location>::const_iterator
i = locs.begin();
i != locs.end(); ++
i) {
447 const int defense = best->defense_modifier(map_.
get_terrain(*
i));
451 if(best_loc.
valid() ==
false || defense < best_defense || (defense == best_defense && vulnerability < best_vulnerability)) {
453 best_defense = defense;
454 best_vulnerability = vulnerability;
458 LOG_AI <<
"returning support...\n";
459 return std::make_pair(best->get_location(), best_loc);
463 std::map<map_location,pathfind::paths> dummy_possible_moves;
468 bool dangerous =
false;
471 LOG_AI <<
"grouping...\n";
473 int movement = best->movement_left();
475 const bool defensive_grouping =
get_grouping() ==
"defensive";
480 for(std::vector<map_location>::const_iterator
i = best_route.
steps.begin();
i != best_route.
steps.end() && movement > 0; ++
i) {
485 if ((threat >= best->hitpoints() && threat >
power_projection(*
i,fullmove_dstsrc)) ||
491 if(!defensive_grouping) {
496 LOG_AI <<
"done grouping...\n";
500 LOG_AI <<
"dangerous path\n";
501 std::set<map_location>
group, enemies;
508 LOG_AI <<
"moving group\n";
513 LOG_AI <<
"group didn't move " << group.size() <<
"\n";
516 return std::make_pair(best->get_location(), best->get_location());
520 LOG_AI <<
"massing to attack " << best_target->loc.x + 1 <<
"," << best_target->loc.y + 1
521 <<
" " << our_strength <<
"\n";
523 const double value = best_target->value;
526 const unit& un = *best;
528 targets.erase(best_target);
532 double best_threat = 0.0;
533 int best_distance = 0;
535 const double max_acceptable_threat = un.
hitpoints()/4;
537 std::set<map_location> mass_locations;
539 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = srcdst.equal_range(loc);
540 for(move_map::const_iterator
i = itors.first;
i != itors.second; ++
i) {
546 if(best_loc.
valid() ==
false || (threat < std::max<double>(best_threat,max_acceptable_threat) && distance < best_distance)) {
547 best_loc =
i->second;
548 best_threat = threat;
549 best_distance = distance;
552 if(threat < max_acceptable_threat) {
553 mass_locations.insert(
i->second);
557 for(std::set<map_location>::const_iterator j = mass_locations.begin(); j != mass_locations.end(); ++j) {
559 LOG_AI <<
"found mass-to-attack target... " << *j <<
" with value: " << value*4.0 <<
"\n";
560 targets.push_back(
target(*j,value*4.0,target::TYPE::MASS));
561 best_target = targets.end() - 1;
565 return std::pair<map_location,map_location>(loc,best_loc);
569 for(std::vector<map_location>::reverse_iterator ri =
570 best_route.
steps.rbegin(); ri != best_route.
steps.rend(); ++ri) {
574 bool is_dangerous =
false;
576 typedef std::multimap<map_location,map_location>::const_iterator Itor;
577 std::pair<Itor,Itor> its = dstsrc.equal_range(*ri);
578 while(its.first != its.second) {
579 if (its.first->second == best->get_location()) {
580 if(!
should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc,
582 double value = best_target->value - best->cost() / 20.0;
584 if(value > 0.0 && best_target->type != target::TYPE::MASS) {
588 LOG_AI <<
"found reinforcement target... " << its.first->first <<
" with value: " << value*2.0 <<
"\n";
589 targets.push_back(
target(its.first->first,value*2.0,target::TYPE::BATTLE_AID));
592 best_target->value =
value;
594 targets.erase(best_target);
597 LOG_AI <<
"Moving to " << its.first->first.x + 1 <<
"," << its.first->first.y + 1 <<
"\n";
599 return std::pair<map_location,map_location>(its.first->second,its.first->first);
610 if(best != units_.
end()) {
611 LOG_AI <<
"Could not make good move, staying still\n";
615 targets.push_back(
target(best->get_location(), best_target->value));
616 best_target = targets.end() - 1;
617 return std::make_pair(best->get_location(), best->get_location());
620 LOG_AI <<
"Could not find anywhere to move!\n";
621 return std::pair<map_location,map_location>();
629 if(u_it == units_.
end()) {
635 const std::pair<move_map::const_iterator,move_map::const_iterator> locs = srcdst.equal_range(u);
636 for(move_map::const_iterator
i = locs.first;
i != locs.second; ++
i) {
642 if(rt.
steps.empty() ==
false) {
652 const double a =
rate_group(our_group,battlefield);
653 const double b = std::max<double>(
rate_group(their_group,battlefield),0.01);
660 for(std::vector<map_location>::const_iterator
i = route.begin();
i != route.end(); ++
i) {
663 for(
size_t n = 0;
n != 6; ++
n) {
664 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(adj[
n]);
665 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
666 res.insert(j->second);
680 std::vector<map_location>::const_iterator
i;
681 for(i = route.begin(); i != route.end(); ++
i) {
682 if(units_.
count(*i) > 0) {
686 size_t n = 0, nunits = res.size();
688 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*i);
689 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
690 if(res.count(j->second) != 0) {
698 res.insert(j->second);
708 if(i != route.begin()) {
721 const std::vector<map_location>::const_iterator
itor =
std::find(route.begin(),route.end(),
dst);
722 if(itor == route.end()) {
726 LOG_AI <<
"group has " << units.size() <<
" members\n";
730 size_t direction = 0;
733 if(itor+1 != route.end()) {
735 }
else if(itor != route.begin()) {
743 direction =
std::find(adj,adj+6,next) - adj;
746 std::deque<map_location> preferred_moves;
747 preferred_moves.push_back(dst);
749 std::map<map_location,pathfind::paths> possible_moves;
753 bool gamestate_changed =
false;
755 for(std::set<map_location>::const_iterator
i = units.begin();
i != units.end(); ++
i) {
757 if(un == units_.
end()) {
762 int best_defense = -1;
763 for(std::deque<map_location>::const_iterator j = preferred_moves.begin(); j != preferred_moves.end(); ++j) {
764 if(units_.
count(*j)) {
768 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*j);
769 move_map::const_iterator
m;
770 for(m = itors.first; m != itors.second; ++m) {
771 if(m->second == *
i) {
776 if(m == itors.second) {
780 int defense = un->defense_modifier(map_.
get_terrain(*j));
781 if(best_loc.
valid() ==
false || defense < best_defense) {
783 best_defense = defense;
787 if(best_loc.
valid()) {
789 gamestate_changed |= move_res->is_gamestate_changed();
793 if (!move_res->is_ok()) {
794 return gamestate_changed;
797 preferred_moves.erase(
std::find(preferred_moves.begin(),preferred_moves.end(),best_loc));
802 for(
size_t n = 0;
n != 6; ++
n) {
803 if(
n != direction && ((
n+3)%6) != direction && map_.
on_board(adj[
n]) &&
804 units_.
count(adj[n]) == 0 &&
std::count(preferred_moves.begin(),preferred_moves.end(),adj[
n]) == 0) {
805 preferred_moves.push_front(adj[n]);
806 LOG_AI <<
"added moves: " << adj[
n].
x + 1 <<
"," << adj[
n].
y + 1 <<
"\n";
810 LOG_AI <<
"Could not move group member to any of " << preferred_moves.size() <<
" locations\n";
814 return gamestate_changed;
823 double strength = 0.0;
824 for(std::set<map_location>::const_iterator
i = group.begin();
i != group.end(); ++
i) {
826 if(u == units_.
end()) {
833 for(std::vector<map_location>::const_iterator j = battlefield.begin(); j != battlefield.end(); ++j) {
837 defense /= battlefield.size();
840 const std::vector<attack_type>& attacks = un.
attacks();
841 for(std::vector<attack_type>::const_iterator
a = attacks.begin();
a != attacks.end(); ++
a) {
842 const int strength =
a->num_attacks()*
a->damage();
843 best_attack = std::max<int>(strength,best_attack);
847 strength += double(rating);
864 srcdst, enemy_dstsrc).chance_to_hit/100.0;
865 const double proposed_terrain =
870 const double exposure = proposed_terrain - optimal_terrain;
874 return caution*their_power*(1.0+exposure) > our_power;
virtual side_number get_side() const
Get the side number.
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)
plain_route a_star_search(const map_location &src, const map_location &dst, double stop_at, const cost_calculator *calc, const size_t width, const size_t height, const teleport_map *teleports, bool border)
int max_hitpoints() const
virtual void raise_user_interact() const
virtual double get_caution() const
bool operator()(const rated_target &a, const rated_target &b) const
int movement_cost(const t_translation::t_terrain &terrain) const
size_t count(const map_location &loc) const
unit_iterator find_leader(int side)
remove_wrong_targets(const readonly_context &context)
Managing the AI-Game interaction - AI actions and their results.
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
double get_score() const
Get the usual score of the candidate action without re-evaluation.
bool is_enemy(int n) const
virtual std::string get_grouping() const
static lg::log_domain log_ai_testing_ca_move_to_targets("ai/ca/move_to_targets")
const terrain_filter & avoid_
GLsizeiptr const GLvoid GLenum usage
int defense_modifier(const t_translation::t_terrain &terrain) const
bool match(const map_location &loc) const
static double getNoPathValue()
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const
Function which finds how much 'power' a side can attack a certain location with.
GLdouble GLdouble GLdouble b
virtual double get_scout_village_targeting() const
double cost(const map_location &loc, const double) const
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
std::pair< map_location, map_location > choose_move(std::vector< target > &targets, const move_map &srcdst, const move_map &dstsrc, const move_map &enemy_dstsrc)
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.
std::vector< team > * teams
virtual std::vector< target > find_targets(const move_map &enemy_dstsrc)
Structure which holds a single route between one location and another.
virtual const std::vector< target > & additional_targets() const
size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
GLsizei const GLfloat * value
std::vector< target >::iterator tg
int w() const
Effective map width.
Composite AI with turn sequence which is a vector of stages.
GLboolean GLboolean GLboolean GLboolean a
Encapsulates the map of the game.
const bool avoid_enemies_
virtual bool get_leader_ignores_keep() const
#define log_scope2(domain, description)
virtual const move_map & get_srcdst() const
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
static const ::config * terrain
The terrain used to create the cache.
double rate_group(const std::set< map_location > &group, const std::vector< map_location > &battlefield) const
GLuint GLuint GLsizei count
virtual const move_map & get_enemy_dstsrc() const
const std::vector< attack_type > & attacks() const
int move_cost
Movement cost for reaching the end of the route.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
virtual bool get_simple_targeting() const
Encapsulates the map of the game.
bool operator()(const target &t)
std::map< std::string, tfilter >::iterator itor
int h() const
Effective map height.
defensive_position const & best_defensive_position(const map_location &unit, const move_map &dstsrc, const move_map &srcdst, const move_map &enemy_dstsrc) const
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 ...
virtual move_result_ptr execute_move_action(const map_location &from, const map_location &to, bool remove_movement=true, bool unreach_is_ok=false)
GLdouble GLdouble GLdouble r
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)
boost::shared_ptr< std::vector< unit_const_ptr > > units_
virtual const team & current_team() const
virtual const gamemap & map() const
t_translation::t_terrain get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Strategic movement routine, for experimentation.
bool move_group(const map_location &dst, const std::vector< map_location > &route, const std::set< map_location > &units)
bool find(E event, F functor)
Tests whether an event handler is available.
boost::shared_ptr< move > move_ptr
Standard logging facilities (interface).
Container associating units to locations.
double compare_groups(const std::set< map_location > &our_group, const std::set< map_location > &their_group, const std::vector< map_location > &battlefield) const
const move_map & enemy_dstsrc_
unit_iterator find(size_t id)
const teleport_map get_teleport_locations(const unit &u, const team &viewing_team, bool see_all, bool ignore_units)
A config object defines a single node in a WML file, with access to child nodes.
rated_target(const std::vector< target >::iterator &t, double r)
This module contains various pathfinding functions and utilities.
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)
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()
virtual const move_map & get_dstsrc() const
virtual void execute()
Execute the candidate action.