mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-21 14:01:17 +00:00
785 lines
22 KiB
C++
785 lines
22 KiB
C++
/* $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.
|
|
*/
|
|
|
|
/**
|
|
* Managing the AI lifecycle and interface for the rest of Wesnoth
|
|
* @file ai/manager.cpp
|
|
*/
|
|
|
|
#include "ai2/ai.hpp"
|
|
#include "composite/ai.hpp"
|
|
#include "configuration.hpp"
|
|
#include "contexts.hpp"
|
|
#include "default/ai.hpp"
|
|
#include "dfool/ai.hpp"
|
|
#include "manager.hpp"
|
|
#include "formula/ai.hpp"
|
|
#include "registry.hpp"
|
|
#include "../game_events.hpp"
|
|
#include "../game_preferences.hpp"
|
|
#include "../log.hpp"
|
|
#include "../replay.hpp"
|
|
#include "../serialization/string_utils.hpp"
|
|
#include "../statistics.hpp"
|
|
|
|
#include <map>
|
|
#include <stack>
|
|
#include <vector>
|
|
|
|
namespace ai {
|
|
|
|
const std::string manager::AI_TYPE_COMPOSITE_AI = "composite_ai";
|
|
const std::string manager::AI_TYPE_SAMPLE_AI = "sample_ai";
|
|
const std::string manager::AI_TYPE_IDLE_AI = "idle_ai";
|
|
const std::string manager::AI_TYPE_FORMULA_AI = "formula_ai";
|
|
const std::string manager::AI_TYPE_DFOOL_AI = "dfool_ai";
|
|
const std::string manager::AI_TYPE_AI2 = "ai2";
|
|
const std::string manager::AI_TYPE_DEFAULT = "default";
|
|
|
|
|
|
static lg::log_domain log_ai_manager("ai/manager");
|
|
#define DBG_AI_MANAGER LOG_STREAM(debug, log_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 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;
|
|
}
|
|
|
|
|
|
void holder::init( side_number side )
|
|
{
|
|
if (side_context_ == NULL) {
|
|
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_,cfg_);
|
|
readonly_context_->on_readonly_context_create();
|
|
}
|
|
if (readwrite_context_ == NULL){
|
|
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_);//@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();
|
|
}
|
|
if (!this->ai_) {
|
|
ERR_AI_MANAGER << describe_ai()<<"AI lazy initialization error!" << std::endl;
|
|
}
|
|
|
|
}
|
|
|
|
holder::~holder()
|
|
{
|
|
if (this->ai_) {
|
|
LOG_AI_MANAGER << describe_ai() << "Managed AI will be deleted" << std::endl;
|
|
}
|
|
delete this->default_ai_context_;
|
|
delete this->readwrite_context_;
|
|
delete this->readonly_context_;
|
|
delete this->side_context_;
|
|
}
|
|
|
|
|
|
interface& holder::get_ai_ref( side_number side )
|
|
{
|
|
if (!this->ai_) {
|
|
this->init(side);
|
|
}
|
|
assert(this->ai_);
|
|
|
|
return *this->ai_;
|
|
}
|
|
|
|
interface& holder::get_ai_ref()
|
|
{
|
|
return get_ai_ref(this->side_);
|
|
}
|
|
|
|
|
|
config holder::to_config() const
|
|
{
|
|
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
|
|
}
|
|
}
|
|
|
|
|
|
|
|
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){
|
|
sidestr = "'command_side'";
|
|
} else {
|
|
sidestr = lexical_cast<std::string>(this->side_);
|
|
}
|
|
if (this->ai_!=NULL) {
|
|
return this->ai_->describe_self()+std::string(" for side ")+sidestr+std::string(" : ");
|
|
} else {
|
|
return std::string("[")+cfg_["ai_algorithm"]+std::string("] (not initialized) for side ")+sidestr+std::string(" : ");
|
|
}
|
|
}
|
|
|
|
|
|
const std::string holder::get_ai_identifier() const
|
|
{
|
|
return cfg_["id"];
|
|
}
|
|
|
|
// =======================================================================
|
|
// AI COMMAND HISTORY ITEM
|
|
// =======================================================================
|
|
|
|
command_history_item::command_history_item()
|
|
: number_(0), command_()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
command_history_item::command_history_item( side_number number, const std::string& command )
|
|
: number_(number), command_(command)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
command_history_item::~command_history_item()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
int command_history_item::get_number() const
|
|
{
|
|
return this->number_;
|
|
}
|
|
|
|
|
|
void command_history_item::set_number( int number )
|
|
{
|
|
this->number_ = number;
|
|
}
|
|
|
|
const std::string& command_history_item::get_command() const
|
|
{
|
|
return this->command_;
|
|
}
|
|
|
|
|
|
void command_history_item::set_command( const std::string& command )
|
|
{
|
|
this->command_ = command;
|
|
}
|
|
|
|
// =======================================================================
|
|
// LIFECYCLE
|
|
// =======================================================================
|
|
|
|
|
|
manager::manager()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
manager::~manager()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
manager::AI_map_of_stacks manager::ai_map_;
|
|
game_info *manager::ai_info_;
|
|
events::generic_event manager::user_interact_("ai_user_interact");
|
|
events::generic_event manager::sync_network_("ai_sync_network");
|
|
events::generic_event manager::unit_recruited_("ai_unit_recruited");
|
|
events::generic_event manager::unit_moved_("ai_unit_moved");
|
|
events::generic_event manager::enemy_attacked_("ai_enemy_attacked");
|
|
events::generic_event manager::turn_started_("ai_turn_started");
|
|
int manager::last_interact_ = 0;
|
|
int manager::num_interact_ = 0;
|
|
|
|
|
|
void manager::set_ai_info(const game_info& i)
|
|
{
|
|
if (ai_info_!=NULL){
|
|
clear_ai_info();
|
|
}
|
|
ai_info_ = new game_info(i);
|
|
registry::init();
|
|
}
|
|
|
|
|
|
void manager::clear_ai_info(){
|
|
if (ai_info_ != NULL){
|
|
delete ai_info_;
|
|
ai_info_ = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void manager::add_observer( events::observer* event_observer){
|
|
user_interact_.attach_handler(event_observer);
|
|
sync_network_.attach_handler(event_observer);
|
|
unit_recruited_.attach_handler(event_observer);
|
|
unit_moved_.attach_handler(event_observer);
|
|
enemy_attacked_.attach_handler(event_observer);
|
|
turn_started_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_observer(events::observer* event_observer){
|
|
user_interact_.detach_handler(event_observer);
|
|
sync_network_.detach_handler(event_observer);
|
|
unit_recruited_.detach_handler(event_observer);
|
|
unit_moved_.detach_handler(event_observer);
|
|
enemy_attacked_.detach_handler(event_observer);
|
|
turn_started_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_gamestate_observer( events::observer* event_observer){
|
|
unit_recruited_.attach_handler(event_observer);
|
|
unit_moved_.attach_handler(event_observer);
|
|
enemy_attacked_.attach_handler(event_observer);
|
|
turn_started_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_gamestate_observer(events::observer* event_observer){
|
|
unit_recruited_.detach_handler(event_observer);
|
|
unit_moved_.detach_handler(event_observer);
|
|
enemy_attacked_.detach_handler(event_observer);
|
|
turn_started_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_user_interact_observer( events::observer* event_observer )
|
|
{
|
|
user_interact_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_sync_network_observer( events::observer* event_observer )
|
|
{
|
|
sync_network_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_unit_recruited_observer( events::observer* event_observer )
|
|
{
|
|
unit_recruited_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_unit_moved_observer( events::observer* event_observer )
|
|
{
|
|
unit_moved_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_enemy_attacked_observer( events::observer* event_observer )
|
|
{
|
|
enemy_attacked_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::add_turn_started_observer( events::observer* event_observer )
|
|
{
|
|
turn_started_.attach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_user_interact_observer( events::observer* event_observer )
|
|
{
|
|
user_interact_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::delete_sync_network_observer( events::observer* event_observer )
|
|
{
|
|
sync_network_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_unit_recruited_observer( events::observer* event_observer )
|
|
{
|
|
unit_recruited_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_unit_moved_observer( events::observer* event_observer )
|
|
{
|
|
unit_moved_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_enemy_attacked_observer( events::observer* event_observer )
|
|
{
|
|
enemy_attacked_.detach_handler(event_observer);
|
|
}
|
|
|
|
|
|
void manager::remove_turn_started_observer( events::observer* event_observer )
|
|
{
|
|
turn_started_.detach_handler(event_observer);
|
|
}
|
|
|
|
void manager::raise_user_interact() {
|
|
const int interact_time = 30;
|
|
const int time_since_interact = SDL_GetTicks() - last_interact_;
|
|
if(time_since_interact < interact_time) {
|
|
return;
|
|
}
|
|
|
|
++num_interact_;
|
|
user_interact_.notify_observers();
|
|
|
|
last_interact_ = SDL_GetTicks();
|
|
|
|
}
|
|
|
|
void manager::raise_sync_network() {
|
|
sync_network_.notify_observers();
|
|
}
|
|
|
|
void manager::raise_unit_recruited() {
|
|
unit_recruited_.notify_observers();
|
|
}
|
|
|
|
void manager::raise_unit_moved() {
|
|
unit_moved_.notify_observers();
|
|
}
|
|
|
|
void manager::raise_enemy_attacked() {
|
|
enemy_attacked_.notify_observers();
|
|
}
|
|
|
|
|
|
void manager::raise_turn_started() {
|
|
turn_started_.notify_observers();
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// EVALUATION
|
|
// =======================================================================
|
|
|
|
const std::string manager::evaluate_command( side_number side, const std::string& str )
|
|
{
|
|
//insert new command into history
|
|
history_.push_back(command_history_item(history_item_counter_++,str));
|
|
|
|
//prune history - erase 1/2 of it if it grows too large
|
|
if (history_.size()>MAX_HISTORY_SIZE){
|
|
history_.erase(history_.begin(),history_.begin()+MAX_HISTORY_SIZE/2);
|
|
LOG_AI_MANAGER << "AI MANAGER: pruned history" << std::endl;
|
|
}
|
|
|
|
if (!should_intercept(str)){
|
|
interface& ai = get_command_ai(side);
|
|
return ai.evaluate(str);
|
|
}
|
|
|
|
return internal_evaluate_command(side,str);
|
|
}
|
|
|
|
|
|
bool manager::should_intercept( const std::string& str )
|
|
{
|
|
if (str.length()<1) {
|
|
return false;
|
|
}
|
|
if (str.at(0)=='!'){
|
|
return true;
|
|
}
|
|
if (str.at(0)=='?'){
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
}
|
|
|
|
std::deque< command_history_item > manager::history_;
|
|
long manager::history_item_counter_ = 1;
|
|
|
|
//this is stub code to allow testing of basic 'history', 'repeat-last-command', 'add/remove/replace ai' capabilities.
|
|
//yes, it doesn't look nice. but it is usable.
|
|
//to be refactored at earliest opportunity
|
|
//@todo 1.7 extract to separate class which will use fai or lua parser
|
|
const std::string manager::internal_evaluate_command( side_number side, const std::string& str ){
|
|
const int MAX_HISTORY_VISIBLE = 30;
|
|
|
|
//repeat last command
|
|
if (str=="!") {
|
|
//this command should not be recorded in history
|
|
if (!history_.empty()){
|
|
history_.pop_back();
|
|
history_item_counter_--;
|
|
}
|
|
|
|
if (history_.empty()){
|
|
return "AI MANAGER: empty history";
|
|
}
|
|
return evaluate_command(side, history_.back().get_command());//no infinite loop since '!' commands are not present in history
|
|
};
|
|
//show last command
|
|
if (str=="?") {
|
|
//this command should not be recorded in history
|
|
if (!history_.empty()){
|
|
history_.pop_back();
|
|
history_item_counter_--;
|
|
}
|
|
|
|
if (history_.empty()){
|
|
return "AI MANAGER: History is empty";
|
|
}
|
|
|
|
int n = std::min<int>( MAX_HISTORY_VISIBLE, history_.size() );
|
|
std::stringstream strstream;
|
|
strstream << "AI MANAGER: History - last "<< n <<" commands:\n";
|
|
std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
|
|
|
|
for (int cmd_id=n; cmd_id>0; --cmd_id){
|
|
strstream << j->get_number() << " :" << j->get_command() << '\n';
|
|
j++;//this is *reverse* iterator
|
|
}
|
|
|
|
return strstream.str();
|
|
};
|
|
|
|
|
|
std::vector< std::string > cmd = utils::paranthetical_split(str, ' ',"'","'");
|
|
|
|
if (cmd.size()==3){
|
|
//!add_ai side file
|
|
if (cmd.at(0)=="!add_ai"){
|
|
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_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;
|
|
}
|
|
}
|
|
//!replace_ai side file
|
|
if (cmd.at(0)=="!replace_ai"){
|
|
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_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;
|
|
}
|
|
}
|
|
|
|
} else if (cmd.size()==2){
|
|
//!remove_ai side
|
|
if (cmd.at(0)=="!remove_ai"){
|
|
side_number side = lexical_cast<side_number>(cmd.at(1));
|
|
remove_ai_for_side(side);
|
|
return std::string("AI MANAGER: made an attempt to remove AI for side ")+lexical_cast<std::string>(side);
|
|
}
|
|
if (cmd.at(0)=="!"){
|
|
//this command should not be recorded in history
|
|
if (!history_.empty()){
|
|
history_.pop_back();
|
|
history_item_counter_--;
|
|
}
|
|
|
|
int command = lexical_cast<int>(cmd.at(1));
|
|
std::deque< command_history_item >::reverse_iterator j = history_.rbegin();
|
|
//yes, the iterator could be precisely positioned (since command numbers go 1,2,3,4,..). will do it later.
|
|
while ( (j!=history_.rend()) && (j->get_number()!=command) ){
|
|
j++;// this is *reverse* iterator
|
|
}
|
|
if (j!=history_.rend()){
|
|
return evaluate_command(side,j->get_command());//no infinite loop since '!' commands are not present in history
|
|
}
|
|
return "AI MANAGER: no command with requested number found";
|
|
}
|
|
} else if (cmd.size()==1){
|
|
if (cmd.at(0)=="!help") {
|
|
return
|
|
"known commands:\n"
|
|
"! - repeat last command (? and ! do not count)\n"
|
|
"! NUMBER - repeat numbered command\n"
|
|
"? - show a history list\n"
|
|
"!add_ai TEAM FILE - add a AI to side (0 - command AI, N - AI for side #N) from file\n"
|
|
"!remove_ai TEAM - remove AI from side (0 - command AI, N - AI for side #N)\n"
|
|
"!replace_ai TEAM FILE - replace AI of side (0 - command AI, N - AI for side #N) from file\n"
|
|
"!help - show this help message";
|
|
}
|
|
}
|
|
|
|
|
|
return "AI MANAGER: nothing to do";
|
|
}
|
|
|
|
// =======================================================================
|
|
// ADD, CREATE AIs, OR LIST AI TYPES
|
|
// =======================================================================
|
|
|
|
//@todo 1.7 add error reporting
|
|
bool manager::add_ai_for_side_from_file( side_number side, const std::string& file, bool replace )
|
|
{
|
|
config cfg;
|
|
if (!configuration::get_side_config_from_file(file,cfg)){
|
|
ERR_AI_MANAGER << " unable to read [SIDE] config for side "<< side << "from file [" << file <<"]"<< std::endl;
|
|
return false;
|
|
}
|
|
return add_ai_for_side_from_config(side,cfg,replace);
|
|
}
|
|
|
|
|
|
bool manager::add_ai_for_side_from_config( side_number side, const config& cfg, bool replace ){
|
|
config parsed_cfg;
|
|
configuration::parse_side_config(cfg, parsed_cfg);
|
|
|
|
if (replace) {
|
|
remove_ai_for_side(side);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
//@todo 1.7 add error reporting
|
|
bool manager::add_ai_for_side( side_number side, const std::string& ai_algorithm_type, bool replace )
|
|
{
|
|
if (replace) {
|
|
remove_ai_for_side (side);
|
|
}
|
|
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;
|
|
}
|
|
|
|
|
|
ai_ptr manager::create_transient_ai(const std::string &ai_algorithm_type, const config &cfg, default_ai_context *ai_context )
|
|
{
|
|
assert(ai_context!=NULL);
|
|
|
|
//to add your own ai, register it in registry,cpp
|
|
ai_factory::factory_map::iterator aii = ai_factory::get_list().find(ai_algorithm_type);
|
|
if (aii == ai_factory::get_list().end()){
|
|
aii = ai_factory::get_list().find("");
|
|
if (aii == ai_factory::get_list().end()){
|
|
throw game::game_error("no default ai set!");
|
|
}
|
|
}
|
|
LOG_AI_MANAGER << "Creating new AI of type [" << ai_algorithm_type << "]"<< std::endl;
|
|
ai_ptr new_ai = aii->second->get_new_instance(*ai_context,cfg);
|
|
return new_ai;
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// REMOVE
|
|
// =======================================================================
|
|
|
|
void manager::remove_ai_for_side( side_number side )
|
|
{
|
|
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
|
|
if (!ai_stack_for_specific_side.empty()){
|
|
ai_stack_for_specific_side.pop();
|
|
}
|
|
}
|
|
|
|
|
|
void manager::remove_all_ais_for_side( side_number side )
|
|
{
|
|
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
|
|
|
|
//clear the stack. std::stack doesn't have a '.clear()' method to do it
|
|
while (!ai_stack_for_specific_side.empty()){
|
|
ai_stack_for_specific_side.pop();
|
|
}
|
|
}
|
|
|
|
|
|
void manager::clear_ais()
|
|
{
|
|
ai_map_.clear();
|
|
}
|
|
|
|
// =======================================================================
|
|
// Work with active AI parameters
|
|
// =======================================================================
|
|
std::string manager::get_active_ai_identifier_for_side( side_number side )
|
|
{
|
|
return get_active_ai_holder_for_side(side).get_ai_identifier();
|
|
}
|
|
|
|
|
|
config manager::to_config( side_number side )
|
|
{
|
|
return get_active_ai_holder_for_side(side).to_config();
|
|
}
|
|
|
|
|
|
game_info& manager::get_active_ai_info_for_side( side_number /*side*/ )
|
|
{
|
|
return *ai_info_;
|
|
}
|
|
|
|
|
|
game_info& manager::get_ai_info()
|
|
{
|
|
return *ai_info_;
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// PROXY
|
|
// =======================================================================
|
|
|
|
void manager::play_turn( side_number side ){
|
|
last_interact_ = 0;
|
|
num_interact_ = 0;
|
|
const int turn_start_time = SDL_GetTicks();
|
|
/*hack. @todo 1.8 rework via extended event system*/
|
|
get_ai_info().recent_attacks.clear();
|
|
interface& ai_obj = get_active_ai_for_side(side);
|
|
raise_turn_started();
|
|
ai_obj.new_turn();
|
|
ai_obj.play_turn();
|
|
const int turn_end_time= SDL_GetTicks();
|
|
DBG_AI_MANAGER << "side " << side << ": number of user interactions: "<<num_interact_<<std::endl;
|
|
DBG_AI_MANAGER << "side " << side << ": total turn time: "<<turn_end_time - turn_start_time << " ms "<< std::endl;
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// PRIVATE
|
|
// =======================================================================
|
|
// =======================================================================
|
|
// AI STACKS
|
|
// =======================================================================
|
|
std::stack<holder>& manager::get_or_create_ai_stack_for_side( side_number side )
|
|
{
|
|
AI_map_of_stacks::iterator iter = ai_map_.find(side);
|
|
if (iter!=ai_map_.end()){
|
|
return iter->second;
|
|
}
|
|
return ai_map_.insert(std::make_pair(side, std::stack<holder>())).first->second;
|
|
}
|
|
|
|
// =======================================================================
|
|
// AI HOLDERS
|
|
// =======================================================================
|
|
holder& manager::get_active_ai_holder_for_side( side_number side )
|
|
{
|
|
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
|
|
|
|
if (!ai_stack_for_specific_side.empty()){
|
|
return ai_stack_for_specific_side.top();
|
|
} else if (side==manager::AI_TEAM_COMMAND_AI){
|
|
return get_command_ai_holder( side );
|
|
} else {
|
|
return get_fallback_ai_holder( side );
|
|
}
|
|
|
|
}
|
|
|
|
holder& manager::get_command_ai_holder( side_number /*side*/ )
|
|
{
|
|
holder& ai_holder = get_or_create_active_ai_holder_for_side_without_fallback(manager::AI_TEAM_COMMAND_AI,AI_TYPE_FORMULA_AI);
|
|
return ai_holder;
|
|
}
|
|
|
|
holder& manager::get_fallback_ai_holder( side_number /*side*/ )
|
|
{
|
|
holder& ai_holder = get_or_create_active_ai_holder_for_side_without_fallback(manager::AI_TEAM_FALLBACK_AI,AI_TYPE_IDLE_AI);
|
|
return ai_holder;
|
|
}
|
|
|
|
holder& manager::get_or_create_active_ai_holder_for_side_without_fallback(side_number side, const std::string& ai_algorithm_type)
|
|
{
|
|
std::stack<holder>& ai_stack_for_specific_side = get_or_create_ai_stack_for_side(side);
|
|
|
|
if (!ai_stack_for_specific_side.empty()){
|
|
return ai_stack_for_specific_side.top();
|
|
} else {
|
|
config cfg = configuration::get_default_ai_parameters();
|
|
cfg["ai_algorithm"] = ai_algorithm_type;//@todo: replace with fallback stage
|
|
holder new_holder(side, cfg);
|
|
ai_stack_for_specific_side.push(new_holder);
|
|
return ai_stack_for_specific_side.top();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// =======================================================================
|
|
// AI POINTERS
|
|
// =======================================================================
|
|
|
|
interface& manager::get_active_ai_for_side( side_number side )
|
|
{
|
|
return get_active_ai_holder_for_side(side).get_ai_ref();
|
|
}
|
|
|
|
|
|
interface& manager::get_or_create_active_ai_for_side_without_fallback( side_number side, const std::string& ai_algorithm_type )
|
|
{
|
|
holder& ai_holder = get_or_create_active_ai_holder_for_side_without_fallback(side,ai_algorithm_type);
|
|
return ai_holder.get_ai_ref();
|
|
}
|
|
|
|
interface& manager::get_command_ai( side_number side )
|
|
{
|
|
holder& ai_holder = get_command_ai_holder(side);
|
|
interface& ai = ai_holder.get_ai_ref(side);
|
|
return ai;
|
|
}
|
|
|
|
interface& manager::get_fallback_ai( side_number side )
|
|
{
|
|
holder& ai_holder = get_fallback_ai_holder(side);
|
|
interface& ai = ai_holder.get_ai_ref(side);
|
|
return ai;
|
|
}
|
|
|
|
// =======================================================================
|
|
// MISC
|
|
// =======================================================================
|
|
|
|
} //end of namespace ai
|