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; } // lines 45-45
35 namespace ai { class ai_context; } // lines 42-42
36 namespace ai { class component; } // lines 43-43
37 namespace ai { class default_ai_context; } // lines 41-41
38 namespace ai { class readonly_context; } // lines 39-39
39 namespace ai { class readwrite_context; } // lines 40-40
40 namespace ai { class side_context; } // lines 38-38
41 namespace events { class generic_event; }
42 namespace events { class observer; }
43 
44 
45 namespace ai
46 {
47 
48 /**
49  * Base class that holds the AI and current AI parameters.
50  * It is an implementation detail.
51  * @todo 1.9 move it out of public view
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
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  * Adds active AI for specified @a side from parameters.
336  * @note Running this command may invalidate references previously returned
337  * by manager. AI is not initialized at this point.
338  * @param side side number (1-based, as in game_info).
339  * @param ai_algorithm_type type of AI algorithm to create.
340  * @param replace should new ai replace the current ai or 'be placed on top of it'.
341  * @return true if successful.
342  */
343  bool add_ai_for_side( side_number side, const std::string& ai_algorithm_type, bool replace = true);
344 
345 
346  // =======================================================================
347  // REMOVE
348  // =======================================================================
349 
350  /**
351  * Removes top-level AI from @a side.
352  * @note Running this command may invalidate references previously returned
353  * by manager.
354  * @param side side number (1-based, as in game_info).
355  */
356  void remove_ai_for_side( side_number side );
357 
358 
359  /**
360  * Removes all AIs from @a side.
361  * @note Running this command may invalidate references previously returned
362  * by manager.
363  * @param side side number (1-based, as in game_info).
364  */
365  void remove_all_ais_for_side( side_number side );
366 
367 
368  /**
369  * Clears all the AIs.
370  * @note Running this command may invalidate references previously returned
371  * by manager. For example, this is called from the destructor of
372  * playsingle_controller. It is necessary to do this if any of the
373  * info structures used by the AI goes out of scope.
374  */
375  void clear_ais();
376 
377  // =======================================================================
378  // GET active AI parameters
379  // =======================================================================
380 
381 
382  /**
383  * Gets AI info for active AI of the given @a side.
384  * @param side side number (1-based).
385  * @return a reference to active AI info.
386  */
387  game_info& get_active_ai_info_for_side( side_number side );
388 
389 
390  /**
391  * Gets AI Overview for active AI of the given @a side
392  * @param side side number (1-based)
393  * @return an ai overview
394  */
395  std::string get_active_ai_overview_for_side( side_number side );
396 
397 
398  /**
399  * Gets AI Structure for active AI of the given @a side
400  * @param side side number (1-based)
401  * @return an ai structure
402  */
403  std::string get_active_ai_structure_for_side( side_number side );
404 
405  /**
406  * Gets AI algorithm identifier for active AI of the given @a side.
407  * @param side side number (1-based).
408  * @return ai identifier for the active AI
409  */
410  std::string get_active_ai_identifier_for_side( side_number side );
411 
412  /**
413  * Gets the active AI holder for debug purposes.
414  * Will only work in debug mode, otherwise returns a reference to an empty holder
415  * @param side side number(1-based)
416  * @return debug ? active holder : empty holder
417  */
418  ai::holder& get_active_ai_holder_for_side_dbg(side_number side);
419 
420  /**
421  * Gets AI config for active AI of the given @a side.
422  * @param side side number (1-based).
423  * @return a config object for the active AI
424  */
425  config to_config( side_number side );
426 
427 
428  /**
429  * Gets global AI-game info
430  * @return a reference to the AI-game info.
431  */
432  game_info& get_ai_info();
433 
434 
435  // =======================================================================
436  // SET active AI parameters
437  // =======================================================================
438 
439  /**
440  * Modifies AI parameters for active AI of the given @a side.
441  * This function is a backend for [modify_ai] tag
442  * @param side side_number (1-based, as in game_info).
443  * @param cfg - content of [modify_ai] tag
444  */
445 
446  void modify_active_ai_for_side( ai::side_number side, const config &cfg );
447 
448  /**
449  * Appends AI parameters to active AI of the given @a side.
450  * This function is a backend for [modify_side][ai] tag
451  * @param side side_number (1-based, as in game_info).
452  * @param cfg - content of [modify_side][ai] tag
453  */
454 
455  void append_active_ai_for_side( ai::side_number side, const config &cfg );
456 
457  // =======================================================================
458  // PROXY
459  // =======================================================================
460 
461  /**
462  * Plays a turn for the specified side using its active AI.
463  * @param side side number (1-based, as in game_info).
464  */
465  void play_turn(side_number side);
466 
467 
468 private:
469 
470  typedef std::map< side_number, std::stack< holder >> AI_map_of_stacks;
471 
472  std::deque< command_history_item > history_;
475 
485 
486  AI_map_of_stacks ai_map_;
487 
489 
490 
491  // =======================================================================
492  // EVALUATION
493  // =======================================================================
494 
495  /**
496  * Evaluates an internal manager command.
497  * @param side side number (1-based).
498  * @param str string to evaluate.
499  * @return string result of evaluation.
500  * @todo 1.9 rewrite this function to use a fai or lua parser.
501  */
502  const std::string internal_evaluate_command( side_number side, const std::string& str );
503 
504  /**
505  * Determines if the command should be intercepted and evaluated as internal command.
506  * @param str command string to check.
507  * @return true if the command should be intercepted and evaluated.
508  */
509  bool should_intercept( const std::string& str ) const;
510 
511  // =======================================================================
512  // AI STACKS
513  // =======================================================================
514 
515 
516  /**
517  * Gets the AI stack for the specified side, create it if it doesn't exist.
518  */
519  std::stack< holder >& get_or_create_ai_stack_for_side(side_number side);
520 
521  // =======================================================================
522  // AI HOLDERS
523  // =======================================================================
524 
525 
526  /**
527  * Gets active holder for specified @a side.
528  */
529  holder& get_active_ai_holder_for_side( side_number side );
530 
531  // =======================================================================
532  // AI POINTERS
533  // =======================================================================
534 
535  /**
536  * Gets active AI for specified side.
537  * @note Running this command may invalidate references previously returned
538  * by manager.
539  * @param side side number (1-based, as in game_info).
540  * @return a reference to the active AI.
541  * @note This reference may become invalid after specific manager operations.
542  */
543  ai_composite& get_active_ai_for_side( side_number side );
544 
545 
546  friend class ::game_launcher;
547 };
548 
549 } //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:481
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:58
struct utils::detail::formula_initer init
std::deque< command_history_item > history_
Definition: manager.hpp:472
events::generic_event user_interact_
Definition: manager.hpp:478
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:479
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:476
events::generic_event turn_started_
Definition: manager.hpp:482
long history_item_counter_
Definition: manager.hpp:473
events::generic_event tod_changed_
Definition: manager.hpp:480
std::map< side_number, std::stack< holder > > AI_map_of_stacks
Definition: manager.hpp:470
Handling of system events.
Definition: manager.hpp:41
game_info ai_info_
Definition: manager.hpp:474
static manager * singleton_
Definition: manager.hpp:488
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:484
AI_map_of_stacks ai_map_
Definition: manager.hpp:486
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:92
AI Command History Item.
Definition: manager.hpp:97
int last_interact_
Definition: manager.hpp:483
events::generic_event recruit_list_changed_
Definition: manager.hpp:477
Base class that holds the AI and current AI parameters.
Definition: manager.hpp:53