Author: suokko
Date: Sun Sep 14 18:11:43 2008
New Revision: 29463

URL: http://svn.gna.org/viewcvs/wesnoth?rev=29463&view=rev
Log:
* Made AI to prefer recruiting over attacking/village grapping
* Added heurestics to select which keep leader should try to move
* other minor tweaks

Modified:
    trunk/src/ai.cpp
    trunk/src/ai.hpp
    trunk/src/ai_move.cpp
    trunk/src/ai_village.cpp

Modified: trunk/src/ai.cpp
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/src/ai.cpp?rev=29463&r1=29462&r2=29463&view=diff
==============================================================================
--- trunk/src/ai.cpp (original)
+++ trunk/src/ai.cpp Sun Sep 14 18:11:43 2008
@@ -47,6 +47,7 @@
 #include <cassert>
 #include <fstream>
 
+
 #define DBG_AI LOG_STREAM(debug, ai)
 #define LOG_AI LOG_STREAM(info, ai)
 #define WRN_AI LOG_STREAM(warn, ai)
@@ -293,7 +294,8 @@
        keeps_(),
        avoid_(),
        unit_stats_cache_(),
-       attack_depth_(0)
+       attack_depth_(0),
+       recruiting_prefered_(false)
 {}
 
 void ai::new_turn()
