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