Applied Silene's "speed up compilation - AI" (patch #3322)

This commit is contained in:
Isaac Clerencia Perez 2004-08-29 11:48:34 +00:00
parent 2b18748bb2
commit 3b6cf7aad0
7 changed files with 292 additions and 281 deletions

View file

@ -31,6 +31,149 @@
#include <iostream>
///a trivial ai that sits around doing absolutely nothing
class idle_ai : public ai_interface {
public:
idle_ai(info& i) : ai_interface(i) {}
void play_turn() {}
};
class sample_ai : public ai_interface {
public:
sample_ai(info& i) : ai_interface(i) {}
void play_turn() {
do_attacks();
get_villages();
do_moves();
do_recruitment();
}
private:
void do_attacks() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(unit_map::const_iterator i = get_info().units.begin(); i != get_info().units.end(); ++i) {
if(current_team().is_enemy(i->second.side())) {
location adjacent_tiles[6];
get_adjacent_tiles(i->first,adjacent_tiles);
int best_defense = -1;
std::pair<location,location> best_movement;
for(size_t n = 0; n != 6; ++n) {
typedef move_map::const_iterator Itor;
std::pair<Itor,Itor> range = dstsrc.equal_range(adjacent_tiles[n]);
while(range.first != range.second) {
const location& dst = range.first->first;
const location& src = range.first->second;
const unit_map::const_iterator un = get_info().units.find(src);
const gamemap::TERRAIN terrain = get_info().map.get_terrain(dst);
const int chance_to_hit = un->second.defense_modifier(get_info().map,terrain);
if(best_defense == -1 || chance_to_hit < best_defense) {
best_defense = chance_to_hit;
best_movement = *range.first;
}
++range.first;
}
}
if(best_defense != -1) {
move_unit(best_movement.second,best_movement.first,possible_moves);
const int weapon = choose_weapon(best_movement.first,i->first);
attack_enemy(best_movement.first,i->first,weapon);
do_attacks();
return;
}
}
}
}
int choose_weapon(const location& attacker, const location& defender) {
const unit_map::const_iterator att = get_info().units.find(attacker);
assert(att != get_info().units.end());
const std::vector<attack_type>& attacks = att->second.attacks();
int best_attack_rating = -1;
int best_attack = -1;
for(size_t n = 0; n != attacks.size(); ++n) {
const battle_stats stats = evaluate_battle_stats(get_info().map,attacker,defender,n,get_info().units,get_info().state,get_info().gameinfo,0,false);
const int attack_rating = stats.damage_defender_takes*stats.nattacks*stats.chance_to_hit_defender;
if(best_attack == -1 || attack_rating > best_attack_rating) {
best_attack = n;
best_attack_rating = attack_rating;
}
}
return best_attack;
}
void get_villages() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
if(get_info().map.is_village(i->first) && current_team().owns_village(i->first) == false) {
move_unit(i->second,i->first,possible_moves);
get_villages();
return;
}
}
}
void do_moves() {
unit_map::const_iterator leader;
for(leader = get_info().units.begin(); leader != get_info().units.end(); ++leader) {
if(leader->second.can_recruit() && current_team().is_enemy(leader->second.side())) {
break;
}
}
if(leader == get_info().units.end())
return;
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
int closest_distance = -1;
std::pair<location,location> closest_move;
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
const int distance = distance_between(i->first,leader->first);
if(closest_distance == -1 || distance < closest_distance) {
closest_distance = distance;
closest_move = *i;
}
}
if(closest_distance != -1) {
move_unit(closest_move.second,closest_move.first,possible_moves);
do_moves();
}
}
void do_recruitment() {
const std::set<std::string>& options = current_team().recruits();
const int choice = (rand()%options.size());
std::set<std::string>::const_iterator i = options.begin();
std::advance(i,choice);
const bool res = recruit(*i);
if(res) {
do_recruitment();
}
}
};
ai_interface* create_ai(const std::string& name, ai_interface::info& info)
{
//to add an AI of your own, put

View file

@ -14,285 +14,11 @@
#define AI_HPP_INCLUDED
#include "actions.hpp"
#include "ai_move.hpp"
#include "display.hpp"
#include "map.hpp"
#include "pathfind.hpp"
#include "unit.hpp"
#include "unit_types.hpp"
#include <map>
#include "ai_interface.hpp"
#define AI_DIAGNOSTIC(MSG) if(game_config::debug) { diagnostic(MSG); } std::cerr << "AI_DIAGNOSTIC: " << MSG << "\n";
#define AI_LOG(MSG) if(game_config::debug) { log_message(MSG); } std::cerr << "AI_LOG: " << MSG << "\n";
class ai_interface {
public:
///a convenient typedef for the often used 'location' object
typedef gamemap::location location;
///the standard way in which a map of possible moves is recorded
typedef std::multimap<location,location> move_map;
///info: a structure which holds references to all the important objects
///that an AI might need access to in order to make and implement its decisions
struct info {
info(display& disp, const gamemap& map, const game_data& gameinfo, unit_map& units,
std::vector<team>& teams, int team_num, const gamestatus& state, class turn_info& turn_data)
: disp(disp), map(map), gameinfo(gameinfo), units(units), teams(teams),
team_num(team_num), state(state), turn_data_(turn_data)
{}
///the display object, used to draw the moves the AI makes.
display& disp;
///the map of the game -- use this object to find the terrain at any location
const gamemap& map;
///this object contains information about the types of units and races in the game
const game_data& gameinfo;
///the map of units - maps locations -> units
unit_map& units;
///a list of the teams in the game
std::vector<team>& teams;
///the number of the team the AI is. Note that this number is 1-based, so it
///has to have 1 subtracted from it for it to be used as an index of 'teams'
int team_num;
///information about what turn it is, and what time of day
const gamestatus& state;
///the object that allows the player to interact with the game.
///should not be used outside of ai_interface
class turn_info& turn_data_;
};
///the constructor. All derived classes should take an argument of type info& which
///they should pass to this constructor
ai_interface(info& arg) : info_(arg), last_interact_(0) {}
virtual ~ai_interface() {}
///the function that is called when the AI must play its turn. Derived classes should
///implement their AI algorithm in this function
virtual void play_turn() = 0;
///functions which return a reference to the 'team' object for the AI
team& current_team();
const team& current_team() const;
///function to update network players as to what the AI has done so far this turn
void sync_network();
///function to show a diagnostic message on the screen
void diagnostic(const std::string& msg);
///function to display a debug message as a chat message is displayed
void log_message(const std::string& msg);
protected:
///this function should be called to attack an enemy.
///'attacking_unit': the location of the attacking unit
///'target': the location of the target unit. This unit must be in range of the
///attacking unit's weapon
///'weapon': the number of the weapon (0-based) which should be used in the attack.
///must be a valid weapon of the attacking unit
void attack_enemy(const location& attacking_unit, const location& target, int weapon);
///this function should be called to move a unit. Once the unit has been moved, its
///movement allowance is set to 0.
///'from': the location of the unit being moved.
///'to': the location to be moved to. This must be a valid move for the unit
///'possible_moves': the map of possible moves, as obtained from 'calculate_possible_moves'
location move_unit(location from, location to, std::map<location,paths>& possible_moves);
///this function is used to calculate the moves units may possibly make.
///'possible_moves': a map which will be filled with the paths each unit can take to
///get to every possible destination. You probably don't want to use this object at all,
///except to pass to 'move_unit'.
///'srcdst': a map of units to all their possible destinations
///'dstsrc': a map of destinations to all the units that can move to that destination
///'enemy': if true, a map of possible moves for enemies will be calculated. If false,
///a map of possible moves for units on the AI's side will be calculated. The AI's own
///leader will not be included in this map.
///'assume_full_movement': if true, the function will operate on the assumption that all
///units can move their full movement allotment.
///'remove_destinations': a pointer to a set of possible destinations to omit
void calculate_possible_moves(std::map<location,paths>& possible_moves, move_map& srcdst, move_map& dstsrc, bool enemy, bool assume_full_movement=false,
const std::set<location>* remove_destinations=NULL);
///this function is used to recruit a unit. It will recruit the unit with the given name,
///at the given location, or at an available location to recruit units if 'loc' is not
///a valid recruiting location.
///
///if recruitment cannot be performed, because there are no available tiles, or not enough
///money, then the function will return false
bool recruit(const std::string& unit_name, location loc=location());
///functions to retrieve the 'info' object. Used by derived classes to discover all
///necessary game information
info& get_info() { return info_; }
const info& get_info() const { return info_; }
///function which should be called frequently to allow the user to interact with
///the interface. This function will make sure that interaction doesn't occur
///too often, so there is no problem with calling it very regularly
void user_interact();
private:
info info_;
int last_interact_;
};
///this function is used to create a new AI object with the specified algorithm name
ai_interface* create_ai(const std::string& algorithm_name, ai_interface::info& info);
///a trivial ai that sits around doing absolutely nothing
class idle_ai : public ai_interface {
public:
idle_ai(info& i) : ai_interface(i) {}
void play_turn() {}
};
class sample_ai : public ai_interface {
public:
sample_ai(info& i) : ai_interface(i) {}
void play_turn() {
do_attacks();
get_villages();
do_moves();
do_recruitment();
}
private:
void do_attacks() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(unit_map::const_iterator i = get_info().units.begin(); i != get_info().units.end(); ++i) {
if(current_team().is_enemy(i->second.side())) {
location adjacent_tiles[6];
get_adjacent_tiles(i->first,adjacent_tiles);
int best_defense = -1;
std::pair<location,location> best_movement;
for(size_t n = 0; n != 6; ++n) {
typedef move_map::const_iterator Itor;
std::pair<Itor,Itor> range = dstsrc.equal_range(adjacent_tiles[n]);
while(range.first != range.second) {
const location& dst = range.first->first;
const location& src = range.first->second;
const unit_map::const_iterator un = get_info().units.find(src);
const gamemap::TERRAIN terrain = get_info().map.get_terrain(dst);
const int chance_to_hit = un->second.defense_modifier(get_info().map,terrain);
if(best_defense == -1 || chance_to_hit < best_defense) {
best_defense = chance_to_hit;
best_movement = *range.first;
}
++range.first;
}
}
if(best_defense != -1) {
move_unit(best_movement.second,best_movement.first,possible_moves);
const int weapon = choose_weapon(best_movement.first,i->first);
attack_enemy(best_movement.first,i->first,weapon);
do_attacks();
return;
}
}
}
}
int choose_weapon(const location& attacker, const location& defender) {
const unit_map::const_iterator att = get_info().units.find(attacker);
assert(att != get_info().units.end());
const std::vector<attack_type>& attacks = att->second.attacks();
int best_attack_rating = -1;
int best_attack = -1;
for(size_t n = 0; n != attacks.size(); ++n) {
const battle_stats stats = evaluate_battle_stats(get_info().map,attacker,defender,n,get_info().units,get_info().state,get_info().gameinfo,0,false);
const int attack_rating = stats.damage_defender_takes*stats.nattacks*stats.chance_to_hit_defender;
if(best_attack == -1 || attack_rating > best_attack_rating) {
best_attack = n;
best_attack_rating = attack_rating;
}
}
return best_attack;
}
void get_villages() {
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
if(get_info().map.is_village(i->first) && current_team().owns_village(i->first) == false) {
move_unit(i->second,i->first,possible_moves);
get_villages();
return;
}
}
}
void do_moves() {
unit_map::const_iterator leader;
for(leader = get_info().units.begin(); leader != get_info().units.end(); ++leader) {
if(leader->second.can_recruit() && current_team().is_enemy(leader->second.side())) {
break;
}
}
if(leader == get_info().units.end())
return;
std::map<location,paths> possible_moves;
move_map srcdst, dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false);
int closest_distance = -1;
std::pair<location,location> closest_move;
for(move_map::const_iterator i = dstsrc.begin(); i != dstsrc.end(); ++i) {
const int distance = distance_between(i->first,leader->first);
if(closest_distance == -1 || distance < closest_distance) {
closest_distance = distance;
closest_move = *i;
}
}
if(closest_distance != -1) {
move_unit(closest_move.second,closest_move.first,possible_moves);
do_moves();
}
}
void do_recruitment() {
const std::set<std::string>& options = current_team().recruits();
const int choice = (rand()%options.size());
std::set<std::string>::const_iterator i = options.begin();
std::advance(i,choice);
const bool res = recruit(*i);
if(res) {
do_recruitment();
}
}
};
class ai : public ai_interface {
public:

144
src/ai_interface.hpp Normal file
View file

@ -0,0 +1,144 @@
/* $Id$ */
/*
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef AI_INTERFACE_HPP_INCLUDED
#define AI_INTERFACE_HPP_INCLUDED
#include "display.hpp"
#include "map.hpp"
#include "unit.hpp"
class ai_interface {
public:
///a convenient typedef for the often used 'location' object
typedef gamemap::location location;
///the standard way in which a map of possible moves is recorded
typedef std::multimap<location,location> move_map;
///info: a structure which holds references to all the important objects
///that an AI might need access to in order to make and implement its decisions
struct info {
info(display& disp, const gamemap& map, const game_data& gameinfo, unit_map& units,
std::vector<team>& teams, int team_num, const gamestatus& state, class turn_info& turn_data)
: disp(disp), map(map), gameinfo(gameinfo), units(units), teams(teams),
team_num(team_num), state(state), turn_data_(turn_data)
{}
///the display object, used to draw the moves the AI makes.
display& disp;
///the map of the game -- use this object to find the terrain at any location
const gamemap& map;
///this object contains information about the types of units and races in the game
const game_data& gameinfo;
///the map of units - maps locations -> units
unit_map& units;
///a list of the teams in the game
std::vector<team>& teams;
///the number of the team the AI is. Note that this number is 1-based, so it
///has to have 1 subtracted from it for it to be used as an index of 'teams'
int team_num;
///information about what turn it is, and what time of day
const gamestatus& state;
///the object that allows the player to interact with the game.
///should not be used outside of ai_interface
class turn_info& turn_data_;
};
///the constructor. All derived classes should take an argument of type info& which
///they should pass to this constructor
ai_interface(info& arg) : info_(arg), last_interact_(0) {}
virtual ~ai_interface() {}
///the function that is called when the AI must play its turn. Derived classes should
///implement their AI algorithm in this function
virtual void play_turn() = 0;
///functions which return a reference to the 'team' object for the AI
team& current_team();
const team& current_team() const;
///function to update network players as to what the AI has done so far this turn
void sync_network();
///function to show a diagnostic message on the screen
void diagnostic(const std::string& msg);
///function to display a debug message as a chat message is displayed
void log_message(const std::string& msg);
protected:
///this function should be called to attack an enemy.
///'attacking_unit': the location of the attacking unit
///'target': the location of the target unit. This unit must be in range of the
///attacking unit's weapon
///'weapon': the number of the weapon (0-based) which should be used in the attack.
///must be a valid weapon of the attacking unit
void attack_enemy(const location& attacking_unit, const location& target, int weapon);
///this function should be called to move a unit. Once the unit has been moved, its
///movement allowance is set to 0.
///'from': the location of the unit being moved.
///'to': the location to be moved to. This must be a valid move for the unit
///'possible_moves': the map of possible moves, as obtained from 'calculate_possible_moves'
location move_unit(location from, location to, std::map<location,paths>& possible_moves);
///this function is used to calculate the moves units may possibly make.
///'possible_moves': a map which will be filled with the paths each unit can take to
///get to every possible destination. You probably don't want to use this object at all,
///except to pass to 'move_unit'.
///'srcdst': a map of units to all their possible destinations
///'dstsrc': a map of destinations to all the units that can move to that destination
///'enemy': if true, a map of possible moves for enemies will be calculated. If false,
///a map of possible moves for units on the AI's side will be calculated. The AI's own
///leader will not be included in this map.
///'assume_full_movement': if true, the function will operate on the assumption that all
///units can move their full movement allotment.
///'remove_destinations': a pointer to a set of possible destinations to omit
void calculate_possible_moves(std::map<location,paths>& possible_moves, move_map& srcdst, move_map& dstsrc, bool enemy, bool assume_full_movement=false,
const std::set<location>* remove_destinations=NULL);
///this function is used to recruit a unit. It will recruit the unit with the given name,
///at the given location, or at an available location to recruit units if 'loc' is not
///a valid recruiting location.
///
///if recruitment cannot be performed, because there are no available tiles, or not enough
///money, then the function will return false
bool recruit(const std::string& unit_name, location loc=location());
///functions to retrieve the 'info' object. Used by derived classes to discover all
///necessary game information
info& get_info() { return info_; }
const info& get_info() const { return info_; }
///function which should be called frequently to allow the user to interact with
///the interface. This function will make sure that interaction doesn't occur
///too often, so there is no problem with calling it very regularly
void user_interact();
private:
info info_;
int last_interact_;
};
///this function is used to create a new AI object with the specified algorithm name
ai_interface* create_ai(const std::string& algorithm_name, ai_interface::info& info);
#endif

View file

@ -20,7 +20,7 @@
#include "about.hpp"
#include "actions.hpp"
#include "ai.hpp"
#include "ai_interface.hpp"
#include "config.hpp"
#include "cursor.hpp"
#include "dialogs.hpp"

View file

@ -14,7 +14,7 @@
#define PLAY_LEVEL_HPP_INCLUDED
#include "actions.hpp"
#include "ai.hpp"
#include "ai_interface.hpp"
#include "config.hpp"
#include "dialogs.hpp"
#include "display.hpp"

View file

@ -14,7 +14,7 @@
#define PLAYTURN_HPP_INCLUDED
#include "actions.hpp"
#include "ai.hpp"
#include "ai_interface.hpp"
#include "config.hpp"
#include "dialogs.hpp"
#include "display.hpp"

View file

@ -11,9 +11,7 @@
See the COPYING file for more details.
*/
#include "actions.hpp"
#include "ai.hpp"
#include "ai_attack.hpp"
#include "ai_move.hpp"
#include "ai_interface.hpp"
#include "dialogs.hpp"
#include "game_config.hpp"
#include "log.hpp"