1 /**********************************************************************
2 *
3 * FreeDoko a Doppelkopf-Game
4 *
5 * Copyright (C) 2001 – 2018 by Diether Knof and Borg Enders
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You can find this license in the file 'gpl.txt'.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * Contact:
24 * Diether Knof dknof@posteo.de
25 *
26 *********************************************************************/
27
28 #include "constants.h"
29
30 #include "aiconfig.h"
31
32 #include "../party/party.h"
33 #include "../party/rule.h"
34 #include "../misc/preferences.h"
35 #include "../ui/ui.h"
36
37
38 /** -> result
39 **
40 ** @param difficulty difficulty of the returned ai
41 **
42 ** @return the preset aiconfig of the given difficulty
43 **/
44 Aiconfig const&
preset(Difficulty const difficulty)45 Aiconfig::preset(Difficulty const difficulty)
46 {
47 DEBUG_ASSERTION( (difficulty != Difficulty::custom),
48 "Aiconfig::preset(Type::difficulty)\n"
49 " difficulty is 'custom'");
50
51 // just to get a warning when a new difficulty has been added
52 switch (difficulty) {
53 case Difficulty::custom:
54 case Difficulty::standard:
55 case Difficulty::careful:
56 case Difficulty::offensive:
57 case Difficulty::unfair:
58 break;
59 } // switch (difficulty)
60
61 static map<Difficulty, unique_ptr<Aiconfig>> aiconfigs_with_nines;
62 static map<Difficulty, unique_ptr<Aiconfig>> aiconfigs_without_nines;
63 if (aiconfigs_with_nines.empty()) {
64 { // standard
65 aiconfigs_with_nines[Difficulty::standard] = make_unique<Aiconfig>();
66 } // standard
67 { // careful
68 aiconfigs_with_nines[Difficulty::careful] = make_unique<Aiconfig>();
69 auto& aiconfig = *aiconfigs_with_nines[Difficulty::careful];
70 aiconfig.bool_[Type::trusting] = false;
71 aiconfig.int_[Type::limitqueen] = 9;
72 aiconfig.int_[Type::limitdulle] = 12;
73 aiconfig.int_[Type::lastfehlcreation] = 4;
74 aiconfig.int_[Type::first_trick_for_trump_points_optimization] = 5;
75 aiconfig.int_[Type::announcelimit] = 11;
76 aiconfig.int_[Type::announcelimitreply] = 10;
77 } // careful
78 { // offensive
79 aiconfigs_with_nines[Difficulty::offensive] = make_unique<Aiconfig>();
80 auto& aiconfig = *aiconfigs_with_nines[Difficulty::offensive];
81 aiconfig.bool_[Type::trusting] = true;
82 aiconfig.bool_[Type::aggressive] = true;
83 aiconfig.int_[Type::limitqueen] = 7;
84 aiconfig.int_[Type::limitdulle] = 10;
85 aiconfig.int_[Type::lastfehlcreation] = 5;
86 aiconfig.int_[Type::first_trick_for_trump_points_optimization] = 5;
87 aiconfig.int_[Type::announcelimit] = 10;
88 aiconfig.int_[Type::announcelimitreply] = 9;
89
90 for (auto& states : aiconfig.heuristic_states_) {
91 for (auto& state : states.second) {
92 if (state.heuristic == Heuristic::grab_trick) {
93 state.active = true;
94 }
95 }
96 }
97 } // offensive
98 { // unfair
99 aiconfigs_with_nines[Difficulty::unfair] = make_unique<Aiconfig>();
100 auto& aiconfig = *aiconfigs_with_nines[Difficulty::unfair];
101 aiconfig.bool_[Type::hands_known] = true;
102 } // unfair
103 // create configs without nines
104 for (auto const difficulty : aiconfig_difficulty_list) {
105 if (difficulty == Difficulty::custom)
106 continue;
107 aiconfigs_without_nines[difficulty]
108 = make_unique<Aiconfig>(*aiconfigs_with_nines[difficulty]);
109 auto& aiconfig = *aiconfigs_without_nines[difficulty];
110 for (unsigned i = aiconfig.aitype_.size() / 2 + 1;
111 i < aiconfig.aitype_.size(); ++i) {
112 aiconfig.aitype_[i - 2] = aiconfig.aitype_[i];
113 }
114 for (unsigned i = aiconfig.rating_.size() / 2 + 1;
115 i < aiconfig.rating_.size(); ++i) {
116 aiconfig.rating_[i - 2] = aiconfig.rating_[i];
117 }
118 for (unsigned i = aiconfig.future_limit_.size() / 2 + 1;
119 i < aiconfig.future_limit_.size(); ++i) {
120 aiconfig.future_limit_[i - 2] = aiconfig.future_limit_[i];
121 }
122 }
123 } // if (aiconfigs.empty())
124
125 if (::party->rule()(Rule::Type::with_nines))
126 return *aiconfigs_with_nines[difficulty];
127 else
128 return *aiconfigs_without_nines[difficulty];
129 }
130
131 /** @return the (interesting) keys for the heuristic configuration
132 **/
133 vector<HeuristicsMap::Key> const&
keys()134 Aiconfig::keys()
135 {
136 static vector<HeuristicsMap::Key> const keys = {
137 {HeuristicsMap::GameTypeGroup::normal, HeuristicsMap::PlayerTypeGroup::re},
138 {HeuristicsMap::GameTypeGroup::normal, HeuristicsMap::PlayerTypeGroup::contra},
139 {HeuristicsMap::GameTypeGroup::marriage_undetermined, HeuristicsMap::PlayerTypeGroup::re},
140 {HeuristicsMap::GameTypeGroup::marriage_undetermined, HeuristicsMap::PlayerTypeGroup::contra},
141 {HeuristicsMap::GameTypeGroup::marriage_silent, HeuristicsMap::PlayerTypeGroup::re},
142 {HeuristicsMap::GameTypeGroup::marriage_silent, HeuristicsMap::PlayerTypeGroup::contra},
143 {HeuristicsMap::GameTypeGroup::poverty, HeuristicsMap::PlayerTypeGroup::special},
144 {HeuristicsMap::GameTypeGroup::poverty, HeuristicsMap::PlayerTypeGroup::re},
145 {HeuristicsMap::GameTypeGroup::poverty, HeuristicsMap::PlayerTypeGroup::contra},
146 {HeuristicsMap::GameTypeGroup::soli_color, HeuristicsMap::PlayerTypeGroup::re},
147 {HeuristicsMap::GameTypeGroup::soli_color, HeuristicsMap::PlayerTypeGroup::contra},
148 {HeuristicsMap::GameTypeGroup::soli_single_picture, HeuristicsMap::PlayerTypeGroup::re},
149 {HeuristicsMap::GameTypeGroup::soli_single_picture, HeuristicsMap::PlayerTypeGroup::contra},
150 {HeuristicsMap::GameTypeGroup::soli_double_picture, HeuristicsMap::PlayerTypeGroup::re},
151 {HeuristicsMap::GameTypeGroup::soli_double_picture, HeuristicsMap::PlayerTypeGroup::contra},
152 {HeuristicsMap::GameTypeGroup::solo_koehler, HeuristicsMap::PlayerTypeGroup::re},
153 {HeuristicsMap::GameTypeGroup::solo_koehler, HeuristicsMap::PlayerTypeGroup::contra},
154 {HeuristicsMap::GameTypeGroup::solo_meatless, HeuristicsMap::PlayerTypeGroup::re},
155 {HeuristicsMap::GameTypeGroup::solo_meatless, HeuristicsMap::PlayerTypeGroup::contra},
156 };
157
158 return keys;
159 }
160
161 /** -> result
162 **
163 ** @param type aitype
164 **
165 ** @return whether the aitype has support for the rating
166 **/
167 bool
supports_rating(AiType const type)168 supports_rating(AiType const type)
169 {
170 switch(type) {
171 case AiType::no_choosebestcard:
172 case AiType::random:
173 case AiType::virtual_games:
174 return false;
175 case AiType::gametree:
176 case AiType::gametree_with_heuristics:
177 case AiType::gametree_for_team:
178 case AiType::monte_carlo:
179 case AiType::monte_carlo_jab_or_serve:
180 return true;
181 }; // switch (type)
182
183 DEBUG_ASSERTION(false,
184 "::support_rating(type)\n"
185 " unsupported type '" << type << "'");
186 return false;
187 }
188
189 /** constructor
190 **/
Aiconfig()191 Aiconfig::Aiconfig() :
192 aitype_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
193 rating_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
194 future_limit_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
195 heuristic_states_(),
196 update_level_(0)
197 {
198 this->reset_to_hardcoded();
199 }
200
201 /** constructor
202 **
203 ** @param difficulty difficulty to set
204 **/
Aiconfig(Difficulty const difficulty)205 Aiconfig::Aiconfig(Difficulty const difficulty) :
206 aitype_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
207 rating_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
208 future_limit_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
209 heuristic_states_(),
210 update_level_(0)
211 {
212 this->reset_to_hardcoded();
213 this->set_to_difficulty(difficulty);
214 }
215
216 /** constructor
217 **
218 ** @param istr stream with the infos
219 **/
Aiconfig(istream & istr)220 Aiconfig::Aiconfig(istream& istr) :
221 aitype_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
222 rating_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
223 future_limit_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
224 heuristic_states_(),
225 update_level_(0)
226 {
227 (void)this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
228 HeuristicsMap::PlayerTypeGroup::re)];
229 #ifdef WORKAROUND
230 this->init_heuristic_states();
231 #endif
232 this->read(istr);
233 }
234
235 /** constructor
236 **
237 ** @param istr stream with the infos
238 ** @param difficulty difficulty to set
239 **/
Aiconfig(istream & istr,Difficulty const difficulty)240 Aiconfig::Aiconfig(istream& istr, Difficulty const difficulty) :
241 difficulty_(difficulty),
242 aitype_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
243 rating_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
244 future_limit_(::party->rule()(Rule::Type::max_number_of_tricks_in_game)),
245 heuristic_states_(),
246 update_level_(1)
247 {
248 (void)this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
249 HeuristicsMap::PlayerTypeGroup::re)];
250 #ifdef WORKAROUND
251 this->init_heuristic_states();
252 #endif
253 this->read(istr);
254 DEBUG_ASSERTION(this->update_level_ == 1,
255 "Aiconfig::Aiconfig(istr, difficulty)\n"
256 " this->update_level_ = " << this->update_level_ << " is not 1");
257 this->update_level_ = 0;
258
259 this->difficulty_ = difficulty;
260 }
261
262 /** copy constructor
263 **
264 ** @param aiconfig aiconfig to copy
265 **/
Aiconfig(Aiconfig const & aiconfig)266 Aiconfig::Aiconfig(Aiconfig const& aiconfig) :
267 difficulty_(aiconfig.difficulty_),
268 aitype_(aiconfig.aitype_),
269 rating_(aiconfig.rating_),
270 future_limit_(aiconfig.future_limit_),
271 heuristic_states_(aiconfig.heuristic_states_),
272 bool_(aiconfig.bool_),
273 int_(aiconfig.int_),
274 card_(aiconfig.card_),
275 update_level_(0)
276 { }
277
278 /** copy operator
279 **
280 ** @param aiconfig aiconfig to copy
281 **
282 ** @return aiconfig
283 **/
284 Aiconfig&
operator =(Aiconfig const & aiconfig)285 Aiconfig::operator=(Aiconfig const& aiconfig)
286 {
287 if (this == &aiconfig)
288 return *this;
289
290 this->enter_update();
291 this->difficulty_ = aiconfig.difficulty_;
292 for (unsigned t = 0; t < ::party->rule()(Rule::Type::max_number_of_tricks_in_game);
293 ++t) {
294 this->set_aitype(t, aiconfig.aitype(t));
295 this->set_rating(t, aiconfig.rating(t));
296 this->set_future_limit(t, aiconfig.future_limit(t));
297 }
298 this->heuristic_states_ = aiconfig.heuristic_states_;
299 for (auto const type : Aiconfig::Type::bool_list)
300 this->set(type, aiconfig.value(type));
301 for (auto const type : Aiconfig::Type::int_list)
302 this->set(type, aiconfig.value(type));
303 for (auto const type : Aiconfig::Type::card_list)
304 this->set(type, aiconfig.value(type));
305 this->difficulty_ = aiconfig.difficulty();
306
307 this->leave_update(this->difficulty());
308
309 return *this;
310 }
311
312 /** destructor
313 **/
314 Aiconfig::~Aiconfig()
315 = default;
316
317 /**
318 ** resets the aiconfig to the default values
319 **
320 ** @param no number of the player
321 ** default: 'UINT_MAX'
322 **/
323 void
reset_to_hardcoded(unsigned const no)324 Aiconfig::reset_to_hardcoded(unsigned const no)
325 {
326
327 switch (no) {
328 case UINT_MAX:
329 break;
330 default:
331 this->set_to_difficulty(Difficulty::standard);
332 return ;
333 } // switch (no)
334
335 this->enter_update();
336
337 this->set(Type::trusting, false);
338 this->set(Type::aggressive, false);
339 this->set(Type::hands_known, false);
340 this->set(Type::teams_known, false);
341 this->set(Type::estimate_hands, true);
342 this->set(Type::fehlcreationonfirstcard, false);
343
344 this->set(Type::remembertricks, 12);
345
346 this->set(Type::limit_throw_fehl, 8);
347 this->set(Type::limitqueen, 9);
348 this->set(Type::limitdulle, 12);
349
350 this->set(Type::lastfehlcreation, 3);
351 this->set(Type::last_tricks_without_heuristics, 3);
352 this->set(Type::first_trick_for_trump_points_optimization, 4);
353
354 this->set(Type::announcelimit, 11);
355 this->set(Type::announcelimitdec, 1);
356 this->set(Type::announceconfig, 1);
357 this->set(Type::announcelimitreply, 10);
358 this->set(Type::announceconfigreply, 1);
359
360 this->set(Type::limitthrowing, Card::diamond_queen);
361
362 this->set(Type::trumplimit_solocolor, Card::diamond_queen);
363 this->set(Type::trumplimit_solojack, Card::diamond_jack);
364 this->set(Type::trumplimit_soloqueen, Card::diamond_queen);
365 this->set(Type::trumplimit_soloking, Card::diamond_king);
366 this->set(Type::trumplimit_solojackking, Card::club_jack);
367 this->set(Type::trumplimit_solojackqueen, Card::club_jack);
368 this->set(Type::trumplimit_soloqueenking, Card::club_queen);
369 this->set(Type::trumplimit_solokoehler, Card::club_queen);
370 this->set(Type::trumplimit_meatless, Card::diamond_ten);
371 this->set(Type::trumplimit_normal, Card::heart_queen);
372
373 this->set(Type::lowest_trumplimit_solocolor, Card::heart_jack);
374 this->set(Type::lowest_trumplimit_solojack, Card::heart_jack);
375 this->set(Type::lowest_trumplimit_soloqueen, Card::heart_queen);
376 this->set(Type::lowest_trumplimit_soloking, Card::heart_king);
377 this->set(Type::lowest_trumplimit_solojackking, Card::spade_jack);
378 this->set(Type::lowest_trumplimit_solojackqueen, Card::spade_jack);
379 this->set(Type::lowest_trumplimit_soloqueenking, Card::spade_queen);
380 this->set(Type::lowest_trumplimit_solokoehler, Card::spade_queen);
381 this->set(Type::lowest_trumplimit_meatless, Card::diamond_queen);
382 this->set(Type::lowest_trumplimit_normal, Card::diamond_jack);
383
384 this->set(Type::limithigh, Card::heart_queen);
385
386 this->aitype_[ 0] = AiType::monte_carlo_jab_or_serve;
387 this->aitype_[ 1] = AiType::monte_carlo_jab_or_serve;
388 this->aitype_[ 2] = AiType::virtual_games;
389 this->aitype_[ 3] = AiType::virtual_games;
390 this->aitype_[ 4] = AiType::virtual_games;
391 this->aitype_[ 5] = AiType::virtual_games;
392 this->aitype_[ 6] = AiType::virtual_games;
393 this->aitype_[ 7] = AiType::virtual_games;
394 this->aitype_[ 8] = AiType::gametree_for_team;
395 this->aitype_[ 9] = AiType::gametree_for_team;
396 this->aitype_[10] = AiType::gametree_for_team;
397 this->aitype_[11] = AiType::gametree_for_team;
398 this->rating_[ 0] = Rating::Type::linear;
399 this->rating_[ 1] = Rating::Type::linear;
400 this->rating_[ 2] = Rating::Type::linear;
401 this->rating_[ 3] = Rating::Type::linear;
402 this->rating_[ 4] = Rating::Type::linear;
403 this->rating_[ 5] = Rating::Type::linear;
404 this->rating_[ 6] = Rating::Type::linear;
405 this->rating_[ 7] = Rating::Type::linear;
406 this->rating_[ 8] = Rating::Type::linear;
407 this->rating_[ 9] = Rating::Type::linear;
408 this->rating_[10] = Rating::Type::linear;
409 this->rating_[11] = Rating::Type::linear;
410 this->future_limit_[ 0] = 2000;
411 this->future_limit_[ 1] = 2000;
412 this->future_limit_[ 2] = 10000;
413 this->future_limit_[ 3] = 10000;
414 this->future_limit_[ 4] = 10000;
415 this->future_limit_[ 5] = 10000;
416 this->future_limit_[ 6] = 10000;
417 this->future_limit_[ 7] = 10000;
418 this->future_limit_[ 8] = 10000;
419 this->future_limit_[ 9] = 10000;
420 this->future_limit_[10] = 10000;
421 this->future_limit_[11] = 10000;
422
423 this->init_heuristic_states();
424
425 this->difficulty_ = Difficulty::standard;
426 this->leave_update(Difficulty::standard);
427 } // void Aiconfig::reset_to_hardcoded(unsigned no = UINT_MAX)
428
429 /** sets the aiconfig to the preset difficulty
430 **
431 ** @param difficulty difficulty to set to
432 **/
433 void
set_to_difficulty(Difficulty const difficulty)434 Aiconfig::set_to_difficulty(Difficulty const difficulty)
435 {
436 if (difficulty == Difficulty::custom)
437 return ;
438
439 *this = Aiconfig::preset(difficulty);
440 if (::ui != nullptr)
441 ::ui->aiconfig_changed(*this);
442 }
443
444 /** the rule has changed
445 **
446 ** @param type rule type to have changed
447 ** @param old_value old value of the rule
448 **/
449 void
rule_changed(int const type,void const * const old_value)450 Aiconfig::rule_changed(int const type, void const* const old_value)
451 {
452 if (type == Rule::Type::with_nines) {
453 if (this->difficulty() != Difficulty::custom) {
454 auto const difficulty = this->difficulty();
455 this->difficulty_ = Difficulty::custom;
456 this->set_to_difficulty(difficulty);
457 }
458 } // if (type == Rule::Type::with_nines)
459 }
460
461 /** @return the difficulty
462 **/
463 Aiconfig::Difficulty
difficulty() const464 Aiconfig::difficulty() const
465 { return this->difficulty_; }
466
467 /** updates the difficulty
468 **/
469 void
update_difficulty()470 Aiconfig::update_difficulty()
471 {
472 if (this->in_update())
473 return ;
474
475 auto difficulty = Difficulty::custom;
476 for (auto const d : aiconfig_difficulty_list) {
477 if ( (d != Difficulty::custom)
478 && this->equal(Aiconfig::preset(d))) {
479 difficulty = d;
480 break;
481 }
482 }
483
484 if (difficulty == this->difficulty())
485 return ;
486
487 this->difficulty_ = difficulty;
488 if (::ui)
489 ::ui->aiconfig_changed(*this);
490 }
491
492 /** @return whether the aiconfig is in an update
493 **/
494 bool
in_update() const495 Aiconfig::in_update() const
496 {
497 return (this->update_level_ > 0);
498 }
499
500 /** begin a (nested) update
501 **/
502 void
enter_update()503 Aiconfig::enter_update()
504 {
505 this->update_level_ += 1;
506 }
507
508 /** end a (nested) update
509 ** if the last update level is ended, update the difficulty
510 **/
511 void
leave_update()512 Aiconfig::leave_update()
513 {
514 DEBUG_ASSERTION((this->update_level_ > 0) && (this->update_level_ < 9999),
515 "Aiconfig::leave_update()\n"
516 " update_level is not > 0 / < 9999: " << this->update_level_);
517 this->update_level_ -= 1;
518 if (this->update_level_ == 0)
519 this->update_difficulty();
520 }
521
522 /** end a (nested) update
523 ** if the last update level is ended, set the difficulty manual
524 **
525 ** @param difficulty difficulty to set to
526 **/
527 void
leave_update(Difficulty const difficulty)528 Aiconfig::leave_update(Difficulty const difficulty)
529 {
530 DEBUG_ASSERTION(this->update_level_ > 0,
531 "Aiconfig::leave_update()\n"
532 " update_level is not > 0: " << this->update_level_);
533 this->update_level_ -= 1;
534 if (this->update_level_ == 0)
535 this->difficulty_ = difficulty;
536 }
537
538 /** comparison with the aiconfig
539 **
540 ** @param aiconfig aiconfig to compare with
541 **
542 ** @return whether aiconfig has the same values as the argument
543 **/
544 bool
equal(Aiconfig const & aiconfig) const545 Aiconfig::equal(Aiconfig const& aiconfig) const
546 {
547 return ( (this->aitype_ == aiconfig.aitype_)
548 && (this->future_limit_ == aiconfig.future_limit_)
549 && (this->rating_ == aiconfig.rating_)
550 && (this->heuristic_states_ == aiconfig.heuristic_states_)
551 && (this->bool_ == aiconfig.bool_)
552 && (this->int_ == aiconfig.int_)
553 && (this->card_ == aiconfig.card_) );
554 }
555
556 /** -> result
557 **
558 ** @param trickno trick number
559 **
560 ** @return the aitype for trick 'trickno'
561 **/
562 AiType
aitype(unsigned const trickno) const563 Aiconfig::aitype(unsigned const trickno) const
564 {
565 #if 0
566 if (::game_status == GameStatus::game_play
567 && trickno == 7
568 && this->aitype_[trickno] != AiType::gametree_for_team)
569 SEGFAULT;
570 #endif
571 return this->aitype_[trickno];
572 return this->aitype_[trickno];
573 } // AiType const& Aiconfig::aitye(unsigned const trickno) const;
574
575 /** sets the aitype for trick 'trickno'
576 **
577 ** @param trickno trick number
578 ** @param aitype new aitype
579 **/
580 void
set_aitype(unsigned const trickno,AiType const aitype)581 Aiconfig::set_aitype(unsigned const trickno, AiType const aitype)
582 {
583 #ifdef WORKAROUND
584 if (trickno >= this->future_limit_.size()) {
585 return ;
586 }
587 #endif
588 this->enter_update();
589 this->aitype_[trickno] = aitype;
590 this->leave_update();
591 }
592
593 /** sets the aitype for all tricks
594 **
595 ** @param aitype new aitype
596 **/
597 void
set_aitype_for_all_tricks(AiType const aitype)598 Aiconfig::set_aitype_for_all_tricks(AiType const aitype)
599 {
600 this->enter_update();
601 for (unsigned i = 0; i < this->aitype_.size(); ++i)
602 this->set_aitype(i, aitype);
603 this->leave_update();
604 }
605
606 /** -> result
607 **
608 ** @param trickno trick number
609 **
610 ** @return the future limit for trick 'trickno'
611 **/
612 unsigned
future_limit(unsigned const trickno) const613 Aiconfig::future_limit(unsigned const trickno) const
614 {
615 return this->future_limit_[trickno];
616 }
617
618 /** sets the future limit for trick 'trickno'
619 **
620 ** @param trickno trick number
621 ** @param future_limit new future limit
622 **/
623 void
set_future_limit(unsigned const trickno,unsigned const future_limit)624 Aiconfig::set_future_limit(unsigned const trickno, unsigned const future_limit)
625 {
626 #ifdef WORKAROUND
627 if (trickno >= this->future_limit_.size()) {
628 return ;
629 }
630 #endif
631 this->enter_update();
632 this->future_limit_[trickno] = future_limit;
633 this->leave_update();
634 }
635
636 /** sets the future limit for all tricks
637 **
638 ** @param future_limit new future limit
639 **/
640 void
set_future_limit_for_all_tricks(unsigned const future_limit)641 Aiconfig::set_future_limit_for_all_tricks(unsigned const future_limit)
642 {
643 this->enter_update();
644 for (unsigned i = 0; i < this->future_limit_.size(); ++i)
645 this->set_future_limit(i, future_limit);
646 this->leave_update();
647 }
648
649 /** -> result
650 **
651 ** @param trickno trick number
652 **
653 ** @return the rating for trick 'trickno'
654 **/
655 Rating::Type
rating(unsigned const trickno) const656 Aiconfig::rating(unsigned const trickno) const
657 {
658 return this->rating_[trickno];
659 }
660
661 /** sets the rating for trick 'trickno'
662 **
663 ** @param trickno trick number
664 ** @param rating new rating
665 **/
666 void
set_rating(unsigned const trickno,Rating::Type const rating)667 Aiconfig::set_rating(unsigned const trickno, Rating::Type const rating)
668 {
669 #ifdef WORKAROUND
670 if (trickno >= this->rating_.size()) {
671 return ;
672 }
673 #endif
674
675 this->enter_update();
676 this->rating_[trickno] = rating;
677 this->leave_update();
678 }
679
680 /** sets the rating for all tricks
681 **
682 ** @param rating new rating for all tricks
683 **/
684 void
set_rating_for_all_tricks(Rating::Type const rating)685 Aiconfig::set_rating_for_all_tricks(Rating::Type const rating)
686 {
687 this->enter_update();
688 for (unsigned i = 0; i < this->rating_.size(); ++i)
689 this->set_rating(i, rating);
690 this->leave_update();
691 }
692
693 /** -> result
694 **
695 ** @param key the key
696 **
697 ** @return the heuristic states for the given key
698 **/
699 vector<Aiconfig::HeuristicState> const&
heuristic_states(HeuristicsMap::Key const key) const700 Aiconfig::heuristic_states(HeuristicsMap::Key const key) const
701 {
702 auto states = this->heuristic_states_.find(key);
703
704 // if there is no special take a default one
705 if ( (states == this->heuristic_states_.end())
706 || states->second.empty()) {
707 if ( (key.gametype_group == HeuristicsMap::GameTypeGroup::solo_meatless)
708 && (key.playertype_group == HeuristicsMap::PlayerTypeGroup::contra) )
709 return this->heuristic_states(HeuristicsMap::GameTypeGroup::solo_meatless,
710 HeuristicsMap::PlayerTypeGroup::re);
711
712 if (key.gametype_group == HeuristicsMap::GameTypeGroup::normal)
713 return this->heuristic_states(HeuristicsMap::GameTypeGroup::normal, HeuristicsMap::PlayerTypeGroup::re);
714
715 return this->heuristic_states(HeuristicsMap::GameTypeGroup::normal, key.playertype_group);
716 } // if (states.empty())
717
718 return states->second;
719 }
720
721 /** -> result
722 **
723 ** @param gametype_group the game type group
724 ** @param playertype_group the player type group
725 **
726 ** @return the heuristic states for the given groups
727 **/
728 vector<Aiconfig::HeuristicState> const&
heuristic_states(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group) const729 Aiconfig::heuristic_states(HeuristicsMap::GameTypeGroup const gametype_group,
730 HeuristicsMap::PlayerTypeGroup const playertype_group
731 ) const
732 {
733 return this->heuristic_states(HeuristicsMap::Key(gametype_group,
734 playertype_group));
735 }
736
737 /** -> result
738 **
739 ** @param key the key
740 **
741 ** @return the heuristic states for the given key
742 **/
743 vector<Aiconfig::HeuristicState>&
heuristic_states(HeuristicsMap::Key const key)744 Aiconfig::heuristic_states(HeuristicsMap::Key const key)
745 {
746 auto states = this->heuristic_states_.find(key);
747
748 // if there is no special take a default one
749 if (states == this->heuristic_states_.end()) {
750 if ( (key.gametype_group == HeuristicsMap::GameTypeGroup::solo_meatless)
751 && (key.playertype_group == HeuristicsMap::PlayerTypeGroup::contra) )
752 return this->heuristic_states(HeuristicsMap::GameTypeGroup::solo_meatless,
753 HeuristicsMap::PlayerTypeGroup::re);
754
755 if (key.gametype_group == HeuristicsMap::GameTypeGroup::normal)
756 return this->heuristic_states(HeuristicsMap::GameTypeGroup::normal, HeuristicsMap::PlayerTypeGroup::re);
757
758 return this->heuristic_states(HeuristicsMap::GameTypeGroup::normal, key.playertype_group);
759 } // if (states.empty())
760
761 return states->second;
762 }
763
764 /** -> result
765 **
766 ** @param gametype_group the game type group
767 ** @param playertype_group the player type group
768 **
769 ** @return the heuristic states for the given groups
770 **/
771 vector<Aiconfig::HeuristicState>&
heuristic_states(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group)772 Aiconfig::heuristic_states(HeuristicsMap::GameTypeGroup const gametype_group,
773 HeuristicsMap::PlayerTypeGroup const playertype_group
774 )
775 {
776 return this->heuristic_states(HeuristicsMap::Key(gametype_group,
777 playertype_group));
778 }
779
780 /** -> result
781 **
782 ** @param gametype_group the game type group
783 ** @param playertype_group the player type group
784 **
785 ** @return the heuristics for the given groups
786 **/
787 vector<Aiconfig::Heuristic>
heuristics(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group) const788 Aiconfig::heuristics(HeuristicsMap::GameTypeGroup const gametype_group,
789 HeuristicsMap::PlayerTypeGroup const playertype_group
790 ) const
791 {
792 auto const& states
793 = this->heuristic_states(gametype_group, playertype_group);
794
795 vector<Heuristic> heuristics;
796 heuristics.push_back(Heuristic::only_one_valid_card);
797 for (auto const state : states)
798 if (state.active)
799 heuristics.push_back(state.heuristic);
800
801 heuristics.push_back(Heuristic::choose_best_card);
802 return heuristics;
803 }
804
805 /** -> result
806 **
807 ** @param player player
808 **
809 ** @return the heuristics for the player
810 **/
811 vector<Aiconfig::Heuristic>
heuristics(Player const & player) const812 Aiconfig::heuristics(Player const& player) const
813 {
814 return this->heuristics(HeuristicsMap::group(player.game()),
815 HeuristicsMap::group(player));
816 }
817
818 /** initializes the heuristic states
819 **/
820 void
init_heuristic_states()821 Aiconfig::init_heuristic_states()
822 {
823 this->enter_update();
824 this->heuristic_states_.clear();
825 (void)this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
826 HeuristicsMap::PlayerTypeGroup::re)];
827
828
829 { // normal
830 vector<HeuristicState>& states
831 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
832 HeuristicsMap::PlayerTypeGroup::re)];
833 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
834 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
835 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
836 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
837 states.push_back(HeuristicState(Heuristic::play_color_for_partner_ace, true));
838 states.push_back(HeuristicState(Heuristic::choose_ten, true));
839 states.push_back(HeuristicState(Heuristic::jab_for_doppelkopf, true));
840 states.push_back(HeuristicState(Heuristic::try_for_doppelkopf, true));
841 states.push_back(HeuristicState(Heuristic::pfund_in_first_color_run, true));
842 states.push_back(HeuristicState(Heuristic::choose_for_color_trick, true));
843 states.push_back(HeuristicState(Heuristic::pfund_in_first_color_run, true));
844 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
845 states.push_back(HeuristicState(Heuristic::jab_fox, true));
846 states.push_back(HeuristicState(Heuristic::choose_pfund, true));
847 states.push_back(HeuristicState(Heuristic::choose_pfund_before_partner, true));
848 states.push_back(HeuristicState(Heuristic::jab_for_ace, true));
849 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
850 states.push_back(HeuristicState(Heuristic::play_for_team, true));
851 states.push_back(HeuristicState(Heuristic::play_color_for_partner, true));
852 states.push_back(HeuristicState(Heuristic::try_color_for_partner, true));
853 states.push_back(HeuristicState(Heuristic::start_with_color, false));
854 states.push_back(HeuristicState(Heuristic::retry_color, true));
855 states.push_back(HeuristicState(Heuristic::jab_color_trick_with_dulle, true));
856 states.push_back(HeuristicState(Heuristic::save_dulle, true));
857 states.push_back(HeuristicState(Heuristic::partner_backhand_draw_trump, true));
858 states.push_back(HeuristicState(Heuristic::create_fehl, true));
859 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
860 states.push_back(HeuristicState(Heuristic::last_player_pass_small_trick, true));
861 states.push_back(HeuristicState(Heuristic::cannot_jab, true));
862 states.push_back(HeuristicState(Heuristic::best_winning, true));
863 states.push_back(HeuristicState(Heuristic::draw_trump, true));
864 states.push_back(HeuristicState(Heuristic::play_to_jab_later, true));
865 states.push_back(HeuristicState(Heuristic::start_with_low_color, false));
866 states.push_back(HeuristicState(Heuristic::start_with_low_trump, true));
867 states.push_back(HeuristicState(Heuristic::low_high, true));
868 states.push_back(HeuristicState(Heuristic::play_for_partner_worries, true));
869 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
870 states.push_back(HeuristicState(Heuristic::play_trump, true));
871 states.push_back(HeuristicState(Heuristic::play_bad_color, true));
872 states.push_back(HeuristicState(Heuristic::jab_color_over_fox, true));
873
874 { // contra
875 vector<HeuristicState>& states
876 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
877 HeuristicsMap::PlayerTypeGroup::contra)]
878 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
879 HeuristicsMap::PlayerTypeGroup::re)];
880 for (auto & state : states) {
881 switch (state.heuristic) {
882 case Heuristic::start_with_color:
883 state.active = true;
884 break;
885 case Heuristic::start_with_low_color:
886 state.active = true;
887 break;
888 case Heuristic::start_with_low_trump:
889 state.active = false;
890 break;
891 default:
892 break;
893 } // switch (s->heuristic)
894 } // for (s)
895 } // contra
896 } // normal
897 { // poverty
898 { // soloplayer
899 vector<HeuristicState>& states
900 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::poverty,
901 HeuristicsMap::PlayerTypeGroup::special)];
902 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
903 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
904 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
905 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
906 states.push_back(HeuristicState(Heuristic::play_color_for_partner_ace, true));
907 states.push_back(HeuristicState(Heuristic::choose_ten, true));
908 states.push_back(HeuristicState(Heuristic::play_color_for_partner, true));
909 states.push_back(HeuristicState(Heuristic::try_color_for_partner, true));
910 states.push_back(HeuristicState(Heuristic::choose_pfund_poverty, true));
911 states.push_back(HeuristicState(Heuristic::poverty_special_play_pfund, true));
912 states.push_back(HeuristicState(Heuristic::poverty_special_give_no_points, true));
913 states.push_back(HeuristicState(Heuristic::poverty_special_offer_pfund, true));
914 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
915 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
916 states.push_back(HeuristicState(Heuristic::play_bad_color, true));
917 } // soloplayer
918 { // re
919 vector<HeuristicState>& states
920 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::poverty,
921 HeuristicsMap::PlayerTypeGroup::re)];
922 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
923 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
924 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
925 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
926 states.push_back(HeuristicState(Heuristic::choose_ten, true));
927 states.push_back(HeuristicState(Heuristic::create_fehl, true));
928 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
929 states.push_back(HeuristicState(Heuristic::pfund_in_first_color_run, true));
930 states.push_back(HeuristicState(Heuristic::choose_for_color_trick, true));
931 states.push_back(HeuristicState(Heuristic::poverty_re_trump_color_trick_high, true));
932 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
933 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
934 states.push_back(HeuristicState(Heuristic::draw_trump, true));
935 states.push_back(HeuristicState(Heuristic::play_to_jab_later, true));
936 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
937 states.push_back(HeuristicState(Heuristic::poverty_re_play_trump, true));
938 states.push_back(HeuristicState(Heuristic::poverty_best_winning_card, true));
939 states.push_back(HeuristicState(Heuristic::play_trump, true));
940 states.push_back(HeuristicState(Heuristic::jab_color_over_fox, true));
941 } // re
942
943 { // contra
944 vector<HeuristicState>& states
945 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::poverty,
946 HeuristicsMap::PlayerTypeGroup::contra)];
947 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
948 states.push_back(HeuristicState(Heuristic::play_color_for_partner, true));
949 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
950 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
951 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
952 states.push_back(HeuristicState(Heuristic::choose_ten, true));
953 states.push_back(HeuristicState(Heuristic::poverty_contra_play_color, true));
954 states.push_back(HeuristicState(Heuristic::poverty_contra_trump_color_trick_high, true));
955 states.push_back(HeuristicState(Heuristic::choose_pfund, true));
956 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
957 states.push_back(HeuristicState(Heuristic::pfund_in_first_color_run, true));
958 states.push_back(HeuristicState(Heuristic::choose_for_color_trick, true));
959 states.push_back(HeuristicState(Heuristic::poverty_leave_to_partner, true));
960 states.push_back(HeuristicState(Heuristic::poverty_overjab_re, true));
961 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
962 states.push_back(HeuristicState(Heuristic::partner_backhand_draw_trump, true));
963 states.push_back(HeuristicState(Heuristic::jab_fox, true));
964 states.push_back(HeuristicState(Heuristic::play_for_partner_worries, true));
965 states.push_back(HeuristicState(Heuristic::choose_pfund_before_partner, true));
966 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
967 states.push_back(HeuristicState(Heuristic::best_winning, true));
968 states.push_back(HeuristicState(Heuristic::jab_color_over_fox, true));
969 } // contra
970 } // poverty
971
972 { // solo
973 { // color
974 { // soloplayer
975 vector<HeuristicState>& states
976 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_color,
977 HeuristicsMap::PlayerTypeGroup::re)];
978 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
979 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
980 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
981 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
982 states.push_back(HeuristicState(Heuristic::choose_ten, true));
983 states.push_back(HeuristicState(Heuristic::color_jab_for_ace, true));
984 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
985 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
986 states.push_back(HeuristicState(Heuristic::best_winning, true));
987 states.push_back(HeuristicState(Heuristic::color_low_high, true));
988 states.push_back(HeuristicState(Heuristic::draw_trump, true));
989 states.push_back(HeuristicState(Heuristic::play_to_jab_later, true));
990 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
991 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
992 } // soloplayer
993 { // contra
994 vector<HeuristicState>& states
995 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_color,
996 HeuristicsMap::PlayerTypeGroup::contra)]
997 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
998 HeuristicsMap::PlayerTypeGroup::re)];
999 for (auto & state : states) {
1000 switch (state.heuristic) {
1001 case Heuristic::start_with_low_color:
1002 state.active = true;
1003 break;
1004 case Heuristic::jab_for_ace:
1005 state.heuristic = Heuristic::color_jab_for_ace;
1006 break;
1007 case Heuristic::low_high:
1008 state.heuristic = Heuristic::color_low_high;
1009 break;
1010 case Heuristic::start_with_color:
1011 state.heuristic = Heuristic::play_color_in_solo;
1012 state.active = true;
1013 break;
1014 case Heuristic::partner_backhand_draw_trump:
1015 state.active = false;
1016 break;
1017 default:
1018 break;
1019 } // switch (s->heuristic)
1020 } // for (s \in states)
1021
1022 // ToDo: add partner_backhand_draw_trump
1023 } // contra
1024 } // color
1025 { // single picture
1026 { // soloplayer
1027 vector<HeuristicState>& states
1028 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1029 HeuristicsMap::PlayerTypeGroup::re)];
1030 states.push_back(HeuristicState(Heuristic::picture_pull_down_color, true));
1031 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
1032 states.push_back(HeuristicState(Heuristic::picture_get_last_trumps, true));
1033 states.push_back(HeuristicState(Heuristic::start_with_color_solo_ace, true));
1034 states.push_back(HeuristicState(Heuristic::picture_draw_trumps, true));
1035 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
1036 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
1037 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
1038 states.push_back(HeuristicState(Heuristic::picture_start_with_highest_color, true));
1039 states.push_back(HeuristicState(Heuristic::picture_play_last_trumps, true));
1040 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
1041 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
1042 states.push_back(HeuristicState(Heuristic::picture_jab_color_trick_for_sure, true));
1043 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
1044 states.push_back(HeuristicState(Heuristic::choose_ten, true));
1045 states.push_back(HeuristicState(Heuristic::color_jab_for_ace, true));
1046 states.push_back(HeuristicState(Heuristic::best_winning, true));
1047 states.push_back(HeuristicState(Heuristic::color_low_high, true));
1048 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
1049 states.push_back(HeuristicState(Heuristic::play_trump, true));
1050 states.push_back(HeuristicState(Heuristic::create_fehl, true));
1051 } // soloplayer
1052 { // contra
1053 vector<HeuristicState>& states
1054 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1055 HeuristicsMap::PlayerTypeGroup::contra)]
1056 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
1057 HeuristicsMap::PlayerTypeGroup::re)];
1058 for (auto & state : states) {
1059 switch (state.heuristic) {
1060 case Heuristic::choose_ten:
1061 state.heuristic = Heuristic::play_color_for_partner_ace;
1062 break;
1063 case Heuristic::play_color_for_partner_ace:
1064 state.heuristic = Heuristic::choose_ten;
1065 break;
1066 case Heuristic::start_with_low_color:
1067 state.active = true;
1068 break;
1069 case Heuristic::start_with_color:
1070 state.heuristic = Heuristic::play_color_in_solo;
1071 state.active = true;
1072 break;
1073 case Heuristic::partner_backhand_draw_trump:
1074 state.active = false;
1075 break;
1076 case Heuristic::pfund_in_first_color_run:
1077 state.active = false;
1078 break;
1079 default:
1080 break;
1081 } // switch (s->heuristic)
1082 } // for (s \in states)
1083 } // contra
1084 } // single picture
1085 { // double picture
1086 { // soloplayer
1087 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_double_picture,
1088 HeuristicsMap::PlayerTypeGroup::re)]
1089 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1090 HeuristicsMap::PlayerTypeGroup::re)];
1091 } // soloplayer
1092 { // contra
1093 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_double_picture,
1094 HeuristicsMap::PlayerTypeGroup::contra)]
1095 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1096 HeuristicsMap::PlayerTypeGroup::contra)];
1097 } // contra
1098 } // double picture
1099 { // koehler
1100 { // soloplayer
1101 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::solo_koehler,
1102 HeuristicsMap::PlayerTypeGroup::re)]
1103 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1104 HeuristicsMap::PlayerTypeGroup::re)];
1105 } // soloplayer
1106 { // contra
1107 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::solo_koehler,
1108 HeuristicsMap::PlayerTypeGroup::contra)]
1109 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_single_picture,
1110 HeuristicsMap::PlayerTypeGroup::contra)];
1111 } // contra
1112 } // koehler
1113 { // meatless
1114 { // soloplayer
1115 vector<HeuristicState>& states
1116 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::solo_meatless,
1117 HeuristicsMap::PlayerTypeGroup::re)];
1118 states.push_back(HeuristicState(Heuristic::picture_pull_down_color, true));
1119 states.push_back(HeuristicState(Heuristic::meatless_retry_last_color, true));
1120 states.push_back(HeuristicState(Heuristic::meatless_start_with_best_color, true));
1121 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
1122 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
1123 } // soloplayer
1124 { // contra
1125 vector<HeuristicState>& states
1126 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::solo_meatless,
1127 HeuristicsMap::PlayerTypeGroup::contra)];
1128 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
1129 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
1130 states.push_back(HeuristicState(Heuristic::choose_pfund, true));
1131 states.push_back(HeuristicState(Heuristic::create_fehl, true));
1132 } // contra
1133 } // meatless
1134 } // solo
1135 { // marriage
1136 { // undetermined marriage
1137 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::marriage_undetermined,
1138 HeuristicsMap::PlayerTypeGroup::re)]
1139 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::normal,
1140 HeuristicsMap::PlayerTypeGroup::re)];
1141
1142 vector<HeuristicState>& states
1143 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::marriage_undetermined,
1144 HeuristicsMap::PlayerTypeGroup::re)];
1145
1146 states.insert(states.begin(),
1147 HeuristicState(Heuristic::play_to_get_married, true));
1148 states.insert(states.begin(),
1149 HeuristicState(Heuristic::start_with_color_solo_ace, true));
1150
1151 {
1152 vector<HeuristicState>& states
1153 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::marriage_undetermined,
1154 HeuristicsMap::PlayerTypeGroup::contra)];
1155 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
1156
1157 states.push_back(HeuristicState(Heuristic::play_to_marry, true));
1158 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
1159 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
1160 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
1161 states.push_back(HeuristicState(Heuristic::play_color_for_partner_ace, true));
1162 states.push_back(HeuristicState(Heuristic::choose_ten, true));
1163 states.push_back(HeuristicState(Heuristic::jab_for_doppelkopf, true));
1164 states.push_back(HeuristicState(Heuristic::try_for_doppelkopf, true));
1165 states.push_back(HeuristicState(Heuristic::pfund_in_first_color_run, true));
1166 states.push_back(HeuristicState(Heuristic::choose_for_color_trick, true));
1167 states.push_back(HeuristicState(Heuristic::serve_color_trick, true));
1168 states.push_back(HeuristicState(Heuristic::jab_fox, true));
1169 states.push_back(HeuristicState(Heuristic::choose_pfund, true));
1170 states.push_back(HeuristicState(Heuristic::choose_pfund_before_partner, true));
1171 states.push_back(HeuristicState(Heuristic::jab_for_ace, true));
1172 states.push_back(HeuristicState(Heuristic::play_for_team, true));
1173 states.push_back(HeuristicState(Heuristic::play_color_for_partner, true));
1174 states.push_back(HeuristicState(Heuristic::try_color_for_partner, true));
1175 states.push_back(HeuristicState(Heuristic::retry_color, true));
1176 states.push_back(HeuristicState(Heuristic::jab_color_trick_with_dulle, true));
1177 states.push_back(HeuristicState(Heuristic::save_dulle, true));
1178 states.push_back(HeuristicState(Heuristic::partner_backhand_draw_trump, true));
1179 states.push_back(HeuristicState(Heuristic::create_fehl, true));
1180 states.push_back(HeuristicState(Heuristic::best_winning, true));
1181 states.push_back(HeuristicState(Heuristic::draw_trump, true));
1182 states.push_back(HeuristicState(Heuristic::play_to_jab_later, true));
1183 states.push_back(HeuristicState(Heuristic::low_high, true));
1184 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
1185 states.push_back(HeuristicState(Heuristic::serve_trump_trick, true));
1186 states.push_back(HeuristicState(Heuristic::play_for_partner_worries, true));
1187 states.push_back(HeuristicState(Heuristic::play_bad_color, true));
1188 states.push_back(HeuristicState(Heuristic::jab_color_over_fox, true));
1189 }
1190 } // undetermined marriage
1191 { // silent marriage
1192 vector<HeuristicState>& states
1193 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::marriage_silent,
1194 HeuristicsMap::PlayerTypeGroup::re)];
1195 states.push_back(HeuristicState(Heuristic::choose_best_card_in_last_tricks, true));
1196 states.push_back(HeuristicState(Heuristic::start_with_color_single_ace, true));
1197 states.push_back(HeuristicState(Heuristic::start_with_color_double_ace, true));
1198 states.push_back(HeuristicState(Heuristic::jab_with_color_ace, true));
1199 states.push_back(HeuristicState(Heuristic::choose_ten, true));
1200 states.push_back(HeuristicState(Heuristic::color_jab_for_ace, true));
1201 states.push_back(HeuristicState(Heuristic::best_winning, true));
1202 states.push_back(HeuristicState(Heuristic::color_low_high, true));
1203 states.push_back(HeuristicState(Heuristic::draw_trump, true));
1204 states.push_back(HeuristicState(Heuristic::play_to_jab_later, true));
1205 states.push_back(HeuristicState(Heuristic::play_highest_color_card_in_game, true));
1206 states.push_back(HeuristicState(Heuristic::jab_to_win, true));
1207
1208 this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::marriage_silent,
1209 HeuristicsMap::PlayerTypeGroup::contra)]
1210 = this->heuristic_states_[HeuristicsMap::Key(HeuristicsMap::GameTypeGroup::soli_color,
1211 HeuristicsMap::PlayerTypeGroup::contra)];
1212 } // silent marriage
1213 } // marriage
1214
1215 this->fill_up_heuristic_states();
1216 this->leave_update();
1217 }
1218
1219 /** fills up the heuristic states so that all real heuristics are included
1220 **/
1221 void
fill_up_heuristic_states()1222 Aiconfig::fill_up_heuristic_states()
1223 {
1224 this->enter_update();
1225 for (auto& heuristic_state : this->heuristic_states_) {
1226 vector<HeuristicState>& states = heuristic_state.second;
1227
1228 std::set<Heuristic> heuristics;
1229 for (auto const heuristic : aiconfig_heuristic_list) {
1230 if (is_real(heuristic))
1231 heuristics.insert(heuristic);
1232 }
1233
1234 for (auto const& s : states)
1235 heuristics.erase(s.heuristic);
1236
1237 for (auto const heuristic : heuristics)
1238 states.push_back(HeuristicState(heuristic, false));
1239
1240 }
1241
1242 this->leave_update();
1243 }
1244
1245 /** -> result
1246 **
1247 ** @param key the group key
1248 ** @param heuristic the heuristic type
1249 **
1250 ** @return the value of the heuristic in the given context
1251 **/
1252 bool
value(HeuristicsMap::Key const key,Heuristic const heuristic) const1253 Aiconfig::value(HeuristicsMap::Key const key,
1254 Heuristic const heuristic) const
1255 {
1256 vector<HeuristicState> const&
1257 states = this->heuristic_states(key);
1258
1259 for (auto state : states)
1260 if (state.heuristic == heuristic)
1261 return state.active;
1262
1263 return false;
1264 }
1265
1266 /** -> result
1267 **
1268 ** @param gametype_group the game type group
1269 ** @param playertype_group the player type group
1270 ** @param heuristic the heuristic type
1271 **
1272 ** @return the value of the heuristic 'type in the given context
1273 **/
1274 bool
value(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group,Heuristic const heuristic) const1275 Aiconfig::value(HeuristicsMap::GameTypeGroup const gametype_group,
1276 HeuristicsMap::PlayerTypeGroup const playertype_group,
1277 Heuristic const heuristic) const
1278 {
1279 return this->value(HeuristicsMap::Key(gametype_group, playertype_group),
1280 heuristic);
1281 }
1282
1283 /** -> result
1284 **
1285 ** @param type the bool type
1286 **
1287 ** @return the value of the aiconfig 'type'
1288 **/
1289 bool
value(Type::Bool const type) const1290 Aiconfig::value(Type::Bool const type) const
1291 {
1292 return this->bool_[type];
1293 }
1294
1295 /** -> result
1296 **
1297 ** @param type the unsigned type
1298 **
1299 ** @return the value of the aiconfig 'type'
1300 **/
1301 int
value(Type::Int const type) const1302 Aiconfig::value(Type::Int const type) const
1303 {
1304 return this->int_[type];
1305 }
1306
1307 /** -> result
1308 **
1309 ** @param type the card type
1310 **
1311 ** @return the value of the aiconfig 'type'
1312 **/
1313 Card
value(Type::Card const type) const1314 Aiconfig::value(Type::Card const type) const
1315 {
1316 return this->card_[type];
1317 }
1318
1319 /** -> result
1320 **
1321 ** @param type config type
1322 **
1323 ** @return minimal value for the type
1324 **/
1325 int
min(Type::Int const type) const1326 Aiconfig::min(Type::Int const type) const
1327 {
1328 switch(type) {
1329 case Type::remembertricks:
1330 case Type::lastfehlcreation:
1331 case Type::last_tricks_without_heuristics:
1332 case Type::first_trick_for_trump_points_optimization:
1333 return 0;
1334
1335 case Type::limit_throw_fehl:
1336 case Type::limitqueen:
1337 case Type::limitdulle:
1338 return 0;
1339
1340 case Type::announcelimit:
1341 case Type::announcelimitdec:
1342 case Type::announceconfig:
1343 case Type::announcelimitreply:
1344 case Type::announceconfigreply:
1345 return 0;
1346 } // switch(type)
1347
1348 return UINT_MAX;
1349 }
1350
1351 /** -> result
1352 **
1353 ** @param type config type
1354 **
1355 ** @return maximum value for the type
1356 **/
1357 int
max(Type::Int const type) const1358 Aiconfig::max(Type::Int const type) const
1359 {
1360 switch(type) {
1361 case Type::remembertricks:
1362 case Type::lastfehlcreation:
1363 case Type::last_tricks_without_heuristics:
1364 case Type::first_trick_for_trump_points_optimization:
1365 // when changing 'with nines' -> 'without nines' -> 'with nines'
1366 // it should keep '12'
1367 //return ::party->rule()(Rule::Type::number_of_tricks_in_game);
1368 return static_cast<int>(::party->rule()(Rule::Type::max_number_of_tricks_in_game));
1369
1370 case Type::limit_throw_fehl:
1371 case Type::limitqueen:
1372 case Type::limitdulle:
1373 return 33;
1374
1375 case Type::announcelimit:
1376 case Type::announcelimitdec:
1377 case Type::announceconfig:
1378 case Type::announcelimitreply:
1379 case Type::announceconfigreply:
1380 return 1000;
1381 } // switch(type)
1382
1383 return UINT_MAX;
1384 }
1385
1386
1387 /** -> result
1388 **
1389 ** @param type config type
1390 **
1391 ** @return the valid cards
1392 **/
1393 vector<Card> const&
valid_cards(Type::Card const type) const1394 Aiconfig::valid_cards(Type::Card const type) const
1395 {
1396 switch(type) {
1397 case Type::limitthrowing:
1398 case Type::limithigh:
1399
1400 case Type::trumplimit_normal:
1401 case Type::lowest_trumplimit_normal:
1402 case Type::trumplimit_solocolor:
1403 case Type::lowest_trumplimit_solocolor:
1404 {
1405 static vector<Card> valid_cards;
1406 if (valid_cards.empty()) {
1407 valid_cards.push_back(Card::club_queen);
1408 valid_cards.push_back(Card::spade_queen);
1409 valid_cards.push_back(Card::heart_queen);
1410 valid_cards.push_back(Card::diamond_queen);
1411 valid_cards.push_back(Card::club_jack);
1412 valid_cards.push_back(Card::spade_jack);
1413 valid_cards.push_back(Card::heart_jack);
1414 valid_cards.push_back(Card::diamond_jack);
1415 } // if (valid.cards.empty())
1416
1417 return valid_cards;
1418 }
1419 case Type::trumplimit_solojack:
1420 case Type::lowest_trumplimit_solojack:
1421 {
1422 static vector<Card> valid_cards;
1423 if (valid_cards.empty()) {
1424 valid_cards.push_back(Card::club_jack);
1425 valid_cards.push_back(Card::spade_jack);
1426 valid_cards.push_back(Card::heart_jack);
1427 valid_cards.push_back(Card::diamond_jack);
1428 } // if (valid.cards.empty())
1429
1430 return valid_cards;
1431 }
1432 case Type::trumplimit_soloqueen:
1433 case Type::lowest_trumplimit_soloqueen:
1434 {
1435 static vector<Card> valid_cards;
1436 if (valid_cards.empty()) {
1437 valid_cards.push_back(Card::club_queen);
1438 valid_cards.push_back(Card::spade_queen);
1439 valid_cards.push_back(Card::heart_queen);
1440 valid_cards.push_back(Card::diamond_queen);
1441 } // if (valid.cards.empty())
1442
1443 return valid_cards;
1444 }
1445 case Type::trumplimit_soloking:
1446 case Type::lowest_trumplimit_soloking:
1447 {
1448 static vector<Card> valid_cards;
1449 if (valid_cards.empty()) {
1450 valid_cards.push_back(Card::club_king);
1451 valid_cards.push_back(Card::spade_king);
1452 valid_cards.push_back(Card::heart_king);
1453 valid_cards.push_back(Card::diamond_king);
1454 } // if (valid.cards.empty())
1455
1456 return valid_cards;
1457 }
1458 case Type::trumplimit_solojackking:
1459 case Type::lowest_trumplimit_solojackking:
1460 {
1461 static vector<Card> valid_cards;
1462 if (valid_cards.empty()) {
1463 valid_cards.push_back(Card::club_king);
1464 valid_cards.push_back(Card::spade_king);
1465 valid_cards.push_back(Card::heart_king);
1466 valid_cards.push_back(Card::diamond_king);
1467 valid_cards.push_back(Card::club_jack);
1468 valid_cards.push_back(Card::spade_jack);
1469 valid_cards.push_back(Card::heart_jack);
1470 valid_cards.push_back(Card::diamond_jack);
1471 } // if (valid.cards.empty())
1472
1473 return valid_cards;
1474 }
1475 case Type::trumplimit_solojackqueen:
1476 case Type::lowest_trumplimit_solojackqueen:
1477 {
1478 static vector<Card> valid_cards;
1479 if (valid_cards.empty()) {
1480 valid_cards.push_back(Card::club_queen);
1481 valid_cards.push_back(Card::spade_queen);
1482 valid_cards.push_back(Card::heart_queen);
1483 valid_cards.push_back(Card::diamond_queen);
1484 valid_cards.push_back(Card::club_jack);
1485 valid_cards.push_back(Card::spade_jack);
1486 valid_cards.push_back(Card::heart_jack);
1487 valid_cards.push_back(Card::diamond_jack);
1488 } // if (valid.cards.empty())
1489
1490 return valid_cards;
1491 }
1492 case Type::trumplimit_soloqueenking:
1493 case Type::lowest_trumplimit_soloqueenking:
1494 {
1495 static vector<Card> valid_cards;
1496 if (valid_cards.empty()) {
1497 valid_cards.push_back(Card::club_king);
1498 valid_cards.push_back(Card::spade_king);
1499 valid_cards.push_back(Card::heart_king);
1500 valid_cards.push_back(Card::diamond_king);
1501 valid_cards.push_back(Card::club_queen);
1502 valid_cards.push_back(Card::spade_queen);
1503 valid_cards.push_back(Card::heart_queen);
1504 valid_cards.push_back(Card::diamond_queen);
1505 } // if (valid.cards.empty())
1506
1507 return valid_cards;
1508 }
1509 case Type::trumplimit_solokoehler:
1510 case Type::lowest_trumplimit_solokoehler:
1511 {
1512 static vector<Card> valid_cards;
1513 if (valid_cards.empty()) {
1514 valid_cards.push_back(Card::club_king);
1515 valid_cards.push_back(Card::spade_king);
1516 valid_cards.push_back(Card::heart_king);
1517 valid_cards.push_back(Card::diamond_king);
1518 valid_cards.push_back(Card::club_queen);
1519 valid_cards.push_back(Card::spade_queen);
1520 valid_cards.push_back(Card::heart_queen);
1521 valid_cards.push_back(Card::diamond_queen);
1522 valid_cards.push_back(Card::club_jack);
1523 valid_cards.push_back(Card::spade_jack);
1524 valid_cards.push_back(Card::heart_jack);
1525 valid_cards.push_back(Card::diamond_jack);
1526 } // if (valid.cards.empty())
1527
1528 return valid_cards;
1529 }
1530 case Type::trumplimit_meatless:
1531 case Type::lowest_trumplimit_meatless:
1532 {
1533 static vector<Card> valid_cards;
1534 if (valid_cards.empty()) {
1535 valid_cards.push_back(Card::diamond_ace);
1536 valid_cards.push_back(Card::diamond_ten);
1537 valid_cards.push_back(Card::diamond_king);
1538 valid_cards.push_back(Card::diamond_queen);
1539 valid_cards.push_back(Card::diamond_jack);
1540 valid_cards.push_back(Card::diamond_nine);
1541 } // if (valid.cards.empty())
1542
1543 return valid_cards;
1544 }
1545 } // switch(type)
1546
1547 {
1548 static vector<Card> valid_cards;
1549 return valid_cards;
1550 }
1551 }
1552
1553 /** sets 'type' to 'value'
1554 **
1555 ** @param type Aiconfigtype
1556 ** @param value new value
1557 **
1558 ** @return 'true', if the type is valid, otherwise 'false'
1559 **/
1560 bool
set(string const type,string const value)1561 Aiconfig::set(string const type, string const value)
1562 {
1563 #ifdef DEPRECATED
1564 // 0.7.6 replacing
1565 if (type == "fairplay hands") {
1566 this->set(Type::teams_known, !( (value == "true")
1567 || (value == "yes")
1568 || (value == "1") ) );
1569 return true;
1570 }
1571 if (type == "fairplay teams") {
1572 this->set(Type::hands_known, !( (value == "true")
1573 || (value == "yes")
1574 || (value == "1")) );
1575 return true;
1576 }
1577 #endif
1578 for (auto const t : Aiconfig::Type::bool_list) {
1579 if (type == to_string(t)) {
1580 this->set(t, value);
1581 return true;
1582 }
1583 }
1584 for (auto const t : Aiconfig::Type::int_list) {
1585 if (type == to_string(t)) {
1586 this->set(t, value);
1587 return true;
1588 }
1589 }
1590 for (auto const t : Aiconfig::Type::card_list) {
1591 if (type == to_string(t)) {
1592 this->set(t, value);
1593 return true;
1594 }
1595 }
1596
1597 return false;
1598 }
1599
1600 /** activates/deactivates the heuristic in the given context
1601 **
1602 ** @param gametype_group the game type group
1603 ** @param playertype_group the player type group
1604 ** @param heuristic the heuristic type
1605 ** @param value new value
1606 **/
1607 void
set(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group,Heuristic const heuristic,string const value)1608 Aiconfig::set(HeuristicsMap::GameTypeGroup const gametype_group,
1609 HeuristicsMap::PlayerTypeGroup const playertype_group,
1610 Heuristic const heuristic,
1611 string const value)
1612 {
1613 if ( (value != "true")
1614 && (value != "false")
1615 && (value != "yes")
1616 && (value != "no")
1617 && (value != "0")
1618 && (value != "1")) {
1619 cerr << "Aiconfig::set(GameTypeGroup, PlayerTypeGroup, Heuristic, value)\n"
1620 << " illegal value '" << value << "' for '" << heuristic << "', "
1621 << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0')."
1622 << '\n'
1623 << " Taking 'false'."
1624 << endl;
1625 }
1626 this->set(gametype_group, playertype_group, heuristic,
1627 ( (value == "true")
1628 || (value == "yes")
1629 || (value == "1")) );
1630 }
1631
1632 /** sets 'type' to 'value'
1633 **
1634 ** @param type Aiconfigtype
1635 ** @param value new value
1636 **/
1637 void
set(Type::Bool const type,string const value)1638 Aiconfig::set(Type::Bool const type, string const value)
1639 {
1640 if ( (value != "true")
1641 && (value != "false")
1642 && (value != "yes")
1643 && (value != "no")
1644 && (value != "0")
1645 && (value != "1")) {
1646 cerr << "Aiconfig::set(Bool, value)\n"
1647 << " illegal value '" << value << "' for '" << type << "', "
1648 << "must be a boolean ('true' or 'false' or 'yes' or 'no' or '1' or '0')."
1649 << '\n'
1650 << " Taking 'false'."
1651 << endl;
1652 }
1653 this->set(type, ( ( (value == "false")
1654 || (value == "no")
1655 || (value == "0") )
1656 ? false
1657 : true) );
1658 }
1659
1660 /** sets 'type' to 'value'
1661 **
1662 ** @param type Aiconfigtype
1663 ** @param value new value
1664 **/
1665 void
set(Type::Int const type,string const value)1666 Aiconfig::set(Type::Int const type, string const value)
1667 {
1668 char* end_ptr;
1669 unsigned number = strtoul(value.c_str(), &end_ptr, 0);
1670 if (*end_ptr != '\0') {
1671 cerr << "Aiconfig::set(Int, value)\n"
1672 << "illegal value '" << value << "' for '" << type << "', "
1673 << "must be a digit.\n"
1674 << " Taking " << number << "."
1675 << endl;
1676 }
1677
1678 this->set(type, number);
1679 }
1680
1681 /** sets 'type' to 'value'
1682 **
1683 ** @param type Aiconfigtype
1684 ** @param value new value
1685 **/
1686 void
set(Type::Card const type,string const value)1687 Aiconfig::set(Type::Card const type, string const value)
1688 {
1689 this->set(type, Card(value));
1690 }
1691
1692
1693 /** activates/deactivates the heuristic in the given context
1694 **
1695 ** @param key the context key
1696 ** @param heuristic the heuristic type
1697 ** @param value new value
1698 **/
1699 void
set(HeuristicsMap::Key const key,Heuristic const heuristic,bool const value)1700 Aiconfig::set(HeuristicsMap::Key const key,
1701 Heuristic const heuristic,
1702 bool const value)
1703 {
1704 this->set(key.gametype_group, key.playertype_group, heuristic, value);
1705 }
1706
1707 /** activates/deactivates the heuristic in the given context
1708 **
1709 ** @param gametype_group the game type group
1710 ** @param playertype_group the player type group
1711 ** @param heuristic the heuristic type
1712 ** @param value new value
1713 **/
1714 void
set(HeuristicsMap::GameTypeGroup const gametype_group,HeuristicsMap::PlayerTypeGroup const playertype_group,Heuristic const heuristic,bool const value)1715 Aiconfig::set(HeuristicsMap::GameTypeGroup const gametype_group,
1716 HeuristicsMap::PlayerTypeGroup const playertype_group,
1717 Heuristic const heuristic,
1718 bool const value)
1719 {
1720 this->enter_update();
1721 vector<HeuristicState>&
1722 states = this->heuristic_states(gametype_group, playertype_group);
1723
1724 for (auto & state : states)
1725 if (state.heuristic == heuristic) {
1726 state.active = value;
1727 return;
1728 }
1729 states.push_back(HeuristicState(heuristic, value));
1730
1731 this->leave_update();
1732 }
1733
1734 /** sets the heuristics map to the default one
1735 **
1736 ** @param key the context key
1737 **/
1738 void
set_to_default(HeuristicsMap::Key const key)1739 Aiconfig::set_to_default(HeuristicsMap::Key const key)
1740 {
1741 this->enter_update();
1742 this->heuristic_states(key)
1743 = this->heuristic_states(HeuristicsMap::Key());
1744 this->leave_update();
1745 }
1746
1747 /** moves the heuristic to the given position
1748 ** all heuristics below are moved one position further
1749 **
1750 ** @param key the key of the heuristic group
1751 ** @param heuristic the heuristic type
1752 ** @param pos new position
1753 **/
1754 void
move(HeuristicsMap::Key const key,Heuristic const heuristic,unsigned const pos)1755 Aiconfig::move(HeuristicsMap::Key const key,
1756 Heuristic const heuristic,
1757 unsigned const pos)
1758 {
1759 vector<HeuristicState>&
1760 states = this->heuristic_states(key);
1761
1762 if (states[pos].heuristic == heuristic)
1763 return ;
1764
1765 if (pos > states.size())
1766 return ;
1767
1768 this->enter_update();
1769
1770 vector<HeuristicState>::iterator s;
1771 for (s = states.begin();
1772 s != states.end();
1773 ++s)
1774 if (s->heuristic == heuristic)
1775 break;
1776
1777 if (s == states.end()) {
1778 states.insert(states.begin() + pos, HeuristicState(heuristic, false));
1779 } else { // if !(s == states.end())
1780 HeuristicState const state = *s;
1781 states.erase(s);
1782 states.insert(states.begin() + pos, state);
1783 } // if !(s == states.end())
1784
1785 this->leave_update();
1786 }
1787
1788 /** sets the aiconfig 'type' to the value 'value'
1789 **
1790 ** @param type heuristic type
1791 ** @param value new value
1792 **/
1793 void
set(Type::Bool const type,bool const value)1794 Aiconfig::set(Type::Bool const type, bool const value)
1795 {
1796 this->enter_update();
1797 this->bool_[type] = value;
1798 this->leave_update();
1799 }
1800
1801 /** sets the aiconfig 'type' to the value 'value'
1802 **
1803 ** @param type heuristic type
1804 ** @param value new value
1805 **/
1806 void
set(Type::Int const type,int const value)1807 Aiconfig::set(Type::Int const type, int const value)
1808 {
1809 this->enter_update();
1810 this->int_[type] = value;
1811 this->leave_update();
1812 }
1813
1814 /** sets the aiconfig 'type' to the value 'value'
1815 **
1816 ** @param type heuristic type
1817 ** @param value new value
1818 **/
1819 void
set(Type::Card const type,Card const value)1820 Aiconfig::set(Type::Card const type, Card const value)
1821 {
1822 this->enter_update();
1823 this->card_[type] = value;
1824 this->leave_update();
1825 }
1826
1827 /** @param ostr output stream
1828 **
1829 ** write only different values into the output stream
1830 **/
1831 void
write(ostream & ostr) const1832 Aiconfig::write(ostream& ostr) const
1833 {
1834 if (this->difficulty() != Difficulty::custom) {
1835 ostr << "difficulty = " << to_string(this->difficulty()) << '\n';
1836 return ;
1837 } // if (this->difficulty() != custom)
1838
1839 auto const difficulty = this->difficulty_with_min_differences();
1840 ostr << "difficulty = " << to_string(difficulty) << '\n';
1841 this->write_differences(ostr, difficulty);
1842 }
1843
1844 /** @return difficulty with the minimum differcences
1845 **/
1846 Aiconfig::Difficulty
difficulty_with_min_differences() const1847 Aiconfig::difficulty_with_min_differences() const
1848 {
1849 Difficulty difficulty_min = Difficulty::custom;
1850 unsigned differences_min = UINT_MAX;
1851 for (auto const difficulty : aiconfig_difficulty_list) {
1852 if (difficulty == Difficulty::custom)
1853 continue;
1854 auto const differences = this->count_differences(difficulty);
1855 if (differences < differences_min) {
1856 difficulty_min = difficulty;
1857 differences_min = differences;
1858 }
1859 }
1860 return difficulty_min;
1861 }
1862
1863 /** @return number of differences to 'difficulty'
1864 **/
1865 unsigned
count_differences(Difficulty difficulty) const1866 Aiconfig::count_differences(Difficulty difficulty) const
1867 {
1868 Aiconfig const& preset_aiconfig = Aiconfig::preset(difficulty);
1869 // the number of differences
1870 unsigned differences = 0;
1871
1872 { // check the values
1873 for (auto const type : Aiconfig::Type::bool_list) {
1874 if (this->value(type) != preset_aiconfig.value(type)) {
1875 differences += 1;
1876 }
1877 }
1878 for (auto const type : Aiconfig::Type::int_list) {
1879 if (this->value(type) != preset_aiconfig.value(type)) {
1880 differences += 1;
1881 }
1882 }
1883 for (auto const type : Aiconfig::Type::card_list) {
1884 if (this->value(type) != preset_aiconfig.value(type)) {
1885 differences += 1;
1886 }
1887 }
1888 } // check the values
1889 { // check the ai types
1890 for (unsigned t = 0;
1891 t < ::party->rule()(Rule::Type::max_number_of_tricks_in_game);
1892 t++) {
1893 if (this->aitype(t) != preset_aiconfig.aitype(t)) {
1894 differences += 1;
1895 }
1896 if (this->rating(t) != preset_aiconfig.rating(t)) {
1897 differences += 1;
1898 }
1899 if (this->future_limit(t) != preset_aiconfig.future_limit(t)) {
1900 differences += 1;
1901 }
1902 }
1903 } // check the ai types
1904 { // check the heuristics
1905 for (auto const key : Aiconfig::keys()) {
1906 if (this->heuristic_states(key)
1907 != preset_aiconfig.heuristic_states(key)) {
1908 differences += 5;
1909 }
1910 }
1911 } // check the heuristics
1912 return differences;
1913 }
1914
1915 /** write only differcences values into the output stream
1916 **
1917 ** @param ostr output stream
1918 ** @param difficulty difficulty to compare with
1919 **/
1920 void
write_differences(ostream & ostr,Aiconfig::Difficulty const difficulty) const1921 Aiconfig::write_differences(ostream& ostr,
1922 Aiconfig::Difficulty const difficulty) const
1923 {
1924 std::ios_base::fmtflags const flags = ostr.flags();
1925 ostr << std::boolalpha;
1926
1927 Aiconfig const& preset_aiconfig = Aiconfig::preset(difficulty);
1928
1929 { // check the values
1930 for (auto const type : Aiconfig::Type::bool_list) {
1931 if (this->value(type) != preset_aiconfig.value(type)) {
1932 ostr << " "
1933 << type << " = "
1934 << (this->value(type) ? "true" : "false")
1935 << '\n';
1936 }
1937 }
1938 for (auto const type : Aiconfig::Type::int_list) {
1939 if (this->value(type) != preset_aiconfig.value(type)) {
1940 ostr << " "
1941 << type << " = "
1942 << this->value(type)
1943 << '\n';
1944 }
1945 }
1946 for (auto const type : Aiconfig::Type::card_list) {
1947 if (this->value(type) != preset_aiconfig.value(type)) {
1948 ostr << " "
1949 << type << " = "
1950 << this->value(type)
1951 << '\n';
1952 }
1953 }
1954 } // check the values
1955 { // check the ai types
1956 for (unsigned t = 0;
1957 t < ::party->rule()(Rule::Type::max_number_of_tricks_in_game);
1958 t++) {
1959 if (this->aitype(t) != preset_aiconfig.aitype(t)) {
1960 ostr << " "
1961 << "type = " << setw(2) << t << ": "
1962 << this->aitype(t) << '\n';
1963 }
1964 }
1965 for (unsigned t = 0;
1966 t < ::party->rule()(Rule::Type::max_number_of_tricks_in_game);
1967 t++) {
1968 if (this->rating(t) != preset_aiconfig.rating(t)) {
1969 ostr << " "
1970 << "rating = " << setw(2) << t << ": "
1971 << this->rating(t) << '\n';
1972 }
1973 }
1974 for (unsigned t = 0;
1975 t < ::party->rule()(Rule::Type::max_number_of_tricks_in_game);
1976 t++) {
1977 if (this->future_limit(t) != preset_aiconfig.future_limit(t)) {
1978 ostr
1979 << " "
1980 << "future limit = " << setw(2) << t << ": "
1981 << this->future_limit(t) << '\n';
1982 } // if (value differs)
1983 } // for (t \in number of tricks)
1984 } // check the ai types
1985 { // check the heuristics
1986 auto const& keys = Aiconfig::keys();
1987 bool first_difference = true;
1988
1989 for (auto const key : keys) {
1990 if (this->heuristic_states(key)
1991 != preset_aiconfig.heuristic_states(key)) {
1992 { // write the differences
1993 if (first_difference) {
1994 ostr << "heuristics" << '\n'
1995 << "{\n";
1996 first_difference = false;
1997 } // if (first_difference)
1998
1999 ostr << " "
2000 << key.gametype_group << " - "
2001 << key.playertype_group << '\n'
2002 << " {\n";
2003 for (auto const h : this->heuristic_states(key)) {
2004 ostr
2005 << " "
2006 << h.heuristic << " = "
2007 << (h.active ? "true" : "false") << '\n';
2008 }
2009 ostr << " }\n";
2010 } // write the differences
2011 } // if (heuristic states differ)
2012 } // for (key : keys)
2013
2014 if (!first_difference) {
2015 // there was a difference
2016 ostr << "}\n";
2017 } // if (!first_difference)
2018
2019 } // check the heuristics
2020
2021 ostr.flags(flags);
2022 }
2023
2024 /** write all values into the output streams
2025 **
2026 ** @param ostr output stream
2027 **/
2028 void
write_full(ostream & ostr) const2029 Aiconfig::write_full(ostream& ostr) const
2030 {
2031 ostr << "# difficulty = " << to_string(this->difficulty()) << '\n';
2032 std::ios_base::fmtflags const flags = ostr.flags();
2033 ostr << std::boolalpha;
2034
2035 for (unsigned i = 0; i < this->aitype_.size(); ++i)
2036 ostr << "type = " << setw(2) << i << ": "
2037 << this->aitype(i) << '\n';
2038 for (unsigned i = 0; i < this->aitype_.size(); ++i)
2039 ostr << "future limit = " << setw(2) << i << ": "
2040 << this->future_limit(i) << '\n';
2041 for (unsigned i = 0; i < this->aitype_.size(); ++i)
2042 ostr << "rating = " << setw(2) << i << ": "
2043 << this->rating(i) << '\n';
2044 ostr << '\n';
2045 ostr << '\n';
2046
2047 ostr << "# bool\n";
2048 for (auto const type : Aiconfig::Type::bool_list) {
2049 ostr << type << " = " << (this->value(type) ? "true" : "false") << '\n';
2050 }
2051 ostr << '\n';
2052
2053 ostr << "# unsigned\n";
2054 for (auto const type : Aiconfig::Type::int_list) {
2055 ostr << type << " = " << this->value(type) << '\n';
2056 }
2057 ostr << '\n';
2058
2059 ostr << "# card\n";
2060 for (auto const type : Aiconfig::Type::card_list) {
2061 ostr << type << " = " << this->value(type) << '\n';
2062 }
2063
2064 ostr << '\n';
2065 ostr << "#heuristics" << '\n';
2066 ostr << "heuristics" << '\n'
2067 << "{\n";
2068 for (const auto & heuristic_state : this->heuristic_states_) {
2069 ostr << " "
2070 << heuristic_state.first.gametype_group << " - " << heuristic_state.first.playertype_group << '\n'
2071 << " {\n";
2072 for (auto const& h : heuristic_state.second)
2073 ostr << " " << h.heuristic << " = " << (h.active ? "true" : "false") << '\n';
2074 ostr << " }\n";
2075 } // for (s \in this->heuristic_states_)
2076 ostr << "}\n";
2077
2078 ostr.flags(flags);
2079 }
2080
2081 /** loads the infos from the file
2082 **
2083 ** @param filename file to load the aiconfig from
2084 **
2085 ** @return whether the loading was successful
2086 **/
2087 bool
load(string const filename)2088 Aiconfig::load(string const filename)
2089 {
2090 {
2091 ifstream istr(filename.c_str());
2092 if (istr.good()) {
2093 return this->read(istr);
2094 }
2095 }
2096 {
2097 ifstream istr((::preferences(Preferences::Type::private_data_directory)
2098 + "/" + ::preferences(Preferences::Type::ai_directory)
2099 + "/" + filename).c_str());
2100 if (istr.good()) {
2101 return this->read(istr);
2102 }
2103 }
2104 {
2105 ifstream istr((::preferences(Preferences::Type::public_data_directory)
2106 + "/" + ::preferences(Preferences::Type::ai_directory)
2107 + "/" + filename).c_str());
2108 if (istr.good()) {
2109 return this->read(istr);
2110 }
2111 }
2112
2113 return false;
2114 }
2115
2116 /** reads the infos from the stream
2117 **
2118 ** @param istr stream with the infos
2119 **
2120 ** @return whether the reading was successful
2121 **/
2122 bool
read(istream & istr)2123 Aiconfig::read(istream& istr)
2124 {
2125 this->enter_update();
2126
2127 unsigned depth = 0;
2128
2129 this->reset_to_hardcoded();
2130
2131 // read the configuration
2132 while (istr.good()) {
2133 Config config;
2134 istr >> config;
2135 if (!istr.good())
2136 break;
2137
2138 // finished with the config file
2139 if ((config.name == "") && (config.value == ""))
2140 break;
2141
2142 if (config.separator) {
2143 // a setting
2144 if (config.name == "difficulty") {
2145 try {
2146 this->set_to_difficulty(aiconfig_difficulty_from_string(config.value));
2147 } catch (std::ios_base::failure const& error) {
2148 cerr << "Aiconfig::read()\n"
2149 << error.what()
2150 << endl;
2151 }
2152 } else if (config.name == "type") {
2153 try {
2154 stringstream istr(config.value);
2155
2156 // tricknumber
2157 unsigned trickno;
2158 istr >> trickno;
2159 if (!istr.good()) {
2160 throw config.value;
2161 }
2162
2163 // separator
2164 if (istr.peek() != ':')
2165 throw config.value;
2166 istr.get();
2167
2168 while (std::isspace(istr.peek())
2169 && istr.good())
2170 istr.get();
2171
2172 if (!istr.good())
2173 throw config.value;
2174
2175 // aitype
2176 string aitype;
2177 std::getline(istr, aitype);
2178 this->set_aitype(trickno, aitype_from_string(aitype));
2179 } catch (string const& value) {
2180 cerr << "aiconfig: "
2181 << "unknown aitype '" << value << "'."
2182 << endl;
2183 } // try
2184 } else if (config.name == "future limit") {
2185 try {
2186 stringstream istr(config.value);
2187
2188 // tricknumber
2189 unsigned trickno;
2190 istr >> trickno;
2191 if (!istr.good()) {
2192 throw config.value;
2193 }
2194
2195 // separator
2196 if (istr.peek() != ':') {
2197 throw config.value;
2198 }
2199 istr.get();
2200
2201 while (std::isspace(istr.peek())
2202 && istr.good())
2203 istr.get();
2204
2205 if (!istr.good()) {
2206 throw config.value;
2207 }
2208
2209 // future limit
2210 unsigned future_limit;
2211 istr >> future_limit;
2212 if (istr.fail()) {
2213 throw config.value;
2214 }
2215
2216 this->set_future_limit(trickno, future_limit);
2217 } // try
2218 catch (string const& value) {
2219 cerr << "aiconfig: "
2220 << "illegal future limit '" << value << "'."
2221 << endl;
2222 }
2223 } else if (config.name == "rating") {
2224 try {
2225 stringstream istr(config.value);
2226
2227 // tricknumber
2228 unsigned trickno;
2229 istr >> trickno;
2230 if (!istr.good()) {
2231 throw config.value;
2232 }
2233
2234 // separator
2235 if (istr.peek() != ':') {
2236 throw config.value;
2237 }
2238 istr.get();
2239
2240 while (std::isspace(istr.peek())
2241 && istr.good())
2242 istr.get();
2243
2244 if (!istr.good()) {
2245 throw config.value;
2246 }
2247
2248 // rating
2249 string rating;
2250 std::getline(istr, rating);
2251
2252 {
2253 auto const r = Rating::type_from_string(rating);
2254 this->set_rating(trickno, r);
2255 }
2256
2257 } catch (string const& value) {
2258 cerr << "rating type: "
2259 << "unknown rating type '" << value << "'."
2260 << endl;
2261 }
2262 } else {
2263 if (!this->set(config.name, config.value)) {
2264 cerr << "aiconfig: "
2265 << "unknown config '" << config.name << "'."
2266 << endl;
2267 }
2268 } // if (config.name == "type")
2269 } else { // if (config.separator)
2270 // a setting
2271 // if the value is in parentencies, remove both
2272 if(config.name == "!end") {
2273 // ignore the rest of the file
2274 break;
2275 } else if(config.name == "!stdout") {
2276 // output of the data to 'stdout'
2277 cout << config.value << endl;
2278 } else if(config.name == "!stderr") {
2279 // output of the data to 'stderr'
2280 cerr << config.value << endl;
2281 } else if(config.name == "{") {
2282 depth += 1;
2283 } else if(config.name == "}") {
2284 if (depth == 0) {
2285 cerr << "Aiconfig: found a '}' without a '{' before.\n"
2286 << "Finish reading the the file."
2287 << endl;
2288 break;
2289 } // if (depth == 0)
2290 depth -= 1;
2291 if (depth == 0)
2292 break;
2293 } else if(config.name == "heuristics") {
2294 this->read_heuristics(istr);
2295 } else if(config.name == "") {
2296 cerr << "Aiconfig: "
2297 << "Ignoring line \'" << config.value << "\'.\n";
2298 } else {
2299 cerr << "Aiconfig: "
2300 << "type '" << config.name << "' unknown.\n"
2301 << "Ignoring it.\n";
2302 } // if (config.name == .)
2303 } // config.separator
2304 } // while (istr.good())
2305
2306 this->leave_update();
2307 return istr.good();
2308 }
2309
2310 /** reads the heuristics
2311 **
2312 ** @param istr input stream
2313 **
2314 ** @return whether the reading was successful
2315 **/
2316 bool
read_heuristics(istream & istr)2317 Aiconfig::read_heuristics(istream& istr)
2318 {
2319 this->enter_update();
2320 unsigned depth = 0;
2321 string line;
2322 while (istr.good()) {
2323 std::getline(istr, line);
2324 if (!istr.good())
2325 break;
2326
2327 while ( !line.empty()
2328 && isspace(*line.begin()))
2329 line.erase(line.begin());
2330
2331 if (*(line.end() - 1) == '\r')
2332 line.erase(line.end() - 1);
2333
2334 if (line.empty()) { // empty line
2335 } else if (line[0] == '#') { // comment
2336 } else if (line == "{") { // block open
2337 depth += 1;
2338 } else if (line == "}") { // block close
2339 if (depth == 0) {
2340 cerr << "Aiconfig: found a '}' without a '{' before.\n"
2341 << "Finish reading the the file."
2342 << endl;
2343 break;
2344 } // if (depth == 0)
2345 depth -= 1;
2346 if (depth == 0)
2347 break;
2348 } else { // gametype group - playertype group
2349 string::size_type const pos = line.find('-');
2350 if (pos == string::npos) {
2351 cerr << "unknown line '" << line << "'\n"
2352 << "ignoring it" << endl;
2353 continue;
2354 } // if (pos == string::npos)
2355
2356 string gametype_group_string(line, 0, pos);
2357 while ( !gametype_group_string.empty()
2358 && isspace(*gametype_group_string.rbegin()))
2359 gametype_group_string.erase(gametype_group_string.size() - 1);
2360 string playertype_group_string(line, pos + 1, string::npos);
2361 while ( !playertype_group_string.empty()
2362 && isspace(*playertype_group_string.begin()))
2363 playertype_group_string.erase(playertype_group_string.begin());
2364
2365 HeuristicsMap::GameTypeGroup const gametype_group
2366 = HeuristicsMap::GameTypeGroup_from_name(gametype_group_string);
2367 HeuristicsMap::PlayerTypeGroup const playertype_group
2368 = HeuristicsMap::PlayerTypeGroup_from_name(playertype_group_string);
2369
2370 unsigned depth2 = 0;
2371 vector<HeuristicState>& states
2372 = this->heuristic_states_[HeuristicsMap::Key(gametype_group,
2373 playertype_group)];
2374 states.clear();
2375 while (istr.good()) {
2376 Config config;
2377 istr >> config;
2378 if (!istr.good())
2379 break;
2380
2381 if (config.separator) {
2382 Heuristic const heuristic = Heuristic_from_name(config.name);
2383 if (is_real(heuristic)) {
2384 bool const active = ( (config.value == "true")
2385 || (config.value == "yes")
2386 || (config.value == "1"));
2387 states.push_back(HeuristicState(heuristic, active));
2388 } // if (is_real(heuristic))
2389 } else { // if (config.separator)
2390 if(config.name == "{") {
2391 depth2 += 1;
2392 } else if(config.name == "}") {
2393 if (depth2 == 0) {
2394 cerr << "Aiconfig: found a '}' without a '{' before.\n"
2395 << "Finish reading the the file."
2396 << endl;
2397 break;
2398 } // if (depth2 == 0)
2399 depth2 -= 1;
2400 if (depth2 == 0)
2401 break;
2402 } else if(config.name == "") {
2403 cerr << "Aiconfig: "
2404 << "Ignoring line \'" << config.value << "\'.\n";
2405 } else {
2406 cerr << "Aiconfig: "
2407 << "type '" << config.name << "' unknown.\n"
2408 << "Ignoring it.\n";
2409 } // if (config.name == .)
2410 } // config.separator
2411 } // while (istr.good())
2412 } // if (line == ...)
2413 } // while (istr.good())
2414
2415 this->fill_up_heuristic_states();
2416
2417 this->leave_update();
2418 return istr.good();
2419 }
2420
2421 /** save the infos in the file
2422 **
2423 ** @param filename file to save the aiconfig
2424 **
2425 ** @return whether the saving was successful
2426 **/
2427 bool
save(string const filename) const2428 Aiconfig::save(string const filename) const
2429 {
2430 string filename_tmp = filename + ".tmp";
2431 ofstream ostr(filename_tmp.c_str());
2432 if (!ostr.good()) {
2433 ::ui->information(_("Error::Aiconfig::save: Error opening temporary file %s. Aborting saving.", filename_tmp), InformationType::problem);
2434 return false;
2435 }
2436
2437 ostr << "# FreeDoko ai configuration (" << *::version << ")\n"
2438 << '\n';
2439 this->write(ostr);
2440
2441 if (!ostr.good()) {
2442 ::ui->information(_("Error::Aiconfig::save: Error saving in temporary file %s. Keeping temporary file (for bug tracking).", filename_tmp), InformationType::problem);
2443 return false;
2444 }
2445 ostr.close();
2446
2447 #ifdef WINDOWS
2448 unlink(filename.c_str());
2449 #endif
2450 if (rename(filename_tmp.c_str(), filename.c_str())) {
2451 ::ui->information(_("Error::Aiconfig::save: Could not rename temporary file %s to requested file %s. Keeping temporary file.", filename_tmp, filename), InformationType::problem);
2452 return false;
2453 }
2454
2455 return true;
2456 }
2457
2458 /** comparison of two aiconfigs
2459 **
2460 ** @param lhs first aiconfig
2461 ** @param rhs second aiconfig
2462 **
2463 ** @return whether the two aiconfigs are equal
2464 **/
2465 bool
operator ==(Aiconfig const & lhs,Aiconfig const & rhs)2466 operator==(Aiconfig const& lhs, Aiconfig const& rhs)
2467 {
2468 return lhs.equal(rhs);
2469 }
2470
2471 /** comparison of two aiconfigs
2472 **
2473 ** @param lhs first aiconfig
2474 ** @param rhs second aiconfig
2475 **
2476 ** @return whether the two aiconfigs are different
2477 **/
2478 bool
operator !=(Aiconfig const & lhs,Aiconfig const & rhs)2479 operator!=(Aiconfig const& lhs, Aiconfig const& rhs)
2480 {
2481 return !(lhs == rhs);
2482 }
2483
2484 /** comparison of two heuristic states
2485 **
2486 ** @param heuristic_state_a first heuristic state
2487 ** @param heuristic_state_b second heuristic state
2488 **
2489 ** @return whether the two heuristic states are equal
2490 **/
2491 bool
operator ==(Aiconfig::HeuristicState const lhs,Aiconfig::HeuristicState const rhs)2492 operator==(Aiconfig::HeuristicState const lhs,
2493 Aiconfig::HeuristicState const rhs)
2494 {
2495 return ( (lhs.heuristic == rhs.heuristic)
2496 && (lhs.active == rhs.active) );
2497 }
2498
2499 /** writes the aiconfig into the output stream
2500 **
2501 ** @param ostr stream to write in
2502 ** @param aiconfig aiconfig to write
2503 **
2504 ** @return output stream
2505 **/
2506 ostream&
operator <<(ostream & ostr,Aiconfig const & aiconfig)2507 operator<<(ostream& ostr, Aiconfig const& aiconfig)
2508 {
2509 aiconfig.write(ostr);
2510
2511 return ostr;
2512 }
2513