ai/configuration.cpp

Go to the documentation of this file.
00001 /* $Id: configuration.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2009 - 2012 by Yurii Chernyi <terraninfo@terraninfo.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 
00017 /**
00018  * Managing the AI configuration
00019  * @file
00020  */
00021 
00022 #include "configuration.hpp"
00023 
00024 #include "../filesystem.hpp"
00025 #include "../foreach.hpp"
00026 #include "../log.hpp"
00027 #include "../serialization/parser.hpp"
00028 #include "../serialization/preprocessor.hpp"
00029 #include "../team.hpp"
00030 
00031 #include <vector>
00032 
00033 namespace ai {
00034 
00035 static lg::log_domain log_ai_configuration("ai/config");
00036 #define DBG_AI_CONFIGURATION LOG_STREAM(debug, log_ai_configuration)
00037 #define LOG_AI_CONFIGURATION LOG_STREAM(info, log_ai_configuration)
00038 #define WRN_AI_CONFIGURATION LOG_STREAM(warn, log_ai_configuration)
00039 #define ERR_AI_CONFIGURATION LOG_STREAM(err, log_ai_configuration)
00040 
00041 
00042 class well_known_aspect {
00043 public:
00044     well_known_aspect(const std::string &name, bool attr = true)
00045         : name_(name),was_an_attribute_(attr)
00046     {
00047     }
00048 
00049     virtual ~well_known_aspect() {};
00050 
00051     std::string name_;
00052     bool was_an_attribute_;
00053 };
00054 
00055 std::vector<well_known_aspect> well_known_aspects;
00056 
00057 void configuration::init(const config &game_config)
00058 {
00059     ai_configurations_.clear();
00060     era_ai_configurations_.clear();
00061     well_known_aspects.clear();
00062     well_known_aspects.push_back(well_known_aspect("aggression"));
00063     well_known_aspects.push_back(well_known_aspect("attack_depth"));
00064     well_known_aspects.push_back(well_known_aspect("attacks"));
00065     well_known_aspects.push_back(well_known_aspect("avoid",false));
00066     well_known_aspects.push_back(well_known_aspect("caution"));
00067     well_known_aspects.push_back(well_known_aspect("grouping"));
00068     well_known_aspects.push_back(well_known_aspect("leader_aggression"));
00069     well_known_aspects.push_back(well_known_aspect("leader_goal",false));
00070     well_known_aspects.push_back(well_known_aspect("leader_value"));
00071     well_known_aspects.push_back(well_known_aspect("number_of_possible_recruits_to_force_recruit"));
00072     well_known_aspects.push_back(well_known_aspect("passive_leader"));
00073     well_known_aspects.push_back(well_known_aspect("passive_leader_shares_keep"));
00074     //well_known_aspects.push_back(well_known_aspect("protect_leader"));
00075     //well_known_aspects.push_back(well_known_aspect("protect_leader_radius"));
00076     //well_known_aspects.push_back(well_known_aspect("protect_location",false));
00077     //well_known_aspects.push_back(well_known_aspect("protect_unit",false));
00078     well_known_aspects.push_back(well_known_aspect("recruitment"));
00079     well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_combat"));
00080     well_known_aspects.push_back(well_known_aspect("recruitment_ignore_bad_movement"));
00081     well_known_aspects.push_back(well_known_aspect("recruitment_pattern"));
00082     well_known_aspects.push_back(well_known_aspect("scout_village_targeting"));
00083     well_known_aspects.push_back(well_known_aspect("simple_targeting"));
00084     well_known_aspects.push_back(well_known_aspect("support_villages"));
00085     well_known_aspects.push_back(well_known_aspect("village_value"));
00086     well_known_aspects.push_back(well_known_aspect("villages_per_scout"));
00087 
00088     const config &ais = game_config.child("ais");
00089     default_config_ = ais.child("default_config");
00090     if (!default_config_) {
00091         ERR_AI_CONFIGURATION << "Missing AI [default_config]. Therefore, default_config_ set to empty." << std::endl;
00092         default_config_ = config();
00093     }
00094 
00095 
00096     foreach (const config &ai_configuration, ais.child_range("ai")) {
00097         const std::string &id = ai_configuration["id"];
00098         if (id.empty()){
00099 
00100             ERR_AI_CONFIGURATION << "skipped AI config due to missing id" << ". Config contains:"<< std::endl << ai_configuration << std::endl;
00101             continue;
00102         }
00103         if (ai_configurations_.count(id)>0){
00104             ERR_AI_CONFIGURATION << "skipped AI config due to duplicate id [" << id << "]. Config contains:"<< std::endl << ai_configuration << std::endl;
00105             continue;
00106         }
00107 
00108         description desc;
00109         desc.id=id;
00110         desc.text = ai_configuration["description"].str();
00111         desc.cfg=ai_configuration;
00112 
00113         ai_configurations_.insert(std::make_pair(id,desc));
00114         LOG_AI_CONFIGURATION << "loaded AI config: " << ai_configuration["description"] << std::endl;
00115     }
00116 }
00117 
00118 void configuration::add_era_ai_from_config(const config &era)
00119 {
00120     era_ai_configurations_.clear();
00121     foreach (const config &ai_configuration, era.child_range("ai")) {
00122         const std::string &id = ai_configuration["id"];
00123         if (id.empty()){
00124 
00125             ERR_AI_CONFIGURATION << "skipped AI config due to missing id" << ". Config contains:"<< std::endl << ai_configuration << std::endl;
00126             continue;
00127         }
00128         if (era_ai_configurations_.count(id)>0){
00129             ERR_AI_CONFIGURATION << "skipped AI config due to duplicate id [" << id << "]. Config contains:"<< std::endl << ai_configuration << std::endl;
00130             continue;
00131         }
00132 
00133         description desc;
00134         desc.id=id;
00135         desc.text = ai_configuration["description"].str();
00136         desc.cfg=ai_configuration;
00137 
00138         era_ai_configurations_.insert(std::make_pair(id,desc));
00139         LOG_AI_CONFIGURATION << "loaded AI config: " << ai_configuration["description"] << std::endl;
00140     }
00141 }
00142 
00143 std::vector<description*> configuration::get_available_ais(){
00144     std::vector<description*> ais_list;
00145     for(description_map::iterator desc = ai_configurations_.begin(); desc!=ai_configurations_.end(); ++desc) {
00146         ais_list.push_back(&desc->second);
00147         DBG_AI_CONFIGURATION << "has ai with config: "<< std::endl << desc->second.cfg<< std::endl;
00148     }
00149     for(description_map::iterator desc = era_ai_configurations_.begin(); desc!=era_ai_configurations_.end(); ++desc) {
00150         ais_list.push_back(&desc->second);
00151         DBG_AI_CONFIGURATION << "has ai with config: "<< std::endl << desc->second.cfg<< std::endl;
00152     }
00153     return ais_list;
00154 }
00155 
00156 const config& configuration::get_ai_config_for(const std::string &id)
00157 {
00158     description_map::iterator cfg_it = ai_configurations_.find(id);
00159     if (cfg_it==ai_configurations_.end()){
00160         description_map::iterator era_cfg_it = era_ai_configurations_.find(id);
00161         if (era_cfg_it==era_ai_configurations_.end()){
00162             return default_config_;
00163         } else {
00164             return era_cfg_it->second.cfg;
00165         }
00166     }
00167     return cfg_it->second.cfg;
00168 }
00169 
00170 
00171 configuration::description_map configuration::ai_configurations_ = configuration::description_map();
00172 configuration::description_map configuration::era_ai_configurations_ = configuration::description_map();
00173 config configuration::default_config_ = config();
00174 
00175 bool configuration::get_side_config_from_file(const std::string& file, config& cfg ){
00176     try {
00177         scoped_istream stream = preprocess_file(get_wml_location(file));
00178         read(cfg, *stream);
00179         LOG_AI_CONFIGURATION << "Reading AI configuration from file '" << file  << "'" << std::endl;
00180     } catch(config::error &) {
00181         ERR_AI_CONFIGURATION << "Error while reading AI configuration from file '" << file  << "'" << std::endl;
00182         return false;
00183     }
00184     LOG_AI_CONFIGURATION << "Successfully read AI configuration from file '" << file  << "'" << std::endl;
00185     return true;
00186 }
00187 
00188 const config& configuration::get_default_ai_parameters()
00189 {
00190     return default_config_;
00191 }
00192 
00193 
00194 bool configuration::upgrade_aspect_config_from_1_07_02_to_1_07_03(side_number /*side*/, const config& cfg, config& parsed_cfg, const std::string &id, bool aspect_was_attribute)
00195 {
00196     config aspect_config;
00197     aspect_config["id"] = id;
00198 
00199     foreach (const config &aiparam, cfg.child_range("ai")) {
00200         const config &_aspect = aiparam.find_child("aspect","id",id);
00201         if (_aspect) {
00202             aspect_config.append(_aspect);
00203         }
00204 
00205         if (aspect_was_attribute && !aiparam.has_attribute(id)) {
00206             continue;//we are looking for an attribute but it isn't present
00207         }
00208 
00209         if (!aspect_was_attribute && !aiparam.child(id)) {
00210             continue;//we are looking for a child but it isn't present
00211         }
00212 
00213         config facet_config;
00214         facet_config["engine"] = "cpp";
00215         facet_config["name"] = "standard_aspect";
00216         if (aspect_was_attribute) {
00217             facet_config["value"] = aiparam[id];
00218         } else {
00219             foreach (const config &value, aiparam.child_range(id)) {
00220                 facet_config.add_child("value",value);
00221             }
00222         }
00223 
00224         if (const config::attribute_value *v = aiparam.get("turns")) {
00225             facet_config["turns"] = *v;
00226         }
00227         if (const config::attribute_value *v = aiparam.get("time_of_day")) {
00228             facet_config["time_of_day"] = *v;
00229         }
00230 
00231         aspect_config.add_child("facet",facet_config);
00232     }
00233 
00234     parsed_cfg.add_child("aspect",aspect_config);
00235     return true;
00236 }
00237 
00238 
00239 bool configuration::parse_side_config(side_number side, const config& original_cfg, config &cfg )
00240 {
00241     LOG_AI_CONFIGURATION << "side "<< side <<": parsing AI configuration from config" << std::endl;
00242 
00243     //leave only the [ai] children
00244     cfg = config();
00245     foreach (const config &aiparam, original_cfg.child_range("ai")) {
00246         cfg.add_child("ai",aiparam);
00247     }
00248 
00249     //backward-compatibility hack: put ai_algorithm if it is present
00250     if (const config::attribute_value *v = original_cfg.get("ai_algorithm")) {
00251         config ai_a;
00252         ai_a["ai_algorithm"] = *v;
00253         cfg.add_child("ai",ai_a);
00254     }
00255     DBG_AI_CONFIGURATION << "side " << side << ": config contains:"<< std::endl << cfg << std::endl;
00256 
00257     //insert default config at the beginning
00258     if (default_config_) {
00259         DBG_AI_CONFIGURATION << "side "<< side <<": applying default configuration" << std::endl;
00260         cfg.add_child_at("ai",default_config_,0);
00261     } else {
00262         ERR_AI_CONFIGURATION << "side "<< side <<": default configuration is not available, do not applying it" << std::endl;
00263     }
00264 
00265     //find version
00266     int version = 10600;
00267     foreach (const config &aiparam, cfg.child_range("ai")) {
00268         if (const config::attribute_value *a = aiparam.get("version")){
00269             int v = a->to_int(version);
00270             if (version<v) {
00271                 version = v;
00272             }
00273         }
00274     }
00275 
00276     if (version<10703) {
00277         if (!upgrade_side_config_from_1_07_02_to_1_07_03(side, cfg)) {
00278             return false;
00279         }
00280         version = 10703;
00281     }
00282 
00283 
00284     if (version<10710) {
00285         version = 10710;
00286     }
00287 
00288     //construct new-style integrated config
00289     LOG_AI_CONFIGURATION << "side "<< side << ": doing final operations on AI config"<< std::endl;
00290     config parsed_cfg = config();
00291 
00292     LOG_AI_CONFIGURATION << "side "<< side <<": merging AI configurations"<< std::endl;
00293     foreach (const config &aiparam, cfg.child_range("ai")) {
00294         parsed_cfg.append(aiparam);
00295     }
00296 
00297     LOG_AI_CONFIGURATION << "side "<< side <<": setting config version to "<< version << std::endl;
00298     parsed_cfg["version"] = version;
00299 
00300 
00301     LOG_AI_CONFIGURATION << "side "<< side <<": merging AI aspect with the same id"<< std::endl;
00302     parsed_cfg.merge_children_by_attribute("aspect","id");
00303 
00304     LOG_AI_CONFIGURATION << "side "<< side <<": removing duplicate [default] tags from aspects"<< std::endl;
00305     foreach (config &aspect_cfg, parsed_cfg.child_range("aspect")) {
00306         if (!aspect_cfg.child("default")) {
00307             WRN_AI_CONFIGURATION << "side "<< side <<": aspect with id=["<<aspect_cfg["id"]<<"] lacks default config facet!" <<std::endl;
00308             continue;
00309         }
00310         config c = aspect_cfg.child("default");
00311         aspect_cfg.clear_children("default");
00312         aspect_cfg.add_child("default",c);
00313     }
00314 
00315     DBG_AI_CONFIGURATION << "side "<< side <<": done parsing side config, it contains:"<< std::endl << parsed_cfg << std::endl;
00316     LOG_AI_CONFIGURATION << "side "<< side <<": done parsing side config"<< std::endl;
00317 
00318     cfg = parsed_cfg;
00319     return true;
00320 
00321 }
00322 
00323 
00324 static void transfer_turns_and_time_of_day_data(const config &src, config &dst)
00325 {
00326     if (const config::attribute_value *turns = src.get("turns")) {
00327         dst["turns"] = *turns;
00328     }
00329     if (const config::attribute_value *time_of_day = src.get("time_of_day")) {
00330         dst["time_of_day"] = *time_of_day;
00331     }
00332 }
00333 
00334 
00335 bool configuration::upgrade_side_config_from_1_07_02_to_1_07_03(side_number side, config &cfg)
00336 {
00337     LOG_AI_CONFIGURATION << "side "<< side <<": upgrading ai config version from version 1.7.2 to 1.7.3"<< std::endl;
00338     config parsed_cfg;
00339 
00340     bool is_idle_ai = false;
00341     if (cfg["ai_algorithm"]=="idle_ai") {
00342         is_idle_ai = true;
00343     } else {
00344         foreach (config &aiparam, cfg.child_range("ai")) {
00345             if (aiparam["ai_algorithm"]=="idle_ai") {
00346                 is_idle_ai = true;
00347                 break;
00348             }
00349         }
00350     }
00351 
00352     if (!is_idle_ai) {
00353         parsed_cfg = get_ai_config_for("testing_ai_default");
00354     }
00355 
00356     //get values of all aspects
00357     upgrade_aspect_configs_from_1_07_02_to_1_07_03(side, cfg.child_range("ai"), parsed_cfg);
00358 
00359     //dump the rest of the config into fallback stage
00360 
00361     config fallback_stage_cfg_ai;
00362 
00363     foreach (config &aiparam, cfg.child_range("ai")) {
00364         foreach (const well_known_aspect &wka, well_known_aspects) {
00365             if (wka.was_an_attribute_) {
00366                 aiparam.remove_attribute(wka.name_);
00367             } else {
00368                 aiparam.clear_children(wka.name_);
00369             }
00370         }
00371 
00372 
00373         foreach (const config &aitarget, aiparam.child_range("target")) {
00374             config aigoal;
00375             transfer_turns_and_time_of_day_data(aiparam,aigoal);
00376 
00377             if (const config::attribute_value *v = aitarget.get("value")) {
00378                 aigoal["value"] = *v;
00379             } else {
00380                 aigoal["value"] = 0;
00381             }
00382 
00383             config &aigoalcriteria = aigoal.add_child("criteria",aitarget);
00384             aigoalcriteria.remove_attribute("value");
00385 
00386             parsed_cfg.add_child("goal",aigoal);
00387         }
00388         aiparam.clear_children("target");
00389 
00390 
00391         foreach (config &ai_protect_unit, aiparam.child_range("protect_unit")) {
00392             transfer_turns_and_time_of_day_data(aiparam,ai_protect_unit);
00393             upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,ai_protect_unit,parsed_cfg,true);
00394         }
00395         aiparam.clear_children("protect_unit");
00396 
00397 
00398         foreach (config &ai_protect_location, aiparam.child_range("protect_location")) {
00399             transfer_turns_and_time_of_day_data(aiparam,ai_protect_location);
00400             upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,ai_protect_location,parsed_cfg,false);
00401         }
00402         aiparam.clear_children("protect_location");
00403 
00404 
00405         if (const config::attribute_value *v = aiparam.get("protect_leader"))
00406         {
00407             config c;
00408             c["value"] = *v;
00409             c["canrecruit"] = true;
00410             c["side_number"] = side;
00411             transfer_turns_and_time_of_day_data(aiparam,c);
00412             if (const config::attribute_value *v = aiparam.get("protect_leader_radius")) {
00413                 c["radius"] = *v;
00414             }
00415 
00416             upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side,c,parsed_cfg,true);
00417         }
00418 
00419         if (!aiparam.has_attribute("turns") && !aiparam.has_attribute("time_of_day")) {
00420             fallback_stage_cfg_ai.append(aiparam);
00421         }
00422     }
00423     fallback_stage_cfg_ai.clear_children("aspect");
00424 
00425     //move [stage]s to root of the config
00426     foreach (const config &aistage, fallback_stage_cfg_ai.child_range("stage")) {
00427         parsed_cfg.add_child("stage",aistage);
00428     }
00429     fallback_stage_cfg_ai.clear_children("stage");
00430 
00431     //move [goal]s to root of the config
00432     foreach (const config &aigoal, fallback_stage_cfg_ai.child_range("goal")) {
00433         parsed_cfg.add_child("goal",aigoal);
00434     }
00435     fallback_stage_cfg_ai.clear_children("goal");
00436 
00437     //move [modify_ai]'s to root of the config
00438     foreach (const config &aimodifyai, fallback_stage_cfg_ai.child_range("modify_ai")) {
00439         parsed_cfg.add_child("modify_ai",aimodifyai);
00440     }
00441     fallback_stage_cfg_ai.clear_children("modify_ai");
00442     //nothing useful should be at fallback_stage_cfg_ai at this point
00443 
00444     cfg = config();
00445     cfg.add_child("ai",parsed_cfg);
00446     DBG_AI_CONFIGURATION << "side "<< side <<": after upgrade to 1.7.3 syntax, config contains:"<< std::endl << cfg << std::endl;
00447     return true;
00448 }
00449 
00450 
00451 void configuration::upgrade_aspect_configs_from_1_07_02_to_1_07_03(side_number side, const config::const_child_itors &ai_parameters, config &parsed_cfg)
00452 {
00453     config cfg;
00454 
00455     foreach (const config &aiparam, ai_parameters) {
00456         cfg.add_child("ai",aiparam);
00457     }
00458 
00459     DBG_AI_CONFIGURATION << "side "<< side <<": upgrading aspects from syntax of 1.7.2 to 1.7.3, old-style config is:" << std::endl << cfg << std::endl;
00460     foreach (const well_known_aspect &wka, well_known_aspects) {
00461         upgrade_aspect_config_from_1_07_02_to_1_07_03(side, cfg,parsed_cfg,wka.name_,wka.was_an_attribute_);
00462     }
00463 }
00464 
00465 
00466 void configuration::upgrade_protect_goal_config_from_1_07_02_to_1_07_03(side_number side, const config &protect_cfg, config &parsed_cfg, bool add_filter)
00467 {
00468     config aigoal;
00469     aigoal["name"] = "protect";
00470     transfer_turns_and_time_of_day_data(protect_cfg,aigoal);
00471 
00472     if (const config::attribute_value *v = protect_cfg.get("value")) {
00473         aigoal["value"] = *v;
00474     } else {
00475         aigoal["value"] = 1; //old default value
00476     }
00477 
00478     //note: 'radius' attribute is renamed to avoid confusion with SLF's radius
00479     if (const config::attribute_value *v = protect_cfg.get("radius")) {
00480         aigoal["protect_radius"] = *v;
00481     } else {
00482         aigoal["protect_radius"] = 20; //old default value
00483     }
00484     DBG_AI_CONFIGURATION << "side "<< side <<": upgrading protect goal from syntax of 1.7.2 to 1.7.3, old-style config is:" << std::endl << protect_cfg << std::endl;
00485 
00486 
00487     if (add_filter) {
00488         config &aigoal_criteria = aigoal.add_child("criteria",config());
00489         config &aigoal_criteria_filter = aigoal_criteria.add_child("filter",protect_cfg);
00490         aigoal_criteria_filter.remove_attribute("value");
00491         aigoal_criteria_filter.remove_attribute("radius");
00492     } else {
00493         config &aigoal_criteria = aigoal.add_child("criteria",protect_cfg);
00494         aigoal_criteria.remove_attribute("value");
00495         aigoal_criteria.remove_attribute("radius");
00496     }
00497 
00498 
00499     parsed_cfg.add_child("goal",aigoal);
00500     DBG_AI_CONFIGURATION << "side "<< side <<": after upgrade of protect goal from syntax of 1.7.2 to 1.7.3, new-style config is:" << std::endl << aigoal << std::endl;
00501 }
00502 
00503 } //end of namespace ai
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:29 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs