restructure of AI code

This commit is contained in:
uid68803 2004-01-13 18:21:10 +00:00
parent ccf31d5a30
commit 1c3e548d92
12 changed files with 374 additions and 414 deletions

View file

@ -12,7 +12,7 @@ advanceto=null
cost=39
ability=leadership
usage=fighter
unit_description="Smetimes the migthiest warriors and generals cursed with hate and angst came back to this world as Death Knights."
unit_description="Sometimes the mightiest warriors and generals cursed with hate and angst came back to this world as Death Knights."
get_hit_sound=groan.wav
[attack]
name=axe

View file

@ -25,13 +25,18 @@
#include <iostream>
namespace {
ai::ai(display& disp, const gamemap& map, const game_data& gameinfo,
std::map<gamemap::location,unit>& units,
std::vector<team>& teams, int team_num, const gamestatus& state)
: disp_(disp), map_(map), gameinfo_(gameinfo), units_(units),
teams_(teams), team_num_(team_num), state_(state),
consider_combat_(true)
{}
bool recruit(const gamemap& map, const gamemap::location& leader,
const std::string& usage, const game_data& gameinfo,
int team_num, team& tm, int min_gold,
std::map<gamemap::location,unit>& units, display& disp)
bool ai::recruit(const std::string& usage)
{
const int min_gold = 0;
log_scope("recruiting troops");
std::cerr << "recruiting " << usage << "\n";
@ -42,12 +47,12 @@ bool recruit(const gamemap& map, const gamemap::location& leader,
//find an available unit that can be recruited, matches the desired
//usage type, and comes in under budget
const std::set<std::string>& recruits = tm.recruits();
const std::set<std::string>& recruits = current_team().recruits();
for(std::map<std::string,unit_type>::const_iterator i =
gameinfo.unit_types.begin(); i != gameinfo.unit_types.end(); ++i) {
gameinfo_.unit_types.begin(); i != gameinfo_.unit_types.end(); ++i) {
if(i->second.usage() == usage && recruits.count(i->second.name())
&& tm.gold() - i->second.cost() > min_gold) {
&& current_team().gold() - i->second.cost() > min_gold) {
options.push_back(i);
option_numbers.push_back(std::distance(recruits.begin(),
@ -57,7 +62,6 @@ bool recruit(const gamemap& map, const gamemap::location& leader,
//from the available options, choose one at random
if(options.empty() == false) {
const gamemap::location loc = gamemap::location::null_location;
const int option = rand()%options.size();
@ -67,13 +71,11 @@ bool recruit(const gamemap& map, const gamemap::location& leader,
replay_undo replay_guard(recorder);
const unit_type& u = options[option]->second;
unit new_unit(&u,team_num,true);
unit new_unit(&u,team_num_,true);
//see if we can actually recruit (i.e. have enough room etc)
if(recruit_unit(map,team_num,units,new_unit,loc,&disp).empty()) {
std::cerr << "recruiting a " << u.name() << " for " << u.cost() << " have " << tm.gold() << " left\n";
tm.spend_gold(u.cost());
if(recruit_unit(map_,team_num_,units_,new_unit,loc,&disp_).empty()) {
current_team().spend_gold(u.cost());
//confirm the transaction - i.e. don't undo recruitment
replay_guard.confirm_transaction();
@ -86,25 +88,21 @@ bool recruit(const gamemap& map, const gamemap::location& leader,
return false;
}
team& ai::current_team()
{
return teams_[team_num_-1];
}
namespace ai {
void move_unit(const game_data& gameinfo, display& disp,
const gamemap& map,
std::map<gamemap::location,unit>& units,
const location& from, const location& to,
std::map<location,paths>& possible_moves,
std::vector<team>& teams, int team_num)
void ai::move_unit(const location& from, const location& to, std::map<location,paths>& possible_moves)
{
assert(units.find(to) == units.end() || from == to);
assert(units_.find(to) == units_.end() || from == to);
disp.select_hex(from);
disp.update_display();
disp_.select_hex(from);
disp_.update_display();
log_scope("move_unit");
std::map<location,unit>::iterator u_it = units.find(from);
if(u_it == units.end()) {
unit_map::iterator u_it = units_.find(from);
if(u_it == units_.end()) {
std::cout << "Could not find unit at " << from.x << ", "
<< from.y << "\n";
assert(false);
@ -115,17 +113,16 @@ void move_unit(const game_data& gameinfo, display& disp,
const bool ignore_zocs = u_it->second.type().is_skirmisher();
const bool teleport = u_it->second.type().teleports();
paths current_paths = paths(map,gameinfo,units,from,teams,
ignore_zocs,teleport);
paths_wiper wiper(disp);
paths current_paths = paths(map_,gameinfo_,units_,from,teams_,ignore_zocs,teleport);
paths_wiper wiper(disp_);
if(!disp.fogged(from.x,from.y))
disp.set_paths(&current_paths);
if(!disp_.fogged(from.x,from.y))
disp_.set_paths(&current_paths);
disp.scroll_to_tiles(from.x,from.y,to.x,to.y);
disp_.scroll_to_tiles(from.x,from.y,to.x,to.y);
unit current_unit = u_it->second;
units.erase(u_it);
units_.erase(u_it);
const std::map<location,paths>::iterator p_it = possible_moves.find(from);
@ -141,38 +138,30 @@ void move_unit(const game_data& gameinfo, display& disp,
if(rt != p.routes.end()) {
std::vector<location> steps = rt->second.steps;
steps.push_back(to); //add the destination to the steps
disp.move_unit(steps,current_unit);
disp_.move_unit(steps,current_unit);
}
}
current_unit.set_movement(0);
units.insert(std::pair<location,unit>(to,current_unit));
if(map.underlying_terrain(map[to.x][to.y]) == gamemap::TOWER)
get_tower(to,teams,team_num-1,units);
units_.insert(std::pair<location,unit>(to,current_unit));
if(map_.underlying_terrain(map_[to.x][to.y]) == gamemap::TOWER)
get_tower(to,teams_,team_num_-1,units_);
disp.draw_tile(to.x,to.y);
disp.draw();
disp_.draw_tile(to.x,to.y);
disp_.draw();
game_events::fire("moveto",to);
if((teams.front().uses_fog() || teams.front().uses_shroud()) && !teams.front().fogged(to.x,to.y)) {
if((teams_.front().uses_fog() || teams_.front().uses_shroud()) && !teams_.front().fogged(to.x,to.y)) {
game_events::fire("sighted",to);
}
}
void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
unit_map& units,
std::vector<team>& teams, int team_num, const gamestatus& state,
bool consider_combat, std::vector<target>* additional_targets)
void ai::do_move()
{
std::vector<target> tgts;
if(additional_targets == NULL)
additional_targets = &tgts;
log_scope("doing ai move");
team& current_team = teams[team_num-1];
typedef paths::route route;
std::multimap<location,location> enemy_srcdst;
@ -186,10 +175,10 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
typedef std::map<location,paths> moves_map;
moves_map possible_moves;
for(std::map<gamemap::location,unit>::iterator un_it = units.begin();
un_it != units.end(); ++un_it) {
for(std::map<gamemap::location,unit>::iterator un_it = units_.begin();
un_it != units_.end(); ++un_it) {
if(current_team.is_enemy(un_it->second.side())) {
if(current_team().is_enemy(un_it->second.side())) {
std::pair<location,location> trivial_mv(un_it->first,un_it->first);
enemy_srcdst.insert(trivial_mv);
enemy_dstsrc.insert(trivial_mv);
@ -198,8 +187,8 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
const bool ignore_zocs = un_it->second.type().is_skirmisher();
const bool teleports = un_it->second.type().teleports();
const paths new_paths(map,gameinfo,units,
un_it->first,teams,ignore_zocs,teleports);
const paths new_paths(map_,gameinfo_,units_,
un_it->first,teams_,ignore_zocs,teleports);
for(paths::routes_map::const_iterator rt = new_paths.routes.begin();
rt != new_paths.routes.end(); ++rt) {
const std::pair<location,location> item(un_it->first,rt->first);
@ -209,7 +198,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
}
if(un_it->second.side() != team_num) {
if(un_it->second.side() != team_num_) {
continue;
}
@ -229,39 +218,38 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
const bool ignore_zocs = un_it->second.type().is_skirmisher();
const bool teleports = un_it->second.type().teleports();
possible_moves.insert(std::pair<gamemap::location,paths>(
un_it->first,paths(map,gameinfo,units,
un_it->first,teams,ignore_zocs,teleports)));
un_it->first,paths(map_,gameinfo_,units_,
un_it->first,teams_,ignore_zocs,teleports)));
}
for(moves_map::iterator m = possible_moves.begin();
m != possible_moves.end(); ++m) {
for(paths::routes_map::iterator rtit =
m->second.routes.begin(); rtit != m->second.routes.end();
++rtit) {
m->second.routes.begin(); rtit != m->second.routes.end(); ++rtit) {
const location& src = m->first;
const location& dst = rtit->first;
if(src != dst && units.find(dst) == units.end()) {
if(src != dst && units_.find(dst) == units_.end()) {
srcdst.insert(std::pair<location,location>(src,dst));
dstsrc.insert(std::pair<location,location>(dst,src));
}
}
}
unit_map::iterator leader = find_leader(units,team_num);
unit_map::iterator leader = find_leader(units_,team_num_);
//no moves left, recruitment phase and leader movement phase
//take stock of our current set of units
if(srcdst.empty() || leader != units.end() && srcdst.count(leader->first) == srcdst.size()) {
if(leader == units.end()) {
if(srcdst.empty() || leader != units_.end() && srcdst.count(leader->first) == srcdst.size()) {
if(leader == units_.end()) {
recorder.end_turn();
return;
}
//find where the leader can move
const paths leader_paths(map,gameinfo,units,leader->first,teams,false,false);
const gamemap::location& start_pos = map.starting_position(leader->second.side());
const paths leader_paths(map_,gameinfo_,units_,leader->first,teams_,false,false);
const gamemap::location& start_pos = map_.starting_position(leader->second.side());
possible_moves.insert(std::pair<gamemap::location,paths>(leader->first,leader_paths));
@ -270,12 +258,11 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
if(leader->first != start_pos) {
leader_moved = true;
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(gameinfo,disp,map,units,leader->first,start_pos,
possible_moves,teams,team_num);
if(itor != leader_paths.routes.end() && units_.count(start_pos) == 0) {
move_unit(leader->first,start_pos,possible_moves);
leader = find_leader(units,team_num);
assert(leader != units.end());
leader = find_leader(units_,team_num_);
assert(leader != units_.end());
}
}
@ -284,38 +271,35 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
//currently just spend all the gold we can!
const int min_gold = 0;
const int towers = map.towers().size();
const int towers = map_.towers().size();
int taken_towers = 0;
for(size_t j = 0; j != teams.size(); ++j) {
taken_towers += teams[j].towers().size();
for(size_t j = 0; j != teams_.size(); ++j) {
taken_towers += teams_[j].towers().size();
}
const int neutral_towers = towers - taken_towers;
//get scouts depending on how many neutral villages there are
int scouts_wanted = current_team.villages_per_scout() > 0 ?
neutral_towers/current_team.villages_per_scout() : 0;
int scouts_wanted = current_team().villages_per_scout() > 0 ?
neutral_towers/current_team().villages_per_scout() : 0;
std::map<std::string,int> unit_types;
while(unit_types["scout"] < scouts_wanted) {
if(recruit(map,leader->first,"scout",gameinfo,team_num,current_team,
min_gold,units,disp) == false)
if(recruit("scout") == false)
break;
++unit_types["scout"];
}
const std::vector<std::string>& options =
current_team.recruitment_pattern();
const std::vector<std::string>& options = current_team().recruitment_pattern();
if(options.empty()) {
assert(false);
return;
}
//buy fighters as long as we have room and can afford it
while(recruit(map,leader->first,options[rand()%options.size()].c_str(),
gameinfo,team_num,current_team,min_gold,units,disp)) {
//buy units as long as we have room and can afford it
while(recruit(options[rand()%options.size()])) {
}
@ -334,16 +318,16 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
//search through villages finding one to capture
if(!leader_moved) {
const std::vector<gamemap::location>& villages = map.towers();
const std::vector<gamemap::location>& villages = map_.towers();
for(std::vector<gamemap::location>::const_iterator v = villages.begin();
v != villages.end(); ++v) {
const paths::routes_map::const_iterator itor = leader_paths.routes.find(*v);
if(itor == leader_paths.routes.end() || units.count(*v) != 0) {
if(itor == leader_paths.routes.end() || units_.count(*v) != 0) {
continue;
}
const int owner = tower_owner(*v,teams);
if(owner == -1 || current_team.is_enemy(owner+1) || leader->second.hitpoints() < leader->second.max_hitpoints()) {
const int owner = tower_owner(*v,teams_);
if(owner == -1 || current_team().is_enemy(owner+1) || leader->second.hitpoints() < leader->second.max_hitpoints()) {
//check that no enemies can reach the village
gamemap::location adj[6];
@ -357,8 +341,7 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
if(n != 6)
continue;
move_unit(gameinfo,disp,map,units,leader->first,*v,
possible_moves,teams,team_num);
move_unit(leader->first,*v,possible_moves);
break;
}
@ -373,9 +356,8 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
std::vector<attack_analysis> analysis;
if(consider_combat) {
analysis = analyze_targets(map,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,
units,current_team,team_num,state,gameinfo);
if(consider_combat_) {
analysis = analyze_targets(srcdst,dstsrc,enemy_srcdst,enemy_dstsrc);
}
int time_taken = SDL_GetTicks() - ticks;
@ -397,14 +379,12 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
std::vector<attack_analysis>::iterator choice_it = analysis.end();
double choice_rating = -1000.0;
for(std::vector<attack_analysis>::iterator it = analysis.begin();
it != analysis.end(); ++it) {
if(skip_num > 0 && ((it - analysis.begin())%skip_num) &&
it->movements.size() > 1)
for(std::vector<attack_analysis>::iterator it = analysis.begin(); it != analysis.end(); ++it) {
if(skip_num > 0 && ((it - analysis.begin())%skip_num) && it->movements.size() > 1)
continue;
const double rating = it->rating(current_team.aggression());
std::cout << "attack option rated at " << rating << " (" << current_team.aggression() << ")\n";
const double rating = it->rating(current_team().aggression());
std::cout << "attack option rated at " << rating << " (" << current_team().aggression() << ")\n";
if(rating > choice_rating) {
choice_it = it;
choice_rating = rating;
@ -420,52 +400,48 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
const location& target_loc = choice_it->target;
const int weapon = choice_it->weapons[0];
const std::map<gamemap::location,unit>::const_iterator tgt =
units.find(target_loc);
const unit_map::const_iterator tgt = units_.find(target_loc);
const bool defender_human = (tgt != units.end()) ?
teams[tgt->second.side()-1].is_human() : false;
const bool defender_human = (tgt != units_.end()) ?
teams_[tgt->second.side()-1].is_human() : false;
move_unit(gameinfo,disp,map,units,from,to,
possible_moves,teams,team_num);
move_unit(from,to,possible_moves);
std::cerr << "attacking...\n";
recorder.add_attack(to,target_loc,weapon);
game_events::fire("attack",to,target_loc);
if(units.count(to) && units.count(target_loc)) {
attack(disp,map,to,target_loc,weapon,units,state,gameinfo,false);
check_victory(units,teams);
if(units_.count(to) && units_.count(target_loc)) {
attack(disp_,map_,to,target_loc,weapon,units_,state_,gameinfo_,false);
check_victory(units_,teams_);
}
std::cerr << "done attacking...\n";
//if this is the only unit in the planned attack, and the target
//is still alive, then also summon reinforcements
if(choice_it->movements.size() == 1 && units.count(target_loc)) {
additional_targets->push_back(target(target_loc,3.0));
if(choice_it->movements.size() == 1 && units_.count(target_loc)) {
additional_targets_.push_back(target(target_loc,3.0));
}
dialogs::advance_unit(gameinfo,units,to,disp,true);
dialogs::advance_unit(gameinfo,units,target_loc,disp,!defender_human);
dialogs::advance_unit(gameinfo_,units_,to,disp_,true);
dialogs::advance_unit(gameinfo_,units_,target_loc,disp_,!defender_human);
do_move(disp,map,gameinfo,units,teams,team_num,state,consider_combat,
additional_targets);
do_move();
return;
} else {
log_scope("summoning reinforcements...\n");
consider_combat = false;
consider_combat_ = false;
std::set<gamemap::location> already_done;
for(std::vector<attack_analysis>::iterator it = analysis.begin();
it != analysis.end(); ++it) {
for(std::vector<attack_analysis>::iterator it = analysis.begin(); it != analysis.end(); ++it) {
assert(it->movements.empty() == false);
const gamemap::location& loc = it->movements.front().first;
if(already_done.count(loc) > 0)
continue;
additional_targets->push_back(target(loc,3.0));
additional_targets_.push_back(target(loc,3.0));
already_done.insert(loc);
}
}
@ -481,13 +457,13 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
//try to acquire towers
for(std::multimap<location,location>::const_iterator i = dstsrc.begin();
i != dstsrc.end(); ++i) {
if(map.underlying_terrain(map[i->first.x][i->first.y]) != gamemap::TOWER)
if(map_.underlying_terrain(map_[i->first.x][i->first.y]) != gamemap::TOWER)
continue;
bool want_tower = true, owned = false;
for(size_t j = 0; j != teams.size(); ++j) {
owned = teams[j].owns_tower(i->first);
if(owned && !current_team.is_enemy(j+1)) {
for(size_t j = 0; j != teams_.size(); ++j) {
owned = teams_[j].owns_tower(i->first);
if(owned && !current_team().is_enemy(j+1)) {
want_tower = false;
}
@ -498,15 +474,15 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
//if it's a neutral tower, and we have no leader, then the village is no use to us,
//and we don't want it.
if(!owned && leader == units.end())
if(!owned && leader == units_.end())
want_tower = false;
if(want_tower) {
std::cerr << "trying to acquire village: " << i->first.x
<< ", " << i->first.y << "\n";
const std::map<location,unit>::iterator un = units.find(i->second);
if(un == units.end()) {
const std::map<location,unit>::iterator un = units_.find(i->second);
if(un == units_.end()) {
assert(false);
return;
}
@ -514,24 +490,21 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
if(un->second.is_guardian())
continue;
move_unit(gameinfo,disp,map,units,i->second,i->first,
possible_moves,teams,team_num);
do_move(disp,map,gameinfo,units,teams,team_num,
state,consider_combat,additional_targets);
move_unit(i->second,i->first,possible_moves);
do_move();
return;
}
}
//find units in need of healing
std::map<location,unit>::iterator u_it = units.begin();
for(; u_it != units.end(); ++u_it) {
unit_map::iterator u_it = units_.begin();
for(; u_it != units_.end(); ++u_it) {
unit& u = u_it->second;
//if the unit is on our side, has lost as many or more than 1/2 round
//worth of healing, and doesn't regenerate itself, then try to
//find a vacant village for it to rest in
if(u.side() == team_num &&
if(u.side() == team_num_ &&
u.type().hitpoints() - u.hitpoints() >= game_config::cure_amount/2 &&
!u.type().regenerates()) {
@ -542,10 +515,10 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
Itor best_loc = it.second;
while(it.first != it.second) {
const location& dst = it.first->second;
if(map.underlying_terrain(map[dst.x][dst.y]) == gamemap::TOWER &&
units.find(dst) == units.end()) {
if(map_.underlying_terrain(map_[dst.x][dst.y]) == gamemap::TOWER &&
units_.find(dst) == units_.end()) {
const double vuln = power_projection(it.first->first,
enemy_srcdst,enemy_dstsrc,units,map);
enemy_srcdst,enemy_dstsrc);
if(vuln < best_vulnerability) {
best_vulnerability = vuln;
best_loc = it.first;
@ -562,25 +535,22 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
std::cerr << "moving unit to village for healing...\n";
move_unit(gameinfo,disp,map,units,src,dst,
possible_moves,teams,team_num);
do_move(disp,map,gameinfo,units,teams,team_num,state,
consider_combat,additional_targets);
move_unit(src,dst,possible_moves);
do_move();
return;
}
}
}
if(dstsrc.empty()) {
do_move(disp,map,gameinfo,units,teams,team_num,state,
consider_combat,additional_targets);
do_move();
return;
}
std::cout << "finding targets...\n";
std::vector<target> targets = find_targets(map,units,teams,team_num,leader != units.end());
targets.insert(targets.end(),additional_targets->begin(),
additional_targets->end());
std::vector<target> targets = find_targets(leader != units_.end());
targets.insert(targets.end(),additional_targets_.begin(),
additional_targets_.end());
for(;;) {
if(targets.empty()) {
recorder.end_turn();
@ -588,12 +558,9 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
}
std::cout << "choosing move...\n";
std::pair<location,location> move = choose_move(targets,dstsrc,units,
map,teams,team_num,
gameinfo);
for(std::vector<target>::const_iterator ittg = targets.begin();
ittg != targets.end(); ++ittg) {
assert(map.on_board(ittg->loc));
std::pair<location,location> move = choose_move(targets,dstsrc);
for(std::vector<target>::const_iterator ittg = targets.begin(); ittg != targets.end(); ++ittg) {
assert(map_.on_board(ittg->loc));
}
@ -610,20 +577,18 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
gamemap::location target;
int weapon = -1;
for(int n = 0; n != 6; ++n) {
const unit_map::iterator enemy = units.find(adj[n]);
if(enemy != units.end() &&
current_team.is_enemy(enemy->second.side()) &&
!enemy->second.invisible(map[enemy->first.x][enemy->first.y])) {
const unit_map::iterator enemy = units_.find(adj[n]);
if(enemy != units_.end() &&
current_team().is_enemy(enemy->second.side()) &&
!enemy->second.invisible(map_[enemy->first.x][enemy->first.y])) {
target = adj[n];
weapon = choose_weapon(map,units,state,gameinfo,move.first,
target,bat_stats,
map[move.second.x][move.second.y]);
weapon = choose_weapon(move.first,target,bat_stats,
map_[move.second.x][move.second.y]);
break;
}
}
move_unit(gameinfo,disp,map,units,move.first,move.second,
possible_moves,teams,team_num);
move_unit(move.first,move.second,possible_moves);
//if we're going to attack someone
if(weapon != -1) {
@ -633,21 +598,18 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
recorder.add_attack(attacker,target,weapon);
game_events::fire("attack",attacker,target);
if(units.count(attacker) && units.count(target)) {
attack(disp,map,attacker,target,weapon,units,state,
gameinfo,false);
if(units_.count(attacker) && units_.count(target)) {
attack(disp_,map_,attacker,target,weapon,units_,state_,gameinfo_,false);
const std::map<gamemap::location,unit>::const_iterator tgt =
units.find(target);
const std::map<gamemap::location,unit>::const_iterator tgt = units_.find(target);
const bool defender_human = (tgt != units.end()) ?
teams[tgt->second.side()-1].is_human() : false;
const bool defender_human = (tgt != units_.end()) ?
teams_[tgt->second.side()-1].is_human() : false;
dialogs::advance_unit(gameinfo_,units_,attacker,disp_,true);
dialogs::advance_unit(gameinfo_,units_,target,disp_,!defender_human);
dialogs::advance_unit(gameinfo,units,attacker,disp,true);
dialogs::advance_unit(gameinfo,units,target,disp,!defender_human);
check_victory(units,teams);
check_victory(units_,teams_);
}
}
@ -659,9 +621,6 @@ void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
dstsrc.erase(del.first,del.second);
}
do_move(disp,map,gameinfo,units,teams,team_num,state,
consider_combat,additional_targets);
do_move();
return;
}
}

View file

@ -13,6 +13,7 @@
#ifndef AI_HPP_INCLUDED
#define AI_HPP_INCLUDED
#include "actions.hpp"
#include "ai_move.hpp"
#include "display.hpp"
#include "map.hpp"
@ -21,15 +22,116 @@
#include <map>
namespace ai {
typedef gamemap::location location;
typedef std::multimap<location,location> move_map;
class ai {
public:
typedef gamemap::location location;
typedef std::multimap<location,location> move_map;
ai(display& disp, const gamemap& map, const game_data& gameinfo,
std::map<gamemap::location,unit>& units,
std::vector<team>& teams, int team_num, const gamestatus& state);
void do_move();
/*
void do_move(display& disp, const gamemap& map, const game_data& gameinfo,
std::map<gamemap::location,unit>& units,
std::vector<team>& teams, int team_num, const gamestatus& state,
bool consider_combat=true,
std::vector<target>* additional_targets=NULL);
}
*/
private:
bool recruit(const std::string& usage);
void move_unit(const location& from, const location& to, std::map<location,paths>& possible_moves);
team& current_team();
struct attack_analysis
{
void analyze(const gamemap& map, std::map<location,unit>& units,
const gamestatus& status, const game_data& info, int sims,
class ai& ai_obj);
double rating(double aggression) const;
gamemap::location target;
std::vector<std::pair<gamemap::location,gamemap::location> > movements;
std::vector<int> weapons;
//the value of the unit being targeted
double target_value;
//the value on average, of units lost in the combat
double avg_losses;
//estimated % chance to kill the unit
double chance_to_kill;
//the average hitpoints damage inflicted
double avg_damage_inflicted;
int target_starting_damage;
//the average hitpoints damage taken
double avg_damage_taken;
//the sum of the values of units used in the attack
double resources_used;
//the weighted average of the % chance to hit each attacking unit
double terrain_quality;
//the ratio of the attacks the unit being attacked will get to
//the strength of its most powerful attack
double counter_strength_ratio;
double vulnerability, support;
};
void do_attack_analysis(
const location& loc,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
const location* tiles, bool* used_locations,
std::vector<location>& units,
std::vector<attack_analysis>& result,
attack_analysis& cur_analysis
);
double power_projection(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, bool use_terrain=true);
public:
int choose_weapon(const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain);
private:
std::vector<attack_analysis> analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
);
struct target {
target(const location& pos, double val) : loc(pos), value(val)
{}
location loc;
double value;
};
std::vector<target> find_targets(bool has_leader);
std::pair<location,location> choose_move(std::vector<target>& targets,const move_map& dstsrc);
display& disp_;
const gamemap& map_;
const game_data& gameinfo_;
unit_map& units_;
std::vector<team>& teams_;
int team_num_;
const gamestatus& state_;
bool consider_combat_;
std::vector<target> additional_targets_;
};
#endif

View file

@ -25,26 +25,20 @@
#include <iostream>
#include <set>
namespace {
const int max_positions = 10000;
using namespace ai;
//analyze possibility of attacking target on 'loc'
void do_analysis(
const gamemap& map,
const location& loc,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
const location* tiles, bool* used_locations,
std::vector<location>& units,
std::map<gamemap::location,unit>& units_map,
std::vector<attack_analysis>& result,
const game_data& data, const gamestatus& status,
attack_analysis& cur_analysis
)
void ai::do_attack_analysis(
const location& loc,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
const location* tiles, bool* used_locations,
std::vector<location>& units,
std::vector<attack_analysis>& result,
attack_analysis& cur_analysis
)
{
std::cerr << "doing attack analysis...\n";
if(cur_analysis.movements.size() >= 4)
return;
@ -93,28 +87,27 @@ void do_analysis(
if(its.first == its.second)
continue;
cur_analysis.movements.push_back(
std::pair<location,location>(current_unit,tiles[j]));
cur_analysis.movements.push_back(std::pair<location,location>(current_unit,tiles[j]));
//find out how vulnerable we are to attack from enemy units in this hex
const double vulnerability = power_projection(tiles[j],enemy_srcdst,enemy_dstsrc,units_map,map);
const double vulnerability = power_projection(tiles[j],enemy_srcdst,enemy_dstsrc);
cur_analysis.vulnerability += vulnerability;
//calculate how much support we have on this hex from allies. Support does not
//take into account terrain, because we don't want to move into a hex that is
//surrounded by good defensive terrain
const double support = power_projection(tiles[j],srcdst,dstsrc,units_map,map,false);
const double support = power_projection(tiles[j],srcdst,dstsrc,false);
cur_analysis.support += support;
cur_analysis.analyze(map,units_map,status,data,50);
cur_analysis.analyze(map_,units_,state_,gameinfo_,50,*this);
if(cur_analysis.rating(0.0) > rating_to_beat) {
result.push_back(cur_analysis);
used_locations[j] = true;
do_analysis(map,loc,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,
tiles,used_locations,
units,units_map,result,data,status,cur_analysis);
do_attack_analysis(loc,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,
tiles,used_locations,
units,result,cur_analysis);
used_locations[j] = false;
}
@ -128,9 +121,6 @@ void do_analysis(
}
}
}
namespace ai {
struct battle_type {
battle_type(const gamemap::location& a, const gamemap::location& d,
@ -161,21 +151,18 @@ bool operator==(const battle_type& a, const battle_type& b)
std::set<battle_type> weapon_choice_cache;
int choose_weapon(const gamemap& map, std::map<location,unit>& units,
const gamestatus& status, const game_data& info,
const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain)
int ai::choose_weapon(const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain)
{
const std::map<location,unit>::const_iterator itor = units.find(att);
if(itor == units.end())
const std::map<location,unit>::const_iterator itor = units_.find(att);
if(itor == units_.end())
return -1;
static int cache_hits = 0;
static int cache_misses = 0;
battle_type battle(att,def,terrain);
const std::set<battle_type>::const_iterator cache_itor
= weapon_choice_cache.find(battle);
const std::set<battle_type>::const_iterator cache_itor = weapon_choice_cache.find(battle);
if(cache_itor != weapon_choice_cache.end()) {
assert(*cache_itor == battle);
@ -203,13 +190,13 @@ int choose_weapon(const gamemap& map, std::map<location,unit>& units,
const std::vector<attack_type>& attacks = itor->second.attacks();
assert(!attacks.empty());
const std::map<location,unit>::const_iterator d_itor = units.find(def);
const unit_map::const_iterator d_itor = units_.find(def);
int d_hitpoints = d_itor->second.hitpoints();
int a_hitpoints = itor->second.hitpoints();
for(size_t a = 0; a != attacks.size(); ++a) {
const battle_stats stats = evaluate_battle_stats(map,att,def,a,units,
status,info,terrain,false);
const battle_stats stats = evaluate_battle_stats(map_,att,def,a,units_,
state_,gameinfo_,terrain,false);
//TODO: improve this rating formula!
const double rating =
@ -233,12 +220,12 @@ int choose_weapon(const gamemap& map, std::map<location,unit>& units,
return current_choice;
}
void attack_analysis::analyze(const gamemap& map,
std::map<location,unit>& units,
const gamestatus& status,
const game_data& info, int num_sims)
void ai::attack_analysis::analyze(const gamemap& map,
unit_map& units,
const gamestatus& status,
const game_data& info, int num_sims, ai& ai_obj)
{
const std::map<location,unit>::const_iterator defend_it =units.find(target);
const std::map<location,unit>::const_iterator defend_it = units.find(target);
assert(defend_it != units.end());
target_value = defend_it->second.type().cost();
@ -266,9 +253,7 @@ void attack_analysis::analyze(const gamemap& map,
std::vector<std::pair<location,location> >::const_iterator m;
for(m = movements.begin(); m != movements.end(); ++m) {
battle_stats bat_stats;
const int weapon = choose_weapon(map,units,status,info,
m->first,target, bat_stats,
map[m->second.x][m->second.y]);
const int weapon = ai_obj.choose_weapon(m->first,target, bat_stats, map[m->second.x][m->second.y]);
assert(weapon != -1);
weapons.push_back(weapon);
@ -289,8 +274,7 @@ void attack_analysis::analyze(const gamemap& map,
int attacks = stat.nattacks;
int defends = stat.ndefends;
std::map<location,unit>::const_iterator att
= units.find(movements[i].first);
unit_map::const_iterator att = units.find(movements[i].first);
double cost = att->second.type().cost();
//up to double the value of a unit based on experience
@ -398,7 +382,7 @@ void attack_analysis::analyze(const gamemap& map,
avg_losses /= num_sims;
}
double attack_analysis::rating(double aggression) const
double ai::attack_analysis::rating(double aggression) const
{
double value = chance_to_kill*target_value - avg_losses;
@ -414,14 +398,10 @@ double attack_analysis::rating(double aggression) const
return value;
}
std::vector<attack_analysis> analyze_targets(
const gamemap& map,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
std::map<location,unit>& units,
const team& current_team, int team_num,
const gamestatus& status, const game_data& data
)
std::vector<ai::attack_analysis> ai::analyze_targets(
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc
)
{
log_scope("analyzing targets...");
@ -430,9 +410,8 @@ std::vector<attack_analysis> analyze_targets(
std::vector<attack_analysis> res;
std::vector<location> unit_locs;
for(std::map<location,unit>::const_iterator i = units.begin();
i != units.end(); ++i) {
if(i->second.side() == team_num) {
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
if(i->second.side() == team_num_) {
unit_locs.push_back(i->first);
}
}
@ -440,13 +419,12 @@ std::vector<attack_analysis> analyze_targets(
bool used_locations[6];
std::fill(used_locations,used_locations+6,false);
for(std::map<location,unit>::const_iterator j = units.begin();
j != units.end(); ++j) {
for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) {
//attack anyone who is on the enemy side, and who is not invisible
if(current_team.is_enemy(j->second.side()) &&
j->second.invisible(map.underlying_terrain(
map[j->first.x][j->first.y])) == false) {
if(current_team().is_enemy(j->second.side()) &&
j->second.invisible(map_.underlying_terrain(map_[j->first.x][j->first.y])) == false) {
std::cerr << "analyzing attack on " << j->first.x+1 << "," << j->first.y+1 << "\n";
location adjacent[6];
get_adjacent_tiles(j->first,adjacent);
attack_analysis analysis;
@ -456,9 +434,8 @@ std::vector<attack_analysis> analyze_targets(
const int ticks = SDL_GetTicks();
do_analysis(map,j->first,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,
adjacent,used_locations,unit_locs,units,
res,data,status,analysis);
do_attack_analysis(j->first,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,
adjacent,used_locations,unit_locs,res,analysis);
const int time_taken = SDL_GetTicks() - ticks;
static int max_time = 0;
@ -472,9 +449,7 @@ std::vector<attack_analysis> analyze_targets(
return res;
}
double power_projection(const gamemap::location& loc,
const move_map& srcdst, const move_map& dstsrc,
const unit_map& units, const gamemap& map, bool use_terrain)
double ai::power_projection(const gamemap::location& loc, const move_map& srcdst, const move_map& dstsrc, bool use_terrain)
{
static gamemap::location used_locs[6];
static double ratings[6];
@ -486,11 +461,11 @@ double power_projection(const gamemap::location& loc,
double res = 0.0;
for(int i = 0; i != 6; ++i) {
if(map.on_board(locs[i]) == false) {
if(map_.on_board(locs[i]) == false) {
continue;
}
const gamemap::TERRAIN terrain = map[locs[i].x][locs[i].y];
const gamemap::TERRAIN terrain = map_[locs[i].x][locs[i].y];
typedef move_map::const_iterator Itor;
typedef std::pair<Itor,Itor> Range;
@ -508,10 +483,10 @@ double power_projection(const gamemap::location& loc,
continue;
}
const unit_map::const_iterator u = units.find(it->second);
const unit_map::const_iterator u = units_.find(it->second);
//unit might have been killed, and no longer exist
if(u == units.end()) {
if(u == units_.end()) {
continue;
}
@ -527,10 +502,10 @@ double power_projection(const gamemap::location& loc,
most_damage = damage;
}
const bool village = map.underlying_terrain(terrain) == gamemap::TOWER;
const bool village = map_.underlying_terrain(terrain) == gamemap::TOWER;
const double village_bonus = (use_terrain && village) ? 1.5 : 1.0;
const double defense = use_terrain ? double(100 - un.defense_modifier(map,terrain))/100.0 : 0.5;
const double defense = use_terrain ? double(100 - un.defense_modifier(map_,terrain))/100.0 : 0.5;
const double rating = village_bonus*hp*defense*double(most_damage);
if(rating > best_rating) {
best_rating = rating;
@ -543,8 +518,7 @@ double power_projection(const gamemap::location& loc,
//a better position to attack from
if(n == 1 && best_unit.valid()) {
end_used = beg_used + num_used_locs;
gamemap::location* const pos
= std::find(beg_used,end_used,best_unit);
gamemap::location* const pos = std::find(beg_used,end_used,best_unit);
const int index = pos - beg_used;
if(best_rating >= ratings[index]) {
res -= ratings[index];
@ -573,6 +547,4 @@ double power_projection(const gamemap::location& loc,
}
return res;
}
}
}

View file

@ -23,67 +23,4 @@
#include <map>
#include <vector>
namespace ai {
double power_projection(const gamemap::location& loc,
const move_map& srcdst, const move_map& dstsrc,
const unit_map& units, const gamemap& map, bool use_terrain=true);
int choose_weapon(const gamemap& map, std::map<location,unit>& units,
const gamestatus& status, const game_data& info,
const location& att, const location& def,
battle_stats& cur_stats, gamemap::TERRAIN terrain);
struct attack_analysis
{
void analyze(const gamemap& map, std::map<location,unit>& units,
const gamestatus& status, const game_data& info, int sims);
double rating(double aggression) const;
gamemap::location target;
std::vector<std::pair<gamemap::location,gamemap::location> > movements;
std::vector<int> weapons;
//the value of the unit being targeted
double target_value;
//the value on average, of units lost in the combat
double avg_losses;
//estimated % chance to kill the unit
double chance_to_kill;
//the average hitpoints damage inflicted
double avg_damage_inflicted;
int target_starting_damage;
//the average hitpoints damage taken
double avg_damage_taken;
//the sum of the values of units used in the attack
double resources_used;
//the weighted average of the % chance to hit each attacking unit
double terrain_quality;
//the ratio of the attacks the unit being attacked will get to
//the strength of its most powerful attack
double counter_strength_ratio;
double vulnerability, support;
};
std::vector<attack_analysis> analyze_targets(
const gamemap& map,
const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc,
std::map<location,unit>& units,
const team& current_team, int team_num,
const gamestatus& status, const game_data& data
);
}
#endif

View file

@ -14,31 +14,30 @@
#include "display.hpp"
#include "game_config.hpp"
#include "log.hpp"
#include "map.hpp"
#include "util.hpp"
#include <iostream>
namespace ai {
struct move_cost_calculator
{
move_cost_calculator(const unit& u, const gamemap& map,
const game_data& data,
const std::map<location,unit>& units,
const unit_map& units,
const gamemap::location& loc,
const std::multimap<location,location>& dstsrc)
const std::multimap<gamemap::location,gamemap::location>& dstsrc)
: unit_(u), map_(map), data_(data), units_(units),
move_type_(u.type().movement_type()), loc_(loc), dstsrc_(dstsrc)
{}
double cost(const location& loc, double so_far) const
double cost(const gamemap::location& loc, double so_far) const
{
if(!map_.on_board(loc))
return 1000.0;
//if this unit can move to that location this turn, it has a very
//very low cost
typedef std::multimap<location,location>::const_iterator Itor;
typedef std::multimap<gamemap::location,gamemap::location>::const_iterator Itor;
std::pair<Itor,Itor> range = dstsrc_.equal_range(loc);
while(range.first != range.second) {
if(range.first->second == loc_)
@ -83,52 +82,47 @@ private:
const unit& unit_;
const gamemap& map_;
const game_data& data_;
const std::map<location,unit>& units_;
const unit_map& units_;
const unit_movement_type& move_type_;
const gamemap::location loc_;
const std::multimap<location,location> dstsrc_;
const ai::move_map dstsrc_;
};
std::vector<target> find_targets(
const gamemap& map, std::map<location,unit>& units,
std::vector<team>& teams, int current_team, bool has_leader
)
std::vector<ai::target> ai::find_targets(bool has_leader)
{
log_scope("finding targets...");
team& tm = teams[current_team-1];
std::vector<target> targets;
if(has_leader && tm.village_value() > 0.0) {
const std::vector<location>& towers = map.towers();
if(has_leader && current_team().village_value() > 0.0) {
const std::vector<location>& towers = map_.towers();
for(std::vector<location>::const_iterator t = towers.begin(); t != towers.end(); ++t) {
assert(map.on_board(*t));
bool get_tower = true;
for(size_t i = 0; i != teams.size(); ++i) {
if(!tm.is_enemy(i+1) && teams[i].owns_tower(*t)) {
for(size_t i = 0; i != teams_.size(); ++i) {
if(!current_team().is_enemy(i+1) && teams_[i].owns_tower(*t)) {
get_tower = false;
break;
}
}
if(get_tower) {
targets.push_back(target(*t,tm.village_value()));
targets.push_back(target(*t,current_team().village_value()));
}
}
}
std::vector<team::target>& team_targets = tm.targets();
std::vector<team::target>& team_targets = current_team().targets();
//find the enemy leaders and explicit targets
std::map<location,unit>::const_iterator u;
for(u = units.begin(); u != units.end(); ++u) {
unit_map::const_iterator u;
for(u = units_.begin(); u != units_.end(); ++u) {
//is an enemy leader
if(u->second.can_recruit() && tm.is_enemy(u->second.side())) {
assert(map.on_board(u->first));
targets.push_back(target(u->first,tm.leader_value()));
if(u->second.can_recruit() && current_team().is_enemy(u->second.side())) {
assert(map_.on_board(u->first));
targets.push_back(target(u->first,current_team().leader_value()));
}
//explicit targets for this team
@ -148,8 +142,7 @@ std::vector<target> find_targets(
new_values.push_back(i->value);
for(std::vector<target>::const_iterator j = targets.begin();
j != targets.end(); ++j) {
for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
if(i->loc == j->loc) {
continue;
}
@ -169,14 +162,7 @@ std::vector<target> find_targets(
return targets;
}
std::pair<location,location> choose_move(
std::vector<target>& targets,
const std::multimap<location,location>& dstsrc,
std::map<location,unit>& units,
const gamemap& map, const std::vector<team>& teams,
int current_team,
const game_data& data
)
std::pair<gamemap::location,gamemap::location> ai::choose_move(std::vector<ai::target>& targets,const std::multimap<location,location>& dstsrc)
{
log_scope("choosing move");
@ -186,21 +172,20 @@ std::pair<location,location> choose_move(
}
paths::route best_route;
std::map<location,unit>::iterator best = units.end();
unit_map::iterator best = units_.end();
double best_rating = 0.1;
std::vector<target>::iterator best_target = targets.end();
std::map<location,unit>::iterator u;
unit_map::iterator u;
//find the first eligible unit
for(u = units.begin(); u != units.end(); ++u) {
if(!(u->second.side() != current_team || u->second.can_recruit() ||
u->second.movement_left() <= 0)) {
for(u = units_.begin(); u != units_.end(); ++u) {
if(!(u->second.side() != team_num_ || u->second.can_recruit() || u->second.movement_left() <= 0)) {
break;
}
}
if(u == units.end()) {
if(u == units_.end()) {
std::cout << "no eligible units found\n";
return std::pair<location,location>();
}
@ -211,8 +196,7 @@ std::pair<location,location> choose_move(
return std::pair<location,location>(u->first,u->first);
}
const move_cost_calculator cost_calc(u->second,map,data,units,
u->first,dstsrc);
const move_cost_calculator cost_calc(u->second,map_,gameinfo_,units_,u->first,dstsrc);
//choose the best target for that unit
for(std::vector<target>::iterator tg = targets.begin(); tg != targets.end(); ++tg) {
@ -236,18 +220,17 @@ std::pair<location,location> choose_move(
}
//now see if any other unit can put a better bid forward
for(++u; u != units.end(); ++u) {
if(u->second.side() != current_team || u->second.can_recruit() ||
for(++u; u != units_.end(); ++u) {
if(u->second.side() != team_num_ || u->second.can_recruit() ||
u->second.movement_left() <= 0 || u->second.is_guardian()) {
continue;
}
const move_cost_calculator calc(u->second,map,data,units,
u->first,dstsrc);
const move_cost_calculator calc(u->second,map_,gameinfo_,units_,u->first,dstsrc);
const paths::route cur_route = a_star_search(u->first,best_target->loc,
minimum(best_target->value/best_rating,100.0),calc);
const double rating = best_target->value/cur_route.move_left;
if(best == units.end() || rating > best_rating) {
if(best == units_.end() || rating > best_rating) {
best_rating = rating;
best = u;
best_route = cur_route;
@ -259,8 +242,7 @@ std::pair<location,location> choose_move(
if(best_target->value <= 0.0)
targets.erase(best_target);
for(ittg = targets.begin();
ittg != targets.end(); ++ittg) {
for(ittg = targets.begin(); ittg != targets.end(); ++ittg) {
assert(map.on_board(ittg->loc));
}
@ -283,7 +265,7 @@ std::pair<location,location> choose_move(
}
}
if(best != units.end()) {
if(best != units_.end()) {
std::cout << "Could not make good move, staying still\n";
return std::pair<location,location>(best->first,best->first);
}
@ -291,5 +273,3 @@ std::pair<location,location> choose_move(
std::cout << "Could not find anywhere to move!\n";
return std::pair<location,location>();
}
}

View file

@ -14,37 +14,11 @@
#define AI_MOVE_H_INCLUDED
#include "map.hpp"
#include "ai.hpp"
#include "pathfind.hpp"
#include "unit.hpp"
#include "unit_types.hpp"
#include <map>
namespace ai {
typedef gamemap::location location;
struct target {
target(const location& pos, double val) : loc(pos), value(val)
{}
location loc;
double value;
};
std::vector<target> find_targets(
const gamemap& map, std::map<location,unit>& units,
std::vector<team>& teams, int current_team, bool has_leader
);
std::pair<location,location> choose_move(
std::vector<target>& targets,
const std::multimap<location,location>& dstsrc,
std::map<location,unit>& units,
const gamemap& map, const std::vector<team>& teams,
int current_team,
const game_data& data
);
}
#endif

View file

@ -161,7 +161,7 @@ void find_routes(const gamemap& map, const game_data& gamedata,
//teleport to
for(std::vector<gamemap::location>::const_iterator t = towers.begin();
t != towers.end(); ++t) {
if(!current_team.owns_tower(*t))
if(!current_team.owns_tower(*t) || units.count(*t))
continue;
locs.push_back(*t);

View file

@ -391,8 +391,7 @@ redo_turn:
update_locker lock(gui,!preferences::show_ai_moves());
ai::do_move(gui,map,gameinfo,units,teams,
player_number,status);
ai(gui,map,gameinfo,units,teams,player_number,status).do_move();
if(network::nconnections() > 0) {
config cfg;

View file

@ -92,8 +92,15 @@ void play_turn(game_data& gameinfo, game_state& state_of_game,
unit u = ui->second;
const shortest_path_calculator calc(u,current_team,units,map);
const std::set<gamemap::location>* const teleports =
u.type().teleports() ? &current_team.towers() : NULL;
const std::set<gamemap::location>* teleports = NULL;
std::set<gamemap::location> allowed_teleports;
if(u.type().teleports()) {
allowed_teleports = vacant_towers(current_team.towers(),units);
teleports = &allowed_teleports;
if(current_team.towers().count(ui->first))
allowed_teleports.insert(ui->first);
}
paths::route route = a_star_search(ui->first,ui->second.get_goto(),
10000.0,calc,teleports);
@ -275,8 +282,15 @@ void turn_info::mouse_motion(const SDL_MouseMotionEvent& event)
units_,map_);
const bool can_teleport = un->second.type().teleports();
const std::set<gamemap::location>* const teleports =
can_teleport ? &current_team.towers() : NULL;
const std::set<gamemap::location>* teleports = NULL;
std::set<gamemap::location> allowed_teleports;
if(can_teleport) {
allowed_teleports = vacant_towers(current_team.towers(),units_);
teleports = &allowed_teleports;
if(current_team.towers().count(un->first))
allowed_teleports.insert(un->first);
}
current_route_ = a_star_search(selected_hex_,new_hex,
10000.0,calc,teleports);
@ -594,8 +608,16 @@ void turn_info::left_click(const SDL_MouseButtonEvent& event)
const shortest_path_calculator calc(u,current_team,
units_,map_);
const std::set<gamemap::location>* const teleports =
teleport ? &current_team.towers() : NULL;
const std::set<gamemap::location>* teleports = NULL;
std::set<gamemap::location> allowed_teleports;
if(u.type().teleports()) {
allowed_teleports = vacant_towers(current_team.towers(),units_);
teleports = &allowed_teleports;
if(current_team.towers().count(it->first))
allowed_teleports.insert(it->first);
}
paths::route route = a_star_search(it->first,go_to,
10000.0,calc,teleports);

View file

@ -510,4 +510,17 @@ int team::nteams()
} else {
return teams->size();
}
}
const std::set<gamemap::location> vacant_towers(const std::set<gamemap::location>& towers, const unit_map& units)
{
std::set<gamemap::location> res;
for(std::set<gamemap::location>::const_iterator i = towers.begin(); i != towers.end(); ++i) {
if(units.count(*i) == 0) {
res.insert(*i);
}
}
return res;
}

View file

@ -202,4 +202,6 @@ team_data calculate_team_data(const class team& tm, int side, const unit_map& un
std::string get_team_name(int side, const unit_map& units);
const std::set<gamemap::location> vacant_towers(const std::set<gamemap::location>& towers, const unit_map& units);
#endif