Scid  4.7.0
searchtournaments.h
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2015-2019 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 <algorithm>
25 #include <numeric>
26 #include <vector>
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  siteID_ = ie->GetSite();
45  eventID_ = ie->GetEvent();
46  eventDate_ = ie->GetEventDate();
47  whiteID_ = ie->GetWhite();
48  blackID_ = ie->GetBlack();
49  wElo_ = ie->GetWhiteElo();
50  bElo_ = ie->GetBlackElo();
51  date_ = ie->GetDate();
52  gnum_ = gnum;
53  result_ = ie->GetResult();
54  }
55 };
56 
57 /**
58  * class Tourney - Calculate information about a tournament
59  *
60  * This class takes a range of TourneyGame references and calculate some
61  * basic information (number of Players, average elo, scores, etc.).
62  * Invariants:
63  * the range of TourneyGame refs should not be empty
64  */
65 class Tourney {
66 public:
67  template <typename Iter>
68  Tourney(Iter begin, Iter end)
69  : begin_(begin), minDateGame_(begin) {
70  ASSERT(begin != end);
71 
72  n_games_ = static_cast<gamenumT>(std::distance(begin, end));
73 
74  for (auto it = begin; it != end; it++) {
75  auto& white = add_player(it->whiteID_, it->wElo_);
76  white.score += RESULT_SCORE[it->result_];
77  auto& black = add_player(it->blackID_, it->bElo_);
78  black.score += RESULT_SCORE[RESULT_OPPOSITE[it->result_]];
79 
80  if (it->date_ < minDateGame_->date_) minDateGame_ = it;
81  }
82  std::sort(players_.begin(), players_.end(), // SortScoreDesc
83  [](auto& a, auto& b) { return a.score > b.score; });
84 
85  const auto eloSum = std::accumulate(players_.begin(), players_.end(),
86  std::make_pair(0ull, gamenumT{0}),
87  [](auto res, const auto& player) {
88  if (player.elo != 0) {
89  res.first += player.elo;
90  ++res.second;
91  }
92  return res;
93  });
94  avgElo_ = (eloSum.second == 0)
95  ? 0
96  : static_cast<unsigned>(eloSum.first / eloSum.second);
97  }
98 
99  idNumberT getEventId() const { return begin_->eventID_; }
100  idNumberT getSiteId() const { return begin_->siteID_; }
101  dateT getStartDate() const { return minDateGame_->date_; }
102  gamenumT getStartGameNum() const { return minDateGame_->gnum_; }
103  unsigned getAvgElo() const { return avgElo_; }
104  gamenumT nGames() const { return n_games_; }
105  unsigned nPlayers() const { return static_cast<unsigned>(players_.size()); }
106 
107  struct Player {
109  uint16_t score;
111 
112  bool operator==(idNumberT id) const { return nameId == id; }
113  };
114  const Player& getPlayer(size_t position) const {
115  ASSERT(position < players_.size());
116  return players_[position];
117  }
118 
119 private:
120  std::vector<TourneyGame>::const_iterator begin_;
121  std::vector<TourneyGame>::const_iterator minDateGame_;
122  std::vector<Player> players_;
123  gamenumT n_games_;
124  unsigned avgElo_;
125 
126  Player& add_player(idNumberT nameID, eloT elo) {
127  auto it = std::find(players_.begin(), players_.end(), nameID);
128  if (it != players_.end()) {
129  if (elo > it->elo)
130  it->elo = elo;
131  return *it;
132  }
133  players_.push_back({nameID, 0, elo});
134  return players_.back();
135  };
136 };
137 
138 
139 /**
140  * class SearchTournamens - Search tournaments in a database
141  *
142  * This class group games in tournaments.
143  * Games with the same EventId, SiteId and EventDate are considered
144  * a tournament. A game with EventDate == 0 is also considered part of
145  * a tournament if its date is greater than or equal to the EventDate
146  * of the other games.
147  * It's also possible to filter the results further by:
148  * - average elo
149  * - number of partecipants
150  * - number of games
151  * - name of a participant
152  * Results can be sorted by
153  * - event name
154  * - event date
155  * - site name
156  * - number of partecipants
157  * - number of games
158  * - average elo
159  *
160  * Dependencies:
161  * Indexes of NameBase are used for the names of the event, site and player
162  * and they must be valid and unchanged throughout all the life of the
163  * SearchTournament object.
164  */
166  const scidBaseT* dbase_;
167  std::vector<TourneyGame> games_;
168  std::vector<Tourney> tourney_;
169 
170 public:
171  SearchTournaments(const scidBaseT* dbase, const HFilter& filter)
172  : dbase_(dbase) {
173  ASSERT(dbase != 0);
174  ASSERT(filter != 0);
175 
176  games_.reserve(filter->size());
177  for (auto gnum : filter) {
178  games_.emplace_back(dbase->getIndexEntry(gnum), gnum);
179  }
180 
181  std::sort(games_.begin(), games_.end(),
182  [](const TourneyGame& a, const TourneyGame& b) {
183  if (a.eventID_ != b.eventID_)
184  return a.eventID_ < b.eventID_;
185  if (a.siteID_ != b.siteID_)
186  return a.siteID_ < b.siteID_;
187  dateT d1 = a.eventDate_ != 0 ? a.eventDate_ : a.date_;
188  dateT d2 = b.eventDate_ != 0 ? b.eventDate_ : b.date_;
189  return d1 < d2;
190  });
191 
192  auto it = games_.begin();
193  const auto it_end = games_.end();
194  while (it != it_end) {
195  const auto start = it;
196  it = std::find_if(it, it_end, [start](const TourneyGame& g) {
197  if (start->eventID_ != g.eventID_ ||
198  start->siteID_ != g.siteID_)
199  return true;
200 
201  if (start->eventDate_ != 0 && g.eventDate_ == 0)
202  return start->eventDate_ > g.date_;
203 
204  if (start->eventDate_ == 0 && g.eventDate_ != 0)
205  return g.eventDate_ > start->date_;
206 
207  return start->eventDate_ != g.eventDate_;
208  });
209  tourney_.emplace_back(start, it);
210  }
211  }
212 
213  typedef std::vector<Tourney>::const_iterator Iter;
214  Iter begin() const { return tourney_.begin(); }
215  Iter end() const { return tourney_.end(); }
216 
217  void filterByAvgElo(const StrRange& range) {
218  tourney_.erase(
219  std::remove_if(tourney_.begin(), tourney_.end(),
220  Filter<& Tourney::getAvgElo>(range)),
221  tourney_.end());
222  }
223 
224  void filterByNPlayers(const StrRange& range) {
225  tourney_.erase(
226  std::remove_if(tourney_.begin(), tourney_.end(),
227  Filter<& Tourney::nPlayers>(range)),
228  tourney_.end());
229  }
230 
231  void filterByNGames(const StrRange& range) {
232  tourney_.erase(
233  std::remove_if(tourney_.begin(), tourney_.end(),
234  Filter<& Tourney::nGames>(range)),
235  tourney_.end());
236  }
237 
238  void filterByPlayer(const char* name) {
239  tourney_.erase(
240  std::remove_if(tourney_.begin(), tourney_.end(),
241  FilterByPlayer(name, dbase_->getNameBase())),
242  tourney_.end());
243  }
244 
245 
246  bool sort(const char* criteria, size_t max);
247 
248 private:
249  template <uint (Tourney::* f)() const>
250  class Filter {
251  const StrRange& range_;
252 
253  public:
254  Filter(const StrRange& range) : range_(range) {}
255 
256  bool operator()(const Tourney& t) {
257  return ! range_.inRange((t.*f)());
258  }
259  };
260 
261  class FilterByPlayer {
262  const char* name_;
263  const NameBase* nb_;
264 
265  public:
266  FilterByPlayer(const char* name, const NameBase* nb)
267  : name_(name), nb_(nb) {}
268 
269  bool operator()(const Tourney& t) {
270  for (size_t i = 0, n = t.nPlayers(); i < n; i++) {
271  const char* name = nb_->GetName(NAME_PLAYER, t.getPlayer(i).nameId);
272  if (strAlphaContains(name, name_)) return false;
273  }
274  return true;
275  }
276  };
277 
278 
279  struct SortDate {
280  bool operator()(const Tourney& a, const Tourney& b) {
281  return a.getStartDate() > b.getStartDate();
282  }
283  };
284 
285  template <uint (Tourney::* f)() const>
286  struct SortDesc {
287  bool operator()(const Tourney& a, const Tourney& b) {
288  return (a.*f)() > (b.*f)();
289  }
290  };
291 
292  template <nameT nt, idNumberT (Tourney::* f)() const>
293  class SortId {
294  const NameBase* nb_;
295  public:
296  SortId(const NameBase* nb) : nb_(nb) {}
297  bool operator()(const Tourney& a, const Tourney& b) {
298  const char* nameA = nb_->GetName(nt, (a.*f)());
299  const char* nameB = nb_->GetName(nt, (b.*f)());
300  return strCaseCompare(nameA, nameB) < 0;
301  }
302  };
303 };
304 
305 inline bool SearchTournaments::sort(const char* criteria, size_t nOrdered) {
306  static const char* criterions [] = {
307  "Date", "Elo", "Event", "Games", "Players", "Site", NULL
308  };
309  enum { DATE, ELO, EVENT, GAMES, PLAYERS, SITE };
310 
311  std::vector<Tourney>::iterator begin = tourney_.begin();
312  std::vector<Tourney>::iterator it = (nOrdered < tourney_.size()) ?
313  tourney_.begin() + nOrdered : tourney_.end();
314  std::vector<Tourney>::iterator end = tourney_.end();
315 
316  switch (strUniqueMatch(criteria, criterions)) {
317  case DATE:
318  std::partial_sort(begin, it, end, SortDate());
319  break;
320  case ELO:
321  std::partial_sort(begin, it, end, SortDesc<& Tourney::getAvgElo>());
322  break;
323  case EVENT:
324  std::partial_sort(begin, it, end,
325  SortId<NAME_EVENT, & Tourney::getEventId>(dbase_->getNameBase()));
326  break;
327  case GAMES:
328  std::partial_sort(begin, it, end, SortDesc<& Tourney::nGames>());
329  break;
330  case PLAYERS:
331  std::partial_sort(begin, it, end, SortDesc<& Tourney::nPlayers>());
332  break;
333  case SITE:
334  std::partial_sort(begin, it, end,
335  SortId<NAME_SITE, & Tourney::getSiteId>(dbase_->getNameBase()));
336  break;
337  default:
338  return false;
339  }
340 
341  return true;
342 }
343 
344 #endif
const IndexEntry * getIndexEntry(gamenumT g) const
Definition: scidbase.h:131
byte resultT
Definition: common.h:187
dateT GetDate() const
Definition: indexentry.h:107
unsigned getAvgElo() const
dateT getStartDate() const
std::vector< Tourney >::const_iterator Iter
idNumberT whiteID_
resultT GetResult() const
Definition: indexentry.h:109
uint max(int a, int b)
Definition: crosstab.cpp:237
idNumberT GetSite() const
Definition: indexentry.h:105
class SearchTournamens - Search tournaments in a database
uint dateT
Definition: common.h:147
#define ASSERT(f)
Definition: common.h:59
Filter(gamenumT size)
Definition: hfilter.h:42
gamenumT nGames() const
idNumberT GetEvent() const
Definition: indexentry.h:104
gamenumT getStartGameNum() const
names
Definition: tablebase.tcl:257
int strUniqueMatch(const char *keyStr, const char **strTable)
Definition: misc.h:255
class StrRange - parse a string interpreting its content as 1 or 2 integers separated by whitespace...
Definition: misc.h:36
const resultT RESULT_OPPOSITE[4]
Definition: common.h:198
idNumberT getEventId() const
void filterByNPlayers(const StrRange &range)
const char * GetName(nameT nt, idNumberT id) const
Retrieve a name.
Definition: namebase.h:162
idNumberT getSiteId() const
bool sort(const char *criteria, size_t max)
uint32_t idNumberT
Definition: common.h:152
eloT GetWhiteElo() const
Definition: indexentry.h:99
int find(const char *filename)
find() - search for a database.
Definition: dbasepool.cpp:51
This class stores the database&#39;s names (players, events, sites and rounds).
Definition: namebase.h:33
void filterByPlayer(const char *name)
class Tourney - Calculate information about a tournament
sort?type?
Definition: analysis.tcl:320
bool operator==(idNumberT id) const
class TourneyGame - Private class used by Tourney and SearchTournaments
void filterByNGames(const StrRange &range)
idNumberT GetWhite() const
Definition: indexentry.h:98
TourneyGame(const IndexEntry *ie, gamenumT gnum)
eloT GetBlackElo() const
Definition: indexentry.h:102
SearchTournaments(const scidBaseT *dbase, const HFilter &filter)
bool strAlphaContains(const char *longStr, const char *keyStr)
Definition: misc.h:401
ushort eloT
Definition: common.h:164
const Player & getPlayer(size_t position) const
int strCaseCompare(const char *str1, const char *str2)
Definition: misc.h:200
Tourney(Iter begin, Iter end)
idNumberT GetBlack() const
Definition: indexentry.h:101
void filterByAvgElo(const StrRange &range)
size_t size() const
Definition: hfilter.h:240
idNumberT eventID_
const uint RESULT_SCORE[4]
Definition: common.h:194
unsigned nPlayers() const
idNumberT siteID_
idNumberT blackID_
uint gamenumT
Definition: common.h:163
const NameBase * getNameBase() const
Definition: scidbase.h:138
Definition: indexentry.h:54
dateT GetEventDate() const
Definition: indexentry.h:108