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