AI refactoring: use a factory lookup pattern to create AIs
This commit is contained in:
parent
ee886864df
commit
2fd9dddd79
10 changed files with 97 additions and 105 deletions
|
@ -247,9 +247,6 @@ ai_default::ai_default(ai::default_ai_context &context) :
|
|||
}
|
||||
|
||||
ai_default::~ai_default(){
|
||||
if (formula_ai_!=NULL) {
|
||||
delete formula_ai_;
|
||||
}
|
||||
}
|
||||
|
||||
void ai_default::switch_side(ai::side_number side){
|
||||
|
@ -1482,11 +1479,12 @@ bool ai_default::do_recruitment()
|
|||
if (get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE)
|
||||
{
|
||||
if (!current_team().ai_parameters()["recruitment"].empty()){
|
||||
if (formula_ai_ == NULL){
|
||||
formula_ai_ = static_cast<formula_ai*>(ai::manager::create_transient_ai(ai::manager::AI_TYPE_FORMULA_AI, this));
|
||||
if (!formula_ai_){
|
||||
formula_ai_ptr_ = (ai::manager::create_transient_ai(ai::manager::AI_TYPE_FORMULA_AI, this));
|
||||
formula_ai_ = static_cast<formula_ai*> (formula_ai_ptr_.get());
|
||||
}
|
||||
|
||||
assert(formula_ai_ != NULL);
|
||||
assert(formula_ai_!=NULL);
|
||||
|
||||
if (formula_ai_->do_recruitment()) {
|
||||
LOG_AI << "Recruitment done by formula_ai\n";
|
||||
|
|
|
@ -96,6 +96,7 @@ public:
|
|||
int get_recursion_count() const;
|
||||
private:
|
||||
ai::recursion_counter recursion_counter_;
|
||||
|
||||
protected:
|
||||
|
||||
std::map<location,defensive_position> defensive_position_cache_;
|
||||
|
@ -409,7 +410,8 @@ private:
|
|||
int recruiting_preferred_;
|
||||
static const int min_recruiting_value_to_force_recruit = 28;
|
||||
protected:
|
||||
formula_ai* formula_ai_;
|
||||
formula_ai *formula_ai_;
|
||||
ai::ai_ptr formula_ai_ptr_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,9 +20,14 @@
|
|||
#ifndef AI_AI_INTERFACE_HPP_INCLUDED
|
||||
#define AI_AI_INTERFACE_HPP_INCLUDED
|
||||
|
||||
#include "../global.hpp"
|
||||
|
||||
#include "../formula_callable.hpp"
|
||||
|
||||
#include "game_info.hpp"
|
||||
|
||||
#include "default/contexts.hpp"
|
||||
|
||||
namespace ai {
|
||||
|
||||
class interface {
|
||||
|
@ -65,6 +70,50 @@ public:
|
|||
|
||||
};
|
||||
|
||||
class ai_factory;
|
||||
|
||||
class ai_factory{
|
||||
public:
|
||||
typedef boost::shared_ptr< ai_factory > factory_ptr;
|
||||
typedef std::map<std::string, factory_ptr> factory_map;
|
||||
typedef std::pair<const std::string, factory_ptr> factory_map_pair;
|
||||
|
||||
static factory_map& get_list() {
|
||||
static factory_map *ai_factories;
|
||||
if (ai_factories==NULL) {
|
||||
ai_factories = new factory_map;
|
||||
}
|
||||
return *ai_factories;
|
||||
}
|
||||
|
||||
/* cfg is commented out so far, because ai parameter handling is a mess atm */
|
||||
virtual ai_ptr get_new_instance( default_ai_context &context/*, const config &cfg*/) = 0;
|
||||
|
||||
ai_factory( const std::string &name )
|
||||
{
|
||||
factory_ptr ptr_to_this(this);
|
||||
get_list().insert(make_pair(name,ptr_to_this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class AI>
|
||||
class register_ai_factory : public ai_factory {
|
||||
public:
|
||||
register_ai_factory( const std::string &name )
|
||||
: ai_factory( name )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ai_ptr get_new_instance( default_ai_context &context/*, const config &cfg*/){
|
||||
ai_ptr a(new AI(context));
|
||||
a->on_create();
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} //end of namespace ai
|
||||
|
||||
#endif
|
||||
|
|
|
@ -54,7 +54,7 @@ static lg::log_domain log_ai_manager("ai/manager");
|
|||
#define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
|
||||
|
||||
holder::holder( int side, const std::string& ai_algorithm_type )
|
||||
: ai_(NULL), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), default_ai_context_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
|
||||
: ai_(), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), default_ai_context_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
|
||||
{
|
||||
DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder" << std::endl;
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ void holder::init( int side )
|
|||
default_ai_context_ = new default_ai_context_impl(*readwrite_context_);
|
||||
}
|
||||
this->ai_ = create_ai(side);
|
||||
if (this->ai_ == NULL) {
|
||||
if (!this->ai_) {
|
||||
ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!" << std::endl;
|
||||
}
|
||||
|
||||
|
@ -87,10 +87,9 @@ void holder::init( int side )
|
|||
|
||||
holder::~holder()
|
||||
{
|
||||
if (this->ai_ != NULL) {
|
||||
if (this->ai_) {
|
||||
LOG_AI_MANAGER << describe_ai() << "Managed AI will be deleted" << std::endl;
|
||||
}
|
||||
delete this->ai_;
|
||||
delete this->default_ai_context_;
|
||||
delete this->readwrite_context_;
|
||||
delete this->readonly_context_;
|
||||
|
@ -100,10 +99,10 @@ holder::~holder()
|
|||
|
||||
interface& holder::get_ai_ref( int side )
|
||||
{
|
||||
if (this->ai_ == NULL) {
|
||||
if (!this->ai_) {
|
||||
this->init(side);
|
||||
}
|
||||
assert(this->ai_ != NULL);
|
||||
assert(this->ai_);
|
||||
|
||||
return *this->ai_;
|
||||
}
|
||||
|
@ -202,7 +201,7 @@ bool holder::is_mandate_ok()
|
|||
return true;
|
||||
}
|
||||
|
||||
interface* holder::create_ai( int side )
|
||||
ai_ptr holder::create_ai( int side )
|
||||
{
|
||||
assert (side > 0);
|
||||
assert (default_ai_context_!=NULL);
|
||||
|
@ -549,76 +548,21 @@ bool manager::add_ai_for_side( int side, const std::string& ai_algorithm_type, b
|
|||
}
|
||||
|
||||
|
||||
interface* manager::create_transient_ai( const std::string &ai_algorithm_type, default_ai_context *ai_context )
|
||||
ai_ptr manager::create_transient_ai( const std::string &ai_algorithm_type, default_ai_context *ai_context )
|
||||
{
|
||||
assert(ai_context!=NULL);
|
||||
//@todo 1.7 modify this code to use a 'factory lookup' pattern -
|
||||
//a singleton which holds a map<string,ai_factory_ptr> of all functors which can create AIs.
|
||||
//this will allow individual AI implementations to 'register' themselves.
|
||||
|
||||
|
||||
|
||||
//: To add an AI of your own, put
|
||||
// if(ai_algorithm_type == "my_ai") {
|
||||
// LOG_AI_MANAGER << "Creating new AI of type [" << "my_ai" << "]"<< std::endl;
|
||||
// interface *a = new my_ai(*ai_context);
|
||||
// a->on_create();
|
||||
// return a;
|
||||
// }
|
||||
// at the top of this function
|
||||
|
||||
//if(ai_algorithm_type == manager::AI_TYPE_SAMPLE_AI) {
|
||||
// LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
|
||||
// interface *a = new sample_ai(*ai_context);
|
||||
// a->on_create();
|
||||
// return a;
|
||||
//}
|
||||
|
||||
if(ai_algorithm_type == manager::AI_TYPE_IDLE_AI) {
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
|
||||
interface *a = new idle_ai(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
//to add your own ai, register it in registry,cpp
|
||||
ai_factory::factory_map::iterator aii = ai_factory::get_list().find(ai_algorithm_type);
|
||||
if (aii == ai_factory::get_list().end()){
|
||||
aii = ai_factory::get_list().find("");
|
||||
if (aii == ai_factory::get_list().end()){
|
||||
throw game::game_error("no default ai set!");
|
||||
}
|
||||
}
|
||||
|
||||
if(ai_algorithm_type == manager::AI_TYPE_FORMULA_AI) {
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_FORMULA_AI << "]"<< std::endl;
|
||||
interface *a = new formula_ai(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
}
|
||||
|
||||
if(ai_algorithm_type == manager::AI_TYPE_DFOOL_AI) {
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_DFOOL_AI << "]"<< std::endl;
|
||||
interface *a = new dfool::dfool_ai(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
}
|
||||
|
||||
if(ai_algorithm_type == manager::AI_TYPE_AI2) {
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_AI2 << "]"<< std::endl;
|
||||
interface *a = new ai2(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
if(ai_algorithm_type == manager::AI_TYPE_COMPOSITE_AI) {
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_COMPOSITE_AI << "]"<< std::endl;
|
||||
interface *a = new composite_ai::ai_composite(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
if (!ai_algorithm_type.empty() && ai_algorithm_type != manager::AI_TYPE_DEFAULT) {
|
||||
ERR_AI_MANAGER << "AI not found: [" << ai_algorithm_type << "]. Using default instead.\n";
|
||||
}
|
||||
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << manager::AI_TYPE_DEFAULT << "]"<< std::endl;
|
||||
interface *a = new ai_default(*ai_context);
|
||||
a->on_create();
|
||||
return a;
|
||||
LOG_AI_MANAGER << "Creating new AI of type [" << ai_algorithm_type << "]"<< std::endl;
|
||||
ai_ptr new_ai = aii->second->get_new_instance(*ai_context);
|
||||
return new_ai;
|
||||
}
|
||||
|
||||
std::vector<std::string> manager::get_available_ais()
|
||||
|
|
|
@ -79,7 +79,7 @@ public:
|
|||
bool is_mandate_ok();
|
||||
|
||||
private:
|
||||
interface *ai_;
|
||||
ai_ptr ai_;
|
||||
side_context *side_context_;
|
||||
readonly_context *readonly_context_;
|
||||
readwrite_context *readwrite_context_;
|
||||
|
@ -91,7 +91,7 @@ private:
|
|||
std::vector<config> ai_parameters_;
|
||||
int side_;
|
||||
|
||||
interface* create_ai( int side );
|
||||
ai_ptr create_ai( int side );
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -270,13 +270,12 @@ public:
|
|||
|
||||
|
||||
/**
|
||||
* Returns a pointer to a new AI. It is the sole responsibility of the caller
|
||||
* to manage its lifetime.
|
||||
* Returns a smart pointer to a new AI.
|
||||
* @param ai_algorithm_type type of AI algorithm to create
|
||||
* @param context context in which this ai is created
|
||||
* @return the reference to the created AI
|
||||
*/
|
||||
static interface* create_transient_ai( const std::string& ai_algorithm_type, default_ai_context *ai_context);
|
||||
static ai_ptr create_transient_ai( const std::string& ai_algorithm_type, default_ai_context *ai_context);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -33,11 +33,15 @@ class gamemap;
|
|||
|
||||
namespace ai {
|
||||
|
||||
class interface;
|
||||
|
||||
typedef boost::shared_ptr< interface > ai_ptr;
|
||||
|
||||
// recursion counter
|
||||
class recursion_counter {
|
||||
public:
|
||||
recursion_counter(int counter)
|
||||
: counter_(counter++)
|
||||
: counter_(++counter)
|
||||
{
|
||||
if (counter > MAX_COUNTER_VALUE ) {
|
||||
throw game::game_error("maximum recursion depth reached!");
|
||||
|
|
|
@ -1857,8 +1857,8 @@ bool formula_ai::make_action(game_logic::const_formula_ptr formula_, const game_
|
|||
if(!formula_) {
|
||||
if(get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE) {
|
||||
LOG_AI << "Falling back to default AI.\n";
|
||||
util::scoped_ptr< ai::interface > fallback( ai::manager::create_transient_ai(ai::manager::AI_TYPE_DEFAULT, this));
|
||||
if (fallback != NULL){
|
||||
ai::ai_ptr fallback( ai::manager::create_transient_ai(ai::manager::AI_TYPE_DEFAULT, this));
|
||||
if (fallback){
|
||||
fallback->play_turn();
|
||||
}
|
||||
}
|
||||
|
@ -2182,8 +2182,8 @@ bool formula_ai::execute_variant(const variant& var, bool commandline)
|
|||
} else
|
||||
{
|
||||
LOG_AI << "Explicit fallback to: " << fallback_command->key() << std::endl;
|
||||
util::scoped_ptr< ai::interface > fallback ( ai::manager::create_transient_ai(fallback_command->key(), this));
|
||||
if(fallback != NULL) {
|
||||
ai::ai_ptr fallback( ai::manager::create_transient_ai(fallback_command->key(), this));
|
||||
if(fallback) {
|
||||
fallback->play_turn();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,14 +32,14 @@ namespace ai {
|
|||
// =======================================================================
|
||||
// AIs
|
||||
// =======================================================================
|
||||
/*
|
||||
static ai_factory<ai> ai_factory("");
|
||||
static ai_factory<ai> default_ai_ai_factory("default_ai");
|
||||
static ai_factory<ai2> ai2_ai_factory("ai2");
|
||||
static ai_factory<dfool_ai> dfool_ai_ai_factory("dfool_ai");
|
||||
static ai_factory<formula_ai> formula_ai_ai_factory("formula_ai");
|
||||
static ai_factory<composite_ai> composite_ai_ai_factory("composite_ai");
|
||||
*/
|
||||
|
||||
static register_ai_factory<ai_default> ai_factory_default("");
|
||||
static register_ai_factory<ai_default> ai_default_ai_factory("default_ai");
|
||||
static register_ai_factory<ai2> ai2_ai_factory("ai2");
|
||||
static register_ai_factory<dfool::dfool_ai> ai_dfool_ai_factory("dfool_ai");
|
||||
static register_ai_factory<formula_ai> ai_formula_ai_factory("formula_ai");
|
||||
static register_ai_factory<composite_ai::ai_composite> ai_composite_ai_factory("composite_ai");
|
||||
|
||||
|
||||
// =======================================================================
|
||||
// Engines
|
||||
|
|
|
@ -32,7 +32,7 @@ static lg::log_domain log_ai_testing_stage_fallback("ai/testing/stage_fallback")
|
|||
#define ERR_AI_TESTING_STAGE_FALLBACK LOG_STREAM(err, log_ai_testing_stage_fallback)
|
||||
|
||||
fallback_to_other_ai::fallback_to_other_ai( ai::composite_ai::composite_ai_context &context, const config &cfg )
|
||||
: stage(context,cfg), cfg_(cfg), fallback_ai_(NULL)
|
||||
: stage(context,cfg), cfg_(cfg), fallback_ai_()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -53,9 +53,6 @@ void fallback_to_other_ai::do_play_stage()
|
|||
|
||||
fallback_to_other_ai::~fallback_to_other_ai()
|
||||
{
|
||||
if (fallback_ai_!=NULL){
|
||||
delete fallback_ai_;
|
||||
}
|
||||
}
|
||||
|
||||
} // of namespace testing_ai_default
|
||||
|
|
|
@ -43,10 +43,9 @@ public:
|
|||
private:
|
||||
const config &cfg_;
|
||||
|
||||
ai::interface *fallback_ai_;
|
||||
ai::ai_ptr fallback_ai_;
|
||||
};
|
||||
|
||||
|
||||
} // of namespace testing_ai_default
|
||||
} // end of namespace testing_ai_default
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue