The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
recruitment.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2017 by Felix Bauer
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Recruitment Engine by flix
18  * See http://wiki.wesnoth.org/AI_Recruitment
19  */
20 
21 #pragma once
22 
23 #include "ai/composite/aspect.hpp"
24 #include "ai/composite/rca.hpp"
25 #include "units/map.hpp"
26 
27 #include <iomanip>
28 
29 #ifdef _MSC_VER
30 #pragma warning(push)
31 // silence "inherits via dominance" warnings
32 #pragma warning(disable:4250)
33 #endif
34 
35 namespace pathfind {
36 
37 struct full_cost_map;
38 
39 } //of namespace pathfind
40 
41 namespace ai {
42 
43 namespace default_recruitment {
44 
45 // each leader have a score_map
46 // the score map indicates what is the best mix of own units from the leader point of view.
47 // The leader will then recruit according to the map.
48 typedef std::map<std::string, double> score_map;
49 
50 typedef std::map<t_translation::terrain_code, int> terrain_count_map;
51 typedef std::map<std::string, int> count_map;
52 
53 struct data {
55  std::set<std::string> recruits;
56  score_map scores;
57 
58  // We use ratio_score to decide with which ratios the leaders recruit among each other.
59  // For example if leader1 have a ratio_score of 1 and leader2 have a ratio_score of 2
60  // then leader2 will recruit twice as much units than leader1.
61  double ratio_score;
62 
64  bool in_danger;
65 
66  explicit data(const unit_map::const_iterator leader)
67  : leader(leader), ratio_score(1.0), recruit_count(0), in_danger(false) { }
68  double get_score_sum() const {
69  double sum = 0.0;
70  for (const score_map::value_type& entry : scores) {
71  sum += entry.second;
72  }
73  return sum;
74  }
75  score_map get_normalized_scores() const {
76  const double sum = get_score_sum();
77  if (sum == 0.0) {
78  return scores;
79  }
80  score_map normalized;
81  for (const score_map::value_type& entry : scores) {
82  normalized[entry.first] = entry.second / sum;
83  }
84  return normalized;
85  }
86  std::string to_string() const;
87 };
88 
90  double a_defense;
91  double b_defense;
92  double value;
93  cached_combat_value(double a_def, double b_def, double v) :
94  a_defense(a_def), b_defense(b_def), value(v) {
95  }
96  bool operator<(const cached_combat_value& o) const {
97  return value < o.value;
98  }
99 };
100 
101 struct recruit_job : public component {
102  std::vector<std::string> types;
106  recruit_job(std::vector<std::string> t, std::string L, std::string id, int n, int i, bool s, bool p, bool b)
107  : types(t), leader(L), id(id)
108  , number(n), importance(i)
109  , total(s), pattern(p), blocker(b)
110  {}
111  config to_config() const {
112  config cfg;
113  if(number > 0 && number < 99999) {
114  cfg["number"] = number;
115  }
116  cfg["importance"] = importance;
117  cfg["total"] = total;
118  cfg["pattern"] = pattern;
119  cfg["blocker"] = blocker;
120  if(!leader.empty()) {
121  cfg["leader_id"] = leader;
122  }
123  if(!id.empty()) {
124  cfg["id"] = id;
125  }
126  if(!types.empty()) {
127  cfg["type"] = utils::join(types);
128  }
129  return cfg;
130  }
131  std::string get_id() const {return id;}
132  std::string get_name() const {return "recruit_job";}
133  std::string get_engine() const {return "cpp";}
134 };
135 
136 struct recruit_limit : public component {
137  std::vector<std::string> types;
139  int limit;
140  recruit_limit(std::vector<std::string> t, std::string id, int lim)
141  : types(t), id(id), limit(lim)
142  {}
143  config to_config() const {
144  config cfg;
145  cfg["max"] = limit;
146  if(!id.empty()) {
147  cfg["id"] = id;
148  }
149  if(!types.empty()) {
150  cfg["type"] = utils::join(types);
151  }
152  return cfg;
153  }
154  std::string get_id() const {return id;}
155  std::string get_name() const {return "recruit_limit";}
156  std::string get_engine() const {return "cpp";}
157 };
158 
159 class recruitment_aspect : public standard_aspect<config> {
160  std::vector<std::shared_ptr<recruit_job> > jobs_;
161  std::vector<std::shared_ptr<recruit_limit> > limits_;
162 public:
163  recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id);
164  void recalculate() const;
165  void create_job(std::vector<std::shared_ptr<recruit_job> > &jobs, const config &job);
166  void create_limit(std::vector<std::shared_ptr<recruit_limit> > &limits, const config &lim);
167 };
168 
169 typedef std::map<std::string, std::set<cached_combat_value> > table_row;
170 typedef std::map<std::string, table_row> cache_table;
171 
173 public:
174  recruitment(rca_context &context, const config &cfg);
175  virtual ~recruitment() { }
176  virtual double evaluate();
177  virtual void execute();
178  config to_config() const;
179 private:
180 // Helper functions for execute()
181  action_result_ptr execute_recall(const std::string& id, data& leader_data);
182  action_result_ptr execute_recruit(const std::string& type, data& leader_data);
184  const data& leader_data) const;
185  data* get_best_leader_from_ratio_scores(std::vector<data>& leader_data,
186  const config* job) const;
187  const std::string get_best_recruit_from_scores(const data& leader_data,
188  const config* job);
189 
190 // Map Analysis
192  const pathfind::full_cost_map& my_cost_map,
193  const pathfind::full_cost_map& enemy_cost_map);
194  double get_average_defense(const std::string& unit_type) const;
195  const pathfind::full_cost_map get_cost_map_of_side(int side) const;
196  void show_important_hexes() const; //Debug only
199  void update_important_hexes();
200 
201 // Combat Analysis
202  double compare_unit_types(const std::string& a, const std::string& b);
203  void do_combat_analysis(std::vector<data>* leader_data);
204  const double* get_cached_combat_value(const std::string& a, const std::string& b,
205  double a_defense, double b_defense);
206  void simulate_attack(
207  const unit_type* const attacker, const unit_type* const defender,
208  double attacker_defense, double defender_defense,
209  double* damage_to_attacker, double* damage_to_defender) const;
210 
211 // Aspect recruitment_instruction
213  const std::string get_random_pattern_type_if_exists(const data& leader_data,
214  const config* job) const;
216  bool leader_matches_job(const data& leader_data, const config* job) const;
217  bool limit_ok(const std::string& recruit) const;
218  bool recruit_matches_job(const std::string& recruit, const config* job) const;
219  bool recruit_matches_type(const std::string& recruit, const std::string& type) const;
220  bool recruit_matches_types(const std::string& recruit,
221  const std::vector<std::string>& types) const;
222  bool remove_job_if_no_blocker(config* job);
223 
224 // Aspect recruitment_save_gold
225  double get_estimated_income(int turns) const;
226  double get_estimated_unit_gain() const;
227  double get_estimated_village_gain() const;
228  double get_unit_ratio() const;
229  void update_state();
230 
231 // Other
232  void do_randomness(std::vector<data>* leader_data) const;
233  void do_similarity_penalty(std::vector<data>* leader_data) const;
235  void handle_recruitment_more(std::vector<data>* leader_data) const;
236  bool is_enemy_in_radius(const map_location& loc, int radius) const;
237  void update_own_units_count();
238  void update_scouts_wanted();
239 
240 // Observer
242  public:
245 
246  void handle_generic_event(const std::string& event);
247 
248  bool recruit_list_changed();
249  void set_recruit_list_changed(bool changed);
250  int gamestate_changed();
252 
253  private:
256 
257  };
258 
259  std::set<map_location> important_hexes_;
260  terrain_count_map important_terrain_;
262  std::map<map_location, double> average_local_cost_;
263  std::map<size_t, int> cheapest_unit_costs_;
264  cache_table combat_cache_;
271  count_map own_units_count_;
274 };
275 
276 } // of namespace default_recruitment
277 
278 } // of namespace ai
279 
280 #ifdef _MSC_VER
281 #pragma warning(pop)
282 #endif
std::shared_ptr< action_result > action_result_ptr
Definition: game_info.hpp:88
std::string to_string() const
std::vector< std::string > types
const double * get_cached_combat_value(const std::string &a, const std::string &b, double a_defense, double b_defense)
For Combat Analysis.
recruit_limit(std::vector< std::string > t, std::string id, int lim)
std::vector< char_t > string
std::map< size_t, int > cheapest_unit_costs_
cached_combat_value(double a_def, double b_def, double v)
Definition: recruitment.hpp:93
bool recruit_matches_job(const std::string &recruit, const config *job) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type is specified in ...
void update_average_local_cost()
For Map Analysis.
bool remove_job_if_no_blocker(config *job)
For Configuration / Aspect "recruitment-instructions".
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
virtual void execute()
Execute the candidate action.
const std::string get_random_pattern_type_if_exists(const data &leader_data, const config *job) const
For Configuration / Aspect "recruitment-instructions" If the flag pattern is set, this method returns...
bool limit_ok(const std::string &recruit) const
For Configuration / Aspect "recruitment-instructions" Checks if a recruit-type can be recruited accor...
void handle_recruitment_more(std::vector< data > *leader_data) const
For Aspect "recruitment_more".
#define a
std::map< map_location, double > average_local_cost_
void update_important_hexes()
For Map Analysis.
std::vector< std::shared_ptr< recruit_job > > jobs_
data * get_best_leader_from_ratio_scores(std::vector< data > &leader_data, const config *job) const
A helper function for execute().
void do_randomness(std::vector< data > *leader_data) const
Will add a random value between 0 and "recruitment_randomness" to all recruits.
void update_scouts_wanted()
This function will use the aspect villages_per_scout to decide how many scouts we want to recruit...
int get_cheapest_unit_cost_for_leader(const unit_map::const_iterator &leader)
Called at the beginning and whenever the recruitment list changes.
std::map< std::string, int > count_map
Definition: recruitment.hpp:51
const std::string get_best_recruit_from_scores(const data &leader_data, const config *job)
A helper function for execute().
double get_estimated_unit_gain() const
For Aspect "recruitment_save_gold".
recruit_situation_change_observer recruit_situation_change_observer_
A single unit type that the player may recruit.
Definition: types.hpp:43
std::set< map_location > important_hexes_
double compare_unit_types(const std::string &a, const std::string &b)
For Combat Analysis.
#define b
double get_estimated_village_gain() const
For Aspect "recruitment_save_gold".
bool recruit_matches_type(const std::string &recruit, const std::string &type) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type matches one atom...
double get_unit_ratio() const
For Aspect "recruitment_save_gold".
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
double get_average_defense(const std::string &unit_type) const
For Map Analysis.
void create_limit(std::vector< std::shared_ptr< recruit_limit > > &limits, const config &lim)
void update_average_lawful_bonus()
Calculates a average lawful bonus, so Combat Analysis will work better in caves and custom time of da...
void integrate_recruitment_pattern_in_recruitment_instructions()
For Configuration / Aspect "recruitment_pattern" Converts the (old) recruitment_pattern into a recrui...
void create_job(std::vector< std::shared_ptr< recruit_job > > &jobs, const config &job)
config * get_most_important_job()
For Configuration / Aspect "recruitment-instructions" We call a [recruit] tag a "job".
bool operator<(const cached_combat_value &o) const
Definition: recruitment.hpp:96
bool is_enemy_in_radius(const map_location &loc, int radius) const
Helper function.
std::vector< std::string > types
void do_combat_analysis(std::vector< data > *leader_data)
Combat Analysis.
bool recruit_matches_types(const std::string &recruit, const std::vector< std::string > &types) const
For Configuration / Aspect "recruitment-instructions" Checks if a given recruit-type matches one of t...
config to_config() const
serialize
action_result_ptr execute_recall(const std::string &id, data &leader_data)
A helper function for execute().
Encapsulates the map of the game.
Definition: location.hpp:40
data(const unit_map::const_iterator leader)
Definition: recruitment.hpp:66
mock_party p
void compare_cost_maps_and_update_important_hexes(const pathfind::full_cost_map &my_cost_map, const pathfind::full_cost_map &enemy_cost_map)
For Map Analysis Computes from our cost map and the combined cost map of all enemies the important he...
static map_location::DIRECTION s
Structure which uses find_routes() to build a cost map This maps each hex to a the movements a unit w...
Definition: pathfind.hpp:266
size_t i
Definition: function.cpp:933
action_result_ptr execute_recruit(const std::string &type, data &leader_data)
A helper function for execute().
std::map< std::string, std::set< cached_combat_value > > table_row
std::vector< std::shared_ptr< recruit_limit > > limits_
std::map< t_translation::terrain_code, int > terrain_count_map
Definition: recruitment.hpp:50
double get_estimated_income(int turns) const
For Aspect "recruitment_save_gold".
int turns()
Definition: game.cpp:560
double t
Definition: astarsearch.cpp:64
recruit_job(std::vector< std::string > t, std::string L, std::string id, int n, int i, bool s, bool p, bool b)
recruitment(rca_context &context, const config &cfg)
const std::string * get_appropriate_recall(const std::string &type, const data &leader_data) const
A helper function for execute().
void simulate_attack(const unit_type *const attacker, const unit_type *const defender, double attacker_defense, double defender_defense, double *damage_to_attacker, double *damage_to_defender) const
For Combat Analysis.
recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id)
score_map get_normalized_scores() const
Definition: recruitment.hpp:75
unit_map::const_iterator leader
Definition: recruitment.hpp:54
std::map< std::string, table_row > cache_table
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
void update_state()
For Aspect "recruitment_save_gold".
const pathfind::full_cost_map get_cost_map_of_side(int side) const
For Map Analysis.
static map_location::DIRECTION n
void show_important_hexes() const
For Map Analysis.
std::map< std::string, double > score_map
Definition: recruitment.hpp:48
void do_similarity_penalty(std::vector< data > *leader_data) const
Will give a penalty to similar units.
std::set< std::string > recruits
Definition: recruitment.hpp:55
candidate action framework
bool leader_matches_job(const data &leader_data, const config *job) const
For Configuration / Aspect "recruitment-instructions" Checks if a given leader is specified in the "l...