00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "ca_testing_move_to_targets.hpp"
00022
00023 #include "../composite/ai.hpp"
00024 #include "../actions.hpp"
00025 #include "../../foreach.hpp"
00026 #include "../../log.hpp"
00027 #include "../../map.hpp"
00028 #include "../../resources.hpp"
00029 #include "../../team.hpp"
00030 #include "../../terrain_filter.hpp"
00031 #include "../../pathfind/pathfind.hpp"
00032
00033 #include <deque>
00034
00035 namespace ai {
00036
00037 namespace testing_ai_default {
00038
00039 static lg::log_domain log_ai_testing_ca_testing_move_to_targets("ai/ca/testing_move_to_targets");
00040 #define DBG_AI LOG_STREAM(debug, log_ai_testing_ca_testing_move_to_targets)
00041 #define LOG_AI LOG_STREAM(info, log_ai_testing_ca_testing_move_to_targets)
00042 #define WRN_AI LOG_STREAM(warn, log_ai_testing_ca_testing_move_to_targets)
00043 #define ERR_AI LOG_STREAM(err, log_ai_testing_ca_testing_move_to_targets)
00044
00045
00046
00047 struct move_cost_calculator : pathfind::cost_calculator
00048 {
00049 move_cost_calculator(const unit& u, const gamemap& map,
00050 const unit_map& units, const move_map& enemy_dstsrc)
00051 : unit_(u), map_(map), units_(units),
00052 enemy_dstsrc_(enemy_dstsrc),
00053 max_moves_(u.total_movement()),
00054 avoid_enemies_(u.usage() == "scout")
00055 {}
00056
00057 double cost(const map_location& loc, const double) const
00058 {
00059 const t_translation::t_terrain terrain = map_[loc];
00060
00061 const double move_cost = unit_.movement_cost(terrain);
00062
00063 if(move_cost > max_moves_)
00064 return getNoPathValue();
00065
00066 double res = move_cost;
00067 if(avoid_enemies_){
00068 res *= 1.0 + enemy_dstsrc_.count(loc);
00069 }
00070
00071
00072
00073 if (units_.count(loc))
00074 res *= 4.0;
00075
00076 return res;
00077 }
00078
00079 private:
00080 const unit& unit_;
00081 const gamemap& map_;
00082 const unit_map& units_;
00083 const move_map& enemy_dstsrc_;
00084 const int max_moves_;
00085 const bool avoid_enemies_;
00086 };
00087
00088
00089 class remove_wrong_targets {
00090 public:
00091 remove_wrong_targets(const readonly_context &context)
00092 :avoid_(context.get_avoid()), map_(*resources::game_map)
00093 {
00094 }
00095
00096 bool operator()(const target &t){
00097 if (!map_.on_board(t.loc)) {
00098 DBG_AI << "removing target "<< t.loc << " due to it not on_board" << std::endl;
00099 return true;
00100 }
00101
00102 if (t.value<=0) {
00103 DBG_AI << "removing target "<< t.loc << " due to value<=0" << std::endl;
00104 return true;
00105 }
00106
00107 if (avoid_.match(t.loc)) {
00108 DBG_AI << "removing target "<< t.loc << " due to 'avoid' match" << std::endl;
00109 return true;
00110 }
00111
00112 return false;
00113 }
00114 private:
00115 const terrain_filter &avoid_;
00116 const gamemap &map_;
00117
00118 };
00119
00120 testing_move_to_targets_phase::testing_move_to_targets_phase( rca_context &context, const config &cfg )
00121 : candidate_action(context,cfg)
00122 {
00123 }
00124
00125
00126 testing_move_to_targets_phase::~testing_move_to_targets_phase()
00127 {
00128 }
00129
00130
00131 double testing_move_to_targets_phase::evaluate()
00132 {
00133 return get_score();
00134 }
00135
00136
00137 void testing_move_to_targets_phase::execute()
00138 {
00139 unit_map::const_iterator leader = resources::units->find_leader(get_side());
00140 LOG_AI << "finding targets...\n";
00141 std::vector<target> targets;
00142 for(;;) {
00143 if(targets.empty()) {
00144 targets = find_targets(get_enemy_dstsrc());
00145 targets.insert(targets.end(),additional_targets().begin(),
00146 additional_targets().end());
00147 LOG_AI << "Found " << targets.size() << " targets\n";
00148 if(targets.empty()) {
00149 break;
00150 }
00151 }
00152
00153 targets.erase( std::remove_if(targets.begin(),targets.end(),remove_wrong_targets(*this)), targets.end() );
00154
00155 if(targets.empty()) {
00156 break;
00157 }
00158
00159 LOG_AI << "choosing move with " << targets.size() << " targets\n";
00160 std::pair<map_location,map_location> move = choose_move(targets, get_srcdst(),
00161 get_dstsrc(), get_enemy_dstsrc());
00162 LOG_AI << "choose_move ends with " << targets.size() << " targets\n";
00163
00164 for(std::vector<target>::const_iterator ittg = targets.begin();
00165 ittg != targets.end(); ++ittg) {
00166 assert(resources::game_map->on_board(ittg->loc));
00167 }
00168
00169 if(move.first.valid() == false || move.second.valid() == false) {
00170 break;
00171 }
00172
00173 assert (resources::game_map->on_board(move.first)
00174 && resources::game_map->on_board(move.second));
00175
00176 LOG_AI << "move: " << move.first << " -> " << move.second << '\n';
00177
00178 move_result_ptr move_ptr = execute_move_action(move.first,move.second,true);
00179 if(!move_ptr->is_ok()) {
00180 WRN_AI << "unexpected outcome of move"<<std::endl;
00181 break;
00182 }
00183 }
00184 }
00185
00186
00187
00188
00189
00190
00191 struct rated_target{
00192 rated_target(const std::vector<target>::iterator& t, double r) : tg(t), max_rating(r) {};
00193 std::vector<target>::iterator tg;
00194 double max_rating;
00195 };
00196
00197
00198
00199 struct rated_target_comparer {
00200 bool operator()(const rated_target& a, const rated_target& b) const {
00201 return a.max_rating > b.max_rating;
00202 }
00203 };
00204
00205
00206 double testing_move_to_targets_phase::rate_target(const target& tg, const unit_map::iterator& u,
00207 const move_map& dstsrc, const move_map& enemy_dstsrc,
00208 const pathfind::plain_route& rt)
00209 {
00210 double move_cost = rt.move_cost;
00211
00212 if(move_cost > 0) {
00213
00214 typedef std::multimap<map_location,map_location>::const_iterator multimapItor;
00215 std::pair<multimapItor,multimapItor> locRange = dstsrc.equal_range(tg.loc);
00216 while (locRange.first != locRange.second) {
00217 if (locRange.first->second == u->get_location()) {
00218 move_cost = 0;
00219 break;
00220 }
00221 ++locRange.first;
00222 }
00223 }
00224
00225 double rating = tg.value;
00226
00227 if(rating == 0)
00228 return rating;
00229
00230
00231 if(move_cost > 0) {
00232 rating /= move_cost;
00233 }
00234
00235
00236
00237 if(tg.type == target::SUPPORT) {
00238 if (move_cost <= u->movement_left() * 2) {
00239 rating *= 10.0;
00240 } else {
00241 rating = 0.0;
00242 return rating;
00243 }
00244 }
00245
00246
00247 if (u->usage() == "scout") {
00248
00249 if(tg.type == target::VILLAGE) {
00250 rating *= get_scout_village_targeting();
00251 }
00252
00253 std::set<map_location> enemies_guarding;
00254 enemies_along_path(rt.steps,enemy_dstsrc,enemies_guarding);
00255
00256
00257 if(enemies_guarding.size() > 1) {
00258 rating /= enemies_guarding.size();
00259 } else {
00260
00261
00262
00263 rating *= 100;
00264 }
00265 }
00266
00267 return rating;
00268 }
00269
00270
00271
00272 std::pair<map_location,map_location> testing_move_to_targets_phase::choose_move(std::vector<target>& targets, const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc)
00273 {
00274 log_scope2(log_ai_testing_ca_testing_move_to_targets, "choosing move");
00275
00276 raise_user_interact();
00277 unit_map &units_ = *resources::units;
00278 gamemap &map_ = *resources::game_map;
00279
00280 unit_map::iterator u;
00281
00282
00283 for(u = units_.begin(); u != units_.end(); ++u) {
00284 if (!(u->side() != get_side() || u->can_recruit() || u->movement_left() <= 0 || u->incapacitated())) {
00285 break;
00286 }
00287 }
00288
00289 if(u == units_.end()) {
00290 LOG_AI << "no eligible units found\n";
00291 return std::pair<map_location,map_location>();
00292 }
00293
00294
00295 if (u->get_state("guardian")) {
00296 LOG_AI << u->type_id() << " is guardian, staying still\n";
00297 return std::make_pair(u->get_location(), u->get_location());
00298 }
00299
00300 const pathfind::plain_route dummy_route;
00301 assert(dummy_route.steps.empty() && dummy_route.move_cost == 0);
00302
00303
00304
00305
00306
00307
00308 std::vector<rated_target> rated_targets;
00309 for(std::vector<target>::iterator tg = targets.begin(); tg != targets.end(); ++tg) {
00310
00311 double max_rating = rate_target(*tg, u, dstsrc, enemy_dstsrc, dummy_route);
00312 rated_targets.push_back( rated_target(tg, max_rating) );
00313 }
00314
00315
00316 std::stable_sort(rated_targets.begin(), rated_targets.end(), rated_target_comparer());
00317
00318 const move_cost_calculator cost_calc(*u, map_, units_, enemy_dstsrc);
00319
00320 pathfind::plain_route best_route;
00321 unit_map::iterator best = units_.end();
00322 double best_rating = -1.0;
00323
00324 std::vector<rated_target>::iterator best_rated_target = rated_targets.end();
00325
00326 std::vector<rated_target>::iterator rated_tg = rated_targets.begin();
00327
00328 for(; rated_tg != rated_targets.end(); ++rated_tg) {
00329 const target& tg = *(rated_tg->tg);
00330
00331 LOG_AI << "Considering target at: " << tg.loc <<"\n";
00332 assert(map_.on_board(tg.loc));
00333
00334 raise_user_interact();
00335
00336
00337
00338
00339 const double locStopValue = 500.0;
00340 pathfind::plain_route real_route = a_star_search(u->get_location(), tg.loc, locStopValue, &cost_calc, map_.w(), map_.h());
00341
00342 if(real_route.steps.empty()) {
00343 LOG_AI << "Can't reach target: " << locStopValue << " = " << tg.value << "/" << best_rating << "\n";
00344 continue;
00345 }
00346
00347 double real_rating = rate_target(tg, u, dstsrc, enemy_dstsrc, real_route);
00348
00349 LOG_AI << tg.value << "/" << real_route.move_cost << " = " << real_rating << "\n";
00350
00351 if(real_rating > best_rating){
00352 best_rating = real_rating;
00353 best_rated_target = rated_tg;
00354 best_route = real_route;
00355 best = u;
00356
00357
00358 if(best_rating == 0)
00359 best_rating = 0.000000001;
00360
00361
00362
00363
00364 if(rated_tg+1 != rated_targets.end() && best_rating >= (rated_tg+1)->max_rating)
00365 break;
00366 }
00367 }
00368
00369 LOG_AI << "choose target...\n";
00370
00371 if(best_rated_target == rated_targets.end()) {
00372 LOG_AI << "no eligible targets found for unit at " << u->get_location() << std::endl;
00373 return std::make_pair(u->get_location(), u->get_location());
00374 }
00375
00376 assert(best_rating >= 0);
00377 std::vector<target>::iterator best_target = best_rated_target->tg;
00378
00379
00380
00381
00382 bool simple_targeting = get_simple_targeting();
00383
00384 if(simple_targeting == false) {
00385 LOG_AI << "complex targeting...\n";
00386
00387 for(++u; u != units_.end(); ++u) {
00388 if (u->side() != get_side() || u->can_recruit() ||
00389 u->movement_left() <= 0 || u->get_state("guardian") ||
00390 u->incapacitated())
00391 {
00392 continue;
00393 }
00394
00395 raise_user_interact();
00396
00397 const move_cost_calculator calc(*u, map_, units_, enemy_dstsrc);
00398
00399
00400
00401
00402
00403
00404
00405 const double locStopValue = 500.0;
00406 pathfind::plain_route cur_route = pathfind::a_star_search(u->get_location(), best_target->loc, locStopValue, &calc, map_.w(), map_.h());
00407
00408 if(cur_route.steps.empty()) {
00409 continue;
00410 }
00411
00412 double rating = rate_target(*best_target, u, dstsrc, enemy_dstsrc, cur_route);
00413
00414 if(best == units_.end() || rating > best_rating) {
00415 best_rating = rating;
00416 best = u;
00417 best_route = cur_route;
00418 }
00419 }
00420
00421 LOG_AI << "done complex targeting...\n";
00422 } else {
00423 u = units_.end();
00424 }
00425
00426 LOG_AI << "best unit: " << best->get_location() << '\n';
00427
00428 assert(best_target != targets.end());
00429
00430
00431
00432 if(best_target->type == target::SUPPORT) {
00433 LOG_AI << "support...\n";
00434
00435 std::vector<map_location> locs;
00436 access_points(srcdst, best->get_location(), best_target->loc, locs);
00437
00438 if(locs.empty() == false) {
00439 LOG_AI << "supporting unit at " << best_target->loc.x + 1 << "," << best_target->loc.y + 1 << "\n";
00440 map_location best_loc;
00441 int best_defense = 0;
00442 double best_vulnerability = 0.0;
00443
00444 for(std::vector<map_location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
00445 const int defense = best->defense_modifier(map_.get_terrain(*i));
00446
00447 const double vulnerability = power_projection(*i,enemy_dstsrc);
00448
00449 if(best_loc.valid() == false || defense < best_defense || (defense == best_defense && vulnerability < best_vulnerability)) {
00450 best_loc = *i;
00451 best_defense = defense;
00452 best_vulnerability = vulnerability;
00453 }
00454 }
00455
00456 LOG_AI << "returning support...\n";
00457 return std::make_pair(best->get_location(), best_loc);
00458 }
00459 }
00460
00461 std::map<map_location,pathfind::paths> dummy_possible_moves;
00462 move_map fullmove_srcdst;
00463 move_map fullmove_dstsrc;
00464 calculate_possible_moves(dummy_possible_moves,fullmove_srcdst,fullmove_dstsrc,false,true);
00465
00466 bool dangerous = false;
00467
00468 if(get_grouping() != "no") {
00469 LOG_AI << "grouping...\n";
00470 const unit_map::const_iterator unit_at_target = units_.find(best_target->loc);
00471 int movement = best->movement_left();
00472
00473 const bool defensive_grouping = get_grouping() == "defensive";
00474
00475
00476
00477
00478 for(std::vector<map_location>::const_iterator i = best_route.steps.begin(); i != best_route.steps.end() && movement > 0; ++i) {
00479
00480
00481 const double threat = power_projection(*i,enemy_dstsrc);
00482
00483 if ((threat >= best->hitpoints() && threat > power_projection(*i,fullmove_dstsrc)) ||
00484 (i+1 >= best_route.steps.end()-1 && unit_at_target != units_.end() && current_team().is_enemy(unit_at_target->side()))) {
00485 dangerous = true;
00486 break;
00487 }
00488
00489 if(!defensive_grouping) {
00490 movement -= best->movement_cost(map_.get_terrain(*i));
00491 }
00492 }
00493
00494 LOG_AI << "done grouping...\n";
00495 }
00496
00497 if(dangerous) {
00498 LOG_AI << "dangerous path\n";
00499 std::set<map_location> group, enemies;
00500 const map_location dst = form_group(best_route.steps,dstsrc,group);
00501 enemies_along_path(best_route.steps,enemy_dstsrc,enemies);
00502
00503 const double our_strength = compare_groups(group,enemies,best_route.steps);
00504
00505 if(our_strength > 0.5 + get_caution()) {
00506 LOG_AI << "moving group\n";
00507 const bool res = move_group(dst,best_route.steps,group);
00508 if(res) {
00509 return std::pair<map_location,map_location>(map_location(1,1),map_location());
00510 } else {
00511 LOG_AI << "group didn't move " << group.size() << "\n";
00512
00513
00514 return std::make_pair(best->get_location(), best->get_location());
00515
00516 }
00517 } else {
00518 LOG_AI << "massing to attack " << best_target->loc.x + 1 << "," << best_target->loc.y + 1
00519 << " " << our_strength << "\n";
00520
00521 const double value = best_target->value;
00522 const map_location target_loc = best_target->loc;
00523 const map_location loc = best->get_location();
00524 const unit& un = *best;
00525
00526 targets.erase(best_target);
00527
00528
00529 map_location best_loc;
00530 double best_threat = 0.0;
00531 int best_distance = 0;
00532
00533 const double max_acceptable_threat = un.hitpoints()/4;
00534
00535 std::set<map_location> mass_locations;
00536
00537 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = srcdst.equal_range(loc);
00538 for(move_map::const_iterator i = itors.first; i != itors.second; ++i) {
00539 const int distance = distance_between(target_loc,i->second);
00540 const int defense = un.defense_modifier(map_.get_terrain(i->second));
00541
00542 const double threat = (power_projection(i->second,enemy_dstsrc)*defense)/100;
00543
00544 if(best_loc.valid() == false || (threat < std::max<double>(best_threat,max_acceptable_threat) && distance < best_distance)) {
00545 best_loc = i->second;
00546 best_threat = threat;
00547 best_distance = distance;
00548 }
00549
00550 if(threat < max_acceptable_threat) {
00551 mass_locations.insert(i->second);
00552 }
00553 }
00554
00555 for(std::set<map_location>::const_iterator j = mass_locations.begin(); j != mass_locations.end(); ++j) {
00556 if(*j != best_loc && distance_between(*j,best_loc) < 3) {
00557 LOG_AI << "found mass-to-attack target... " << *j << " with value: " << value*4.0 << "\n";
00558 targets.push_back(target(*j,value*4.0,target::MASS));
00559 best_target = targets.end() - 1;
00560 }
00561 }
00562
00563 return std::pair<map_location,map_location>(loc,best_loc);
00564 }
00565 }
00566
00567 for(std::vector<map_location>::reverse_iterator ri =
00568 best_route.steps.rbegin(); ri != best_route.steps.rend(); ++ri) {
00569
00570
00571
00572 bool is_dangerous = false;
00573
00574 typedef std::multimap<map_location,map_location>::const_iterator Itor;
00575 std::pair<Itor,Itor> its = dstsrc.equal_range(*ri);
00576 while(its.first != its.second) {
00577 if (its.first->second == best->get_location()) {
00578 if(!should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc,
00579 get_caution())) {
00580 double value = best_target->value - best->cost() / 20.0;
00581
00582 if(value > 0.0 && best_target->type != target::MASS) {
00583
00584
00585 if(is_dangerous) {
00586 LOG_AI << "found reinforcement target... " << its.first->first << " with value: " << value*2.0 << "\n";
00587 targets.push_back(target(its.first->first,value*2.0,target::BATTLE_AID));
00588 }
00589
00590 best_target->value = value;
00591 } else {
00592 targets.erase(best_target);
00593 }
00594
00595 LOG_AI << "Moving to " << its.first->first.x + 1 << "," << its.first->first.y + 1 << "\n";
00596
00597 return std::pair<map_location,map_location>(its.first->second,its.first->first);
00598 } else {
00599 LOG_AI << "dangerous!\n";
00600 is_dangerous = true;
00601 }
00602 }
00603
00604 ++its.first;
00605 }
00606 }
00607
00608 if(best != units_.end()) {
00609 LOG_AI << "Could not make good move, staying still\n";
00610
00611
00612
00613 targets.push_back(target(best->get_location(), best_target->value));
00614 best_target = targets.end() - 1;
00615 return std::make_pair(best->get_location(), best->get_location());
00616 }
00617
00618 LOG_AI << "Could not find anywhere to move!\n";
00619 return std::pair<map_location,map_location>();
00620 }
00621
00622 void testing_move_to_targets_phase::access_points(const move_map& srcdst, const map_location& u, const map_location& dst, std::vector<map_location>& out)
00623 {
00624 unit_map &units_ = *resources::units;
00625 gamemap &map_ = *resources::game_map;
00626 const unit_map::const_iterator u_it = units_.find(u);
00627 if(u_it == units_.end()) {
00628 return;
00629 }
00630
00631
00632
00633 const std::pair<move_map::const_iterator,move_map::const_iterator> locs = srcdst.equal_range(u);
00634 for(move_map::const_iterator i = locs.first; i != locs.second; ++i) {
00635 const map_location& loc = i->second;
00636 if (int(distance_between(loc,dst)) <= u_it->total_movement()) {
00637 pathfind::shortest_path_calculator calc(*u_it, current_team(), units_, *resources::teams, map_);
00638 pathfind::plain_route rt = a_star_search(loc, dst, u_it->total_movement(), &calc, map_.w(), map_.h());
00639 if(rt.steps.empty() == false) {
00640 out.push_back(loc);
00641 }
00642 }
00643 }
00644 }
00645
00646
00647 double testing_move_to_targets_phase::compare_groups(const std::set<map_location>& our_group, const std::set<map_location>& their_group, const std::vector<map_location>& battlefield) const
00648 {
00649 const double a = rate_group(our_group,battlefield);
00650 const double b = std::max<double>(rate_group(their_group,battlefield),0.01);
00651 return a/b;
00652 }
00653
00654
00655 void testing_move_to_targets_phase::enemies_along_path(const std::vector<map_location>& route, const move_map& dstsrc, std::set<map_location>& res)
00656 {
00657 for(std::vector<map_location>::const_iterator i = route.begin(); i != route.end(); ++i) {
00658 map_location adj[6];
00659 get_adjacent_tiles(*i,adj);
00660 for(size_t n = 0; n != 6; ++n) {
00661 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(adj[n]);
00662 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
00663 res.insert(j->second);
00664 }
00665 }
00666 }
00667 }
00668
00669
00670 map_location testing_move_to_targets_phase::form_group(const std::vector<map_location>& route, const move_map& dstsrc, std::set<map_location>& res)
00671 {
00672 unit_map &units_ = *resources::units;
00673 if(route.empty()) {
00674 return map_location();
00675 }
00676
00677 std::vector<map_location>::const_iterator i;
00678 for(i = route.begin(); i != route.end(); ++i) {
00679 if(units_.count(*i) > 0) {
00680 continue;
00681 }
00682
00683 size_t n = 0, nunits = res.size();
00684
00685 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*i);
00686 for(move_map::const_iterator j = itors.first; j != itors.second; ++j) {
00687 if(res.count(j->second) != 0) {
00688 ++n;
00689 } else {
00690 const unit_map::const_iterator un = units_.find(j->second);
00691 if(un == units_.end() || un->can_recruit() || un->movement_left() < un->total_movement()) {
00692 continue;
00693 }
00694
00695 res.insert(j->second);
00696 }
00697 }
00698
00699
00700 if(n < nunits) {
00701 break;
00702 }
00703 }
00704
00705 if(i != route.begin()) {
00706 --i;
00707 }
00708
00709 return *i;
00710 }
00711
00712
00713 bool testing_move_to_targets_phase::move_group(const map_location& dst, const std::vector<map_location>& route, const std::set<map_location>& units)
00714 {
00715 unit_map &units_ = *resources::units;
00716 gamemap &map_ = *resources::game_map;
00717
00718 const std::vector<map_location>::const_iterator itor = std::find(route.begin(),route.end(),dst);
00719 if(itor == route.end()) {
00720 return false;
00721 }
00722
00723 LOG_AI << "group has " << units.size() << " members\n";
00724
00725 map_location next;
00726
00727 size_t direction = 0;
00728
00729
00730 if(itor+1 != route.end()) {
00731 next = *(itor+1);
00732 } else if(itor != route.begin()) {
00733 next = *(itor-1);
00734 }
00735
00736 if(next.valid()) {
00737 map_location adj[6];
00738 get_adjacent_tiles(dst,adj);
00739
00740 direction = std::find(adj,adj+6,next) - adj;
00741 }
00742
00743 std::deque<map_location> preferred_moves;
00744 preferred_moves.push_back(dst);
00745
00746 std::map<map_location,pathfind::paths> possible_moves;
00747 move_map srcdst, dstsrc;
00748 calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
00749
00750 bool gamestate_changed = false;
00751
00752 for(std::set<map_location>::const_iterator i = units.begin(); i != units.end(); ++i) {
00753 const unit_map::const_iterator un = units_.find(*i);
00754 if(un == units_.end()) {
00755 continue;
00756 }
00757
00758 map_location best_loc;
00759 int best_defense = -1;
00760 for(std::deque<map_location>::const_iterator j = preferred_moves.begin(); j != preferred_moves.end(); ++j) {
00761 if(units_.count(*j)) {
00762 continue;
00763 }
00764
00765 const std::pair<move_map::const_iterator,move_map::const_iterator> itors = dstsrc.equal_range(*j);
00766 move_map::const_iterator m;
00767 for(m = itors.first; m != itors.second; ++m) {
00768 if(m->second == *i) {
00769 break;
00770 }
00771 }
00772
00773 if(m == itors.second) {
00774 continue;
00775 }
00776
00777 int defense = un->defense_modifier(map_.get_terrain(*j));
00778 if(best_loc.valid() == false || defense < best_defense) {
00779 best_loc = *j;
00780 best_defense = defense;
00781 }
00782 }
00783
00784 if(best_loc.valid()) {
00785 move_result_ptr move_res = execute_move_action(*i,best_loc);
00786 gamestate_changed |= move_res->is_gamestate_changed();
00787
00788
00789
00790 if (!move_res->is_ok()) {
00791 return gamestate_changed;
00792 }
00793
00794 preferred_moves.erase(std::find(preferred_moves.begin(),preferred_moves.end(),best_loc));
00795
00796
00797 map_location adj[6];
00798 get_adjacent_tiles(best_loc,adj);
00799 for(size_t n = 0; n != 6; ++n) {
00800 if(n != direction && ((n+3)%6) != direction && map_.on_board(adj[n]) &&
00801 units_.count(adj[n]) == 0 && std::count(preferred_moves.begin(),preferred_moves.end(),adj[n]) == 0) {
00802 preferred_moves.push_front(adj[n]);
00803 LOG_AI << "added moves: " << adj[n].x + 1 << "," << adj[n].y + 1 << "\n";
00804 }
00805 }
00806 } else {
00807 LOG_AI << "Could not move group member to any of " << preferred_moves.size() << " locations\n";
00808 }
00809 }
00810
00811 return gamestate_changed;
00812 }
00813
00814
00815 double testing_move_to_targets_phase::rate_group(const std::set<map_location>& group, const std::vector<map_location>& battlefield) const
00816 {
00817 unit_map &units_ = *resources::units;
00818 gamemap &map_ = *resources::game_map;
00819
00820 double strength = 0.0;
00821 for(std::set<map_location>::const_iterator i = group.begin(); i != group.end(); ++i) {
00822 const unit_map::const_iterator u = units_.find(*i);
00823 if(u == units_.end()) {
00824 continue;
00825 }
00826
00827 const unit &un = *u;
00828
00829 int defense = 0;
00830 for(std::vector<map_location>::const_iterator j = battlefield.begin(); j != battlefield.end(); ++j) {
00831 defense += un.defense_modifier(map_.get_terrain(*j));
00832 }
00833
00834 defense /= battlefield.size();
00835
00836 int best_attack = 0;
00837 const std::vector<attack_type>& attacks = un.attacks();
00838 for(std::vector<attack_type>::const_iterator a = attacks.begin(); a != attacks.end(); ++a) {
00839 const int strength = a->num_attacks()*a->damage();
00840 best_attack = std::max<int>(strength,best_attack);
00841 }
00842
00843 const int rating = (defense*best_attack*un.hitpoints())/(100*un.max_hitpoints());
00844 strength += double(rating);
00845 }
00846
00847 return strength;
00848 }
00849
00850
00851
00852 bool testing_move_to_targets_phase::should_retreat(const map_location& loc, const unit_map::const_iterator& un,
00853 const move_map& srcdst, const move_map& dstsrc, const move_map& enemy_dstsrc,
00854 double caution)
00855 {
00856 if(caution <= 0.0) {
00857 return false;
00858 }
00859
00860 double optimal_terrain = best_defensive_position(un->get_location(), dstsrc,
00861 srcdst, enemy_dstsrc).chance_to_hit/100.0;
00862 const double proposed_terrain =
00863 un->defense_modifier(resources::game_map->get_terrain(loc))/100.0;
00864
00865
00866
00867 const double exposure = proposed_terrain - optimal_terrain;
00868
00869 const double our_power = power_projection(loc,dstsrc);
00870 const double their_power = power_projection(loc,enemy_dstsrc);
00871 return caution*their_power*(1.0+exposure) > our_power;
00872 }
00873
00874 }
00875
00876 }