new AI: ai_composite

This commit is contained in:
Iurii Chernyi 2009-06-04 17:48:27 +00:00
parent cdfcaf800a
commit 59f781e290
38 changed files with 2655 additions and 129 deletions

View file

@ -1,6 +1,7 @@
Version 1.7.0+svn:
* AI:
* Reworked AI code to allow easier creation of AI components.
* New AI: Composite AI
* Campaigns
* Delfador's Memoirs: new portrait for Lionel.
* Graphics

View file

@ -0,0 +1,22 @@
#textdomain wesnoth
ai_algorithm=composite_ai
[ai]
ai_identifier=testing_ai_default
[stage]
engine=cpp
name=testing_ai_default::candidate_action_evaluation_loop
[candidate_action]
engine=cpp
name=testing_ai_default::goto_phase
[/candidate_action]
[candidate_action]
engine=cpp
name=testing_ai_default::recruitment_phase
[/candidate_action]
[/stage]
[stage]
engine=cpp
name=testing_ai_default::fallback
fallback=default
[/stage]
[/ai]

View file

@ -2737,10 +2737,66 @@
RelativePath="..\..\src\ai\game_info.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\registry.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing.cpp"
>
</File>
<Filter
Name="composite"
>
<File
RelativePath="..\..\src\ai\composite\ai.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\contexts.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\engine.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\engine_default.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\rca.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\stage.cpp"
>
</File>
</Filter>
<Filter
Name="default"
>
<File
RelativePath="..\..\src\ai\default\contexts.cpp"
>
</File>
</Filter>
<Filter
Name="testing"
>
<File
RelativePath="..\..\src\ai\testing\ca.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing\stage_rca.cpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing\stage_fallback.cpp"
>
</File>
</Filter>
</Filter>
</Filter>
<Filter
@ -3576,10 +3632,66 @@
RelativePath="..\..\src\ai\game_info.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\registry.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing.hpp"
>
</File>
<Filter
Name="composite"
>
<File
RelativePath="..\..\src\ai\composite\ai.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\contexts.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\engine.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\engine_default.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\rca.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\stage.hpp"
>
</File>
</Filter>
<Filter
Name="default"
>
<File
RelativePath="..\..\src\ai\default\contexts.hpp"
>
</File>
</Filter>
<Filter
Name="testing"
>
<File
RelativePath="..\..\src\ai\testing\ca.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing\stage_rca.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\testing\stage_fallback.hpp"
>
</File>
</Filter>
</Filter>
</Filter>
<Filter

View file

