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 #ifdef USE_UI_GTKMM
31
32 #include "players_db.h"
33 #include "ui.h"
34 #include "cards.h"
35
36 #include "../../party/party.h"
37 #include "../../player/player.h"
38 #include "../../player/playersDb.h"
39 #include "../../player/ai/aiDb.h"
40
41 #include "../../utils/string.h"
42
43
44 #include <gtkmm/treeview.h>
45 #include <gtkmm/radiobutton.h>
46 #include <gtkmm/scrolledwindow.h>
47 #include <gdk/gdkkeysyms.h>
48 namespace UI_GTKMM_NS {
49
50 constexpr PlayersDB::Statistic PlayersDB::statistic_all[];
51
52 /** -> result
53 **
54 ** @param statistic statistic
55 **
56 ** @return string of 'statistic'
57 **/
58 string
to_string(Statistic const statistic)59 PlayersDB::to_string(Statistic const statistic)
60 {
61 switch(statistic) {
62 case Statistic::total:
63 (void)_("Statistic::total");
64 return "total";
65 case Statistic::won:
66 (void)_("Statistic::won");
67 return "won";
68 case Statistic::lost:
69 (void)_("Statistic::lost");
70 return "lost";
71 case Statistic::percent_won:
72 (void)_("Statistic::percent won");
73 return "percent won";
74 } // switch(statistic)
75
76 return "";
77 } // static string PlayersDB::to_string(Statistic statistic)
78
79 /** translation
80 **
81 ** @param statistic statistic
82 **
83 ** @return translation
84 **/
85 string
gettext(Statistic const statistic)86 PlayersDB::gettext(Statistic const statistic)
87 {
88 return ::gettext("Statistic::" + to_string(statistic));
89 }
90
91 /** Constructor for the model
92 **
93 ** @param playerno number of players in the party
94 **/
PlayersDBModel(unsigned const playerno)95 PlayersDB::PlayersDBModel::PlayersDBModel(unsigned const playerno) :
96 Gtk::TreeModel::ColumnRecord(),
97 type(),
98 statistic(playerno)
99 {
100 this->add(this->type);
101 for (unsigned p = 0; p < playerno; p++)
102 this->add(this->statistic[p]);
103 } // PlayersDB::PlayersDBModel::PlayersDBModel(unsigned playerno)
104
105 /** constructor
106 **
107 ** @param parent the parent object
108 **/
PlayersDB(Base * const parent)109 PlayersDB::PlayersDB(Base* const parent) :
110 Base(parent),
111 StickyDialog("FreeDoko – " + _("Window::players database"), false)
112 {
113 this->ui->add_window(*this);
114
115 this->set_default_size(0, 3 * this->ui->cards->height());
116 this->signal_realize().connect(sigc::mem_fun(*this, &PlayersDB::init));
117
118 #ifndef GLIBMM_DEFAULT_SIGNAL_HANDLERS_ENABLED
119 this->signal_key_press_event().connect(sigc::mem_fun(*this, &PlayersDB::on_key_press_event));
120 #endif
121 } // PlayersDB::PlayersDB(Base* parent)
122
123 /** destructor
124 **/
125 PlayersDB::~PlayersDB() = default;
126
127 /** create all subelements
128 **/
129 void
init()130 PlayersDB::init()
131 {
132 this->set_icon(this->ui->icon);
133
134 { // hbox
135 auto hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 1 EM));
136 { // statistic type
137 auto vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL, 1 EX / 2));
138
139 Gtk::RadioButton::Group statistic_group;
140 for (auto statistic : statistic_all) {
141 auto const radio_button
142 = Gtk::manage(new Gtk::RadioButton(statistic_group,
143 gettext(statistic)));
144 vbox->add(*radio_button);
145 radio_button->signal_clicked().connect(sigc::bind<Statistic const>(sigc::mem_fun(*this, &PlayersDB::set_statistic), statistic));
146 if (statistic == Statistic::percent_won)
147 radio_button->set_active(true);
148
149 } // for (statistic)
150 vbox->set_valign(Gtk::ALIGN_START);
151 hbox->add(*vbox);
152 } // statistic type
153
154 { // the treeview
155
156 // the points table
157 this->players_db_model = std::make_unique<PlayersDBModel>(this->ui->party().players().size());
158
159 this->players_db_list
160 = Gtk::TreeStore::create(*this->players_db_model);
161 this->players_db_treeview
162 = Gtk::manage(new Gtk::TreeView(this->players_db_list));
163
164 this->players_db_treeview->append_column(_("players database data type"),
165 this->players_db_model->type);
166 this->players_db_treeview->get_column_cell_renderer(0)->set_property("xalign", 1);
167 for (unsigned p = 0; p < this->ui->party().players().size(); p++) {
168 this->players_db_treeview->append_column(this->ui->party().players()[p].name(),
169 this->players_db_model->statistic[p]);
170 this->players_db_treeview->get_column_cell_renderer(p + 1)->set_property("xalign", 0.5);
171 } // for (p < this->ui->party().players().size())
172
173 { // the scrolled window
174 auto scrolled_window = Gtk::manage(new Gtk::ScrolledWindow);
175 scrolled_window->set_policy(Gtk::POLICY_NEVER,
176 Gtk::POLICY_AUTOMATIC);
177 scrolled_window->add(*(this->players_db_treeview));
178
179 hbox->pack_start(*scrolled_window);
180 } // the scrolled window
181 } // the treeview
182 this->get_content_area()->pack_start(*hbox);
183 } // hbox
184
185 { // action area
186 { // clear button
187 auto clear_button = Gtk::manage(new Gtk::Button(_("Button::clear database")));
188 clear_button->set_image_from_icon_name("edit-clear-all");
189 clear_button->set_always_show_image();
190 this->add_action_widget(*clear_button, Gtk::RESPONSE_NONE);
191 clear_button->signal_clicked().connect(sigc::mem_fun(*this, &PlayersDB::clear_db));
192 } // clear button
193
194 add_close_button(*this);
195 } // action area
196
197 this->show_all_children();
198
199 this->signal_show().connect(sigc::mem_fun(*this,
200 &PlayersDB::recreate_db));
201 this->recreate_db();
202
203 Party::signal_open().connect_back([this](Party&) { this->recreate_db(); }, this->disconnector_);
204 party->signal_close().connect_back(*this, &PlayersDB::hide, this->disconnector_);
205 } // void PlayersDB::init()
206
207 /** the name of 'player' has changed
208 **
209 ** @param player the player with the changed name
210 **/
211 void
name_changed(Player const & player)212 PlayersDB::name_changed(Player const& player)
213 {
214 if (!this->get_realized())
215 return ;
216
217 this->players_db_treeview->get_column(this->ui->party().players().no(player) + 1
218 )->set_title(" " + player.name() + " ");
219 } // void PlayersDB::name_changed(Player player)
220
221 /** recreates the table
222 **/
223 void
recreate_db()224 PlayersDB::recreate_db()
225 {
226 if (!this->get_realized())
227 return ;
228
229 if (!this->players_db_list)
230 return ;
231
232 this->players_db_list->clear();
233
234 { // ranking
235 this->ranking = *this->players_db_list->append();
236 this->ranking[this->players_db_model->type]
237 = _("ranking");
238 } // ranking
239
240 { // average game points
241 this->average_game_points = *this->players_db_list->append();
242 this->average_game_points[this->players_db_model->type]
243 = _("average game points");
244 } // average game points
245
246 { // average game trick points
247 this->average_game_trick_points = *this->players_db_list->append();
248 this->average_game_trick_points[this->players_db_model->type]
249 = _("average game trick points");
250 } // average game trick points
251
252 {
253 for (unsigned p = 0; p < 4; ++p) {
254 this->ranking[this->players_db_model->statistic[p]]
255 = this->statistic_data(TLWcount());
256 }
257 }
258
259 { // game type
260 this->games = *this->players_db_list->append();
261 this->games[this->players_db_model->type]
262 = _("games");
263 this->games_marriage
264 = *(this->players_db_list->append(this->games.children()));
265 this->games_marriage[this->players_db_model->type]
266 = _("GameType::Group::marriage");
267 this->games_poverty
268 = *(this->players_db_list->append(this->games.children()));
269 this->games_poverty[this->players_db_model->type]
270 = _("GameType::Group::poverty");
271 this->games_solo
272 = *(this->players_db_list->append(this->games.children()));
273 this->games_solo[this->players_db_model->type]
274 = _("GameType::Group::solo");
275 this->games_solo_color
276 = *(this->players_db_list->append(this->games_solo.children()));
277 this->games_solo_color[this->players_db_model->type]
278 = _("GameType::Group::Solo::color");
279 this->games_solo_picture
280 = *(this->players_db_list->append(this->games_solo.children()));
281 this->games_solo_picture[this->players_db_model->type]
282 = _("GameType::Group::Solo::picture");
283 this->games_solo_picture_single
284 = *(this->players_db_list->append(this->games_solo_picture.children()));
285 this->games_solo_picture_single[this->players_db_model->type]
286 = _("GameType::Group::Solo::Picture::single");
287 this->games_solo_picture_double
288 = *(this->players_db_list->append(this->games_solo_picture.children()));
289 this->games_solo_picture_double[this->players_db_model->type]
290 = _("GameType::Group::Solo::Picture::double");
291
292 this->game.clear();
293 for (auto gt : game_type_list) {
294 switch (gt) {
295 case GameType::normal:
296 this->game.push_back(*this->players_db_list->prepend(this->games.children()));
297 break;
298 case GameType::thrown_nines:
299 case GameType::thrown_kings:
300 case GameType::thrown_nines_and_kings:
301 case GameType::thrown_richness:
302 case GameType::fox_highest_trump:
303 case GameType::redistribute:
304 case GameType::poverty:
305 this->game.push_back(*this->players_db_list->append(this->games_poverty.children()));
306 break;
307 case GameType::genscher:
308 case GameType::marriage:
309 case GameType::marriage_solo:
310 case GameType::marriage_silent:
311 this->game.push_back(*this->players_db_list->append(this->games_marriage.children()));
312 break;
313 case GameType::solo_jack:
314 case GameType::solo_queen:
315 this->game.push_back(*this->players_db_list->append(this->games_solo_picture_single.children()));
316 break;
317 case GameType::solo_king:
318 case GameType::solo_queen_jack:
319 case GameType::solo_king_jack:
320 case GameType::solo_king_queen:
321 this->game.push_back(*this->players_db_list->append(this->games_solo_picture_double.children()));
322 break;
323 case GameType::solo_koehler:
324 this->game.push_back(*this->players_db_list->append(this->games_solo_picture.children()));
325 break;
326 case GameType::solo_club:
327 case GameType::solo_heart:
328 case GameType::solo_spade:
329 case GameType::solo_diamond:
330 this->game.push_back(*this->players_db_list->append(this->games_solo_color.children()));
331 break;
332 case GameType::solo_meatless:
333 this->game.push_back(*this->players_db_list->append(this->games_solo.children()));
334 break;
335 #if 0
336 default:
337 DEBUG_ASSERTION(false,
338 "UI_GTKMM::PlayersDB::recreate_db()\n"
339 " game type '" << static_cast<GameType>(gt) << "' is not considered");
340 break;
341 #endif
342 } // switch(gt)
343 this->game.back()[this->players_db_model->type] = _(gt);
344 } // for (gt \in GameType)
345 } // game type
346
347 { // special points
348 this->specialpoints = *this->players_db_list->append();
349 this->specialpoints[this->players_db_model->type]
350 = _("Specialpoint::specialpoints");
351 this->specialpoints_winning
352 = *this->players_db_list->append(this->specialpoints.children());
353 this->specialpoints_winning[this->players_db_model->type]
354 = _("Specialpoint::Group::winning");
355 this->specialpoints_announcement
356 = *this->players_db_list->append(this->specialpoints.children());
357 this->specialpoints_announcement[this->players_db_model->type]
358 = _("Specialpoint::Group::announcement");
359
360 this->specialpoint.clear();
361 for (auto sp : Specialpoint::types) {
362 switch (sp) {
363 case Specialpoint::Type::nospecialpoint:
364 case Specialpoint::Type::caught_fox:
365 case Specialpoint::Type::caught_fox_last_trick:
366 case Specialpoint::Type::fox_last_trick:
367 case Specialpoint::Type::charlie:
368 case Specialpoint::Type::caught_charlie:
369 case Specialpoint::Type::dulle_caught_dulle:
370 case Specialpoint::Type::heart_trick:
371 case Specialpoint::Type::doppelkopf:
372 this->specialpoint[sp] = *this->players_db_list->prepend(this->specialpoints.children());
373 break;
374 case Specialpoint::Type::won:
375 case Specialpoint::Type::no90:
376 case Specialpoint::Type::no60:
377 case Specialpoint::Type::no30:
378 case Specialpoint::Type::no0:
379 case Specialpoint::Type::contra_won:
380 case Specialpoint::Type::solo:
381 case Specialpoint::Type::bock:
382 this->specialpoint[sp] = *this->players_db_list->append(this->specialpoints_winning.children());
383 break;
384 case Specialpoint::Type::no120_said:
385 case Specialpoint::Type::no90_said:
386 case Specialpoint::Type::no60_said:
387 case Specialpoint::Type::no30_said:
388 case Specialpoint::Type::no0_said:
389 case Specialpoint::Type::no90_said_120_got:
390 case Specialpoint::Type::no60_said_90_got:
391 case Specialpoint::Type::no30_said_60_got:
392 case Specialpoint::Type::no0_said_30_got:
393 case Specialpoint::Type::no120_reply:
394 case Specialpoint::Type::no90_reply:
395 case Specialpoint::Type::no60_reply:
396 case Specialpoint::Type::no30_reply:
397 case Specialpoint::Type::no0_reply:
398 this->specialpoint[sp] = *this->players_db_list->append(this->specialpoints_announcement.children());
399 break;
400 } // switch(sp)
401 this->specialpoint[sp][this->players_db_model->type] = _(sp);
402 } // for (sp \in Specialpoint)
403 } // special points
404
405 { // heuristics
406 this->heuristics = *this->players_db_list->append();
407 this->heuristics[this->players_db_model->type]
408 = _("AiConfig::Group::heuristics");
409 this->heuristics_general
410 = *this->players_db_list->append(this->heuristics.children());
411 this->heuristics_general[this->players_db_model->type]
412 = _("AiConfig::Heuristic::Group::normal game");
413 this->heuristics_poverty
414 = *this->players_db_list->append(this->heuristics.children());
415 this->heuristics_poverty[this->players_db_model->type]
416 = _("AiConfig::Heuristic::Group::poverty");
417 this->heuristics_solo
418 = *this->players_db_list->append(this->heuristics.children());
419 this->heuristics_solo[this->players_db_model->type]
420 = _("AiConfig::Heuristic::Group::solo");
421 this->heuristics_solo_color
422 = *this->players_db_list->append(this->heuristics_solo.children());
423 this->heuristics_solo_color[this->players_db_model->type]
424 = _("AiConfig::Heuristic::Group::Solo::color");
425 this->heuristics_solo_picture
426 = *this->players_db_list->append(this->heuristics_solo.children());
427 this->heuristics_solo_picture[this->players_db_model->type]
428 = _("AiConfig::Heuristic::Group::Solo::picture");
429 this->heuristics_solo_meatless
430 = *this->players_db_list->append(this->heuristics_solo.children());
431 this->heuristics_solo_meatless[this->players_db_model->type]
432 = _("AiConfig::Heuristic::Group::Solo::meatless");
433
434 this->heuristic.clear();
435 for (auto const heuristic : aiconfig_heuristic_list) {
436 switch (heuristic) {
437 case Aiconfig::Heuristic::error:
438 break;
439 case Aiconfig::Heuristic::no_heuristic:
440 case Aiconfig::Heuristic::manual:
441 case Aiconfig::Heuristic::bug_report:
442 this->heuristic.push_back(this->heuristics);
443 break;
444 case Aiconfig::Heuristic::only_one_valid_card:
445 this->heuristic.push_back(*this->players_db_list->prepend(this->heuristics.children()));
446 break;
447 case Aiconfig::Heuristic::choose_best_card_in_last_tricks:
448 case Aiconfig::Heuristic::choose_best_card:
449 this->heuristic.push_back(*this->players_db_list->prepend(this->heuristics.children()));
450 std::swap(this->heuristic[static_cast<int>(Aiconfig::Heuristic::only_one_valid_card)],
451 this->heuristic.back());
452 break;
453 case Aiconfig::Heuristic::start_with_color_solo_ace:
454 case Aiconfig::Heuristic::start_with_color_single_ace:
455 case Aiconfig::Heuristic::start_with_color_double_ace:
456 case Aiconfig::Heuristic::jab_with_color_ace:
457 case Aiconfig::Heuristic::choose_ten:
458 case Aiconfig::Heuristic::play_to_marry:
459 case Aiconfig::Heuristic::play_to_get_married:
460 case Aiconfig::Heuristic::choose_for_color_trick:
461 case Aiconfig::Heuristic::jab_color_over_fox:
462 case Aiconfig::Heuristic::start_with_color:
463 case Aiconfig::Heuristic::start_with_low_color:
464 case Aiconfig::Heuristic::start_with_low_trump:
465 case Aiconfig::Heuristic::retry_color:
466 case Aiconfig::Heuristic::play_color_for_partner:
467 case Aiconfig::Heuristic::try_color_for_partner:
468 case Aiconfig::Heuristic::play_color_for_partner_ace:
469 case Aiconfig::Heuristic::play_bad_color:
470 case Aiconfig::Heuristic::jab_color_trick_with_dulle:
471 case Aiconfig::Heuristic::save_dulle:
472 case Aiconfig::Heuristic::pfund_in_first_color_run:
473 case Aiconfig::Heuristic::serve_color_trick:
474 case Aiconfig::Heuristic::serve_trump_trick:
475 case Aiconfig::Heuristic::choose_pfund:
476 case Aiconfig::Heuristic::choose_pfund_before_partner:
477 case Aiconfig::Heuristic::jab_for_ace:
478 case Aiconfig::Heuristic::create_fehl:
479 case Aiconfig::Heuristic::best_winning:
480 case Aiconfig::Heuristic::low_high:
481 case Aiconfig::Heuristic::play_trump:
482 case Aiconfig::Heuristic::play_for_team:
483 case Aiconfig::Heuristic::jab_fox:
484 case Aiconfig::Heuristic::jab_for_doppelkopf:
485 case Aiconfig::Heuristic::try_for_doppelkopf:
486 case Aiconfig::Heuristic::play_for_partner_worries:
487 case Aiconfig::Heuristic::draw_trump:
488 case Aiconfig::Heuristic::play_to_jab_later:
489 case Aiconfig::Heuristic::partner_backhand_draw_trump:
490 case Aiconfig::Heuristic::play_highest_color_card_in_game:
491 case Aiconfig::Heuristic::jab_to_win:
492 case Aiconfig::Heuristic::grab_trick:
493 case Aiconfig::Heuristic::last_player_pass_small_trick:
494 case Aiconfig::Heuristic::cannot_jab:
495 this->heuristic.push_back(*this->players_db_list->append(this->heuristics_general.children()));
496 break;
497 case Aiconfig::Heuristic::color_jab_for_ace:
498 case Aiconfig::Heuristic::color_low_high:
499 case Aiconfig::Heuristic::play_color_in_solo:
500 this->heuristic.push_back(*this->players_db_list->append(this->heuristics_solo_color.children()));
501 break;
502 case Aiconfig::Heuristic::choose_pfund_poverty:
503 case Aiconfig::Heuristic::poverty_special_play_pfund:
504 case Aiconfig::Heuristic::poverty_special_give_no_points:
505 case Aiconfig::Heuristic::poverty_special_offer_pfund:
506 case Aiconfig::Heuristic::poverty_re_trump_color_trick_high:
507 case Aiconfig::Heuristic::poverty_re_play_trump:
508 case Aiconfig::Heuristic::poverty_contra_play_color:
509 case Aiconfig::Heuristic::poverty_contra_trump_color_trick_high:
510 case Aiconfig::Heuristic::poverty_leave_to_partner:
511 case Aiconfig::Heuristic::poverty_overjab_re:
512 case Aiconfig::Heuristic::poverty_best_winning_card:
513 this->heuristic.push_back(*this->players_db_list->append(this->heuristics_poverty.children()));
514 break;
515 case Aiconfig::Heuristic::picture_pull_down_color:
516 case Aiconfig::Heuristic::picture_start_with_highest_color:
517 case Aiconfig::Heuristic::picture_get_last_trumps:
518 case Aiconfig::Heuristic::picture_draw_trumps:
519 case Aiconfig::Heuristic::picture_play_last_trumps:
520 case Aiconfig::Heuristic::picture_jab_color_trick_for_sure:
521 this->heuristic.push_back(*this->players_db_list->append(this->heuristics_solo_picture.children()));
522 case Aiconfig::Heuristic::meatless_start_with_best_color:
523 case Aiconfig::Heuristic::meatless_retry_last_color:
524 this->heuristic.push_back(*this->players_db_list->append(this->heuristics_solo_meatless.children()));
525 break;
526 } // switch(h)
527 this->heuristic.back()[this->players_db_model->type]
528 = _(heuristic);
529 } // for (h \in Aiconfig::Heuristic)
530 } // heuristics
531
532 this->update_db();
533
534 this->players_db_treeview->show_all();
535 } // void PlayersDB::recreate_db()
536
537 /** updates the statistics
538 **/
539 void
update_db()540 PlayersDB::update_db()
541 {
542 if (!this->get_realized())
543 return ;
544
545 if (!this->players_db_list)
546 return ;
547
548 Party const& party = this->ui->party();
549
550 for (unsigned p = 0; p < party.players().size(); ++p) {
551 auto const& player = this->ui->party().players()[p];
552 auto const& db = player.db();
553
554 this->ranking[this->players_db_model->statistic[p]]
555 = String::to_string(static_cast<int>(db.rank.value() * 10) / 10.0);
556
557 this->average_game_points[this->players_db_model->statistic[p]]
558 = String::to_string(static_cast<int>(db.averageGamePoints() * 10) / 10.0);
559
560 this->average_game_trick_points[this->players_db_model->statistic[p]]
561 = String::to_string(static_cast<int>(db.averageGameTrickPoints() * 10) / 10.0);
562
563 { // game type
564 this->games[this->players_db_model->statistic[p]]
565 = this->statistic_data(db.games_all());
566 this->games_marriage[this->players_db_model->statistic[p]]
567 = this->statistic_data(db.games_group_marriage());
568 this->games_poverty[this->players_db_model->statistic[p]]
569 = this->statistic_data(db.games_group_poverty());
570 this->games_solo[this->players_db_model->statistic[p]]
571 = this->statistic_data(db.games_group_solo());
572 this->games_solo_color[this->players_db_model->statistic[p]]
573 = this->statistic_data(db.games_group_solo_color());
574 this->games_solo_picture[this->players_db_model->statistic[p]]
575 = this->statistic_data(db.games_group_solo_picture());
576 this->games_solo_picture_single[this->players_db_model->statistic[p]]
577 = this->statistic_data(db.games_group_solo_picture_single());
578 this->games_solo_picture_double[this->players_db_model->statistic[p]]
579 = this->statistic_data(db.games_group_solo_picture_double());
580 for (auto gt : game_type_list) {
581 this->game[static_cast<int>(gt)][this->players_db_model->statistic[p]]
582 = this->statistic_data(db.games(gt));
583 } // for (gt \in gameTYPE)
584 } // game type
585
586 { // special points
587 this->specialpoints[this->players_db_model->statistic[p]]
588 = this->statistic_data(db.specialpoints_all());
589 this->specialpoints_winning[this->players_db_model->statistic[p]]
590 = this->statistic_data(db.specialpoints_group_winning());
591 this->specialpoints_announcement[this->players_db_model->statistic[p]]
592 = this->statistic_data(db.specialpoints_group_announcement());
593 for (auto sp : Specialpoint::types) {
594 this->specialpoint[sp][this->players_db_model->statistic[p]]
595 = this->statistic_data(db.specialpoints(sp));
596 } // for (sp : Specialpoint::types)
597 } // special points
598 { // heuristics
599 if (dynamic_cast<AiDb const*>(&db) == nullptr)
600 continue;
601 auto const& aidb = dynamic_cast<AiDb const&>(db);
602 auto const total = aidb.heuristic(Aiconfig::Heuristic::no_heuristic);
603
604 this->heuristics[this->players_db_model->statistic[p]]
605 = this->heuristic_statistic_data(total, total);
606 this->heuristics_general[this->players_db_model->statistic[p]]
607 = this->heuristic_statistic_data(total, aidb.heuristics_group_general());
608 this->heuristics_poverty[this->players_db_model->statistic[p]]
609 = this->heuristic_statistic_data(total, aidb.heuristics_group_poverty());
610 this->heuristics_solo[this->players_db_model->statistic[p]]
611 = this->heuristic_statistic_data(total, aidb.heuristics_group_solo());
612 this->heuristics_solo_color[this->players_db_model->statistic[p]]
613 = this->heuristic_statistic_data(total, aidb.heuristics_group_solo_color());
614 this->heuristics_solo_picture[this->players_db_model->statistic[p]]
615 = this->heuristic_statistic_data(total, aidb.heuristics_group_solo_picture());
616 this->heuristics_solo_meatless[this->players_db_model->statistic[p]]
617 = this->heuristic_statistic_data(total, aidb.heuristics_group_solo_meatless());
618 for (auto const heuristic : aiconfig_heuristic_list) {
619 if (this->heuristic[static_cast<int>(heuristic)] == this->heuristics)
620 continue;
621 this->heuristic[static_cast<int>(heuristic)][this->players_db_model->statistic[p]]
622 = this->heuristic_statistic_data(total, aidb.heuristic(heuristic));
623 } // for (h \in Heuristic)
624 } // heuristics
625 } // for (p < party.players().size())
626 } // void PlayersDB::update_db()
627
628 /** sets the statistic
629 **
630 ** @param statistic new statistic
631 **/
632 void
set_statistic(Statistic const statistic)633 PlayersDB::set_statistic(Statistic const statistic)
634 {
635 this->statistic = statistic;
636 this->update_db();
637 } // void PlayersDB::set_statistic(Statistic const statistic)
638
639 /** clears the database
640 **
641 ** @todo remove 'const cast'
642 **/
643 void
clear_db()644 PlayersDB::clear_db()
645 {
646 for (auto& p : this->ui->party().players())
647 p.db().clear();
648
649 this->update_db();
650 } // void PlayersDB::clear_db()
651
652 /** -> result
653 **
654 ** @param tlwcount counter
655 **
656 ** @return string of the data analysed by 'this->statistic'
657 **/
658 Glib::ustring
statistic_data(TLWcount const & tlwcount) const659 PlayersDB::statistic_data(TLWcount const& tlwcount) const
660 {
661 switch(this->statistic) {
662 case Statistic::total:
663 return String::to_string(tlwcount.total());
664 case Statistic::won:
665 if (tlwcount.total() > 0)
666 return String::to_string(tlwcount.won());
667 else
668 return "-";
669 case Statistic::lost:
670 if (tlwcount.total() > 0)
671 return String::to_string(tlwcount.lost());
672 else
673 return "-";
674 case Statistic::percent_won:
675 if (tlwcount.total() > 0)
676 return (String::to_string(tlwcount.won() * 100
677 / tlwcount.total())
678 + "%");
679 else
680 return "-";
681 } // switch(this->statistic)
682
683 return "-";
684 } // void PlayersDB::statistic_data(TLWcout tlwcount) const
685
686 /** -> result
687 **
688 ** @param total total number of heuristics
689 ** @param num number of the active heuristics
690 **
691 ** @return string of the data analysed by 'this->statistic'
692 **/
693 Glib::ustring
heuristic_statistic_data(unsigned const total,unsigned const num) const694 PlayersDB::heuristic_statistic_data(unsigned const total,
695 unsigned const num) const
696 {
697 if (num == 0)
698 return "-";
699
700 switch(this->statistic) {
701 case Statistic::total:
702 case Statistic::won:
703 case Statistic::lost:
704 return String::to_string(num);
705 case Statistic::percent_won:
706 return (String::to_string((num * 100 / total))
707 + "."
708 + String::to_string((num * 1000 / total) % 10)
709 + "%");
710 } // switch(this->statistic)
711
712 return "-";
713 } // void PlayersDB::heuristic_statistic_data(unsigned total, unsigned num) const
714
715 /** a key has been pressed
716 ** C-o: output of the statistics on 'stdout'
717 **
718 ** @param key the key
719 **
720 ** @return whether the key was managed
721 **/
722 bool
on_key_press_event(GdkEventKey * const key)723 PlayersDB::on_key_press_event(GdkEventKey* const key)
724 {
725 bool managed = false;
726
727 if ((key->state & ~GDK_SHIFT_MASK) == GDK_CONTROL_MASK) {
728 switch (key->keyval) {
729 case GDK_KEY_o: // ouput of the preferences
730 for (auto& p : this->ui->party().players()) {
731 cout << p.name() << '\n'
732 << "{\n"
733 << p.db()
734 << "}\n";
735 }
736 managed = true;
737 break;
738 } // switch (key->keyval)
739 } // if (key->state == GDK_CONTROL_MASK)
740
741 return (managed
742 || this->StickyDialog::on_key_press_event(key)
743 || this->ui->key_press(key));
744 } // bool PlayersDB::on_key_press_event(GdkEventKey* key)
745
746 } // namespace UI_GTKMM_NS
747
748 #endif // #ifdef USE_UI_GTKMM
749