refactoring of ai component model to a more object-oriented approach.

[modify_ai] now works fully and uniformly, with less code
duplication. added the ability to see all ai components from
gamestate_inspector.
This commit is contained in:
Iurii Chernyi 2009-12-24 22:38:59 +00:00
parent 706395577b
commit 1462573062
29 changed files with 759 additions and 298 deletions

View file

@ -65,6 +65,7 @@
<Unit filename="..\..\src\ai\composite\engine_fai.hpp" />
<Unit filename="..\..\src\ai\composite\goal.cpp" />
<Unit filename="..\..\src\ai\composite\goal.hpp" />
<Unit filename="..\..\src\ai\composite\property_handler.hpp" />
<Unit filename="..\..\src\ai\composite\rca.cpp" />
<Unit filename="..\..\src\ai\composite\rca.hpp" />
<Unit filename="..\..\src\ai\composite\stage.cpp" />

View file

@ -94,6 +94,7 @@
<Unit filename="..\..\src\ai\composite\engine_fai.hpp" />
<Unit filename="..\..\src\ai\composite\goal.cpp" />
<Unit filename="..\..\src\ai\composite\goal.hpp" />
<Unit filename="..\..\src\ai\composite\property_handler.hpp" />
<Unit filename="..\..\src\ai\composite\rca.cpp" />
<Unit filename="..\..\src\ai\composite\rca.hpp" />
<Unit filename="..\..\src\ai\composite\stage.cpp" />

View file

@ -6194,6 +6194,10 @@
RelativePath="..\..\src\ai\composite\goal.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\property_handler.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\rca.hpp"
>

View file

@ -1,3 +1,4 @@
/* $Id$ */
/*
Copyright (C) 2009 by Yurii Chernyi <terraninfo@terraninfo.net>
@ -23,6 +24,9 @@
#include "../../foreach.hpp"
#include "../../log.hpp"
#include <boost/bind.hpp>
#include <boost/function.hpp>
namespace ai {
static lg::log_domain log_ai_composite("ai/composite");
@ -51,50 +55,76 @@ void ai_composite::on_create()
// init the composite ai stages
foreach(const config &cfg_element, cfg_.child_range("stage")){
add_stage(-1,cfg_element);
add_stage(cfg_element);
}
config cfg;
cfg["engine"] = "fai";
engine_ptr e_ptr = get_engine(cfg);
engine_ptr e_ptr = get_engine_by_cfg(cfg);
if (e_ptr) {
e_ptr->set_ai_context(this);
}
boost::function2<void, std::vector<engine_ptr>&, const config&> factory_engines =
boost::bind(&ai::ai_composite::create_engine,*this,_1,_2);
boost::function2<void, std::vector<goal_ptr>&, const config&> factory_goals =
boost::bind(&ai::ai_composite::create_goal,*this,_1,_2);
boost::function2<void, std::vector<stage_ptr>&, const config&> factory_stages =
boost::bind(&ai::ai_composite::create_stage,*this,_1,_2);
register_vector_property("engine",get_engines(), factory_engines);
register_vector_property("goal",get_goals(), factory_goals);
register_vector_property("stage",stages_, factory_stages);
register_aspect_property("aspect",get_aspects());
}
void ai_composite::create_stage(std::vector<stage_ptr> &stages, const config &cfg)
{
engine::parse_stage_from_config(*this,cfg,std::back_inserter(stages));
}
void ai_composite::create_goal(std::vector<goal_ptr> &goals, const config &cfg)
{
engine::parse_goal_from_config(*this,cfg,std::back_inserter(goals));
}
void ai_composite::create_engine(std::vector<engine_ptr> &engines, const config &cfg)
{
engine::parse_engine_from_config(*this,cfg,std::back_inserter(engines));
}
ai_composite::~ai_composite()
{
}
bool ai_composite::add_stage(int pos, const config &cfg)
bool ai_composite::add_stage(const config &cfg)
{
if (pos<0) {
pos = stages_.size();
}
std::vector< stage_ptr > stages;
engine::parse_stage_from_config(*this,cfg,std::back_inserter(stages));
create_stage(stages,cfg);
int j=0;
foreach (stage_ptr b, stages ){
stages_.insert(stages_.begin()+pos+j,b);
stages_.push_back(b);
j++;
}
return (j>0);
}
bool ai_composite::add_goal(int pos, const config &cfg)
bool ai_composite::add_goal(const config &cfg)
{
if (pos<0) {
pos = get_goals().size();
}
std::vector< goal_ptr > goals;
engine::parse_goal_from_config(*this,cfg,std::back_inserter(goals));
create_goal(goals,cfg);
int j=0;
foreach (goal_ptr b, goals ){
get_goals().insert(get_goals().begin()+pos+j,b);
get_goals().push_back(b);
j++;
}
return (j>0);
@ -108,11 +138,30 @@ void ai_composite::play_turn(){
}
const std::string& ai_composite::get_id() const
{
return cfg_["id"];
}
const std::string& ai_composite::get_name() const
{
return cfg_["name"];
}
const std::string& ai_composite::get_engine() const
{
return cfg_["engine"];
}
std::string ai_composite::evaluate(const std::string& str)
{
config cfg;
cfg["engine"] = "fai";//@todo 1.9 : consider allowing other engines to evaluate
engine_ptr e_ptr = get_engine(cfg);
engine_ptr e_ptr = get_engine_by_cfg(cfg);
if (!e_ptr) {
return interface::evaluate(str);
}
@ -159,118 +208,4 @@ config ai_composite::to_config() const
return cfg;
}
component* ai_composite::get_child(const path_element &child)
{
if (child.property=="aspect") {
//ASPECT
aspect_map::const_iterator a = get_aspects().find(child.id);
if (a!=get_aspects().end()){
return &*a->second;
}
return NULL;
} else if (child.property=="stage") {
//std::vector< stage_ptr >::iterator i = std::find_if(stages_.begin(),stages_.end(),path_element_matches< stage_ptr >(child));
//if (i!=stages_.end()){
// return &*(*i);
//}
return NULL;
} else if (child.property=="engine") {
//ENGINE
//@todo 1.7.5 implement
return NULL;
} else if (child.property=="goal") {
//std::vector< goal_ptr >::iterator i = std::find_if(get_goals().begin(),get_goals().end(),path_element_matches< goal_ptr >(child));
//if (i!=get_goals().end()){
// return &*(*i);
//}
return NULL;
}
//OOPS
return NULL;
}
bool ai_composite::add_child(const path_element &child, const config &cfg)
{
if (child.property=="aspect") {
//ASPECT
return false;//adding aspects directly is not supported - aspect['foo'].facet should be added instead
} else if (child.property=="stage") {
std::vector< stage_ptr >::iterator i = std::find_if(stages_.begin(),stages_.end(),path_element_matches< stage_ptr >(child));
return add_stage(i-stages_.begin(),cfg);
} else if (child.property=="engine") {
//ENGINE
//@todo 1.7.5 implement
return false;
} else if (child.property=="goal") {
std::vector< goal_ptr >::iterator i = std::find_if(get_goals().begin(),get_goals().end(),path_element_matches< goal_ptr >(child));
return add_goal(i-get_goals().begin(),cfg);
}
//OOPS
return false;
}
bool ai_composite::change_child(const path_element &child, const config &cfg)
{
if (child.property=="aspect") {
//ASPECT
return false;//changing aspects directly is not supported - aspect['foo'].facet should be changed instead
} else if (child.property=="stage") {
std::vector< stage_ptr >::iterator i = std::find_if(stages_.begin(),stages_.end(),path_element_matches< stage_ptr >(child));
if (i!=stages_.end()) {
//@todo 1.7.5 implement
//return (*i)->redeploy(cfg);
}
return false;
} else if (child.property=="engine") {
//ENGINE
//@todo 1.7.5 implement
return false;
} else if (child.property=="goal") {
std::vector< goal_ptr >::iterator i = std::find_if(get_goals().begin(),get_goals().end(),path_element_matches< goal_ptr >(child));
if (i!=get_goals().end()) {
return (*i)->redeploy(cfg);
}
}
//OOPS
return false;
}
bool ai_composite::delete_child(const path_element &child)
{
if (child.property=="aspect") {
//ASPECT
return false;//deleting aspects directly is not supported - aspect['foo'].facet should be deleted instead
} else if (child.property=="stage") {
std::vector< stage_ptr >::iterator i = std::find_if(stages_.begin(),stages_.end(),path_element_matches< stage_ptr >(child));
if (i!=stages_.end()) {
stages_.erase(i);
return true;
}
return false;
} else if (child.property=="engine") {
//ENGINE
//@todo 1.7.5 implement
return false;
} else if (child.property=="goal") {
std::vector< goal_ptr >::iterator i = std::find_if(get_goals().begin(),get_goals().end(),path_element_matches< goal_ptr >(child));
if (i!=get_goals().end()) {
get_goals().erase(i);
return true;
}
return false;
}
//OOPS
return false;
}
} //end of namespace ai

View file

@ -90,10 +90,19 @@ public:
void switch_side(side_number side);
virtual bool add_goal(int pos, const config &cfg);
virtual bool add_goal(const config &cfg);
virtual bool add_stage(int pos, const config &cfg);
virtual bool add_stage(const config &cfg);
void create_stage(std::vector<stage_ptr> &stages, const config &cfg);
void create_goal(std::vector<goal_ptr> &goals, const config &cfg);
void create_engine(std::vector<engine_ptr> &engines, const config &cfg);
void on_create();
@ -104,16 +113,13 @@ public:
virtual ai_context& get_ai_context();
virtual component* get_child(const path_element &child);
const std::string& get_id() const;
virtual bool add_child(const path_element &child, const config &cfg);
const std::string& get_name() const;
virtual bool change_child(const path_element &child, const config &cfg);
virtual bool delete_child(const path_element &child);
const std::string& get_engine() const;
protected:

View file

@ -76,6 +76,13 @@ const std::string& aspect::get_name() const
return name_;
}
const std::string& aspect::get_engine() const
{
return engine_;
}
bool aspect::redeploy(const config &cfg, const std::string& /*id*/)
{
if (invalidate_on_turn_start_) {
@ -135,6 +142,11 @@ config aspect::to_config() const
}
bool aspect::delete_all_facets()
{
return false;
}
known_aspect::known_aspect(const std::string &name)
: name_(name)
{

View file

@ -40,6 +40,7 @@
#include <deque>
#include <iterator>
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/pointer_cast.hpp>
@ -82,6 +83,9 @@ public:
virtual config to_config() const;
virtual bool delete_all_facets();
void handle_generic_event(const std::string &/*event_name*/)
{
invalidate();
@ -100,6 +104,9 @@ public:
const std::string& get_id() const;
const std::string& get_engine() const;
static lg::log_domain& log();
protected:
@ -242,7 +249,6 @@ public:
}
}
protected:
boost::shared_ptr<typesafe_aspect <T> > &where_;
aspect_map &aspects_;
@ -272,11 +278,29 @@ public:
default_ = b;
}
}
boost::function2<void, typename aspect_type<T>::typesafe_ptr_vector&, const config&> factory_facets =
boost::bind(&ai::composite_aspect<T>::create_facet,*this,_1,_2);
register_vector_property("facet",facets_, factory_facets);
}
void create_facet( typename aspect_type<T>::typesafe_ptr_vector &facets, const config &cfg)
{
std::vector<aspect_ptr> facets_base;
engine::parse_aspect_from_config(*this,cfg,this->get_id(),std::back_inserter(facets_base));
foreach (aspect_ptr a, facets_base ){
typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
facets.push_back(b);
}
}
virtual void recalculate() const
{
//@todo 1.7.5 optimize in case of an aspect which returns variant
//@todo 1.9 optimize in case of an aspect which returns variant
//typedef std::vector< boost::shared_ptr< typesafe_aspect < T > > >::reverse_const_iterator Iter;
foreach (const typename aspect_type<T>::typesafe_ptr &f, make_pair(facets_.rbegin(),facets_.rend())) {
@ -321,55 +345,11 @@ public:
}
virtual component* get_child(const path_element &child)
virtual bool delete_all_facets()
{
if (child.property!="facet") {
return NULL;
}
typename aspect_type<T>::typesafe_ptr_vector::iterator i = std::find_if(facets_.begin(),facets_.end(),path_element_matches< typename aspect_type<T>::typesafe_ptr >(child));
if (i!=facets_.end()){
return &*(*i);
}
return NULL;
}
virtual bool add_child(const path_element &child, const config &cfg)
{
if (child.property!="facet") {
return false;
}
typename aspect_type<T>::typesafe_ptr_vector::iterator i = std::find_if(facets_.begin(),facets_.end(),path_element_matches< typename aspect_type<T>::typesafe_ptr >(child));
LOG_STREAM(info, aspect::log()) << "adding a new child facet to composite aspect["<<this->get_id()<<"]"<< std::endl;
return add_facet(i-facets_.begin(),cfg);
}
virtual bool change_child(const path_element &child, const config &cfg)
{
if (child.property!="facet") {
return false;
}
typename aspect_type<T>::typesafe_ptr_vector::iterator i = std::find_if(facets_.begin(),facets_.end(),path_element_matches< typename aspect_type<T>::typesafe_ptr >(child));
if (i!=facets_.end()){
return (*i)->redeploy(cfg,this->get_id());
}
return false;
}
virtual bool delete_child(const path_element &child)
{
if (child.property!="facet") {
return false;
}
typename aspect_type<T>::typesafe_ptr_vector::iterator i = std::find_if(facets_.begin(),facets_.end(),path_element_matches< typename aspect_type<T>::typesafe_ptr >(child));
if (i!=facets_.end()) {
facets_.erase(i);
this->invalidate();//@todo: invalidate only if facet was active
return true;
}
return false;
bool b = !facets_.empty();
facets_.clear();
return b;
}
protected:

View file

@ -19,8 +19,10 @@
#include "component.hpp"
#include "engine.hpp"
#include "../formula/ai.hpp"
#include "../../log.hpp"
#include "../../foreach.hpp"
#include "../formula/ai.hpp"
#include <boost/lexical_cast.hpp>
#include <boost/regex.hpp>
@ -33,32 +35,6 @@ static lg::log_domain log_ai_composite_component("ai/composite/component");
#define ERR_AI_COMPOSITE LOG_STREAM(err, log_ai_composite_component)
component* component::get_child(const path_element &/*child*/)
{
return NULL;
}
bool component::add_child(const path_element &/*child*/, const config &/*cfg*/)
{
return false;
}
bool component::change_child(const path_element &/*child*/, const config &/*cfg*/)
{
return false;
}
bool component::delete_child(const path_element &/*child*/)
{
return false;
}
/*
[modify_ai]
path = "stage[fallback]
@ -85,6 +61,68 @@ bool component::delete_child(const path_element &/*child*/)
*/
component* component::get_child(const path_element &child)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_get(child);
}
return NULL;
}
bool component::add_child(const path_element &child, const config &cfg)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_add(child,cfg);
}
return false;
}
bool component::change_child(const path_element &child, const config &cfg)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_change(child,cfg);
}
return false;
}
bool component::delete_child(const path_element &child)
{
std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
if (i!=property_handlers_.end()) {
return i->second->handle_delete(child);
}
return false;
}
std::vector<component*> component::get_children(const std::string &type)
{
std::vector<component*> components;
property_handler_map::iterator i = property_handlers_.find(type);
if (i!=property_handlers_.end()) {
return i->second->handle_get_children();
}
return components;
}
std::vector<std::string> component::get_children_types()
{
std::vector<std::string> types;
foreach (property_handler_map::value_type &ph, property_handlers_) {
types.push_back(ph.first);
}
return types;
}
static component *find_component(component *root, const std::string &path, path_element &tail)
{
if (root==NULL) {
@ -115,7 +153,7 @@ static component *find_component(component *root, const std::string &path, path_
pe.position = -2;
}
}
DBG_AI_COMPOSITE << "adding path element: "<< pe << std::endl;
//DBG_AI_COMPOSITE << "adding path element: "<< pe << std::endl;
elements.push_back(pe);
}
if (elements.size()<1) {
@ -177,8 +215,47 @@ bool component_manager::delete_component(component *root, const std::string &pat
}
static void print_component(component *root, const std::string &type, std::stringstream &s, int offset)
{
std::stringstream offset_ss;
for (int i=0;i<offset;++i) {
offset_ss<<" ";
}
const std::string &offset_str = offset_ss.str();
const std::vector<std::string> &t_list = root->get_children_types();
s << offset_str << type<<"["<<root->get_id() <<"] "<<root->get_engine()<<" "<<root->get_name()<< std::endl;
foreach (std::string t, t_list) {
std::vector<component*> c_list = root->get_children(t);
foreach (component *c, c_list) {
print_component(c,t,s,offset+1);
}
}
}
std::string component_manager::print_component_tree(component *root, const std::string &path)
{
path_element tail;
component *c;
if (!path.empty()) {
c = find_component(root,path,tail);
if (c==NULL) {
ERR_AI_COMPOSITE << "unable to find component" <<std::endl;
return "";
}
} else {
c = root;
}
std::stringstream s;
print_component(c, "", s, 0);
return s.str();
}
} //end of namespace ai
std::ostream &operator<<(std::ostream &o, const ai::path_element &e)
{
o << "property["<<e.property<<"] id["<<e.id <<"] position["<<e.position<<"]"<<std::endl;

View file

@ -20,11 +20,14 @@
#ifndef AI_COMPOSITE_COMPONENT_HPP_INCLUDED
#define AI_COMPOSITE_COMPONENT_HPP_INCLUDED
#include "../../global.hpp"
#include "../game_info.hpp"
#include <vector>
#include <string>
#include <iostream>
#include <map>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include "property_handler.hpp"
#ifdef _MSC_VER
#pragma warning(push)
@ -35,29 +38,37 @@
//============================================================================
namespace ai {
struct path_element {
path_element()
: property()
, id()
, position(0)
{
}
std::string property;
std::string id;
int position;
};
class component {
public:
component() {};
virtual const std::string& get_id() const = 0;
virtual const std::string& get_name() const = 0;
virtual const std::string& get_engine() const = 0;
virtual ~component() {};
virtual component* get_child(const path_element &child);
virtual std::vector<component*> get_children(const std::string &type);
virtual std::vector<std::string> get_children_types();
virtual bool change_child(const path_element &child, const config &cfg);
virtual bool add_child(const path_element &child, const config &cfg);
virtual bool delete_child(const path_element &child);
template<typename X>
void register_vector_property(const std::string &property, std::vector< boost::shared_ptr<X> > &values_, boost::function2<void, std::vector< boost::shared_ptr<X> >&, const config&> construction_factory)
{
property_handlers_.insert(make_pair(property,property_handler_ptr(new vector_property_handler<X>(property,values_,construction_factory))));
}
template<typename X>
void register_aspect_property(const std::string &property, std::map< std::string, boost::shared_ptr<X> > &aspects_)
{
property_handlers_.insert(make_pair(property,property_handler_ptr(new aspect_property_handler<X>(property,aspects_))));
}
typedef std::map<std::string,property_handler_ptr> property_handler_map;
private:
property_handler_map property_handlers_;
};
class component_manager {
@ -65,40 +76,12 @@ public:
static bool add_component(component *root, const std::string &path, const config &cfg);
static bool change_component(component *root, const std::string &path, const config &cfg);
static bool delete_component(component *root, const std::string &path);
};
template<typename T>
class path_element_matches{
public:
path_element_matches(const path_element &element)
: count_(0), element_(element)
{
}
virtual ~path_element_matches(){}
bool operator()(const T& t)
{
if ( (!element_.id.empty()) && (element_.id == t->get_id()) ) {
return true;
}
if (count_ == element_.position) {
return true;
}
count_++;
return false;
}
private:
int count_;
path_element element_;
static std::string print_component_tree(component *root, const std::string &path);
};
} //end of namespace ai
std::ostream &operator<<(std::ostream &o, const ai::path_element &e);
#ifdef _MSC_VER

View file

@ -31,9 +31,9 @@ static lg::log_domain log_ai_composite_engine("ai/composite/engine");
#define ERR_AI_COMPOSITE_ENGINE LOG_STREAM(err, log_ai_composite_engine)
engine::engine( readonly_context &context, const config &cfg )
: ai_(context), engine_(cfg["engine"])
: ai_(context), engine_(cfg["engine"]), id_(cfg["id"]), name_(cfg["name"])
{
LOG_AI_COMPOSITE_ENGINE << "side "<< ai_.get_side() << " : "<<" created engine with name=["<<cfg["name"]<<"]"<<std::endl;
LOG_AI_COMPOSITE_ENGINE << "side "<< ai_.get_side() << " : "<<" created engine with name=["<<name_<<"]"<<std::endl;
}
engine::~engine()
@ -43,7 +43,7 @@ engine::~engine()
void engine::parse_aspect_from_config( readonly_context &context, const config &cfg, const std::string &id, std::back_insert_iterator< std::vector< aspect_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
engine_ptr eng = context.get_engine_by_cfg(cfg);
if (eng){
//do not override that method in subclasses which cannot create aspects
eng->do_parse_aspect_from_config(cfg, id, b);
@ -52,7 +52,7 @@ void engine::parse_aspect_from_config( readonly_context &context, const config &
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);
engine_ptr eng = context.get_engine_by_cfg(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);
@ -61,7 +61,7 @@ void engine::parse_candidate_action_from_config( rca_context &context, const con
void engine::parse_engine_from_config( readonly_context &context, const config &cfg, std::back_insert_iterator<std::vector< engine_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
engine_ptr eng = context.get_engine_by_cfg(cfg);
if (eng){
//do not override that method in subclasses which cannot create engines
eng->do_parse_engine_from_config(cfg, b);
@ -71,7 +71,7 @@ void engine::parse_engine_from_config( readonly_context &context, const config &
void engine::parse_goal_from_config( readonly_context &context, const config &cfg, std::back_insert_iterator<std::vector< goal_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
engine_ptr eng = context.get_engine_by_cfg(cfg);
if (eng){
//do not override that method in subclasses which cannot create goals
eng->do_parse_goal_from_config(cfg, b);
@ -81,7 +81,7 @@ void engine::parse_goal_from_config( readonly_context &context, const config &cf
void engine::parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
{
engine_ptr eng = context.get_engine(cfg);
engine_ptr eng = context.get_engine_by_cfg(cfg);
if (eng){
//do not override that method in subclasses which cannot create stages
eng->do_parse_stage_from_config(context, cfg, b);
@ -120,9 +120,16 @@ std::string engine::evaluate(const std::string& /*str*/)
std::string engine::get_name() const
const std::string& engine::get_name() const
{
return "null";
return name_;
}
const std::string& engine::get_engine() const
{
return engine_;
}
@ -140,4 +147,10 @@ config engine::to_config() const
}
const std::string& engine::get_id() const
{
return id_;
}
} //end of namespace ai

View file

@ -23,6 +23,7 @@
#include "../../global.hpp"
#include "component.hpp"
#include "../contexts.hpp"
#include "../game_info.hpp"
#include "../../config.hpp"
@ -38,7 +39,7 @@ class rca_context;
class ai_context;
class component;
class engine {
class engine : public component {
public:
engine( readonly_context &context, const config &cfg );
@ -82,7 +83,7 @@ public:
virtual std::string evaluate(const std::string& str);
virtual std::string get_name() const;
virtual const std::string& get_name() const;
/**
* set ai context (which is not available during early initialization)
@ -95,12 +96,19 @@ public:
*/
virtual config to_config() const;
virtual const std::string& get_id() const;
virtual const std::string& get_engine() const;
protected:
readonly_context &ai_;
/** name of the engine which has created this engine*/
std::string engine_;
std::string id_;
std::string name_;
};

View file

@ -33,6 +33,7 @@ static lg::log_domain log_ai_composite_engine_cpp("ai/composite/engine/cpp");
engine_cpp::engine_cpp( readonly_context &context, const config &cfg )
: engine(context,cfg)
{
name_ = "cpp";
}
engine_cpp::~engine_cpp()
@ -112,9 +113,4 @@ void engine_cpp::do_parse_goal_from_config(const config &cfg, std::back_insert_i
}
std::string engine_cpp::get_name() const
{
return "cpp";
}
} //end of namespace ai

View file

@ -49,8 +49,6 @@ public:
virtual void do_parse_goal_from_config(const config &cfg, std::back_insert_iterator<std::vector< goal_ptr > > b );
virtual std::string get_name() const;
};
} //end of namespace ai

View file

@ -75,6 +75,7 @@ private:
engine_fai::engine_fai( readonly_context &context, const config &cfg )
: engine(context,cfg), formula_ai_(context,cfg.child_or_empty("formula_ai"))
{
name_ = "fai";
formula_ai_.on_create();
}
@ -124,11 +125,6 @@ std::string engine_fai::evaluate(const std::string &str)
}
std::string engine_fai::get_name() const
{
return "fai";
}
void engine_fai::set_ai_context(ai_context *context)
{
if (context!=NULL) {

View file

@ -42,8 +42,6 @@ public:
virtual std::string evaluate(const std::string &str);
virtual std::string get_name() const;
virtual config to_config() const;
virtual void set_ai_context(ai_context *context);

View file

@ -67,6 +67,20 @@ const std::string& goal::get_id() const
}
const std::string& goal::get_name() const
{
return cfg_["id"];
}
const std::string& goal::get_engine() const
{
return cfg_["engine"];
}
bool goal::redeploy(const config &cfg)
{
cfg_ = cfg;

View file

@ -35,6 +35,8 @@
//included for 'target' markers
#include "../default/contexts.hpp"
#include "component.hpp"
#include <map>
#include <stack>
#include <vector>
@ -42,7 +44,7 @@
namespace ai {
class goal : public readonly_context_proxy {
class goal : public readonly_context_proxy, public component {
public:
goal(readonly_context &context, const config &cfg);
@ -65,6 +67,12 @@ public:
const std::string& get_id() const;
const std::string& get_name() const;
const std::string& get_engine() const;
bool redeploy(const config &cfg);

View file

@ -0,0 +1,245 @@
/* $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 component
* @file ai/composite/property_handler.hpp
*/
#ifndef AI_COMPOSITE_PROPERTY_HANDLER_HPP_INCLUDED
#define AI_COMPOSITE_PROPERTY_HANDLER_HPP_INCLUDED
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <string>
#include <map>
#include <vector>
#include "../../config.hpp"
#include "../../foreach.hpp"
namespace ai{
struct path_element {
path_element()
: property()
, id()
, position(0)
{
}
std::string property;
std::string id;
int position;
};
template<typename T>
class path_element_matches{
public:
path_element_matches(const path_element &element)
: count_(0), element_(element)
{
}
virtual ~path_element_matches(){}
bool operator()(const T& t)
{
if ( (!element_.id.empty()) && (element_.id == t->get_id()) ) {
return true;
}
if (count_ == element_.position) {
return true;
}
count_++;
return false;
}
private:
int count_;
path_element element_;
};
class component;
class base_property_handler {
public:
virtual component* handle_get(const path_element &child) = 0;
virtual bool handle_change(const path_element &child, const config &cfg) = 0;
virtual bool handle_add(const path_element &child, const config &cfg) = 0;
virtual bool handle_delete(const path_element &child) = 0;
virtual std::vector< component* > handle_get_children() = 0;
};
typedef boost::shared_ptr< base_property_handler > property_handler_ptr;
template<typename T>
class vector_property_handler : public base_property_handler {
public:
typedef boost::shared_ptr<T> t_ptr;
typedef std::vector< boost::shared_ptr<T> > t_ptr_vector;
vector_property_handler(const std::string &property, t_ptr_vector &values, boost::function2<void, t_ptr_vector&, const config&> &construction_factory)
: factory_(construction_factory), property_(property), values_(values){}
component* handle_get(const path_element &child)
{
typename t_ptr_vector::iterator i = std::find_if(values_.begin(),values_.end(),path_element_matches<t_ptr>(child));
if (i!=values_.end()){
return &*(*i);
}
return NULL;
}
bool handle_change(const path_element &child, const config &cfg)
{
if (!handle_delete(child)) {
return false;
}
return handle_add(child,cfg);
}
bool handle_add(const path_element &child, const config &cfg)
{
//if the id is not empty, try to delete all with this id
if (!cfg["id"].empty()) {
path_element with_same_id;
with_same_id.id=cfg["id"];
with_same_id.property = property_;
with_same_id.position=-1;
handle_delete(with_same_id);
}
typename t_ptr_vector::iterator i = std::find_if(values_.begin(),values_.end(),path_element_matches<t_ptr>(child));
return do_add(i-values_.begin(),cfg);
}
bool handle_delete(const path_element &child)
{
//* is a special case - 'delete all'
if (child.id == "*") {
values_.clear();
return true;
}
typename t_ptr_vector::iterator i = std::find_if(values_.begin(),values_.end(),path_element_matches<t_ptr>(child));
if (i!=values_.end()){
values_.erase(i);
return true;
}
return false;
}
std::vector<component*> handle_get_children()
{
std::vector<component*> children;
foreach (t_ptr v, values_) {
children.push_back(&*v);
}
return children;
}
private:
bool do_add(int pos, const config &cfg)
{
if (pos<0) {
pos = values_.size();
}
t_ptr_vector values;
factory_(values,cfg);
int j=0;
foreach (t_ptr b, values ){
values_.insert(values_.begin()+pos+j,b);
j++;
}
return (j>0);
}
boost::function2<void, t_ptr_vector&, const config&> factory_;
const std::string property_;
t_ptr_vector &values_;
};
template<typename T>
class aspect_property_handler : public base_property_handler {
public:
typedef boost::shared_ptr<T> t_ptr;
typedef std::map< std::string, t_ptr > aspect_map;
aspect_property_handler(const std::string &property, aspect_map &aspects)
: property_(property), aspects_(aspects)
{
}
component* handle_get(const path_element &child)
{
typename aspect_map::const_iterator a = aspects_.find(child.id);
if (a!=aspects_.end()){
return &*a->second;
}
return NULL;
}
bool handle_change(const path_element &child, const config &cfg)
{
return false;
}
bool handle_add(const path_element &child, const config &cfg)
{
return false;
}
bool handle_delete(const path_element &child)
{
//* is a special case - 'delete all facets'
if (child.id == "*") {
bool b = false;
foreach(typename aspect_map::value_type a, aspects_) {
b |= a.second->delete_all_facets();
}
return b;
}
return false;
}
std::vector<component*> handle_get_children()
{
std::vector<component*> children;
foreach(typename aspect_map::value_type a, aspects_) {
children.push_back(&*a.second);
}
return children;
}
private:
const std::string &property_;
aspect_map &aspects_;
};
} //of namespace ai
#endif

View file

@ -34,7 +34,7 @@ const double candidate_action::BAD_SCORE = 0;
const double candidate_action::HIGH_SCORE = 100000;
candidate_action::candidate_action(rca_context &context, const config &cfg)
: recursion_counter_(context.get_recursion_count()), enabled_(utils::string_bool(cfg["enabled"],true)), engine_(cfg["engine"]), score_(lexical_cast_default<double>(cfg["score"],BAD_SCORE)),max_score_(lexical_cast_default<double>(cfg["max_score"],HIGH_SCORE)),name_(cfg["name"]),type_(cfg["type"])
: recursion_counter_(context.get_recursion_count()), enabled_(utils::string_bool(cfg["enabled"],true)), engine_(cfg["engine"]), score_(lexical_cast_default<double>(cfg["score"],BAD_SCORE)),max_score_(lexical_cast_default<double>(cfg["max_score"],HIGH_SCORE)),id_(cfg["id"]),name_(cfg["name"]),type_(cfg["type"])
{
init_rca_context_proxy(context);
}
@ -90,6 +90,18 @@ const std::string& candidate_action::get_type() const
}
const std::string& candidate_action::get_id() const
{
return id_;
}
const std::string& candidate_action::get_engine() const
{
return engine_;
}
config candidate_action::to_config() const
{
config cfg;

View file

@ -24,6 +24,7 @@
#include "../../config.hpp"
#include "component.hpp"
#include "contexts.hpp"
#include "../contexts.hpp"
#include <boost/shared_ptr.hpp>
@ -39,7 +40,7 @@
//============================================================================
namespace ai {
class candidate_action : public virtual rca_context_proxy {
class candidate_action : public virtual rca_context_proxy, public component {
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;
@ -111,6 +112,12 @@ public:
const std::string& get_type() const;
const std::string& get_id() const;
const std::string& get_engine() const;
int get_recursion_count() const;
@ -125,14 +132,22 @@ private:
bool enabled_;
std::string engine_;
double score_;
double max_score_;
std::string id_;
std::string name_;
std::string type_;
};

View file

@ -77,6 +77,22 @@ const std::string& stage::get_id() const
return cfg_["id"];
}
const std::string& stage::get_engine() const
{
return cfg_["engine"];
}
const std::string& stage::get_name() const
{
return cfg_["name"];
}
// =======================================================================
// COMPOSITE AI IDLE STAGE
// =======================================================================

View file

@ -22,6 +22,7 @@
#include "../../global.hpp"
#include "component.hpp"
#include "contexts.hpp"
#include "../contexts.hpp"
#include "../../config.hpp"
@ -39,7 +40,7 @@ namespace ai {
class ai_composite;
class stage : public virtual ai_context_proxy {
class stage : public virtual ai_context_proxy, public component {
public:
/**
@ -78,6 +79,15 @@ public:
virtual const std::string& get_id() const;
virtual const std::string& get_name() const;
virtual const std::string& get_engine() const;
protected:
/**
* Play the turn - implementation

View file

@ -487,6 +487,12 @@ const aspect_map& readonly_context_impl::get_aspects() const
}
aspect_map& readonly_context_impl::get_aspects()
{
return aspects_;
}
const attacks_vector& readonly_context_impl::get_attacks() const
{
if (attacks_) {
@ -562,7 +568,7 @@ const move_map& readonly_context_impl::get_enemy_srcdst() const
}
engine_ptr readonly_context_impl::get_engine(const config& cfg)
engine_ptr readonly_context_impl::get_engine_by_cfg(const config& cfg)
{
std::string engine_name = cfg["engine"];
if (engine_name.empty()) {
@ -597,6 +603,19 @@ engine_ptr readonly_context_impl::get_engine(const config& cfg)
return engines_.back();
}
const std::vector<engine_ptr>& readonly_context_impl::get_engines() const
{
return engines_;
}
std::vector<engine_ptr>& readonly_context_impl::get_engines()
{
return engines_;
}
std::string readonly_context_impl::get_grouping() const
{
if (grouping_) {

View file

@ -207,6 +207,9 @@ public:
virtual const aspect_map& get_aspects() const = 0;
virtual aspect_map& get_aspects() = 0;
virtual void add_facet(const std::string &id, const config &cfg) const = 0;
@ -239,7 +242,13 @@ public:
/**
* get engine by cfg, creating it if it is not created yet but known
*/
virtual engine_ptr get_engine(const config& cfg) = 0;
virtual engine_ptr get_engine_by_cfg(const config& cfg) = 0;
virtual const std::vector<engine_ptr>& get_engines() const = 0;
virtual std::vector<engine_ptr>& get_engines() = 0;
virtual std::string get_grouping() const = 0;
@ -588,6 +597,12 @@ public:
}
virtual aspect_map& get_aspects()
{
return target_->get_aspects();
}
virtual void add_aspects(std::vector< aspect_ptr > &aspects )
{
return target_->add_aspects(aspects);
@ -650,9 +665,21 @@ public:
}
virtual engine_ptr get_engine(const config &cfg)
virtual engine_ptr get_engine_by_cfg(const config &cfg)
{
return target_->get_engine(cfg);
return target_->get_engine_by_cfg(cfg);
}
virtual const std::vector<engine_ptr>& get_engines() const
{
return target_->get_engines();
}
virtual std::vector<engine_ptr>& get_engines()
{
return target_->get_engines();
}
@ -1173,6 +1200,9 @@ public:
virtual const aspect_map& get_aspects() const;
virtual aspect_map& get_aspects();
virtual const attacks_vector& get_attacks() const;
@ -1197,7 +1227,13 @@ public:
virtual const move_map& get_enemy_srcdst() const;
virtual engine_ptr get_engine(const config& cfg);
virtual engine_ptr get_engine_by_cfg(const config& cfg);
virtual const std::vector<engine_ptr>& get_engines() const;
virtual std::vector<engine_ptr>& get_engines();
virtual std::string get_grouping() const;

View file

@ -248,6 +248,17 @@ const std::string holder::get_ai_overview()
return s.str();
}
const std::string holder::get_ai_structure()
{
if (!this->ai_) {
get_ai_ref();
}
return component_manager::print_component_tree(&*this->ai_,"");
}
const std::string holder::get_ai_identifier() const
{
return cfg_["id"];
@ -667,6 +678,13 @@ std::string manager::get_active_ai_overview_for_side( side_number side)
return get_active_ai_holder_for_side(side).get_ai_overview();
}
std::string manager::get_active_ai_structure_for_side( side_number side)
{
return get_active_ai_holder_for_side(side).get_ai_structure();
}
std::string manager::get_active_ai_identifier_for_side( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_identifier();

View file

@ -73,6 +73,9 @@ public:
const std::string get_ai_overview();
const std::string get_ai_structure();
const std::string get_ai_identifier() const;
private:
@ -377,6 +380,14 @@ public:
*/
static std::string get_active_ai_overview_for_side( side_number side);
/**
* Gets AI Structure for active AI of the given @a side
* @param side side number (1-based)
* @return an ai structure
*/
static std::string get_active_ai_structure_for_side( side_number side);
/**
* Gets AI algorithm identifier for active AI of the given @a side.
* @param side side number (1-based).

View file

@ -23,6 +23,8 @@
#include "../../foreach.hpp"
#include "../../log.hpp"
#include <boost/bind.hpp>
namespace ai {
namespace testing_ai_default {
@ -45,8 +47,20 @@ void candidate_action_evaluation_loop::on_create()
foreach(const config &cfg_element, cfg_.child_range("candidate_action")){
engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
}
boost::function2<void, std::vector<candidate_action_ptr>&, const config&> factory_candidate_actions =
boost::bind(&testing_ai_default::candidate_action_evaluation_loop::create_candidate_action,*this,_1,_2);
register_vector_property("candidate_action",candidate_actions_, factory_candidate_actions);
}
void candidate_action_evaluation_loop::create_candidate_action(std::vector<candidate_action_ptr> &candidate_actions, const config &cfg)
{
engine::parse_candidate_action_from_config(*this,cfg,std::back_inserter(candidate_actions));
}
config candidate_action_evaluation_loop::to_config() const
{
config cfg = stage::to_config();
@ -135,6 +149,25 @@ candidate_action_evaluation_loop::~candidate_action_evaluation_loop()
{
}
bool candidate_action_evaluation_loop::add_child(const path_element &/*child*/, const config &/*cfg*/)
{
//if (child.property=="candidate_action") {
// std::vector< candidate_action_ptr >::iterator i = std::find_if(candidate_actions_.begin(),candidate_actions_.end(),path_element_matches< candidate_action_ptr >(child));
//return add_candidate_action(i-candidate_actions_.begin(),cfg);
//}
return false;
}
bool candidate_action_evaluation_loop::change_child(const path_element &/*child*/, const config &/*cfg*/)
{
return false;
}
bool candidate_action_evaluation_loop::delete_child(const path_element &/*child*/)
{
return false;
}
} // end of namespace testing_ai_default
} // end of namespace ai

View file

@ -23,6 +23,7 @@
#include "../../global.hpp"
#include "../composite/contexts.hpp"
#include "../composite/component.hpp"
#include "../composite/rca.hpp"
#include "../composite/stage.hpp"
#include "../../config.hpp"
@ -54,6 +55,15 @@ public:
rca_context& get_rca_context();
virtual bool add_child(const path_element &child, const config &cfg);
virtual bool change_child(const path_element &child, const config &cfg);
virtual bool delete_child(const path_element &child);
void create_candidate_action(std::vector<candidate_action_ptr> &candidate_actions, const config &cfg);
private:
std::vector<candidate_action_ptr> candidate_actions_;

View file

@ -230,6 +230,7 @@ public:
model_.add_row_to_stuff_list("ai config full","ai config full");
model_.add_row_to_stuff_list("recall list overview","recall list overview");
model_.add_row_to_stuff_list("recall list full","recall list full");
model_.add_row_to_stuff_list("ai component structure","ai component structure");
model_.set_inspect_window_text("");
}
@ -287,6 +288,11 @@ public:
return;
}
if (selected==5) {
model_.set_inspect_window_text(ai::manager::get_active_ai_structure_for_side(side_));
return;
}
}
virtual void update_view_from_model()