Scid  4.6.5
searchtournaments.h
Go to the documentation of this file.
1 /*
2 # Copyright (C) 2015 Fulvio Benini
3 
4 * This file is part of Scid (Shane's Chess Information Database).
5 *
6 * Scid is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation.
9 *
10 * Scid is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifndef SEARCHTOURNAMENTS_H
20 #define SEARCHTOURNAMENTS_H
21 
22 #include "common.h"
23 #include "misc.h"
24 #include <vector>
25 #include <algorithm>
26 
27 
28 /**
29  * class TourneyGame - Private class used by Tourney and SearchTournaments
30  */
31 struct TourneyGame {
42 
43  TourneyGame(const IndexEntry* ie, gamenumT gnum)
44  : gnum_ (gnum) {
45  siteID_ = ie->GetSite();
46  eventID_ = ie->GetEvent();
47  eventDate_ = ie->GetEventDate();
48  whiteID_ = ie->GetWhite();
49  blackID_ = ie->GetBlack();
50  wElo_ = ie->GetWhiteElo();
51  bElo_ = ie->GetBlackElo();
52  result_ = ie->GetResult();
53  date_ = ie->GetDate();
54  }
55 };
56 
57 
58 /**
59  * class Tourney - Calculate information about a tournament
60  *
61  * This class takes a range of TourneyGame references and calculate some
62  * basic information (number of Players, average elo, scores, etc.).
63  * Invariants:
64  * the range of TourneyGame refs should not be empty
65  */
66 class Tourney {
67  typedef std::vector<TourneyGame>::const_iterator Iter;
68 
69 public:
70  Tourney(Iter begin, Iter end)
71  : begin_(begin), end_(end), minDateGame_(begin) {
72  ASSERT(begin_ != end_);
73 
74  for (Iter it = begin_; it != end_; it++) {
75  size_t idxW = addPlayer(it->whiteID_);
76  size_t idxB = addPlayer(it->blackID_);
77  players_[idxW].elo = std::max(players_[idxW].elo, it->wElo_);
78  players_[idxB].elo = std::max(players_[idxB].elo, it->bElo_);
79  switch (it->result_) {
80  case RESULT_White:
81  players_[idxW].score += 2;
82  break;
83  case RESULT_Black:
84  players_[idxB].score += 2;
85  break;
86  case RESULT_Draw:
87  players_[idxW].score++;
88  players_[idxB].score++;
89  break;
90  }
91 
92  if (it->date_ < minDateGame_->date_) minDateGame_ = it;
93  }
94 
95  std::sort(players_.begin(), players_.end(), SortScoreDesc());
96 
97  avgElo_ = calcAvgElo();
98  }
99 
100  idNumberT getEventId() const { return begin_->eventID_; }
101  idNumberT getSiteId() const { return begin_->siteID_; }
102  dateT getStartDate() const { return minDateGame_->date_; }
103  gamenumT getStartGameNum() const { return minDateGame_->gnum_; }
104  uint getAvgElo() const { return avgElo_; }
105  uint nGames() const { return std::distance(begin_, end_); }
106  uint nPlayers() const { return players_.size(); }
107 
108  struct Player {
110  uint16_t score;
112 
113  explicit Player(idNumberT id) : nameId(id), score(0), elo(0) {}
114  bool operator==(idNumberT id) { return nameId == id; }
115  };
116  const Player& getPlayer(size_t position) const {
117  ASSERT(position < players_.size());
118  return players_[position];
119  }
120 
121 private:
122  std::vector<TourneyGame>::const_iterator begin_;
123  std::vector<TourneyGame>::const_iterator end_;
124  std::vector<TourneyGame>::const_iterator minDateGame_;
125  std::vector<Player> players_;
126  eloT avgElo_;
127 
128  size_t addPlayer(idNumberT playerID) {
129  std::vector<Player>::iterator it_begin = players_.begin();
130  std::vector<Player>::iterator it_end = players_.end();
131  std::vector<Player>::iterator it = std::find(it_begin, it_end, playerID);
132  size_t res = std::distance(it_begin, it);
133  if (it == it_end) players_.push_back(Player(playerID));
134  return res;
135  };
136 
137  uint calcAvgElo() const {
138  uint sum = 0;
139  uint n = 0;
140  std::vector<Player>::const_iterator it = players_.begin();
141  std::vector<Player>::const_iterator it_end = players_.end();
142  for (; it != it_end; it++) {
143  if (it->elo != 0) {
144  sum += it->elo;
145  n++;
146  }
147  }
148  return (n != 0) ? sum / n : 0;
149  }
150 
151  struct SortScoreDesc {
152  bool operator()(const Tourney::Player& a, const Tourney::Player& b) {
153  return a.score > b.score;
154  }
155  };
156 };
157 
158 
159 /**
160  * class SearchTournamens - Search tournaments in a database
161  *
162  * This class group games in tournaments.
163  * Games with the same EventId, SiteId and EventDate are considered
164  * a tournament. A game with EventDate == 0 is also considered part of
165  * a tournament if its date is greater than or equal to the EventDate
166  * of the other games.
167  * It's also possible to filter the results further by:
168  * - average elo
169  * - number of partecipants
170  * - number of games
171  * - name of a participant
172  * Results can be sorted by
173  * - event name
174  * - event date
175  * - site name
176  * - number of partecipants
177  * - number of games
178  * - average elo
179  *
180  * Dependencies:
181  * Indexes of NameBase are used for the names of the event, site and player
182  * and they must be valid and unchanged throughout all the life of the
183  * SearchTournament object.
184  */
186  const scidBaseT* dbase_;
187  std::vector<TourneyGame> games_;
188  std::vector<Tourney> tourney_;
189 
190 public:
191  SearchTournaments(const scidBaseT* dbase, const HFilter& filter);
192 
193  typedef std::vector<Tourney>::const_iterator Iter;
194  Iter begin() const { return tourney_.begin(); }
195  Iter end() const { return tourney_.end(); }
196 
197  void filterByAvgElo(const StrRange& range) {
198  tourney_.erase(
199  std::remove_if(tourney_.begin(), tourney_.end(),
200  Filter<& Tourney::getAvgElo>(range)),
201  tourney_.end());
202  }
203 
204  void filterByNPlayers(const StrRange& range) {
205  tourney_.erase(
206  std::remove_if(tourney_.begin(), tourney_.end(),
207  Filter<& Tourney::nPlayers>(range)),
208  tourney_.end());
209  }
210 
211  void filterByNGames(const StrRange& range) {
212  tourney_.erase(
213  std::remove_if(tourney_.begin(), tourney_.end(),
214  Filter<& Tourney::nGames>(range)),
215  tourney_.end());
216  }
217 
218  void filterByPlayer(const char* name) {
219  tourney_.erase(
220  std::remove_if(tourney_.begin(), tourney_.end(),
221  FilterByPlayer(name, dbase_->getNameBase())),
222  tourney_.end());
223  }
224 
225 
226  bool sort(const char* criteria, size_t max);
227 
228 private:
229  struct GameSort {
230  bool operator()(const TourneyGame& a, const TourneyGame& b) {
231  if (a.eventID_ != b.eventID_) return a.eventID_ < b.eventID_;
232  if (a.siteID_ != b.siteID_) return a.siteID_ < b.siteID_;
233  dateT d1 = a.eventDate_ != 0 ? a.eventDate_ : a.date_;
234  dateT d2 = b.eventDate_ != 0 ? b.eventDate_ : b.date_;
235  return d1 < d2;
236  }
237  };
238 
239  class FindNewTourney {
240  const TourneyGame& g_;
241  public:
242  FindNewTourney(const TourneyGame& start) : g_(start) {}
243 
244  bool operator()(const TourneyGame& g) {
245  if (g_.eventID_ != g.eventID_ || g_.siteID_ != g.siteID_)
246  return true;
247 
248  if (g_.eventDate_ != 0 && g.eventDate_ == 0)
249  return g_.eventDate_ > g.date_;
250 
251  if (g_.eventDate_ == 0 && g.eventDate_ != 0)
252  return g.eventDate_ > g_.date_;
253 
254  return g_.eventDate_ != g.eventDate_;
255  }
256  };
257 
258 
259  template <uint (Tourney::* f)() const>
260  class Filter {
261  const StrRange& range_;
262 
263  public:
264  Filter(const StrRange& range) : range_(range) {}
265 
266  bool operator()(const Tourney& t) {
267  return ! range_.inRange((t.*f)());
268  }
269  };
270 
271  class FilterByPlayer {
272  const char* name_;
273  const NameBase* nb_;
274 
275  public:
276  FilterByPlayer(const char* name, const NameBase* nb)
277  : name_(name), nb_(nb) {}
278 
279  bool operator()(const Tourney& t) {
280  for (size_t i = 0, n = t.nPlayers(); i < n; i++) {
281  const char* name = nb_->GetName(NAME_PLAYER, t.getPlayer(i).nameId);
282  if (strAlphaContains(name, name_)) return false;
283  }
284  return true;
285  }
286  };
287 
288 
289  struct SortDate {
290  bool operator()(const Tourney& a, const Tourney& b) {
291  return a.getStartDate() > b.getStartDate();
292  }
293  };
294 
295  template <uint (Tourney::* f)() const>
296  struct SortDesc {
297  bool operator()(const Tourney& a, const Tourney& b) {
298  return (a.*f)() > (b.*f)();
299  }
300  };
301 
302  template <nameT nt, idNumberT (Tourney::* f)() const>
303  class SortId {
304  const NameBase* nb_;
305  public:
306  SortId(const NameBase* nb) : nb_(nb) {}
307  bool operator()(const Tourney& a, const Tourney& b) {
308  const char* nameA = nb_->GetName(nt, (a.*f)());
309  const char* nameB = nb_->GetName(nt, (b.*f)());
310  return strCaseCompare(nameA, nameB) < 0;
311  }
312  };
313 };
314 
315 inline SearchTournaments::SearchTournaments(const scidBaseT* dbase, const HFilter& filter)
316 : dbase_(dbase) {
317  ASSERT(dbase != 0);
318  ASSERT(filter != 0);
319  games_.reserve(filter->size());
320  for (uint i=0, n = dbase->numGames(); i < n; i++) {
321  if (filter.get(i) == 0) continue;
322  games_.push_back( TourneyGame(dbase->getIndexEntry(i), i) );
323  }
324 
325  std::sort(games_.begin(), games_.end(), GameSort());
326 
327  typedef std::vector<TourneyGame>::const_iterator GameIt;
328  GameIt it = games_.begin();
329  GameIt it_end = games_.end();
330  while (it != it_end) {
331  GameIt start = it;
332  it = std::find_if(it, it_end, FindNewTourney(*start));
333  tourney_.push_back(Tourney(start, it));
334  }
335 }
336 
337 inline bool SearchTournaments::sort(const char* criteria, size_t nOrdered) {
338  static const char* criterions [] = {
339  "Date", "Elo", "Event", "Games", "Players", "Site", NULL
340  };
341  enum { DATE, ELO, EVENT, GAMES, PLAYERS, SITE };
342 
343  std::vector<Tourney>::iterator begin = tourney_.begin();
344  std::vector<Tourney>::iterator it = (nOrdered < tourney_.size()) ?
345  tourney_.begin() + nOrdered : tourney_.end();
346  std::vector<Tourney>::iterator end = tourney_.end();
347 
348  switch (strUniqueMatch(criteria, criterions)) {
349  case DATE:
350  std::partial_sort(begin, it, end, SortDate());
351  break;
352  case ELO:
353  std::partial_sort(begin, it, end, SortDesc<& Tourney::getAvgElo>());
354  break;
355  case EVENT:
356  std::partial_sort(begin, it, end,
357  SortId<NAME_EVENT, & Tourney::getEventId>(dbase_->getNameBase()));
358  break;
359  case GAMES:
360  std::partial_sort(begin, it, end, SortDesc<& Tourney::nGames>());
361  break;
362  case PLAYERS:
363  std::partial_sort(begin, it, end, SortDesc<& Tourney::nPlayers>());
364  break;
365  case SITE:
366  std::partial_sort(begin, it, end,
367  SortId<NAME_SITE, & Tourney::getSiteId>(dbase_->getNameBase()));
368  break;
369  default:
370  return false;
371  }
372 
373  return true;
374 }
375 
376 #endif
byte resultT
Definition: common.h:183
idNumberT GetEvent() const
Definition: indexentry.h:127
uint idNumberT
Definition: namebase.h:39
std::vector< Tourney >::const_iterator Iter
idNumberT whiteID_
uint max(int a, int b)
Definition: crosstab.cpp:237
Tourney(Iter begin, Iter end)
class SearchTournamens - Search tournaments in a database
uint dateT
Definition: common.h:155
#define ASSERT(f)
Definition: common.h:67
gamenumT numGames() const
Definition: scidbase.h:97
dateT GetEventDate() const
Definition: indexentry.h:235
const resultT RESULT_Black
Definition: common.h:187
const IndexEntry * getIndexEntry(gamenumT g) const
Definition: scidbase.h:101
names
Definition: tablebase.tcl:260
int strUniqueMatch(const char *keyStr, const char **strTable)
Definition: misc.h:336
class StrRange - parse a string interpreting its content as 1 or 2 integers separated by whitespace...
Definition: misc.h:37
eloT GetBlackElo() const
Definition: indexentry.h:252
void filterByNPlayers(const StrRange &range)
dateT getStartDate() const
resultT GetResult() const
Definition: indexentry.h:245
bool sort(const char *criteria, size_t max)
const resultT RESULT_Draw
Definition: common.h:188
const Player & getPlayer(size_t position) const
bool operator==(idNumberT id)
int find(const char *filename)
find() - search for a database.
Definition: dbasepool.cpp:51
void filterByPlayer(const char *name)
class Tourney - Calculate information about a tournament
sort?type?
Definition: analysis.tcl:321
const resultT RESULT_White
Definition: common.h:186
uint32_t uint
Definition: common.h:99
class TourneyGame - Private class used by Tourney and SearchTournaments
idNumberT getSiteId() const
void filterByNGames(const StrRange &range)
const char * GetName(nameT nt, idNumberT id) const
Definition: namebase.h:97
TourneyGame(const IndexEntry *ie, gamenumT gnum)
SearchTournaments(const scidBaseT *dbase, const HFilter &filter)
bool strAlphaContains(const char *longStr, const char *keyStr)
Definition: misc.h:482
ushort eloT
Definition: common.h:160
int strCaseCompare(const char *str1, const char *str2)
Definition: misc.h:281
gamenumT getStartGameNum() const
size_t size() const
Definition: hfilter.h:161
void filterByAvgElo(const StrRange &range)
idNumberT eventID_
uint getAvgElo() const
idNumberT siteID_
uint nGames() const
byte get(gamenumT gnum) const
Definition: hfilter.h:168
idNumberT GetBlack() const
Definition: indexentry.h:116
idNumberT blackID_
uint gamenumT
Definition: common.h:159
eloT GetWhiteElo() const
Definition: indexentry.h:246
uint nPlayers() const
idNumberT GetSite() const
Definition: indexentry.h:134
idNumberT GetWhite() const
Definition: indexentry.h:109
Player(idNumberT id)
const NameBase * getNameBase() const
Definition: scidbase.h:108
dateT GetDate() const
Definition: indexentry.h:231
Definition: indexentry.h:54
idNumberT getEventId() const