new AI configuration syntax. Note: boost 1.35 required for compilation

This commit is contained in:
Iurii Chernyi 2009-08-01 14:17:15 +00:00
parent ec6b1657b0
commit 09223f03cc
68 changed files with 2775 additions and 1125 deletions

View file

@ -1,4 +1,6 @@
Version 1.7.2+svn:
* AI:
* New AI configuration syntax
* Campaigns:
* Two Brothers
* Replaced campaign specific portraits with mainline portraits

View file

@ -11,6 +11,9 @@
{campaigns/}
[ais]
[default_config]
{ai/utils/default_config.cfg}
[/default_config]
{ai/ais/}
#ifdef DEBUG_MODE
{ai/dev/}

View file

@ -5,6 +5,8 @@
[stage]
engine=cpp
name=testing_ai_default::fallback
fallback=formula_ai
[ai]
algorithm_type=formula_ai
[/ai]
[/stage]
[/ai]

View file

@ -2,6 +2,14 @@
[ai]
id=testing_ai_default
description=RCA AI
[aspect]
id=aggression
[facet]
engine=cpp
name=standard_aspect
value=1
[/facet]
[/aspect]
[stage]
engine=cpp
name=testing_ai_default::candidate_action_evaluation_loop

View file

@ -0,0 +1,67 @@
#define DEFAULT_ASPECT_VALUE ID VALUE
[aspect]
id={ID}
engine=cpp
name=composite_aspect
[default]
engine=cpp
name=standard_aspect
value={VALUE}
[/default]
[/aspect]
#enddef
#define DEFAULT_ASPECT_EMPTY ID
[aspect]
id={ID}
engine=cpp
name=composite_aspect
[default]
engine=cpp
name=standard_aspect
[/default]
[/aspect]
#enddef
#define DEFAULT_ASPECT_EMPTY_SLF ID
[aspect]
id={ID}
engine=cpp
name=composite_aspect
[default]
engine=cpp
name=standard_aspect
[value]
[not]
[/not]
[/value]
[/default]
[/aspect]
#enddef
{DEFAULT_ASPECT_VALUE aggression 0.5}
{DEFAULT_ASPECT_VALUE attack_depth 5}
{DEFAULT_ASPECT_EMPTY_SLF avoid}
{DEFAULT_ASPECT_VALUE caution 0.25}
{DEFAULT_ASPECT_VALUE grouping offensive}
{DEFAULT_ASPECT_EMPTY leader_goal}
{DEFAULT_ASPECT_VALUE leader_value 3.0}
{DEFAULT_ASPECT_VALUE number_of_possible_recruits_to_force_recruit 3.1}
{DEFAULT_ASPECT_VALUE passive_leader no}
{DEFAULT_ASPECT_VALUE passive_leader_shares_keep no}
{DEFAULT_ASPECT_VALUE protect_leader 2.0}
{DEFAULT_ASPECT_VALUE protect_leader_radius 10}
{DEFAULT_ASPECT_EMPTY protect_location}
{DEFAULT_ASPECT_EMPTY protect_unit}
{DEFAULT_ASPECT_VALUE recruitment_ignore_bad_combat no}
{DEFAULT_ASPECT_VALUE recruitment_ignore_bad_movement no}
{DEFAULT_ASPECT_EMPTY recruitment_pattern}
{DEFAULT_ASPECT_VALUE scout_village_targeting 3}
{DEFAULT_ASPECT_VALUE simple_targeting no}
{DEFAULT_ASPECT_VALUE support_villages no}
{DEFAULT_ASPECT_EMPTY target}
{DEFAULT_ASPECT_VALUE village_value 1.0}
{DEFAULT_ASPECT_VALUE villages_per_scout 4}
ai_algorithm = "default_ai"
default_config_applied="yes"

View file

@ -51,6 +51,8 @@
<Unit filename="..\..\src\ai\ai2\ai.hpp" />
<Unit filename="..\..\src\ai\composite\ai.cpp" />
<Unit filename="..\..\src\ai\composite\ai.hpp" />
<Unit filename="..\..\src\ai\composite\aspect.cpp" />
<Unit filename="..\..\src\ai\composite\aspect.hpp" />
<Unit filename="..\..\src\ai\composite\contexts.cpp" />
<Unit filename="..\..\src\ai\composite\contexts.hpp" />
<Unit filename="..\..\src\ai\composite\engine.cpp" />
@ -59,6 +61,8 @@
<Unit filename="..\..\src\ai\composite\engine_default.hpp" />
<Unit filename="..\..\src\ai\composite\engine_fai.cpp" />
<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\rca.cpp" />
<Unit filename="..\..\src\ai\composite\rca.hpp" />
<Unit filename="..\..\src\ai\composite\stage.cpp" />

View file

@ -80,6 +80,8 @@
<Unit filename="..\..\src\ai\ai2\ai.hpp" />
<Unit filename="..\..\src\ai\composite\ai.cpp" />
<Unit filename="..\..\src\ai\composite\ai.hpp" />
<Unit filename="..\..\src\ai\composite\aspect.cpp" />
<Unit filename="..\..\src\ai\composite\aspect.hpp" />
<Unit filename="..\..\src\ai\composite\contexts.cpp" />
<Unit filename="..\..\src\ai\composite\contexts.hpp" />
<Unit filename="..\..\src\ai\composite\engine.cpp" />
@ -88,6 +90,8 @@
<Unit filename="..\..\src\ai\composite\engine_default.hpp" />
<Unit filename="..\..\src\ai\composite\engine_fai.cpp" />
<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\rca.cpp" />
<Unit filename="..\..\src\ai\composite\rca.hpp" />
<Unit filename="..\..\src\ai\composite\stage.cpp" />

View file

@ -3871,6 +3871,34 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\ai\composite\aspect.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug (fast)|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\ai\composite\contexts.cpp"
>
@ -3983,6 +4011,34 @@
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\ai\composite\goal.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
<FileConfiguration
Name="Debug (fast)|Win32"
>
<Tool
Name="VCCLCompilerTool"
ObjectFile="$(IntDir)\ai\composite\"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\..\src\ai\composite\rca.cpp"
>
@ -5518,6 +5574,10 @@
RelativePath="..\..\src\ai\composite\ai.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\aspect.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\contexts.hpp"
>
@ -5534,6 +5594,10 @@
RelativePath="..\..\src\ai\composite\engine_fai.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\goal.hpp"
>
</File>
<File
RelativePath="..\..\src\ai\composite\rca.hpp"
>

View file

