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