various AI improvements

This commit is contained in:
Dave White 2004-05-13 15:40:36 +00:00
parent aaae03dec2
commit bf663eb2e2
9 changed files with 79 additions and 27 deletions

View file

@ -74,7 +74,8 @@ Defeat:
description=Robert
side=2
canrecruit=1
recruit=Cavalry, Swordsman, Mage, Ogre, Duelist
recruit=Cavalry,Swordsman,Mage,Ogre,Duelist,Longbowman
recruitment_pattern=scout,fighter,fighter,fighter,archer,mixed fighter
{GOLD 200 300 500}
[/side]
@ -85,6 +86,9 @@ Defeat:
canrecruit=1
recruit=Gryphon
gold=0
[ai]
passive_leader=yes
[/ai]
[/side]
#if the player kills the mother gryphon

View file

@ -61,7 +61,7 @@ Defeat:
experience=0
side=2
canrecruit=1
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp
recruit=Orcish Grunt,Wolf Rider,Orcish Archer,Troll Whelp,Saurian
recruitment_pattern=scout,scout,fighter,fighter,archer
{GOLD 80 160 260}
enemy=1

View file

@ -71,6 +71,7 @@ bool ai::recruit_usage(const std::string& usage)
if(i->second.usage() == usage && recruits.count(name)
&& current_team().gold() - i->second.cost() > min_gold
&& not_recommended_units_.count(name) == 0) {
std::cerr << "recommending '" << name << "'\n";
options.push_back(name);
}
}
@ -170,6 +171,7 @@ void ai_interface::sync_network()
gamemap::location ai_interface::move_unit(location from, location to, std::map<location,paths>& possible_moves)
{
std::cerr << "ai_interface::move_unit " << (from.x+1) << (from.y+1) << " -> " << (to.x+1) << "," << (to.y+1) << "\n";
//stop the user from issuing any commands while the unit is moving
const command_disabler disable_commands(&info_.disp);
@ -188,6 +190,7 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
}
if(from == to) {
std::cerr << "moving unit at " << (from.x+1) << "," << (from.y+1) << " on spot. resetting moves\n";
u_it->second.set_movement(0);
return to;
}
@ -274,6 +277,7 @@ gamemap::location ai_interface::move_unit(location from, location to, std::map<l
gamemap::location ai::move_unit(location from, location to, std::map<location,paths>& possible_moves)
{
std::cerr << "ai::move_unit " << (from.x+1) << (from.y+1) << " -> " << (to.x+1) << "," << (to.y+1) << "\n";
std::map<location,paths> temp_possible_moves;
std::map<location,paths>* possible_moves_ptr = &possible_moves;
@ -321,6 +325,7 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
const unit_map::iterator itor = units_.find(from);
if(itor != units_.end()) {
std::cerr << "setting temp moves of unit to " << move_left << "\n";
itor->second.set_movement(move_left);
}
@ -335,7 +340,7 @@ gamemap::location ai::move_unit(location from, location to, std::map<location,pa
do_recruitment();
}
if(units_.count(to) == 0) {
if(units_.count(to) == 0 || from == to) {
return ai_interface::move_unit(from,to,*possible_moves_ptr);
} else {
return from;
@ -416,6 +421,18 @@ void ai_interface::calculate_possible_moves(std::map<location,paths>& res, move_
}
}
void ai::remove_unit_from_moves(const gamemap::location& loc, move_map& srcdst, move_map& dstsrc)
{
srcdst.erase(loc);
for(move_map::iterator i = dstsrc.begin(); i != dstsrc.end(); ) {
if(i->second == loc) {
dstsrc.erase(i++);
} else {
++i;
}
}
}
void ai::play_turn()
{
consider_combat_ = true;
@ -438,7 +455,12 @@ void ai::do_move()
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
calculate_possible_moves(enemy_possible_moves,enemy_srcdst,enemy_dstsrc,true);
const bool passive_leader = current_team().ai_parameters()["passive_leader"] == "yes";
unit_map::iterator leader = find_leader(units_,team_num_);
if(leader != units_.end() && passive_leader) {
remove_unit_from_moves(leader->first,srcdst,dstsrc);
}
int ticks = SDL_GetTicks();
@ -475,27 +497,26 @@ void ai::do_move()
}
if(leader != units_.end()) {
srcdst.erase(leader->first);
for(move_map::iterator i = dstsrc.begin(); i != dstsrc.end(); ) {
if(i->second == leader->first) {
dstsrc.erase(i++);
} else {
++i;
}
}
remove_unit_from_moves(leader->first,srcdst,dstsrc);
}
const bool met_invisible_unit = move_to_targets(possible_moves,srcdst,dstsrc,enemy_srcdst,enemy_dstsrc,leader);
if(met_invisible_unit) {
std::cerr << "met_invisible_unit\n";
do_move();
return;
}
std::cerr << "done move to targets\n";
//recruitment phase and leader movement phase
if(leader != units_.end()) {
move_leader_to_keep(enemy_dstsrc);
do_recruitment();
move_leader_after_recruit(enemy_dstsrc);
if(!passive_leader) {
move_leader_after_recruit(enemy_dstsrc);
}
}
recorder.end_turn();
@ -877,8 +898,9 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
assert(map_.on_board(ittg->loc));
}
if(move.first.valid() == false)
if(move.first.valid() == false) {
break;
}
std::cerr << "move: " << move.first.x << ", " << move.first.y << " - " << move.second.x << ", " << move.second.y << "\n";
@ -909,6 +931,7 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
//we didn't arrive at our intended destination. We return true, meaning that
//the AI algorithm should be recalculated from the start.
if(arrived_at != move.second) {
std::cerr << "didn't arrive at destination\n";
return true;
}
@ -921,7 +944,7 @@ bool ai::move_to_targets(std::map<gamemap::location,paths>& possible_moves, move
//don't allow any other units to move onto the tile our unit
//just moved onto
typedef std::multimap<location,location>::iterator Itor;
typedef move_map::iterator Itor;
std::pair<Itor,Itor> del = dstsrc.equal_range(arrived_at);
dstsrc.erase(del.first,del.second);
}

View file

@ -325,6 +325,8 @@ protected:
virtual bool recruit_usage(const std::string& usage);
void remove_unit_from_moves(const gamemap::location& u, move_map& srcdst, move_map& dstsrc);
//function which will calculate which movements should be made to get an optimal number of villages
std::vector<std::pair<gamemap::location,gamemap::location> > get_village_combinations(std::map<gamemap::location,paths>& possible_moves, const move_map& srcdst, const move_map& dstsrc,
const move_map& enemy_srcdst, const move_map& enemy_dstsrc, unit_map::const_iterator leader,
@ -382,6 +384,9 @@ protected:
//is true if the unit is a threat to our leader
bool leader_threat;
//is true if this attack sequence makes use of the leader
bool uses_leader;
};
virtual void do_attack_analysis(

View file

@ -309,6 +309,7 @@ void ai::attack_analysis::analyze(const gamemap& map,
}
leader_threat = (tile != 6);
uses_leader = false;
target_value = defend_it->second.type().cost();
target_value += (double(defend_it->second.experience())/
@ -359,6 +360,10 @@ void ai::attack_analysis::analyze(const gamemap& map,
unit_map::const_iterator att = units.find(movements[i].first);
double cost = att->second.type().cost();
if(att->second.can_recruit()) {
uses_leader = true;
}
const bool on_village = map.is_village(movements[i].second);
//up to double the value of a unit based on experience
@ -472,6 +477,12 @@ double ai::attack_analysis::rating(double aggression) const
aggression = 1.0;
}
//only use the leader if we do a serious amount of damage
//compared to how much they do to us.
if(uses_leader && aggression > -1.0) {
aggression = -1.0;
}
double value = chance_to_kill*target_value - avg_losses;
//prefer to attack already damaged targets

View file

@ -171,7 +171,7 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
//if this isn't the last scenario, then save the game
if(scenario != NULL) {
state.label = translate_string_default((*scenario)["id"],(*scenario)["name"]);
state.starting_pos = *scenario;
state.starting_pos = config();
bool retry = true;
@ -192,6 +192,8 @@ LEVEL_RESULT play_game(display& disp, game_state& state, config& game_config,
}
}
}
state.starting_pos = *scenario;
}
}

View file

@ -279,13 +279,17 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
else if(cmd == "allow_recruit") {
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
if(index >= teams->size())
return rval;
const std::string& type = cfg["type"];
(*teams)[index].recruits().insert(type);
if(index == 0) {
state_of_game->can_recruit.insert(type);
const std::vector<std::string>& types = config::split(type);
for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
(*teams)[index].recruits().insert(*i);
if(index == 0) {
state_of_game->can_recruit.insert(*i);
}
}
}
@ -293,20 +297,23 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
else if(cmd == "disallow_recruit") {
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
if(index >= teams->size())
return rval;
const std::string& type = cfg["type"];
(*teams)[index].recruits().erase(type);
if(index == 0) {
state_of_game->can_recruit.erase(type);
const std::vector<std::string>& types = config::split(type);
for(std::vector<std::string>::const_iterator i = types.begin(); i != types.end(); ++i) {
(*teams)[index].recruits().erase(*i);
if(index == 0) {
state_of_game->can_recruit.erase(*i);
}
}
}
else if(cmd == "set_recruit") {
const int side = maximum<int>(1,atoi(cfg["side"].c_str()));
const size_t index = side-1;
if(index > teams->size())
if(index >= teams->size())
return rval;
std::vector<std::string> recruit = config::split(cfg["recruit"]);
@ -693,7 +700,7 @@ bool event_handler::handle_event_command(const queued_event& event_info, const s
std::vector<unit>& avail = state_of_game->available_units;
for(std::vector<unit>::iterator u = avail.begin(); u != avail.end(); ++u) {
if(u->matches_filter(cfg)) {
gamemap::location loc;
gamemap::location loc(cfg);
recruit_unit(*game_map,1,*units,*u,loc,screen,false,true);
avail.erase(u);
break;

View file

@ -603,6 +603,7 @@ redo_turn:
if((end_level.result == DEFEAT || end_level.result == VICTORY) && is_observer(teams)) {
gui::show_dialog(gui,NULL,string_table["observer_endgame_heading"],
string_table["observer_endgame"], gui::OK_ONLY);
return end_level.result;
}
if(end_level.result == QUIT || end_level.result == REPLAY) {

View file

@ -119,8 +119,7 @@ team::team_info::team_info(const config& cfg)
}
std::vector<std::string> recruits = config::split(cfg["recruit"]);
for(std::vector<std::string>::const_iterator i = recruits.begin();
i != recruits.end(); ++i) {
for(std::vector<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
can_recruit.insert(*i);
}