@ -226,10 +226,21 @@ SET(wesnoth-main_SRC
ai/ai_manager.cpp
ai/ai_move.cpp
ai/ai_village.cpp
ai/composite/ai.cpp
ai/composite/contexts.cpp
ai/composite/engine.cpp
ai/composite/engine_default.cpp
ai/composite/rca.cpp
ai/composite/stage.cpp
ai/contexts.cpp
ai/default/contexts.cpp
ai/formula_ai.cpp
ai/formula_candidates.cpp
ai/game_info.cpp
ai/registry.cpp
ai/testing/ca.cpp
ai/testing/stage_rca.cpp
ai/testing/stage_fallback.cpp
ai/testing.cpp
animated_game.cpp
attack_prediction.cpp

View file

@ -51,10 +51,21 @@ wesnoth_source = \
ai/ai_manager.cpp \
ai/ai_move.cpp \
ai/ai_village.cpp \
ai/composite/ai.cpp \
ai/composite/context.cpp \
ai/composite/engine.cpp \
ai/composite/engine_default.cpp \
ai/composite/rca.cpp \
ai/composite/stage.cpp \
ai/contexts.cpp \
ai/default/contexts.cpp \
ai/formula_ai.cpp \
ai/formula_candidates.cpp \
ai/game_info.cpp \
ai/registry.cpp \
ai/testing/ca.cpp \
ai/testing/stage_rca.cpp \
ai/testing/stage_fallback.cpp \
ai/testing.cpp \
animated_game.cpp \
attack_prediction.cpp \

View file

@ -156,10 +156,21 @@ wesnoth_sources = Split("""
ai/ai_manager.cpp
ai/ai_move.cpp
ai/ai_village.cpp
ai/composite/ai.cpp
ai/composite/contexts.cpp
ai/composite/engine.cpp
ai/composite/engine_default.cpp
ai/composite/rca.cpp
ai/composite/stage.cpp
ai/contexts.cpp
ai/default/contexts.cpp
ai/formula_ai.cpp
ai/formula_candidates.cpp
ai/game_info.cpp
ai/registry.cpp
ai/testing/ca.cpp
ai/testing/stage_rca.cpp
ai/testing/stage_fallback.cpp
ai/testing.cpp
animated_game.cpp
attack_prediction.cpp

4
src/ai/SConstruct Normal file
View file

@ -0,0 +1,4 @@
import sys
from subprocess import call
print "scons --directory=../.. " + " ".join(sys.argv[1:])
Exit(call(Split("scons --directory=../..") + sys.argv[1:]))

View file

@ -36,7 +36,6 @@
#include <fstream>
static lg::log_domain log_ai("ai/general");
#define DBG_AI LOG_STREAM(debug, log_ai)
#define LOG_AI LOG_STREAM(info, log_ai)
@ -46,8 +45,9 @@ static lg::log_domain log_ai("ai/general");
typedef util::array<map_location,6> adjacent_tiles_array;
idle_ai::idle_ai(ai::readwrite_context &context) : ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count())
idle_ai::idle_ai(ai::readwrite_context &context) : recursion_counter_(context.get_recursion_count())
{
init_readwrite_context_proxy(context);
}
std::string idle_ai::describe_self()
@ -76,7 +76,9 @@ void idle_ai::play_turn()
class sample_ai : public ai::readwrite_context_proxy, public ai_interface {
public:
sample_ai(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count()) {}
: recursion_counter_(context.get_recursion_count()) {
init_readwrite_context_proxy(context);
}
virtual void play_turn() {
game_events::fire("ai turn");
@ -217,20 +219,17 @@ private:
ai::recursion_counter recursion_counter_;
};
ai_default::ai_default(ai::readwrite_context &context) :
ai::side_context_proxy(context),
ai::readonly_context_proxy(context),
ai::readwrite_context_proxy(context),
ai_default::ai_default(ai::default_ai_context &context) :
game_logic::formula_callable(),
recursion_counter_(context.get_recursion_count()),
defensive_position_cache_(),
threats_found_(false),
attacks_(),
disp_(get_info().disp),
map_(get_info().map),
units_(get_info().units),
teams_(get_info().teams),
state_(get_info().state),
disp_(context.get_info().disp),
map_(context.get_info().map),
units_(context.get_info().units),
teams_(context.get_info().teams),
state_(context.get_info().state),
consider_combat_(true),
additional_targets_(),
unit_movement_scores_(),
@ -241,9 +240,10 @@ ai_default::ai_default(ai::readwrite_context &context) :
unit_stats_cache_(),
attack_depth_(0),
recruiting_preferred_(0),
formula_ai_(NULL)
formula_ai_()
{
add_ref();
init_default_ai_context_proxy(context);
}
ai_default::~ai_default(){

View file

@ -22,6 +22,7 @@
#include "../actions.hpp"
#include "ai_interface.hpp"
#include "contexts.hpp"
#include "default/contexts.hpp"
#include "../formula_callable.hpp"
class formula_ai;
@ -38,12 +39,12 @@ private:
ai::recursion_counter recursion_counter_;
};
class ai_default : public virtual ai::readwrite_context_proxy, public ai_interface, public game_logic::formula_callable {
class ai_default : public virtual ai::default_ai_context_proxy, public ai_interface, public game_logic::formula_callable {
public:
typedef ai::move_map move_map;
typedef map_location location;//will get rid of this later
ai_default(ai::readwrite_context &context);
ai_default(ai::default_ai_context &context);
virtual ~ai_default();
virtual void play_turn();

View file

@ -23,23 +23,29 @@
#include "ai_interface.hpp"
#include "contexts.hpp"
class ai2 : public ai::readwrite_context_proxy, public ai_interface {
namespace ai {
class ai2 : public readwrite_context_proxy, public ai_interface {
public:
ai2(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context),recursion_counter_(context.get_recursion_count())
{}
ai2(readwrite_context &context)
: recursion_counter_(context.get_recursion_count())
{
init_readwrite_context_proxy(context);
}
virtual ~ai2() {}
virtual void play_turn() {}
virtual void switch_side(ai::side_number side){
virtual void switch_side(side_number side){
set_side(side);
}
int get_recursion_count() const{
return recursion_counter_.get_count();
}
private:
ai::recursion_counter recursion_counter_;
recursion_counter recursion_counter_;
};
} //of namespace ai
#endif

View file

@ -102,7 +102,10 @@ namespace dfool {
class dfool_ai : public ai::readwrite_context_proxy, public ai_interface {
public:
dfool_ai(ai::readwrite_context &context)
: ai::side_context_proxy(context), ai::readonly_context_proxy(context), ai::readwrite_context_proxy(context), recursion_counter_(context.get_recursion_count()), unit_memory_(current_team().ai_memory()){}
: recursion_counter_(context.get_recursion_count()), unit_memory_(current_team().ai_memory())
{
init_readwrite_context_proxy(context);
}
void play_turn();
virtual std::string describe_self();
virtual int get_recursion_count() const{

View file

@ -23,7 +23,9 @@
#include "ai_manager.hpp"
#include "ai_dfool.hpp"
#include "contexts.hpp"
#include "composite/ai.hpp"
#include "formula_ai.hpp"
#include "registry.hpp"
#include "../game_events.hpp"
#include "../game_preferences.hpp"
#include "../log.hpp"
@ -35,6 +37,9 @@
#include <stack>
#include <vector>
using namespace ai;
const std::string ai_manager::AI_TYPE_COMPOSITE_AI = "composite_ai";
const std::string ai_manager::AI_TYPE_SAMPLE_AI = "sample_ai";
const std::string ai_manager::AI_TYPE_IDLE_AI = "idle_ai";
const std::string ai_manager::AI_TYPE_FORMULA_AI = "formula_ai";
@ -49,7 +54,7 @@ static lg::log_domain log_ai_manager("ai/manager");
#define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
ai_holder::ai_holder( int side, const std::string& ai_algorithm_type )
: ai_(NULL), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
: 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)
{
DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder" << std::endl;
}
@ -59,15 +64,18 @@ void ai_holder::init( int side )
{
LOG_AI_MANAGER << describe_ai() << "Preparing to create new managed master AI" << std::endl;
if (side_context_ == NULL) {
side_context_ = new ai::side_context_impl(side);
side_context_ = new side_context_impl(side);
} else {
side_context_->set_side(side);
}
if (readonly_context_ == NULL){
readonly_context_ = new ai::readonly_context_impl(*side_context_);
readonly_context_ = new readonly_context_impl(*side_context_);
}
if (readwrite_context_ == NULL){
readwrite_context_ = new ai::readwrite_context_impl(*readonly_context_);
readwrite_context_ = new readwrite_context_impl(*readonly_context_);
}
if (default_ai_context_ == NULL){
default_ai_context_ = new default_ai_context_impl(*readwrite_context_);
}
this->ai_ = create_ai(side);
if (this->ai_ == NULL) {
@ -83,6 +91,7 @@ ai_holder::~ai_holder()
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_;
delete this->side_context_;
@ -196,9 +205,9 @@ bool ai_holder::is_mandate_ok()
ai_interface* ai_holder::create_ai( int side )
{
assert (side > 0);
assert (readwrite_context_!=NULL);
assert (default_ai_context_!=NULL);
//@note: ai_params, contexts, and ai_algorithm_type are supposed to be set before calling init( );
return ai_manager::create_transient_ai(ai_algorithm_type_,readwrite_context_);
return ai_manager::create_transient_ai(ai_algorithm_type_,default_ai_context_);
}
@ -281,6 +290,7 @@ void ai_manager::set_ai_info(const ai_game_info& i)
clear_ai_info();
}
ai_info_ = new ai_game_info(i);
ai_registry::init();
}
@ -539,9 +549,9 @@ bool ai_manager::add_ai_for_side( int side, const std::string& ai_algorithm_type
}
ai_interface* ai_manager::create_transient_ai( const std::string &ai_algorithm_type, ai::readwrite_context *rw_context )
ai_interface* ai_manager::create_transient_ai( const std::string &ai_algorithm_type, default_ai_context *ai_context )
{
assert(rw_context!=NULL);
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.
@ -551,7 +561,7 @@ ai_interface* ai_manager::create_transient_ai( const std::string &ai_algorithm_t
//: 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;
// ai_interface *a = new my_ai(*rw_context);
// ai_interface *a = new my_ai(*ai_context);
// a->on_create();
// return a;
// }
@ -559,45 +569,54 @@ ai_interface* ai_manager::create_transient_ai( const std::string &ai_algorithm_t
//if(ai_algorithm_type == ai_manager::AI_TYPE_SAMPLE_AI) {
// LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
// ai_interface *a = new sample_ai(*rw_context);
// ai_interface *a = new sample_ai(*ai_context);
// a->on_create();
// return a;
//}
if(ai_algorithm_type == ai_manager::AI_TYPE_IDLE_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_IDLE_AI << "]"<< std::endl;
ai_interface *a = new idle_ai(*rw_context);
ai_interface *a = new idle_ai(*ai_context);
a->on_create();
return a;
}
if(ai_algorithm_type == ai_manager::AI_TYPE_FORMULA_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_FORMULA_AI << "]"<< std::endl;
ai_interface *a = new formula_ai(*rw_context);
ai_interface *a = new formula_ai(*ai_context);
a->on_create();
return a;
}
if(ai_algorithm_type == ai_manager::AI_TYPE_DFOOL_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_DFOOL_AI << "]"<< std::endl;
ai_interface *a = new dfool::dfool_ai(*rw_context);
ai_interface *a = new dfool::dfool_ai(*ai_context);
a->on_create();
return a;
}
if(ai_algorithm_type == ai_manager::AI_TYPE_AI2) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_AI2 << "]"<< std::endl;
ai_interface *a = new ai2(*rw_context);
ai_interface *a = new ai2(*ai_context);
a->on_create();
return a;
}
if(ai_algorithm_type == ai_manager::AI_TYPE_COMPOSITE_AI) {
LOG_AI_MANAGER << "Creating new AI of type [" << ai_manager::AI_TYPE_COMPOSITE_AI << "]"<< std::endl;
ai_interface *a = new composite_ai::ai_composite(*ai_context);
a->on_create();
return a;
}
if (!ai_algorithm_type.empty() && ai_algorithm_type != ai_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 [" << ai_manager::AI_TYPE_DEFAULT << "]"<< std::endl;
ai_interface *a = new ai_default(*rw_context);
ai_interface *a = new ai_default(*ai_context);
a->on_create();
return a;
}

View file

@ -25,8 +25,9 @@
#include "../global.hpp"
#include "contexts.hpp"
#include "game_info.hpp"
#include "default/contexts.hpp"
#include <map>
#include <stack>
#include <vector>
@ -78,6 +79,7 @@ private:
ai::side_context *side_context_;
ai::readonly_context *readonly_context_;
ai::readwrite_context *readwrite_context_;
ai::default_ai_context *default_ai_context_;
std::string ai_algorithm_type_;
config ai_effective_parameters_;
config ai_global_parameters_;
@ -130,6 +132,7 @@ public:
static const int AI_TEAM_FALLBACK_AI = -1;
static const std::string AI_TYPE_COMPOSITE_AI;
static const std::string AI_TYPE_SAMPLE_AI;
static const std::string AI_TYPE_IDLE_AI;
static const std::string AI_TYPE_FORMULA_AI;
@ -269,7 +272,7 @@ public:
* @param context context in which this ai is created
* @return the reference to the created AI
*/
static ai_interface* create_transient_ai( const std::string& ai_algorithm_type, ai::readwrite_context *rw_context);
static ai_interface* create_transient_ai( const std::string& ai_algorithm_type, ai::default_ai_context *ai_context);
/**

127
src/ai/composite/ai.cpp Normal file
View file

@ -0,0 +1,127 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Composite AI with turn sequence which is a vector of stages
* @file ai/composite/ai.cpp
*/
#include "ai.hpp"
#include "stage.hpp"
#include "../ai_manager.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite("ai/composite");
#define DBG_AI_COMPOSITE LOG_STREAM(debug, log_ai_composite)
#define LOG_AI_COMPOSITE LOG_STREAM(info, log_ai_composite)
#define ERR_AI_COMPOSITE LOG_STREAM(err, log_ai_composite)
// =======================================================================
// COMPOSITE AI
// =======================================================================
std::string ai_composite::describe_self(){
return "[composite_ai]";
}
ai_composite::ai_composite( default_ai_context &context)
: recursion_counter_(context.get_recursion_count())
{
init_default_ai_context_proxy(context);
}
void ai_composite::on_create()
{
const config& ai_global_parameters = ai_manager::get_active_ai_global_parameters_for_side(get_side());
LOG_AI_COMPOSITE << "side "<< get_side() << " : "<<" created AI with ai_identifier=["<<
ai_global_parameters["ai_identifier"]<<"]"<<std::endl;
//init the composite ai engines
foreach(const config &cfg_element, ai_global_parameters.child_range("engine")){
engine::parse_engine_from_config(*this,cfg_element,std::back_inserter(engines_));
}
// init the composite ai stages
foreach(const config &cfg_element, ai_global_parameters.child_range("stage")){
engine::parse_stage_from_config(*this,cfg_element,std::back_inserter(stages_));
}
}
ai_composite::~ai_composite()
{
}
void ai_composite::play_turn(){
foreach(stage_ptr &s, stages_){
s->play_stage();
}
}
engine_ptr ai_composite::get_engine(const config& cfg)
{
const std::string& engine_name = cfg["engine"];
std::vector<engine_ptr>::iterator en = engines_.begin();
while (en!=engines_.end() && ((*en)->get_name()!=engine_name)) {
en++;
}
if (en != engines_.end()){
return *en;
}
engine_factory::factory_map::iterator eng = engine_factory::get_list().find(engine_name);
if (eng == engine_factory::get_list().end()){
ERR_AI_COMPOSITE << "side "<<get_side()<<" : UNABLE TO FIND engine["<<
engine_name <<"]" << std::endl;
DBG_AI_COMPOSITE << "config snippet contains: " << std::endl << cfg << std::endl;
return engine_ptr();
}
engine_ptr new_engine = eng->second->get_new_instance(*this,engine_name);
if (!new_engine) {
ERR_AI_COMPOSITE << "side "<<get_side()<<" : UNABLE TO CREATE engine["<<
engine_name <<"] " << std::endl;
DBG_AI_COMPOSITE << "config snippet contains: " << std::endl << cfg << std::endl;
return engine_ptr();
}
engines_.push_back(new_engine);
return engines_.back();
}
int ai_composite::get_recursion_count() const
{
return recursion_counter_.get_count();
}
void ai_composite::switch_side(side_number side)
{
set_side(side);
}
composite_ai_context& ai_composite::get_composite_ai_context()
{
return *this;
}
} //end of namespace composite_ai
} //end of namespace ai

106
src/ai/composite/ai.hpp Normal file
View file

@ -0,0 +1,106 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/composite/ai.hpp
* Composite AI with turn sequence which is a vector of stages
*/
#ifndef AI_COMPOSITE_AI_HPP_INCLUDED
#define AI_COMPOSITE_AI_HPP_INCLUDED
#include "../../global.hpp"
#include "contexts.hpp"
#include "engine.hpp"
#include "stage.hpp"
#include "../contexts.hpp"
#include "../default/contexts.hpp"
#include "../ai_interface.hpp"
#include <vector>
//============================================================================
namespace ai {
namespace composite_ai {
class ai_composite : public composite_ai_context, public virtual default_ai_context_proxy, public ai_interface {
public:
/**
* Constructor
*/
ai_composite( default_ai_context &context );
/**
* Destructor
*/
virtual ~ai_composite();
/**
* Play the turn
*/
void play_turn();
/**
* get engine by cfg, creating it if it is not created yet but known
*/
virtual engine_ptr get_engine(const config& cfg);
std::string describe_self();
int get_recursion_count() const;
void switch_side(side_number side);
void on_create();
/**
* unwrap
*/
virtual composite_ai_context& get_composite_ai_context();
protected:
/**
* Stages of the composite AI
*/
std::vector< stage_ptr > stages_;
/**
* Engines of the composite AI
*/
std::vector< engine_ptr > engines_;
/**
* Recursion counter
*/
recursion_counter recursion_counter_;
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -0,0 +1,72 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Helper functions for the object which operates in the context of AI for specific side
* This is part of AI interface
* @file ai/composite/contexts.cpp
*/
#include "contexts.hpp"
// =======================================================================
namespace ai {
namespace composite_ai {
composite_ai_context::composite_ai_context()
{
}
composite_ai_context::~composite_ai_context()
{
}
composite_ai_context_proxy::composite_ai_context_proxy()
: target_()
{
}
composite_ai_context_proxy::~composite_ai_context_proxy()
{
}
rca_context::rca_context()
{
}
rca_context::~rca_context()
{
}
rca_context_proxy::rca_context_proxy()
: target_()
{
}
rca_context_proxy::~rca_context_proxy()
{
}
} //end of namespace composite_ai
} //end of namespace ai

View file

@ -0,0 +1,185 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/composite/contexts.hpp
* Composite AI contexts
*/
#ifndef AI_COMPOSITE_CONTEXTS_HPP_INCLUDED
#define AI_COMPOSITE_CONTEXTS_HPP_INCLUDED
#include "../../global.hpp"
#include "../contexts.hpp"
#include "../default/contexts.hpp"
#include <boost/shared_ptr.hpp>
#include <vector>
//============================================================================
namespace ai {
namespace composite_ai {
class engine;
class stage;
class composite_ai_context;
typedef boost::shared_ptr< engine > engine_ptr;
typedef boost::shared_ptr< stage > stage_ptr;
class composite_ai_context : public virtual default_ai_context{
public:
/**
* Constructor
*/
composite_ai_context();
/**
* Destructor
*/
virtual ~composite_ai_context();
/**
* Unwrap
*/
virtual composite_ai_context& get_composite_ai_context() = 0;
/**
* get engine by cfg, creating it if it is not created yet but known
*/
virtual engine_ptr get_engine(const config& cfg) = 0;
};
class rca_context;
class rca_context : public virtual composite_ai_context {
public:
/**
* Constructor
*/
rca_context();
/**
* Destructor
*/
virtual ~rca_context();
/**
* Unwrap
*/
virtual rca_context& get_rca_context() = 0;
};
class candidate_action_context;
class candidate_action_context : public virtual rca_context {
public:
/**
* Constructor
*/
candidate_action_context() {}
/**
* Destructor
*/
virtual ~candidate_action_context() {}
/**
* Unwrap
*/
virtual candidate_action_context& get_candidate_action_context() = 0;
};
// proxies
class composite_ai_context_proxy : public virtual composite_ai_context, public virtual default_ai_context_proxy {
public:
composite_ai_context_proxy();
void init_composite_ai_context_proxy(composite_ai_context &target)
{
init_default_ai_context_proxy(target);
target_ = &target;
}
virtual ~composite_ai_context_proxy();
composite_ai_context& get_composite_ai_context()
{
return target_->get_composite_ai_context();
}
engine_ptr get_engine(const config& cfg)
{
return target_->get_engine(cfg);
}
private:
composite_ai_context *target_;
};
class rca_context_proxy : public virtual rca_context, public virtual composite_ai_context_proxy {
public:
rca_context_proxy();
virtual ~rca_context_proxy();
void init_rca_context_proxy(rca_context &target)
{
init_composite_ai_context_proxy(target);
target_ = &target;
}
rca_context& get_rca_context()
{
return target_->get_rca_context();
}
private:
rca_context *target_;
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -0,0 +1,90 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* AI Support engine - creating specific ai components from config
* @file ai/composite/engine.cpp
*/
#include "ai.hpp"
#include "engine.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite_engine("ai/composite/engine");
#define DBG_AI_COMPOSITE_ENGINE LOG_STREAM(debug, log_ai_composite_engine)
#define LOG_AI_COMPOSITE_ENGINE LOG_STREAM(info, log_ai_composite_engine)
#define ERR_AI_COMPOSITE_ENGINE LOG_STREAM(err, log_ai_composite_engine)
engine::engine( composite_ai_context &context, const config &cfg )
: ai_(context)
{
LOG_AI_COMPOSITE_ENGINE << "side "<< ai_.get_side() << " : "<<" created engine with name=["<<cfg["name"]<<"]"<<std::endl;
}
engine::~engine()
{
}
void engine::parse_candidate_action_from_config( rca_context& context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
if (eng){
//do not override that method in subclasses which cannot create candidate actions
eng->do_parse_candidate_action_from_config(context,cfg, b);
}
}
void engine::parse_engine_from_config( composite_ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< engine_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
if (eng){
//do not override that method in subclasses which cannot create engines
eng->do_parse_engine_from_config(cfg, b);
}
}
void engine::parse_stage_from_config( composite_ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
if (eng){
//do not override that method in subclasses which cannot create stages
eng->do_parse_stage_from_config(cfg, b);
}
}
void engine::do_parse_candidate_action_from_config( rca_context &/*context*/, const config &/*cfg*/, std::back_insert_iterator<std::vector< candidate_action_ptr > > /*b*/ ){
}
void engine::do_parse_engine_from_config( const config &/*cfg*/, std::back_insert_iterator<std::vector< engine_ptr > > /*b*/ ){
}
void engine::do_parse_stage_from_config( const config &/*cfg*/, std::back_insert_iterator<std::vector< stage_ptr > > /*b*/ )
{
}
std::string engine::get_name(){
return "null";
}
} //end of namespace composite_ai
} //end of namespace ai

123
src/ai/composite/engine.hpp Normal file
View file

@ -0,0 +1,123 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* AI Support engine - creating specific ai components from config
* @file ai/composite/engine.hpp
*/
#ifndef AI_COMPOSITE_ENGINE_HPP_INCLUDED
#define AI_COMPOSITE_ENGINE_HPP_INCLUDED
#include "../../global.hpp"
#include "contexts.hpp"
#include "rca.hpp"
#include "stage.hpp"
#include "../../config.hpp"
#include <algorithm>
#include <iterator>
#include <vector>
//============================================================================
namespace ai {
namespace composite_ai {
class ai_composite;
class engine {
public:
engine( composite_ai_context &context, const config &cfg );
virtual ~engine();
static void parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b );
static void parse_engine_from_config( composite_ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< engine_ptr > > b );
static void parse_stage_from_config( composite_ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
//do not override that method in subclasses which cannot create candidate_actions
virtual void do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b );
//do not override that method in subclasses which cannot create engines
virtual void do_parse_engine_from_config( const config &cfg, std::back_insert_iterator<std::vector< engine_ptr > > b );
//do not override that method in subclasses which cannot create stages
virtual void do_parse_stage_from_config( const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
virtual std::string get_name();
protected:
composite_ai_context &ai_;
};
class engine_factory;
class engine_factory{
public:
typedef boost::shared_ptr< engine_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 *engine_factories;
if (engine_factories==NULL) {
engine_factories = new factory_map;
}
return *engine_factories;
}
virtual engine_ptr get_new_instance( composite_ai_context &ai, const config &cfg ) = 0;
virtual engine_ptr get_new_instance( composite_ai_context &ai, const std::string& name ) = 0;
engine_factory( const std::string &name )
{
factory_ptr ptr_to_this(this);
get_list().insert(make_pair(name,ptr_to_this));
}
};
template<class ENGINE>
class register_engine_factory : public engine_factory {
public:
register_engine_factory( const std::string &name )
: engine_factory( name )
{
}
virtual engine_ptr get_new_instance( composite_ai_context &ai, const config &cfg ){
return engine_ptr(new ENGINE(ai,cfg));
}
virtual engine_ptr get_new_instance( composite_ai_context &ai, const std::string& name ){
config cfg;
cfg["name"] = name;
return engine_ptr(new ENGINE(ai,cfg));
}
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -0,0 +1,87 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* CPP AI Support engine - creating specific ai components from config
* @file ai/composite/engine_default.cpp
*/
#include "ai.hpp"
#include "engine_default.hpp"
#include "rca.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite_engine_cpp("ai/composite/engine/cpp");
#define DBG_AI_COMPOSITE_ENGINE_CPP LOG_STREAM(debug, log_ai_composite_engine_cpp)
#define LOG_AI_COMPOSITE_ENGINE_CPP LOG_STREAM(info, log_ai_composite_engine_cpp)
#define ERR_AI_COMPOSITE_ENGINE_CPP LOG_STREAM(err, log_ai_composite_engine_cpp)
engine_cpp::engine_cpp( composite_ai_context &context, const config &cfg )
: engine(context,cfg)
{
}
engine_cpp::~engine_cpp()
{
}
void engine_cpp::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b ){
candidate_action_factory::factory_map::iterator f = candidate_action_factory::get_list().find(cfg["name"]);
if (f == candidate_action_factory::get_list().end()){
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNKNOWN candidate_action["<<cfg["name"]<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
candidate_action_ptr new_candidate_action = f->second->get_new_instance(context,cfg);
if (!new_candidate_action) {
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNABLE TO CREATE candidate_action["<<cfg["name"]<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
*b = new_candidate_action;
}
void engine_cpp::do_parse_stage_from_config( const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
{
stage_factory::factory_map::iterator f = stage_factory::get_list().find(cfg["name"]);
if (f == stage_factory::get_list().end()){
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNKNOWN stage["<<cfg["name"]<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
stage_ptr new_stage = f->second->get_new_instance(ai_,cfg);
if (!new_stage) {
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNABLE TO CREATE stage["<<cfg["name"]<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
*b = new_stage;
}
std::string engine_cpp::get_name()
{
return "cpp";
}
} //end of namespace composite_ai
} //end of namespace ai

View file

@ -0,0 +1,52 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* CPP AI Support engine - creating specific ai components from config
* @file ai/composite/engine_default.hpp
*/
#ifndef AI_COMPOSITE_ENGINE_DEFAULT_HPP_INCLUDED
#define AI_COMPOSITE_ENGINE_DEFAULT_HPP_INCLUDED
#include "../../global.hpp"
#include "engine.hpp"
#include "../contexts.hpp"
#include <algorithm>
//============================================================================
namespace ai {
namespace composite_ai {
class engine_cpp : public engine {
public:
engine_cpp( composite_ai_context &context, const config &cfg );
virtual ~engine_cpp();
virtual void do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b );
virtual void do_parse_stage_from_config( const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
virtual std::string get_name();
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

138
src/ai/composite/rca.cpp Normal file
View file

@ -0,0 +1,138 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Candidate actions framework
* @file ai/composite/rca.cpp
*/
#include "ai.hpp"
#include "engine.hpp"
#include "rca.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite_rca("ai/composite/rca");
#define DBG_AI_COMPOSITE_RCA LOG_STREAM(debug, log_ai_composite_rca)
#define LOG_AI_COMPOSITE_RCA LOG_STREAM(info, log_ai_composite_rca)
#define ERR_AI_COMPOSITE_RCA LOG_STREAM(err, log_ai_composite_rca)
candidate_action::candidate_action(rca_context &context, const std::string &name, const std::string &type)
: recursion_counter_(context.get_recursion_count()), enabled_(true), score_(BAD_SCORE),name_(name),type_(type)
{
init_rca_context_proxy(context);
//LOG_AI_COMPOSITE_RCA << "side "<< get_side() << " : "<<" created "<<*this<<std::endl;
}
candidate_action::~candidate_action()
{
}
bool candidate_action::is_enabled() const
{
return enabled_;
}
void candidate_action::enable()
{
enabled_ = true;
}
int candidate_action::get_recursion_count() const
{
return recursion_counter_.get_count();
}
void candidate_action::disable()
{
enabled_ = false;
}
double candidate_action::get_score() const
{
return score_;
}
const std::string& candidate_action::get_name() const
{
return name_;
}
const std::string& candidate_action::get_type() const
{
return type_;
}
candidate_action_evaluation_exception::candidate_action_evaluation_exception(const std::string &message)
: message_(message)
{
}
candidate_action_execution_exception::candidate_action_execution_exception(const std::string &message)
: message_(message)
{
}
candidate_action_evaluation_exception::~candidate_action_evaluation_exception()
{
}
candidate_action_execution_exception::~candidate_action_execution_exception()
{
}
const std::string& candidate_action_evaluation_exception::get_message() const
{
return message_;
}
const std::string& candidate_action_execution_exception::get_message() const
{
return message_;
}
//============================================================================
} //end of namespace composite_ai
} // of namespace ai
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_evaluation_exception const &caee) {
s << "candidate action evaluation exception :"<< caee.get_message();
return s;
}
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_execution_exception const &caee) {
s << "candidate action execution exception :"<< caee.get_message();
return s;
}
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action const &ca) {
s << "candidate action with name ["<< ca.get_name() <<"]";
return s;
}

193
src/ai/composite/rca.hpp Normal file
View file

@ -0,0 +1,193 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/composite/rca.hpp
* candidate action framework
*/
#ifndef AI_COMPOSITE_RCA_HPP_INCLUDED
#define AI_COMPOSITE_RCA_HPP_INCLUDED
#include "../../global.hpp"
#include "../../config.hpp"
#include "contexts.hpp"
#include "../contexts.hpp"
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
//============================================================================
namespace ai {
namespace composite_ai {
class candidate_action : public virtual rca_context_proxy {
public:
//this is a score guaranteed to be <=0, thus candidate action with this score will not be selected for execution
static const double BAD_SCORE = 0;
/**
* Constructor
* @param ai context of the candidate action
* @param name name of the action (for debug purposes)
* @param type type of the action (for debug purposes)
*/
candidate_action( rca_context &context, const std::string &name, const std::string &type );
/**
* Destructor
*/
virtual ~candidate_action();
/**
* Evaluate the candidate action, resetting the internal state of the action
* @return the score
* @retval >0 if the action is good
* @retval <0 if the action is not good
*/
virtual double evaluate() = 0;
/**
* Execute the candidate action
*/
virtual bool execute() = 0;
/**
* Is this candidate action enabled ?
*/
bool is_enabled() const;
/**
* Disable the candidate action
*/
void enable();
/**
* Enable the candidate action
*/
void disable();
/**
* Get the last score of the candidate action without re-evaluation
*/
double get_score() const;
/**
* Get the name of the candidate action (useful for debug purposes)
*/
const std::string& get_name() const;
/**
* Get the type of the candidate action (useful for debug purposes)
*/
const std::string& get_type() const;
int get_recursion_count() const;
private:
recursion_counter recursion_counter_;
bool enabled_;
double score_;
std::string name_;
std::string type_;
};
class candidate_action_evaluation_exception{
public:
candidate_action_evaluation_exception(const std::string& message);
~candidate_action_evaluation_exception();
// get the message associated with this exception
const std::string& get_message() const;
private:
std::string message_;
};
class candidate_action_execution_exception{
public:
candidate_action_execution_exception(const std::string& message);
~candidate_action_execution_exception();
// get the message associated with this exception
const std::string& get_message() const;
private:
std::string message_;
};
typedef boost::shared_ptr<candidate_action> candidate_action_ptr;
class candidate_action_factory;
class candidate_action_factory{
public:
typedef boost::shared_ptr< candidate_action_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 *candidate_action_factories;
if (candidate_action_factories==NULL) {
candidate_action_factories = new factory_map;
}
return *candidate_action_factories;
}
virtual candidate_action_ptr get_new_instance( rca_context &context, const config &cfg ) = 0;
candidate_action_factory( const std::string &name )
{
factory_ptr ptr_to_this(this);
get_list().insert(make_pair(name,ptr_to_this));
}
};
template<class CANDIDATE_ACTION>
class register_candidate_action_factory : public candidate_action_factory {
public:
register_candidate_action_factory( const std::string &name )
: candidate_action_factory( name )
{
}
virtual candidate_action_ptr get_new_instance( rca_context &ai, const config &cfg ){
return candidate_action_ptr(new CANDIDATE_ACTION(ai,cfg));
}
};
//============================================================================
} //end of namespace composite_ai
} //end of namespace ai
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action const &ca);
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_evaluation_exception const &caee);
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_execution_exception const &caee);
#endif

View file

@ -0,0 +1,86 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Stage of a composite AI
* @file ai/composite/stage.cpp
*/
#include "ai.hpp"
#include "stage.hpp"
#include "../contexts.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
#include <map>
#include <string>
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite_stage("ai/composite/stage");
#define DBG_AI_COMPOSITE_STAGE LOG_STREAM(debug, log_ai_composite_stage)
#define LOG_AI_COMPOSITE_STAGE LOG_STREAM(info, log_ai_composite_stage)
#define ERR_AI_COMPOSITE_STAGE LOG_STREAM(err, log_ai_composite_stage)
// =======================================================================
// COMPOSITE AI STAGE
// =======================================================================
stage::stage( composite_ai_context &context, const config &cfg )
: recursion_counter_(context.get_recursion_count()), cfg_(cfg)
{
init_composite_ai_context_proxy(context);
}
void stage::on_create()
{
LOG_AI_COMPOSITE_STAGE << "side "<< get_side() << " : "<<" created stage with name=["<<cfg_["name"]<<"]"<<std::endl;
}
stage::~stage()
{
}
void stage::play_stage()
{
do_play_stage();
}
int stage::get_recursion_count() const
{
return recursion_counter_.get_count();
}
// =======================================================================
// COMPOSITE AI IDLE STAGE
// =======================================================================
idle_stage::idle_stage( composite_ai_context &context, const config &cfg )
: stage(context,cfg)
{
}
idle_stage::~idle_stage()
{
}
void idle_stage::do_play_stage(){
LOG_AI_COMPOSITE_STAGE << "Turn " << get_info().state.turn() << ": playing idle stage for side: "<< get_side() << std::endl;
}
} //end of namespace composite_ai
} //end of namespace ai

137
src/ai/composite/stage.hpp Normal file
View file

@ -0,0 +1,137 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/composite/stage.hpp
* Composite AI stages
*/
#ifndef AI_COMPOSITE_STAGE_HPP_INCLUDED
#define AI_COMPOSITE_STAGE_HPP_INCLUDED
#include "../../global.hpp"
#include "contexts.hpp"
#include "../contexts.hpp"
#include "../../config.hpp"
#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
namespace ai {
namespace composite_ai {
class ai_composite;
class stage : public virtual composite_ai_context_proxy {
public:
/**
* Constructor
*/
stage( composite_ai_context &context, const config &cfg );
/**
* Initialization
*/
virtual void on_create();
/**
* Destructor
*/
virtual ~stage();
/**
* Play the turn - strategy
*/
void play_stage();
/**
* get the value of the recursion counter
*/
int get_recursion_count() const;
protected:
/**
* Play the turn - implementation
*/
virtual void do_play_stage() = 0;
recursion_counter recursion_counter_;
const config &cfg_;
};
class idle_stage : public stage {
idle_stage( composite_ai_context &context, const config &cfg );
~idle_stage();
virtual void do_play_stage();
};
class stage_factory;
class stage_factory{
public:
typedef boost::shared_ptr< stage_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 *stage_factories;
if (stage_factories==NULL) {
stage_factories = new factory_map;
}
return *stage_factories;
}
virtual stage_ptr get_new_instance( composite_ai_context &context, const config &cfg ) = 0;
stage_factory( const std::string &name )
{
factory_ptr ptr_to_this(this);
get_list().insert(make_pair(name,ptr_to_this));
}
};
template<class STAGE>
class register_stage_factory : public stage_factory {
public:
register_stage_factory( const std::string &name )
: stage_factory( name )
{
}
virtual stage_ptr get_new_instance( composite_ai_context &context, const config &cfg ){
stage_ptr a(new STAGE(context,cfg));
a->on_create();
return a;
}
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -31,11 +31,6 @@ class gamemap;
#include "../pathfind.hpp"
#include "../playturn.hpp"
class ai_attack_result;
class ai_move_result;
class ai_recruit_result;
class ai_stopunit_result;
namespace ai {
// recursion counter
@ -49,12 +44,30 @@ public:
}
}
int get_count() const{
/**
* Get the current value of the recursion counter
*/
int get_count() const
{
return counter_;
}
static const int MAX_COUNTER_VALUE = 100;//max recursion depth
//max recursion depth
static const int MAX_COUNTER_VALUE = 100;
/**
* Check if more recursion is allowed
*/
bool is_ok() const
{
return counter_ < MAX_COUNTER_VALUE;
}
private:
// recursion counter value
int counter_;
};
@ -64,13 +77,42 @@ class side_context;
class side_context{
public:
/**
* Get the side number
*/
virtual side_number get_side() const = 0;
/**
* Set the side number
*/
virtual void set_side(side_number side) = 0;
/**
* empty destructor
*/
virtual ~side_context(){}
/**
* empty constructor
*/
side_context() {}
/**
* unwrap
*/
virtual side_context& get_side_context() = 0;
/**
* Get the value of the recursion counter
*/
virtual int get_recursion_count() const = 0;
};
class readonly_context;
@ -121,180 +163,253 @@ public:
virtual ai_game_info& get_info_w() = 0;
};
class ai_default_context;
class ai_default_context : public virtual readwrite_context {
public:
ai_default_context(){}
virtual ~ai_default_context(){}
virtual ai_default_context& get_ai_default_context() = 0;
};
//proxies
class side_context_proxy : public virtual side_context {
public:
side_context_proxy(side_context& target)
:target_(target.get_side_context())
side_context_proxy()
: target_(NULL)
{
}
virtual ~side_context_proxy(){}
void init_side_context_proxy(side_context &target)
{
target_= &target.get_side_context();
}
virtual side_number get_side() const
{
return target_.get_side();
return target_->get_side();
}
virtual void set_side(side_number side)
{
return target_.set_side(side);
return target_->set_side(side);
}
virtual side_context& get_side_context()
{
return target_.get_side_context();
return target_->get_side_context();
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
return target_->get_recursion_count();
}
private:
side_context& target_;
side_context *target_;
};
class readonly_context_proxy : public virtual readonly_context, public virtual side_context_proxy {
public:
readonly_context_proxy(readonly_context &target)
: side_context_proxy(target.get_side_context()), target_(target.get_readonly_context())
readonly_context_proxy()
: target_(NULL)
{
}
virtual ~readonly_context_proxy() {}
void init_readonly_context_proxy(readonly_context &target)
{
init_side_context_proxy(target);
target_ = &target.get_readonly_context();
}
virtual readonly_context& get_readonly_context()
{
return target_.get_readonly_context();
return target_->get_readonly_context();
}
virtual const team& current_team() const{
return target_.current_team();
virtual const team& current_team() const
{
return target_->current_team();
}
virtual void diagnostic(const std::string& msg){
target_.diagnostic(msg);
virtual void diagnostic(const std::string& msg)
{
target_->diagnostic(msg);
}
virtual void log_message(const std::string& msg){
target_.log_message(msg);
virtual void log_message(const std::string& msg)
{
target_->log_message(msg);
}
virtual ai_attack_result_ptr check_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon) {
return target_.check_attack_action(attacker_loc, defender_loc, attacker_weapon);
virtual ai_attack_result_ptr check_attack_action(const map_location &attacker_loc, const map_location &defender_loc, int attacker_weapon)
{
return target_->check_attack_action(attacker_loc, defender_loc, attacker_weapon);
}
virtual ai_move_result_ptr check_move_action(const map_location &from, const map_location &to, bool remove_movement=true){
return target_.check_move_action(from, to, remove_movement);
virtual ai_move_result_ptr check_move_action(const map_location &from, const map_location &to, bool remove_movement=true)
{
return target_->check_move_action(from, to, remove_movement);
}
virtual ai_recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where = map_location::null_location){
return target_.check_recruit_action(unit_name, where);
virtual ai_recruit_result_ptr check_recruit_action(const std::string &unit_name, const map_location &where = map_location::null_location)
{
return target_->check_recruit_action(unit_name, where);
}
virtual ai_stopunit_result_ptr check_stopunit_action(const map_location &unit_location, bool remove_movement = true, bool remove_attacks = false){
return target_.check_stopunit_action(unit_location, remove_movement, remove_attacks);
virtual ai_stopunit_result_ptr check_stopunit_action(const map_location &unit_location, bool remove_movement = true, bool remove_attacks = false)
{
return target_->check_stopunit_action(unit_location, remove_movement, remove_attacks);
}
virtual void calculate_possible_moves(std::map<map_location,paths>& possible_moves,
move_map& srcdst, move_map& dstsrc, bool enemy,
bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL) const{
target_.calculate_possible_moves(possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations);
const std::set<map_location>* remove_destinations=NULL) const
{
target_->calculate_possible_moves(possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations);
}
virtual void calculate_moves(const unit_map& units,
std::map<map_location,paths>& possible_moves, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement=false,
const std::set<map_location>* remove_destinations=NULL,
bool see_all=false) const{
target_.calculate_moves(units, possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations, see_all);
bool see_all=false) const
{
target_->calculate_moves(units, possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations, see_all);
}
const virtual ai_game_info& get_info() const{
return target_.get_info();
const virtual ai_game_info& get_info() const
{
return target_->get_info();
}
virtual void raise_user_interact() const{
target_.raise_user_interact();
virtual void raise_user_interact() const
{
target_->raise_user_interact();
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
virtual int get_recursion_count() const
{
return target_->get_recursion_count();
}
private:
readonly_context& target_;
readonly_context *target_;
};
class readwrite_context_proxy : public virtual readwrite_context, public virtual readonly_context_proxy {
public:
readwrite_context_proxy(readwrite_context &target)
: side_context_proxy(target.get_side_context()), readonly_context_proxy(target.get_readonly_context()),target_(target.get_readwrite_context())
readwrite_context_proxy()
: target_(NULL)
{
}
void init_readwrite_context_proxy(readwrite_context &target)
{
init_readonly_context_proxy(target);
target_ = &target.get_readwrite_context();
}
virtual readwrite_context& get_readwrite_context()
{
return target_.get_readwrite_context();
return target_->get_readwrite_context();
}
virtual ai_attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return target_.execute_attack_action(attacker_loc,defender_loc,attacker_weapon);
virtual ai_attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon)
{
return target_->execute_attack_action(attacker_loc,defender_loc,attacker_weapon);
}
virtual ai_move_result_ptr execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true)
{
return target_.execute_move_action(from, to, remove_movement);
}
virtual ai_recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location){
return target_.execute_recruit_action(unit_name,where);
}
virtual ai_stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false){
return target_.execute_stopunit_action(unit_location,remove_movement,remove_attacks);
return target_->execute_move_action(from, to, remove_movement);
}
virtual team& current_team_w(){
return target_.current_team_w();
virtual ai_recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location)
{
return target_->execute_recruit_action(unit_name,where);
}
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon){
target_.attack_enemy(u, target, att_weapon, def_weapon);
virtual ai_stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false)
{
return target_->execute_stopunit_action(unit_location,remove_movement,remove_attacks);
}
virtual map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves){
return target_.move_unit(from, to, possible_moves);
virtual team& current_team_w()
{
return target_->current_team_w();
}
virtual map_location move_unit_partial(map_location from, map_location to, std::map<map_location,paths>& possible_moves){
return target_.move_unit_partial(from, to, possible_moves);
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon)
{
target_->attack_enemy(u, target, att_weapon, def_weapon);
}
virtual bool recruit(const std::string& unit_name, map_location loc=map_location()){
return target_.recruit(unit_name, loc);
}
virtual void raise_unit_recruited() const{
target_.raise_unit_recruited();
virtual map_location move_unit(map_location from, map_location to, std::map<map_location,paths>& possible_moves)
{
return target_->move_unit(from, to, possible_moves);
}
virtual void raise_unit_moved() const{
target_.raise_unit_moved();
virtual map_location move_unit_partial(map_location from, map_location to, std::map<map_location,paths>& possible_moves)
{
return target_->move_unit_partial(from, to, possible_moves);
}
virtual void raise_enemy_attacked() const{
target_.raise_enemy_attacked();
}
virtual ai_game_info& get_info_w() {
return target_.get_info_w();
virtual bool recruit(const std::string& unit_name, map_location loc=map_location())
{
return target_->recruit(unit_name, loc);
}
virtual int get_recursion_count(){
return target_.get_recursion_count();
virtual void raise_unit_recruited() const
{
target_->raise_unit_recruited();
}
virtual void raise_unit_moved() const
{
target_->raise_unit_moved();
}
virtual void raise_enemy_attacked() const
{
target_->raise_enemy_attacked();
}
virtual ai_game_info& get_info_w()
{
return target_->get_info_w();
}
virtual int get_recursion_count()
{
return target_->get_recursion_count();
}
private:
readwrite_context& target_;
readwrite_context *target_;
};
@ -336,30 +451,41 @@ private:
//@todo: public game_logic::formula_callable
class readonly_context_impl : public virtual side_context_proxy, public readonly_context {
public:
/**
* The constructor.
* Constructor
*/
readonly_context_impl( side_context &context )
: side_context_proxy(context), recursion_counter_(context.get_recursion_count())
readonly_context_impl(side_context &context)
: recursion_counter_(context.get_recursion_count())
{
//add_ref(); //this class shouldn't be reference counted.
init_side_context_proxy(context);
}
/**
* Destructor
*/
virtual ~readonly_context_impl() {}
/**
* Unwrap - this class is not a proxy, so return *this
:w
*/
virtual readonly_context& get_readonly_context()
{
return *this;
}
/** Return a reference to the 'team' object for the AI. */
const team& current_team() const { return get_info().teams[get_side()-1]; }
/** Show a diagnostic message on the screen. */
void diagnostic(const std::string& msg);
/** Display a debug message as a chat message. */
void log_message(const std::string& msg);
@ -473,7 +599,7 @@ private:
};
class readwrite_context_impl : public virtual side_context_proxy, public virtual readonly_context_proxy, public readwrite_context {
class readwrite_context_impl : public virtual readonly_context_proxy, public readwrite_context {
public:
/**
* Unwrap - this class is not a proxy, so return *this
@ -539,6 +665,7 @@ public:
/** Return a reference to the 'team' object for the AI. */
virtual team& current_team_w() { return get_info_w().teams[get_side()-1]; }
/**
* This function should be called to attack an enemy.
*
@ -555,6 +682,7 @@ public:
*/
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon);
/**
* This function should be called to move a unit.
*
@ -592,13 +720,17 @@ public:
void raise_unit_moved() const;
void raise_enemy_attacked() const;
/**
* The constructor.
* Constructor.
*/
readwrite_context_impl(readonly_context &context)
: side_context_proxy(context), readonly_context_proxy(context), recursion_counter_(context.get_recursion_count())
: recursion_counter_(context.get_recursion_count())
{
init_readonly_context_proxy(context);
}
virtual ~readwrite_context_impl() {}
/**
@ -607,6 +739,7 @@ public:
*/
virtual ai_game_info& get_info_w();
virtual int get_recursion_count() const;
private:

View file

@ -0,0 +1,56 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Helper functions for the object which operates in the context of AI for specific side
* This is part of AI interface
* @file ai/default/contexts.cpp
*/
#include "contexts.hpp"
// =======================================================================
namespace ai {
default_ai_context::default_ai_context()
{
}
default_ai_context::~default_ai_context()
{
}
default_ai_context_proxy::~default_ai_context_proxy()
{
}
void default_ai_context_proxy::init_default_ai_context_proxy(default_ai_context &target)
{
init_readwrite_context_proxy(target);
target_= &target.get_default_ai_context();
}
default_ai_context& default_ai_context_impl::get_default_ai_context(){
return *this;
}
default_ai_context_impl::~default_ai_context_impl()
{
}
} //of namespace ai

View file

@ -0,0 +1,98 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/default/contexts.hpp
* Default AI contexts
*/
#ifndef AI_DEFAULT_CONTEXTS_HPP_INCLUDED
#define AI_DEFAULT_CONTEXTS_HPP_INCLUDED
#include "../../global.hpp"
#include "../contexts.hpp"
#include <vector>
//============================================================================
namespace ai {
class default_ai_context;
class default_ai_context : public virtual readwrite_context{
public:
default_ai_context();
virtual ~default_ai_context();
virtual default_ai_context& get_default_ai_context() = 0;
};
// proxies
class default_ai_context_proxy : public virtual default_ai_context, public virtual readwrite_context_proxy {
public:
default_ai_context_proxy()
: target_(NULL)
{
}
void init_default_ai_context_proxy(default_ai_context &target);
virtual ~default_ai_context_proxy();
virtual default_ai_context& get_default_ai_context()
{
return target_->get_default_ai_context();
}
private:
default_ai_context *target_;
};
class default_ai_context_impl : public virtual readwrite_context_proxy, public default_ai_context {
public:
default_ai_context_impl(readwrite_context &context)
: recursion_counter_(context.get_recursion_count())
{
init_readwrite_context_proxy(context);
}
virtual ~default_ai_context_impl();
virtual default_ai_context& get_default_ai_context();
int get_recursion_count() const
{
return recursion_counter_.get_count();
}
private:
recursion_counter recursion_counter_;
};
} //end of namespace ai
#endif

View file

@ -1600,10 +1600,7 @@ expression_ptr ai_function_symbol_table::create_function(const std::string &fn,
}
formula_ai::formula_ai(ai::readwrite_context &context) :
side_context_proxy(context),
readonly_context_proxy(context),
readwrite_context_proxy(context),
formula_ai::formula_ai(ai::default_ai_context &context) :
ai_default(context),
recursion_counter_(context.get_recursion_count()),
recruit_formula_(),

View file

@ -63,9 +63,9 @@ private:
}
class formula_ai : public ai_default, public virtual ai::readwrite_context_proxy {
class formula_ai : public ai_default {
public:
explicit formula_ai(ai::readwrite_context &context);
explicit formula_ai(ai::default_ai_context &context);
virtual ~formula_ai() {};
virtual void play_turn();
virtual void new_turn();

76
src/ai/registry.cpp Normal file
View file

@ -0,0 +1,76 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* All known AI parts. Workaround to a linker feature of not includning all symbols from files, and including only actually referenced stuff. this is not good for 'static registry' pattern. (other workarounds such as --whole-archive for ld are possible, but require messing with all buildsystems)
* @file ai/registry.cpp
*/
#include "ai.hpp"
#include "ai2.hpp"
#include "ai_dfool.hpp"
#include "composite/ai.hpp"
#include "composite/engine_default.hpp"
#include "formula_ai.hpp"
#include "registry.hpp"
#include "testing/ca.hpp"
#include "testing/stage_rca.hpp"
#include "testing/stage_fallback.hpp"
// =======================================================================
// 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");
*/
// =======================================================================
// Engines
// =======================================================================
static ai::composite_ai::register_engine_factory<ai::composite_ai::engine_cpp>
composite_ai_factory("cpp");
// =======================================================================
// Stages
// =======================================================================
static ai::composite_ai::register_stage_factory<testing_ai_default::candidate_action_evaluation_loop>
candidate_action_evaluation_loop_factory("testing_ai_default::candidate_action_evaluation_loop");
static ai::composite_ai::register_stage_factory<testing_ai_default::fallback_to_other_ai>
fallback_to_other_ai_factory("testing_ai_default::fallback");
// =======================================================================
// Candidate actions
// =======================================================================
static ai::composite_ai::register_candidate_action_factory<testing_ai_default::goto_phase>
goto_phase_factory("testing_ai_default::goto_phase");
static ai::composite_ai::register_candidate_action_factory<testing_ai_default::recruitment_phase>
recruitment_phase_factory("testing_ai_default::recruitment_phase");
void ai_registry::init()
{
}
ai_registry::ai_registry()
{
}

33
src/ai/registry.hpp Normal file
View file

@ -0,0 +1,33 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/registry.hpp
* All known AI parts
*/
#ifndef AI_REGISTRY_HPP_INCLUDED
#define AI_REGISTRY_HPP_INCLUDED
#include "../global.hpp"
class ai_registry{
public:
static void init();
private:
ai_registry();
};
#endif

77
src/ai/testing/ca.cpp Normal file
View file

@ -0,0 +1,77 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Default AI (Testing)
* @file ai/testing/ca.cpp
*/
#include "../../global.hpp"
#include "ca.hpp"
#include "../composite/engine.hpp"
#include "../composite/rca.hpp"
#include "../../log.hpp"
static lg::log_domain log_ai_testing_ai_default("ai/testing/ai_default");
#define DBG_AI_TESTING_AI_DEFAULT LOG_STREAM(debug, log_ai_testing_ai_default)
#define LOG_AI_TESTING_AI_DEFAULT LOG_STREAM(info, log_ai_testing_ai_default)
#define ERR_AI_TESTING_AI_DEFAULT LOG_STREAM(err, log_ai_testing_ai_default)
namespace testing_ai_default {
goto_phase::goto_phase( ai::composite_ai::rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::goto_phase",cfg["type"])
{
}
goto_phase::~goto_phase()
{
}
double goto_phase::evaluate()
{
ERR_AI_TESTING_AI_DEFAULT << get_name() << ": evaluate - not yet implemented" << std::endl;
return BAD_SCORE;
}
bool goto_phase::execute()
{
ERR_AI_TESTING_AI_DEFAULT << get_name() << ": execute - not yet implemented" << std::endl;
return true;
}
recruitment_phase::recruitment_phase( ai::composite_ai::rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::recruitment_phase",cfg["type"])
{
}
recruitment_phase::~recruitment_phase()
{
}
double recruitment_phase::evaluate()
{
ERR_AI_TESTING_AI_DEFAULT << get_name() << ": evaluate - not yet implemented!" << std::endl;
return BAD_SCORE;
}
bool recruitment_phase::execute()
{
ERR_AI_TESTING_AI_DEFAULT << get_name() << ": execute - not yet implemented!" << std::endl;
return true;
}
}

172
src/ai/testing/ca.hpp Normal file
View file

@ -0,0 +1,172 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Default AI (Testing)
* @file ai/testing/ca.hpp
*/
#ifndef AI_TESTING_CA_HPP_INCLUDED
#define AI_TESTING_CA_HPP_INCLUDED
#include "../../global.hpp"
#include "../composite/rca.hpp"
#include "../composite/engine_default.hpp"
namespace testing_ai_default {
//============================================================================
class goto_phase : public ai::composite_ai::candidate_action {
public:
goto_phase( ai::composite_ai::rca_context &context, const config &cfg );
virtual ~goto_phase();
virtual double evaluate();
virtual bool execute();
};
//============================================================================
class recruitment_phase : public ai::composite_ai::candidate_action {
public:
recruitment_phase( ai::composite_ai::rca_context &context, const config &cfg );
virtual ~recruitment_phase();
virtual double evaluate();
virtual bool execute();
};
/*
//============================================================================
class combat_phase : public ai_candidate_action {
public:
combat_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~combat_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& context);
};
//============================================================================
class move_leader_to_goals_phase : public ai_candidate_action {
public:
move_leader_to_goals_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~move_leader_to_goals_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
class get_villages_phase : public ai_candidate_action {
public:
get_villages_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~get_villages_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
class get_healing_phase : public ai_candidate_action {
public:
get_healing_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~get_healing_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
class retreat_phase : public ai_candidate_action {
public:
retreat_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~retreat_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
class move_and_targeting_phase : public ai_candidate_action {
public:
move_and_targeting_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~move_and_targeting_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
class leader_control_phase : public ai_candidate_action {
public:
leader_control_phase( ai_readonly_context& ai, const std::string& name, const std::string& type );
virtual ~leader_control_phase();
virtual double evaluate();
virtual bool execute(ai_readwrite_context& ai);
};
//============================================================================
*/
}
#endif

View file

@ -0,0 +1,61 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Stage: fallback to other AI
* @file ai/testing/rca_default.cpp
*/
#include "stage_fallback.hpp"
#include "../ai_manager.hpp"
#include "../composite/ai.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace testing_ai_default {
static lg::log_domain log_ai_testing_stage_fallback("ai/testing/stage_fallback");
#define DBG_AI_TESTING_STAGE_FALLBACK LOG_STREAM(debug, log_ai_testing_stage_fallback)
#define LOG_AI_TESTING_STAGE_FALLBACK LOG_STREAM(info, log_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)
{
}
void fallback_to_other_ai::on_create()
{
fallback_ai_ = ai_manager::create_transient_ai(cfg_["fallback"], this);
}
void fallback_to_other_ai::do_play_stage()
{
if (fallback_ai_) {
LOG_AI_TESTING_STAGE_FALLBACK << "side "<<get_side()<<" : falling back to "<<fallback_ai_->describe_self()<<std::endl;
fallback_ai_->play_turn();
} else {
ERR_AI_TESTING_STAGE_FALLBACK << "side "<<get_side()<<" : UNABLE TO FALLBACK, fallback ai is NULL"<<std::endl;
}
}
fallback_to_other_ai::~fallback_to_other_ai()
{
if (fallback_ai_!=NULL){
delete fallback_ai_;
}
}
} // of namespace testing_ai_default

View file

@ -0,0 +1,51 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Stage: fallback to other AI
* @file ai/testing/stage_fallback.hpp
*/
#ifndef AI_TESTING_STAGE_FALLBACK_HPP_INCLUDED
#define AI_TESTING_STAGE_FALLBACK_HPP_INCLUDED
#include "../../global.hpp"
#include "../composite/stage.hpp"
#include "../ai_interface.hpp"
#include "../../config.hpp"
#include <vector>
namespace testing_ai_default {
class fallback_to_other_ai: public ai::composite_ai::stage {
public:
fallback_to_other_ai( ai::composite_ai::composite_ai_context &context, const config &cfg );
~fallback_to_other_ai();
void do_play_stage();
void on_create();
private:
const config &cfg_;
ai_interface *fallback_ai_;
};
} // of namespace testing_ai_default
#endif

View file

@ -0,0 +1,116 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* Candidate actions evaluator
* @file ai/testing/stage_rca.cpp
*/
#include "stage_rca.hpp"
#include "../composite/ai.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
namespace testing_ai_default {
static lg::log_domain log_ai_testing_rca_default("ai/testing/rca_default");
#define DBG_AI_TESTING_RCA_DEFAULT LOG_STREAM(debug, log_ai_testing_rca_default)
#define LOG_AI_TESTING_RCA_DEFAULT LOG_STREAM(info, log_ai_testing_rca_default)
#define ERR_AI_TESTING_RCA_DEFAULT LOG_STREAM(err, log_ai_testing_rca_default)
candidate_action_evaluation_loop::candidate_action_evaluation_loop( ai::composite_ai::composite_ai_context &context, const config &cfg)
: stage(context,cfg),cfg_(cfg)
{
}
void candidate_action_evaluation_loop::on_create()
{
//init the candidate actions
foreach(const config &cfg_element, cfg_.child_range("candidate_action")){
ai::composite_ai::engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
}
}
void candidate_action_evaluation_loop::do_play_stage()
{
LOG_AI_TESTING_RCA_DEFAULT << "Starting candidate action evaluation loop for side "<< get_side() << std::endl;
const static double STOP_VALUE = 0;
foreach(ai::composite_ai::candidate_action_ptr ca, candidate_actions_){
ca->enable();
}
bool executed = false;
do {
executed = false;
double best_score = ai::composite_ai::candidate_action::BAD_SCORE;
ai::composite_ai::candidate_action_ptr best_ptr;
//Evaluation
foreach(ai::composite_ai::candidate_action_ptr ca_ptr, candidate_actions_){
if (!ca_ptr->is_enabled()){
continue;
}
double score = STOP_VALUE;
try {
DBG_AI_TESTING_RCA_DEFAULT << "Evaluating candidate action: "<< *ca_ptr << std::endl;
score = ca_ptr->evaluate();
DBG_AI_TESTING_RCA_DEFAULT << "Evaluated candidate action to score "<< score << " : " << *ca_ptr << std::endl;
} catch (ai::composite_ai::candidate_action_evaluation_exception &caee) {
ERR_AI_TESTING_RCA_DEFAULT << "Candidate action evaluation threw an exception: " << caee << std::endl;
ca_ptr->disable();
continue;
}
if (score>best_score) {
best_score = score;
best_ptr = ca_ptr;
}
}
//Execution
if (best_score>ai::composite_ai::candidate_action::BAD_SCORE) {
try {
DBG_AI_TESTING_RCA_DEFAULT << "Best candidate action: "<< *best_ptr << std::endl;
executed = best_ptr->execute();
} catch (ai::composite_ai::candidate_action_execution_exception &caee) {
ERR_AI_TESTING_RCA_DEFAULT << "Candidate action execution threw an exception: " << caee << std::endl;
executed = false;
}
if (!executed) {
//this means that this CA has lied to us in evaluate()
//we punish it by disabling it
best_ptr->disable();
//since we don't re-enable at this play_stage, if we disable this CA, other may get the change to go.
executed = true;
}
} else {
LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< ai::composite_ai::candidate_action::BAD_SCORE<<std::endl;
}
} while (executed);
LOG_AI_TESTING_RCA_DEFAULT << "Ended candidate action evaluation loop for side "<< get_side() << std::endl;
}
ai::composite_ai::rca_context& candidate_action_evaluation_loop::get_rca_context()
{
return *this;
}
candidate_action_evaluation_loop::~candidate_action_evaluation_loop()
{
}
} // of namespace testing_ai_default

View file

@ -0,0 +1,56 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file ai/testing/stage_rca.hpp
* candidate action evaluator
*/
#ifndef AI_TESTING_STAGE_RCA_HPP_INCLUDED
#define AI_TESTING_STAGE_RCA_HPP_INCLUDED
#include "../../global.hpp"
#include "../composite/contexts.hpp"
#include "../composite/rca.hpp"
#include "../composite/stage.hpp"
#include "../../config.hpp"
#include <boost/shared_ptr.hpp>
#include <vector>
namespace testing_ai_default {
class candidate_action_evaluation_loop: public virtual ai::composite_ai::stage, public virtual ai::composite_ai::rca_context {
public:
candidate_action_evaluation_loop( ai::composite_ai::composite_ai_context &context, const config &cfg );
~candidate_action_evaluation_loop();
void do_play_stage();
void on_create();
ai::composite_ai::rca_context& get_rca_context();
private:
std::vector<ai::composite_ai::candidate_action_ptr> candidate_actions_;
const config &cfg_;
};
} // of namespace testing_ai_default
#endif