@ -220,10 +220,12 @@ SET(wesnoth-main_SRC
addon_management.cpp
ai/actions.cpp
ai/composite/ai.cpp
ai/composite/aspect.cpp
ai/composite/contexts.cpp
ai/composite/engine.cpp
ai/composite/engine_default.cpp
ai/composite/engine_fai.cpp
ai/composite/goal.cpp
ai/composite/rca.cpp
ai/composite/stage.cpp
ai/configuration.cpp

View file

@ -44,10 +44,12 @@ wesnoth_source = \
addon_management.cpp \
ai/actions.cpp \
ai/composite/ai.cpp \
ai/composite/aspect.cpp \
ai/composite/contexts.cpp \
ai/composite/engine.cpp \
ai/composite/engine_default.cpp \
ai/composite/engine_fai.cpp \
ai/composite/goal.cpp \
ai/composite/rca.cpp \
ai/composite/stage.cpp \
ai/configuration.cpp \

View file

@ -149,10 +149,12 @@ wesnoth_sources = Split("""
addon_management.cpp
ai/actions.cpp
ai/composite/ai.cpp
ai/composite/aspect.cpp
ai/composite/contexts.cpp
ai/composite/engine.cpp
ai/composite/engine_default.cpp
ai/composite/engine_fai.cpp
ai/composite/goal.cpp
ai/composite/rca.cpp
ai/composite/stage.cpp
ai/configuration.cpp

View file

@ -17,6 +17,7 @@
* Recruiting, Fighting.
*/
#include "ai/manager.hpp"
#include "ai/testing.hpp"
#include "attack_prediction.hpp"
#include "foreach.hpp"
@ -2013,7 +2014,7 @@ void check_victory()
if(non_interactive()) {
std::cout << "winner: ";
for(std::vector<unsigned int>::const_iterator i = seen_leaders.begin(); i != seen_leaders.end(); ++i) {
std::string ai = (*resources::teams)[*i - 1].ai_algorithm();
std::string ai = ai::manager::get_active_ai_identifier_for_side(*i);
if (ai == "") ai = "default ai";
std::cout << *i << " (using " << ai << ") ";
}

View file

@ -177,8 +177,8 @@ const team& action_result::get_my_team(const game_info& info) const
}
// attack_result
attack_result::attack_result( side_number side, const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon)
: action_result(side), attacker_loc_(attacker_loc), defender_loc_(defender_loc), attacker_weapon_(attacker_weapon){
attack_result::attack_result( side_number side, const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon, double aggression)
: action_result(side), attacker_loc_(attacker_loc), defender_loc_(defender_loc), attacker_weapon_(attacker_weapon), aggression_(aggression){
}
void attack_result::do_check_before()
@ -200,6 +200,7 @@ std::string attack_result::do_describe() const
s << " from location "<<attacker_loc_;
s << " to location "<<defender_loc_;
s << " using weapon "<< attacker_weapon_;
s << " with aggression "<< aggression_;
s <<std::endl;
return s.str();
}
@ -247,8 +248,9 @@ void attack_result::do_execute()
//CHECK ENEMY(DEFENDER)
//CHECK ATTACKER WEAPON
//@note: yes, this is a decision done here. It's that way because we want to allow a simpler attack 'with whatever weapon is considered best', and because we want to allow the defender to pick it's weapon. That's why aggression is needed. a cleaner solution is needed.
battle_context bc(get_info().units, attacker_loc_,
defender_loc_, attacker_weapon_, -1, get_my_team(get_info()).aggression());
defender_loc_, attacker_weapon_, -1, aggression_);
int attacker_weapon = bc.get_attacker_stats().attack_num;
int defender_weapon = bc.get_defender_stats().attack_num;
@ -818,9 +820,10 @@ attack_result_ptr actions::execute_attack_action( side_number side,
bool execute,
const map_location& attacker_loc,
const map_location& defender_loc,
int attacker_weapon)
int attacker_weapon,
double aggression)
{
attack_result_ptr action(new attack_result(side,attacker_loc,defender_loc,attacker_weapon));
attack_result_ptr action(new attack_result(side,attacker_loc,defender_loc,attacker_weapon,aggression));
execute ? action->execute() : action->check_before();
return action;
}

View file

@ -135,7 +135,8 @@ public:
attack_result( side_number side,
const map_location& attacker_loc,
const map_location& defender_loc,
int attacker_weapon );
int attacker_weapon,
double aggression );
static const int E_EMPTY_ATTACKER = 1001;
static const int E_EMPTY_DEFENDER = 1002;
static const int E_INCAPACITATED_ATTACKER = 1003;
@ -154,6 +155,7 @@ private:
const map_location& attacker_loc_;
const map_location& defender_loc_;
int attacker_weapon_;
double aggression_;
};
class move_result : public action_result {
@ -277,6 +279,7 @@ public:
* @param attacker_loc location of attacker
* @param defender_loc location of defender
* @param attacker_weapon weapon of attacker
* @param aggression aggression of attacker, is used to determine attacker's weapon if it is not specified
* @retval possible result: ok
* @retval possible result: something wrong
* @retval possible result: attacker and/or defender are invalid
@ -286,7 +289,8 @@ static attack_result_ptr execute_attack_action( side_number side,
bool execute,
const map_location& attacker_loc,
const map_location& defender_loc,
int attacker_weapon );
int attacker_weapon,
double aggression );
/**

View file

@ -33,8 +33,8 @@ namespace ai {
class ai2 : public readwrite_context_proxy, public interface {
public:
ai2(readwrite_context &context)
: recursion_counter_(context.get_recursion_count())
ai2(readwrite_context &context, const config &cfg)
: cfg_(cfg),recursion_counter_(context.get_recursion_count())
{
init_readwrite_context_proxy(context);
}
@ -43,14 +43,24 @@ public:
virtual void switch_side(side_number side){
set_side(side);
}
int get_recursion_count() const{
return recursion_counter_.get_count();
}
virtual void new_turn()
{
}
virtual config to_config() const{
return config();
}
private:
const config &cfg_;
recursion_counter recursion_counter_;
};

View file

@ -25,8 +25,6 @@
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)
@ -39,25 +37,19 @@ std::string ai_composite::describe_self(){
return "[composite_ai]";
}
ai_composite::ai_composite( default_ai_context &context)
: recursion_counter_(context.get_recursion_count())
ai_composite::ai_composite( default_ai_context &context, const config &cfg)
: cfg_(cfg),stages_(),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 id=["<<
ai_global_parameters["id"]<<"]"<<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_));
}
cfg_["id"]<<"]"<<std::endl;
// init the composite ai stages
foreach(const config &cfg_element, ai_global_parameters.child_range("stage")){
foreach(const config &cfg_element, cfg_.child_range("stage")){
engine::parse_stage_from_config(*this,cfg_element,std::back_inserter(stages_));
}
@ -77,10 +69,8 @@ void ai_composite::play_turn(){
void ai_composite::new_turn()
{
//todo 1.7 replace with event system
//@todo 1.7 replace with event system
recalculate_move_maps();
invalidate_attack_depth_cache();
invalidate_avoided_locations_cache();
invalidate_defensive_position_cache();
invalidate_recent_attacks_list();
invalidate_keeps_cache();
@ -88,37 +78,6 @@ void ai_composite::new_turn()
}
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();
@ -129,12 +88,23 @@ void ai_composite::switch_side(side_number side)
set_side(side);
}
composite_ai_context& ai_composite::get_composite_ai_context()
ai_context& ai_composite::get_ai_context()
{
return *this;
}
} //end of namespace composite_ai
config ai_composite::to_config() const
{
config cfg;
//serialize the composite ai stages
foreach(const stage_ptr &s, stages_){
cfg.add_child("stage",s->to_config());
}
return cfg;
}
} //end of namespace ai

View file

@ -22,8 +22,10 @@
#include "../../global.hpp"
#include "aspect.hpp"
#include "contexts.hpp"
#include "engine.hpp"
#include "goal.hpp"
#include "stage.hpp"
#include "../contexts.hpp"
#include "../default/contexts.hpp"
@ -40,16 +42,14 @@
//============================================================================
namespace ai {
namespace composite_ai {
class ai_composite : public composite_ai_context, public virtual default_ai_context_proxy, public interface {
class ai_composite : public ai_context, public virtual default_ai_context_proxy, public interface {
public:
/**
* Constructor
*/
ai_composite( default_ai_context &context );
ai_composite( default_ai_context &context, const config &cfg );
/**
@ -69,14 +69,14 @@ public:
*/
virtual void new_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();
/**
* serialize
*/
virtual config to_config() const;
int get_recursion_count() const;
@ -89,20 +89,21 @@ public:
/**
* unwrap
*/
virtual composite_ai_context& get_composite_ai_context();
virtual ai_context& get_ai_context();
protected:
/**
* Config of the AI
*/
const config &cfg_;
/**
* Stages of the composite AI
*/
std::vector< stage_ptr > stages_;
/**
* Engines of the composite AI
*/
std::vector< engine_ptr > engines_;
/**
* Recursion counter
@ -110,8 +111,6 @@ protected:
recursion_counter recursion_counter_;
};
} //end of namespace composite_ai
} //end of namespace ai
#ifdef _MSC_VER

123
src/ai/composite/aspect.cpp 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.
*/
/**
* @file ai/composite/aspect.cpp
*/
#include "aspect.hpp"
#include "../manager.hpp"
#include "../../log.hpp"
namespace ai {
static lg::log_domain log_ai_composite_aspect("ai/composite/aspect");
#define DBG_AI_COMPOSITE_ASPECT LOG_STREAM(debug, log_ai_composite_aspect)
#define LOG_AI_COMPOSITE_ASPECT LOG_STREAM(info, log_ai_composite_aspect)
#define WRN_AI_COMPOSITE_ASPECT LOG_STREAM(warn, log_ai_composite_aspect)
#define ERR_AI_COMPOSITE_ASPECT LOG_STREAM(err, log_ai_composite_aspect)
aspect::aspect(readonly_context &context, const config &cfg, const std::string &id)
: valid_(false), cfg_(cfg), invalidate_on_turn_start_(utils::string_bool(cfg["invalidate_on_turn_start"],true)), invalidate_on_tod_change_(utils::string_bool(cfg["invalidate_on_tod_change"],true)), invalidate_on_gamestate_change_(utils::string_bool(cfg["invalidate_on_gamestate_change"])), invalidate_on_minor_gamestate_change_(utils::string_bool(cfg["invalidate_on_minor_gamestate_change"])),engine_(cfg["engine"]),name_(cfg["name"]),id_(id)
{
DBG_AI_COMPOSITE_ASPECT << "creating new aspect: engine=["<<engine_<<"], name=["<<name_<<"], id=["<<id_<<"]"<< std::endl;
init_readonly_context_proxy(context);
if (invalidate_on_turn_start_) {
manager::add_turn_started_observer(this);
}
if (invalidate_on_tod_change_) {
//@todo 1.7 add tod_changed_observer
//manager::add_tod_changed_observer(this);
}
if (invalidate_on_gamestate_change_) {
manager::add_gamestate_observer(this);
}
if (invalidate_on_minor_gamestate_change_) {
//@todo 1.7 add minor_gamestate_change_observer
//manager::add_minor_gamestate_observer(this);
}
}
aspect::~aspect()
{
if (invalidate_on_turn_start_) {
manager::remove_turn_started_observer(this);
}
if (invalidate_on_tod_change_) {
//@todo 1.7 add tod_changed_observer
//manager::remove_tod_changed_observer(this);
}
if (invalidate_on_gamestate_change_) {
manager::remove_gamestate_observer(this);
}
if (invalidate_on_minor_gamestate_change_) {
//@todo 1.7 add minor_gamestate_change_observer
//manager::remove_minor_gamestate_observer(this);
}
}
lg::log_domain& aspect::log()
{
return log_ai_composite_aspect;
}
void aspect::on_create()
{
}
const std::string& aspect::get_id() const
{
return id_;
}
const std::string& aspect::get_name() const
{
return name_;
}
config aspect::to_config() const
{
config cfg;
cfg["invalidate_on_turn_start"] = invalidate_on_turn_start_ ? "yes" : "no";
cfg["invalidate_on_tod_change"] = invalidate_on_tod_change_ ? "yes" : "no";
cfg["invalidate_on_gamestate_change"] = invalidate_on_gamestate_change_ ? "yes" : "no";
cfg["invalidate_on_minor_gamestate_change"] = invalidate_on_minor_gamestate_change_ ? "yes" : "no";
cfg["engine"] = engine_;
cfg["name"] = name_;
cfg["id"] = id_;
return cfg;
}
known_aspect::known_aspect(const std::string &name)
: name_(name)
{
}
const std::string& known_aspect::get_name() const
{
return name_;
}
known_aspect::~known_aspect()
{
}
} //end of namespace ai

505
src/ai/composite/aspect.hpp Normal file
View file

@ -0,0 +1,505 @@
/* $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/aspect.hpp
*/
#ifndef AI_COMPOSITE_ASPECT_HPP_INCLUDED
#define AI_COMPOSITE_ASPECT_HPP_INCLUDED
#include "../../global.hpp"
#include "engine.hpp"
#include "../contexts.hpp"
#include "../game_info.hpp"
#include "../manager.hpp"
#include "../../foreach.hpp"
#include "../../log.hpp"
#include "../../terrain_filter.hpp"
#include <map>
#include <stack>
#include <vector>
#include <deque>
#include <boost/lexical_cast.hpp>
#include <boost/pointer_cast.hpp>
namespace ai {
//----
// @todo: move to some other place
template<typename T>
class config_value_translator {
public:
static void cfg_to_value(const config &cfg, T &value)
{
value = boost::lexical_cast<T>(cfg["value"]);
}
static void value_to_cfg(const T &value, config &cfg)
{
cfg["value"] = boost::lexical_cast<std::string>(value);
}
static config value_to_cfg(const T &value)
{
config cfg;
value_to_cfg(value,cfg);
return cfg;
}
static T cfg_to_value(const config &cfg)
{
T value;
cfg_to_value(cfg,value);
return value;
}
};
template<>
class config_value_translator<bool> {
public:
static void cfg_to_value(const config &cfg, bool &value)
{
value = utils::string_bool(cfg["value"]);
}
static void value_to_cfg(const bool &value, config &cfg)
{
cfg["value"] = value ? "yes" : "no";
}
static config value_to_cfg(const bool &value)
{
config cfg;
value_to_cfg(value,cfg);
return cfg;
}
static bool cfg_to_value(const config &cfg)
{
bool value;
cfg_to_value(cfg,value);
return value;
}
};
template<>
class config_value_translator< std::vector<std::string> > {
public:
static void cfg_to_value(const config &cfg, std::vector<std::string> &value)
{
value = utils::split(cfg["value"]);
}
static void value_to_cfg(const std::vector<std::string> &value, config &cfg)
{
std::stringstream buf;
for(std::vector<std::string>::const_iterator p = value.begin(); p != value.end(); ++p) {
if (p != value.begin()) {
buf << ",";
}
buf << *p;
}
cfg["value"] = buf.str();
}
static config value_to_cfg(const std::vector<std::string> &value)
{
config cfg;
value_to_cfg(value,cfg);
return cfg;
}
static std::vector<std::string> cfg_to_value(const config &cfg)
{
std::vector<std::string> value;
cfg_to_value(cfg,value);
return value;
}
};
template<>
class config_value_translator<config> {
public:
static void cfg_to_value(const config &cfg, config &value)
{
if (cfg.child("value")) {
value = cfg.child("value");
} else {
value = config();
}
}
static void value_to_cfg(const config &value, config &cfg)
{
cfg.add_child("value",value);
}
static config value_to_cfg(const config &value)
{
return value;
}
static config cfg_to_value(const config &cfg)
{
return cfg;
}
};
template<>
class config_value_translator<terrain_filter> {
public:
static void cfg_to_value(const config &cfg, terrain_filter &value)
{
if (cfg.child("value")) {
value = terrain_filter(vconfig(cfg.child("value")),manager::get_ai_info().units);
} else {
static config c;
if (!c.child("not")) {
c.add_child("not");
}
value = terrain_filter(vconfig(c),manager::get_ai_info().units);
}
}
static void value_to_cfg(const terrain_filter &value, config &cfg)
{
cfg.add_child("value",value.to_config());
}
static config value_to_cfg(const terrain_filter &value)
{
config cfg;
value_to_cfg(value,cfg);
return cfg;
}
static terrain_filter cfg_to_value(const config &cfg)
{
if (cfg.child("value")) {
return terrain_filter(vconfig(cfg.child("value")),manager::get_ai_info().units);
}
static config c;
if (!c.child("not")) {
c.add_child("not");
}
return terrain_filter(vconfig(c),manager::get_ai_info().units);
}
};
//----
class aspect : public readonly_context_proxy, public events::observer {
public:
aspect(readonly_context &context, const config &cfg, const std::string &id);
virtual ~aspect();
void invalidate() const
{
valid_ = false;
}
virtual void recalculate() const = 0;
virtual void on_create();
virtual config to_config() const;
void handle_generic_event(const std::string &/*event_name*/)
{
invalidate();
}
virtual bool active() const
{
return true;
}
const std::string& get_name() const;
const std::string& get_id() const;
static lg::log_domain& log();
protected:
mutable bool valid_;
config cfg_;
bool invalidate_on_turn_start_;
bool invalidate_on_tod_change_;
bool invalidate_on_gamestate_change_;
bool invalidate_on_minor_gamestate_change_;
std::string engine_;
std::string name_;
std::string id_;
};
template<typename T>
class typesafe_aspect : public aspect {
public:
typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
: aspect(context,cfg,id)
{
}
virtual ~typesafe_aspect()
{
}
virtual const T& get() const
{
if (!valid_) {
recalculate();
}
return *value_;
}
virtual void recalculate() const = 0;
virtual boost::shared_ptr<T> get_ptr() const
{
if (!valid_) {
recalculate();
}
return value_;
}
protected:
mutable boost::shared_ptr<T> value_;
};
class known_aspect {
public:
known_aspect(const std::string &name);
virtual ~known_aspect();
virtual void set(aspect_ptr a) = 0;
const std::string& get_name() const;
protected:
const std::string name_;
};
template<typename T>
class typesafe_known_aspect : public known_aspect {
public:
typesafe_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect<T> > &where, aspect_map &aspects)
: known_aspect(name), where_(where), aspects_(aspects)
{
}
void set(aspect_ptr a)
{
boost::shared_ptr< typesafe_aspect <T> > c = boost::dynamic_pointer_cast< typesafe_aspect<T> >(a);
if (c) {
assert (c->get_id()== this->get_name());
where_ = c;
aspects_.insert(make_pair(this->get_name(),c));
} else {
LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while setting aspect, got null. this might be caused by invalid [aspect] WML" << std::endl;
}
}
protected:
boost::shared_ptr<typesafe_aspect <T> > &where_;
aspect_map &aspects_;
};
template<typename T>
class composite_aspect : public typesafe_aspect<T> {
public:
composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
: typesafe_aspect<T>(context, cfg, id)
{
foreach (const config &cfg_element, this->cfg_.child_range("facet") ){
std::vector< aspect_ptr > facets;
engine::parse_aspect_from_config(*this,cfg_element,this->get_id(),std::back_inserter(facets));
foreach (aspect_ptr a, facets ){
boost::shared_ptr< typesafe_aspect<T> > b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
facets_.push_back(b);
}
}
const config &_default = this->cfg_.child("default");
if (_default) {
std::vector< aspect_ptr > default_aspects;
engine::parse_aspect_from_config(*this,_default,this->get_id(),std::back_inserter(default_aspects));
if (!default_aspects.empty()) {
boost::shared_ptr< typesafe_aspect<T> > b = boost::dynamic_pointer_cast< typesafe_aspect<T> >(default_aspects.front());
default_ = b;
}
}
}
virtual void recalculate() const
{
foreach (const boost::shared_ptr< typesafe_aspect<T> > f, facets_) {
if (f->active()) {
this->value_ = boost::shared_ptr<T>(f->get_ptr());
return;
}
}
this->value_ = boost::shared_ptr<T>(default_->get_ptr());
}
virtual config to_config() const
{
config cfg = aspect::to_config();
foreach (const boost::shared_ptr< typesafe_aspect<T> > f, facets_) {
cfg.add_child("facet",f->to_config());
}
if (default_) {
cfg.add_child("default",default_->to_config());
}
return cfg;
}
protected:
std::vector< boost::shared_ptr< typesafe_aspect<T> > > facets_;
boost::shared_ptr< typesafe_aspect<T> > default_;
};
template<typename T>
class standard_aspect : public typesafe_aspect<T> {
public:
standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
: typesafe_aspect<T>(context, cfg, id), time_of_day_(cfg["time_of_day"]),turns_(cfg["turns"])
{
boost::shared_ptr<T> value(new T(config_value_translator<T>::cfg_to_value(this->cfg_)));
this->value_= value;
LOG_STREAM(debug, aspect::log()) << "standard aspect has time_of_day=["<<time_of_day_<<"], turns=["<<turns_<<"], and value: "<< std::endl << config_value_translator<T>::value_to_cfg(this->get()) << std::endl;
}
virtual bool active() const
{
if(time_of_day_.empty() == false) {
const std::vector<std::string>& times = utils::split(time_of_day_);
if(std::count(times.begin(),times.end(),this->get_info().tod_manager_.get_time_of_day().name) == 0) {
return false;
}
}
if(turns_.empty() == false) {
int turn = this->get_info().tod_manager_.turn();
const std::vector<std::string>& turns_list = utils::split(turns_);
for(std::vector<std::string>::const_iterator j = turns_list.begin(); j != turns_list.end() ; j++ ) {
const std::pair<int,int> range = utils::parse_range(*j);
if(turn >= range.first && turn <= range.second) {
return true;
}
}
return false;
}
return false;
}
void recalculate() const
{
//nothing to recalculate
}
config to_config() const
{
config cfg = aspect::to_config();
config_value_translator<T>::value_to_cfg(this->get(),cfg);
cfg["time_of_day"] = time_of_day_;
cfg["turns"] = turns_;
return cfg;
}
protected:
std::string time_of_day_;
std::string turns_;
};
class aspect_factory{
public:
typedef boost::shared_ptr< aspect_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 *aspect_factories;
if (aspect_factories==NULL) {
aspect_factories = new factory_map;
}
return *aspect_factories;
}
virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id) = 0;
aspect_factory( const std::string &name )
{
factory_ptr ptr_to_this(this);
get_list().insert(make_pair(name,ptr_to_this));
}
virtual ~aspect_factory() {}
};
template<class ASPECT>
class register_aspect_factory : public aspect_factory {
public:
register_aspect_factory( const std::string &name )
: aspect_factory( name )
{
}
virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id){
boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id));
aspect_ptr a = _a;
a->on_create();
return a;
}
};
} //end of namespace ai
#endif

View file

@ -23,26 +23,23 @@
// =======================================================================
namespace ai {
namespace composite_ai {
composite_ai_context::composite_ai_context()
ai_context::ai_context()
{
}
composite_ai_context::~composite_ai_context()
ai_context::~ai_context()
{
}
composite_ai_context_proxy::composite_ai_context_proxy()
ai_context_proxy::ai_context_proxy()
: target_()
{
}
composite_ai_context_proxy::~composite_ai_context_proxy()
ai_context_proxy::~ai_context_proxy()
{
}
@ -67,6 +64,4 @@ rca_context_proxy::~rca_context_proxy()
{
}
} //end of namespace composite_ai
} //end of namespace ai

View file

@ -38,49 +38,33 @@
//============================================================================
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{
class ai_context : public virtual default_ai_context{
public:
/**
* Constructor
*/
composite_ai_context();
ai_context();
/**
* Destructor
*/
virtual ~composite_ai_context();
virtual ~ai_context();
/**
* Unwrap
*/
virtual composite_ai_context& get_composite_ai_context() = 0;
virtual ai_context& get_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 {
class rca_context : public virtual ai_context {
public:
@ -127,39 +111,33 @@ public:
};
// proxies
class composite_ai_context_proxy : public virtual composite_ai_context, public virtual default_ai_context_proxy {
class ai_context_proxy : public virtual ai_context, public virtual default_ai_context_proxy {
public:
composite_ai_context_proxy();
ai_context_proxy();
void init_composite_ai_context_proxy(composite_ai_context &target)
void init_ai_context_proxy(ai_context &target)
{
init_default_ai_context_proxy(target);
target_ = &target;
}
virtual ~composite_ai_context_proxy();
virtual ~ai_context_proxy();
composite_ai_context& get_composite_ai_context()
ai_context& get_ai_context()
{
return target_->get_composite_ai_context();
}
engine_ptr get_engine(const config& cfg)
{
return target_->get_engine(cfg);
return target_->get_ai_context();
}
private:
composite_ai_context *target_;
ai_context *target_;
};
class rca_context_proxy : public virtual rca_context, public virtual composite_ai_context_proxy {
class rca_context_proxy : public virtual rca_context, public virtual ai_context_proxy {
public:
rca_context_proxy();
@ -169,7 +147,7 @@ public:
void init_rca_context_proxy(rca_context &target)
{
init_composite_ai_context_proxy(target);
init_ai_context_proxy(target);
target_ = &target;
}
@ -185,8 +163,6 @@ private:
};
} //end of namespace composite_ai
} //end of namespace ai
#ifdef _MSC_VER

View file

@ -17,22 +17,21 @@
* @file ai/composite/engine.cpp
*/
#include "ai.hpp"
#include "engine.hpp"
#include "contexts.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)
engine::engine( readonly_context &context, const config &cfg )
: ai_(context), engine_(cfg["engine"])
{
LOG_AI_COMPOSITE_ENGINE << "side "<< ai_.get_side() << " : "<<" created engine with name=["<<cfg["name"]<<"]"<<std::endl;
}
@ -41,16 +40,26 @@ 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 )
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);
if (eng){
//do not override that method in subclasses which cannot create aspects
eng->do_parse_aspect_from_config(cfg, id, b);
}
}
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);
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 )
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);
if (eng){
@ -59,15 +68,32 @@ void engine::parse_engine_from_config( composite_ai_context &context, const conf
}
}
void engine::parse_stage_from_config( composite_ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
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);
if (eng){
//do not override that method in subclasses which cannot create goals
eng->do_parse_goal_from_config(cfg, b);
}
}
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);
if (eng){
//do not override that method in subclasses which cannot create stages
eng->do_parse_stage_from_config(cfg, b);
eng->do_parse_stage_from_config(context, cfg, b);
}
}
void engine::do_parse_aspect_from_config( const config &/*cfg*/, const std::string &/*id*/, std::back_insert_iterator< std::vector<aspect_ptr> > /*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*/ ){
}
@ -76,15 +102,30 @@ void engine::do_parse_engine_from_config( const config &/*cfg*/, std::back_inser
}
void engine::do_parse_stage_from_config( const config &/*cfg*/, std::back_insert_iterator<std::vector< stage_ptr > > /*b*/ )
void engine::do_parse_goal_from_config( const config &/*cfg*/, std::back_insert_iterator<std::vector< goal_ptr > > /*b*/ ){
}
void engine::do_parse_stage_from_config( ai_context &/*context*/, const config &/*cfg*/, std::back_insert_iterator<std::vector< stage_ptr > > /*b*/ )
{
}
std::string engine::get_name(){
std::string engine::get_name() const
{
return "null";
}
} //end of namespace composite_ai
config engine::to_config() const
{
config cfg;
cfg["engine"] = engine_;
cfg["name"] = get_name();
return cfg;
}
} //end of namespace ai

View file

@ -22,9 +22,8 @@
#include "../../global.hpp"
#include "contexts.hpp"
#include "rca.hpp"
#include "stage.hpp"
#include "../contexts.hpp"
#include "../game_info.hpp"
#include "../../config.hpp"
#include <algorithm>
#include <iterator>
@ -34,38 +33,64 @@
namespace ai {
namespace composite_ai {
class ai_composite;
class rca_context;
class ai_context;
class engine {
public:
engine( composite_ai_context &context, const config &cfg );
engine( readonly_context &context, const config &cfg );
virtual ~engine();
static void parse_aspect_from_config( readonly_context &context, const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b );
static void parse_goal_from_config( readonly_context &context, const config &cfg, std::back_insert_iterator<std::vector< goal_ptr > > b );
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 );
static void parse_engine_from_config( readonly_context &context, const config &cfg, std::back_insert_iterator<std::vector< engine_ptr > > b );
static void parse_stage_from_config( 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 aspects
virtual void do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator< std::vector< aspect_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 goals
virtual void do_parse_goal_from_config( const config &cfg, std::back_insert_iterator<std::vector< goal_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 void do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
virtual std::string get_name();
virtual std::string get_name() const;
/**
* serialize
*/
virtual config to_config() const;
protected:
composite_ai_context &ai_;
readonly_context &ai_;
/** name of the engine which has created this engine*/
std::string engine_;
};
@ -86,8 +111,8 @@ public:
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;
virtual engine_ptr get_new_instance( readonly_context &ai, const config &cfg ) = 0;
virtual engine_ptr get_new_instance( readonly_context &ai, const std::string& name ) = 0;
engine_factory( const std::string &name )
{
@ -107,19 +132,18 @@ public:
{
}
virtual engine_ptr get_new_instance( composite_ai_context &ai, const config &cfg ){
virtual engine_ptr get_new_instance( readonly_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 ){
virtual engine_ptr get_new_instance( readonly_context &ai, const std::string& name ){
config cfg;
cfg["name"] = name;
cfg["engine"] = "cpp";
return engine_ptr(new ENGINE(ai,cfg));
}
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -25,14 +25,12 @@
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_cpp::engine_cpp( readonly_context &context, const config &cfg )
: engine(context,cfg)
{
}
@ -42,6 +40,25 @@ engine_cpp::~engine_cpp()
}
void engine_cpp::do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b )
{
const std::string aspect_factory_key = id+"*"+cfg["name"];//@note: hack which combines aspect id and name to get the std::string key of the aspect factory
aspect_factory::factory_map::iterator f = aspect_factory::get_list().find(aspect_factory_key);
if (f == aspect_factory::get_list().end()){
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNKNOWN aspect["<<aspect_factory_key<<"]" << std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
aspect_ptr new_aspect = f->second->get_new_instance(ai_,cfg,id);
if (!new_aspect) {
ERR_AI_COMPOSITE_ENGINE_CPP << "side "<<ai_.get_side()<< " : UNABLE TO CREATE aspect, key=["<<aspect_factory_key<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_CPP << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
*b = new_aspect;
}
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()){
@ -59,7 +76,7 @@ void engine_cpp::do_parse_candidate_action_from_config( rca_context &context, co
}
void engine_cpp::do_parse_stage_from_config( const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
void engine_cpp::do_parse_stage_from_config( ai_context &context, 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()){
@ -67,7 +84,7 @@ void engine_cpp::do_parse_stage_from_config( const config &cfg, std::back_insert
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);
stage_ptr new_stage = f->second->get_new_instance(context,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;
@ -77,11 +94,9 @@ void engine_cpp::do_parse_stage_from_config( const config &cfg, std::back_insert
}
std::string engine_cpp::get_name()
std::string engine_cpp::get_name() const
{
return "cpp";
}
} //end of namespace composite_ai
} //end of namespace ai

View file

@ -29,24 +29,27 @@
//============================================================================
namespace ai {
namespace composite_ai {
class engine_cpp : public engine {
public:
engine_cpp( composite_ai_context &context, const config &cfg );
engine_cpp( readonly_context &context, const config &cfg );
virtual ~engine_cpp();
void do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b );
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 void do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b );
virtual std::string get_name();
virtual std::string get_name() const;
};
} //end of namespace composite_ai
} //end of namespace ai
#endif

View file

@ -25,8 +25,6 @@
namespace ai {
namespace composite_ai {
static lg::log_domain log_ai_composite_engine_fai("ai/composite/engine/fai");
#define DBG_AI_COMPOSITE_ENGINE_FAI LOG_STREAM(debug, log_ai_composite_engine_fai)
#define LOG_AI_COMPOSITE_ENGINE_FAI LOG_STREAM(info, log_ai_composite_engine_fai)
@ -40,8 +38,8 @@ static lg::log_domain log_ai_composite_engine_fai("ai/composite/engine/fai");
class fai_candidate_action_wrapper : public candidate_action {
public:
fai_candidate_action_wrapper( rca_context &context, const config &/*cfg*/, game_logic::candidate_action_ptr fai_ca, formula_ai &_formula_ai )
: candidate_action(context,fai_ca->get_name(),fai_ca->get_type()),fai_ca_(fai_ca),formula_ai_(_formula_ai)
fai_candidate_action_wrapper( rca_context &context, const config &cfg, game_logic::candidate_action_ptr fai_ca, formula_ai &_formula_ai )
: candidate_action(context,cfg),fai_ca_(fai_ca),formula_ai_(_formula_ai),cfg_(cfg)//@todo 1.7: implement fai_ca->to_config()
{
}
@ -60,17 +58,23 @@ public:
{
return formula_ai_.execute_candidate_action(fai_ca_);
}
virtual config to_config() const
{
return cfg_;
}
private:
game_logic::candidate_action_ptr fai_ca_;
formula_ai &formula_ai_;
const config &cfg_;
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
engine_fai::engine_fai( composite_ai_context &context, const config &cfg )
: engine(context,cfg), formula_ai_(context)
engine_fai::engine_fai( readonly_context &context, const config &cfg )
: engine(context,cfg)/*, formula_ai_(context,cfg.child("formula_ai"))*///@fixme
{
}
@ -81,24 +85,30 @@ engine_fai::~engine_fai()
}
void engine_fai::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b ){
game_logic::candidate_action_ptr fai_ca = formula_ai_.load_candidate_action_from_config(cfg);
void engine_fai::do_parse_candidate_action_from_config( rca_context &/*context*/, const config &/*cfg*/, std::back_insert_iterator<std::vector< candidate_action_ptr > > /*b*/ ){
/*game_logic::candidate_action_ptr fai_ca = formula_ai_.load_candidate_action_from_config(cfg);
if (!fai_ca) {
ERR_AI_COMPOSITE_ENGINE_FAI << "side "<<ai_.get_side()<< " : ERROR creating candidate_action["<<cfg["name"]<<"]"<< std::endl;
DBG_AI_COMPOSITE_ENGINE_FAI << "config snippet contains: " << std::endl << cfg << std::endl;
return;
}
candidate_action_ptr ca = candidate_action_ptr(new fai_candidate_action_wrapper(context,cfg,fai_ca,formula_ai_));
*b = ca;
*b = ca; */
}
std::string engine_fai::get_name()
std::string engine_fai::get_name() const
{
return "fai";
}
} //end of namespace composite_ai
config engine_fai::to_config() const
{
config cfg = engine::to_config();
/*cfg.add_child("formula_ai",formula_ai_.to_config());*/
return cfg;
}
} //end of namespace ai

View file

@ -30,22 +30,20 @@
//============================================================================
namespace ai {
namespace composite_ai {
class engine_fai : public engine {
public:
engine_fai( composite_ai_context &context, const config &cfg );
engine_fai( readonly_context &context, const config &cfg );
virtual ~engine_fai();
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 std::string get_name();
private:
formula_ai formula_ai_;
};
virtual std::string get_name() const;
} //end of namespace composite_ai
virtual config to_config() const;
private:
//formula_ai formula_ai_;//@fixme
};
} //end of namespace ai

69
src/ai/composite/goal.cpp Normal file
View file

@ -0,0 +1,69 @@
/* $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/goal.cpp
*/
#include "goal.hpp"
#include "../manager.hpp"
#include "../../log.hpp"
#include "../../gamestatus.hpp"
#include "../../variable.hpp"
namespace ai {
static lg::log_domain log_ai_composite_aspect("ai/composite/goal");
#define DBG_AI_COMPOSITE_GOAL LOG_STREAM(debug, log_ai_composite_goal)
#define LOG_AI_COMPOSITE_GOAL LOG_STREAM(info, log_ai_composite_goal)
#define ERR_AI_COMPOSITE_GOAL LOG_STREAM(err, log_ai_composite_goal)
goal::goal(const config &cfg)
: cfg_(cfg),loc_(),value_(),type_()
{
//@todo 1.7: parse config of goal
}
goal::goal(const map_location &loc, double value, TYPE type)
: cfg_(),loc_(loc), value_(value), type_(type)
{
}
goal::~goal()
{
}
//@todo: push to subclass
bool goal::matches_unit(unit_map::const_iterator u)
{
if (!u.valid()) {
return false;
}
config &criteria = cfg_.child("criteria");
return u->second.matches_filter(vconfig(criteria),u->first);
}
config goal::to_config() const
{
config cfg;
//@todo 1.7 recreate config
return cfg;
}
} //end of namespace ai

68
src/ai/composite/goal.hpp Normal file
View file

@ -0,0 +1,68 @@
/* $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/goal.hpp
*/
#ifndef AI_COMPOSITE_GOAL_HPP_INCLUDED
#define AI_COMPOSITE_GOAL_HPP_INCLUDED
#include "../../global.hpp"
#include "../game_info.hpp"
#include <map>
#include <stack>
#include <vector>
#include <deque>
namespace ai {
class goal {
public:
enum TYPE { VILLAGE, LEADER, EXPLICIT, THREAT, BATTLE_AID, MASS, SUPPORT };
goal(const config &cfg);
goal(const map_location &loc, double value, TYPE type=VILLAGE);
virtual ~goal();
bool matches_unit(unit_map::const_iterator u);
config to_config() const;
double value()
{
return value_;
}
private:
config cfg_;
map_location loc_;
double value_;
TYPE type_;
};
} //end of namespace ai
#endif

View file

@ -25,8 +25,6 @@
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)
@ -34,11 +32,10 @@ static lg::log_domain log_ai_composite_rca("ai/composite/rca");
const double candidate_action::BAD_SCORE = 0;
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)
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)),name_(cfg["name"]),type_(cfg["type"])
{
init_rca_context_proxy(context);
//LOG_AI_COMPOSITE_RCA << "side "<< get_side() << " : "<<" created "<<*this<<std::endl;
}
candidate_action::~candidate_action()
@ -85,6 +82,18 @@ const std::string& candidate_action::get_type() const
return type_;
}
config candidate_action::to_config() const
{
config cfg;
cfg["enabled"] = lexical_cast<std::string>(enabled_);
cfg["engine"] = engine_;
cfg["name"] = name_;
cfg["score"] = lexical_cast<std::string>(score_);
cfg["type"] = type_;
return cfg;
}
candidate_action_evaluation_exception::candidate_action_evaluation_exception(const std::string &message)
: message_(message)
{
@ -115,24 +124,23 @@ const std::string& candidate_action_execution_exception::get_message() const
//============================================================================
} //end of namespace composite_ai
} // of namespace ai
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_evaluation_exception const &caee) {
std::ostream &operator<<(std::ostream &s, 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) {
std::ostream &operator<<(std::ostream &s, 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) {
std::ostream &operator<<(std::ostream &s, ai::candidate_action const &ca) {
s << "candidate action with name ["<< ca.get_name() <<"]";
return s;
}

View file

@ -39,8 +39,6 @@
//============================================================================
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
@ -52,7 +50,7 @@ public:
* @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 );
candidate_action( rca_context &context, const config &cfg );
/**
* Destructor
@ -103,13 +101,23 @@ public:
*/
const std::string& get_type() const;
int get_recursion_count() const;
/**
* serialize
*/
virtual config to_config() const;
private:
recursion_counter recursion_counter_;
bool enabled_;
std::string engine_;
double score_;
std::string name_;
@ -188,15 +196,14 @@ public:
//============================================================================
} //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::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::candidate_action_evaluation_exception const &caee);
std::ostream &operator<<(std::ostream &s, ai::composite_ai::candidate_action_execution_exception const &caee);
std::ostream &operator<<(std::ostream &s, ai::candidate_action_execution_exception const &caee);
#ifdef _MSC_VER
#pragma warning(pop)

View file

@ -27,8 +27,6 @@
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)
@ -38,10 +36,10 @@ static lg::log_domain log_ai_composite_stage("ai/composite/stage");
// COMPOSITE AI STAGE
// =======================================================================
stage::stage( composite_ai_context &context, const config &cfg )
stage::stage( ai_context &context, const config &cfg )
: recursion_counter_(context.get_recursion_count()), cfg_(cfg)
{
init_composite_ai_context_proxy(context);
init_ai_context_proxy(context);
}
void stage::on_create()
@ -63,12 +61,20 @@ int stage::get_recursion_count() const
return recursion_counter_.get_count();
}
config stage::to_config() const
{
config cfg;
cfg["engine"] = cfg_["engine"];
cfg["name"] = cfg_["name"];
return cfg;
}
// =======================================================================
// COMPOSITE AI IDLE STAGE
// =======================================================================
idle_stage::idle_stage( composite_ai_context &context, const config &cfg )
idle_stage::idle_stage( ai_context &context, const config &cfg )
: stage(context,cfg)
{
}
@ -81,6 +87,5 @@ void idle_stage::do_play_stage(){
LOG_AI_COMPOSITE_STAGE << "Turn " << get_info().tod_manager_.turn() << ": playing idle stage for side: "<< get_side() << std::endl;
}
} //end of namespace composite_ai
} //end of namespace ai

View file

@ -37,17 +37,15 @@
namespace ai {
namespace composite_ai {
class ai_composite;
class stage : public virtual composite_ai_context_proxy {
class stage : public virtual ai_context_proxy {
public:
/**
* Constructor
*/
stage( composite_ai_context &context, const config &cfg );
stage( ai_context &context, const config &cfg );
/**
* Initialization
@ -71,6 +69,13 @@ public:
*/
int get_recursion_count() const;
/**
* serialize
*/
virtual config to_config() const;
protected:
/**
* Play the turn - implementation
@ -86,7 +91,7 @@ protected:
class idle_stage : public stage {
public:
idle_stage( composite_ai_context &context, const config &cfg );
idle_stage( ai_context &context, const config &cfg );
~idle_stage();
@ -108,7 +113,7 @@ public:
return *stage_factories;
}
virtual stage_ptr get_new_instance( composite_ai_context &context, const config &cfg ) = 0;
virtual stage_ptr get_new_instance( ai_context &context, const config &cfg ) = 0;
stage_factory( const std::string &name )
{
@ -128,7 +133,7 @@ public:
{
}
virtual stage_ptr get_new_instance( composite_ai_context &context, const config &cfg ){
virtual stage_ptr get_new_instance( ai_context &context, const config &cfg ){
stage_ptr a(new STAGE(context,cfg));
a->on_create();
return a;
@ -136,8 +141,6 @@ public:
};
} //end of namespace composite_ai
} //end of namespace ai
#ifdef _MSC_VER

View file

@ -26,6 +26,8 @@
#include "../serialization/parser.hpp"
#include "../serialization/preprocessor.hpp"
#include "../team.hpp"
#include <boost/lexical_cast.hpp>
#include <vector>
namespace ai {
@ -35,11 +37,57 @@ static lg::log_domain log_ai_configuration("ai/config");
#define WRN_AI_CONFIGURATION LOG_STREAM(warn, log_ai_configuration)
#define ERR_AI_CONFIGURATION LOG_STREAM(err, log_ai_configuration)
class well_known_aspect {
public:
well_known_aspect(const std::string &name, bool attr = true)
: name_(name),was_an_attribute_(attr)
{
}
virtual ~well_known_aspect() {};
std::string name_;
bool was_an_attribute_;
};
std::vector<well_known_aspect> well_known_aspects;
void configuration::init(const config &game_config)
{
ai_configurations_.clear();
well_known_aspects.clear();
well_known_aspects.push_back(well_known_aspect("aggression"));
well_known_aspects.push_back(well_known_aspect("attack_depth"));
well_known_aspects.push_back(well_known_aspect("avoid",false));
well_known_aspects.push_back(well_known_aspect("caution"));
well_known_aspects.push_back(well_known_aspect("grouping"));
well_known_aspects.push_back(well_known_aspect("leader_goal",false));
well_known_aspects.push_back(well_known_aspect("leader_value"));
well_known_aspects.push_back(well_known_aspect("number_of_possible_recruits_to_force_recruit"));
well_known_aspects.push_back(well_known_aspect("passive_leader"));
well_known_aspects.push_back(well_known_aspect("passive_leader_shares_keep"));
//well_known_aspects.push_back(well_known_aspect("protect_leader"));
//well_known_aspects.push_back(well_known_aspect("protect_leader_radius"));
//well_known_aspects.push_back(well_known_aspect("protect_location",false));
//well_known_aspects.push_back(well_known_aspect("protect_unit",false));
well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_combat"));
well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_movement"));
well_known_aspects.push_back(well_known_aspect("recruitment_pattern"));
well_known_aspects.push_back(well_known_aspect("scout_village_targeting"));
well_known_aspects.push_back(well_known_aspect("simple_targeting"));
well_known_aspects.push_back(well_known_aspect("support_villages"));
well_known_aspects.push_back(well_known_aspect("village_value"));
well_known_aspects.push_back(well_known_aspect("villages_per_scout"));
const config &ais = game_config.child("ais");
default_config_ = ais.child("default_config");
if (!default_config_) {
ERR_AI_CONFIGURATION << "Missing AI [default_config]. Therefore, default_config_ set to empty." << std::endl;
default_config_ = config();
}
foreach (const config &ai_configuration, ais.child_range("ai")) {
const std::string &id = ai_configuration["id"];
if (id.empty()){
@ -84,19 +132,6 @@ const config& configuration::get_ai_config_for(const std::string &id)
configuration::description_map configuration::ai_configurations_ = configuration::description_map();
config configuration::default_config_ = config();
static std::string bind_config_parameter( const std::string& value_from_config,
const std::string& value_from_global_config,
const std::string& default_value )
{
if (value_from_config!=""){
return value_from_config;
} else if (value_from_global_config!=""){
return value_from_global_config;
}
return default_value;
}
bool configuration::get_side_config_from_file(const std::string& file, config& cfg ){
try {
scoped_istream stream = preprocess_file(get_wml_location(file));
@ -107,178 +142,204 @@ bool configuration::get_side_config_from_file(const std::string& file, config& c
return false;
}
LOG_AI_CONFIGURATION << "Successfully read AI configuration from file '" << file << "'" << std::endl;
return true;
return cfg;//in boolean context
}
const config& configuration::get_default_ai_parameters()
{
return default_config_;
}
bool configuration::parse_side_config(const config& cfg,
std::string& ai_algorithm_type,
config& global_ai_parameters,
std::vector<config>& ai_parameters,
const config& default_ai_parameters,
config& ai_memory,
config& effective_ai_parameters )
bool configuration::upgrade_aspect_config_from_1_07_02_to_1_07_03(const config& cfg, config& parsed_cfg, const std::string &id, bool aspect_was_attribute)
{
config aspect_config;
aspect_config["id"] = id;
foreach (const config &aiparam, cfg.child_range("ai")) {
const config &_aspect = aiparam.find_child("aspect","id",id);
if (_aspect) {
aspect_config.append(_aspect);
}
if (aspect_was_attribute && !aiparam.has_attribute(id)) {
continue;//we are looking for an attribute but it isn't present
}
if (!aspect_was_attribute && !aiparam.child(id)) {
continue;//we are looking for a child but it isn't present
}
config facet_config;
facet_config["engine"] = "cpp";
facet_config["name"] = "standard_aspect";
if (aspect_was_attribute) {
facet_config["value"] = aiparam[id];
} else {
foreach (const config &value, cfg.child_range(id)) {
facet_config.add_child("value",value);
}
}
if (aiparam.has_attribute("turns")) {
facet_config["turns"] = aiparam["turns"];
}
if (aiparam.has_attribute("time_of_day")) {
facet_config["time_of_day"] = aiparam["time_of_day"];
}
aspect_config.add_child("facet",facet_config);
}
parsed_cfg.add_child("aspect",aspect_config);
return parsed_cfg;//in boolean context
}
bool configuration::parse_side_config(const config& original_cfg, config &cfg )
{
LOG_AI_CONFIGURATION << "Parsing [side] configuration from config" << std::endl;
//leave only the [ai] children
cfg = config();
foreach (const config &aiparam, original_cfg.child_range("ai")) {
cfg.add_child("ai",aiparam);
}
DBG_AI_CONFIGURATION << "Config contains:"<< std::endl << cfg << std::endl;
bool new_syntax=false;//@todo 1.8 remove old way when necessary
bool default_config_applied = false;
//check for default config
foreach (const config &aiparam, cfg.child_range("ai")) {
if (aiparam.child("stage")){
new_syntax=true;
if (aiparam.has_attribute("default_config_applied")) {
default_config_applied = true;
break;
}
}
if (new_syntax) {
DBG_AI_CONFIGURATION << "new syntax parsing rules"<< std::endl;
return parse_side_config_new(cfg,ai_algorithm_type,global_ai_parameters,ai_parameters,default_ai_parameters,ai_memory,effective_ai_parameters);
if (!default_config_applied) {
//insert default config at the beginning
if (default_config_) {
LOG_AI_CONFIGURATION << "Applying default configuration" << std::endl;
cfg.add_child_at("ai",default_config_,0);
} else {
WRN_AI_CONFIGURATION << "Default configuration is not available, do not applying it" << std::endl;
}
} else {
DBG_AI_CONFIGURATION << "old syntax parsing rules"<< std::endl;
return parse_side_config_old(cfg,ai_algorithm_type,global_ai_parameters,ai_parameters,default_ai_parameters,ai_memory,effective_ai_parameters);
}
}
bool configuration::parse_side_config_new(const config &cfg,
std::string &ai_algorithm_type,
config &global_ai_parameters,
std::vector<config> &ai_parameters,
const config &default_ai_parameters,
config &ai_memory,
config &effective_ai_parameters )
{
//construct new-style integrated config
ai_parameters.push_back(default_ai_parameters);
global_ai_parameters.append(default_ai_parameters);
global_ai_parameters["ai_algorithm"] = "composite_ai";
DBG_AI_CONFIGURATION << "after taking default values into account, new-style config contains:"<< std::endl << global_ai_parameters << std::endl;
foreach (const config &aiparam, cfg.child_range("ai"))
{
ai_parameters.push_back(aiparam);
global_ai_parameters.append(aiparam);
DBG_AI_CONFIGURATION << "Default configuration already applied" << std::endl;
}
DBG_AI_CONFIGURATION << "finally, new-style config contains:"<< std::endl << global_ai_parameters << std::endl;
ai_algorithm_type = global_ai_parameters["ai_algorithm"];
//AI memory
foreach (const config &aimem, global_ai_parameters.child_range("ai_memory")) {
ai_memory.append(aimem);
}
effective_ai_parameters["number_of_possible_recruits_to_force_recruit"]= global_ai_parameters["number_of_possible_recruits_to_force_recruit"];
effective_ai_parameters["villages_per_scout"] = global_ai_parameters["villages_per_scout"];
effective_ai_parameters["leader_value"] = global_ai_parameters["leader_value"];
effective_ai_parameters["village_value"] = global_ai_parameters["village_value"];
effective_ai_parameters["aggression"] = global_ai_parameters["aggression"];
effective_ai_parameters["caution"] = global_ai_parameters["caution"];
return true;
}
bool configuration::parse_side_config_old(const config& cfg,
std::string& ai_algorithm_type,
config& global_ai_parameters,
std::vector<config>& ai_parameters,
const config& default_ai_parameters,
config& ai_memory,
config& effective_ai_parameters )
{
foreach (const config &aiparam, cfg.child_range("ai"))
{
ai_parameters.push_back(aiparam);
//those AI parameters, which are always active, are also added to global ai parameters
if (aiparam["turns"].empty() && aiparam["time_of_day"].empty()) {
global_ai_parameters.append(aiparam);
//find version
int version = 10600;
foreach (const config &aiparam, cfg.child_range("ai")) {
if (aiparam.has_attribute("version")){
int v = boost::lexical_cast<int>(aiparam["version"]);//@todo 1.7 parse version from more readable form, such as "1.7.3"
if (version<v) {
version = v;
}
}
}
int original_version = version;
//AI memory
foreach (const config &aimem, cfg.child_range("ai_memory")) {
ai_memory.append(aimem);
if (version<10703) {
if (!upgrade_side_config_from_1_07_02_to_1_07_03(cfg)) {
return false;
}
version = 10703;
}
//set some default config values.
//@todo 1.7 later, the entire 'ai parameter/ai memory/ai effective parameter' system should be refactored.
//@todo 1.7 the following can also be rewritten to use a loop and a better version of bind_config_parameter [for each in default parameters T do bind_config_parameter(T,cfg,global_ai_params,defaults) ]
ai_algorithm_type = bind_config_parameter(
cfg["ai_algorithm"],
global_ai_parameters["ai_algorithm"],
default_ai_parameters["ai_algorithm"]);
//construct new-style integrated config
LOG_AI_CONFIGURATION << "Doing final operations on AI config"<< std::endl;
config parsed_cfg = config();
effective_ai_parameters["number_of_possible_recruits_to_force_recruit"] = bind_config_parameter(
cfg["number_of_possible_recruits_to_force_recruit"],
global_ai_parameters["number_of_possible_recruits_to_force_recruit"],
default_ai_parameters["number_of_possible_recruits_to_force_recruit"]);
LOG_AI_CONFIGURATION << "Merging AI configurations"<< std::endl;
foreach (const config &aiparam, cfg.child_range("ai")) {
parsed_cfg.append(aiparam);
}
effective_ai_parameters["villages_per_scout"] = bind_config_parameter(
cfg["villages_per_scout"],
global_ai_parameters["villages_per_scout"],
default_ai_parameters["villages_per_scout"]);
LOG_AI_CONFIGURATION << "Setting config version to "<< version << std::endl;
parsed_cfg["version"] = boost::lexical_cast<std::string>( version );
effective_ai_parameters["leader_value"] = bind_config_parameter(
cfg["leader_value"],
global_ai_parameters["leader_value"],
default_ai_parameters["leader_value"]);
effective_ai_parameters["village_value"] = bind_config_parameter(
cfg["village_value"],
global_ai_parameters["village_value"],
default_ai_parameters["village_value"]);
LOG_AI_CONFIGURATION << "Merging AI aspect with the same id"<< std::endl;
parsed_cfg.merge_children_by_attribute("aspect","id");
effective_ai_parameters["aggression"] = bind_config_parameter(
cfg["aggression"],
global_ai_parameters["aggression"],
default_ai_parameters["aggression"]);
LOG_AI_CONFIGURATION << "Finally, applying [modify_ai] tags to configuration"<< std::endl;
foreach (const config &mod_ai, cfg.child_range("modify_ai")){
//do ai config modification without redeployement
modify_ai_configuration(mod_ai,parsed_cfg);
}
effective_ai_parameters["caution"] = bind_config_parameter(
cfg["caution"],
global_ai_parameters["caution"],
default_ai_parameters["caution"]);
DBG_AI_CONFIGURATION << "After applying [modify_ai] tags, config contains:"<< std::endl << parsed_cfg << std::endl;
LOG_AI_CONFIGURATION << "Done parsing side config"<< std::endl;
cfg = parsed_cfg;
return cfg;//in boolean context
}
bool configuration::upgrade_side_config_from_1_07_02_to_1_07_03(config &cfg)
{
LOG_AI_CONFIGURATION << "Upgrading ai config version from version 1.7.2 to 1.7.3"<< std::endl;
config parsed_cfg = config();
//get values of all aspects
foreach (const well_known_aspect &wka, well_known_aspects) {
upgrade_aspect_config_from_1_07_02_to_1_07_03(cfg,parsed_cfg,wka.name_,wka.was_an_attribute_);
}
//dump the rest of the config into fallback stage
config fallback_stage_cfg;
fallback_stage_cfg["engine"] = "cpp";
fallback_stage_cfg["name"] = "testing_ai_default::fallback";
fallback_stage_cfg["id"] = "fallback";
config fallback_stage_cfg_ai;
bool default_config_applied = false;
foreach (config &aiparam, cfg.child_range("ai")) {
if (aiparam.has_attribute("default_config_applied")) {
default_config_applied = true;
}
if (!aiparam.has_attribute("turns") && !aiparam.has_attribute("time_of_day")) {
foreach (const well_known_aspect &wka, well_known_aspects) {
if (wka.was_an_attribute_) {
aiparam.remove_attribute(wka.name_);
} else {
aiparam.clear_children(wka.name_);
}
}
fallback_stage_cfg_ai.append(aiparam);
}
}
fallback_stage_cfg_ai.clear_children("aspect");//@todo 1.7: cleanup only configs of well-known ai aspects
//move stages to root of the config
foreach (const config &aistage, fallback_stage_cfg_ai.child_range("stage")) {
parsed_cfg.add_child("stage",aistage);
}
fallback_stage_cfg_ai.clear_children("stage");
fallback_stage_cfg.add_child("ai",fallback_stage_cfg_ai);
parsed_cfg.add_child("stage",fallback_stage_cfg);
if (default_config_applied) {
parsed_cfg["default_config_applied"] = "yes";
parsed_cfg.remove_attribute("default_config_applied");
}
cfg = config();
cfg.add_child("ai",parsed_cfg);
DBG_AI_CONFIGURATION << "After upgrade to 1.7.3 syntax, config contains:"<< std::endl << cfg << std::endl;
return cfg;//in boolean context
}
bool configuration::modify_ai_configuration(const config &/*mod_ai*/, config &/*parsed_cfg*/)
{
//@todo 1.7.3 implement
return true;
}
//some default values for the AI parameters following the default values listed
//in the wiki at http://www.wesnoth.org/wiki/AiWML
//@todo 1.7 think about reading this from config
const config& configuration::get_default_ai_parameters(){
static config default_cfg;
if (!default_cfg["init"].empty()) {
return default_cfg;
}
default_cfg["init"] = "true";
default_cfg["ai_algorithm"] = "default_ai";
//A number 0 or higher which determines how many scouts the AI recruits. If 0,
//the AI doesn't recruit scouts to capture villages.
default_cfg["villages_per_scout"] = "4";
//A number 0 or higher which determines how much the AI targets enemy leaders.
default_cfg["leader_value"] = "3.0";
//A number 0 or higher which determines how much the AI tries to capture villages.
default_cfg["village_value"] = "1.0";
//details see in the [AI] tag explaination in the wiki:
//http://www.wesnoth.org/wiki/AiWML#the_.5Bai.5D_tag
default_cfg["aggression"] = "0.5";
//details see in the [AI] tag explaination in the wiki:
//http://www.wesnoth.org/wiki/AiWML#the_.5Bai.5D_tag
default_cfg["caution"] = "0.25";
//number_of_possible_recruits_to_force_recruit: a number higher than 0.0.
//Tells AI to force the leader to move to a keep if it has enough gold to
//recruit the given number of units. If set to 0.0, moving to recruit is disabled.
default_cfg["number_of_possible_recruits_to_force_recruit"] = "3.1";
LOG_AI_CONFIGURATION << "AI default configuration is created" << std::endl;
return default_cfg;
}
} //end of namespace ai

View file

@ -81,7 +81,7 @@ public:
/**
* get side config from file
* @param file the file name to open. follows usual WML convention.
* @param cfg[out] the config to be written from file.
* @param[out] cfg the config to be written from file.
* @return was all ok?
* @retval true success
* @retval false failure
@ -89,60 +89,61 @@ public:
static bool get_side_config_from_file( const std::string& file, config& cfg );
/**
* modify a config of the ai by applying rules in [modify_ai] tag
* @param[in] mod_ai config containing the contents of the [modify_ai] tag
* @param[in][out] cfg ai configuration to modify
* @return was all ok?
* @retval true success, cfg is guaranteed to be valid
* @retval false failure
*/
static bool modify_ai_configuration(const config &mod_ai, config &cfg);
/**
* @deprecated bug-for-bug compatibility with current parameter handling
* @param[in] cfg the config to be read
* @param[out] ai_algorithm_type al algorithm type to be written
* @param[out] global_ai_parameters global AI parameters to be written
* @param[out] ai_parameters vector of [ai] section parameters.
* @param[in] default_ai_parameters default ai parameters to use
* @param[out] ai_memory ai memory to be written
* @param[out] effective_ai_parameters effective ai parameters to be written
* @param[out] parsed_cfg parsed config
* @return was all ok?
* @retval true success
* @retval false failure
*/
static bool parse_side_config(const config& cfg,
std::string& ai_algorithm_type,
config& global_ai_parameters,
std::vector<config>& ai_parameters,
const config& default_ai_parameters,
config& ai_memory,
config& effective_ai_parameters );
static bool parse_side_config(const config& cfg, config &parsed_cfg);
private:
/**
* Upgrade aspect config from version 1.7.2 to version 1.7.3
* @param[in] cfg the config to be read
* @param[out] parsed_cfg parsed config
* @param[in] id id of the aspect to work on
* @param aspect_was_attribute aspect was an attribute, not a [child]
* @return was all ok?
* @retval true success
* @retval false failure
*/
static bool upgrade_aspect_config_from_1_07_02_to_1_07_03(const config& cfg, config& parsed_cfg, const std::string &id, bool aspect_was_attribute = true);
/**
* Same as parse_side_config, new syntax
* Upgrade side config from version 1.7.2 to version 1.7.3
* @param[in] cfg the config to be read
* @param[out] parsed_cfg parsed config
* @return was all ok?
* @retval true success, cfg is guaranteed to be valid
* @retval false failure
*/
static bool parse_side_config_new(const config& cfg,
std::string& ai_algorithm_type,
config& global_ai_parameters,
std::vector<config>& ai_parameters,
const config& default_ai_parameters,
config& ai_memory,
config& effective_ai_parameters );
static bool upgrade_side_config_from_1_07_02_to_1_07_03(config &cfg);
/**
* Same as parse_side_config, old syntax
*/
static bool parse_side_config_old(const config& cfg,
std::string& ai_algorithm_type,
config& global_ai_parameters,
std::vector<config>& ai_parameters,
const config& default_ai_parameters,
config& ai_memory,
config& effective_ai_parameters );
/**
* get default AI parameters
* @return default AI parameters
*/
static const config& get_default_ai_parameters();
private:
typedef std::map<std::string, description> description_map;
static std::map<std::string, description> ai_configurations_;
static description_map ai_configurations_;
static config default_config_;
};

View file

@ -20,6 +20,11 @@
#include "contexts.hpp"
#include "manager.hpp"
#include "composite/aspect.hpp"
#include "composite/engine.hpp"
#include "composite/goal.hpp"
#include "../callable_objects.hpp"
#include "../dialogs.hpp"
#include "../formula.hpp"
@ -89,12 +94,12 @@ void readwrite_context_impl::raise_enemy_attacked() const
attack_result_ptr readwrite_context_impl::execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return actions::execute_attack_action(get_side(),true,attacker_loc,defender_loc,attacker_weapon);
return actions::execute_attack_action(get_side(),true,attacker_loc,defender_loc,attacker_weapon, get_aggression());
}
attack_result_ptr readonly_context_impl::check_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon){
return actions::execute_attack_action(get_side(),false,attacker_loc,defender_loc,attacker_weapon);
return actions::execute_attack_action(get_side(),false,attacker_loc,defender_loc,attacker_weapon, get_aggression());
}
@ -127,23 +132,116 @@ stopunit_result_ptr readonly_context_impl::check_stopunit_action(const map_locat
return actions::execute_stopunit_action(get_side(),false,unit_location,remove_movement,remove_attacks);
}
readonly_context_impl::readonly_context_impl(side_context &context)
: recursion_counter_(context.get_recursion_count()),dstsrc_(),enemy_dstsrc_(),enemy_possible_moves_(),enemy_srcdst_(),possible_moves_(),srcdst_(),avoided_locations_(),move_maps_enemy_valid_(false),move_maps_valid_(false)
template<typename T>
void readonly_context_impl::add_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect <T> > &where)
{
boost::shared_ptr< typesafe_known_aspect <T> > ka_ptr(new typesafe_known_aspect<T>(name,where,aspects_));
known_aspects_.insert(make_pair(name,ka_ptr));
}
readonly_context_impl::readonly_context_impl(side_context &context, const config &cfg)
: cfg_(cfg),
engines_(),
known_aspects_(),
aggression_(),
attack_depth_(),
aspects_(),
avoid_(),
caution_(),
dstsrc_(),enemy_dstsrc_(),
enemy_possible_moves_(),
enemy_srcdst_(),
grouping_(),
goals_(),
leader_goal_(),
leader_value_(),
move_maps_enemy_valid_(false),
move_maps_valid_(false),
number_of_possible_recruits_to_force_recruit_(),
passive_leader_(),
passive_leader_shares_keep_(),
possible_moves_(),
recruitment_ignore_bad_combat_(),
recruitment_ignore_bad_movement_(),
recruitment_pattern_(),
recursion_counter_(context.get_recursion_count()),
scout_village_targeting_(),
simple_targeting_(),
srcdst_(),
support_villages_(),
village_value_(),
villages_per_scout_()
{
init_side_context_proxy(context);
manager::add_gamestate_observer(this);
add_known_aspect("aggression",aggression_);
add_known_aspect("attack_depth",attack_depth_);
add_known_aspect("avoid",avoid_);
add_known_aspect("caution",caution_);
add_known_aspect("grouping",grouping_);
add_known_aspect("leader_goal",leader_goal_);
add_known_aspect("leader_value",leader_value_);
add_known_aspect("number_of_possible_recruits_to_force_recruit",number_of_possible_recruits_to_force_recruit_);
add_known_aspect("passive_leader",passive_leader_);
add_known_aspect("passive_leader_shares_keep",passive_leader_shares_keep_);
add_known_aspect("recruitment_ignore_bad_combat",recruitment_ignore_bad_combat_);
add_known_aspect("recruitment_ignore_bad_movement",recruitment_ignore_bad_movement_);
add_known_aspect("recruitment_pattern",recruitment_pattern_);
add_known_aspect("scout_village_targeting",scout_village_targeting_);
add_known_aspect("simple_targeting",simple_targeting_);
add_known_aspect("support_villages",support_villages_);
add_known_aspect("village_value",village_value_);
add_known_aspect("villages_per_scout",villages_per_scout_);
}
void readonly_context_impl::on_readonly_context_create() {
//init the composite ai engines
foreach(const config &cfg_element, cfg_.child_range("engine")){
engine::parse_engine_from_config(*this,cfg_element,std::back_inserter(engines_));
}
// init the composite ai aspects
foreach(const config &cfg_element, cfg_.child_range("aspect")){
std::vector<aspect_ptr> aspects;
engine::parse_aspect_from_config(*this,cfg_element,cfg_element["id"],std::back_inserter(aspects));
add_aspects(aspects);
}
// init the composite ai goals
foreach(const config &cfg_element, cfg_.child_range("goal")){
engine::parse_goal_from_config(*this,cfg_element,std::back_inserter(get_goals()));
}
}
config readonly_context_impl::to_readonly_context_config() const
{
config cfg;
foreach(const engine_ptr e, engines_) {
cfg.add_child("engine",e->to_config());
}
foreach(const aspect_map::value_type a, aspects_) {
cfg.add_child("aspect",a.second->to_config());
}
foreach(const goal_ptr g, goals_) {
cfg.add_child("goal",g->to_config());
}
cfg["default_config_applied"] = "yes";
return cfg;
}
readonly_context_impl::~readonly_context_impl()
{
manager::remove_gamestate_observer(this);
}
{
manager::remove_gamestate_observer(this);
}
void readonly_context_impl::handle_generic_event(const std::string& /*event_name*/)
{
invalidate_move_maps();
}
{
invalidate_move_maps();
}
bool readwrite_context_impl::recruit(const std::string& unit_name, map_location loc)
@ -431,14 +529,14 @@ map_location readwrite_context_impl::move_unit_partial(map_location from, map_lo
void readonly_context_impl::calculate_possible_moves(std::map<map_location,paths>& res, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement,
const std::set<map_location>* remove_destinations) const
const terrain_filter* remove_destinations) const
{
calculate_moves(get_info().units,res,srcdst,dstsrc,enemy,assume_full_movement,remove_destinations);
}
void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_location,paths>& res, move_map& srcdst,
move_map& dstsrc, bool enemy, bool assume_full_movement,
const std::set<map_location>* remove_destinations,
const terrain_filter* remove_destinations,
bool see_all
) const
{
@ -485,7 +583,7 @@ void readonly_context_impl::calculate_moves(const unit_map& units, std::map<map_
const map_location& src = m->first;
const map_location& dst = dest.curr;
if(remove_destinations != NULL && remove_destinations->count(dst) != 0) {
if(remove_destinations != NULL && remove_destinations->match(dst)) {
continue;
}
@ -587,22 +685,63 @@ void readwrite_context_impl::attack_enemy(const map_location u,
}
const std::set<map_location>& readonly_context_impl::avoided_locations() const
{
if(avoided_locations_.empty()) {
foreach (const config &av, current_team().ai_parameters().child_range("avoid"))
{
foreach (const map_location &loc, parse_location_range(av["x"], av["y"])) {
avoided_locations_.insert(loc);
}
}
if(avoided_locations_.empty()) {
avoided_locations_.insert(map_location());
void readonly_context_impl::add_aspects(std::vector< aspect_ptr > &aspects )
{
foreach (aspect_ptr a, aspects) {
const std::string name = a->get_id();
known_aspect_map::iterator i = known_aspects_.find(name);
if (i != known_aspects_.end()) {
i->second->set(a);
} else {
ERR_AI << "when adding aspects, unknown aspect id["<<name<<"]"<<std::endl;
}
}
}
return avoided_locations_;
const terrain_filter& readonly_context_impl::get_avoid() const
{
if (avoid_) {
return avoid_->get();
}
config cfg;
cfg.add_child("not");
static terrain_filter tf(vconfig(cfg),get_info().units);
return tf;
}
double readonly_context_impl::get_aggression() const
{
if (aggression_) {
return aggression_->get();
}
return 0;
}
int readonly_context_impl::get_attack_depth() const
{
if (attack_depth_) {
return std::max<int>(1,attack_depth_->get()); //@todo 1.7: add minmax filter to attack_depth aspect
}
return 1;
}
const aspect_map& readonly_context_impl::get_aspects() const
{
return aspects_;
}
double readonly_context_impl::get_caution() const
{
if (caution_) {
return caution_->get();
}
return 0;
}
const move_map& readonly_context_impl::get_dstsrc() const
@ -641,6 +780,105 @@ const move_map& readonly_context_impl::get_enemy_srcdst() const
}
engine_ptr readonly_context_impl::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 << "side "<<get_side()<<" : UNABLE TO FIND engine["<<
engine_name <<"]" << std::endl;
DBG_AI << "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 << "side "<<get_side()<<" : UNABLE TO CREATE engine["<<
engine_name <<"] " << std::endl;
DBG_AI << "config snippet contains: " << std::endl << cfg << std::endl;
return engine_ptr();
}
engines_.push_back(new_engine);
return engines_.back();
}
std::string readonly_context_impl::get_grouping() const
{
if (grouping_) {
return grouping_->get();
}
return std::string();
}
const std::vector<goal_ptr>& readonly_context_impl::get_goals() const
{
return goals_;
}
std::vector<goal_ptr>& readonly_context_impl::get_goals()
{
return goals_;
}
config readonly_context_impl::get_leader_goal() const
{
if (leader_goal_) {
return leader_goal_->get();
}
return config();
}
double readonly_context_impl::get_leader_value() const
{
if (leader_value_) {
return leader_value_->get();
}
return 0;
}
double readonly_context_impl::get_number_of_possible_recruits_to_force_recruit() const
{
if (number_of_possible_recruits_to_force_recruit_) {
return number_of_possible_recruits_to_force_recruit_->get();
}
return 0;
}
bool readonly_context_impl::get_passive_leader() const
{
if (passive_leader_) {
return passive_leader_->get();
}
return false;
}
bool readonly_context_impl::get_passive_leader_shares_keep() const
{
if (passive_leader_shares_keep_) {
return passive_leader_shares_keep_->get();
}
return false;
}
const moves_map& readonly_context_impl::get_possible_moves() const
{
if (!move_maps_valid_) {
@ -650,6 +888,51 @@ const moves_map& readonly_context_impl::get_possible_moves() const
}
bool readonly_context_impl::get_recruitment_ignore_bad_combat() const
{
if (recruitment_ignore_bad_combat_) {
return recruitment_ignore_bad_combat_->get();
}
return false;
}
bool readonly_context_impl::get_recruitment_ignore_bad_movement() const
{
if (recruitment_ignore_bad_movement_) {
return recruitment_ignore_bad_movement_->get();
}
return false;
}
const std::vector<std::string> readonly_context_impl::get_recruitment_pattern() const
{
if (recruitment_pattern_) {
return recruitment_pattern_->get();
}
return std::vector<std::string>();
}
double readonly_context_impl::get_scout_village_targeting() const
{
if (scout_village_targeting_) {
return scout_village_targeting_->get();
}
return 1;
}
bool readonly_context_impl::get_simple_targeting() const
{
if (simple_targeting_) {
return simple_targeting_->get();
}
return false;
}
const move_map& readonly_context_impl::get_srcdst() const
{
if (!move_maps_valid_) {
@ -659,9 +942,30 @@ const move_map& readonly_context_impl::get_srcdst() const
}
void readonly_context_impl::invalidate_avoided_locations_cache() const
bool readonly_context_impl::get_support_villages() const
{
avoided_locations_.clear();
if (support_villages_) {
return support_villages_->get();
}
return false;
}
double readonly_context_impl::get_village_value() const
{
if (village_value_) {
return village_value_->get();
}
return 0;
}
int readonly_context_impl::get_villages_per_scout() const
{
if (villages_per_scout_) {
return villages_per_scout_->get();
}
return 0;
}
@ -677,7 +981,7 @@ void readonly_context_impl::recalculate_move_maps() const
dstsrc_ = move_map();
possible_moves_ = moves_map();
srcdst_ = move_map();
calculate_possible_moves(possible_moves_,srcdst_,dstsrc_,false,false,&avoided_locations());
calculate_possible_moves(possible_moves_,srcdst_,dstsrc_,false,false,&get_avoid());
move_maps_valid_ = true;
}
@ -691,5 +995,4 @@ void readonly_context_impl::recalculate_move_maps_enemy() const
move_maps_enemy_valid_ = true;
}
} //of namespace ai

View file

@ -38,11 +38,12 @@ class gamemap;
#pragma warning(disable:4250)
#endif
class terrain_filter;
namespace ai {
class interface;
// recursion counter
class recursion_counter {
public:
@ -123,6 +124,7 @@ public:
*/
virtual int get_recursion_count() const = 0;
};
class readonly_context;
@ -131,6 +133,7 @@ public:
readonly_context(){}
virtual ~readonly_context(){}
virtual readonly_context& get_readonly_context() = 0;
virtual void on_readonly_context_create() = 0;
virtual const team& current_team() const = 0;
virtual void diagnostic(const std::string& msg) = 0;
virtual void log_message(const std::string& msg) = 0;
@ -141,11 +144,11 @@ public:
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 = 0;
const terrain_filter* remove_destinations=NULL) const = 0;
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,
const terrain_filter* remove_destinations=NULL,
bool see_all=false) const = 0;
const virtual game_info& get_info() const = 0;
@ -154,7 +157,24 @@ public:
virtual void raise_user_interact() const = 0;
virtual const std::set<map_location>& avoided_locations() const = 0;
//@note: following part is in alphabetic order
virtual double get_aggression() const = 0;
virtual int get_attack_depth() const = 0;
virtual const aspect_map& get_aspects() const = 0;
virtual void add_aspects(std::vector< aspect_ptr > &aspects ) = 0;
virtual const terrain_filter& get_avoid() const = 0;
virtual double get_caution() const = 0;
virtual const move_map& get_dstsrc() const = 0;
@ -168,14 +188,64 @@ public:
virtual const move_map& get_enemy_srcdst() const = 0;
/**
* get engine by cfg, creating it if it is not created yet but known
*/
virtual engine_ptr get_engine(const config& cfg) = 0;
virtual std::string get_grouping() const = 0;
virtual const std::vector<goal_ptr>& get_goals() const = 0;
virtual std::vector<goal_ptr>& get_goals() = 0;
virtual config get_leader_goal() const = 0;
virtual double get_leader_value() const = 0;
virtual double get_number_of_possible_recruits_to_force_recruit() const = 0;
virtual bool get_passive_leader() const = 0;
virtual bool get_passive_leader_shares_keep() const = 0;
virtual const moves_map& get_possible_moves() const = 0;
virtual bool get_recruitment_ignore_bad_combat() const = 0;
virtual bool get_recruitment_ignore_bad_movement() const = 0;
virtual const std::vector<std::string> get_recruitment_pattern() const = 0;
virtual double get_scout_village_targeting() const = 0;
virtual bool get_simple_targeting() const = 0;
virtual const move_map& get_srcdst() const = 0;
virtual void invalidate_avoided_locations_cache() const = 0;
virtual bool get_support_villages() const = 0;
virtual double get_village_value() const = 0;
virtual int get_villages_per_scout() const = 0;
virtual void invalidate_move_maps() const = 0;
@ -186,27 +256,63 @@ public:
virtual void recalculate_move_maps_enemy() const = 0;
/**
* serialize to config
*/
virtual config to_readonly_context_config() const = 0;
};
class readwrite_context;
class readwrite_context : public virtual readonly_context {
public:
readwrite_context(){}
virtual ~readwrite_context(){}
virtual readwrite_context& get_readwrite_context() = 0;
virtual attack_result_ptr execute_attack_action(const map_location& attacker_loc, const map_location& defender_loc, int attacker_weapon) = 0;
virtual move_result_ptr execute_move_action(const map_location& from, const map_location& to, bool remove_movement=true) = 0;
virtual recruit_result_ptr execute_recruit_action(const std::string& unit_name, const map_location &where = map_location::null_location) = 0;
virtual stopunit_result_ptr execute_stopunit_action(const map_location& unit_location, bool remove_movement = true, bool remove_attacks = false) = 0;
virtual team& current_team_w() = 0;
virtual void attack_enemy(const map_location u, const map_location target, int att_weapon, int def_weapon) = 0;
virtual map_location move_unit(map_location from, map_location to, const moves_map &possible_moves) = 0;
virtual map_location move_unit_partial(map_location from, map_location to, const moves_map &possible_moves) = 0;
virtual bool recruit(const std::string& unit_name, map_location loc=map_location()) = 0;
virtual void raise_unit_recruited() const = 0;
virtual void raise_unit_moved() const = 0;
virtual void raise_enemy_attacked() const = 0;
virtual game_info& get_info_w() = 0;
};
//proxies
@ -241,7 +347,8 @@ public:
return target_->get_side_context();
}
virtual int get_recursion_count(){
virtual int get_recursion_count()
{
return target_->get_recursion_count();
}
@ -270,6 +377,13 @@ public:
return target_->get_readonly_context();
}
virtual void on_readonly_context_create()
{
return target_->on_readonly_context_create();
}
virtual const team& current_team() const
{
return target_->current_team();
@ -308,7 +422,7 @@ public:
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
const terrain_filter* remove_destinations=NULL) const
{
target_->calculate_possible_moves(possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations);
}
@ -316,7 +430,7 @@ public:
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,
const terrain_filter* remove_destinations=NULL,
bool see_all=false) const
{
target_->calculate_moves(units, possible_moves, srcdst, dstsrc, enemy, assume_full_movement, remove_destinations, see_all);
@ -333,17 +447,49 @@ public:
}
virtual const std::set<map_location>& avoided_locations() const
{
return target_->avoided_locations();
}
virtual int get_recursion_count() const
{
return target_->get_recursion_count();
}
//@note: following part is in alphabetic order
virtual double get_aggression() const
{
return target_->get_aggression();
}
virtual int get_attack_depth() const
{
return target_->get_attack_depth();
}
virtual const aspect_map& get_aspects() const
{
return target_->get_aspects();
}
virtual void add_aspects(std::vector< aspect_ptr > &aspects )
{
return target_->add_aspects(aspects);
}
virtual const terrain_filter& get_avoid() const
{
return target_->get_avoid();
}
virtual double get_caution() const
{
return target_->get_caution();
}
virtual const move_map& get_dstsrc() const
{
@ -369,21 +515,117 @@ public:
}
virtual engine_ptr get_engine(const config &cfg)
{
return target_->get_engine(cfg);
}
virtual std::string get_grouping() const
{
return target_->get_grouping();
}
virtual const std::vector<goal_ptr>& get_goals() const
{
return target_->get_goals();
}
virtual std::vector<goal_ptr>& get_goals()
{
return target_->get_goals();
}
virtual config get_leader_goal() const
{
return target_->get_leader_goal();
}
virtual double get_leader_value() const
{
return target_->get_leader_value();
}
virtual double get_number_of_possible_recruits_to_force_recruit() const
{
return target_->get_number_of_possible_recruits_to_force_recruit();
}
virtual bool get_passive_leader() const
{
return target_->get_passive_leader();
}
virtual bool get_passive_leader_shares_keep() const
{
return target_->get_passive_leader_shares_keep();
}
virtual const moves_map& get_possible_moves() const
{
return target_->get_possible_moves();
}
virtual bool get_recruitment_ignore_bad_combat() const
{
return target_->get_recruitment_ignore_bad_combat();
}
virtual bool get_recruitment_ignore_bad_movement() const
{
return target_->get_recruitment_ignore_bad_movement();
}
virtual const std::vector<std::string> get_recruitment_pattern() const
{
return target_->get_recruitment_pattern();
}
virtual const move_map& get_srcdst() const
{
return target_->get_srcdst();
}
virtual void invalidate_avoided_locations_cache() const
virtual double get_scout_village_targeting() const
{
target_->invalidate_avoided_locations_cache();
return target_->get_scout_village_targeting();
}
virtual bool get_simple_targeting() const
{
return target_->get_simple_targeting();
}
virtual bool get_support_villages() const
{
return target_->get_support_villages();
}
virtual double get_village_value() const
{
return target_->get_village_value();
}
virtual int get_villages_per_scout() const
{
return target_->get_villages_per_scout();
}
@ -404,6 +646,12 @@ public:
target_->recalculate_move_maps_enemy();
}
virtual config to_readonly_context_config() const
{
return target_->to_readonly_context_config();
}
private:
readonly_context *target_;
};
@ -559,7 +807,7 @@ public:
/**
* Constructor
*/
readonly_context_impl(side_context &context);
readonly_context_impl(side_context &context, const config &cfg);
/**
@ -578,6 +826,9 @@ public:
}
virtual void on_readonly_context_create();
/** Handle generic event */
virtual void handle_generic_event(const std::string& event_name);
@ -667,13 +918,13 @@ public:
* If true, the function will operate on the
* assumption that all units can move their full
* movement allotment.
* @param remove_destinations a pointer to a set of possible destinations
* @param remove_destinations a pointer to a terrain filter for possible destinations
* to omit.
*/
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;
const terrain_filter* remove_destinations=NULL) const;
/**
* A more fundamental version of calculate_possible_moves which allows the
@ -682,7 +933,7 @@ public:
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,
const terrain_filter* remove_destinations=NULL,
bool see_all=false) const;
@ -697,12 +948,27 @@ public:
void raise_user_interact() const;
virtual const std::set<map_location>& avoided_locations() const;
virtual int get_recursion_count() const;
//@note: following functions are in alphabetic order
virtual double get_aggression() const;
virtual int get_attack_depth() const;
virtual const aspect_map& get_aspects() const;
virtual const terrain_filter& get_avoid() const;
virtual double get_caution() const;
virtual const move_map& get_dstsrc() const;
@ -715,13 +981,61 @@ public:
virtual const move_map& get_enemy_srcdst() const;
virtual engine_ptr get_engine(const config& cfg);
virtual std::string get_grouping() const;
virtual const std::vector<goal_ptr>& get_goals() const;
virtual std::vector<goal_ptr>& get_goals();
virtual double get_number_of_possible_recruits_to_force_recruit() const;
virtual config get_leader_goal() const;
virtual double get_leader_value() const;
virtual bool get_passive_leader() const;
virtual bool get_passive_leader_shares_keep() const;
virtual const moves_map& get_possible_moves() const;
virtual bool get_recruitment_ignore_bad_combat() const;
virtual bool get_recruitment_ignore_bad_movement() const;
virtual const std::vector<std::string> get_recruitment_pattern() const;
virtual double get_scout_village_targeting() const;
virtual bool get_simple_targeting() const;
virtual const move_map& get_srcdst() const;
virtual void invalidate_avoided_locations_cache() const;
virtual bool get_support_villages() const;
virtual double get_village_value() const;
virtual int get_villages_per_scout() const;
virtual void invalidate_move_maps() const;
@ -732,17 +1046,57 @@ public:
virtual void recalculate_move_maps_enemy() const;
virtual void add_aspects(std::vector< aspect_ptr > &aspects);
void on_create();
virtual config to_readonly_context_config() const;
private:
recursion_counter recursion_counter_;
template<typename T>
void add_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect <T> >& where);
const config cfg_;
/**
* AI Support Engines
*/
std::vector< engine_ptr > engines_;
known_aspect_map known_aspects_;
aspect_type<double>::typesafe_ptr aggression_;
aspect_type<int>::typesafe_ptr attack_depth_;
aspect_map aspects_;
mutable aspect_type<terrain_filter>::typesafe_ptr avoid_;
aspect_type<double>::typesafe_ptr caution_;
mutable move_map dstsrc_;
mutable move_map enemy_dstsrc_;
mutable moves_map enemy_possible_moves_;
mutable move_map enemy_srcdst_;
mutable moves_map possible_moves_;
mutable move_map srcdst_;
mutable std::set<map_location> avoided_locations_;
aspect_type< std::string >::typesafe_ptr grouping_;
std::vector< goal_ptr > goals_;
aspect_type< config >::typesafe_ptr leader_goal_;
aspect_type< double >::typesafe_ptr leader_value_;
mutable bool move_maps_enemy_valid_;
mutable bool move_maps_valid_;
aspect_type<double>::typesafe_ptr number_of_possible_recruits_to_force_recruit_;
aspect_type<bool>::typesafe_ptr passive_leader_;
aspect_type<bool>::typesafe_ptr passive_leader_shares_keep_;
mutable moves_map possible_moves_;
aspect_type< bool >::typesafe_ptr recruitment_ignore_bad_combat_;
aspect_type< bool >::typesafe_ptr recruitment_ignore_bad_movement_;
aspect_type< std::vector<std::string> >::typesafe_ptr recruitment_pattern_;
recursion_counter recursion_counter_;
aspect_type< double >::typesafe_ptr scout_village_targeting_;
aspect_type< bool >::typesafe_ptr simple_targeting_;
mutable move_map srcdst_;
aspect_type< bool >::typesafe_ptr support_villages_;
aspect_type< double >::typesafe_ptr village_value_;
aspect_type< int >::typesafe_ptr villages_per_scout_;
};

View file

@ -54,7 +54,8 @@ namespace ai {
typedef util::array<map_location,6> adjacent_tiles_array;
idle_ai::idle_ai(readwrite_context &context) : recursion_counter_(context.get_recursion_count())
idle_ai::idle_ai(readwrite_context &context, const config &cfg)
: cfg_(cfg), recursion_counter_(context.get_recursion_count())
{
init_readwrite_context_proxy(context);
}
@ -75,6 +76,13 @@ void idle_ai::switch_side(side_number side)
set_side(side);
}
config idle_ai::to_config() const
{
return config();
}
int idle_ai::get_recursion_count() const
{
return recursion_counter_.get_count();
@ -91,8 +99,8 @@ void idle_ai::play_turn()
/** Sample ai, with simple strategy. */
class sample_ai : public readwrite_context_proxy, public interface {
public:
sample_ai(readwrite_context &context)
: recursion_counter_(context.get_recursion_count()) {
sample_ai(readwrite_context &context, const config &cfg)
: cfg_(cfg), recursion_counter_(context.get_recursion_count()) {
init_readwrite_context_proxy(context);
}
@ -151,7 +159,7 @@ protected:
if(best_defense != -1) {
move_unit(best_movement.second,best_movement.first,possible_moves);
battle_context bc(get_info().units, best_movement.first, i->first, -1, -1, current_team().aggression());
battle_context bc(get_info().units, best_movement.first, i->first, -1, -1, get_aggression());
attack_enemy(best_movement.first,i->first,
bc.get_attacker_stats().attack_num,
bc.get_defender_stats().attack_num);
@ -213,6 +221,12 @@ protected:
}
config to_config() const
{
return config();
}
bool do_recruitment() {
const std::set<std::string>& options = current_team().recruits();
if (!options.empty()) {
@ -229,6 +243,7 @@ protected:
return false;
}
private:
const config &cfg_;
recursion_counter recursion_counter_;
};
@ -237,8 +252,9 @@ private:
#endif
ai_default::ai_default(default_ai_context &context) :
ai_default::ai_default(default_ai_context &context, const config &cfg) :
game_logic::formula_callable(),
cfg_(cfg),
recursion_counter_(context.get_recursion_count()),
threats_found_(false),
disp_(context.get_info().disp),
@ -268,8 +284,6 @@ void ai_default::switch_side(side_number side){
void ai_default::new_turn()
{
invalidate_attack_depth_cache();
invalidate_avoided_locations_cache();
invalidate_defensive_position_cache();
invalidate_recent_attacks_list();
threats_found_ = false;
@ -294,6 +308,13 @@ int ai_default::get_recursion_count() const
return recursion_counter_.get_count();
}
config ai_default::to_config() const
{
return config();
}
bool ai_default::recruit_usage(const std::string& usage)
{
raise_user_interact();
@ -364,7 +385,9 @@ bool ai_default::recruit_usage(const std::string& usage)
WRN_AI << warning;
// Uncommented until the recruitment limiting macro can be fixed to not trigger this warning.
//lg::wml_error << warning;
return current_team_w().remove_recruitment_pattern_entry(usage);
//@fixme
//return current_team_w().remove_recruitment_pattern_entry(usage);
return false;
}
return false;
}
@ -456,7 +479,7 @@ map_location ai_default::move_unit(map_location from, map_location to, moves_map
const unit_map::const_iterator itor = units_.find(*adj_i);
if(itor != units_.end() && current_team().is_enemy(itor->second.side()) &&
!itor->second.incapacitated()) {
battle_context bc(units_, res, *adj_i, -1, -1, current_team().aggression());
battle_context bc(units_, res, *adj_i, -1, -1, get_aggression());
attack_enemy(res,itor->first,bc.get_attacker_stats().attack_num,bc.get_defender_stats().attack_num);
break;
}
@ -512,7 +535,7 @@ void ai_default::find_threats()
threats_found_ = true;
const config& parms = current_team().ai_parameters();
const config& parms = cfg_;
std::vector<protected_item> items;
@ -589,14 +612,14 @@ void ai_default::evaluate_recruiting_value(const map_location &leader_loc)
recruiting_preferred_ = 0;
return;
}
if (current_team().num_pos_recruits_to_force()< 0.01f)
if (get_number_of_possible_recruits_to_force_recruit()< 0.01f)
{
return;
}
float free_slots = 0.0f;
const float gold = static_cast<float>(current_team().gold());
const float unit_price = static_cast<float>(current_team_w().average_recruit_price());
const float unit_price = static_cast<float>(current_team().average_recruit_price());
if (map_.is_keep(leader_loc))
{
std::set<map_location> checked_hexes;
@ -606,15 +629,15 @@ void ai_default::evaluate_recruiting_value(const map_location &leader_loc)
map_location loc = nearest_keep(leader_loc);
if (units_.find(loc) == units_.end() && gold/unit_price > 1.0f)
{
free_slots -= current_team().num_pos_recruits_to_force();
free_slots -= get_number_of_possible_recruits_to_force_recruit();
}
}
recruiting_preferred_ = (gold/unit_price) - free_slots > current_team().num_pos_recruits_to_force();
recruiting_preferred_ = (gold/unit_price) - free_slots > get_number_of_possible_recruits_to_force_recruit();
DBG_AI << "recruiting preferred: " << (recruiting_preferred_?"yes":"no") <<
" units to recruit: " << (gold/unit_price) <<
" unit_price: " << unit_price <<
" free slots: " << free_slots <<
" limit: " << current_team().num_pos_recruits_to_force() << "\n";
" limit: " << get_number_of_possible_recruits_to_force_recruit() << "\n";
}
void ai_default::do_move()
@ -630,11 +653,11 @@ void ai_default::do_move()
move_map srcdst, dstsrc, enemy_srcdst, enemy_dstsrc;
calculate_possible_moves(possible_moves,srcdst,dstsrc,false,false,&avoided_locations());
calculate_possible_moves(possible_moves,srcdst,dstsrc,false,false,&get_avoid());
calculate_possible_moves(enemy_possible_moves,enemy_srcdst,enemy_dstsrc,true);
const bool passive_leader_shares_keep = utils::string_bool(current_team().ai_parameters()["passive_leader_shares_keep"],false);
const bool passive_leader = utils::string_bool(current_team().ai_parameters()["passive_leader"])||passive_leader_shares_keep;
const bool passive_leader_shares_keep = get_passive_leader_shares_keep();
const bool passive_leader = get_passive_leader()||passive_leader_shares_keep;
unit_map::iterator leader = units_.find_leader(get_side());
@ -815,9 +838,9 @@ bool ai_default::do_combat(std::map<map_location,paths>& possible_moves, const m
if(skip_num > 0 && ((it - analysis.begin())%skip_num) && it->movements.size() > 1)
continue;
const double rating = it->rating(current_team().aggression(),*this);
const double rating = it->rating(get_aggression(),*this);
LOG_AI << "attack option rated at " << rating << " ("
<< current_team().aggression() << ")\n";
<< get_aggression() << ")\n";
if (recruiting_preferred_)
{
@ -857,7 +880,7 @@ bool ai_default::do_combat(std::map<map_location,paths>& possible_moves, const m
}
// Recalc appropriate weapons here: AI uses approximations.
battle_context bc(units_, to, target_loc, -1, -1, current_team().aggression());
battle_context bc(units_, to, target_loc, -1, -1, get_aggression());
attack_enemy(to, target_loc, bc.get_attacker_stats().attack_num,
bc.get_defender_stats().attack_num);
@ -965,7 +988,7 @@ bool ai_default::retreat_units(std::map<map_location,paths>& possible_moves,
move_map fullmove_srcdst;
move_map fullmove_dstsrc;
calculate_possible_moves(dummy_possible_moves, fullmove_srcdst, fullmove_dstsrc,
false, true, &avoided_locations());
false, true, &get_avoid());
map_location leader_adj[6];
if(leader != units_.end()) {
@ -982,7 +1005,7 @@ bool ai_default::retreat_units(std::map<map_location,paths>& possible_moves,
// We see the amount of power of each side on the situation,
// and decide whether it should retreat.
if(should_retreat(i->first, i, fullmove_srcdst, fullmove_dstsrc,
enemy_dstsrc, current_team().caution())) {
enemy_dstsrc, get_caution())) {
bool can_reach_leader = false;
@ -1276,7 +1299,7 @@ int ai_default::compare_unit_types(const unit_type& a, const unit_type& b) const
void ai_default::analyze_potential_recruit_combat()
{
if(unit_combat_scores_.empty() == false ||
utils::string_bool(current_team().ai_parameters()["recruitment_ignore_bad_combat"])) {
get_recruitment_ignore_bad_combat()) {
return;
}
@ -1357,7 +1380,7 @@ private:
void ai_default::analyze_potential_recruit_movements()
{
if(unit_movement_scores_.empty() == false ||
utils::string_bool(current_team().ai_parameters()["recruitment_ignore_bad_movement"])) {
get_recruitment_ignore_bad_movement()) {
return;
}
@ -1474,9 +1497,9 @@ bool ai_default::do_recruitment()
// Let formula ai to do recruiting first
if (get_recursion_count()<recursion_counter::MAX_COUNTER_VALUE)
{
if (!current_team().ai_parameters()["recruitment"].empty()){
if (!cfg_["recruitment"].empty()){
if (!formula_ai_){
formula_ai_ptr_ = (manager::create_transient_ai(manager::AI_TYPE_FORMULA_AI, this));
formula_ai_ptr_ = manager::create_transient_ai(manager::AI_TYPE_FORMULA_AI, cfg_,this);
formula_ai_ = static_cast<formula_ai*> (formula_ai_ptr_.get());
}
@ -1494,7 +1517,7 @@ bool ai_default::do_recruitment()
analyze_potential_recruit_movements();
analyze_potential_recruit_combat();
std::vector<std::string> options = current_team().recruitment_pattern();
std::vector<std::string> options = get_recruitment_pattern();
if (std::count(options.begin(), options.end(), "scout") > 0) {
size_t neutral_villages = 0;
@ -1527,7 +1550,7 @@ bool ai_default::do_recruitment()
// accounting for all neutral villages on the map.
// We only look at villages closer to us, so we halve it,
// making us get twice as many scouts.
const int villages_per_scout = current_team().villages_per_scout()/2;
const int villages_per_scout = get_villages_per_scout()/2;
// Get scouts depending on how many neutral villages there are.
int scouts_wanted = villages_per_scout > 0 ? neutral_villages/villages_per_scout : 0;
@ -1563,7 +1586,7 @@ bool ai_default::do_recruitment()
bool ret = false;
while (recruit_usage(options[rand()%options.size()])) {
ret = true;
options = current_team().recruitment_pattern();
options = get_recruitment_pattern();
if (options.empty()) {
options.push_back("");
}
@ -1574,7 +1597,7 @@ bool ai_default::do_recruitment()
void ai_default::move_leader_to_goals( const move_map& enemy_dstsrc)
{
const config &goal = current_team().ai_parameters().child("leader_goal");
const config &goal = get_leader_goal();
if (!goal) {
LOG_AI << "No goal found\n";
@ -1636,8 +1659,8 @@ void ai_default::move_leader_after_recruit(const move_map& /*srcdst*/,
return;
}
const bool passive_leader_shares_keep = utils::string_bool(current_team().ai_parameters()["passive_leader_shares_keep"],false);
const bool passive_leader = utils::string_bool(current_team().ai_parameters()["passive_leader"])||passive_leader_shares_keep;
const bool passive_leader_shares_keep = get_passive_leader_shares_keep();
const bool passive_leader = get_passive_leader()||passive_leader_shares_keep;
const paths leader_paths(map_, units_, leader->first,
teams_, false, false, current_team());
@ -1740,7 +1763,7 @@ void ai_default::move_leader_after_recruit(const move_map& /*srcdst*/,
std::map<map_location,paths> dummy_possible_moves;
move_map fullmove_srcdst;
move_map fullmove_dstsrc;
calculate_possible_moves(dummy_possible_moves,fullmove_srcdst,fullmove_dstsrc,false,true,&avoided_locations());
calculate_possible_moves(dummy_possible_moves,fullmove_srcdst,fullmove_dstsrc,false,true,&get_avoid());
if (should_retreat(leader->first, leader, fullmove_srcdst, fullmove_dstsrc, enemy_dstsrc, 0.5)) {
desperate_attack(leader->first);

View file

@ -40,13 +40,15 @@ namespace ai {
/** A trivial ai that sits around doing absolutely nothing. */
class idle_ai : public readwrite_context_proxy, public interface {
public:
idle_ai(readwrite_context &context);
idle_ai(readwrite_context &context, const config &cfg);
void play_turn();
void new_turn();
virtual std::string describe_self();
void switch_side(side_number side);
int get_recursion_count() const;
virtual config to_config() const;
private:
const config &cfg_;
recursion_counter recursion_counter_;
};
@ -54,12 +56,13 @@ class ai_default : public virtual default_ai_context_proxy, public interface, pu
public:
typedef map_location location;//will get rid of this later
ai_default(default_ai_context &context);
ai_default(default_ai_context &context, const config &cfg);
virtual ~ai_default();
virtual void play_turn();
virtual void new_turn();
virtual std::string describe_self();
virtual config to_config() const;
void switch_side(side_number side);
struct target {
@ -79,6 +82,7 @@ public:
/** get the recursion counter */
int get_recursion_count() const;
private:
const config &cfg_;
recursion_counter recursion_counter_;
protected:

View file

@ -273,7 +273,7 @@ double attack_analysis::rating(double aggression, default_ai_context& ai_obj) co
const double exposure_mod = uses_leader ? ai_obj.current_team().caution()* 8.0 : ai_obj.current_team().caution() * 4.0;
const double exposure = exposure_mod*resources_used*((terrain_quality - alternative_terrain_quality)/10)*vulnerability/std::max<double>(0.01,support);
#else
const double exposure_mod = uses_leader ? 2.0 : ai_obj.current_team().caution();
const double exposure_mod = uses_leader ? 2.0 : ai_obj.get_caution();
const double exposure = exposure_mod*resources_used*(terrain_quality - alternative_terrain_quality)*vulnerability/std::max<double>(0.01,support);
#endif
LOG_AI << "attack option has base value " << value << " with exposure " << exposure << ": "

View file

@ -131,18 +131,6 @@ bool default_ai_context_impl::attack_close(const map_location& loc) const
}
int default_ai_context_impl::attack_depth()
{
if(attack_depth_ > 0) {
return attack_depth_;
}
const config& parms = current_team().ai_parameters();
attack_depth_ = std::max<int>(1,lexical_cast_default<int>(parms["attack_depth"],5));
return attack_depth_;
}
default_ai_context_impl::~default_ai_context_impl()
{
}
@ -246,8 +234,8 @@ void default_ai_context_impl::do_attack_analysis(
// This function is called fairly frequently, so interact with the user here.
raise_user_interact();
if(cur_analysis.movements.size() >= size_t(attack_depth())) {
//std::cerr << "ANALYSIS " << cur_analysis.movements.size() << " >= " << attack_depth() << "\n";
if(cur_analysis.movements.size() >= size_t(get_attack_depth())) {
//std::cerr << "ANALYSIS " << cur_analysis.movements.size() << " >= " << get_attack_depth() << "\n";
return;
}
gamemap &map_ = get_info().map;
@ -268,7 +256,7 @@ void default_ai_context_impl::do_attack_analysis(
}
const double cur_rating = cur_analysis.movements.empty() ? -1.0 :
cur_analysis.rating(current_team().aggression(),*this);
cur_analysis.rating(get_aggression(),*this);
double rating_to_beat = cur_rating;
@ -469,13 +457,13 @@ void default_ai_context_impl::do_attack_analysis(
cur_analysis.is_surrounded = is_surrounded;
cur_analysis.analyze(map_, units_, *this, dstsrc, srcdst, enemy_dstsrc, current_team().aggression());
cur_analysis.analyze(map_, units_, *this, dstsrc, srcdst, enemy_dstsrc, get_aggression());
//This logic to sometimes not add the attack because it doesn't
//rate high enough seems to remove attacks from consideration
//that should not be removed, so it has been removed.
// -- David.
// if(cur_analysis.rating(current_team().aggression(),*this) > rating_to_beat) {
// if(cur_analysis.rating(get_aggression(),*this) > rating_to_beat) {
result.push_back(cur_analysis);
used_locations[cur_position] = true;
@ -501,11 +489,6 @@ default_ai_context& default_ai_context_impl::get_default_ai_context(){
}
void default_ai_context_impl::invalidate_attack_depth_cache(){
attack_depth_ = 0;
}
void default_ai_context_impl::invalidate_defensive_position_cache()
{
defensive_position_cache_.clear();

View file

@ -176,9 +176,6 @@ public:
virtual default_ai_context& get_default_ai_context() = 0;
virtual void invalidate_attack_depth_cache() = 0;
virtual void invalidate_defensive_position_cache() = 0;
@ -302,12 +299,6 @@ public:
void init_default_ai_context_proxy(default_ai_context &target);
virtual void invalidate_attack_depth_cache()
{
target_->invalidate_attack_depth_cache();
}
void invalidate_defensive_position_cache()
{
return target_->invalidate_defensive_position_cache();
@ -396,9 +387,6 @@ public:
bool attack_close(const map_location& loc) const;
int attack_depth();
int count_free_hexes_in_castle(const map_location& loc, std::set<map_location> &checked_hexes);
@ -408,7 +396,7 @@ public:
default_ai_context_impl(readwrite_context &context)
: recursion_counter_(context.get_recursion_count()),unit_stats_cache_(),
defensive_position_cache_(),attacks_(),keeps_(),attack_depth_()
defensive_position_cache_(),attacks_(),keeps_()
{
init_readwrite_context_proxy(context);
}
@ -438,9 +426,6 @@ public:
}
virtual void invalidate_attack_depth_cache();
virtual void invalidate_defensive_position_cache();
@ -488,8 +473,6 @@ private:
std::set<map_location> keeps_;
int attack_depth_;
};
} //end of namespace ai

View file

@ -21,11 +21,13 @@
#include "../../global.hpp"
#include "ai.hpp"
#include "../composite/goal.hpp"
#include "../../foreach.hpp"
#include "../../gettext.hpp"
#include "../../log.hpp"
#include "../../map.hpp"
#include "../../terrain_filter.hpp"
#include "../../wml_exception.hpp"
@ -100,7 +102,7 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
const bool has_leader = leader != units_.end();
std::vector<target> targets;
std::vector<ai_default::target> targets;
std::map<location,paths> friends_possible_moves;
move_map friends_srcdst, friends_dstsrc;
@ -129,8 +131,8 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
assert(threats.empty() == false);
#ifdef SUOKKO
//FIXME: sukko's veraion 29531 included this change. Correct?
const double value = threat*lexical_cast_default<double>(current_team().ai_parameters()["protect_leader"], 3.0)/leader->second.hitpoints();
//FIXME: suokko's revision 29531 included this change. Correct?
const double value = threat*get_protect_leader()/leader->second.hitpoints();
#else
const double value = threat/double(threats.size());
#endif
@ -142,8 +144,8 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
}
double corner_distance = distance_between(map_location(0,0), map_location(map_.w(),map_.h()));
double village_value = current_team().village_value();
if(has_leader && current_team().village_value() > 0.0) {
double village_value = get_village_value();
if(has_leader && get_village_value() > 0.0) {
const std::vector<location>& villages = map_.villages();
for(std::vector<location>::const_iterator t =
villages.begin(); t != villages.end(); ++t) {
@ -162,7 +164,7 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
{
//Support seems to cause the AI to just 'sit around' a lot, so
//only turn it on if it's explicitly enabled.
if(utils::string_bool(current_team().ai_parameters()["support_villages"])) {
if(get_support_villages()) {
double enemy = power_projection(*t, enemy_dstsrc);
if (enemy > 0)
{
@ -185,7 +187,7 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
}
}
std::vector<team::target>& team_targets = current_team_w().targets();
std::vector<goal_ptr>& goals = get_goals();
//find the enemy leaders and explicit targets
unit_map::const_iterator u;
@ -195,18 +197,20 @@ std::vector<ai_default::target> ai_default::find_targets(unit_map::const_iterato
if (u->second.can_recruit() && current_team().is_enemy(u->second.side())
&& !u->second.invisible(u->first, units_, teams_)) {
assert(map_.on_board(u->first));
LOG_AI << "found enemy leader (side: " << u->second.side() << ") target... " << u->first << " with value: " << current_team().leader_value() << "\n";
targets.push_back(target(u->first,current_team().leader_value(),target::LEADER));
LOG_AI << "found enemy leader (side: " << u->second.side() << ") target... " << u->first << " with value: " << get_leader_value() << "\n";
targets.push_back(target(u->first,get_leader_value(),target::LEADER));
}
//explicit targets for this team
for(std::vector<team::target>::iterator j = team_targets.begin();
j != team_targets.end(); ++j) {
if (u->second.matches_filter(vconfig(j->criteria), u->first)) {
LOG_AI << "found explicit target... " << u->first << " with value: " << j->value << "\n";
targets.push_back(target(u->first,j->value,target::EXPLICIT));
for(std::vector<goal_ptr>::iterator j = goals.begin();
j != goals.end(); ++j) {
if ((*j)->matches_unit(u)) {
LOG_AI << "found explicit target... " << u->first << " with value: " << (*j)->value() << "\n";
targets.push_back(target(u->first,(*j)->value(),target::EXPLICIT));
}
}
}
std::vector<double> new_values;
@ -471,7 +475,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
//choose the best target for that unit
for(std::vector<target>::iterator tg = targets.begin(); tg != targets.end(); ++tg) {
if(avoided_locations().count(tg->loc) > 0) {
if(get_avoid().match(tg->loc)) {
continue;
}
LOG_AI << "Considering target at: " << tg->loc <<"\n";
@ -532,13 +536,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
//scouts also get a bonus for going after villages
if(tg->type == target::VILLAGE) {
if(current_team().ai_parameters().has_attribute("scout_village_targetting")) {
rating *= lexical_cast_default<int>(current_team().ai_parameters()["scout_village_targetting"],3);
lg::wml_error << "[ai_default] the 'scout_village_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'scout_village_targeting' instead\n";
}
else {
rating *= lexical_cast_default<int>(current_team().ai_parameters()["scout_village_targeting"],3);
}
rating *= get_scout_village_targeting();
}
}
@ -555,7 +553,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
}
}
LOG_AI << "chose target...\n";
LOG_AI << "choose target...\n";
if(best_target == targets.end()) {
@ -566,17 +564,9 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
//if we have the 'simple_targeting' flag set, then we don't
//see if any other units can put a better bid forward for this
//target
bool simple_targeting = false;
if(current_team().ai_parameters().has_attribute("simple_targetting")) {
simple_targeting = utils::string_bool(current_team().ai_parameters()["simple_targetting"]);
lg::wml_error << "[ai_default] the 'simple_targetting' attribute is deprecated, support will be removed in version 1.7.0; use 'simple_targeting' instead\n";
}
else {
simple_targeting = utils::string_bool(current_team().ai_parameters()["simple_targeting"]);
}
const bool& dumb_ai = simple_targeting;
bool simple_targeting = get_simple_targeting();
if(dumb_ai == false) {
if(simple_targeting == false) {
LOG_AI << "complex targeting...\n";
//now see if any other unit can put a better bid forward
for(++u; u != units_.end(); ++u) {
@ -666,7 +656,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
for(std::vector<location>::const_iterator i = locs.begin(); i != locs.end(); ++i) {
const int distance = distance_between(*i,best_target->loc);
const int defense = best->second.defense_modifier(map_.get_terrain(*i));
//FIXME: suokko multiplied by 10 * current_team().caution(). ?
//FIXME: suokko multiplied by 10 * get_caution(). ?
const double vulnerability = power_projection(*i,enemy_dstsrc);
if(best_loc.valid() == false || defense < best_defense || (defense == best_defense && vulnerability < best_vulnerability)) {
@ -689,19 +679,19 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
bool dangerous = false;
if(current_team().ai_parameters()["grouping"] != "no") {
if(get_grouping() != "no") {
LOG_AI << "grouping...\n";
const unit_map::const_iterator unit_at_target = units_.find(best_target->loc);
int movement = best->second.movement_left();
const bool defensive_grouping = current_team().ai_parameters()["grouping"] == "defensive";
const bool defensive_grouping = get_grouping() == "defensive";
//we stop and consider whether the route to this
//target is dangerous, and whether we need to group some units to move in unison toward the target
//if any point along the path is too dangerous for our single unit, then we hold back
for(std::vector<location>::const_iterator i = best_route.steps.begin(); i != best_route.steps.end() && movement > 0; ++i) {
//FIXME: suokko multiplied by 10 * current_team().caution(). ?
//FIXME: suokko multiplied by 10 * get_caution(). ?
const double threat = power_projection(*i,enemy_dstsrc);
//FIXME: sukko doubled the power-projection them in the second test. ?
if((threat >= double(best->second.hitpoints()) && threat > power_projection(*i,fullmove_dstsrc)) ||
@ -726,7 +716,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
const double our_strength = compare_groups(group,enemies,best_route.steps);
if(our_strength > 0.5 + current_team().caution()) {
if(our_strength > 0.5 + get_caution()) {
LOG_AI << "moving group\n";
const bool res = move_group(dst,best_route.steps,group);
if(res) {
@ -762,7 +752,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
for(move_map::const_iterator i = itors.first; i != itors.second; ++i) {
const int distance = distance_between(target_loc,i->second);
const int defense = un.defense_modifier(map_.get_terrain(i->second));
//FIXME: suokko multiplied by 10 * current_team().caution(). ?
//FIXME: suokko multiplied by 10 * get_caution(). ?
const double threat = (power_projection(i->second,enemy_dstsrc)*defense)/100;
if(best_loc.valid() == false || (threat < std::max<double>(best_threat,max_acceptable_threat) && distance < best_distance)) {
@ -804,7 +794,7 @@ std::pair<map_location,map_location> ai_default::choose_move(std::vector<target>
while(its.first != its.second) {
if(its.first->second == best->first) {
if(!should_retreat(its.first->first,best,fullmove_srcdst,fullmove_dstsrc,enemy_dstsrc,
current_team().caution())) {
get_caution())) {
const double value = best_target->value - best->second.cost()/20.0;
if(value > 0.0 && best_target->type != target::MASS) {

View file

@ -267,8 +267,7 @@ void ai_default::find_villages(
{
std::map<location, double> vulnerability;
const bool passive_leader = recruiting_preferred_ ||
utils::string_bool(current_team().ai_parameters()["passive_leader"]);
const bool passive_leader = recruiting_preferred_ || get_passive_leader();
size_t min_distance = 100000;

View file

@ -31,8 +31,7 @@ static lg::log_domain log_ai("ai/dfool");
void dfool_ai::play_turn(){
int team_num = get_side();
const config& parms = current_team().ai_parameters();
config ai_mem = current_team().ai_memory();
const config& parms = cfg_;
LOG_AI << "dfool side:" << team_num << " of " << current_team().nteams() << '\n';
@ -182,8 +181,7 @@ static lg::log_domain log_ai("ai/dfool");
}
}
unit_memory_.write(ai_mem);
current_team_w().set_ai_memory(ai_mem);
//unit_memory_.write(ai_mem);
return;
}

View file

@ -112,8 +112,8 @@ namespace dfool {
*/
class dfool_ai : public default_ai_context_proxy, public interface {
public:
dfool_ai(default_ai_context &context)
: recursion_counter_(context.get_recursion_count()), unit_memory_(context.current_team().ai_memory())
dfool_ai(default_ai_context &context, const config &cfg)
: cfg_(cfg), recursion_counter_(context.get_recursion_count()), unit_memory_(config())
{
init_default_ai_context_proxy(context);
}
@ -125,7 +125,14 @@ namespace dfool {
virtual void new_turn()
{
}
private:
virtual config to_config() const{
return config();
}
private:
const config &cfg_;
recursion_counter recursion_counter_;
// std::map<std::string,target> target_map_;
unit_list all_units();

View file

@ -55,8 +55,9 @@ int formula_ai::get_recursion_count() const{
}
formula_ai::formula_ai(ai::default_ai_context &context) :
ai_default(context),
formula_ai::formula_ai(ai::default_ai_context &context, const config &cfg) :
ai_default(context,cfg),
cfg_(cfg),
recursion_counter_(context.get_recursion_count()),
recruit_formula_(),
move_formula_(),
@ -313,7 +314,7 @@ variant formula_ai::make_action(game_logic::const_formula_ptr formula_, const ga
if(!formula_) {
if(get_recursion_count()<ai::recursion_counter::MAX_COUNTER_VALUE) {
LOG_AI << "Falling back to default AI.\n";
ai::ai_ptr fallback( ai::manager::create_transient_ai(ai::manager::AI_TYPE_DEFAULT, this));
ai::ai_ptr fallback( ai::manager::create_transient_ai(ai::manager::AI_TYPE_DEFAULT, config(), this));
if (fallback){
fallback->play_turn();
}
@ -686,7 +687,7 @@ variant formula_ai::execute_variant(const variant& var, bool commandline)
} else
{
LOG_AI << "Explicit fallback to: " << fallback_command->key() << std::endl;
ai::ai_ptr fallback( ai::manager::create_transient_ai(fallback_command->key(), this));
ai::ai_ptr fallback( ai::manager::create_transient_ai(fallback_command->key(), config(), this));
if(fallback) {
fallback->play_turn();
}
@ -1065,7 +1066,7 @@ bool formula_ai::can_reach_unit(map_location unit_A, map_location unit_B) const
void formula_ai::on_create(){
//make sure we don't run out of refcount
vars_.add_ref();
const config& ai_param = current_team().ai_parameters();
const config& ai_param = cfg_;
// load candidate actions from config
candidate_action_manager_.load_config(ai_param, this, &function_table);
@ -1091,7 +1092,7 @@ void formula_ai::on_create(){
try{
recruit_formula_ = game_logic::formula::create_optional_formula(current_team().ai_parameters()["recruitment"], &function_table);
recruit_formula_ = game_logic::formula::create_optional_formula(cfg_["recruitment"], &function_table);
}
catch(formula_error& e) {
handle_exception(e);
@ -1099,7 +1100,7 @@ void formula_ai::on_create(){
}
try{
move_formula_ = game_logic::formula::create_optional_formula(current_team().ai_parameters()["move"], &function_table);
move_formula_ = game_logic::formula::create_optional_formula(cfg_["move"], &function_table);
}
catch(formula_error& e) {
handle_exception(e);
@ -1164,3 +1165,8 @@ bool formula_ai::gamestate_change_observer::continue_check() {
continue_counter_++;
return true;
}
config formula_ai::to_config() const
{
return cfg_;//@todo 1.7 add a proper serialization
}

View file

@ -54,11 +54,12 @@ typedef std::multiset< unit_formula_pair, game_logic::unit_formula_compare > uni
class formula_ai : public ai::ai_default {
public:
explicit formula_ai(ai::default_ai_context &context);
explicit formula_ai(ai::default_ai_context &context, const config &cfg);
virtual ~formula_ai() {};
virtual void play_turn();
virtual void new_turn();
virtual std::string describe_self();
virtual config to_config() const;
typedef ai::move_map move_map;
@ -134,6 +135,7 @@ public:
bool execute_candidate_action(game_logic::candidate_action_ptr fai_ca);
private:
const config &cfg_;
ai::recursion_counter recursion_counter_;
void display_message(const std::string& msg) const;
bool do_recruitment();

View file

@ -72,7 +72,7 @@ bool candidate_action_manager::evaluate_candidate_actions(formula_ai* ai, unit_m
}
if( evaluated_candidate_actions_.empty() ||
(*evaluated_candidate_actions_.begin())->get_score() <= 0 ) //@note ai::composite_ai::candidate_action::BAD_SCORE )
(*evaluated_candidate_actions_.begin())->get_score() <= 0 ) //@note ai::candidate_action::BAD_SCORE )
return false;
return true;

View file

@ -48,6 +48,39 @@ class interface;
typedef boost::shared_ptr< interface > ai_ptr;
class aspect;
class candidate_action;
class engine;
class goal;
class known_aspect;
class stage;
template<typename T>
class typesafe_aspect;
template<typename T>
struct aspect_type {
typedef boost::shared_ptr< typesafe_aspect<T> > typesafe_ptr;
};
template<typename T>
class typesafe_known_aspect;
template<typename T>
struct known_aspect_type {
typedef boost::shared_ptr< typesafe_known_aspect<T> > typesafe_ptr;
};
typedef boost::shared_ptr< aspect > aspect_ptr;
typedef boost::shared_ptr< candidate_action > candidate_action_ptr;
typedef boost::shared_ptr< engine > engine_ptr;
typedef boost::shared_ptr< goal > goal_ptr;
typedef boost::shared_ptr< known_aspect > known_aspect_ptr;
typedef boost::shared_ptr< stage > stage_ptr;
typedef std::map<std::string, aspect_ptr > aspect_map;
typedef std::map<std::string, known_aspect_ptr > known_aspect_map;
class game_info {
public:

View file

@ -30,15 +30,20 @@
namespace ai {
class interface {
class interface : savegame_config {
public:
/**
* The constructor.
*/
interface() {
interface()
: savegame_config()
{
}
virtual ~interface() {}
/**
* Function that is called when the AI must play its turn.
* Derived classes should implement their AI algorithm in this function.
@ -66,6 +71,9 @@ public:
/** Describe self*/
virtual std::string describe_self() const;
/** serialize to config **/
virtual config to_config() const = 0;
};
class ai_factory;
@ -85,7 +93,7 @@ public:
}
/* cfg is commented out so far, because ai parameter handling is a mess atm */
virtual ai_ptr get_new_instance( default_ai_context &context/*, const config &cfg*/) = 0;
virtual ai_ptr get_new_instance( default_ai_context &context, const config &cfg) = 0;
ai_factory( const std::string &name )
{
@ -105,8 +113,8 @@ public:
{
}
virtual ai_ptr get_new_instance( default_ai_context &context/*, const config &cfg*/){
ai_ptr a(new AI(context));
virtual ai_ptr get_new_instance( default_ai_context &context, const config &cfg){
ai_ptr a(new AI(context,cfg));
a->on_create();
return a;
}

View file

@ -53,8 +53,8 @@ static lg::log_domain log_ai_manager("ai/manager");
#define LOG_AI_MANAGER LOG_STREAM(info, log_ai_manager)
#define ERR_AI_MANAGER LOG_STREAM(err, log_ai_manager)
holder::holder( side_number side, const std::string& ai_algorithm_type )
: ai_(), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), default_ai_context_(NULL), ai_algorithm_type_(ai_algorithm_type), ai_effective_parameters_(), ai_global_parameters_(), ai_memory_(), ai_parameters_(), side_(side)
holder::holder( side_number side, const config &cfg )
: ai_(), side_context_(NULL), readonly_context_(NULL), readwrite_context_(NULL), default_ai_context_(NULL), side_(side), cfg_(cfg)
{
DBG_AI_MANAGER << describe_ai() << "Preparing new AI holder" << std::endl;
}
@ -62,29 +62,31 @@ holder::holder( side_number side, const std::string& ai_algorithm_type )
void holder::init( side_number side )
{
LOG_AI_MANAGER << describe_ai() << "Preparing to create new managed master AI" << std::endl;
if (side_context_ == NULL) {
side_context_ = new side_context_impl(side);
side_context_ = new side_context_impl(side);//@todo 1.7.3 add config
} else {
side_context_->set_side(side);
}
if (readonly_context_ == NULL){
readonly_context_ = new readonly_context_impl(*side_context_);
readonly_context_ = new readonly_context_impl(*side_context_,cfg_);
readonly_context_->on_readonly_context_create();
}
if (readwrite_context_ == NULL){
readwrite_context_ = new readwrite_context_impl(*readonly_context_);
readwrite_context_ = new readwrite_context_impl(*readonly_context_);//@todo 1.7.3 add config
}
if (default_ai_context_ == NULL){
default_ai_context_ = new default_ai_context_impl(*readwrite_context_);
default_ai_context_ = new default_ai_context_impl(*readwrite_context_);//@todo 1.7.3 add config
}
if (!this->ai_){
ai_ = boost::shared_ptr<ai_composite>(new ai_composite(*default_ai_context_,cfg_));
ai_->on_create();
}
this->ai_ = create_ai(side);
if (!this->ai_) {
ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!" << std::endl;
}
}
holder::~holder()
{
if (this->ai_) {
@ -113,74 +115,26 @@ interface& holder::get_ai_ref()
}
const std::string& holder::get_ai_algorithm_type() const
config holder::to_config() const
{
return this->ai_algorithm_type_;
if (!this->ai_) {
return cfg_;
} else {
config cfg = ai_->to_config();
if (this->readonly_context_) {
cfg.merge_with(this->readonly_context_->to_readonly_context_config());
}
return cfg;//@todo 1.7.3: include all other upper contexts
}
}
config& holder::get_ai_memory()
{
return this->ai_memory_;
}
std::vector<config>& holder::get_ai_parameters()
{
return this->ai_parameters_;
}
void holder::set_ai_parameters( const std::vector<config>& ai_parameters )
{
this->ai_parameters_ = ai_parameters;
DBG_AI_MANAGER << describe_ai() << "AI parameters are set." << std::endl;
}
config& holder::get_ai_effective_parameters()
{
return this->ai_effective_parameters_;
}
void holder::set_ai_effective_parameters( const config& ai_effective_parameters )
{
this->ai_effective_parameters_ = ai_effective_parameters;
DBG_AI_MANAGER << describe_ai() << "AI effective parameters are set." << std::endl;
}
config& holder::get_ai_global_parameters()
{
return this->ai_global_parameters_;
}
void holder::set_ai_global_parameters( const config& ai_global_parameters )
{
this->ai_global_parameters_ = ai_global_parameters;
DBG_AI_MANAGER << describe_ai() << "AI global parameters are set." << std::endl;
}
void holder::set_ai_memory( const config& ai_memory )
{
this->ai_memory_ = ai_memory;
DBG_AI_MANAGER << describe_ai() << "AI memory is set." << std::endl;
}
void holder::set_ai_algorithm_type( const std::string& ai_algorithm_type ){
this->ai_algorithm_type_ = ai_algorithm_type;
DBG_AI_MANAGER << describe_ai() << "AI algorithm type is set to '"<< ai_algorithm_type_<< "'" << std::endl;
}
const std::string holder::describe_ai()
{
std::string sidestr;
//@todo 1.7 extract side naming to separate static function
//@todo 1.7.3 refactor the command ai role
if (this->side_ == manager::AI_TEAM_FALLBACK_AI){
sidestr = "'fallback_side'";
} else if (this->side_ == manager::AI_TEAM_COMMAND_AI){
@ -191,23 +145,14 @@ const std::string holder::describe_ai()
if (this->ai_!=NULL) {
return this->ai_->describe_self()+std::string(" for side ")+sidestr+std::string(" : ");
} else {
return std::string("[")+this->ai_algorithm_type_+std::string("] (not initialized) for side ")+sidestr+std::string(" : ");
return std::string("[")+cfg_["ai_algorithm"]+std::string("] (not initialized) for side ")+sidestr+std::string(" : ");
}
}
bool holder::is_mandate_ok()
{
DBG_AI_MANAGER << describe_ai() << "AI mandate is ok" << std::endl;
return true;
}
ai_ptr holder::create_ai( side_number side )
const std::string holder::get_ai_identifier() const
{
assert (side > 0);
assert (default_ai_context_!=NULL);
//@note: ai_params, contexts, and ai_algorithm_type are supposed to be set before calling init( );
return manager::create_transient_ai(ai_algorithm_type_,default_ai_context_);
return cfg_["id"];
}
// =======================================================================
@ -375,7 +320,7 @@ void manager::add_turn_started_observer( events::observer* event_observer )
}
void manager::delete_user_interact_observer( events::observer* event_observer )
void manager::remove_user_interact_observer( events::observer* event_observer )
{
user_interact_.detach_handler(event_observer);
}
@ -387,25 +332,25 @@ void manager::delete_sync_network_observer( events::observer* event_observer )
}
void manager::delete_unit_recruited_observer( events::observer* event_observer )
void manager::remove_unit_recruited_observer( events::observer* event_observer )
{
unit_recruited_.detach_handler(event_observer);
}
void manager::delete_unit_moved_observer( events::observer* event_observer )
void manager::remove_unit_moved_observer( events::observer* event_observer )
{
unit_moved_.detach_handler(event_observer);
}
void manager::delete_enemy_attacked_observer( events::observer* event_observer )
void manager::remove_enemy_attacked_observer( events::observer* event_observer )
{
enemy_attacked_.detach_handler(event_observer);
}
void manager::delete_turn_started_observer( events::observer* event_observer )
void manager::remove_turn_started_observer( events::observer* event_observer )
{
turn_started_.detach_handler(event_observer);
}
@ -542,7 +487,7 @@ const std::string manager::internal_evaluate_command( side_number side, const st
side_number side = lexical_cast<side_number>(cmd.at(1));
std::string file = cmd.at(2);
if (add_ai_for_side_from_file(side,file,false)){
return std::string("AI MANAGER: added [")+manager::get_active_ai_algorithm_type_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
} else {
return std::string("AI MANAGER: failed attempt to add AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
}
@ -552,7 +497,7 @@ const std::string manager::internal_evaluate_command( side_number side, const st
side_number side = lexical_cast<side_number>(cmd.at(1));
std::string file = cmd.at(2);
if (add_ai_for_side_from_file(side,file,true)){
return std::string("AI MANAGER: added [")+manager::get_active_ai_algorithm_type_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
return std::string("AI MANAGER: added [")+manager::get_active_ai_identifier_for_side(side)+std::string("] AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
} else {
return std::string("AI MANAGER: failed attempt to add AI for side ")+lexical_cast<std::string>(side)+std::string(" from file ")+file;
}
@ -618,22 +563,14 @@ bool manager::add_ai_for_side_from_file( side_number side, const std::string& fi
bool manager::add_ai_for_side_from_config( side_number side, const config& cfg, bool replace ){
config ai_memory;//AI memory
std::vector<config> ai_parameters;//AI parameters inside [ai] tags. May contain filters
config global_ai_parameters ;//AI parameters which do not have a filter applied
const config& default_ai_parameters = configuration::get_default_ai_parameters();//default AI parameters
std::string ai_algorithm_type;//AI algorithm type
config effective_ai_parameters;//legacy effective ai parameters
config parsed_cfg;
configuration::parse_side_config(cfg, parsed_cfg);
configuration::parse_side_config(cfg, ai_algorithm_type, global_ai_parameters, ai_parameters, default_ai_parameters, ai_memory, effective_ai_parameters);
if (replace) {
remove_ai_for_side (side);
remove_ai_for_side(side);
}
holder new_holder(side,ai_algorithm_type);
new_holder.set_ai_effective_parameters(effective_ai_parameters);
new_holder.set_ai_global_parameters(global_ai_parameters);
new_holder.set_ai_memory(ai_memory);
new_holder.set_ai_parameters(ai_parameters);
holder new_holder(side,parsed_cfg);
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
ai_stack_for_specific_side.push(new_holder);
return true;
@ -646,15 +583,16 @@ bool manager::add_ai_for_side( side_number side, const std::string& ai_algorithm
if (replace) {
remove_ai_for_side (side);
}
holder new_holder(side,ai_algorithm_type);
config cfg;
cfg["ai_algorithm"] = ai_algorithm_type;
holder new_holder(side,cfg);
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
ai_stack_for_specific_side.push(new_holder);
return true;
}
//@todo 1.7 refactor away from ai::manager
ai_ptr manager::create_transient_ai( const std::string &ai_algorithm_type, default_ai_context *ai_context )
ai_ptr manager::create_transient_ai(const std::string &ai_algorithm_type, const config &cfg, default_ai_context *ai_context )
{
assert(ai_context!=NULL);
@ -667,7 +605,7 @@ ai_ptr manager::create_transient_ai( const std::string &ai_algorithm_type, defau
}
}
LOG_AI_MANAGER << "Creating new AI of type [" << ai_algorithm_type << "]"<< std::endl;
ai_ptr new_ai = aii->second->get_new_instance(*ai_context);
ai_ptr new_ai = aii->second->get_new_instance(*ai_context,cfg);
return new_ai;
}
@ -702,36 +640,17 @@ void manager::clear_ais()
}
// =======================================================================
// GET active AI parameters
// Work with active AI parameters
// =======================================================================
const std::vector<config>& manager::get_active_ai_parameters_for_side( side_number side )
std::string manager::get_active_ai_identifier_for_side( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_parameters();
return get_active_ai_holder_for_side(side).get_ai_identifier();
}
const config& manager::get_active_ai_effective_parameters_for_side( side_number side )
config manager::to_config( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_effective_parameters();
}
const config& manager::get_active_ai_global_parameters_for_side( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_global_parameters();
}
const config& manager::get_active_ai_memory_for_side( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_memory();
}
const std::string& manager::get_active_ai_algorithm_type_for_side( side_number side )
{
return get_active_ai_holder_for_side(side).get_ai_algorithm_type();
return get_active_ai_holder_for_side(side).to_config();
}
@ -746,39 +665,6 @@ game_info& manager::get_ai_info()
return *ai_info_;
}
// =======================================================================
// SET active AI parameters
// =======================================================================
void manager::set_active_ai_parameters_for_side( side_number side, const std::vector<config>& ai_parameters )
{
get_active_ai_holder_for_side(side).set_ai_parameters(ai_parameters);
}
void manager::set_active_ai_effective_parameters_for_side( side_number side, const config& ai_parameters )
{
get_active_ai_holder_for_side(side).set_ai_effective_parameters(ai_parameters);
}
void manager::set_active_ai_global_parameters_for_side( side_number side, const config& ai_global_parameters )
{
get_active_ai_holder_for_side(side).set_ai_global_parameters(ai_global_parameters);
}
void manager::set_active_ai_memory_for_side( side_number side, const config& ai_memory )
{
get_active_ai_holder_for_side(side).set_ai_memory(ai_memory);
}
void manager::set_active_ai_algorithm_type_for_side( side_number side, const std::string& ai_algorithm_type )
{
get_active_ai_holder_for_side(side).set_ai_algorithm_type(ai_algorithm_type);
}
// =======================================================================
// PROXY
@ -849,7 +735,9 @@ holder& manager::get_or_create_active_ai_holder_for_side_without_fallback(side_n
if (!ai_stack_for_specific_side.empty()){
return ai_stack_for_specific_side.top();
} else {
holder new_holder(side, ai_algorithm_type);
config cfg;
cfg["ai_algorithm"] = ai_algorithm_type;
holder new_holder(side, cfg);
ai_stack_for_specific_side.push(new_holder);
return ai_stack_for_specific_side.top();
}

View file

@ -16,7 +16,6 @@
* @file ai/ai_manager.hpp
* Managing the AIs lifecycle - headers
* @todo 1.7 Refactor history handling and internal commands.
* @todo 1.7 Refactor all the mess with those AI parameters.
* @todo 1.7 AI Interface command to clear the history.
*/
@ -42,60 +41,41 @@ class readonly_context;
class readwrite_context;
class default_ai_context;
class ai_composite;
typedef boost::shared_ptr<ai_composite> composite_ai_ptr;
/**
* Base class that holds the AI and current AI parameters.
* It is an implementation detail.
* @todo 1.7.2 move it out of public view
* @todo 1.7.3 move it out of public view
*/
class holder{
public:
holder(int side, const std::string& ai_algorithm_type);
void init( int side );
holder(side_number side, const config &cfg);
virtual ~holder();
interface& get_ai_ref();
interface& get_ai_ref( int side );
const std::string& get_ai_algorithm_type() const;
void set_ai_algorithm_type(const std::string& ai_algorithm_type);
const config& get_ai_memory() const;
config& get_ai_memory();
void set_ai_memory(const config& ai_memory);
const std::vector<config>& get_ai_parameters() const;
std::vector<config>& get_ai_parameters();
void set_ai_parameters(const std::vector<config>& ai_parameters);
const config& get_ai_effective_parameters() const;
config& get_ai_effective_parameters();
void set_ai_effective_parameters(const config& ai_effective_parameters);
const config& get_ai_global_parameters() const;
config& get_ai_global_parameters();
void set_ai_global_parameters(const config& ai_global_parameters);
interface& get_ai_ref( side_number side );//@todo 1.7.3 remove this
const std::string describe_ai();
//not used in the moment
bool is_mandate_ok();
config to_config() const;
const std::string get_ai_identifier() const;
private:
ai_ptr ai_;
void init( side_number side );
composite_ai_ptr ai_;
side_context *side_context_;
readonly_context *readonly_context_;
readwrite_context *readwrite_context_;
default_ai_context *default_ai_context_;
std::string ai_algorithm_type_;
config ai_effective_parameters_;
config ai_global_parameters_;
config ai_memory_;
std::vector<config> ai_parameters_;
side_number side_;
ai_ptr create_ai( side_number side );
config cfg_;
};
/**
@ -270,9 +250,9 @@ public:
/**
* Deletes an observer of 'user interact' event.
* Removes an observer of 'user interact' event.
*/
static void delete_user_interact_observer( events::observer* event_observer );
static void remove_user_interact_observer( events::observer* event_observer );
/**
@ -284,25 +264,25 @@ public:
/**
* Deletes an observer of 'unit recruited' event.
*/
static void delete_unit_recruited_observer( events::observer* event_observer );
static void remove_unit_recruited_observer( events::observer* event_observer );
/**
* Deletes an observer of 'unit moved' event.
*/
static void delete_unit_moved_observer( events::observer* event_observer );
static void remove_unit_moved_observer( events::observer* event_observer );
/**
* Deletes an observer of 'enemy attacked' event.
*/
static void delete_enemy_attacked_observer( events::observer* event_observer );
static void remove_enemy_attacked_observer( events::observer* event_observer );
/**
* Deletes an observer of 'turn started' event.
*/
static void delete_turn_started_observer( events::observer* event_observer );
static void remove_turn_started_observer( events::observer* event_observer );
protected:
@ -373,10 +353,11 @@ public:
/**
* Returns a smart pointer to a new AI.
* @param ai_algorithm_type type of AI algorithm to create
* @param cfg a config of the ai
* @param context context in which this ai is created
* @return the reference to the created AI
*/
static ai_ptr create_transient_ai( const std::string& ai_algorithm_type, default_ai_context *ai_context);
static ai_ptr create_transient_ai( const std::string &ai_algorithm_type, const config &cfg, default_ai_context *ai_context);
// =======================================================================
@ -456,6 +437,22 @@ public:
static game_info& get_active_ai_info_for_side( side_number side );
/**
* Gets AI algorithm identifier for active AI of the given @a side.
* @param side side number (1-based).
* @return ai identifier for the active AI
*/
static std::string get_active_ai_identifier_for_side( side_number side );
/**
* Gets AI config for active AI of the given @a side.
* @param side side number (1-based).
* @return a config object for the active AI
*/
static config to_config( side_number side );
/**
* Gets global AI-game info
* @return a reference to the AI-game info.

View file

@ -13,12 +13,13 @@
*/
/**
* 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)
* All known AI parts. Workaround to a linker feature of not including 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 "ai2/ai.hpp"
#include "composite/ai.hpp"
#include "composite/aspect.hpp"
#include "composite/engine_default.hpp"
#include "composite/engine_fai.hpp"
#include "default/ai.hpp"
@ -40,62 +41,233 @@ static register_ai_factory<ai2> ai2_ai_factory("ai2");
static register_ai_factory<idle_ai> ai_idle_ai_factory("idle_ai");
static register_ai_factory<dfool::dfool_ai> ai_dfool_ai_factory("dfool_ai");
static register_ai_factory<formula_ai> ai_formula_ai_factory("formula_ai");
static register_ai_factory<composite_ai::ai_composite> ai_composite_ai_factory("composite_ai");
static register_ai_factory<ai_composite> ai_composite_ai_factory("composite_ai");
// =======================================================================
// Engines
// =======================================================================
static composite_ai::register_engine_factory<composite_ai::engine_cpp>
static register_engine_factory<engine_cpp>
composite_ai_factory_cpp("cpp");
static composite_ai::register_engine_factory<composite_ai::engine_fai>
static register_engine_factory<engine_fai>
composite_ai_factory_fai("fai");
// =======================================================================
// Stages
// =======================================================================
static composite_ai::register_stage_factory<testing_ai_default::candidate_action_evaluation_loop>
static register_stage_factory<testing_ai_default::candidate_action_evaluation_loop>
candidate_action_evaluation_loop_factory("testing_ai_default::candidate_action_evaluation_loop");
static composite_ai::register_stage_factory<testing_ai_default::fallback_to_other_ai>
static register_stage_factory<testing_ai_default::fallback_to_other_ai>
fallback_to_other_ai_factory("testing_ai_default::fallback");
// =======================================================================
// Candidate actions
// =======================================================================
static composite_ai::register_candidate_action_factory<testing_ai_default::goto_phase>
static register_candidate_action_factory<testing_ai_default::goto_phase>
goto_phase_factory("testing_ai_default::goto_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::recruitment_phase>
static register_candidate_action_factory<testing_ai_default::recruitment_phase>
recruitment_phase_factory("testing_ai_default::recruitment_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::combat_phase>
static register_candidate_action_factory<testing_ai_default::combat_phase>
combat_phase_factory("testing_ai_default::combat_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::move_leader_to_goals_phase>
static register_candidate_action_factory<testing_ai_default::move_leader_to_goals_phase>
move_leader_to_goals_phase_factory("testing_ai_default::move_leader_to_goals_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::move_leader_to_keep_phase>
static register_candidate_action_factory<testing_ai_default::move_leader_to_keep_phase>
move_leader_to_keep_phase_factory("testing_ai_default::move_leader_to_keep_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::get_villages_phase>
static register_candidate_action_factory<testing_ai_default::get_villages_phase>
get_villages_phase_factory("testing_ai_default::get_villages_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::get_healing_phase>
static register_candidate_action_factory<testing_ai_default::get_healing_phase>
get_healing_phase_factory("testing_ai_default::get_healing_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::retreat_phase>
static register_candidate_action_factory<testing_ai_default::retreat_phase>
retreat_phase_factory("testing_ai_default::retreat_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::simple_move_and_targeting_phase>
static register_candidate_action_factory<testing_ai_default::simple_move_and_targeting_phase>
simple_move_and_targeting_phase_factory("testing_ai_default::simple_move_and_targeting_phase");
static composite_ai::register_candidate_action_factory<testing_ai_default::leader_control_phase>
static register_candidate_action_factory<testing_ai_default::leader_control_phase>
leader_control_phase_factory("testing_ai_default::leader_control_phase");
// =======================================================================
// Aspects
// =======================================================================
//name=composite_aspect
static register_aspect_factory< composite_aspect<double> >
aggression__composite_aspect_factory("aggression*composite_aspect");
static register_aspect_factory< composite_aspect<int> >
attack_depth__composite_aspect_factory("attack_depth*composite_aspect");
static register_aspect_factory< composite_aspect< terrain_filter > >
avoid__composite_aspect_factory("avoid*composite_aspect");
static register_aspect_factory< composite_aspect<double> >
caution__composite_aspect_factory("caution*composite_aspect");
static register_aspect_factory< composite_aspect<std::string> >
grouping__composite_aspect_factory("grouping*composite_aspect");
static register_aspect_factory< composite_aspect<config> >
leader_goal__composite_aspect_factory("leader_goal*composite_aspect");
static register_aspect_factory< composite_aspect<double> >
leader_value__composite_aspect_factory("leader_value*composite_aspect");
static register_aspect_factory< composite_aspect<double> >
number_of_possible_recruits_to_force_recruit__composite_aspect_factory("number_of_possible_recruits_to_force_recruit*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
passive_leader__composite_aspect_factory("passive_leader*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
passive_leader_shares_keep__composite_aspect_factory("passive_leader_shares_keep*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
recruitment_ignore_bad_combat__composite_aspect_factory("recruitment_ignore_bad_combat*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
recruitment_ignore_bad_movement__composite_aspect_factory("recruitment_ignore_bad_movement*composite_aspect");
static register_aspect_factory< composite_aspect< std::vector<std::string> > >
recruitment_pattern__composite_aspect_factory("recruitment_pattern*composite_aspect");
static register_aspect_factory< composite_aspect<double> >
scout_village_targeting__composite_aspect_factory("scout_village_targeting*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
simple_targeting__composite_aspect_factory("simple_targeting*composite_aspect");
static register_aspect_factory< composite_aspect<bool> >
support_villages__composite_aspect_factory("support_villages*composite_aspect");
static register_aspect_factory< composite_aspect<double> >
village_value__composite_aspect_factory("village_value*composite_aspect");
static register_aspect_factory< composite_aspect<int> >
villages_per_scout__composite_aspect_factory("villages_per_scout*composite_aspect");
//name=standard_aspect
static register_aspect_factory< standard_aspect<double> >
aggression__standard_aspect_factory("aggression*standard_aspect");
static register_aspect_factory< standard_aspect<int> >
attack_depth__standard_aspect_factory("attack_depth*standard_aspect");
static register_aspect_factory< standard_aspect< terrain_filter > >
avoid__standard_aspect_factory("avoid*standard_aspect");
static register_aspect_factory< standard_aspect<double> >
caution__standard_aspect_factory("caution*standard_aspect");
static register_aspect_factory< standard_aspect<std::string> >
grouping__standard_aspect_factory("grouping*standard_aspect");
static register_aspect_factory< standard_aspect<config> >
leader_goal__standard_aspect_factory("leader_goal*standard_aspect");
static register_aspect_factory< standard_aspect<double> >
leader_value__standard_aspect_factory("leader_value*standard_aspect");
static register_aspect_factory< standard_aspect<double> >
number_of_possible_recruits_to_force_recruit__standard_aspect_factory("number_of_possible_recruits_to_force_recruit*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
passive_leader__standard_aspect_factory("passive_leader*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
passive_leader_shares_keep__standard_aspect_factory("passive_leader_shares_keep*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
recruitment_ignore_bad_combat__standard_aspect_factory("recruitment_ignore_bad_combat*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
recruitment_ignore_bad_movement__standard_aspect_factory("recruitment_ignore_bad_movement*standard_aspect");
static register_aspect_factory< standard_aspect< std::vector<std::string> > >
recruitment_pattern__standard_aspect_factory("recruitment_pattern*standard_aspect");
static register_aspect_factory< standard_aspect<double> >
scout_village_targeting__standard_aspect_factory("scout_village_targeting*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
simple_targeting__standard_aspect_factory("simple_targeting*standard_aspect");
static register_aspect_factory< standard_aspect<bool> >
support_villages__standard_aspect_factory("support_villages*standard_aspect");
static register_aspect_factory< standard_aspect<double> >
village_value__standard_aspect_factory("village_value*standard_aspect");
static register_aspect_factory< standard_aspect<int> >
villages_per_scout__standard_aspect_factory("villages_per_scout*standard_aspect");
//name = default
static register_aspect_factory< standard_aspect<double> >
aggression__standard_aspect_factory2("aggression*");
static register_aspect_factory< standard_aspect<int> >
attack_depth__standard_aspect_factory2("attack_depth*");
static register_aspect_factory< standard_aspect< terrain_filter > >
avoid__standard_aspect_factory2("avoid*");
static register_aspect_factory< standard_aspect<double> >
caution__standard_aspect_factory2("caution*");
static register_aspect_factory< standard_aspect<std::string> >
grouping__standard_aspect_factory2("grouping*");
static register_aspect_factory< standard_aspect<config> >
leader_goal__standard_aspect_factory2("leader_goal*");
static register_aspect_factory< standard_aspect<double> >
leader_value__standard_aspect_factory2("leader_value*");
static register_aspect_factory< standard_aspect<double> >
number_of_possible_recruits_to_force_recruit__standard_aspect_factory2("number_of_possible_recruits_to_force_recruit*");
static register_aspect_factory< standard_aspect<bool> >
passive_leader__standard_aspect_factory2("passive_leader*");
static register_aspect_factory< standard_aspect<bool> >
passive_leader_shares_keep__standard_aspect_factory2("passive_leader_shares_keep*");
static register_aspect_factory< standard_aspect<bool> >
recruitment_ignore_bad_combat__standard_aspect_factory2("recruitment_ignore_bad_combat*");
static register_aspect_factory< standard_aspect<bool> >
recruitment_ignore_bad_movement__standard_aspect_factory2("recruitment_ignore_bad_movement*");
static register_aspect_factory< standard_aspect< std::vector<std::string> > >
recruitment_pattern__standard_aspect_factory2("recruitment_pattern*");
static register_aspect_factory< standard_aspect<double> >
scout_village_targeting__standard_aspect_factory2("scout_village_targeting*");
static register_aspect_factory< standard_aspect<bool> >
simple_targeting__standard_aspect_factory2("simple_targeting*");
static register_aspect_factory< standard_aspect<bool> >
support_villages__standard_aspect_factory2("support_villages*");
static register_aspect_factory< standard_aspect<double> >
village_value__standard_aspect_factory2("village_value*");
static register_aspect_factory< standard_aspect<int> >
villages_per_scout__standard_aspect_factory2("villages_per_scout*");
void registry::init()
{
}

View file

@ -73,7 +73,7 @@ void ai_testing::log_game_start()
ai::game_info& i = ai::manager::get_ai_info();
for (std::vector<team>::const_iterator tm = i.teams.begin(); tm != i.teams.end(); ++tm) {
int side = tm-i.teams.begin()+1;
LOG_AI_TESTING << "AI_IDENTIFIER"<<side<<": " << tm->ai_algorithm_identifier() <<std::endl;
LOG_AI_TESTING << "AI_IDENTIFIER"<<side<<": " << ai::manager::get_active_ai_identifier_for_side(side) <<std::endl;
LOG_AI_TESTING << "FACTION"<<side<<": " << tm->name() << std::endl;
}
LOG_AI_TESTING << "VERSION: " << game_config::revision << std::endl;

View file

@ -40,7 +40,7 @@ namespace testing_ai_default {
//==============================================================
goto_phase::goto_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::goto_phase",cfg["type"])
: candidate_action(context,cfg)
{
}
@ -63,7 +63,7 @@ bool goto_phase::execute()
//==============================================================
recruitment_phase::recruitment_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::recruitment_phase",cfg["type"])
: candidate_action(context,cfg)
{
}
@ -112,7 +112,7 @@ bool recruitment_phase::execute()
//analyze_potential_recruit_movements();
analyze_potential_recruit_combat();
std::vector<std::string> options = current_team().recruitment_pattern();
std::vector<std::string> options = get_recruitment_pattern();
if (std::count(options.begin(), options.end(), "scout") > 0) {
size_t neutral_villages = 0;
@ -145,7 +145,7 @@ bool recruitment_phase::execute()
// accounting for all neutral villages on the map.
// We only look at villages closer to us, so we halve it,
// making us get twice as many scouts.
const int villages_per_scout = current_team().villages_per_scout()/2;
const int villages_per_scout = get_villages_per_scout()/2;
// Get scouts depending on how many neutral villages there are.
int scouts_wanted = villages_per_scout > 0 ? neutral_villages/villages_per_scout : 0;
@ -180,7 +180,7 @@ bool recruitment_phase::execute()
// Buy units as long as we have room and can afford it.
while (recruit_usage(options[rand()%options.size()],gamestate_changed)) {
//refresh the recruitment pattern - it can be changed by recruit_usage
options = current_team().recruitment_pattern();
options = get_recruitment_pattern();
if (options.empty()) {
options.push_back("");
}
@ -261,7 +261,9 @@ bool recruitment_phase::recruit_usage(const std::string& usage, bool &gamestate_
WRN_AI_TESTING_AI_DEFAULT << warning;
// Uncommented until the recruitment limiting macro can be fixed to not trigger this warning.
//lg::wml_error << warning;
return current_team_w().remove_recruitment_pattern_entry(usage);
//@fixme
//return current_team_w().remove_recruitment_pattern_entry(usage);
return false;
}
return false;
}
@ -477,8 +479,7 @@ int recruitment_phase::compare_unit_types(const unit_type& a, const unit_type& b
void recruitment_phase::analyze_potential_recruit_combat()
{
unit_map &units_ = get_info().units;
if(unit_combat_scores_.empty() == false ||
utils::string_bool(current_team().ai_parameters()["recruitment_ignore_bad_combat"])) {
if(unit_combat_scores_.empty() == false || get_recruitment_ignore_bad_combat()) {
return;
}
@ -545,7 +546,7 @@ void recruitment_phase::analyze_potential_recruit_combat()
//==============================================================
combat_phase::combat_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::combat_phase",cfg["type"]),best_analysis_(),choice_rating_(-1000.0)
: candidate_action(context,cfg),best_analysis_(),choice_rating_(-1000.0)
{
}
@ -585,9 +586,9 @@ double combat_phase::evaluate()
if(skip_num > 0 && ((it - analysis.begin())%skip_num) && it->movements.size() > 1)
continue;
const double rating = it->rating(current_team().aggression(),*this);
const double rating = it->rating(get_aggression(),*this);
LOG_AI_TESTING_AI_DEFAULT << "attack option rated at " << rating << " ("
<< current_team().aggression() << ")\n";
<< get_aggression() << ")\n";
if(rating > choice_rating_) {
choice_it = it;
@ -638,7 +639,7 @@ bool combat_phase::execute()
//==============================================================
move_leader_to_goals_phase::move_leader_to_goals_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::move_leader_to_goals_phase",cfg["type"])
: candidate_action(context,cfg)
{
}
@ -661,7 +662,7 @@ bool move_leader_to_goals_phase::execute()
//==============================================================
move_leader_to_keep_phase::move_leader_to_keep_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::move_leader_to_keep_phase",cfg["type"]),move_()
: candidate_action(context,cfg),move_()
{
}
@ -742,7 +743,7 @@ bool move_leader_to_keep_phase::execute()
//==============================================================
get_villages_phase::get_villages_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::get_villages_phase",cfg["type"]), keep_loc_(),
: candidate_action(context,cfg), keep_loc_(),
leader_loc_(),best_leader_loc_(),debug_(false)
{
}
@ -757,7 +758,7 @@ double get_villages_phase::evaluate()
unit_map::const_iterator leader = get_info().units.find_leader(get_side());
get_villages(get_possible_moves(),get_dstsrc(),get_enemy_dstsrc(),leader);
if (moves_.size()>0) {
return 25;
return 25;//@todo 1.7 externalize
}
return BAD_SCORE;
}
@ -883,7 +884,7 @@ void get_villages_phase::find_villages(
{
std::map<map_location, double> vulnerability;
const bool passive_leader = utils::string_bool(current_team().ai_parameters()["passive_leader"]);//@todo: make an aspect
const bool passive_leader = get_passive_leader();
size_t min_distance = 100000;
gamemap &map_ = get_info().map;
@ -1555,7 +1556,7 @@ void get_villages_phase::dump_reachmap(treachmap& reachmap)
//==============================================================
get_healing_phase::get_healing_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::get_healing_phase",cfg["type"]),from_(),to_()
: candidate_action(context,cfg),from_(),to_()
{
}
@ -1642,7 +1643,7 @@ bool get_healing_phase::execute()
//==============================================================
retreat_phase::retreat_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::retreat_phase",cfg["type"])
: candidate_action(context,cfg)
{
}
@ -1665,7 +1666,7 @@ bool retreat_phase::execute()
//==============================================================
simple_move_and_targeting_phase::simple_move_and_targeting_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::simple_move_and_targeting_phase",cfg["type"])
: candidate_action(context,cfg)
{
}
@ -1728,7 +1729,7 @@ bool simple_move_and_targeting_phase::execute()
//==============================================================
leader_control_phase::leader_control_phase( rca_context &context, const config &cfg )
: candidate_action(context,"testing_ai_default::leader_control_phase",cfg["type"])
: candidate_action(context,cfg)
{
}

View file

@ -36,9 +36,6 @@ namespace ai {
namespace testing_ai_default {
using composite_ai::rca_context;
using composite_ai::candidate_action;
//============================================================================
class goto_phase : public candidate_action {

View file

@ -33,14 +33,27 @@ static lg::log_domain log_ai_testing_stage_fallback("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( composite_ai::composite_ai_context &context, const config &cfg )
fallback_to_other_ai::fallback_to_other_ai( ai_context &context, const config &cfg )
: stage(context,cfg), cfg_(cfg), fallback_ai_()
{
}
void fallback_to_other_ai::on_create()
{
fallback_ai_ = manager::create_transient_ai(cfg_["fallback"], this);
const config &ai_cfg = cfg_.child("ai");
if (ai_cfg) {
fallback_ai_ = manager::create_transient_ai(ai_cfg["ai_algorithm"], ai_cfg, this);
}
}
config fallback_to_other_ai::to_config() const
{
config cfg = stage::to_config();
if (fallback_ai_) {
cfg.add_child("ai",fallback_ai_->to_config());
}
return cfg;
}
void fallback_to_other_ai::do_play_stage()

View file

@ -38,9 +38,9 @@ namespace ai {
namespace testing_ai_default {
class fallback_to_other_ai: public composite_ai::stage {
class fallback_to_other_ai: public stage {
public:
fallback_to_other_ai( composite_ai::composite_ai_context &context, const config &cfg );
fallback_to_other_ai( ai_context &context, const config &cfg );
~fallback_to_other_ai();
@ -48,6 +48,8 @@ public:
void on_create();
config to_config() const;
private:
const config &cfg_;

View file

@ -32,7 +32,7 @@ static lg::log_domain log_ai_testing_rca_default("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( composite_ai::composite_ai_context &context, const config &cfg)
candidate_action_evaluation_loop::candidate_action_evaluation_loop( ai_context &context, const config &cfg)
: stage(context,cfg),cfg_(cfg)
{
}
@ -41,27 +41,36 @@ void candidate_action_evaluation_loop::on_create()
{
//init the candidate actions
foreach(const config &cfg_element, cfg_.child_range("candidate_action")){
composite_ai::engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
engine::parse_candidate_action_from_config(*this,cfg_element,back_inserter(candidate_actions_));
}
}
config candidate_action_evaluation_loop::to_config() const
{
config cfg = stage::to_config();
foreach(candidate_action_ptr ca, candidate_actions_){
cfg.add_child("candidate_action",ca->to_config());
}
return cfg;
}
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(composite_ai::candidate_action_ptr ca, candidate_actions_){
foreach(candidate_action_ptr ca, candidate_actions_){
ca->enable();
}
bool executed = false;
do {
executed = false;
double best_score = composite_ai::candidate_action::BAD_SCORE;
composite_ai::candidate_action_ptr best_ptr;
double best_score = candidate_action::BAD_SCORE;
candidate_action_ptr best_ptr;
//Evaluation
foreach(composite_ai::candidate_action_ptr ca_ptr, candidate_actions_){
foreach(candidate_action_ptr ca_ptr, candidate_actions_){
if (!ca_ptr->is_enabled()){
DBG_AI_TESTING_RCA_DEFAULT << "Skipping disabled candidate action: "<< *ca_ptr << std::endl;
continue;
@ -72,7 +81,7 @@ void candidate_action_evaluation_loop::do_play_stage()
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 (composite_ai::candidate_action_evaluation_exception &caee) {
} catch (candidate_action_evaluation_exception &caee) {
ERR_AI_TESTING_RCA_DEFAULT << "Candidate action evaluation threw an exception: " << caee << std::endl;
ca_ptr->disable();
continue;
@ -85,11 +94,11 @@ void candidate_action_evaluation_loop::do_play_stage()
}
//Execution
if (best_score>composite_ai::candidate_action::BAD_SCORE) {
if (best_score>candidate_action::BAD_SCORE) {
try {
DBG_AI_TESTING_RCA_DEFAULT << "Best candidate action: "<< *best_ptr << std::endl;
executed = best_ptr->execute();
} catch (composite_ai::candidate_action_execution_exception &caee) {
} catch (candidate_action_execution_exception &caee) {
ERR_AI_TESTING_RCA_DEFAULT << "Candidate action execution threw an exception: " << caee << std::endl;
executed = false;
}
@ -101,13 +110,13 @@ void candidate_action_evaluation_loop::do_play_stage()
executed = true;
}
} else {
LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< composite_ai::candidate_action::BAD_SCORE<<std::endl;
LOG_AI_TESTING_RCA_DEFAULT << "Ending candidate action evaluation loop due to best score "<< best_score<<"<="<< candidate_action::BAD_SCORE<<std::endl;
}
} while (executed);
LOG_AI_TESTING_RCA_DEFAULT << "Ended candidate action evaluation loop for side "<< get_side() << std::endl;
}
composite_ai::rca_context& candidate_action_evaluation_loop::get_rca_context()
rca_context& candidate_action_evaluation_loop::get_rca_context()
{
return *this;
}

View file

@ -40,9 +40,9 @@ namespace ai {
namespace testing_ai_default {
class candidate_action_evaluation_loop: public virtual composite_ai::stage, public virtual composite_ai::rca_context {
class candidate_action_evaluation_loop: public virtual stage, public virtual rca_context {
public:
candidate_action_evaluation_loop( composite_ai::composite_ai_context &context, const config &cfg );
candidate_action_evaluation_loop( ai_context &context, const config &cfg );
~candidate_action_evaluation_loop();
@ -50,10 +50,12 @@ public:
void on_create();
composite_ai::rca_context& get_rca_context();
config to_config() const;
rca_context& get_rca_context();
private:
std::vector<composite_ai::candidate_action_ptr> candidate_actions_;
std::vector<candidate_action_ptr> candidate_actions_;
const config &cfg_;
};

View file

@ -120,6 +120,33 @@ void config::merge_children(const std::string& key)
add_child(key,merged_children);
}
void config::merge_children_by_attribute(const std::string& key, const std::string& attribute)
{
check_valid();
std::map<std::string,config> merged_children_map;
const child_list& children = get_children(key);
if(children.size() < 2) {
return;
}
for(child_list::const_iterator i = children.begin(); i != children.end(); ++i) {
const std::string& value = (**i)[attribute];
std::map<std::string,config>::iterator m = merged_children_map.find(value);
if ( m!=merged_children_map.end() ) {
m->second.append(**i);
} else {
merged_children_map.insert(make_pair(value,**i));
}
}
clear_children(key);
typedef std::map<std::string,config> config_map;
foreach (const config_map::value_type &i, merged_children_map) {
add_child(key,i.second);
}
}
config::child_itors_bak config::child_range_bak(const std::string& key)
{
check_valid();

View file

@ -341,6 +341,13 @@ public:
*/
void merge_children(const std::string& key);
/**
* All children with the given key and with equal values
* of the specified attribute will be merged into the
* element with that key and that value of the attribute
*/
void merge_children_by_attribute(const std::string& key, const std::string& attribute);
//this is a cheap O(1) operation
void swap(config& cfg);

View file

@ -522,7 +522,6 @@ void play_controller::do_init_side(const unsigned int team_index){
}
const time_of_day &tod = tod_manager_.get_time_of_day();
current_team.set_time_of_day(int(turn()), tod);
if (int(team_index) + 1 == first_player_)
sound::play_sound(tod.sounds, sound::SOUND_SOURCES);

View file

@ -68,16 +68,6 @@ int teams_manager::get_first_human_team(const config::child_list::const_iterator
return result;
}
team::target::target(const config& cfg)
: criteria(cfg), value(atof(cfg["value"].c_str()))
{
}
void team::target::write(config& cfg) const
{
cfg = criteria;
}
team::team_info::team_info(const config& cfg) :
name(cfg["name"]),
gold(lexical_cast_default<int>(cfg["gold"])),
@ -86,10 +76,7 @@ team::team_info::team_info(const config& cfg) :
income(lexical_cast_default<int>(cfg["income"])),
income_per_village(0),
average_price(0),
number_of_possible_recruits_to_force_recruit(),
can_recruit(),
global_recruitment_pattern(),
recruitment_pattern(),
enemies(),
team_name(cfg["team_name"]),
user_team_name(cfg["user_team_name"]),
@ -103,12 +90,6 @@ team::team_info::team_info(const config& cfg) :
objectives(cfg["objectives"]),
objectives_changed(utils::string_bool(cfg["objectives_changed"])),
controller(),
villages_per_scout(),
leader_value(),
village_value(),
aggression_(),
caution_(),
targets(),
share_maps(false),
share_view(false),
disallow_observers(utils::string_bool(cfg["disallow_observers"])),
@ -120,7 +101,7 @@ team::team_info::team_info(const config& cfg) :
side(lexical_cast_default<int>(cfg["side"], 1)),
persistent(false)
{
// If are starting new scenario overide settings from [ai] tags
// If arel starting new scenario overide settings from [ai] tags
if (!user_team_name.translatable())
user_team_name = user_team_name.from_serialized(user_team_name);
@ -130,50 +111,10 @@ team::team_info::team_info(const config& cfg) :
ai::manager::add_ai_for_side_from_config(side, cfg, true);
}
//legacy parameters
const config& global_ai_parameters = ai::manager::get_active_ai_global_parameters_for_side(side);
const config& effective_ai_params = ai::manager::get_active_ai_effective_parameters_for_side(side);
number_of_possible_recruits_to_force_recruit = lexical_cast<float>(effective_ai_params["number_of_possible_recruits_to_force_recruit"]);
villages_per_scout = lexical_cast<int>(effective_ai_params["villages_per_scout"]);
leader_value = lexical_cast<double>(effective_ai_params["leader_value"]);
village_value = lexical_cast<double>(effective_ai_params["village_value"]);
aggression_ = lexical_cast<double>(effective_ai_params["aggression"]);
caution_ = lexical_cast<double>(effective_ai_params["caution"]);
//START OF MESSY CODE
//========================================================================
//this part will be cleaned later
std::vector<std::string> recruits = utils::split(cfg["recruit"]);
for(std::vector<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
can_recruit.insert(*i);
}
recruitment_pattern = utils::split(cfg["recruitment_pattern"]);
if(recruitment_pattern.empty())
{
recruitment_pattern =
utils::split(global_ai_parameters["recruitment_pattern"]);
}
// Keep a copy of the initial recruitment_pattern,
// since it can be changed on a per-time-of-day
// or per-turn basis inside [ai] sections.
global_recruitment_pattern = recruitment_pattern;
// Additional targets
foreach (const config &tgt, cfg.child_range("target")) {
targets.push_back(target(tgt));
}
foreach (const config &tgt, global_ai_parameters.child_range("target")) {
targets.push_back(target(tgt));
}
//all past this point should be non-ai code
//========================================================
std::vector<std::string> recruits = utils::split(cfg["recruit"]);
for(std::vector<std::string>::const_iterator i = recruits.begin(); i != recruits.end(); ++i) {
can_recruit.insert(*i);
}
// at the start of a scenario "start_gold" is not set, we need to take the
// value from the gold setting (or fall back to the gold default)
@ -259,14 +200,6 @@ team::team_info::team_info(const config& cfg) :
void team::team_info::write(config& cfg) const
{
const std::vector<config> &ai_params = ai::manager::get_active_ai_parameters_for_side(side);;
for(std::vector<config>::const_iterator ai = ai_params.begin(); ai != ai_params.end(); ++ai) {
cfg.add_child("ai",*ai);
}
const config &ai_memory_ = ai::manager::get_active_ai_memory_for_side(side);
if(!ai_memory_.empty()) cfg.add_child("ai_memory", ai_memory_ );
cfg["ai_algorithm"] = ai::manager::get_active_ai_algorithm_type_for_side(side);
cfg["gold"] = str_cast(gold);
cfg["start_gold"] = str_cast(start_gold);
cfg["gold_add"] = gold_add ? "yes" : "no";
@ -288,7 +221,6 @@ void team::team_info::write(config& cfg) const
cfg["allow_player"] = allow_player ? "yes" : "no";
cfg["no_leader"] = no_leader ? "yes" : "no";
cfg["hidden"] = hidden ? "yes" : "no";
cfg["number_of_possible_recruits_to_force_recruit"] = lexical_cast<std::string>(number_of_possible_recruits_to_force_recruit);
std::stringstream enemies_str;
for(std::vector<int>::const_iterator en = enemies.begin(); en != enemies.end(); ++en) {
@ -309,16 +241,6 @@ void team::team_info::write(config& cfg) const
default: assert(false); return;
}
cfg["villages_per_scout"] = str_cast(villages_per_scout);
cfg["leader_value"] = str_cast(leader_value);
cfg["village_value"] = str_cast(village_value);
cfg["aggression"] = str_cast(aggression_);
cfg["caution"] = str_cast(caution_);
for(std::vector<target>::const_iterator tg = targets.begin(); tg != targets.end(); ++tg) {
tg->write(cfg.add_child("target"));
}
std::stringstream can_recruit_str;
for(std::set<std::string>::const_iterator cr = can_recruit.begin(); cr != can_recruit.end(); ++cr) {
if(cr != can_recruit.begin())
@ -329,28 +251,6 @@ void team::team_info::write(config& cfg) const
cfg["recruit"] = can_recruit_str.str();
std::stringstream global_recruit_pattern_str;
for(std::vector<std::string>::const_iterator p = global_recruitment_pattern.begin();
p != global_recruitment_pattern.end(); ++p) {
if(p != global_recruitment_pattern.begin())
global_recruit_pattern_str << ",";
global_recruit_pattern_str << *p;
}
cfg["global_recruitment_pattern"] = global_recruit_pattern_str.str();
std::stringstream recruit_pattern_str;
for(std::vector<std::string>::const_iterator p = recruitment_pattern.begin();
p != recruitment_pattern.end(); ++p) {
if(p != recruitment_pattern.begin())
recruit_pattern_str << ",";
recruit_pattern_str << *p;
}
cfg["recruitment_pattern"] = recruit_pattern_str.str();
cfg["share_maps"] = share_maps ? "yes" : "no";
cfg["share_view"] = share_view ? "yes" : "no";
@ -360,6 +260,8 @@ void team::team_info::write(config& cfg) const
cfg["colour"] = lexical_cast_default<std::string>(colour);
cfg["persistent"] = persistent ? "yes" : "no";
cfg.add_child("ai",ai::manager::to_config(side));
}
void team::merge_shroud_map_data(const std::string& shroud_data)
@ -490,7 +392,7 @@ void team::add_recruits(const std::set<std::string>& recruits)
namespace {
struct count_average {
count_average(size_t& a) : a_(a), sum_(0), count_(0)
count_average(int a) : a_(a), sum_(0), count_(0)
{}
~count_average() {
// If no recruits disable leader from moving to keep
@ -508,13 +410,13 @@ namespace {
sum_ += i->second.cost();
}
private:
size_t& a_;
size_t sum_;
size_t count_;
int a_;
int sum_;
int count_;
};
}
size_t team::average_recruit_price()
int team::average_recruit_price() const
{
if (info_.average_price)
return info_.average_price;
@ -528,52 +430,6 @@ size_t team::average_recruit_price()
return info_.average_price;
}
void team::set_time_of_day(int turn, const time_of_day& tod)
{
config aiparams_effective;//current effective_parameters_for_team are to be cleared
const std::vector<config>& ai_params = ai::manager::get_active_ai_parameters_for_side(info_.side);
for(std::vector<config>::const_iterator i = ai_params.begin(); i != ai_params.end(); ++i) {
const std::string& time_of_day = (*i)["time_of_day"];
if(time_of_day.empty() == false) {
const std::vector<std::string>& times = utils::split(time_of_day);
if(std::count(times.begin(),times.end(),tod.id) == 0) {
continue;
}
}
const std::string& turns = (*i)["turns"];
if(turns.empty() == false) {
bool matched = false;
const std::vector<std::string>& turns_list = utils::split(turns);
for(std::vector<std::string>::const_iterator j = turns_list.begin(); j != turns_list.end(); ++j) {
const std::pair<int,int> range = utils::parse_range(*j);
if(turn >= range.first && turn <= range.second) {
matched = true;
break;
}
}
if(!matched) {
continue;
}
}
aiparams_effective.append(*i);
}
// Get the recruitment pattern from the matching [ai] section,
// and fall back to the global recruitment pattern otherwise.
info_.recruitment_pattern = utils::split(aiparams_effective["recruitment_pattern"]);
if (info_.recruitment_pattern.empty())
info_.recruitment_pattern = info_.global_recruitment_pattern;
info_.aggression_ = lexical_cast_default<double>(aiparams_effective["aggression"],info_.aggression_);
info_.caution_ = lexical_cast_default<double>(aiparams_effective["caution"],info_.caution_);
info_.number_of_possible_recruits_to_force_recruit = lexical_cast_default<float>(aiparams_effective["number_of_possible_recruits_to_force_recruit"],info_.number_of_possible_recruits_to_force_recruit);
ai::manager::set_active_ai_effective_parameters_for_side(info_.side,aiparams_effective);
}
bool team::calculate_enemies(size_t index) const
{
if(teams == NULL || index >= teams->size()) {
@ -663,39 +519,6 @@ void team::set_objectives(const t_string& new_objectives, bool silently)
info_.objectives_changed = true;
}
const std::string& team::ai_algorithm() const
{
return ai::manager::get_active_ai_algorithm_type_for_side(info_.side);
}
const std::string& team::ai_algorithm_identifier() const
{
return ai::manager::get_active_ai_global_parameters_for_side(info_.side)["id"];
}
const config& team::ai_parameters() const
{
return ai::manager::get_active_ai_effective_parameters_for_side(info_.side);
}
const config& team::ai_memory() const
{
return ai::manager::get_active_ai_memory_for_side(info_.side);
}
void team::set_ai_memory(const config& ai_mem){
ai::manager::set_active_ai_memory_for_side(info_.side,ai_mem);
}
void team::set_ai_parameters(const config::const_child_itors &ai_parameters)
{
std::vector<config> ai_params;
foreach (const config &p, ai_parameters) {
ai_params.push_back(p);
}
ai::manager::set_active_ai_parameters_for_side(info_.side,ai_params);
}
bool team::shrouded(const map_location& loc) const
{
if(!teams)

View file

@ -62,13 +62,6 @@ class team : public viewpoint, public savegame_config
};
public:
struct target {
explicit target(const config& cfg);
void write(config& cfg) const;
config criteria;
double value;
};
struct team_info
{
team_info(const config& cfg);
@ -79,11 +72,8 @@ public:
bool gold_add;
int income;
int income_per_village;
size_t average_price;
float number_of_possible_recruits_to_force_recruit;
mutable int average_price;
std::set<std::string> can_recruit;
std::vector<std::string> global_recruitment_pattern;
std::vector<std::string> recruitment_pattern;
std::vector<int> enemies;
std::string team_name;
t_string user_team_name;
@ -108,13 +98,6 @@ public:
enum CONTROLLER { HUMAN, HUMAN_AI, AI, NETWORK, NETWORK_AI, EMPTY };
CONTROLLER controller;
int villages_per_scout;
double leader_value, village_value;
//cached values for ai parameters
double aggression_, caution_;
std::vector<target> targets;
bool share_maps, share_view;
bool disallow_observers;
bool allow_player;
@ -153,7 +136,6 @@ public:
void set_village_gold(int income) { info_.income_per_village = income; }
int total_income() const { return base_income() + villages_.size() * info_.income_per_village; }
void new_turn() { gold_ += total_income(); }
void set_time_of_day(int turn, const time_of_day &tod);
void get_shared_maps();
void set_gold(int amount) { gold_ = amount; }
void spend_gold(const int amount) { gold_ -= amount; }
@ -169,27 +151,14 @@ public:
void set_current_player(const std::string player)
{ info_.current_player = player; }
size_t average_recruit_price();
float num_pos_recruits_to_force() const
{ return info_.number_of_possible_recruits_to_force_recruit; }
int average_recruit_price() const;
const std::set<std::string>& recruits() const
{ return info_.can_recruit; }
void add_recruits(const std::set<std::string>& recruits);
void add_recruit(const std::string& s) { info_.can_recruit.insert(s); }
void remove_recruit(const std::string& recruits);
void set_recruits(const std::set<std::string>& recruits);
const std::vector<std::string>& recruitment_pattern() const
{ return info_.recruitment_pattern; }
bool remove_recruitment_pattern_entry(const std::string& key)
{
std::vector<std::string>::iterator itor = std::find(info_.recruitment_pattern.begin(),
info_.recruitment_pattern.end(),
key);
if (itor == info_.recruitment_pattern.end())
return false;
info_.recruitment_pattern.erase(itor);
return true;
}
const std::string& name() const
{ return info_.name; }
const std::string& save_id() const { return info_.save_id; }
@ -226,9 +195,6 @@ public:
seen_[index] = true;
}
double aggression() const { return info_.aggression_; }
double caution() const { return info_.caution_; }
team_info::CONTROLLER controller() const { return info_.controller; }
bool is_human() const { return info_.controller == team_info::HUMAN; }
bool is_human_ai() const { return info_.controller == team_info::HUMAN_AI; }
@ -257,22 +223,6 @@ public:
const std::string& flag() const { return info_.flag; }
const std::string& flag_icon() const { return info_.flag_icon; }
const std::string& ai_algorithm() const;
const std::string& ai_algorithm_identifier() const;
const config& ai_parameters() const;
const config& ai_memory() const;
void set_ai_memory(const config& ai_mem);
void set_ai_parameters(const config::const_child_itors &ai_parameters);
double leader_value() const { return info_.leader_value; }
void set_leader_value(double value) { info_.leader_value = value; }
double village_value() const { return info_.village_value; }
void set_village_value(double value) { info_.village_value = value; }
int villages_per_scout() const { return info_.villages_per_scout; }
std::vector<target>& targets() { return info_.targets; }
//Returns true if the hex is shrouded/fogged for this side, or
//any other ally with shared vision.
bool shrouded(const map_location& loc) const;

View file

@ -17,6 +17,7 @@
#include "global.hpp"
#include "actions.hpp"
#include "config.hpp"
#include "tod_manager.hpp"
#include "log.hpp"
#include "map.hpp"
@ -35,6 +36,8 @@ static lg::log_domain log_engine("engine");
terrain_filter::terrain_filter():
cfg_(vconfig()),
units_(unit_map()),
cfg_(vconfig(empty_config)),
units_(*resources::units),
max_loop_(),
flat_()
{
@ -43,6 +46,7 @@ terrain_filter::terrain_filter():
#pragma warning(pop)
#endif
terrain_filter::terrain_filter(const vconfig& cfg, const unit_map& units,
const bool flat_tod, const size_t max_loop) :
cfg_(cfg),
@ -91,7 +95,7 @@ namespace {
};
} //end anonymous namespace
bool terrain_filter::match_internal(const map_location& loc, const bool ignore_xy)
bool terrain_filter::match_internal(const map_location& loc, const bool ignore_xy) const
{
if(cfg_.has_attribute("terrain")) {
if(cache_.parsed_terrain == NULL) {
@ -255,7 +259,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x
return true;
}
bool terrain_filter::match(const map_location& loc)
bool terrain_filter::match(const map_location& loc) const
{
if(cfg_["x"] == "recall" && cfg_["y"] == "recall") {
return !resources::game_map->on_board(loc);
@ -322,7 +326,7 @@ bool terrain_filter::match(const map_location& loc)
return false;
}
void terrain_filter::get_locations(std::set<map_location>& locs)
void terrain_filter::get_locations(std::set<map_location>& locs) const
{
std::vector<map_location> xy_vector = parse_location_range(cfg_["x"],cfg_["y"], resources::game_map);
std::set<map_location> xy_set(xy_vector.begin(), xy_vector.end());
@ -461,4 +465,8 @@ void terrain_filter::get_locations(std::set<map_location>& locs)
}
}
config terrain_filter::to_config() const
{
return cfg_.get_config();
}

View file

@ -17,23 +17,25 @@
#include "map_location.hpp"
#include "pathfind.hpp"
#include "variable.hpp"
class config;
class unit;
class vconfig;
class unit_map;
class team;
//terrain_filter: a class that implements the Standard Location Filter
class terrain_filter : public xy_pred {
public:
#ifdef _MSC_VER
// This constructor is required for MSVC 9 SP1 due to a bug there
// see http://social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/34473b8c-0184-4750-a290-08558e4eda4e
// other compilers don't need it.
terrain_filter();
terrain_filter();
#endif
terrain_filter(const vconfig &cfg,
terrain_filter(const vconfig& cfg,
const unit_map& units, const bool flat_tod=false, const size_t max_loop=MAX_MAP_AREA);
terrain_filter(const vconfig& cfg, const terrain_filter& original);
~terrain_filter() {};
@ -42,12 +44,12 @@ public:
terrain_filter& operator=(const terrain_filter &other);
//match: returns true if and only if the given location matches this filter
bool match(const map_location& loc);
bool match(const map_location& loc) const;
virtual bool operator()(const map_location& loc) { return this->match(loc); }
//get_locations: gets all locations on the map that match this filter
// @param locs - out parameter containing the results
void get_locations(std::set<map_location>& locs);
void get_locations(std::set<map_location>& locs) const;
//restrict: limits the allowed radius size and also limits nesting
// The purpose to limit the time spent for WML handling
@ -57,10 +59,11 @@ public:
//flatten: use base time of day -- ignore illumination ability
void flatten(const bool flat_tod=true) { flat_ = flat_tod; }
config to_config() const;
private:
bool match_internal(const map_location& loc, const bool ignore_xy);
bool match_internal(const map_location& loc, const bool ignore_xy) const;
const vconfig& cfg_; //config contains WML for a Standard Location Filter
const vconfig cfg_; //config contains WML for a Standard Location Filter
const unit_map& units_;
struct terrain_filter_cache {
@ -86,7 +89,7 @@ private:
std::vector< std::pair<terrain_filter, std::map<map_location,bool> > > adjacent_match_cache;
};
terrain_filter_cache cache_;
mutable terrain_filter_cache cache_;
size_t max_loop_;
bool flat_;
};