The Battle for Wesnoth  1.19.5+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  /* The singleton can't be set to null in the destructor because member objects
135  (which access the singleton) are destroyed *after* the destructor has been run. */
136  ~manager() = default;
137 
138  // =======================================================================
139  // ACCESS TO MANAGER
140  // =======================================================================
141 
143  {
144  assert(singleton_ != nullptr);
145  return *singleton_;
146  }
147 
148  static bool has_manager()
149  {
150  return singleton_ != nullptr;
151  }
152 
153  // =======================================================================
154  // LIFECYCLE
155  // =======================================================================
156 
157  /**
158  * Adds observer of game events.
159  * Should be called in playsingle_controller 's constructor.
160  */
161  void add_observer( events::observer* event_observer);
162 
163  /**
164  * Removes an observer of game events.
165  * Should be called in playsingle_controller 's destructor.
166  */
167  void remove_observer( events::observer* event_observer );
168 
169  /**
170  * Adds observer of game events except ai_user_interact event and ai_sync_network event
171  */
172  void add_gamestate_observer( events::observer* event_observer);
173 
174  /**
175  * Removes an observer of game events except ai_user_interact event and ai_sync_network event
176  */
177  void remove_gamestate_observer( events::observer* event_observer );
178 
179  /**
180  * Notifies all observers of 'ai_user_interact' event.
181  * Function which should be called frequently to allow the user to interact
182  * with the interface. This function will make sure that interaction
183  * doesn't occur too often, so there is no problem with calling it very
184  * regularly.
185  */
186  void raise_user_interact();
187 
188  /**
189  * Notifies all observers of 'ai_sync_network' event.
190  * Basically a request from the AI to sync the network.
191  */
192  void raise_sync_network();
193 
194  /**
195  * Notifies all observers of 'ai_gamestate_changed' event.
196  */
198 
199  /**
200  * Notifies all observers of 'ai_tod_changed' event.
201  */
202  void raise_tod_changed();
203 
204  /**
205  * Notifies all observers of 'ai_recruit_list_changed' event.
206  */
208 
209  /**
210  * Notifies all observers of 'ai_turn_started' event.
211  */
212  void raise_turn_started();
213 
214  /**
215  * Notifies all observers of 'ai_map_changed' event.
216  */
217  void raise_map_changed();
218 
219  /**
220  * Adds an observer of 'ai_map_changed' event.
221  */
222  void add_map_changed_observer( events::observer* event_observer );
223 
224  /**
225  * Adds an observer of 'ai_recruit_list_changed' event.
226  */
227  void add_recruit_list_changed_observer( events::observer* event_observer );
228 
229  /**
230  * Adds an observer of 'ai_turn_started' event.
231  */
232  void add_turn_started_observer( events::observer* event_observer );
233 
234  /**
235  * Adds an observer of 'ai_tod_changed' event.
236  */
237  void add_tod_changed_observer( events::observer* event_observer );
238 
239  /**
240  * Deletes an observer of 'ai_map_changed' event.
241  */
242  void remove_map_changed_observer( events::observer* event_observer );
243 
244 
245  /**
246  * Deletes an observer of 'ai_recruit_list_changed' event.
247  */
249 
250  /**
251  * Deletes an observer of 'ai_turn_started' event.
252  */
253  void remove_turn_started_observer( events::observer* event_observer );
254 
255  /**
256  * Deletes an observer of 'ai_tod_changed' event.
257  */
258  void remove_tod_changed_observer( events::observer* event_observer );
259 
260 public:
261 
262  // =======================================================================
263  // EVALUATION
264  // =======================================================================
265 
266  /**
267  * Evaluates a string command using command AI.
268  * @note Running this command may invalidate references previously returned
269  * by manager. Will intercept those commands which start with '!'
270  * and '?', and will try to evaluate them as internal commands.
271  * @param side side number (1-based).
272  * @param str string to evaluate.
273  * @return string result of evaluation.
274  */
275  const std::string evaluate_command( side_number side, const std::string& str );
276 
277  // =======================================================================
278  // ADD, CREATE AIs, OR LIST AI TYPES
279  // =======================================================================
280 
281  /**
282  * Adds active AI for specified @a side from @a file.
283  * @note Running this command may invalidate references previously returned
284  * by manager. AI is not initialized at this point.
285  * @param side side number (1-based, as in game_info).
286  * @param file file name, follows the usual WML convention.
287  * @param replace should new ai replace the current ai or 'be placed on top of it'.
288  * @return true if successful.
289  */
290  bool add_ai_for_side_from_file( side_number side, const std::string& file, bool replace = true );
291 
292  /**
293  * Adds active AI for specified @a side from @a cfg.
294  * @note Running this command may invalidate references previously returned
295  * by manager. AI is not initialized at this point.
296  * @param side side number (1-based, as in game_info).
297  * @param cfg the config from which all ai parameters are to be read.
298  * @param replace should new ai replace the current ai or 'be placed on top of it'.
299  * @return true if successful.
300  */
301  bool add_ai_for_side_from_config(side_number side, const config &cfg, bool replace = true);
302 
303  // =======================================================================
304  // REMOVE
305  // =======================================================================
306 
307  /**
308  * Removes top-level AI from @a side.
309  * @note Running this command may invalidate references previously returned
310  * by manager.
311  * @param side side number (1-based, as in game_info).
312  */
313  void remove_ai_for_side( side_number side );
314 
315  /**
316  * Removes all AIs from @a side.
317  * @note Running this command may invalidate references previously returned
318  * by manager.
319  * @param side side number (1-based, as in game_info).
320  */
322 
323  /**
324  * Clears all the AIs.
325  * @note Running this command may invalidate references previously returned
326  * by manager. For example, this is called from the destructor of
327  * playsingle_controller. It is necessary to do this if any of the
328  * info structures used by the AI goes out of scope.
329  */
330  void clear_ais();
331 
332  // =======================================================================
333  // GET active AI parameters
334  // =======================================================================
335 
336  /**
337  * Gets AI info for active AI of the given @a side.
338  * @param side side number (1-based).
339  * @return a reference to active AI info.
340  */
342 
343  /**
344  * Gets AI Overview for active AI of the given @a side
345  * @param side side number (1-based)
346  * @return an ai overview
347  */
348  std::string get_active_ai_overview_for_side( side_number side );
349 
350  /**
351  * Gets AI Structure for active AI of the given @a side
352  * @param side side number (1-based)
353  * @return an ai structure
354  */
355  std::string get_active_ai_structure_for_side( side_number side );
356 
357  /**
358  * Gets AI algorithm identifier for active AI of the given @a side.
359  * @param side side number (1-based).
360  * @return ai identifier for the active AI
361  */
363 
364  /**
365  * Gets the active AI holder for debug purposes.
366  * Will only work in debug mode, otherwise returns a reference to an empty holder
367  * @param side side number(1-based)
368  * @return debug ? active holder : empty holder
369  */
371 
372  /**
373  * Gets AI config for active AI of the given @a side.
374  * @param side side number (1-based).
375  * @return a config object for the active AI
376  */
377  config to_config( side_number side );
378 
379  /**
380  * Gets global AI-game info
381  * @return a reference to the AI-game info.
382  */
384 
386 
387  // =======================================================================
388  // SET active AI parameters
389  // =======================================================================
390 
391  /**
392  * Modifies AI parameters for active AI of the given @a side.
393  * This function is a backend for [modify_ai] tag
394  * @param side side_number (1-based, as in game_info).
395  * @param cfg - content of [modify_ai] tag
396  */
397 
398  void modify_active_ai_for_side( ai::side_number side, const config &cfg );
399 
400  /**
401  * Appends AI parameters to active AI of the given @a side.
402  * This function is a backend for [modify_side][ai] tag
403  * @param side side_number (1-based, as in game_info).
404  * @param cfg - content of [modify_side][ai] tag
405  */
406 
407  void append_active_ai_for_side( ai::side_number side, const config &cfg );
408 
409  // =======================================================================
410  // PROXY
411  // =======================================================================
412 
413  /**
414  * Plays a turn for the specified side using its active AI.
415  * @param side side number (1-based, as in game_info).
416  */
417  void play_turn(side_number side);
418 
419 private:
420 
421  typedef std::map< side_number, std::stack< holder >> AI_map_of_stacks;
422 
423  std::deque< command_history_item > history_;
426 
434  std::chrono::steady_clock::time_point last_interact_;
436 
438 
440 
441  // =======================================================================
442  // EVALUATION
443  // =======================================================================
444 
445  /**
446  * Evaluates an internal manager command.
447  * @param side side number (1-based).
448  * @param str string to evaluate.
449  * @return string result of evaluation.
450  * TODO: rewrite this function to use a fai or lua parser.
451  */
452  const std::string internal_evaluate_command( side_number side, const std::string& str );
453 
454  /**
455  * Determines if the command should be intercepted and evaluated as internal command.
456  * @param str command string to check.
457  * @return true if the command should be intercepted and evaluated.
458  */
459  bool should_intercept( const std::string& str ) const;
460 
461  // =======================================================================
462  // AI STACKS
463  // =======================================================================
464 
465  /**
466  * Gets the AI stack for the specified side, create it if it doesn't exist.
467  */
468  std::stack< holder >& get_or_create_ai_stack_for_side(side_number side);
469 
470  // =======================================================================
471  // AI HOLDERS
472  // =======================================================================
473 
474  /**
475  * Gets active holder for specified @a side.
476  */
478 
479  // =======================================================================
480  // AI POINTERS
481  // =======================================================================
482 
483  /**
484  * Gets active AI for specified side.
485  * @note Running this command may invalidate references previously returned
486  * by manager.
487  * @param side side number (1-based, as in game_info).
488  * @return a reference to the active AI.
489  * @note This reference may become invalid after specific manager operations.
490  */
492 
493  friend class ::game_launcher;
494 };
495 
496 } //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:427
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:685
void clear_ais()
Clears all the AIs.
Definition: manager.cpp:660
std::string get_active_ai_overview_for_side(side_number side)
Gets AI Overview for active AI of the given side.
Definition: manager.cpp:675
ai_composite & get_active_ai_for_side(side_number side)
Gets active AI for specified side.
Definition: manager.cpp:777
void raise_tod_changed()
Notifies all observers of 'ai_tod_changed' event.
Definition: manager.cpp:445
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:625
config to_config(side_number side)
Gets AI config for active AI of the given side.
Definition: manager.cpp:700
events::generic_event user_interact_
Definition: manager.hpp:429
void remove_all_ais_for_side(side_number side)
Removes all AIs from side.
Definition: manager.cpp:650
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:373
void remove_observer(events::observer *event_observer)
Removes an observer of game events.
Definition: manager.cpp:360
void raise_turn_started()
Notifies all observers of 'ai_turn_started' event.
Definition: manager.cpp:449
static manager * singleton_
Definition: manager.hpp:439
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:441
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:367
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:670
AI_map_of_stacks ai_map_
Definition: manager.hpp:437
std::map< side_number, std::stack< holder > > AI_map_of_stacks
Definition: manager.hpp:421
std::string get_active_ai_structure_for_side(side_number side)
Gets AI Structure for active AI of the given side.
Definition: manager.cpp:680
events::generic_event sync_network_
Definition: manager.hpp:430
void raise_user_interact()
Notifies all observers of 'ai_user_interact' event.
Definition: manager.cpp:417
static const std::string AI_TYPE_FORMULA_AI
Definition: manager.hpp:123
events::generic_event recruit_list_changed_
Definition: manager.hpp:428
const std::string evaluate_command(side_number side, const std::string &str)
Evaluates a string command using command AI.
Definition: manager.cpp:465
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:748
holder & get_active_ai_holder_for_side(side_number side)
Gets active holder for specified side.
Definition: manager.cpp:760
void add_recruit_list_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:392
game_info & get_active_ai_info_for_side(side_number side)
Gets AI info for active AI of the given side.
Definition: manager.cpp:705
void add_map_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_map_changed' event.
Definition: manager.cpp:387
static manager & get_singleton()
Definition: manager.hpp:142
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:397
static const std::string AI_TYPE_DEFAULT
Definition: manager.hpp:126
std::deque< command_history_item > history_
Definition: manager.hpp:423
static bool has_manager()
Definition: manager.hpp:148
~manager()=default
game_info & get_ai_info()
Gets global AI-game info.
Definition: manager.cpp:710
game_info ai_info_
Definition: manager.hpp:425
events::generic_event gamestate_changed_
Definition: manager.hpp:432
const ai::unit_advancements_aspect & get_advancement_aspect_for_side(side_number side)
Definition: manager.cpp:715
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:615
events::generic_event turn_started_
Definition: manager.hpp:433
void remove_ai_for_side(side_number side)
Removes top-level AI from side.
Definition: manager.cpp:642
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:665
int num_interact_
Definition: manager.hpp:435
void play_turn(side_number side)
Plays a turn for the specified side using its active AI.
Definition: manager.cpp:724
std::chrono::steady_clock::time_point last_interact_
Definition: manager.hpp:434
const std::string internal_evaluate_command(side_number side, const std::string &str)
Evaluates an internal manager command.
Definition: manager.cpp:504
long history_item_counter_
Definition: manager.hpp:424
void raise_map_changed()
Notifies all observers of 'ai_map_changed' event.
Definition: manager.cpp:457
bool should_intercept(const std::string &str) const
Determines if the command should be intercepted and evaluated as internal command.
Definition: manager.cpp:485
void raise_recruit_list_changed()
Notifies all observers of 'ai_recruit_list_changed' event.
Definition: manager.cpp:453
void remove_turn_started_observer(events::observer *event_observer)
Deletes an observer of 'ai_turn_started' event.
Definition: manager.cpp:412
ai::holder & get_active_ai_holder_for_side_dbg(side_number side)
Gets the active AI holder for debug purposes.
Definition: manager.cpp:690
void raise_sync_network()
Notifies all observers of 'ai_sync_network' event.
Definition: manager.cpp:437
events::generic_event tod_changed_
Definition: manager.hpp:431
void remove_map_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_map_changed' event.
Definition: manager.cpp:407
void add_tod_changed_observer(events::observer *event_observer)
Adds an observer of 'ai_tod_changed' event.
Definition: manager.cpp:379
void remove_tod_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_tod_changed' event.
Definition: manager.cpp:383
void add_observer(events::observer *event_observer)
Adds observer of game events.
Definition: manager.cpp:353
void remove_recruit_list_changed_observer(events::observer *event_observer)
Deletes an observer of 'ai_recruit_list_changed' event.
Definition: manager.cpp:402
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:90