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