The Battle for Wesnoth  1.17.17+dev
manager.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2023
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 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
387 
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 
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  */
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  */
495 
496  friend class ::game_launcher;
497 };
498 
499 } //end of namespace ai
AI Command History Item.
Definition: manager.hpp:93
int get_number() const
Definition: manager.hpp:100
const std::string & get_command() const
Definition: manager.hpp:102
command_history_item(int number, const std::string &command)
Definition: manager.hpp:96
Base class that holds the AI and current AI parameters.
Definition: manager.hpp:53
config to_config() const
Definition: manager.cpp:223
composite_ai_ptr ai_
Definition: manager.hpp:81
void micro_ai(const config &cfg)
Definition: manager.cpp:149
void modify_ai(const config &cfg)
Definition: manager.cpp:162
config cfg_
Definition: manager.hpp:87
ai_composite & get_ai_ref()
Definition: manager.cpp:139
virtual ~holder()
Definition: manager.cpp:130
component * get_component(component *root, const std::string &path)
Definition: manager.cpp:314
const std::string get_ai_overview()
Definition: manager.cpp:257
std::unique_ptr< side_context > side_context_
Definition: manager.hpp:82
const std::string get_ai_identifier() const
Definition: manager.cpp:309
side_number side_
Definition: manager.hpp:86
std::unique_ptr< readwrite_context > readwrite_context_
Definition: manager.hpp:84
const std::string get_ai_structure()
Definition: manager.cpp:301
std::unique_ptr< readonly_context > readonly_context_
Definition: manager.hpp:83
const std::string describe_ai()
Definition: manager.cpp:246
void init(side_number side)
Definition: manager.cpp:82
void append_ai(const config &cfg)
Definition: manager.cpp:191
std::unique_ptr< default_ai_context > default_ai_context_
Definition: manager.hpp:85
holder(side_number side, const config &cfg)
Definition: manager.cpp:76
Class that manages AIs for all sides and manages AI redeployment.
Definition: manager.hpp:114
static const std::string AI_TYPE_SAMPLE_AI
Definition: manager.hpp:124
events::generic_event map_changed_
Definition: manager.hpp:430
std::string get_active_ai_identifier_for_side(side_number side)
Gets AI algorithm identifier for active AI of the given side.
Definition: manager.cpp:687
void clear_ais()
Clears all the AIs.
Definition: manager.cpp:662
std::string get_active_ai_overview_for_side(side_number side)
Gets AI Overview for active AI of the given side.
Definition: manager.cpp:677
ai_composite & get_active_ai_for_side(side_number side)
Gets active AI for specified side.
Definition: manager.cpp:779
void raise_tod_changed()
Notifies all observers of 'ai_tod_changed' event.
Definition: manager.cpp:447
bool add_ai_for_side_from_config(side_number side, const config &cfg, bool replace=true)
Adds active AI for specified side from cfg.
Definition: manager.cpp:627
config to_config(side_number side)
Gets AI config for active AI of the given side.
Definition: manager.cpp:702
events::generic_event user_interact_
Definition: manager.hpp:432
void remove_all_ais_for_side(side_number side)
Removes all AIs from side.
Definition: manager.cpp:652
void remove_gamestate_observer(events::observer *event_observer)
Removes an observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:377
void remove_observer(events::observer *event_observer)
Removes an observer of game events.
Definition: manager.cpp:364
void raise_turn_started()
Notifies all observers of 'ai_turn_started' event.
Definition: manager.cpp:451
static manager * singleton_
Definition: manager.hpp:442
static const std::string AI_TYPE_IDLE_AI
Definition: manager.hpp:125
static const std::string AI_TYPE_COMPOSITE_AI
Definition: manager.hpp:123
static const std::size_t MAX_HISTORY_SIZE
Definition: manager.hpp:121
static const std::string AI_TYPE_DFOOL_AI
Definition: manager.hpp:127
void raise_gamestate_changed()
Notifies all observers of 'ai_gamestate_changed' event.
Definition: manager.cpp:443
void add_gamestate_observer(events::observer *event_observer)
Adds observer of game events except ai_user_interact event and ai_sync_network event.
Definition: manager.cpp:371
void append_active_ai_for_side(ai::side_number side, const config &cfg)
Appends AI parameters to active AI of the given side.
Definition: manager.cpp:672
AI_map_of_stacks ai_map_
Definition: manager.hpp:440
std::map< side_number, std::stack< holder > > AI_map_of_stacks
Definition: manager.hpp:424
std::string get_active_ai_structure_for_side(side_number side)
Gets AI Structure for active AI of the given side.
Definition: manager.cpp:682
events::generic_event sync_network_
Definition: manager.hpp:433
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
Definition: manager.cpp:421
static const std::string AI_TYPE_FORMULA_AI
Definition: manager.hpp:126
events::generic_event recruit_list_changed_
Definition: manager.hpp:431
const std::string evaluate_command(side_number side, const std::string &str)
Evaluates a string command using command AI.
Definition: manager.cpp:467
std::stack< holder > & get_or_create_ai_stack_for_side(side_number side)
Gets the AI stack for the specified side, create it if it doesn't exist.
Definition: manager.cpp:750
holder & get_active_ai_holder_for_side(side_number side)
Gets active holder for specified side.
Definition: manager.cpp:762
void add_recruit_list_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:396
game_info & get_active_ai_info_for_side(side_number side)
Gets AI info for active AI of the given side.
Definition: manager.cpp:707
void add_map_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_map_changed' event.
Definition: manager.cpp:391
static manager & get_singleton()
Definition: manager.hpp:145
static const std::string AI_TYPE_AI2
Definition: manager.hpp:128
void add_turn_started_observer(events::observer *event_observer)
Adds an observer of 'ai_turn_started' event.
Definition: manager.cpp:401
static const std::string AI_TYPE_DEFAULT
Definition: manager.hpp:129
std::deque< command_history_item > history_
Definition: manager.hpp:426
static bool has_manager()
Definition: manager.hpp:151
~manager()=default
game_info & get_ai_info()
Gets global AI-game info.
Definition: manager.cpp:712
game_info ai_info_
Definition: manager.hpp:428
events::generic_event gamestate_changed_
Definition: manager.hpp:435
const ai::unit_advancements_aspect & get_advancement_aspect_for_side(side_number side)
Definition: manager.cpp:717
bool add_ai_for_side_from_file(side_number side, const std::string &file, bool replace=true)
Adds active AI for specified side from file.
Definition: manager.cpp:617
events::generic_event turn_started_
Definition: manager.hpp:436
void remove_ai_for_side(side_number side)
Removes top-level AI from side.
Definition: manager.cpp:644
void modify_active_ai_for_side(ai::side_number side, const config &cfg)
Modifies AI parameters for active AI of the given side.
Definition: manager.cpp:667
int last_interact_
Definition: manager.hpp:437
int num_interact_
Definition: manager.hpp:438
void play_turn(side_number side)
Plays a turn for the specified side using its active AI.
Definition: manager.cpp:726
const std::string internal_evaluate_command(side_number side, const std::string &str)
Evaluates an internal manager command.
Definition: manager.cpp:506
long history_item_counter_
Definition: manager.hpp:427
void raise_map_changed()
Notifies all observers of 'ai_map_changed' event.
Definition: manager.cpp:459
bool should_intercept(const std::string &str) const
Determines if the command should be intercepted and evaluated as internal command.
Definition: manager.cpp:487
void raise_recruit_list_changed()
Notifies all observers of 'ai_recruit_list_changed' event.
Definition: manager.cpp:455
void remove_turn_started_observer(events::observer *event_observer)
Deletes an observer of 'ai_turn_started' event.
Definition: manager.cpp:416
ai::holder & get_active_ai_holder_for_side_dbg(side_number side)
Gets the active AI holder for debug purposes.
Definition: manager.cpp:692
void raise_sync_network()
Notifies all observers of 'ai_sync_network' event.
Definition: manager.cpp:439
events::generic_event tod_changed_
Definition: manager.hpp:434
void remove_map_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_map_changed' event.
Definition: manager.cpp:411
void add_tod_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_tod_changed' event.
Definition: manager.cpp:383
void remove_tod_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_tod_changed' event.
Definition: manager.cpp:387
void add_observer(events::observer *event_observer)
Adds observer of game events.
Definition: manager.cpp:357
void remove_recruit_list_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:406
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:161
Game information for the AI.
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:61
int side_number
Definition: game_info.hpp:40
std::unique_ptr< ai_composite > composite_ai_ptr
Definition: game_info.hpp:48
Handling of system events.
Definition: manager.hpp:43
std::string observer
std::string path
Definition: filesystem.cpp:83