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