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