1
/***************************************************************************
2
* (C) 2007-2009 Michal Rudolf <mrudolf@kdewebdev.org> *
4
* This program 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 2 of the License, or *
7
* (at your option) any later version. *
8
***************************************************************************/
10
#include "openingtree.h"
16
const unsigned MinAveYear = 1;
17
const unsigned MinAveRating = 5;
22
for(int r = ResultUnknown; r <= BlackWin; ++r)
31
void MoveData::addGame(Game& g, Color c, MoveType movetype)
34
move = (movetype == StandardMove) ? g.moveToSan(Game::MoveOnly, Game::PreviousMove)
35
: qApp->translate("MoveData", "[end]");
38
unsigned elo = (c == White) ? g.tag("WhiteElo").toInt() : g.tag("BlackElo").toInt();
44
unsigned y = g.tag("Date").section(".", 0, 0).toInt();
52
double MoveData::percentage() const
54
unsigned c = result[ResultUnknown] + 2 * result[WhiteWin] + result[Draw];
55
return c * 500 / count / 10.0;
58
int MoveData::averageRating() const
60
return rated ? rating / rated : 0;
63
int MoveData::averageYear() const
65
return dated ? year / dated : 0;
68
bool operator<(const MoveData& m1, const MoveData& m2)
70
return m1.count < m2.count || (m1.count == m2.count && m1.move < m2.move);
73
bool compareMove(const MoveData& m1, const MoveData& m2)
75
return m1.move < m2.move;
78
bool compareScore(const MoveData& m1, const MoveData& m2)
80
return m1.percentage() < m2.percentage() ||
81
(m1.percentage() == m2.percentage() && m1.move < m2.move);
84
bool compareRating(const MoveData& m1, const MoveData& m2)
86
return m1.averageRating() < m2.averageRating() ||
87
(m1.averageRating() == m2.averageRating() && m1.move < m2.move);
90
bool compareYear(const MoveData& m1, const MoveData& m2)
92
return m1.averageYear() < m2.averageYear() ||
93
(m1.averageYear() == m2.averageYear() && m1.move < m2.move);
96
OpeningTreeUpdater oupd;
98
void OpeningTreeUpdater::run()
101
QMap<Move, MoveData> moves;
103
for(int i = 0; i < m_filter->size(); ++i)
105
m_filter->database()->lock();
106
m_filter->database()->loadGameMoves(i, g);
107
m_filter->database()->unlock();
108
int id = g.findPosition(m_board);
109
if((id != NO_MOVE) && (m_bEnd ? g.atGameEnd(id) : true))
113
m_filter->set(i, id + 1); // not zero means success, but id could be 0.
115
m_filter->database()->lock();
116
m_filter->database()->loadGameHeaders(i, g);
117
m_filter->database()->unlock();
121
moves[Move()].addGame(g, m_board.toMove(), MoveData::GameEnd);
126
moves[g.move()].addGame(g, m_board.toMove());
137
if(i * 100 / m_filter->size() > (i - 1) * 100 / m_filter->size())
139
emit progress(i * 100 / m_filter->size());
150
for(QMap<Move, MoveData>::iterator it = moves.begin(); it != moves.end(); ++it)
152
m_moves->append(it.value());
154
qSort(m_moves->begin(), m_moves->end());
155
emit UpdateFinished(&m_board);
159
emit UpdateTerminated(&m_board);
163
void OpeningTreeUpdater::cancel()
168
bool OpeningTreeUpdater::updateFilter(Filter& f, const Board& b, QList<MoveData>& m, int& g, bool updateFilter, bool bEnd)
176
m_updateFilter = updateFilter;
177
// todo: if running wait for stop
182
bool OpeningTree::updateFilter(Filter& f, const Board& b, bool updateFilter, bool bEnd)
184
if(!oupd.isRunning())
186
if(&f == m_filter && b == m_board && m_bEnd == bEnd)
193
m_updateFilter = updateFilter;
194
emit openingTreeUpdateStarted();
195
m_bRequestPending = false;
196
connect(&oupd, SIGNAL(UpdateFinished(Board*)), this, SLOT(updateFinished(Board*)), Qt::UniqueConnection);
197
connect(&oupd, SIGNAL(UpdateTerminated(Board*)), this, SLOT(updateTerminated(Board*)), Qt::UniqueConnection);
198
connect(&oupd, SIGNAL(progress(int)), SIGNAL(progress(int)), Qt::UniqueConnection);
199
return oupd.updateFilter(f, b, m_moves, m_games, m_updateFilter, m_bEnd);
203
if(&f == m_filter && b == m_board && m_bEnd == bEnd)
210
m_updateFilter = updateFilter;
211
m_bRequestPending = true;
217
void OpeningTree::cancel(bool bVisible)
219
if(!bVisible && oupd.isRunning())
221
m_bRequestPending = false;
227
void OpeningTree::updateFinished(Board* b)
230
emit openingTreeUpdated();
231
if(m_bRequestPending)
237
void OpeningTree::updateTerminated(Board*)
239
if(m_bRequestPending)
241
emit openingTreeUpdateStarted();
242
m_bRequestPending = false;
243
connect(&oupd, SIGNAL(UpdateFinished(Board*)), this, SLOT(updateFinished(Board*)), Qt::UniqueConnection);
244
connect(&oupd, SIGNAL(UpdateTerminated(Board*)), this, SLOT(updateTerminated(Board*)), Qt::UniqueConnection);
245
connect(&oupd, SIGNAL(progress(int)), SIGNAL(progress(int)), Qt::UniqueConnection);
246
oupd.updateFilter(*m_filter, m_board, m_moves, m_games, m_updateFilter, m_bEnd);
250
QString OpeningTree::debug()
253
for(int i = 0; i < m_moves.count(); ++i)
254
s.append(QString("%1. %2\t%3 games\t%4%\n")
255
.arg(i + 1).arg(m_moves[i].move).arg(m_moves[i].count).arg(m_moves[i].percentage()));
259
int OpeningTree::rowCount(const QModelIndex& parent) const
261
return parent.isValid() ? 0 : m_moves.count();
264
int OpeningTree::columnCount(const QModelIndex&) const
266
return m_names.count();
269
OpeningTree::OpeningTree() : m_sortcolumn(1), m_order(Qt::DescendingOrder), m_filter(0)
271
m_names << tr("Move") << tr("Count") << tr("Score") << tr("Rating") << tr("Year");
274
OpeningTree::OpeningTree(Filter & f, const Board & b, bool updFilter) :
275
m_sortcolumn(1), m_order(Qt::DescendingOrder), m_filter(0)
277
m_names << tr("Move") << tr("Count") << tr("Score") << tr("Rating") << tr("Year");
278
updateFilter(f, b, updFilter, false);
281
QVariant OpeningTree::headerData(int section, Qt::Orientation orientation, int role) const
283
if(role == Qt::DisplayRole && orientation == Qt::Horizontal)
285
return m_names[section];
293
QVariant OpeningTree::data(const QModelIndex& index, int role) const
295
if(role != Qt::DisplayRole || !index.isValid() || index.row() >= m_moves.count())
299
switch(index.column())
302
return QString("%1: %2").arg(index.row() + 1).arg(m_moves[index.row()].move);
309
int percentage = m_moves[index.row()].count * 1000 / m_games / 10.0;
316
return QString("%1: %2%3%")
317
.arg(m_moves[index.row()].count)
322
return QString("%1%").arg(m_moves[index.row()].percentage());
324
return m_moves[index.row()].rated >= MinAveRating ?
325
m_moves[index.row()].averageRating() : QVariant();
327
return m_moves[index.row()].dated >= MinAveYear ?
328
m_moves[index.row()].averageYear() : QVariant();
335
void OpeningTree::sort(int column, Qt::SortOrder order)
337
m_sortcolumn = column;
342
qSort(m_moves.begin(), m_moves.end(), compareMove);
345
qSort(m_moves.begin(), m_moves.end());
348
qSort(m_moves.begin(), m_moves.end(), compareScore);
351
qSort(m_moves.begin(), m_moves.end(), compareRating);
354
qSort(m_moves.begin(), m_moves.end(), compareYear);
357
if(order == Qt::DescendingOrder)
358
for(int i = 0; i < m_moves.count() / 2; ++i)
360
qSwap(m_moves[i], m_moves[m_moves.count() - i - 1]);
366
void OpeningTree::sort()
368
sort(m_sortcolumn, m_order);
371
QString OpeningTree::move(const QModelIndex& index) const
373
return index.isValid() ? m_moves[index.row()].move : QString();
376
Board OpeningTree::board() const