ai/testing/ca_testing_recruitment.cpp

Go to the documentation of this file.
00001 /* $Id: ca_testing_recruitment.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2009 - 2012 by Yurii Chernyi <terraninfo@terraninfo.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 as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (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 /**
00017 * @file
00018 * Experimental recruitment phase by Floris Kint
00019 */
00020 
00021 #include "ca_testing_recruitment.hpp"
00022 #include "../actions.hpp"
00023 #include "../manager.hpp"
00024 #include "../composite/engine.hpp"
00025 #include "../composite/rca.hpp"
00026 #include "../composite/stage.hpp"
00027 #include "../../gamestatus.hpp"
00028 #include "../../foreach.hpp"
00029 #include "../../log.hpp"
00030 #include "../../map.hpp"
00031 #include "../../resources.hpp"
00032 #include "../../team.hpp"
00033 #include "../../wml_exception.hpp"
00034 #include "../../pathfind/pathfind.hpp"
00035 
00036 
00037 #include <numeric>
00038 #include <string>
00039 #include <vector>
00040 #include <algorithm>
00041 #include <iostream>
00042 #include <map>
00043 
00044 
00045 namespace ai {
00046 
00047 namespace testing_ai_default {
00048 
00049 static lg::log_domain log_ai_ca_testing_recruitment("ai/ca/testing_recruitment");
00050 #define DBG_AI LOG_STREAM(debug, log_ai_ca_testing_recruitment)
00051 #define LOG_AI LOG_STREAM(info, log_ai_ca_testing_recruitment)
00052 #define WRN_AI LOG_STREAM(warn, log_ai_ca_testing_recruitment)
00053 #define ERR_AI LOG_STREAM(err, log_ai_ca_testing_recruitment)
00054 
00055 
00056 testing_recruitment_phase::testing_recruitment_phase( rca_context &context, const config &cfg )
00057 : candidate_action(context,cfg)
00058 {
00059 }
00060 
00061 
00062 testing_recruitment_phase::~testing_recruitment_phase()
00063 {
00064 }
00065 
00066 
00067 double testing_recruitment_phase::evaluate()
00068 {
00069    const unit_map::const_iterator leader = resources::units->find_leader(get_side());
00070    if(leader == resources::units->end()) {
00071       return BAD_SCORE;
00072    }
00073    if (!resources::game_map->is_keep(leader->get_location())) {
00074       return BAD_SCORE;
00075    }
00076 
00077    std::set<map_location> checked_hexes;
00078    checked_hexes.insert(leader->get_location());
00079    if (count_free_hexes_in_castle(leader->get_location(), checked_hexes)==0) {
00080       return BAD_SCORE;
00081    }
00082    return get_score();
00083 }
00084 
00085 
00086 class potential_recruit
00087 {
00088    public:
00089       bool operator==(const std::string &i) const
00090       {
00091          return id() == i;
00092       }
00093 
00094       potential_recruit(int cost, int max_qty, double quality, int side, const unit_type *type)
00095          : cost_(cost), max_qty_(max_qty), quality_(quality), side_(side), type_(type)
00096       {}
00097 
00098       const std::string& id() const
00099       {
00100          return type_->id();
00101       }
00102       int cost() const
00103       {
00104          return cost_;
00105       }
00106       double quality() const
00107       {
00108          return quality_;
00109       }
00110       void set_quality(double quality)
00111       {
00112          quality_ = quality;
00113       }
00114       int max_qty() const
00115       {
00116          return max_qty_;
00117       }
00118       int side() const
00119       {
00120          return side_;
00121       }
00122       const unit_type *type() const
00123       {
00124          return type_;
00125       }
00126    private:
00127       int cost_;
00128       int max_qty_;
00129       double quality_;
00130       int side_;
00131       const unit_type *type_;
00132 };
00133 
00134 class potential_recruit_converter
00135 {
00136    public:
00137       potential_recruit_converter(int max_qty, int side )
00138          : max_qty_ (max_qty), side_(side)
00139       {
00140       }
00141       potential_recruit operator()(const std::string &id)
00142       {
00143          const unit_type *type = unit_types.find(id);
00144          return potential_recruit(type->cost(),max_qty_,0,side_,type);
00145       }
00146    private:
00147       int max_qty_;
00148       int side_;
00149 };
00150 
00151 class fake_team
00152 {
00153    public:
00154       fake_team(const team &target)
00155          : target_(&target)
00156          , gold_(0)
00157          , extra_units_()
00158          , recruit_list_()
00159       {
00160          reset();
00161       }
00162 
00163       void reset()
00164       {
00165          extra_units_.clear();
00166          gold_ = target_->gold();
00167          recruit_list_.clear();
00168          std::transform(target_->recruits().begin(),target_->recruits().end(),std::back_inserter(recruit_list_), potential_recruit_converter(999,side()));//999 - unlimited recruits of this type
00169       }
00170 
00171       int gold()
00172       {
00173          return gold_;
00174       }
00175 
00176       void set_gold(int gold)
00177       {
00178          gold_ = gold;
00179       }
00180 
00181       void fake_recruit(const potential_recruit &r)
00182       {
00183          if (gold()<r.cost()) {
00184             ERR_AI <<  "ERROR: cannot fake recruit "<<r.id()<<", not enough gold" << std::endl;
00185             return;
00186          }
00187          if (get_current_qty(r)>=r.max_qty()) {
00188             ERR_AI << "ERROR: cannot fake recruit "<<r.id()<<", too many in the field" << std::endl;
00189             return;
00190          }
00191          DBG_AI << " Fake recruiting [" << r.id() << "] for side [" << side() << "]"<< std::endl;
00192          spend_gold(r.cost());
00193          extra_units_.push_back(r);//@todo: give an id if needed
00194       }
00195 
00196       std::vector<potential_recruit>& extra_units()
00197       {
00198          return extra_units_;
00199       }
00200 
00201       int get_current_qty(const potential_recruit &r) const
00202       {
00203          return get_current_qty(r.id());//@todo: fix
00204       }
00205 
00206       int get_current_qty(const std::string &name) const
00207       {
00208          int counter = 0;
00209          foreach(unit &un, *resources::units){
00210             if(un.side() == side() && un.type_id() == name) // @todo: is type_id good?
00211             {
00212                counter++;
00213             }
00214          }
00215          return std::count(extra_units_.begin(), extra_units_.end(), name) + counter;//@todo: fix
00216       }
00217 
00218       void spend_gold(int gold)
00219       {
00220          gold_-=gold;
00221       }
00222 
00223       int side() const
00224       {
00225          return target_->side();
00226       }
00227 
00228       bool is_enemy(int side) const
00229       {
00230          return target_->is_enemy(side);
00231       }
00232 
00233       std::vector<potential_recruit>& recruit_list()
00234       {
00235          return recruit_list_;
00236       }
00237 
00238       const std::vector<potential_recruit> &recruit_list() const
00239       {
00240          return recruit_list_;
00241       }
00242 
00243    private:
00244       const team *target_;
00245       int gold_;
00246       std::vector<potential_recruit> extra_units_;
00247       std::vector<potential_recruit> recruit_list_;
00248 };
00249 
00250 static int average_resistance_against(const unit_type& a, const unit_type& b)
00251 {
00252    gamemap &map_ = *resources::game_map;
00253 
00254    int weighting_sum = 0, defense = 0;
00255    const std::map<t_translation::t_terrain, size_t>& terrain =
00256       map_.get_weighted_terrain_frequencies();
00257 
00258    for (std::map<t_translation::t_terrain, size_t>::const_iterator j = terrain.begin(),
00259          j_end = terrain.end(); j != j_end; ++j)
00260    {
00261       // Use only reachable tiles when computing the average defense.
00262       if (a.movement_type().movement_cost(map_, j->first) < unit_movement_type::UNREACHABLE) {
00263          defense += a.movement_type().defense_modifier(map_, j->first) * j->second;
00264          weighting_sum += j->second;
00265       }
00266    }
00267 
00268    if (weighting_sum == 0) {
00269       // This unit can't move on this map, so just get the average weighted
00270       // of all available terrains. This still is a kind of silly
00271       // since the opponent probably can't recruit this unit and it's a static unit.
00272       for (std::map<t_translation::t_terrain, size_t>::const_iterator jj = terrain.begin(),
00273             jj_end = terrain.end(); jj != jj_end; ++jj)
00274       {
00275          defense += a.movement_type().defense_modifier(map_, jj->first) * jj->second;
00276          weighting_sum += jj->second;
00277       }
00278    }
00279 
00280    if(weighting_sum != 0) {
00281       defense /= weighting_sum;
00282    } else {
00283       LOG_AI << "The weighting sum is 0 and is ignored.\n";
00284    }
00285 
00286    //LOG_AI << "average defense of '" << a.id() << "': " << defense << "\n";
00287 
00288    int sum = 0, weight_sum = 0;
00289 
00290    // calculation of the average damage taken
00291    bool steadfast = a.has_ability_by_id("steadfast");
00292    bool living = !a.not_living();
00293    const std::vector<attack_type>& attacks = b.attacks();
00294    for (std::vector<attack_type>::const_iterator i = attacks.begin(),
00295          i_end = attacks.end(); i != i_end; ++i)
00296    {
00297       int resistance = a.movement_type().resistance_against(*i);
00298       // Apply steadfast resistance modifier.
00299       if (steadfast && resistance < 100)
00300          resistance = std::max<int>(resistance * 2 - 100, 50);
00301       // Do not look for filters or values, simply assume 70% if CTH is customized.
00302       int cth = i->get_special_bool("chance_to_hit", true) ? 70 : defense;
00303       int weight = i->damage() * i->num_attacks();
00304       // if cth == 0 the division will do 0/0 so don't execute this part
00305       if (living && cth != 0 && i->get_special_bool("poison", true)) {
00306          // Compute the probability of not poisoning the unit.
00307          int prob = 100;
00308          for (int j = 0; j < i->num_attacks(); ++j)
00309             prob = prob * (100 - cth);
00310          // Assume poison works one turn.
00311          weight += game_config::poison_amount * (100 - prob) / 100;
00312       }
00313       sum += cth * resistance * weight * weight; // average damage * weight
00314       weight_sum += weight;
00315    }
00316 
00317    // normalize by HP
00318    sum /= std::max<int>(1,std::min<int>(a.hitpoints(),1000)); // avoid values really out of range
00319 
00320    // Catch division by zero here if the attacking unit
00321    // has zero attacks and/or zero damage.
00322    // If it has no attack at all, the ai shouldn't prefer
00323    // that unit anyway.
00324    if (weight_sum == 0) {
00325       return sum;
00326    }
00327    return sum/weight_sum;
00328 }
00329 
00330 
00331 static int compare_unit_types(const unit_type& a, const unit_type& b)
00332 {
00333     const int a_effectiveness_vs_b = average_resistance_against(b,a);
00334     const int b_effectiveness_vs_a = average_resistance_against(a,b);
00335 
00336     DBG_AI << "    comparison of '" << a.id() << " vs " << b.id() << ": "
00337            << a_effectiveness_vs_b << " - " << b_effectiveness_vs_a << " = "
00338            << (a_effectiveness_vs_b - b_effectiveness_vs_a) << '\n';
00339     return a_effectiveness_vs_b - b_effectiveness_vs_a;
00340 }
00341 
00342 
00343 /*static double get_unit_quality(const unit_type &info, fake_team &t, std::vector<fake_team> & fake_teams)
00344 {
00345    const int hitpoints_const = 100;
00346    double score = 0;
00347    double total_weight = 0;
00348    foreach(const unit &enemy_unit, *resources::units)
00349    {
00350       if(enemy_unit.can_recruit() || !t.is_enemy(enemy_unit.side()))
00351       {
00352          continue;
00353       }
00354       const unit_type *enemy_info = unit_types.find(enemy_unit.type_id());
00355       double weight = enemy_unit.hitpoints() * hitpoints_const / enemy_unit.max_hitpoints();
00356       total_weight += weight;
00357       VALIDATE(enemy_info, "Unknown unit type : " + enemy_unit.type_id() + " while updating recruit quality.");
00358 
00359       score += compare_unit_types(info, *enemy_info) * weight;
00360    }
00361    foreach(fake_team &enemy_team, fake_teams)
00362    {
00363       if(!t.is_enemy(enemy_team.side()))
00364       {
00365          continue;
00366       }
00367       foreach(const potential_recruit &enemy_unit,  enemy_team.extra_units())
00368       {
00369          const unit_type *enemy_info = enemy_unit.type();
00370          VALIDATE(enemy_info, "Unknown unit type : " + enemy_unit.id() + " while updating recruit quality.");
00371 
00372          total_weight += hitpoints_const;
00373          score += compare_unit_types(info, *enemy_info) * hitpoints_const;
00374       }
00375    }
00376 
00377    if(total_weight != 0)
00378    {
00379       return score / total_weight;
00380    }
00381    else
00382    {
00383       return score;
00384    }
00385 }*/
00386 
00387 /*static void update_recruit_qualities(fake_team &t, std::vector<fake_team> &fake_teams)
00388 {
00389    foreach ( potential_recruit &recruit, t.recruit_list() )
00390    {
00391       double score = get_unit_quality(*recruit.type(),t,fake_teams);
00392       recruit.set_quality(score);
00393    }
00394 }*/
00395 
00396 struct potential_recruit_sorter
00397 {
00398    potential_recruit_sorter():max_cost(0), max_quality(0), quality_factor(0)
00399    {
00400    }
00401    potential_recruit_sorter(int max_cost_, double max_quality_, double quality_factor_) : max_cost(max_cost_), max_quality(max_quality_), quality_factor(quality_factor_)
00402    {
00403    }
00404    bool operator()(const potential_recruit *a, const potential_recruit *b)
00405    {
00406       return (a->quality() * quality_factor - a->cost()
00407             * (1.0 - quality_factor) * max_quality
00408             / static_cast<double>(max_cost))
00409         > (b->quality() * quality_factor - b->cost() * (1.0 - quality_factor)
00410             * max_quality / static_cast<double>(max_cost));
00411    }
00412 
00413    int max_cost;
00414    double max_quality;
00415    double quality_factor;
00416 };
00417 static std::vector<potential_recruit> ai_choose_best_recruits(fake_team &t, int max_units_to_recruit, double quality_factor, bool counter_recruit)
00418 {
00419     LOG_AI << "Running simple "<< (counter_recruit ? "counter-":"")<< "recruit selection algorithm for side "<< t.side() << std::endl;
00420     std::vector<potential_recruit> recruits;
00421     const std::vector<potential_recruit> &recruit_list = t.recruit_list();
00422     if(recruit_list.empty())
00423     {
00424         return recruits;
00425     }
00426 
00427    std::map<std::string, int> current_units;
00428    foreach (const potential_recruit &i, t.extra_units())
00429    {
00430       current_units[(i.id())]++;
00431    }
00432    foreach (const unit &i, *resources::units)
00433    {
00434     if (i.side()==t.side())
00435     {
00436         current_units[(i.type_id())]++;
00437     }
00438    }
00439    int gold = t.gold();
00440    double max_quality = recruit_list[0].quality();
00441    int max_cost = recruit_list[0].cost();
00442    std::vector<const potential_recruit*> sorted = std::vector<const potential_recruit*>();
00443    foreach(const potential_recruit &i, recruit_list)
00444    {
00445       if(i.cost() > max_cost)
00446       {
00447          max_cost = i.cost();
00448       }
00449       if(i.quality() > max_quality)
00450       {
00451          max_quality = i.quality();
00452       }
00453 
00454       LOG_AI <<"IN "<< (counter_recruit ? "COUNTER-" : "") <<"RECRUIT: side=["<<t.side()<<"] unit=["<<i.id()<<"] quality=["<<i.quality()<<"] cost=["<<i.cost()<<"]"<< std::endl;
00455       sorted.push_back(&i);
00456    }
00457    potential_recruit_sorter sorter(max_cost, max_quality, quality_factor);
00458    std::sort(sorted.begin(), sorted.end(), sorter);
00459    int recruited = 0;
00460    foreach(const potential_recruit *i, sorted)
00461    {
00462       if(recruited < max_units_to_recruit)
00463       {
00464          int possible_amount = static_cast<int>(gold / i->cost());
00465          if(possible_amount > max_units_to_recruit - recruited)
00466          {
00467             possible_amount = max_units_to_recruit - recruited;
00468          }
00469          if(possible_amount > i->max_qty() -  current_units[i->id()])
00470          {
00471             possible_amount = i->max_qty() - current_units[i->id()];
00472          }
00473          for(int j = 0; j < possible_amount; j++)
00474          {
00475             recruits.push_back(*i);
00476          }
00477          gold -= possible_amount * i->cost();
00478          recruited += possible_amount;
00479       }
00480       else
00481       {
00482          break;
00483       }
00484    }
00485    LOG_AI << "Finished simple recruit selection algorithm for side "<< t.side() << std::endl;
00486    return recruits;
00487 }
00488 static void ai_choose_recruits(fake_team &t, int max_units_to_recruit, double quality_factor, bool counter_recruit)
00489 {
00490     std::vector<potential_recruit> recruits = ai_choose_best_recruits(t, max_units_to_recruit, quality_factor, counter_recruit);
00491    foreach(potential_recruit &i, recruits) {
00492       t.fake_recruit(i);
00493    }
00494 
00495 }
00496 
00497 /*struct unit_data{
00498    unit_data(const std::string _id, const unit_type *_type):id(_id), type(*_type)
00499    {}
00500    const std::string id;
00501    const unit_type &type;
00502 };*/
00503 //class defender_pair_type{
00504 //public:
00505 //   //defender_pair_type(const unit_data *_defender):defender(_defender){}
00506 //   defender_pair_type(const unit_type *_defender):defender(_defender){}
00507 ////   ~defender_pair_type(){
00508 ////      delete defender;
00509 ////      for(unsigned int i = 0; i < enemies.size(); i++){
00510 ////         delete enemies[i];
00511 ////      }
00512 ////   }
00513 ////   const unit_data* defender;
00514 ////   std::vector<unit_data*> enemies;
00515 ////   void add_enemy(unit_data *data){
00516 ////      enemies.push_back(data);
00517 ////   }
00518 //   const unit_type *defender;
00519 //   std::vector<const unit_type*> enemies;
00520 //   void add_enemy(const unit_type *type){
00521 //      enemies.push_back(type);
00522 //   }
00523 //};
00524 //class enemy_pair_type{
00525 //public:
00526 ////   enemy_pair_type(const unit_data *_enemy):enemy(_enemy){
00527 ////      score = 0;
00528 ////
00529 ////   }
00530 ////   ~enemy_pair_type(){
00531 ////      delete enemy;
00532 ////      for(unsigned int i = 0; i < defenders.size(); i++){
00533 ////         delete defenders[i];
00534 ////      }
00535 ////   }
00536 ////   void add_defender(unit_data *data){
00537 ////      defenders.push_back(data);
00538 ////   }
00539 ////   const unit_data* enemy;
00540 ////   std::vector<unit_data*> defenders;
00541 //   enemy_pair_type(const unit_type *_enemy):enemy(_enemy){
00542 //      score = 0;
00543 //   }
00544 //   void add_defender(const unit_type *defender){
00545 //      defenders.push_back(defender);
00546 //   }
00547 //   const unit_type *enemy;
00548 //   std::vector<const unit_type*> defenders;
00549 //   double score;
00550 //};
00551 
00552 static void get_recruit_qualities(std::vector<potential_recruit> &recruit_list, fake_team &t, std::vector<fake_team> &fake_teams)
00553 {
00554    //DBG_AI << "start of get_recruit_qualities" << std::endl;
00555    typedef std::map<const unit_type*, std::vector<double> > unit_map;
00556    unit_map enemies;
00557    foreach(unit &un, *resources::units){
00558        if(t.is_enemy(un.side()) && !un.can_recruit()){
00559            enemies[un.type()].push_back(
00560               static_cast<double>(un.hitpoints())
00561             / static_cast<double>(un.max_hitpoints()));
00562        }
00563    }
00564    DBG_AI << "before extra_units of fake_teams: enemies.size() = " << enemies.size() << std::endl;
00565    foreach(fake_team &tmp_t, fake_teams)
00566    {
00567        if (t.is_enemy(tmp_t.side())) {
00568            foreach(potential_recruit &rec, tmp_t.extra_units())
00569            {
00570                enemies[rec.type()].push_back(1.0);
00571            }
00572        }
00573    }
00574    DBG_AI << "after extra_units of fake_teams: enemies.size() = " << enemies.size() << std::endl;
00575 
00576    foreach(potential_recruit &rec, recruit_list) {
00577        double score = 0;
00578        double weighting = 0;
00579        foreach(unit_map::value_type &enemy, enemies) {
00580            double hitpoints_sum = std::accumulate(enemy.second.begin(),enemy.second.end(),0);
00581            score += compare_unit_types(*rec.type(), *enemy.first) * hitpoints_sum;
00582            weighting += hitpoints_sum;
00583        }
00584        if (weighting!=0) {
00585            score /= weighting;
00586        }
00587        rec.set_quality(score);
00588        LOG_AI <<"side=["<<t.side()<<"] unit=["<<rec.id()<<"] quality=["<<rec.quality()<<"] cost=["<<rec.cost()<<"]"<< std::endl;
00589    }
00590 
00591 }
00592 
00593 /*
00594 class unit_type_health{
00595 public:
00596    unit_type_health(const unit_type *type, double health):type_(type), health_(health){
00597 
00598    }
00599    double health(){return health_;}
00600    const unit_type* type(){return type_;}
00601 protected:
00602    const unit_type* type_;
00603    double health_;
00604 };
00605 */
00606 
00607 static void get_recruit_qualities(fake_team &t, std::vector<fake_team> &fake_teams)
00608 {
00609     get_recruit_qualities(t.recruit_list(),t,fake_teams);
00610 }
00611 
00612 static void get_recruit_quality(potential_recruit &rec, fake_team &t, std::vector<fake_team> &fake_teams)
00613 {
00614     std::vector<potential_recruit> recruits;
00615     recruits.push_back(rec);
00616     get_recruit_qualities(recruits,t,fake_teams);
00617     rec.set_quality(recruits[0].quality());
00618 }
00619 
00620 /*static double get_combat_score2(fake_team &t, std::vector<fake_team> &fake_teams)
00621 {
00622    std::vector<defender_pair_type*> defenders;
00623    std::vector<enemy_pair_type*> enemies;
00624    foreach(unit &un, *resources::units)
00625    {
00626       if(t.is_enemy(un.side()))
00627       {
00628 //         const unit_type &enemy_type = *un.type();
00629          //enemy_pair_type *pair = new enemy_pair_type(new unit_data(un.id(), un.type()));
00630          enemy_pair_type *pair = new enemy_pair_type(un.type());
00631          foreach(unit &defender, *resources::units)
00632          {
00633             if(!t.is_enemy(defender.side())){
00634                //int score = compare_unit_types(*defender.type(), enemy_type);
00635                //if(score >= 0)
00636                //{
00637                   //pair->add_defender(new unit_data(defender.id(), defender.type()));
00638                pair->add_defender(defender.type());
00639                //}
00640             }
00641          }
00642          foreach(fake_team &tmp_t, fake_teams){
00643             if(!t.is_enemy(tmp_t.side())){
00644                foreach(potential_recruit &rec, tmp_t.extra_units()){
00645          //         int score = compare_unit_types(*rec.type(), enemy_type);
00646          //         if(score >= 0){
00647                      //pair->add_defender(new unit_data(rec.id(), rec.type()));
00648                      pair->add_defender(rec.type());
00649          //         }
00650                }
00651             }
00652          }
00653          enemies.push_back(pair);
00654       }
00655       else
00656       {
00657          //const unit_type &defender_type = *un.type();
00658          //defender_pair_type *pair = new defender_pair_type(new unit_data(un.id(), un.type()));
00659          defender_pair_type *pair = new defender_pair_type(un.type());
00660          foreach(unit &enemy, *resources::units)
00661          {
00662             //int score = compare_unit_types(defender_type, *enemy.type());
00663             //if(score >= 0)
00664             //{
00665                //pair->add_enemy(new unit_data(enemy.id(), enemy.type()));
00666             pair->add_enemy(enemy.type());
00667             //}
00668          }
00669          foreach(fake_team &tmp_t, fake_teams){
00670             if(t.is_enemy(tmp_t.side())){
00671                foreach(potential_recruit &rec, tmp_t.extra_units()){
00672                   //int score = compare_unit_types(defender_type, *rec.type());
00673                   //if(score >= 0){
00674                      //pair->add_enemy(new unit_data(rec.id(), rec.type()));
00675                   pair->add_enemy(rec.type());
00676                   //}
00677                }
00678             }
00679          }
00680          defenders.push_back(pair);
00681       }
00682    }
00683    foreach(fake_team &tmp_t, fake_teams)
00684    {
00685       foreach(potential_recruit &rec, tmp_t.extra_units()){
00686          if(t.is_enemy(tmp_t.side())){
00687             //const unit_type &enemy_type = *rec.type();
00688             //enemy_pair_type *pair = new enemy_pair_type(new unit_data(rec.id(), rec.type()));
00689             enemy_pair_type *pair = new enemy_pair_type(rec.type());
00690             foreach(unit &defender, *resources::units){
00691                if(t.is_enemy(defender.side())){
00692                   continue;
00693                }
00694                //int score = compare_unit_types(*defender.type(), enemy_type);
00695                //if(score >= 0){
00696                   //pair->add_defender(new unit_data(defender.id(), defender.type()));
00697                pair->add_defender(defender.type());
00698                //}
00699             }
00700             //HIER
00701             foreach(fake_team &sub_t, fake_teams){
00702                if(t.is_enemy(sub_t.side())){
00703                   continue;
00704                }
00705                foreach(potential_recruit &sub_rec, sub_t.extra_units()){
00706                   //int score = compare_unit_types(*sub_rec.type(), enemy_type);
00707                   //if(score >= 0){
00708                      //pair->add_defender(new unit_data(sub_rec.id(), sub_rec.type()));
00709                   pair->add_defender(sub_rec.type());
00710                   //}
00711                }
00712             }
00713             enemies.push_back(pair);
00714          }else{
00715             //const unit_type &defender_type = *rec.type();
00716             //defender_pair_type *pair = new defender_pair_type(new unit_data(rec.id(), rec.type()));
00717             defender_pair_type *pair = new defender_pair_type(rec.type());
00718             foreach(unit &enemy, *resources::units)
00719             {
00720                if(!t.is_enemy(enemy.side())){
00721                   continue;
00722                }
00723             //   int score = compare_unit_types(defender_type, *enemy.type());
00724             //   if(score >= 0){
00725                   //pair->add_enemy(new unit_data(rec.id(), rec.type()));
00726                pair->add_enemy(rec.type());
00727             //   }
00728             }
00729             foreach(fake_team &sub_t, fake_teams){
00730                if(!t.is_enemy(sub_t.side())){
00731                   continue;
00732                }
00733                foreach(potential_recruit &sub_rec, sub_t.extra_units()){
00734                //   int score = compare_unit_types(defender_type, *sub_rec.type());
00735                //   if(score >= 0){
00736                      //pair->add_enemy(new unit_data(sub_rec.id(), sub_rec.type()));
00737                   pair->add_enemy(sub_rec.type());
00738                //   }
00739                }
00740             }
00741             defenders.push_back(pair);
00742          }
00743       }
00744    }
00745    double min_score = 0;
00746    double max_score = 0;
00747    foreach(enemy_pair_type *pair, enemies)
00748    {
00749 //      if(pair->defenders.size() == 0)
00750 //      {
00751 //         pair->score = -10000;
00752 //      }else{
00753          //foreach(unit_data *defender, pair->defenders)
00754          foreach(unit_type *defender, pair->defenders)
00755          {
00756             unsigned int defender_enemies = 0;
00757             foreach(defender_pair_type *defender_p, defenders)
00758             {
00759                //if(defender->id == defender_p->defender->id){
00760                if(defender->type_name()() == defender_p->defender->type_name()){
00761                   defender_enemies = defender_p->enemies.size();
00762                   break;
00763                }
00764             }
00765             //double tmpscore =(compare_unit_types(defender->type, pair->enemy->type) / ((defender_enemies != 0) ? defender_enemies : 1 ));
00766             double tmpscore =(compare_unit_types(defender, pair->enemy) / ((defender_enemies != 0) ? defender_enemies : 1 ));
00767             if(tmpscore > 0){
00768                pair->score += tmpscore;
00769                std::cout << defender->type_name() << " resistance against " << pair->enemy->type_name() << " is: " << tmpscore << ", new score = " << pair->score << std::endl;
00770             }
00771          }
00772          if(pair->score > max_score)
00773             max_score = pair->score;
00774          if(pair->score < min_score)
00775             min_score = pair->score;
00776          std::cout << pair->enemy->id << " resistance = " << pair->score << std::endl;
00777       //}
00778    }
00779    double score = 0;
00780    score -= max_score - min_score;
00781    foreach(enemy_pair_type *pair, enemies)
00782    {
00783       score += pair->score;
00784    }
00785 
00786    for(unsigned int i = 0; i < enemies.size(); i++)
00787    {
00788       delete enemies[i];
00789    }
00790    for(unsigned int i = 0; i < defenders.size(); i++)
00791    {
00792       delete defenders[i];
00793    }
00794    return score;
00795 }*/
00796 /*static double get_combat_score(fake_team &t, std::vector<fake_team> &fake_teams)
00797 {
00798    typedef std::map<const unit_type*, std::vector<double> > unit_map;
00799    unit_map enemies;
00800    unit_map defenders;
00801    foreach(unit &un, *resources::units){
00802       if(t.is_enemy(un.side())){
00803          enemies[un.type()].push_back((double)un.hitpoints() / (double)un.max_hitpoints());
00804       }else{
00805          defenders[un.type()].push_back(un.hitpoints() / un.max_hitpoints());
00806       }
00807    }
00808    foreach(fake_team &tmp_t, fake_teams)
00809    {
00810       foreach(potential_recruit &rec, tmp_t.extra_units())
00811       {
00812          if(t.is_enemy(tmp_t.side())){
00813             enemies[rec.type()].push_back(1.0);
00814          }else{
00815             defenders[rec.type()].push_back(1.0);
00816          }
00817       }
00818    }
00819    double result = 0;
00820    foreach(unit_map::value_type &defender, defenders)
00821    {
00822       double defenders_score = 0;
00823       foreach(unit_map::value_type &enemy, enemies)
00824       {
00825          double hitpoints_sum = 0;
00826          foreach(double i, enemy.second)
00827          {
00828             hitpoints_sum += i;
00829          }
00830          defenders_score += compare_unit_types(*defender.first, *enemy.first) / ((hitpoints_sum == 0)?1:hitpoints_sum);
00831 
00832       }
00833       double hitpoints_sum = 0;
00834       foreach(double i, defender.second)
00835       {
00836          hitpoints_sum += i;
00837       }
00838       defenders_score *= hitpoints_sum;
00839 
00840       result += defenders_score;
00841    }
00842    return result;
00843 //   vector<defender_pair> defenders;
00844 //   vector<enemy_pair> enemies;
00845 //   //foreach(unit &un, *resources::units)
00846 //   //{
00847 //   //   if(t.is_enemy(un.side()))
00848 //   //   {
00849 //   //      enemies.push_back(un.id());
00850 //   //   }else{
00851 //   //      defenders.push_back(un.id());
00852 //   //   }
00853 //   //}
00854 //   foreach(unit &un, *resources::units)
00855 //   {
00856 //      if(t.is_enemy(un.side()))
00857 //      {
00858 //         const unit_type &enemy_type = un.type();
00859 //         enemy_pair pair;
00860 //         pair.enemy = new unit_data(un.id(), enemy_type);
00861 //         foreach(unit &defender, *resources::units)
00862 //         {
00863 //            int score = compare_unit_types(defender.type(), enemy_type);
00864 //            if(score >= 0)
00865 //            {
00866 //               pair.defenders.push_back(new unit_data(defender.id(), defender.type()));
00867 //            }
00868 //         }
00869 //         defenders.push_back(pair);
00870 //      }
00871 //      else
00872 //      {
00873 //         const unit_type &defender_type = un.type();
00874 //         defender_pair pair;
00875 //         pair.defender = new unit_data(defender.id(), defender_type);
00876 //         foreach(unit &enemy, *resources::units)
00877 //         {
00878 //            int score = compare_unit_types(defender_type, enemy.type());
00879 //            if(score >= 0)
00880 //            {
00881 //               pair.enemies.push_back(new unit_data(enemy.id(), enemy.type()));
00882 //               //pair.score += score;
00883 //            }
00884 //         }
00885 //         enemies.push_back(pair);
00886 //      }
00887 //   }
00888 //   foreach(fake_team &tmp_t, fake_teams)
00889 //   {
00890 //      if(t.is_enemy(tmp_t.side())){
00891 //         foreach(potential_recruit &rec, tmp_t.extra_units())
00892 //         {
00893 //
00894 //         }
00895 //      }else{
00896 //
00897 //      }
00898 //
00899 //   }
00900 //   //std::vector<unit> no_defense_enemies;
00901 //   foreach(enemy_pair &pair, enemies)
00902 //   {
00903 //      if(pair.defenders.size() == 0)
00904 //      {
00905 //         //no_defense_enemies.push_back(pair.enemy);
00906 //
00907 //         pair.score = 0;
00908 //      }else{
00909 //         foreach(unit_data &defender, pair.defenders)
00910 //         {
00911 //            //unit_type &defender = defender_data.type;
00912 //            unsigned int defender_enemies = 0;
00913 //            foreach(defender_pair &defender_p, defenders)
00914 //            {
00915 //               if(defender.id == defender_p.defender.id){
00916 //                  defender_enemies = defender_p.enemies.size();
00917 //                  break;
00918 //               }
00919 //            }
00920 //
00921 //            pair.score += (compare_unit_types(defender.type, pair.enemy.type) / ((defender_enemies != 0) ? defender_enemies : 1 ));
00922 //         }
00923 //      }
00924 //   }
00925 //   //enemy_pair *worst_pair = &enemies[0];
00926 //   double total_score = 0;
00927 //   foreach(enemy_pair &pair, enemies)
00928 //   {
00929 //      total_score += pair.score;
00930 //   }
00931 //   return worst_pair->enemy;
00932 }*/
00933 //static void check_worst_defense(fake_team &t)
00934 //{
00935 //   //std::vector<unit_pair> pairs;
00936 //   //unit &worst_def_unit;
00937 //   vector<defender_pair> defenders;
00938 //   vector<enemy_pair> enemies;
00939 //   /*foreach(unit &un, *resources::units)
00940 //   {
00941 //      if(t.is_enemy(un.side()))
00942 //      {
00943 //         enemies.push_back(un.id());
00944 //      }else{
00945 //         defenders.push_back(un.id());
00946 //      }
00947 //   }*/
00948 //   foreach(unit &un, *resources::units)
00949 //   {
00950 //      if(t.is_enemy(un.side()))
00951 //      {
00952 //         const unit_type &enemy_type = un.type();
00953 //         enemy_pair pair;
00954 //         pair.enemy = un;
00955 //         foreach(unit &defender, *resources::units)
00956 //         {
00957 //            int score = compare_unit_types(defender.type(), enemy_type);
00958 //            if(score >= 0)
00959 //            {
00960 //               pair.defenders.push_back(defender);
00961 //            }
00962 //         }
00963 //         defenders.push_back(pair);
00964 //      }
00965 //      else
00966 //      {
00967 //         const unit_type &defender_type = un.type();
00968 //         defender_pair pair;
00969 //         pair.defender = un;
00970 //         foreach(unit &enemy, *resources::units)
00971 //         {
00972 //            int score = compare_unit_types(defender_type, enemy.type());
00973 //            if(score >= 0)
00974 //            {
00975 //               pair.enemies.push_back(enemy);
00976 //               //pair.score += score;
00977 //            }
00978 //         }
00979 //         enemies.push_back(pair);
00980 //      }
00981 //   }
00982 //   //std::vector<unit> no_defense_enemies;
00983 //   foreach(enemy_pair &pair, enemies)
00984 //   {
00985 //      if(pair.defenders.size() == 0)
00986 //      {
00987 //         //no_defense_enemies.push_back(pair.enemy);
00988 //         return pair.enemy;
00989 //         //pair.score = 0;
00990 //      }else{
00991 //         foreach(unit &defender, pair.defenders)
00992 //         {
00993 //            unsigned int defender_enemies = 0;
00994 //            foreach(defender_pair &defender_p, defenders)
00995 //            {
00996 //               if(defender.id() == defender_p.defender.id()){
00997 //                  defender_enemies = defender_p.enemies.size();
00998 //                  break;
00999 //               }
01000 //            }
01001 //
01002 //            pair.score += (compare_unit_types(defender, pair.enemy) / ((defender_enemies != 0) ? defender_enemies : 1 ));
01003 //         }
01004 //      }
01005 //   }
01006 //   enemy_pair *worst_pair = &enemies[0];
01007 //   foreach(enemy_pair &pair, enemies)
01008 //   {
01009 //      if(pair.score < worst_pair.score)
01010 //      {
01011 //         worst_pair = &pair;
01012 //      }
01013 //   }
01014 //   return worst_pair->enemy;
01015 //}
01016 
01017 void testing_recruitment_phase::do_recruit(int max_units_to_recruit, double quality_factor)
01018 {
01019    std::vector<fake_team> tmp_fake_teams;
01020    std::vector<fake_team> fake_teams;
01021    std::copy(resources::teams->begin(), resources::teams->end(), std::back_inserter(tmp_fake_teams));
01022    fake_team *ai_t = 0;
01023    for(int i = get_side() - 1
01024            ; static_cast<unsigned int>(i) < tmp_fake_teams.size()
01025            ; i++)
01026    {
01027       fake_teams.push_back(tmp_fake_teams[i]);
01028 
01029    }
01030    for(int i = 0; i < get_side() - 1; i++)
01031    {
01032       fake_teams.push_back(tmp_fake_teams[i]);
01033    }
01034    ai_t = &fake_teams[0];
01035    if(ai_t->recruit_list().empty())
01036    {
01037       return;
01038    }
01039    for(int recruited_amount = 0; recruited_amount < max_units_to_recruit; recruited_amount++)
01040    {
01041 
01042       foreach(fake_team &t, fake_teams)
01043       {
01044          t.reset();
01045       }
01046 
01047       std::vector<potential_recruit> ai_recruit_list = ai_t->recruit_list();
01048 
01049       foreach(potential_recruit &recruit_type, ai_recruit_list)
01050       {
01051          foreach(fake_team &t, fake_teams)
01052          {
01053             t.reset();
01054          }
01055 
01056          if(ai_t->gold() < recruit_type.cost())
01057          {
01058             continue;
01059          }
01060          if(ai_t->get_current_qty(recruit_type) >= recruit_type.max_qty())
01061          {
01062             continue;
01063          }
01064          LOG_AI << "Pretend that we recruited: " << recruit_type.id() << std::endl;
01065          ai_t->fake_recruit(recruit_type);
01066          foreach(fake_team &t, fake_teams)
01067          {
01068             if(ai_t->side() == t.side())
01069             {
01070                continue;
01071             }
01072             LOG_AI << "evaluating reaction of fake_team " << t.side() << std::endl;
01073 
01074             //@todo: enemy_max_units: for each enemy leader, find nearest keep, find free space near that keep, sum
01075             int enemy_max_units = 5;
01076             //@todo: enemy_quality_factor. will be taken later from parameter
01077             double enemy_quality_factor = 1.0;
01078 
01079             //update quality ratings for enemy
01080             get_recruit_qualities(t, fake_teams);
01081 
01082             ai_choose_recruits(t, enemy_max_units, enemy_quality_factor, true);
01083 
01084          }
01085          get_recruit_quality(recruit_type,*ai_t, fake_teams);
01086       }
01087       ai_t->recruit_list() = ai_recruit_list;
01088       // choose the best unit
01089       std::vector<potential_recruit> recruit_result = ai_choose_best_recruits(*ai_t, 1, quality_factor,false);
01090       if(recruit_result.empty())
01091       {
01092          std::cout << "recruit_result = empty" << std::endl;
01093          break;
01094       }
01095       const potential_recruit &recruit_unit = recruit_result[0];
01096       std::cout << "recruit: " << recruit_unit.id() << std::endl;
01097       if(ai_t->gold() >= recruit_unit.cost())
01098       {
01099          recruit_result_ptr recruit_action = check_recruit_action(recruit_unit.id());
01100          if (recruit_action->is_ok())
01101          {
01102             recruit_action->execute();
01103             if (!recruit_action->is_ok()){
01104                ERR_AI << "recruit failed" << std::endl;
01105             }
01106          } else {
01107             return;
01108          }
01109       }
01110       else
01111       {
01112          std::cout << "gold not ok" << std::endl;
01113       }
01114    }
01115 }
01116 
01117 /*
01118    int main(int argc, char ** argv)
01119    {
01120 //a small testcase
01121 fake_team t;
01122 t.set_gold(120);
01123 t.add_unit("Spearman");
01124 std::vector<potential_recruit> recruit_list;
01125 recruit_list.push_back(potential_recruit("Spearman", 13, 12.6 ,10));
01126 recruit_list.push_back(potential_recruit("Royal Guard", 30, 40.0, 2));
01127 expect(t,"Spearman", 1);
01128 expect(t,"Royal Guard", 0);
01129 ai_choose_recruits(t, 5, 1, recruit_list);
01130 
01131 ai_recruit(t, 5, 1, recruit_list);
01132 
01133 //expect(t,"Spearman", 4);
01134 //expect(t,"Royal Guard", 2);
01135 return 0;
01136 }
01137 */
01138 
01139 
01140 void testing_recruitment_phase::execute()
01141 {
01142    std::cout << "execute floris' recruitment algorithm" << std::endl;
01143    int max_units_to_recruit = 1;
01144    double quality_factor = 1.0;
01145    do_recruit(max_units_to_recruit, quality_factor);
01146 }
01147 
01148 } // end of namespace testing_ai_default
01149 
01150 } // end of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Wed May 23 2012 01:02:33 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs