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