ai_move.cpp

Go to the documentation of this file.
00001 /* $Id: ai_move.cpp 26030 2008-04-23 18:20:33Z alink $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version
00008    or at your option any later version2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include "ai.hpp"
00019 #include "game_config.hpp"
00020 #include "gettext.hpp"
00021 #include "log.hpp"
00022 #include "map.hpp"
00023 #include "util.hpp"
00024 #include "variable.hpp"
00025 #include "wml_exception.hpp"
00026 
00027 #include <cassert>
00028 #include <iostream>
00029 
00030 #define LOG_AI LOG_STREAM(info, ai)
00031 
00032 struct move_cost_calculator : cost_calculator
00033 {
00034     move_cost_calculator(const unit& u, const gamemap& map,
00035                          const unit_map& units,
00036                          const gamemap::location& loc,
00037                          const ai::move_map& dstsrc,
00038                          const ai::move_map& enemy_dstsrc)
00039       : unit_(u), map_(map), units_(units),
00040         loc_(loc), dstsrc_(dstsrc), enemy_dstsrc_(enemy_dstsrc),
00041         avoid_enemies_(u.usage() == "scout")
00042     {}
00043 
00044     virtual double cost(const gamemap::location&, const gamemap::location& loc, const double) const
00045     {
00046         /*
00047         if(!map_.on_board(loc))
00048             return 1000.0;
00049 
00050         // if this unit can move to that location this turn, it has a very very low cost
00051         typedef std::multimap<gamemap::location,gamemap::location>::const_iterator Itor;
00052         std::pair<Itor,Itor> range = dstsrc_.equal_range(loc);
00053         while(range.first != range.second) {
00054             if(range.first->second == loc_) {
00055                 return 0.01;
00056             }
00057             ++range.first;
00058         }
00059         */
00060         assert(map_.on_board(loc));
00061 
00062         const t_translation::t_terrain terrain = map_[loc];
00063 
00064         const double modifier = 1.0; //move_type_.defense_modifier(map_,terrain);
00065         const double move_cost = unit_.movement_cost(terrain);//move_type_[terrain];
00066 
00067         const int enemies = 1 + (avoid_enemies_ ? enemy_dstsrc_.count(loc) : 0);
00068         double res = modifier*move_cost*double(enemies);
00069 
00070         //if there is a unit (even a friendly one) on this tile, we increase the cost to
00071         //try discourage going through units, to thwart the 'single file effect'
00072         if (units_.count(loc))
00073             res *= 4.0;
00074 
00075         VALIDATE(res > 0,
00076             _("Movement cost is 0, probably a terrain with movement cost of 0."));
00077         return res;
00078     }
00079 
00080 private:
00081     const unit& unit_;
00082     const gamemap& map_;
00083     const unit_map& units_;
00084 //  mutable std::map<t_translation::t_terrain,int> move_type_;
00085     const gamemap::location loc_;
00086     const ai::move_map dstsrc_, enemy_dstsrc_;
00087     const bool avoid_enemies_;
00088 };
00089 
00090 std::vector<ai::target> ai::find_targets(unit_map::const_iterator leader, const move_map& enemy_dstsrc)
00091 {
00092     log_scope2(ai, "finding targets...");
00093 
00094     const bool has_leader = leader != units_.end();
00095 
00096     std::vector<target> targets;
00097 
00098     //if enemy units are in range of the leader, then we target the enemies who are in range.
00099     if(has_leader) {
00100         const double threat = power_projection(leader->first,enemy_dstsrc);
00101         if(threat > 0.0) {
00102             //find the location of enemy threats
00103             std::set<gamemap::location> threats;
00104 
00105             gamemap::location adj[6];
00106             get_adjacent_tiles(leader->first,adj);
00107             for(size_t n = 0; n != 6; ++n) {
00108                 std::pair<move_map::const_iterator,move_map::const_iterator> itors = enemy_dstsrc.equal_range(adj[n]);
00109                 while(itors.first != itors.second) {
00110                     if(units_.count(itors.first->second)) {
00111                         threats.insert(itors.first->second);
00112                     }
00113 
00114                     ++itors.first;
00115                 }
00116             }
00117 
00118             assert(threats.empty() == false);
00119 
00120             const double value = threat/double(threats.size());
00121             for(std::set<gamemap::location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
00122                 targets.push_back(target(*i,value,target::THREAT));
00123             }
00124         }
00125     }
00126 
00127     if(has_leader && current_team().village_value() > 0.0) {
00128         const std::vector<location>& villages = map_.villages();
00129         for(std::vector<location>::const_iterator t =
00130                 villages.begin(); t != villages.end(); ++t) {
00131 
00132             assert(map_.on_board(*t));
00133             bool get_village = true;
00134             for(size_t i = 0; i != teams_.size(); ++i) {
00135                 if(!current_team().is_enemy(i+1) && teams_[i].owns_village(*t)) {
00136                     get_village = false;
00137                     break;
00138                 }
00139             }
00140 
00141             if(get_village) {
00142                 targets.push_back(target(*t,current_team().village_value(),target::VILLAGE));
00143             }
00144         }
00145     }
00146 
00147     std::vector<team::target>& team_targets = current_team().targets();
00148 
00149     //find the enemy leaders and explicit targets
00150     unit_map::const_iterator u;
00151     for(u = units_.begin(); u != units_.end(); ++u) {
00152 
00153         //is an enemy leader
00154         if(u->second.can_recruit() &&
00155                 current_team().is_enemy(u->second.side())) {
00156 
00157             assert(map_.on_board(u->first));
00158             targets.push_back(target(u->first,current_team().leader_value(),target::LEADER));
00159         }
00160 
00161         //explicit targets for this team
00162         for(std::vector<team::target>::iterator j = team_targets.begin();
00163             j != team_targets.end(); ++j) {
00164             if(u->second.matches_filter(&(j->criteria),u->first)) {
00165                 LOG_AI << "found explicit target..." << j->value << "\n";
00166                 targets.push_back(target(u->first,j->value,target::EXPLICIT));
00167             }
00168         }
00169     }
00170 
00171     std::vector<double> new_values;
00172 
00173     for(std::vector<target>::iterator i = targets.begin();
00174         i != targets.end(); ++i) {
00175 
00176         new_values.push_back(i->value);
00177 
00178         for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
00179             if(i->loc == j->loc) {
00180                 continue;
00181             }
00182 
00183             const double distance = abs(j->loc.x - i->loc.x) +
00184                                     abs(j->loc.y - i->loc.y);
00185             new_values.back() += j->value/(distance*distance);
00186         }
00187     }
00188 
00189     assert(new_values.size() == targets.size());
00190     for(size_t n = 0; n != new_values.size(); ++n) {
00191         LOG_AI << "target value: " << targets[n].value << " -> " << new_values[n] << "\n";
00192         targets[n].value = new_values[n];
00193     }
00194 
00195     return targets;
00196 }
00197 
00198 gamemap::location ai::form_group(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
00199 {
00200     if(route.empty()) {
00201         return location();
00202     }
00203 
00204     std::vector<location>::const_iterator i;
00205     for(i = route.begin(); i != route.end(); ++i) {
00206         if(units_.count(*i) > 0) {
00207             continue;
00208         }
00209 
00210         size_t n = 0, nunits = res.size();
00211 
00212         const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*i);
00213         for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
00214             if(res.count(j->second) != 0) {
00215                 ++n;
00216             } else {
00217                 const unit_map::const_iterator un = units_.find(j->second);
00218                 if(un == units_.end() || un->second.can_recruit() || un->second.movement_left() < un->second.total_movement()) {
00219                     continue;
00220                 }
00221 
00222                 res.insert(j->second);
00223             }
00224         }
00225 
00226         //if not all our units can reach this position.
00227         if(n < nunits) {
00228             break;
00229         }
00230     }
00231 
00232     if(i != route.begin()) {
00233         --i;
00234     }
00235 
00236     return *i;
00237 }
00238 
00239 void ai::enemies_along_path(const std::vector<location>& route, const move_map& dstsrc, std::set<location>& res)
00240 {
00241     for(std::vector<location>::const_iterator i = route.begin(); i != route.end(); ++i) {
00242         gamemap::location adj[6];
00243         get_adjacent_tiles(*i,adj);
00244         for(size_t n = 0; n != 6; ++n) {
00245             const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(adj[n]);
00246             for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
00247                 res.insert(j->second);
00248             }
00249         }
00250     }
00251 }
00252 
00253 bool ai::move_group(const location& dst, const std::vector<location>& route, const std::set<location>& units)
00254 {
00255     const std::vector<location>::const_iterator itor = std::find(route.begin(),route.end(),dst);
00256     if(itor == route.end()) {
00257         return false;
00258     }
00259 
00260     LOG_AI << "group has " << units.size() << " members\n";
00261 
00262     location next;
00263 
00264     size_t direction = 0;
00265 
00266     //find the direction the group is moving in
00267     if(itor+1 != route.end()) {
00268         next = *(itor+1);
00269     } else if(itor != route.begin()) {
00270         next = *(itor-1);
00271     }
00272 
00273     if(next.valid()) {
00274         location adj[6];
00275         get_adjacent_tiles(dst,adj);
00276 
00277         direction = std::find(adj,adj+6,next) - adj;
00278     }
00279 
00280     std::deque<location> preferred_moves;
00281     preferred_moves.push_back(dst);
00282 
00283     std::map<location,paths> possible_moves;
00284     move_map srcdst, dstsrc;
00285     calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
00286 
00287     bool res = false;
00288 
00289     for(std::set<location>::const_iterator i = units.begin(); i != units.end(); ++i) {
00290         const unit_map::const_iterator un = units_.find(*i);
00291         if(un == units_.end()) {
00292             continue;
00293         }
00294 
00295         location best_loc;
00296         int best_defense = -1;
00297         for(std::deque<location>::const_iterator j = preferred_moves.begin(); j != preferred_moves.end(); ++j) {
00298             if(units_.count(*j)) {
00299                 continue;
00300             }
00301 
00302             const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*j);
00303             move_map::const_iterator m;
00304             for(m = itors.first; m != itors.second; ++m) {
00305                 if(m->second == *i) {
00306                     break;
00307                 }
00308             }
00309 
00310             if(m == itors.second) {
00311                 continue;
00312             }
00313 
00314             const int defense = un->second.defense_modifier(map_.get_terrain(*j));
00315             if(best_loc.valid() == false || defense < best_defense) {
00316                 best_loc = *j;
00317                 best_defense = defense;
00318             }
00319         }
00320 
00321         if(best_loc.valid()) {
00322             res = true;
00323             const location res = move_unit(*i,best_loc,possible_moves);
00324 
00325             //if we were ambushed, abort the group's movement.
00326             if(res != best_loc) {
00327                 return true;
00328             }
00329 
00330             preferred_moves.erase(std::find(preferred_moves.begin(),preferred_moves.end(),best_loc));
00331 
00332             //find locations that are 'perpendicular' to the direction of movement for further units to move to.
00333             location adj[6];
00334             get_adjacent_tiles(best_loc,adj);
00335             for(size_t n = 0; n != 6; ++n) {
00336                 if(n != direction && ((n+3)%6) != direction && map_.on_board(adj[n]) &&
00337                    units_.count(adj[n]) == 0 && std::count(preferred_moves.begin(),preferred_moves.end(),adj[n]) == 0) {
00338                     preferred_moves.push_front(adj[n]);
00339                     LOG_AI << "added moves: " << adj[n].x + 1 << "," << adj[n].y + 1 << "\n";
00340                 }
00341             }
00342         } else {
00343             LOG_AI << "Could not move group member to any of " << preferred_moves.size() << " locations\n";
00344         }
00345     }
00346 
00347     return res;
00348 }
00349 
00350 double ai::rate_group(const std::set<location>& group, const std::vector<location>& battlefield) const
00351 {
00352     double strength = 0.0;
00353     for(std::set<location>::const_iterator i = group.begin(); i != group.end(); ++i) {
00354         const unit_map::const_iterator u = units_.find(*i);
00355         if(u == units_.end()) {
00356             continue;
00357         }
00358 
00359         const unit& un = u->second;
00360 
00361         int defense = 0;
00362         for(std::vector<location>::const_iterator j = battlefield.begin(); j != battlefield.end(); ++j) {
00363             defense += un.defense_modifier(map_.get_terrain(*j));
00364         }
00365 
00366         defense /= battlefield.size();
00367 
00368         int best_attack = 0;
00369         const std::vector<attack_type>& attacks = un.attacks();
00370         for(std::vector<attack_type>::const_iterator a = attacks.begin(); a != attacks.end(); ++a) {
00371             const int strength = a->num_attacks()*a->damage();
00372             best_attack = maximum<int>(strength,best_attack);
00373         }
00374 
00375         const int rating = (defense*best_attack*un.hitpoints())/(100*un.max_hitpoints());
00376         strength += double(rating);
00377     }
00378 
00379     return strength;
00380 }
00381 
00382 double ai::compare_groups(const std::set<location>& our_group, const std::set<location>& their_group, const std::vector<location>& battlefield) const
00383 {
00384     const double a = rate_group(our_group,battlefield);
00385     const double b = maximum<double>(rate_group(their_group,battlefield),0.01);
00386     return a/b;
00387 }
00388 
00389 std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<target>& targets, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc)
00390 {
00391     log_scope2(ai, "choosing move");
00392 
00393     raise_user_interact();
00394 
00395     std::vector<target>::const_iterator ittg;
00396     for(ittg = targets.begin(); ittg != targets.end(); ++ittg) {
00397         assert(map_.on_board(ittg->loc));
00398     }
00399 
00400     paths::route best_route;
00401     unit_map::iterator best = units_.end();
00402     double best_rating = 0.1;
00403 
00404     std::vector<target>::iterator best_target = targets.end();
00405 
00406     unit_map::iterator u;
00407 
00408     //find the first eligible unit
00409     for(u = units_.begin(); u != units_.end(); ++u) {
00410         if(!(u->second.side() != team_num_ || u->second.can_recruit() || u->second.movement_left() <= 0 || u->second.incapacitated())) {
00411             break;
00412         }
00413     }
00414 
00415     if(u == units_.end()) {
00416         LOG_AI  << "no eligible units found\n";
00417         return std::pair<location,location>();
00418     }
00419 
00420     //guardian units stay put
00421     if(utils::string_bool(u->second.get_state("guardian"))) {
00422         LOG_AI << u->second.type_id() << " is guardian, staying still\n";
00423         return std::pair<location,location>(u->first,u->first);
00424     }
00425 
00426     const move_cost_calculator cost_calc(u->second, map_, units_, u->first, dstsrc, enemy_dstsrc);
00427 
00428     //choose the best target for that unit
00429     for(std::vector<target>::iterator tg = targets.begin(); tg != targets.end(); ++tg) {
00430         if(avoided_locations().count(tg->loc) > 0) {
00431             continue;
00432         }
00433 
00434         raise_user_interact();
00435 
00436         assert(map_.on_board(tg->loc));
00437 
00438         const double locStopValue = minimum(tg->value / best_rating, 500.0);
00439         paths::route cur_route = a_star_search(u->first, tg->loc, locStopValue, &cost_calc, map_.w(), map_.h());
00440 
00441         if (cur_route.move_left < locStopValue)
00442         {
00443             // if this unit can move to that location this turn, it has a very very low cost
00444             typedef std::multimap<gamemap::location,gamemap::location>::const_iterator multimapItor;
00445             std::pair<multimapItor,multimapItor> locRange = dstsrc.equal_range(u->first);
00446             while (locRange.first != locRange.second) {
00447                 if (locRange.first->second == u->first) {
00448                     cur_route.move_left = 0;
00449                 }
00450                 ++locRange.first;
00451             }
00452         }
00453 
00454         double rating = tg->value/maximum<int>(1,cur_route.move_left);
00455 
00456         //for 'support' targets, they are rated much higher if we can get there within two turns,
00457         //otherwise they are worthless to go for at all.
00458         if(tg->type == target::SUPPORT) {
00459             if(cur_route.move_left <= u->second.movement_left()*2) {
00460                 rating *= 10.0;
00461             } else {
00462                 rating = 0.0;
00463             }
00464         }
00465 
00466         //scouts do not like encountering enemies on their paths
00467         if(u->second.usage() == "scout") {
00468             std::set<location> enemies_guarding;
00469             enemies_along_path(cur_route.steps,enemy_dstsrc,enemies_guarding);
00470 
00471             if(enemies_guarding.size() > 1) {
00472                 rating /= enemies_guarding.size();
00473             } else {
00474                 //scouts who can travel on their route without coming in range of many enemies
00475                 //get a massive bonus, so that they can be processed first, and avoid getting
00476                 //bogged down in lots of grouping
00477                 rating *= 100;
00478             }
00479 
00480             //scouts also get a bonus for going after villages
00481             if(tg->type == target::VILLAGE) {
00482                 rating *= lexical_cast_default<int>(current_team().ai_parameters()["scout_village_targetting"],3);
00483             }
00484         }
00485 
00486         LOG_AI << tg->value << "/" << cur_route.move_left << " = " << rating << "\n";
00487         if(best_target == targets.end() || rating > best_rating) {
00488             best_rating = rating;
00489             best_target = tg;
00490             best = u;
00491             best_route = cur_route;
00492             if(best_rating == 0)
00493             {
00494                 best_rating = 0.000000001; //prevent divivion by zero
00495             }
00496         }
00497     }
00498 
00499     LOG_AI << "chose target...\n";
00500 
00501 
00502     if(best_target == targets.end()) {
00503         LOG_AI << "no eligible targets found\n";
00504         return std::pair<location,location>();
00505     }
00506 
00507     //if we have the 'simple_targetting' flag set, then we don't see if any other
00508     //units can put a better bid forward for this target
00509     const bool dumb_ai = utils::string_bool(current_team().ai_parameters()["simple_targetting"]);
00510 
00511     if(dumb_ai == false) {
00512         LOG_AI << "complex targetting...\n";
00513         //now see if any other unit can put a better bid forward
00514         for(++u; u != units_.end(); ++u) {
00515             if(u->second.side() != team_num_ || u->second.can_recruit() ||
00516                u->second.movement_left() <= 0 || utils::string_bool(u->second.get_state("guardian")) || u->second.incapacitated()) {
00517                 continue;
00518             }
00519 
00520             raise_user_interact();
00521 
00522             const move_cost_calculator calc(u->second, map_, units_, u->first, dstsrc, enemy_dstsrc);
00523             const double locStopValue = minimum(best_target->value / best_rating, 100.0);
00524             paths::route cur_route = a_star_search(u->first, best_target->loc, locStopValue, &calc, map_.w(), map_.h());
00525 
00526             if (cur_route.move_left < locStopValue)
00527             {
00528                 // if this unit can move to that location this turn, it has a very very low cost
00529                 typedef std::multimap<gamemap::location,gamemap::location>::const_iterator multimapItor;
00530                 std::pair<multimapItor,multimapItor> locRange = dstsrc.equal_range(u->first);
00531                 while (locRange.first != locRange.second) {
00532                     if (locRange.first->second == u->first) {
00533                         cur_route.move_left = 0;
00534                     }
00535                     ++locRange.first;
00536                 }
00537             }
00538 
00539             double rating = best_target->value/maximum<int>(1,cur_route.move_left);
00540 
00541             //for 'support' targets, they are rated much higher if we can get there within two turns,
00542             //otherwise they are worthless to go for at all.
00543             if(best_target->type == target::SUPPORT) {
00544                 if(cur_route.move_left <= u->second.movement_left()*2) {
00545                     rating *= 10.0;
00546                 } else {
00547                     rating = 0.0;
00548                 }
00549             }
00550 
00551             //scouts do not like encountering enemies on their paths
00552             if(u->second.usage() == "scout") {
00553                 std::set<location> enemies_guarding;
00554                 enemies_along_path(cur_route.steps,enemy_dstsrc,enemies_guarding);
00555 
00556                 if(enemies_guarding.size() > 1) {
00557                     rating /= enemies_guarding.size();
00558                 } else {
00559                     rating *= 100;
00560                 }
00561             }
00562 
00563             if(best == units_.end() || rating > best_rating) {
00564                 best_rating = rating;
00565                 best = u;
00566                 best_route = cur_route;
00567             }
00568         }
00569 
00570         LOG_AI << "done complex targetting...\n";
00571     } else {
00572         u = units_.end();
00573     }
00574 
00575     LOG_AI << "best unit: " << best->first << '\n';
00576 
00577     assert(best_target >= targets.begin() && best_target < targets.end());
00578 
00579     for(ittg = targets.begin(); ittg != targets.end(); ++ittg) {
00580         assert(map_.on_board(ittg->loc));
00581     }
00582 
00583     //if our target is a position to support, then we
00584     //see if we can move to a position in support of this target
00585     if(best_target->type == target::SUPPORT) {
00586         LOG_AI << "support...\n";
00587 
00588         std::vector<location> locs;
00589         access_points(srcdst,best->first,best_target->loc,locs);
00590 
00591         if(locs.empty() == false) {
00592             LOG_AI << "supporting unit at " << best_target->loc.x + 1 << "," << best_target->loc.y + 1 << "\n";
00593             location best_loc;
00594             int best_defense = 0;
00595             double best_vulnerability = 0.0;
00596             int best_distance = 0;
00597 
00598             for(std::vector<location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
00599                 const int distance = distance_between(*i,best_target->loc);
00600                 const int defense = best->second.defense_modifier(map_.get_terrain(*i));
00601                 const double vulnerability = power_projection(*i,enemy_dstsrc);
00602 
00603                 if(best_loc.valid() == false || defense < best_defense || (defense == best_defense && vulnerability < best_vulnerability)) {
00604                     best_loc = *i;
00605                     best_defense = defense;
00606                     best_vulnerability = vulnerability;
00607                     best_distance = distance;
00608                 }
00609             }
00610 
00611             LOG_AI << "returning support...\n";
00612             return std::pair<location,location>(best->first,best_loc);
00613         }
00614     }
00615 
00616     std::map<gamemap::location,paths> dummy_possible_moves;
00617     move_map fullmove_srcdst;
00618     move_map fullmove_dstsrc;
00619     calculate_possible_moves(dummy_possible_moves,fullmove_srcdst,fullmove_dstsrc,false,true);
00620 
00621     bool dangerous = false;
00622 
00623     if(current_team().ai_parameters()["grouping"] != "no") {
00624         LOG_AI << "grouping...\n";
00625         const unit_map::const_iterator unit_at_target = units_.find(best_target->loc);
00626         int movement = best->second.movement_left();
00627 
00628         const bool defensive_grouping = current_team().ai_parameters()["grouping"] == "defensive";
00629 
00630         //we stop and consider whether the route to this
00631         //target is dangerous, and whether we need to group some units to move in unison toward the target
00632         //if any point along the path is too dangerous for our single unit, then we hold back
00633         for(std::vector<location>::const_iterator i = best_route.steps.begin(); i != best_route.steps.end() && movement > 0; ++i) {
00634 
00635             const double threat = power_projection(*i,enemy_dstsrc);
00636             if((threat >= double(best->second.hitpoints()) && threat > power_projection(*i,fullmove_dstsrc)) ||
00637                (i >= best_route.steps.end()-2 && unit_at_target != units_.end() && current_team().is_enemy(unit_at_target->second.side()))) {
00638                 dangerous = true;
00639                 break;
00640             }
00641 
00642             if(!defensive_grouping) {
00643                 movement -= best->second.movement_cost(map_.get_terrain(*i));
00644             }
00645         }
00646 
00647         LOG_AI << "done grouping...\n";
00648     }
00649 
00650     if(dangerous) {
00651         LOG_AI << "dangerous path\n";
00652         std::set<location> group, enemies;
00653         const location dst = form_group(best_route.steps,dstsrc,group);
00654         enemies_along_path(best_route.steps,enemy_dstsrc,enemies);
00655 
00656         const double our_strength = compare_groups(group,enemies,best_route.steps);
00657 
00658         if(our_strength > 0.5 + current_team().caution()) {
00659             LOG_AI << "moving group\n";
00660             const bool res = move_group(dst,best_route.steps,group);
00661             if(res) {
00662                 return std::pair<location,location>(location(1,1),location());
00663             } else {
00664                 LOG_AI << "group didn't move " << group.size() << "\n";
00665 
00666                 //the group didn't move, so end the first unit in the group's turn, to prevent an infinite loop
00667                 return std::pair<location,location>(best->first,best->first);
00668 
00669             }
00670         } else {
00671             LOG_AI << "massing to attack " << best_target->loc.x + 1 << "," << best_target->loc.y + 1
00672                 << " " << our_strength << "\n";
00673 
00674             const double value = best_target->value;
00675             const location target_loc = best_target->loc;
00676             const location loc = best->first;
00677             const unit& un = best->second;
00678 
00679             targets.erase(best_target);
00680 
00681             //find the best location to mass units at for an attack on the enemies
00682             location best_loc;
00683             double best_threat = 0.0;
00684             int best_distance = 0;
00685 
00686             const double max_acceptable_threat = un.hitpoints()/4;
00687 
00688             std::set<location> mass_locations;
00689 
00690             const std::pair<move_map::const_iterator,move_map::const_iterator> itors = srcdst.equal_range(loc);
00691             for(move_map::const_iterator i = itors.first; i != itors.second; ++i) {
00692                 const int distance = distance_between(target_loc,i->second);
00693                 const int defense = un.defense_modifier(map_.get_terrain(i->second));
00694                 const double threat = (power_projection(i->second,enemy_dstsrc)*defense)/100;
00695 
00696                 if(best_loc.valid() == false || (threat < maximum<double>(best_threat,max_acceptable_threat) && distance < best_distance)) {
00697                     best_loc = i->second;
00698                     best_threat = threat;
00699                     best_distance = distance;
00700                 }
00701 
00702                 if(threat < max_acceptable_threat) {
00703                     mass_locations.insert(i->second);
00704                 }
00705             }
00706 
00707             for(std::set<location>::const_iterator j = mass_locations.begin(); j != mass_locations.end(); ++j) {
00708                 if(*j != best_loc && distance_between(*j,best_loc) < 3) {
00709                     targets.push_back(target(*j,value*4.0,target::MASS));
00710                 }
00711             }
00712 
00713             return std::pair<location,location>(loc,best_loc);
00714         }
00715     }
00716 
00717     for(std::vector<location>::reverse_iterator ri =
00718         best_route.steps.rbegin(); ri != best_route.steps.rend(); ++ri) {
00719 
00720         if(game_config::debug) {
00721             //game_display::debug_highlight(*ri,static_cast<size_t>(0.2));
00722         }
00723 
00724         //this is set to 'true' if we are hesitant to proceed because of enemy units,
00725         //to rally troops around us.
00726         bool is_dangerous = false;
00727 
00728         typedef std::multimap<location,location>::const_iterator Itor;
00729         std::pair<Itor,Itor> its = dstsrc.equal_range(*ri);
00730         while(its.first != its.second) {
00731             if(its.first->second == best->first) {
00732                 if(!should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc,
00733                                    current_team().caution())) {
00734                     const double value = best_target->value - best->second.cost()/20.0;
00735 
00736                     if(value > 0.0 && best_target->type != target::MASS) {
00737                         //there are enemies ahead. Rally troops around us to
00738                         //try to take the target
00739                         if(is_dangerous) {
00740                             targets.push_back(target(its.first->first,value*2.0,target::BATTLE_AID));
00741                         }
00742 
00743                         best_target->value = value;
00744                     } else {
00745                         targets.erase(best_target);
00746                     }
00747 
00748                     LOG_AI << "Moving to " << its.first->first.x + 1 << "," << its.first->first.y + 1 << "\n";
00749 
00750                     return std::pair<location,location>(its.first->second,its.first->first);
00751                 } else {
00752                     LOG_AI << "dangerous!\n";
00753                     is_dangerous = true;
00754                 }
00755             }
00756 
00757             ++its.first;
00758         }
00759     }
00760 
00761     if(best != units_.end()) {
00762         LOG_AI << "Could not make good move, staying still\n";
00763 
00764         //this sounds like the road ahead might be dangerous, and that's why we don't advance.
00765         //create this as a target, attempting to rally units around
00766         targets.push_back(target(best->first,best_target->value));
00767         return std::pair<location,location>(best->first,best->first);
00768     }
00769 
00770     LOG_AI << "Could not find anywhere to move!\n";
00771     return std::pair<location,location>();
00772 }
00773 
00774 void ai::access_points(const move_map& srcdst, const location& u, const location& dst, std::vector<location>& out)
00775 {
00776     const unit_map::const_iterator u_it = units_.find(u);
00777     if(u_it == units_.end()) {
00778         return;
00779     }
00780 
00781     // unit_map single_unit(u_it->first, u_it->second);
00782 
00783     const std::pair<move_map::const_iterator,move_map::const_iterator> locs = srcdst.equal_range(u);
00784     for(move_map::const_iterator i = locs.first; i != locs.second; ++i) {
00785         const location& loc = i->second;
00786         if (int(distance_between(loc,dst)) <= u_it->second.total_movement()) {
00787             shortest_path_calculator calc(u_it->second, current_team(), units_, teams_, map_);
00788             const paths::route& rt = a_star_search(loc, dst, u_it->second.total_movement(), &calc, map_.w(), map_.h());
00789             if(rt.steps.empty() == false) {
00790                 out.push_back(loc);
00791             }
00792         }
00793     }
00794 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs