The Battle for Wesnoth  1.15.0-dev
manager.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Yurii Chernyi <terraninfo@terraninfo.net>
3  Part of the Battle for Wesnoth Project https://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  * Managing the AIs lifecycle - headers
18  * @todo 1.9 Refactor history handling and internal commands.
19  * @todo 1.9 AI Interface command to clear the history.
20  */
21 
22 #pragma once
23 
24 #include "ai/game_info.hpp" // for side_number, ai_ptr
25 #include "config.hpp" // for config, etc
26 #include "generic_event.hpp" // for generic_event, etc
27 
28 #include <deque> // for deque
29 #include <map> // for map, map<>::value_compare
30 #include <stack> // for stack
31 #include <string> // for string
32 
33 class game_launcher;
34 namespace ai { class ai_composite; }
35 namespace ai { class ai_context; }
36 namespace ai { class component; }
37 namespace ai { class default_ai_context; }
38 namespace ai { class readonly_context; }
39 namespace ai { class readwrite_context; }
40 namespace ai { class side_context; }
41 namespace events { class generic_event; }
42 namespace events { class observer; }
43 
44 namespace ai
45 {
46 /**
47  * Base class that holds the AI and current AI parameters.
48  * It is an implementation detail.
49  * @todo 1.9 move it out of public view
50  */
51 class holder
52 {
53 public:
54  holder(side_number side, const config& cfg);
55 
56  virtual ~holder();
57 
58  ai_composite& get_ai_ref();
59 
60  const std::string describe_ai();
61 
62  config to_config() const;
63 
64  void modify_ai(const config& cfg);
65 
66  void append_ai(const config& cfg);
67 
68  const std::string get_ai_overview();
69 
70  const std::string get_ai_structure();
71 
72  const std::string get_ai_identifier() const;
73 
74  component* get_component(component* root, const std::string& path); // Ai debug method
75 
76 private:
77  void init(side_number side);
78 
80  std::unique_ptr<side_context> side_context_;
81  std::unique_ptr<readonly_context> readonly_context_;
82  std::unique_ptr<readwrite_context> readwrite_context_;
83  std::unique_ptr<default_ai_context> default_ai_context_;
86 };
87 
88 /**
89  * AI Command History Item. It is an implementation detail
90  */
92 {
93 public:
94  command_history_item(int number, const std::string& command)
95  : number_(number)
96  , command_(command)
97  {
98  }
99 
100  int get_number() const
101  {
102  return number_;
103  }
104 
105  const std::string& get_command() const
106  {
107  return command_;
108  }
109 
110 private:
111  int number_;
112  std::string command_;
113 };
114 
115 /**
116  * Class that manages AIs for all sides and manages AI redeployment.
117  * This class is responsible for managing the AI lifecycle.
118  */
119 class manager
120 {
121 public:
122  // =======================================================================
123  // CONSTANTS
124  // =======================================================================
125 
126  static const std::size_t MAX_HISTORY_SIZE = 200;
127 
128  static const std::string AI_TYPE_COMPOSITE_AI;
129  static const std::string AI_TYPE_SAMPLE_AI;
130  static const std::string AI_TYPE_IDLE_AI;
131  static const std::string AI_TYPE_FORMULA_AI;
132  static const std::string AI_TYPE_DFOOL_AI;
133  static const std::string AI_TYPE_AI2;
134  static const std::string AI_TYPE_DEFAULT;
135 
136  // =======================================================================
137  // CONSTRUCTORS AND DESTRUCTORS
138  // =======================================================================
139 
140  manager();
141 
142  /**
143  * The singleton can't be set to null in the destructor because member objects
144  * (which access the singleton) are destroyed *after* the destructor has been run.
145  */
146  ~manager() = default;
147 
148  // =======================================================================
149  // ACCESS TO MANAGER
150  // =======================================================================
151 
153  {
154  assert(singleton_ != nullptr);
155  return *singleton_;
156  }
157 
158  static bool has_manager()
159  {
160  return singleton_ != nullptr;
161  }
162 
163  // =======================================================================
164  // LIFECYCLE
165  // =======================================================================
166 
167  /**
168  * Adds observer of game events.
169  * Should be called in playsingle_controller 's constructor.
170  */
171  void add_observer(events::observer* event_observer);
172 
173  /**
174  * Removes an observer of game events.
175  * Should be called in playsingle_controller 's destructor.
176  */
177  void remove_observer(events::observer* event_observer);
178 
179  /**
180  * Adds observer of game events except ai_user_interact event and ai_sync_network event
181  */
182  void add_gamestate_observer(events::observer* event_observer);
183 
184  /**
185  * Removes an observer of game events except ai_user_interact event and ai_sync_network event
186  */
187  void remove_gamestate_observer(events::observer* event_observer);
188 
189  /**
190  * Notifies all observers of 'ai_user_interact' event.
191  * Function which should be called frequently to allow the user to interact
192  * with the interface. This function will make sure that interaction
193  * doesn't occur too often, so there is no problem with calling it very
194  * regularly.
195  */
196  void raise_user_interact();
197 
198  /**
199  * Notifies all observers of 'ai_sync_network' event.
200  * Basically a request from the AI to sync the network.
201  */
202  void raise_sync_network();
203 
204  /**
205  * Notifies all observers of 'ai_gamestate_changed' event.
206  */
207  void raise_gamestate_changed();
208 
209  /**
210  * Notifies all observers of 'ai_tod_changed' event.
211  */
212  void raise_tod_changed();
213 
214  /**
215  * Notifies all observers of 'ai_recruit_list_changed' event.
216  */
217  void raise_recruit_list_changed();
218 
219  /**
220  * Notifies all observers of 'ai_turn_started' event.
221  */
222  void raise_turn_started();
223 
224  /**
225  * Notifies all observers of 'ai_map_changed' event.
226  */
227  void raise_map_changed();
228 
229  /**
230  * Adds an observer of 'ai_map_changed' event.
231  */
232  void add_map_changed_observer(events::observer* event_observer);
233 
234  /**
235  * Adds an observer of 'ai_recruit_list_changed' event.
236  */
237  void add_recruit_list_changed_observer(events::observer* event_observer);
238 
239  /**
240  * Adds an observer of 'ai_turn_started' event.
241  */
242  void add_turn_started_observer(events::observer* event_observer);
243 
244  /**
245  * Adds an observer of 'ai_tod_changed' event.
246  */
247  void add_tod_changed_observer(events::observer* event_observer);
248 
249  /**
250  * Deletes an observer of 'ai_map_changed' event.
251  */
252  void remove_map_changed_observer(events::observer* event_observer);
253 
254  /**
255  * Deletes an observer of 'ai_recruit_list_changed' event.
256  */
257  void remove_recruit_list_changed_observer(events::observer* event_observer);
258 
259  /**
260  * Deletes an observer of 'ai_turn_started' event.
261  */
262  void remove_turn_started_observer(events::observer* event_observer);
263 
264  /**
265  * Deletes an observer of 'ai_tod_changed' event.
266  */
267  void remove_tod_changed_observer(events::observer* event_observer);
268 
269 public:
270  // =======================================================================
271  // EVALUATION
272  // =======================================================================
273 
274  /**
275  * Evaluates a string command using command AI.
276  * @note Running this command may invalidate references previously returned
277  * by manager. Will intercept those commands which start with '!'
278  * and '?', and will try to evaluate them as internal commands.
279  * @param side side number (1-based).
280  * @param str string to evaluate.
281  * @return string result of evaluation.
282  */
283  const std::string evaluate_command(side_number side, const std::string& str);
284 
285  // =======================================================================
286  // ADD, CREATE AIs, OR LIST AI TYPES
287  // =======================================================================
288 
289  /**
290  * Adds active AI for specified @a side from @a file.
291  * @note Running this command may invalidate references previously returned
292  * by manager. AI is not initialized at this point.
293  * @param side side number (1-based, as in game_info).
294  * @param file file name, follows the usual WML convention.
295  * @param replace should new ai replace the current ai or 'be placed on top of it'.
296  * @return true if successful.
297  */
298  bool add_ai_for_side_from_file(side_number side, const std::string& file, bool replace = true);
299 
300  /**
301  * Adds active AI for specified @a side from @a cfg.
302  * @note Running this command may invalidate references previously returned
303  * by manager. AI is not initialized at this point.
304  * @param side side number (1-based, as in game_info).
305  * @param cfg the config from which all ai parameters are to be read.
306  * @param replace should new ai replace the current ai or 'be placed on top of it'.
307  * @return true if successful.
308  */
309  bool add_ai_for_side_from_config(side_number side, const config& cfg, bool replace = true);
310 
311  /**
312  * Adds active AI for specified @a side from parameters.
313  * @note Running this command may invalidate references previously returned
314  * by manager. AI is not initialized at this point.
315  * @param side side number (1-based, as in game_info).
316  * @param ai_algorithm_type type of AI algorithm to create.
317  * @param replace should new ai replace the current ai or 'be placed on top of it'.
318  * @return true if successful.
319  */
320  bool add_ai_for_side(side_number side, const std::string& ai_algorithm_type, bool replace = true);
321 
322  // =======================================================================
323  // REMOVE
324  // =======================================================================
325 
326  /**
327  * Removes top-level AI from @a side.
328  * @note Running this command may invalidate references previously returned
329  * by manager.
330  * @param side side number (1-based, as in game_info).
331  */
332  void remove_ai_for_side(side_number side);
333 
334  /**
335  * Removes all AIs from @a side.
336  * @note Running this command may invalidate references previously returned
337  * by manager.
338  * @param side side number (1-based, as in game_info).
339  */
340  void remove_all_ais_for_side(side_number side);
341 
342  /**
343  * Clears all the AIs.
344  * @note Running this command may invalidate references previously returned
345  * by manager. For example, this is called from the destructor of
346  * playsingle_controller. It is necessary to do this if any of the
347  * info structures used by the AI goes out of scope.
348  */
349  void clear_ais();
350 
351  // =======================================================================
352  // GET active AI parameters
353  // =======================================================================
354 
355  /**
356  * Gets AI info for active AI of the given @a side.
357  * @param side side number (1-based).
358  * @return a reference to active AI info.
359  */
360  game_info& get_active_ai_info_for_side(side_number side);
361 
362  /**
363  * Gets AI Overview for active AI of the given @a side
364  * @param side side number (1-based)
365  * @return an ai overview
366  */
367  std::string get_active_ai_overview_for_side(side_number side);
368 
369  /**
370  * Gets AI Structure for active AI of the given @a side
371  * @param side side number (1-based)
372  * @return an ai structure
373  */
374  std::string get_active_ai_structure_for_side(side_number side);
375 
376  /**
377  * Gets AI algorithm identifier for active AI of the given @a side.
378  * @param side side number (1-based).
379  * @return ai identifier for the active AI
380  */
381  std::string get_active_ai_identifier_for_side(side_number side);
382 
383  /**
384  * Gets the active AI holder for debug purposes.
385  * Will only work in debug mode, otherwise returns a reference to an empty holder
386  * @param side side number(1-based)
387  * @return debug ? active holder : empty holder
388  */
389  ai::holder& get_active_ai_holder_for_side_dbg(side_number side);
390 
391  /**
392  * Gets AI config for active AI of the given @a side.
393  * @param side side number (1-based).
394  * @return a config object for the active AI
395  */
396  config to_config(side_number side);
397 
398  /**
399  * Gets global AI-game info
400  * @return a reference to the AI-game info.
401  */
402  game_info& get_ai_info();
403 
404  // =======================================================================
405  // SET active AI parameters
406  // =======================================================================
407 
408  /**
409  * Modifies AI parameters for active AI of the given @a side.
410  * This function is a backend for [modify_ai] tag
411  * @param side side_number (1-based, as in game_info).
412  * @param cfg - content of [modify_ai] tag
413  */
414 
415  void modify_active_ai_for_side(ai::side_number side, const config& cfg);
416 
417  /**
418  * Appends AI parameters to active AI of the given @a side.
419  * This function is a backend for [modify_side][ai] tag
420  * @param side side_number (1-based, as in game_info).
421  * @param cfg - content of [modify_side][ai] tag
422  */
423 
424  void append_active_ai_for_side(ai::side_number side, const config& cfg);
425 
426  // =======================================================================
427  // PROXY
428  // =======================================================================
429 
430  /**
431  * Plays a turn for the specified side using its active AI.
432  * @param side side number (1-based, as in game_info).
433  */
434  void play_turn(side_number side);
435 
436 private:
437  typedef std::map<side_number, std::stack<holder>> AI_map_of_stacks;
438 
439  std::deque<command_history_item> history_;
442 
452 
453  AI_map_of_stacks ai_map_;
454 
456 
457  // =======================================================================
458  // EVALUATION
459  // =======================================================================
460 
461  /**
462  * Evaluates an internal manager command.
463  * @param side side number (1-based).
464  * @param str string to evaluate.
465  * @return string result of evaluation.
466  * @todo 1.9 rewrite this function to use a fai or lua parser.
467  */
468  const std::string internal_evaluate_command(side_number side, const std::string& str);
469 
470  /**
471  * Determines if the command should be intercepted and evaluated as internal command.
472  * @param str command string to check.
473  * @return true if the command should be intercepted and evaluated.
474  */
475  bool should_intercept(const std::string& str) const;
476 
477  // =======================================================================
478  // AI STACKS
479  // =======================================================================
480 
481  /**
482  * Gets the AI stack for the specified side, create it if it doesn't exist.
483  */
484  std::stack<holder>& get_or_create_ai_stack_for_side(side_number side);
485 
486  // =======================================================================
487  // AI HOLDERS
488  // =======================================================================
489 
490  /**
491  * Gets active holder for specified @a side.
492  */
493  holder& get_active_ai_holder_for_side(side_number side);
494 
495  // =======================================================================
496  // AI POINTERS
497  // =======================================================================
498 
499  /**
500  * Gets active AI for specified side.
501  * @note Running this command may invalidate references previously returned
502  * by manager.
503  * @param side side number (1-based, as in game_info).
504  * @return a reference to the active AI.
505  * @note This reference may become invalid after specific manager operations.
506  */
507  ai_composite& get_active_ai_for_side(side_number side);
508 
509  friend class ::game_launcher;
510 };
511 
512 } // end of namespace ai
static const std::string AI_TYPE_DFOOL_AI
Definition: manager.hpp:132
std::unique_ptr< ai_composite > composite_ai_ptr
Definition: game_info.hpp:47
const std::string & get_command() const
Definition: manager.hpp:105
static manager & get_singleton()
Definition: manager.hpp:152
static help_manager manager
The help manager.
Definition: help.cpp:34
static bool has_manager()
Definition: manager.hpp:158
config cfg_
Definition: manager.hpp:85
events::generic_event gamestate_changed_
Definition: manager.hpp:448
Class that manages AIs for all sides and manages AI redeployment.
Definition: manager.hpp:119
std::unique_ptr< readonly_context > readonly_context_
Definition: manager.hpp:81
Definitions for the interface to Wesnoth Markup Language (WML).
command_history_item(int number, const std::string &command)
Definition: manager.hpp:94
composite_ai_ptr ai_
Definition: manager.hpp:79
std::unique_ptr< side_context > side_context_
Definition: manager.hpp:80
int get_number() const
Definition: manager.hpp:100
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
struct utils::detail::formula_initer init
events::generic_event user_interact_
Definition: manager.hpp:445
static const std::string AI_TYPE_AI2
Definition: manager.hpp:133
std::unique_ptr< default_ai_context > default_ai_context_
Definition: manager.hpp:83
std::deque< command_history_item > history_
Definition: manager.hpp:439
static const std::string AI_TYPE_DEFAULT
Definition: manager.hpp:134
static const std::string AI_TYPE_IDLE_AI
Definition: manager.hpp:130
events::generic_event sync_network_
Definition: manager.hpp:446
static const std::string AI_TYPE_COMPOSITE_AI
Definition: manager.hpp:128
Game information for the AI.
events::generic_event map_changed_
Definition: manager.hpp:443
events::generic_event turn_started_
Definition: manager.hpp:449
long history_item_counter_
Definition: manager.hpp:440
events::generic_event tod_changed_
Definition: manager.hpp:447
Handling of system events.
Definition: manager.hpp:41
game_info ai_info_
Definition: manager.hpp:441
static manager * singleton_
Definition: manager.hpp:455
static const std::string AI_TYPE_FORMULA_AI
Definition: manager.hpp:131
static const std::string AI_TYPE_SAMPLE_AI
Definition: manager.hpp:129
side_number side_
Definition: manager.hpp:84
std::unique_ptr< readwrite_context > readwrite_context_
Definition: manager.hpp:82
int num_interact_
Definition: manager.hpp:451
AI_map_of_stacks ai_map_
Definition: manager.hpp:453
int side_number
Definition: game_info.hpp:39
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
AI Command History Item.
Definition: manager.hpp:91
int last_interact_
Definition: manager.hpp:450
std::string path
File path.
events::generic_event recruit_list_changed_
Definition: manager.hpp:444
Base class that holds the AI and current AI parameters.
Definition: manager.hpp:51
std::map< side_number, std::stack< holder > > AI_map_of_stacks
Definition: manager.hpp:437