@@ -335,10 +337,10 @@
        {
                const std::string& name = i->second.id();
                // If usage is empty consider any unit.
-               DBG_AI << name << " considered\n";
+//             DBG_AI << name << " considered\n";
                if (i->second.usage() == usage || usage == "") {
                        if (!recruits.count(name)) {
-                               DBG_AI << name << " rejected, not in 
recruitment list\n";
+//                             DBG_AI << name << " rejected, not in 
recruitment list\n";
                                continue;
                        }
                        LOG_AI << name << " considered for " << usage << " 
recruitment\n";
@@ -489,7 +491,7 @@
                if(u->second.movement_left()==u->second.total_movement()) {
                        u->second.set_movement(0);
                        u->second.set_state("not_moved","yes");
-               } else {
+               } else if (from == loc) {
                        u->second.set_movement(0);
                }
        }
@@ -532,25 +534,26 @@
                }
 
                if(rt != p.routes.end()) {
+                       
assert(static_cast<size_t>(u_it->second.movement_left()) >= 
rt->second.steps.size()-1 && "Trying to move unit without enough move points 
left\n");
                        u_it->second.set_movement(rt->second.move_left);
 
                        std::vector<location> steps = rt->second.steps;
 
                        while(steps.empty() == false && (!(info_.units.find(to) 
== info_.units.end() || from == to))){
-                                   LOG_AI << "AI attempting illegal move. 
Attempting to move onto existing unit\n";
-                                   LOG_AI << "\t" << 
info_.units.find(to)->second.underlying_id() <<" already on " << to << "\n";
-                                   LOG_AI <<"\tremoving 
"<<*(steps.end()-1)<<"\n";
-                                   to = *(steps.end()-1);
-                                   steps.pop_back();
-                                   LOG_AI << "\tresetting to " << from << " -> 
" << to << '\n';
+                               LOG_AI << "AI attempting illegal move. 
Attempting to move onto existing unit\n";
+                               LOG_AI << "\t" << 
info_.units.find(to)->second.underlying_id() <<" already on " << to << "\n";
+                               LOG_AI <<"\tremoving "<<*(steps.end()-1)<<"\n";
+                               to = *(steps.end()-1);
+                               steps.pop_back();
+                               LOG_AI << "\tresetting to " << from << " -> " 
<< to << '\n';
                        }
 
                        if(steps.size()) { // First step is starting hex
-                         unit_map::const_iterator 
utest=info_.units.find(*(steps.begin()));
-                         if(utest != info_.units.end() && 
current_team().is_enemy(utest->second.side())){
-                           LOG_STREAM(err, ai) << "AI tried to move onto 
existing enemy unit at"<<*(steps.begin())<<"\n";
-                           //                      return(from);
-                         }
+                               unit_map::const_iterator 
utest=info_.units.find(*(steps.begin()));
+                               if(utest != info_.units.end() && 
current_team().is_enemy(utest->second.side())){
+                                       LOG_STREAM(err, ai) << "AI tried to 
move onto existing enemy unit at"<<*(steps.begin())<<"\n";
+                                       //                          
return(from);
+                               }
 
                                // Check if there are any invisible units that 
we uncover
                                for(std::vector<location>::iterator i = 
steps.begin()+1; i != steps.end(); ++i) {
@@ -568,27 +571,27 @@
                                                const unit_map::const_iterator 
u = info_.units.find(adj[n]);
                                                // If level 0 is invisible it 
ambush us too
                                                if (u != info_.units.end() && 
(u->second.emits_zoc() || u->second.invisible(adj[n], info_.units, info_.teams))
-                                                       && 
current_team().is_enemy(u->second.side())) {
+                                                               && 
current_team().is_enemy(u->second.side())) {
                                                        if 
(u->second.invisible(adj[n], info_.units, info_.teams)) {
                                                                to = *i;
                                                                
u->second.ambush();
                                                                
steps.erase(i,steps.end());
                                                                break;
                                                        } else {
-                                                         if 
(!u_it->second.get_ability_bool("skirmisher",*i)){
-                                                           LOG_STREAM(err, ai) 
<< "AI tried to skirmish with non-skirmisher\n";
-                                                           LOG_AI << 
"\tresetting destination from " <<to;
-                                                           to = *i;
-                                                           LOG_AI << " to " << 
to;
-                                                           
steps.erase(i,steps.end());
-                                                           while(steps.empty() 
== false && (!(info_.units.find(to) == info_.units.end() || from == to))){
-                                                                to = 
*(steps.end()-1);
-                                                                
steps.pop_back();
-                                                                LOG_AI << 
"\tresetting to " << from << " -> " << to << '\n';
-                                                           }
-
-                                                           break;
-                                                         }
+                                                               if 
(!u_it->second.get_ability_bool("skirmisher",*i)){
+                                                                       
LOG_STREAM(err, ai) << "AI tried to skirmish with non-skirmisher\n";
+                                                                       LOG_AI 
<< "\tresetting destination from " <<to;
+                                                                       to = *i;
+                                                                       LOG_AI 
<< " to " << to;
+                                                                       
steps.erase(i,steps.end());
+                                                                       
while(steps.empty() == false && (!(info_.units.find(to) == info_.units.end() || 
from == to))){
+                                                                               
to = *(steps.end()-1);
+                                                                               
steps.pop_back();
+                                                                               
LOG_AI << "\tresetting to " << from << " -> " << to << '\n';
+                                                                       }
+
+                                                                       break;
+                                                               }
                                                        }
                                                }
                                        }
@@ -726,7 +729,8 @@
                        possible_moves_ptr = &temp_possible_moves;
                }
 
-               do_recruitment();
+               if (map_.is_keep(from))
+                       do_recruitment();
        }
 
        if(units_.count(to) == 0 || from == to) {
@@ -795,7 +799,8 @@
                        continue;
                }
                // Discount incapacitated units
-               if(un_it->second.incapacitated()) {
+               if(un_it->second.incapacitated() 
+                       || un_it->second.movement_left() == 0) {
                        continue;
                }
 
@@ -960,6 +965,14 @@
        }
 }
 
+void ai::evaluate_recruiting_value(unit_map::iterator leader)
+{
+       const int gold = current_team().gold();
+//     const int unit_price = current_team().average_recruit_price();
+//     recruiting_prefered_ = (gold/unit_price) > 
min_recruiting_value_to_force_recruit && !map_.is_keep();
+       recruiting_prefered_ = gold > min_recruiting_value_to_force_recruit && 
!map_.is_keep(leader->first);
+}
+
 void ai::do_move()
 {
        log_scope2(ai, "doing ai move");
@@ -980,9 +993,13 @@
 
        const bool passive_leader = 
utils::string_bool(current_team().ai_parameters()["passive_leader"]);
 
-       if (passive_leader) {
-               unit_map::iterator leader = find_leader(units_,team_num_);
-               if(leader != units_.end()) {
+
+       unit_map::iterator leader = find_leader(units_,team_num_);
+       if (leader != units_.end())
+       {
+               evaluate_recruiting_value(leader);
+               if (passive_leader)
+               {
                        remove_unit_from_moves(leader->first,srcdst,dstsrc);
                }
        }
@@ -1037,7 +1054,7 @@
        LOG_AI << "get villages phase\n";
 
        // Iterator could be invalidated by combat analysis or 
move_leader_to_goals.
-       unit_map::iterator leader = find_leader(units_,team_num_);
+       leader = find_leader(units_,team_num_);
 
        LOG_AI << "villages...\n";
        if(get_villages(possible_moves, dstsrc, enemy_dstsrc, leader)) {
@@ -1089,7 +1106,8 @@
                        move_leader_to_keep(enemy_dstsrc);
                }
 
-               do_recruitment();
+               if (map_.is_keep(leader->first))
+                       do_recruitment();
 
                if(!passive_leader) {
                        move_leader_after_recruit(srcdst,dstsrc,enemy_dstsrc);
@@ -1135,6 +1153,16 @@
                LOG_AI << "attack option rated at " << rating << " ("
                        << current_team().aggression() << ")\n";
 
+               if (recruiting_prefered_)
+               {
+                       unit_map::unit_iterator u = 
units_.find(it->movements[0].first);
+                       if (u != units_.end()
+                               && u->second.can_recruit())
+                       {
+                               LOG_AI << "Not fighting with leader because 
recruiting is more preferable\n";
+                               continue;
+                       }
+               }
                if(rating > choice_rating) {
                        choice_it = it;
                        choice_rating = rating;
@@ -1144,7 +1172,7 @@
        time_taken = SDL_GetTicks() - ticks;
        LOG_AI << "analysis took " << time_taken << " ticks\n";
 
-       if(choice_rating > 0.0) {
+       if(choice_rating > current_team().caution()) {
                location from   = choice_it->movements[0].first;
                location to     = choice_it->movements[0].second;
                location target_loc = choice_it->target;
@@ -1916,64 +1944,12 @@
        }
 }
 
-void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
-{
-       const unit_map::iterator leader = find_leader(units_,team_num_);
-       if(leader == units_.end() || leader->second.incapacitated()) {
-               return;
-       }
-
-       // Find where the leader can move
-       const paths leader_paths(map_, units_, leader->first,
-                       teams_, false, false, current_team());
-       const gamemap::location& start_pos = nearest_keep(leader->first);
-
-       std::map<gamemap::location,paths> possible_moves;
-       
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
-
-       // If the leader is not on his starting location, move him there.
-       if(leader->first != start_pos) {
-               const paths::routes_map::const_iterator itor = 
leader_paths.routes.find(start_pos);
-               if(itor != leader_paths.routes.end() && units_.count(start_pos) 
== 0) {
-                       move_unit(leader->first,start_pos,possible_moves);
-               } else {
-                       // Make a map of the possible locations the leader can 
move to,
-                       // ordered by the distance from the keep.
-                       std::multimap<int,gamemap::location> moves_toward_keep;
-
-                       // The leader can't move to his keep, try to move to 
the closest location
-                       // to the keep where there are no enemies in range.
-                       const int current_distance = 
distance_between(leader->first,start_pos);
-                       for(paths::routes_map::const_iterator i = 
leader_paths.routes.begin();
-                                       i != leader_paths.routes.end(); ++i) {
-
-                               const int new_distance = 
distance_between(i->first,start_pos);
-                               if(new_distance < current_distance) {
-                                       
moves_toward_keep.insert(std::pair<int,gamemap::location>(new_distance,i->first));
-                               }
-                       }
-
-                       // Find the first location which we can move to,
-                       // without the threat of enemies.
-                       
for(std::multimap<int,gamemap::location>::const_iterator j = 
moves_toward_keep.begin();
-                                       j != moves_toward_keep.end(); ++j) {
-
-                               if(enemy_dstsrc.count(j->second) == 0) {
-                                       
move_unit(leader->first,j->second,possible_moves);
-                                       break;
-                               }
-                       }
-               }
-       }
-}
-
 void ai::move_leader_after_recruit(const move_map& /*srcdst*/,
                const move_map& /*dstsrc*/, const move_map& enemy_dstsrc)
 {
-       LOG_AI << "moving leader after recruit...\n";
 
        unit_map::iterator leader = find_leader(units_,team_num_);
-       if(leader == units_.end() || leader->second.incapacitated()) {
+       if(leader == units_.end() || leader->second.incapacitated() || 
leader->second.movement_left() == 0) {
                return;
        }
 

Modified: trunk/src/ai.hpp
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/src/ai.hpp?rev=29463&r1=29462&r2=29463&view=diff
==============================================================================
--- trunk/src/ai.hpp (original)
+++ trunk/src/ai.hpp Sun Sep 14 18:11:43 2008
@@ -338,6 +338,9 @@
        /** Functions to deal with keeps. */
        const std::set<location>& keeps();
        const location& nearest_keep(const location& loc);
+       int count_free_hexes_in_castle(const gamemap::location& loc, 
std::set<gamemap::location>&);
+
+       void evaluate_recruiting_value(unit_map::iterator leader);
 
        std::set<location> keeps_;
 
@@ -373,6 +376,9 @@
                const std::multimap<gamemap::location,gamemap::location>& 
dstsrc,
                const std::map<gamemap::location,paths>& possible_moves,
                const std::multimap<gamemap::location,gamemap::location>& 
enemy_dstsrc) const;
+       
+       bool recruiting_prefered_;
+       static const int min_recruiting_value_to_force_recruit = 28;
 };
 
 class ai_manager {

Modified: trunk/src/ai_move.cpp
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/src/ai_move.cpp?rev=29463&r1=29462&r2=29463&view=diff
==============================================================================
--- trunk/src/ai_move.cpp (original)
+++ trunk/src/ai_move.cpp Sun Sep 14 18:11:43 2008
@@ -25,7 +25,10 @@
 #include <cassert>
 #include <iostream>
 
+#include <queue>
+
 #define LOG_AI LOG_STREAM(info, ai)
+#define DBG_AI LOG_STREAM(debug, ai)
 
 struct move_cost_calculator : cost_calculator
 {
@@ -433,8 +436,11 @@
 
                assert(map_.on_board(tg->loc));
 
-               const double locStopValue = std::min(tg->value / best_rating, 
500.0);
+               const double locStopValue = 500.0;
                paths::route cur_route = a_star_search(u->first, tg->loc, 
locStopValue, &cost_calc, map_.w(), map_.h());
+
+               if (cur_route.move_left == cost_calc.getNoPathValue())
+                       continue;
 
                if (cur_route.move_left < locStopValue)
                {
@@ -790,3 +796,114 @@
                }
        }
 }
+
+struct keep_value {
+       size_t value;
+       gamemap::location loc;
+
+       keep_value(size_t v, const gamemap::location& l) : value(v), loc(l)
+       {}
+       bool operator<(const keep_value& val) const 
+       {
+               return value > val.value;
+       }
+};
+
+
+void ai::move_leader_to_keep(const move_map& enemy_dstsrc)
+{
+       const unit_map::iterator leader = find_leader(units_,team_num_);
+       if(leader == units_.end() 
+               || leader->second.incapacitated() 
+               || leader->second.movement_left() == 0
+               || !recruiting_prefered_) {
+               return;
+       }
+
+       std::map<gamemap::location,paths> possible_moves;
+       std::map<gamemap::location,paths>::iterator path_itor = 
possible_moves.insert(std::make_pair(leader->first, paths())).first;
+
+       // Guess how many units we want to recruit
+       const int number_of_recruit = current_team().gold() / 15;
+
+       // If the leader is not on his starting location, move him there.
+       {
+               {
+                       // Make a map of the possible locations the leader can 
move to,
+                       // ordered by the distance from the keep.
+                       std::priority_queue<keep_value> moves_toward_keep;
+
+                       // The leader can't move to his keep, try to move to 
the closest location
+                       // to the keep where there are no enemies in range.
+                       for(std::set<location>::iterator i = keeps().begin();
+                                       i != keeps().end(); ++i) {
+
+                               const shortest_path_calculator 
cost_calc(leader->second, current_team(), units_,
+                                               teams_,map_);
+                               
+                               paths::routes_map::iterator route = 
path_itor->second.routes.insert(
+                                               std::make_pair(*i,
+                                                       
a_star_search(leader->first, *i, 10000.0, &cost_calc,map_.w(), 
map_.h()))).first;
+
+                               std::set<gamemap::location> checked_hexes;
+                               const int distance = 
route->second.steps.size()-1;
+                               checked_hexes.insert(*i);
+                               const int free_slots = 
count_free_hexes_in_castle(*i, checked_hexes);
+                               const int tactical_value = 
leader->second.total_movement() * 0;
+                               const int empty_slots = 
leader->second.total_movement() * std::max(number_of_recruit - free_slots,0);
+                               unit_map::const_iterator u = units_.find(*i);
+                               const int reserved_penalty = 
leader->second.total_movement() * 
+                                       (u != units_.end()?
+                                               
(current_team().is_enemy(u->second.side())?4:2)
+                                       :0);
+                               const int enemy = 
leader->second.total_movement() * enemy_dstsrc.count(*i);
+                               gamemap::location target;
+                               if (distance > leader->second.movement_left())
+                               {
+                                       target = 
route->second.steps[leader->second.movement_left()+1];
+                                       
route->second.steps.erase(route->second.steps.begin() + 
leader->second.movement_left(),route->second.steps.end());
+                                       route->second.move_left = 0;
+                               } else {
+                                       target = *i;
+                                       route->second.move_left = 
leader->second.movement_left() - distance;
+                               }
+                               DBG_AI << "Considiring keep: " << *i << 
+                                       " empty slots: " << empty_slots << 
+                                       " distance: " << distance << 
+                                       " enemy: " << enemy << 
+                                       " target: " << target <<
+                                   " route: " << route->second.steps.size() << 
" " << route->second.move_left <<       
+                                       "\n";
+                               moves_toward_keep.push(keep_value(distance + 
empty_slots + enemy + tactical_value + reserved_penalty ,target));
+                       }
+
+                       // Find the location with the best value
+                       if (leader->first != moves_toward_keep.top().loc)
+                               
move_unit(leader->first,moves_toward_keep.top().loc,possible_moves);
+               }
+       }
+}
+
+int ai::count_free_hexes_in_castle(const gamemap::location& loc, 
std::set<gamemap::location>& checked_hexes)
+{
+       int ret = 0;
+       location adj[6];
+       get_adjacent_tiles(loc,adj);
+       for(size_t n = 0; n != 6; ++n) {
+               if (checked_hexes.find(adj[n]) != checked_hexes.end())
+                       continue;
+               checked_hexes.insert(adj[n]);
+               if (map_.is_castle(adj[n])) {
+                       const unit_map::const_iterator u = units_.find(adj[n]);
+                       ret += count_free_hexes_in_castle(adj[n], 
checked_hexes);
+                       if (u == units_.end() 
+                               || (current_team().is_enemy(u->second.side()) 
+                                       && u->second.invisible(adj[n], units_, 
teams_))) {
+                               ret += 1;
+                       }
+               }
+       }
+       return ret;
+}
+
+

Modified: trunk/src/ai_village.cpp
URL: 
http://svn.gna.org/viewcvs/wesnoth/trunk/src/ai_village.cpp?rev=29463&r1=29462&r2=29463&view=diff
==============================================================================
--- trunk/src/ai_village.cpp (original)
+++ trunk/src/ai_village.cpp Sun Sep 14 18:11:43 2008
@@ -174,7 +174,6 @@
 
                if(u_itor->second.side() == team_num_ 
                                && u_itor->second.movement_left()) {
-
                        reachmap.insert(std::make_pair(u_itor->first,   
std::vector<gamemap::location>()));
                }
        }
@@ -261,7 +260,7 @@
 {
        std::map<location, double> vulnerability;
 
-       const bool passive_leader = 
+       const bool passive_leader = recruiting_prefered_ ||  
                
utils::string_bool(current_team().ai_parameters()["passive_leader"]);
 
        size_t min_distance = 100000;


_______________________________________________
Wesnoth-commits mailing list
[email protected]
https://mail.gna.org/listinfo/wesnoth-commits

Reply via email to