Officially at GitHub
[sloppygui.git] / projects / cli / src / enginematch.cpp
blob73b95ddc43bb649bbcb97630ece18b088092097f
1 /*
2 This file is part of Cute Chess.
4 Cute Chess is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 Cute Chess is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with Cute Chess. If not, see <http://www.gnu.org/licenses/>.
18 #include "enginematch.h"
19 #include <cmath>
20 #include <QMultiMap>
21 #include <chessplayer.h>
22 #include <playerbuilder.h>
23 #include <chessgame.h>
24 #include <polyglotbook.h>
25 #include <tournament.h>
26 #include <gamemanager.h>
29 EngineMatch::EngineMatch(Tournament* tournament, QObject* parent)
30 : QObject(parent),
31 m_tournament(tournament),
32 m_debug(false),
33 m_ratingInterval(0)
35 Q_ASSERT(tournament != 0);
37 m_startTime.start();
40 EngineMatch::~EngineMatch()
42 qDeleteAll(m_books);
45 OpeningBook* EngineMatch::addOpeningBook(const QString& fileName)
47 if (fileName.isEmpty())
48 return 0;
50 if (m_books.contains(fileName))
51 return m_books[fileName];
53 PolyglotBook* book = new PolyglotBook;
54 if (!book->read(fileName))
56 delete book;
57 qWarning("Can't read opening book file %s", qPrintable(fileName));
58 return 0;
61 m_books[fileName] = book;
62 return book;
65 void EngineMatch::start()
67 connect(m_tournament, SIGNAL(finished()),
68 this, SLOT(onTournamentFinished()));
69 connect(m_tournament, SIGNAL(gameStarted(ChessGame*, int, int, int)),
70 this, SLOT(onGameStarted(ChessGame*, int)));
71 connect(m_tournament, SIGNAL(gameFinished(ChessGame*, int, int, int)),
72 this, SLOT(onGameFinished(ChessGame*, int)));
74 if (m_debug)
75 connect(m_tournament->gameManager(), SIGNAL(debugMessage(QString)),
76 this, SLOT(print(QString)));
78 QMetaObject::invokeMethod(m_tournament, "start", Qt::QueuedConnection);
81 void EngineMatch::stop()
83 QMetaObject::invokeMethod(m_tournament, "stop", Qt::QueuedConnection);
86 void EngineMatch::setDebugMode(bool debug)
88 m_debug = debug;
91 void EngineMatch::setRatingInterval(int interval)
93 Q_ASSERT(interval >= 0);
94 m_ratingInterval = interval;
97 void EngineMatch::onGameStarted(ChessGame* game, int number)
99 Q_ASSERT(game != 0);
101 qDebug("Started game %d of %d (%s vs %s)",
102 number,
103 m_tournament->finalGameCount(),
104 qPrintable(game->player(Chess::Side::White)->name()),
105 qPrintable(game->player(Chess::Side::Black)->name()));
108 void EngineMatch::onGameFinished(ChessGame* game, int number)
110 Q_ASSERT(game != 0);
112 Chess::Result result(game->result());
113 qDebug("Finished game %d (%s vs %s): %s",
114 number,
115 qPrintable(game->player(Chess::Side::White)->name()),
116 qPrintable(game->player(Chess::Side::Black)->name()),
117 qPrintable(result.toVerboseString()));
119 if (m_tournament->playerCount() == 2)
121 Tournament::PlayerData fcp = m_tournament->playerAt(0);
122 Tournament::PlayerData scp = m_tournament->playerAt(1);
123 int totalResults = fcp.wins + fcp.losses + fcp.draws;
124 qDebug("Score of %s vs %s: %d - %d - %d [%.2f] %d",
125 qPrintable(fcp.builder->name()),
126 qPrintable(scp.builder->name()),
127 fcp.wins, scp.wins, fcp.draws,
128 double(fcp.wins * 2 + fcp.draws) / (totalResults * 2),
129 totalResults);
132 if (m_ratingInterval != 0
133 && (m_tournament->finishedGameCount() % m_ratingInterval) == 0)
134 printRanking();
137 void EngineMatch::onTournamentFinished()
139 if (m_ratingInterval == 0
140 || m_tournament->finishedGameCount() % m_ratingInterval != 0)
141 printRanking();
143 qDebug("Finished match");
144 connect(m_tournament->gameManager(), SIGNAL(finished()),
145 this, SIGNAL(finished()));
146 m_tournament->gameManager()->finish();
149 void EngineMatch::print(const QString& msg)
151 qDebug("%d %s", m_startTime.elapsed(), qPrintable(msg));
154 struct RankingData
156 QString name;
157 int games;
158 qreal score;
159 qreal draws;
162 void EngineMatch::printRanking()
164 QMultiMap<qreal, RankingData> ranking;
166 for (int i = 0; i < m_tournament->playerCount(); i++)
168 Tournament::PlayerData player(m_tournament->playerAt(i));
170 int score = player.wins * 2 + player.draws;
171 int total = (player.wins + player.losses + player.draws) * 2;
172 if (total <= 0)
173 continue;
175 qreal ratio = qreal(score) / qreal(total);
176 qreal eloDiff = -400.0 * std::log(1.0 / ratio - 1.0) / std::log(10.0);
178 if (m_tournament->playerCount() == 2)
180 qDebug("ELO difference: %.0f", eloDiff);
181 break;
184 RankingData data = { player.builder->name(),
185 total / 2,
186 ratio,
187 qreal(player.draws * 2) / qreal(total) };
188 ranking.insert(-eloDiff, data);
191 if (!ranking.isEmpty())
192 qDebug("%4s %-23s %7s %7s %7s %7s",
193 "Rank", "Name", "ELO", "Games", "Score", "Draws");
195 int rank = 0;
196 QMultiMap<qreal, RankingData>::const_iterator it;
197 for (it = ranking.constBegin(); it != ranking.constEnd(); ++it)
199 const RankingData& data = it.value();
200 qDebug("%4d %-23s %7.0f %7d %6.0f%% %6.0f%%",
201 ++rank,
202 qPrintable(data.name),
203 -it.key(),
204 data.games,
205 data.score * 100.0,
206 data.draws * 100.0);