Scid  4.7.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
crosstab.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 //
3 // FILE: crosstab.cpp
4 // Crosstable class methods
5 //
6 // Part of: Scid (Shane's Chess Information Database)
7 // Version: 3.3
8 //
9 // Notice: Copyright (c) 2001 Shane Hudson. All rights reserved.
10 //
11 // Author: Shane Hudson (sgh@users.sourceforge.net)
12 //
13 //////////////////////////////////////////////////////////////////////
14 
15 #ifndef WINCE
16 
17 #include "crosstab.h"
18 #include "dstring.h"
19 
20 // Expected differences in rating according to performance
21 // from 50% to 100%:
22 const uint perf_elodiff [51] = {
23  /* 50 - 59 */ 0, 7, 14, 21, 29, 36, 43, 50, 57, 65,
24  /* 60 - 69 */ 72, 80, 87, 95, 102, 110, 117, 125, 133, 141,
25  /* 70 - 79 */ 149, 158, 166, 175, 184, 193, 202, 211, 220, 230,
26  /* 80 - 89 */ 240, 251, 262, 273, 284, 296, 309, 322, 336, 351,
27  /* 90 - 99 */ 366, 383, 401, 422, 444, 470, 501, 538, 589, 677,
28  /* 100 */ 999
29 };
30 
31 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32 // Crosstable::Performance():
33 // Given an average of opponents ratings and a percentage score,
34 // returns the performance rating.
35 uint
36 Crosstable::Performance (uint oppAvg, uint percentage)
37 {
38  if (percentage > 100) { percentage = 100; }
39  uint performance = oppAvg;
40  if (percentage < 50) {
41  performance -= perf_elodiff [50 - percentage];
42  } else {
43  performance += perf_elodiff [percentage - 50];
44  }
45  return performance;
46 }
47 
48 
49 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50 // Crosstable::RatingChange():
51 // Calculates rating change, given current rating, average rating
52 // and score
53 int
54 Crosstable::RatingChange (eloT player, uint oppAvg, uint percentage, uint games)
55 {
56  uint diff = (player > oppAvg) ? player - oppAvg : oppAvg - player;
57  int i;
58  for (i=0; i<50 ; i++)
59  if (diff <= perf_elodiff[i])
60  break;
61  uint expected = i;
62  if (player > oppAvg)
63  expected += 50;
64  else
65  expected = 50 - expected;
66  int cutoff = (percentage > expected) ? 5 : -5;
67  return (((int)percentage - (int)expected) * (int)games + cutoff) / 10;
68 }
69 
70 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
71 // Crosstable::FideCategory()
72 // Given an average Elo rating for an all-play-all tournament,
73 // returns the FIDE Category of the tournament.
74 // Ratings under 2251 have no category.
75 // 2251-2275 = Cat. 1, 2276-2300 = Cat. 2, etc in blocks of 25.
76 uint
78 {
79  if (rating <= 2250) { return 0; }
80  return 1 + ((rating - 2251) / 25);
81 }
82 
83 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84 // Crosstable::OpponentElo():
85 // Strips ELO rating if difference is bigger than 350
86 eloT
87 Crosstable::OpponentElo (eloT player, eloT opponent)
88 {
89  const eloT Margin = 350;
90  if (!player)
91  return opponent;
92  else if (player - opponent > Margin)
93  return player - Margin;
94  else if (opponent - player > Margin)
95  return player + Margin;
96  else
97  return opponent;
98 }
99 
100 
101 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102 // comparePlayerData():
103 // Compares two playerDataT structs based on their tournament score.
104 int
106 {
107  int result = 0;
108  switch (option) {
109  case CROSSTABLE_SortScore: // Sort by highest score, then fewest games:
110  result = p2->score - p1->score;
111  if (result == 0) { result = p1->gameCount - p2->gameCount; }
112  if (result == 0) { result = p2->tiebreak - p1->tiebreak; }
113  break;
114 
115  case CROSSTABLE_SortName:
116  result = strCompare(p1->name, p2->name);
117  break;
118 
119  case CROSSTABLE_SortElo:
120  result = p2->elo - p1->elo;
121  break;
122 
124  result = strCompare(p1->country, p2->country);
125  break;
126  }
127  return result;
128 }
129 
130 
131 void
132 Crosstable::Init ()
133 {
134  for (uint pcount=0; pcount < CROSSTABLE_MaxPlayers; pcount++) {
135  PlayerData[pcount] = NULL;
136  }
137  GameCount = 0;
138  PlayerCount = 0;
139  MaxClashes = 0;
140  MaxRound = 0;
141  FirstDate = ZERO_DATE;
142  for (resultT r = 0; r < NUM_RESULT_TYPES; r++) { ResultCount[r] = 0; }
143  ShowTitles = ShowElos = ShowCountries = ShowTallies = SwissColors = ShowAges = true;
144  ShowTiebreaks = false;
145  SortOption = CROSSTABLE_SortScore;
146  OutputFormat = CROSSTABLE_Plain;
147  DecimalPointChar = '.';
148  APAColumnNums = false;
149 }
150 
151 void
152 Crosstable::Destroy ()
153 {
154  for (uint player=0; player < PlayerCount; player++) {
155  playerDataT * pdata = PlayerData[player];
156  ASSERT (pdata != NULL);
157 #ifdef WINCE
158  my_Tcl_Free((char*)pdata->name);
159 #else
160  delete[] pdata->name;
161 #endif
162  for (uint opp = 0; opp < PlayerCount; opp++) {
163  clashT * clash = pdata->firstClash[opp];
164  while (clash != NULL) {
165  clashT * temp = clash->next;
166 #ifdef WINCE
167  my_Tcl_Free((char*)clash);
168 #else
169  delete clash;
170 #endif
171  clash = temp;
172  }
173  }
174 
175 #ifdef WINCE
176  my_Tcl_Free((char*)pdata);
177 #else
178  delete pdata;
179 #endif
180  }
181 }
182 
183 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184 // Crosstable::AddPlayer()
185 // Adds a player to the crosstable, if that player is not
186 // already listed.
187 errorT
188 Crosstable::AddPlayer (idNumberT id, const char * name, eloT elo, const SpellChecker* SpellCheck)
189 {
190  for (uint i = 0; i < PlayerCount; i++) {
191  if (PlayerData[i]->id == id) {
192  // The player already exists in the crosstable, but
193  // check the elo rating and keep the largest value:
194  if (elo > PlayerData[i]->elo) { PlayerData[i]->elo = elo; }
195  return OK;
196  }
197  }
198  if (PlayerCount == CROSSTABLE_MaxPlayers) { return ERROR_Full; }
199  playerDataT * pdata = new playerDataT;
200 
201  PlayerData[PlayerCount] = pdata;
202  pdata->id = id;
203  pdata->name = strDuplicate (name);
204  pdata->elo = elo;
205  pdata->score = 0;
206  pdata->gameCount = 0;
207  pdata->tiebreak = 0;
208  pdata->oppEloCount = 0;
209  pdata->oppEloTotal = 0;
210  pdata->oppEloScore = 0;
211  pdata->title[0] = 0;
212  pdata->country[0] = 0;
213  pdata->birthdate = ZERO_DATE;
214  pdata->ageInYears = 0;
215  for (uint opp = 0; opp < CROSSTABLE_MaxPlayers; opp++) {
216  pdata->firstClash[opp] = pdata->lastClash[opp] = NULL;
217  pdata->clashCount[opp] = 0;
218  }
219  for (uint round = 1; round < CROSSTABLE_MaxRounds; round++) {
220  pdata->roundClash[round] = NULL;
221  }
222 
223  if (SpellCheck != NULL ) {
224  const PlayerInfo* pInfo = SpellCheck->getPlayerInfo(name);
225  if (pInfo != NULL) {
226  strCopy (pdata->title, pInfo->getTitle());
227  strCopy (pdata->country, pInfo->getLastCountry());
228  pdata->birthdate = pInfo->getBirthdate();
229  if (strEqual (pdata->title, "w")) { strCopy (pdata->title, "w "); }
230  }
231  }
232  PlayerCount++;
233  return OK;
234 }
235 
236 
237 uint max(int a, int b) {return a<b ? b : a;}
238 
239 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
240 // Crosstable::AddResult()
241 // Adds a game result to the crosstable.
242 errorT
243 Crosstable::AddResult (uint gameNumber, idNumberT white, idNumberT black,
244  resultT result, uint round, dateT date)
245 {
246  // Find the two players in the player data:
247  int whiteIdx = -1;
248  int blackIdx = -1;
249  uint i;
250  for (i=0; i < PlayerCount; i++) {
251  if (PlayerData[i]->id == white) { whiteIdx = i; break; }
252  }
253  for (i=0; i < PlayerCount; i++) {
254  if (PlayerData[i]->id == black) { blackIdx = i; break; }
255  }
256 
257  // Both players must exist in the crosstable:
258  if (whiteIdx < 0 || blackIdx < 0) { return ERROR_NotFound; }
259 
260  // The two players must actually be different:
261  if (whiteIdx == blackIdx) { return ERROR_Corrupt; }
262 
263  playerDataT * pwhite = PlayerData[whiteIdx];
264  playerDataT * pblack = PlayerData[blackIdx];
265 
266  // The number of prior encounters must be consistent:
267  ASSERT (pwhite->clashCount[blackIdx] == pblack->clashCount[whiteIdx]);
268  clashT * whiteClash = new clashT;
269 
270  if (pwhite->firstClash[blackIdx] == NULL) { // New head of list:
271  pwhite->firstClash[blackIdx] = whiteClash;
272  } else {
273  pwhite->lastClash[blackIdx]->next = whiteClash;
274  }
275  whiteClash->next = NULL;
276  pwhite->lastClash[blackIdx] = whiteClash;
277 
278  clashT * blackClash = new clashT;
279  if (pblack->firstClash[whiteIdx] == NULL) { // New head of list:
280  pblack->firstClash[whiteIdx] = blackClash;
281  } else {
282  pblack->lastClash[whiteIdx]->next = blackClash;
283  }
284  blackClash->next = NULL;
285  pblack->lastClash[whiteIdx] = blackClash;
286 
287  whiteClash->result = result;
288  blackClash->result = RESULT_OPPOSITE[result];
289  whiteClash->gameNum = gameNumber;
290  blackClash->gameNum = gameNumber;
291  whiteClash->opponent = blackIdx;
292  blackClash->opponent = whiteIdx;
293  whiteClash->color = WHITE;
294  blackClash->color = BLACK;
295  whiteClash->round = round;
296  blackClash->round = round;
297  if (round > 0 && round < CROSSTABLE_MaxRounds) {
298  pwhite->roundClash[round] = whiteClash;
299  pblack->roundClash[round] = blackClash;
300  if (round > MaxRound) { MaxRound = round; }
301  }
302  pwhite->clashCount[blackIdx]++;
303  pblack->clashCount[whiteIdx]++;
304  if (pwhite->clashCount[blackIdx] > MaxClashes) {
305  MaxClashes = pwhite->clashCount[blackIdx];
306  }
307  pwhite->gameCount++;
308  pblack->gameCount++;
309 
310  // Update averages of opponents ratings for performance stats:
311  if (result && pblack->elo > 0) {
312  pwhite->oppEloCount++;
313  pwhite->oppEloTotal += OpponentElo(pwhite->elo, pblack->elo);
314  }
315  if (result && pwhite->elo > 0) {
316  pblack->oppEloCount++;
317  pblack->oppEloTotal += OpponentElo(pblack->elo, pwhite->elo);
318  }
319 
320  if (FirstDate == ZERO_DATE) { FirstDate = date; }
321  if (date != ZERO_DATE && date < FirstDate) {
322  FirstDate = date;
323  }
324 
325  switch (result) {
326  case RESULT_White:
327  pwhite->score += (ThreeWin ? 6 : 2);
328  if (pblack->elo > 0) {
329  pwhite->oppEloScore += 2;
330  }
331  break;
332  case RESULT_Black:
333  pblack->score += (ThreeWin ? 6 : 2);
334  if (pwhite->elo > 0) {
335  pblack->oppEloScore += 2;
336  }
337  break;
338  case RESULT_Draw:
339  pwhite->score += (ThreeWin ? 2 : 1);
340  pblack->score += (ThreeWin ? 2 : 1);
341  if (pblack->elo > 0) {
342  pwhite->oppEloScore ++;
343  }
344  if (pwhite->elo > 0) {
345  pblack->oppEloScore ++;
346  }
347  break;
348  default:
349  break; // Nothing.
350  }
351  ResultCount[result]++;
352  GameCount++;
353  return OK;
354 }
355 
356 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
357 // Crosstable::Tiebreaks()
358 // Computes the tiebreak score for all players.
359 void
360 Crosstable::Tiebreaks (crosstableModeT mode)
361 {
362  uint player;
363  for (player = 0; player < PlayerCount; player++) {
364  playerDataT * pd = PlayerData[player];
365  pd->tiebreak = 0;
366  uint tb = 0;
367  // Tiebreaks are meaningless for Knockout tables:
368  if (mode == CROSSTABLE_Knockout) { continue; }
369 
370  for (uint opp = 0; opp < PlayerCount; opp++) {
371  if (opp == player) { continue; }
372  clashT * clash = pd->firstClash[opp];
373  while (clash != NULL) {
374  uint oppScore = PlayerData[opp]->score;
375  if (mode == CROSSTABLE_Swiss) {
376  // For Swiss, just do sum of opponent scores:
377  tb += PlayerData[opp]->score;
378  } else {
379  // AllPlayAll mode: do Sonneborn-Berger:
380  if (clash->result == RESULT_White) {
381  tb += oppScore + oppScore;
382  } else if (clash->result == RESULT_Draw) {
383  tb += oppScore;
384  }
385  }
386  clash = clash->next;
387  }
388  }
389  pd->tiebreak = tb;
390  }
391 }
392 
393 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
394 // Crosstable::BestMode():
395 // Returns the best mode of table to use for this tournament:
396 // All-play-all, Swiss or Knockout.
397 // XXX Currently never chooses Knockout, fix this sometime...
400 {
401  // If 12 players of less, use all-play-all:
402  if (PlayerCount <= 12) { return CROSSTABLE_AllPlayAll; }
403  // If more than 30 players, use Swiss:
404  if (PlayerCount > 30) { return CROSSTABLE_Swiss; }
405  // If less than 5 games per player on average, use Swiss:
406  if ((GameCount / PlayerCount) < 5) { return CROSSTABLE_Swiss; }
407  // If less than half the number of games in a complete all-play-all
408  // tournament, use Swiss:
409  uint completeAllPlayAll = (PlayerCount * (PlayerCount - 1)) / 2;
410  if (GameCount < completeAllPlayAll / 2) { return CROSSTABLE_Swiss; }
411  // Otherwise, use all-play-all:
412  return CROSSTABLE_AllPlayAll;
413 }
414 
415 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416 // Crosstable::AvgRating()
417 // Returns the average Elo rating of all players in the
418 // tournament who have a rating. Players with no rating
419 // are ignored.
420 eloT
422 {
423  uint count = 0;
424  uint total = 0;
425  for (uint i=0; i < PlayerCount; i++) {
426  if (PlayerData[i]->elo > 0) { total += PlayerData[i]->elo; count++; }
427  }
428  if (count == 0) { return 0; }
429  return (eloT) (total / count);
430 }
431 
432 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
433 // Crosstable::PrintTable()
434 // Prints the crosstable to a self-extending DString.
435 // The format can be plain text or hypertext with player and game tags,
436 // depending on the value of the OutputFormat member variable.
437 void
438 Crosstable::PrintTable (DString * dstr, crosstableModeT mode, uint playerLimit, int currentGame)
439 {
440  CurrentGame = currentGame;
441  if (playerLimit == 0 || playerLimit > PlayerCount) {
442  playerLimit = PlayerCount;
443  }
444  if (playerLimit < 2) { return; }
445 
446  if (mode == CROSSTABLE_Auto) { mode = BestMode(); }
447 
448  // Sort the players by score, name or rating:
449  Tiebreaks (mode);
450  uint player;
451  for (player=0; player < PlayerCount; player++) {
452  SortedIndex[player] = player;
453  InvertedIndex[player] = player;
454  }
455  for (uint first=0; first < PlayerCount-1; first++) {
456  for (uint second = first+1; second < PlayerCount; second++) {
457  if (comparePlayerData (PlayerData[SortedIndex[first]],
458  PlayerData[SortedIndex[second]],
459  SortOption) > 0) {
460  uint temp = SortedIndex[first];
461  SortedIndex[first] = SortedIndex[second];
462  SortedIndex[second] = temp;
463  }
464  }
465  }
466  for (player=0; player < PlayerCount; player++) {
467  InvertedIndex[SortedIndex[player]] = player;
468  }
469 
470  PlayerNumWidth = 2;
471  if (playerLimit > 99) { PlayerNumWidth = 3; }
472 
473  // Determine the longest player name:
474  LongestNameLen = 0;
475  for (player = 0; player < PlayerCount; player++) {
476  uint len = strLength (PlayerData[player]->name);
477  if (len > LongestNameLen) { LongestNameLen = len; }
478  }
479 
480  // Determine if any players have elo rating, title, country:
481  PrintRatings = false;
482  PrintTitles = false;
483  PrintCountries = false;
484  PrintAges = false;
485  PrintTiebreaks = true;
486  PrintTallies = true;
487  for (player = 0; player < PlayerCount; player++) {
488  playerDataT * pd = PlayerData[player];
489  if (pd->elo > 0) { PrintRatings = true; }
490  if (pd->title[0] != 0) { PrintTitles = true; }
491  if (pd->country[0] != 0) { PrintCountries = true; }
492  if (pd->birthdate != ZERO_DATE) {
493  PrintAges = true;
494  int age = (int) date_GetYear(FirstDate);
495  age -= (int) date_GetYear (pd->birthdate);
496  if (date_GetMonth(pd->birthdate) > date_GetMonth(FirstDate)) {
497  age--;
498  }
499  pd->ageInYears = age;
500  }
501  }
502  if (! ShowElos) { PrintRatings = false; }
503  if (! ShowTitles) { PrintTitles = false; }
504  if (! ShowCountries) { PrintCountries = false; }
505  if (! ShowTallies) { PrintTallies = false; }
506  if (! ShowAges) { PrintAges = false; }
507  if (! ShowTiebreaks) { PrintTiebreaks = false; }
508  if (mode == CROSSTABLE_Knockout) { PrintTiebreaks = false; }
509 
510  // Print the table header:
511  StartTable = "";
512  EndTable = "";
513  StartRow = "";
514  EndRow = "";
515  NewLine = "\n";
516  BlankRowLine = "\n";
517  StartCol = "";
518  EndCol = "";
519  StartRightCol = "";
520  EndRightCol = "";
521  StartBoldCol = "";
522  EndBoldCol = "";
523 
524  if (OutputFormat == CROSSTABLE_Hypertext) {
525  NewLine = BlankRowLine = "<br>";
526  }
527  if (OutputFormat == CROSSTABLE_Html) {
528  StartTable = "\n<p><table border=1 cellspacing=0 cellpadding=4>\n";
529  EndTable = "</table></p>\n";
530  StartRow = "<tr>";
531  EndRow = "</tr>";
532  NewLine = "\n";
533  BlankRowLine = "<tr></tr>\n";
534  StartCol = "<td>";
535  EndCol = "</td>";
536  StartRightCol = "<td align=right>";
537  EndRightCol = "</td>";
538  StartBoldCol = "<th>";
539  EndBoldCol = "</th>";
540  }
541  if (OutputFormat == CROSSTABLE_LaTeX) {
542  StartTable = "";
543  EndTable = "\\end{tabular}\n\n";
544  StartRow = "";
545  EndRow = " \\\\";
546  NewLine = "\n";
547  BlankRowLine = "\\\\\n";
548  StartCol = "";
549  EndCol = " &";
550  StartRightCol = "";
551  EndRightCol = " &";
552  StartBoldCol = "\\bf ";
553  EndBoldCol = " &";
554  }
555 
556  // LineWidth is used to determine length of line of dashes to print.
557  LineWidth = LongestNameLen + 6;
558  if (PrintRatings) { LineWidth += 16; }
559  if (PrintTitles) { LineWidth += 4; }
560  if (PrintCountries) { LineWidth += 4; }
561  if (PrintAges) { LineWidth += 4; }
562 
563  if (mode == CROSSTABLE_Swiss) {
564  LineWidth += 16 + PlayerNumWidth;
565  LineWidth += (PlayerNumWidth + (SwissColors ? 3 : 2)) * MaxRound;
566  if (PrintTiebreaks) { LineWidth += 5; }
567  } else if (mode == CROSSTABLE_AllPlayAll) {
568  LineWidth += 16 + PlayerNumWidth;
569  if (playerLimit == 2) {
570  LineWidth += (MaxClashes + 1);
571  } else {
572  LineWidth += (playerLimit * (MaxClashes + 1));
573  }
574  if (PrintTiebreaks) { LineWidth += 7; }
575  } else { // Knockout
576  LineWidth = (LongestNameLen * 2) + 17 + MaxClashes;
577  if (PrintRatings) { LineWidth += 10; }
578  if (PrintTitles) { LineWidth += 8; }
579  if (PrintCountries) { LineWidth += 8; }
580  if (PrintAges) { LineWidth += 8; }
581  }
582 
583  switch (mode) {
585  PrintAllPlayAll (dstr, playerLimit);
586  break;
587  case CROSSTABLE_Knockout:
588  PrintKnockout (dstr, playerLimit);
589  break;
590  case CROSSTABLE_Swiss:
591  case CROSSTABLE_Auto:
592  PrintSwiss (dstr, playerLimit);
593  break;
594  }
595 
596  char stemp [100];
597  if (GameCount > 1) {
598  sprintf (stemp, "%u game%s: %s%u %s%u %s%u",
599  GameCount, strPlural (GameCount),
600  OutputFormat == CROSSTABLE_LaTeX ? "{\\tt +}" : "+",
601  ResultCount[RESULT_White],
602  OutputFormat == CROSSTABLE_LaTeX ? "{\\tt =}" : "=",
603  ResultCount[RESULT_Draw],
604  OutputFormat == CROSSTABLE_LaTeX ? "{\\tt -}" : "-",
605  ResultCount[RESULT_Black]);
606  dstr->Append (stemp);
607  if (ResultCount[RESULT_None] > 0) {
608  sprintf (stemp, " %s%u",
609  OutputFormat == CROSSTABLE_LaTeX ? "{\\tt *}" : "*",
610  ResultCount[RESULT_None]);
611  dstr->Append (stemp);
612  }
613  dstr->Append (NewLine);
614  }
615  return;
616 }
617 
618 void
619 Crosstable::PrintDashesLine (DString * dstr)
620 {
621  // Print line of dashes, if not in HTML or LaTeX:
622  if (OutputFormat == CROSSTABLE_LaTeX) {
623  dstr->Append ("\\hline\n");
624  return;
625  }
626  if (OutputFormat == CROSSTABLE_Html) {
627  return;
628  }
629  for (uint i=0; i < LineWidth; i++) {
630  dstr->AddChar ('-');
631  }
632  dstr->Append (NewLine);
633 }
634 
635 void
636 Crosstable::PrintPlayer (DString * dstr, playerDataT * pdata)
637 {
638  char stemp[1000];
639  if (OutputFormat == CROSSTABLE_Hypertext) {
640  sprintf (stemp, "<pi %s>", pdata->name);
641  dstr->Append (stemp);
642  }
643  sprintf (stemp, "%-*s ", LongestNameLen, pdata->name);
644  dstr->Append (StartCol, stemp, EndCol);
645 
646  if (PrintRatings) {
647  if (pdata->elo) {
648  sprintf (stemp, "%4u ", pdata->elo);
649  } else {
650  if (OutputFormat == CROSSTABLE_Html) {
651  strcpy (stemp, " - ");
652  } else {
653  strcpy (stemp, " ");
654  }
655  }
656  dstr->Append (StartRightCol, stemp, EndRightCol);
657  }
658 
659  // if exporting to html, don't print blank fields
660  // as firefox doesn't make a grid box for blanks S.A.
661 
662  if (PrintTitles) {
663  if (OutputFormat == CROSSTABLE_Html && !strCompare(pdata->title,"")) {
664  sprintf (stemp, " - ");
665  } else {
666  sprintf (stemp, "%3s ", pdata->title);
667  }
668  dstr->Append (StartCol, stemp, EndCol);
669  }
670  if (PrintAges) {
671  if (pdata->ageInYears == 0) {
672  if (OutputFormat == CROSSTABLE_Html) {
673  sprintf (stemp, " - ");
674  } else {
675  strCopy (stemp, " ");
676  }
677  } else {
678  sprintf (stemp, "%3d ", pdata->ageInYears);
679  }
680  dstr->Append (StartCol, stemp, EndCol);
681  }
682  if (PrintCountries) {
683  if (OutputFormat == CROSSTABLE_Html && !strCompare(pdata->country,"")) {
684  sprintf (stemp, " - ");
685  } else {
686  sprintf (stemp, "%-3s ", pdata->country);
687  }
688  dstr->Append (StartCol, stemp, EndCol);
689  }
690  if (OutputFormat == CROSSTABLE_Hypertext) { dstr->Append ("</pi>"); }
691 }
692 
693 void
694 Crosstable::PrintPerformance (DString * dstr, playerDataT * pdata)
695 {
696  if (!PrintRatings) { return; }
697  if (!pdata->oppEloCount) { return; }
698 
699  int oppAvgRating = pdata->oppEloTotal / pdata->oppEloCount;
700  int percentage = pdata->oppEloScore * 50 + pdata->oppEloCount/2;
701  percentage = percentage / pdata->oppEloCount;
702  int performance = Performance(oppAvgRating, percentage);
703  if (performance > 0 && performance < 5000) {
704  char stemp [20];
705  if (pdata->elo) {
706  int change = RatingChange (pdata->elo, oppAvgRating,
707  percentage, pdata->oppEloCount);
708  sprintf (stemp, "%4d %+3d", performance, change);
709  } else {
710  sprintf (stemp, "%4d ", performance);
711  }
712  dstr->Append (" ", StartRightCol, stemp, EndRightCol);
713  }
714 }
715 
716 // Calculate and format the percentage performance of the player 8 Points from 10 Games = 80%
717 void
718 Crosstable::PrintScorePercentage (DString * dstr, playerDataT * pdata)
719 {
720  char stemp [20];
721  uint per_score;
722 
723  per_score = ( pdata->gameCount > 0) ? pdata->score * 500 / pdata->gameCount : 0;
724  sprintf (stemp, "%3d%c%1d%%", per_score / 10 , DecimalPointChar, per_score % 10);
725  dstr->Append (" ", StartRightCol, stemp, EndRightCol);
726 }
727 
728 void
729 Crosstable::PrintAllPlayAll (DString * dstr, uint playerLimit)
730 {
731  char stemp [1000];
732  uint player;
733 
734  dstr->Append (StartTable);
735  if (OutputFormat == CROSSTABLE_LaTeX) {
736  dstr->Append ("\\begin{tabular}{rl");
737  if (PrintRatings) { dstr->Append ("r"); }
738  if (PrintTitles) { dstr->Append ("r"); }
739  if (PrintAges) { dstr->Append ("r"); }
740  if (PrintCountries) { dstr->Append ("l"); }
741  dstr->Append ("r@{ / }r");
742  if (PrintTiebreaks) { dstr->Append ("r"); }
743  for (uint i=0; i < playerLimit; i++) {
744  dstr->Append ("c");
745  if (i < playerLimit-1) { dstr->Append ("@{ }"); }
746  }
747  if (PrintRatings) { dstr->Append ("r"); }
748  dstr->Append ("r}\n");
749  }
750  dstr->Append (StartRow);
751  if (OutputFormat == CROSSTABLE_Html) {
752  dstr->Append ("<th></th> <th>Player</th> ");
753  } else if (OutputFormat == CROSSTABLE_LaTeX) {
754  dstr->Append (" & \\bf Player & ");
755  } else {
756  strPad (stemp, "", LongestNameLen + 2 + PlayerNumWidth, ' ');
757  dstr->Append (stemp);
758  }
759  if (PrintRatings) {
760  dstr->Append (StartBoldCol, " Rtng", EndBoldCol);
761  }
762  if (PrintTitles) {
763  dstr->Append (StartBoldCol, " Ti", EndBoldCol);
764  }
765  if (PrintAges) {
766  dstr->Append (StartBoldCol, " Age", EndBoldCol);
767  }
768  if (PrintCountries) {
769  dstr->Append (StartBoldCol, " Nat", EndBoldCol);
770  }
771  if (OutputFormat == CROSSTABLE_LaTeX) {
772  // Todo : fix LateX Score column alignment with 3 points for win.
773  dstr->Append (" \\multicolumn{2}{c}{\\bf Score} & ");
774  } else {
775  if (ThreeWin)
776  dstr->Append (" ", StartBoldCol, "Score", EndBoldCol, " ");
777  else
778  dstr->Append (" ", StartBoldCol, " Score ", EndBoldCol, " ");
779  }
780  if (PrintTiebreaks) {
781  dstr->Append (StartBoldCol, " (Tie) ", EndBoldCol);
782  }
783 
784  for (player = 0; player < playerLimit; player++) {
785  strPad (stemp, PlayerData[SortedIndex[player]]->name, MaxClashes, ' ');
786  if (APAColumnNums) {
787  // Print numbers instead of names over columns:
788  strPad (stemp, "", MaxClashes, ' ');
789  uint pnum = player + 1;
790  stemp[MaxClashes-1] = (pnum % 10) + '0';
791  if (MaxClashes >= 2 && pnum >= 10) {
792  stemp[MaxClashes-2] = ((pnum / 10) % 10) + '0';
793  }
794  if (MaxClashes >= 3 && pnum >= 100) {
795  stemp[MaxClashes-3] = ((pnum / 10) % 10) + '0';
796  }
797  }
798  if (playerLimit == 2) {
799  // Make two-player crosstable look better:
800  player = 1;
801  strPad (stemp,
802  "12345678901234567890123456789012345678901234567890",
803  MaxClashes, ' ');
804  }
805  if (OutputFormat == CROSSTABLE_LaTeX) {
806  dstr->Append (" \\tt ", stemp, " &");
807  } else {
808  dstr->Append (" ", StartBoldCol, stemp, EndBoldCol);
809  }
810  }
811  if (PrintRatings) {
812  dstr->Append (" ", StartBoldCol, "Perf Chg Percnt", EndBoldCol);
813  } else
814  dstr->Append (" ", StartBoldCol, "Percnt", EndBoldCol);
815  if (PrintTallies && OutputFormat == CROSSTABLE_Html) {
816  dstr->Append (" ", StartBoldCol, "+/-/=", EndBoldCol);
817  }
818  dstr->Append (EndRow, NewLine);
819 
820  PrintDashesLine (dstr);
821 
822  // Print the rows of players and results:
823  uint previousScore = 0;
824  for (player = 0; player < playerLimit; player++) {
825  uint index = SortedIndex[player];
826  playerDataT * pdata = PlayerData[index];
827 
828  // Print a blank line if we are at a new score group:
829  if (SeparateScoreGroups && SortOption == CROSSTABLE_SortScore) {
830  if (player > 0 && pdata->score != previousScore) {
831  dstr->Append (BlankRowLine);
832  }
833  }
834  previousScore = pdata->score;
835 
836  sprintf (stemp, "%*u: ", PlayerNumWidth, player+1);
837  dstr->Append (StartRow, StartRightCol, stemp, EndRightCol);
838 
839  PrintPlayer (dstr, pdata);
840 
841  if (OutputFormat == CROSSTABLE_LaTeX) {
842  sprintf (stemp, " %2u%c%c ", pdata->score / 2, DecimalPointChar,
843  (pdata->score & 1 ? '5' : '0'));
844  dstr->Append (StartRightCol, stemp, EndRightCol);
845  sprintf (stemp, " %2u ", pdata->gameCount);
846  dstr->Append (StartRightCol, stemp, EndRightCol);
847  } else {
848  if (ThreeWin) {
849  sprintf (stemp, " %2u%c%c ",
850  pdata->score / 2, DecimalPointChar,
851  (pdata->score & 1 ? '5' : '0'));
852  } else {
853  sprintf (stemp, " %2u%c%c / %2u ",
854  pdata->score / 2, DecimalPointChar,
855  (pdata->score & 1 ? '5' : '0'), pdata->gameCount);
856  }
857  dstr->Append (StartRightCol, stemp, EndRightCol);
858  }
859  if (PrintTiebreaks) {
860  sprintf (stemp, "%3u%c%02u ", pdata->tiebreak / 4,
861  DecimalPointChar, (pdata->tiebreak % 4) * 25);
862  dstr->Append (StartRightCol, stemp, EndRightCol);
863  }
864 
865  uint r_won = 0, r_loss = 0, r_draw = 0;
866  for (uint oppCount = 0; oppCount < playerLimit; oppCount++) {
867  if (playerLimit == 2 && oppCount == player) { continue; }
868  uint opp = SortedIndex[oppCount];
869  dstr->AddChar (' ');
870  dstr->Append (StartRightCol);
871  clashT * clash = pdata->firstClash[opp];
872 
873  for (uint count = 0; count < MaxClashes; count++) {
874  if (clash != NULL) {
875  if (OutputFormat == CROSSTABLE_Hypertext) {
876  if (CurrentGame == clash->gameNum)
877  sprintf(stemp, "<green><g_%u>%c</g></green>",
878  clash->gameNum, RESULT_CHAR[clash->result]);
879  else
880  sprintf(stemp, "<blue><g_%u>%c</g></blue>",
881  clash->gameNum, RESULT_CHAR[clash->result]);
882  dstr->Append (stemp);
883  } else {
884  dstr->AddChar (RESULT_CHAR[clash->result]);
885  }
886  switch (clash->result) {
887  case 1:
888  r_won++;
889  break;
890  case 2:
891  r_loss++;
892  break;
893  case 3:
894  r_draw++;
895  break;
896  }
897  clash = clash->next;
898  } else {
899  dstr->AddChar (index == opp ? 'X' : '.');
900  }
901  }
902  dstr->Append (EndCol);
903  }
904 
905  PrintPerformance (dstr, pdata);
906  PrintScorePercentage (dstr, pdata);
907 
908  if (PrintTallies) {
909  dstr->Append (StartCol);
910  sprintf (stemp, " (+%u -%u =%u)", r_won, r_loss, r_draw);
911  dstr->Append (stemp);
912  dstr->Append (EndCol);
913  }
914 
915  dstr->Append (EndRow, NewLine);
916  }
917  PrintDashesLine (dstr);
918  dstr->Append (EndTable);
919 }
920 
921 void
922 Crosstable::PrintSwiss (DString * dstr, uint playerLimit)
923 {
924  char stemp [1000];
925  uint player;
926 
927  const char * resultStr [NUM_RESULT_TYPES];
928  if (OutputFormat == CROSSTABLE_LaTeX) {
929  resultStr[RESULT_White] = "{\\tt +}";
930  resultStr[RESULT_Draw] = "{\\tt =}";
931  resultStr[RESULT_Black] = "{\\tt -}";
932  resultStr[RESULT_None] = "{\\tt *}";
933  } else {
934  resultStr[RESULT_White] = "+";
935  resultStr[RESULT_Draw] = "=";
936  resultStr[RESULT_Black] = "-";
937  resultStr[RESULT_None] = "*";
938  }
939 
940  dstr->Append (StartTable);
941  if (OutputFormat == CROSSTABLE_LaTeX) {
942  dstr->Append ("\\begin{tabular}{rl");
943  if (PrintRatings) { dstr->Append ("r"); }
944  if (PrintTitles) { dstr->Append ("r"); }
945  if (PrintAges) { dstr->Append ("r"); }
946  if (PrintCountries) { dstr->Append ("l"); }
947  dstr->Append ("r@{ / }r");
948  if (PrintTiebreaks) { dstr->Append ("r"); }
949  for (uint i=0; i < MaxRound; i++) {
950  dstr->Append ("r");
951  if (i < MaxRound-1) { dstr->Append ("@{ }"); }
952  }
953  if (PrintRatings) { dstr->Append ("r"); }
954  dstr->Append ("r}\n");
955  }
956  dstr->Append (StartRow);
957  if (OutputFormat == CROSSTABLE_Html) {
958  dstr->Append ("<th></th> <th>Player</th> ");
959  } else if (OutputFormat == CROSSTABLE_LaTeX) {
960  dstr->Append (" & \\bf Player & ");
961  } else {
962  strPad (stemp, "", LongestNameLen + 2 + PlayerNumWidth, ' ');
963  dstr->Append (stemp);
964  }
965  if (PrintRatings) {
966  dstr->Append (StartBoldCol, " Rtng", EndBoldCol);
967  }
968  if (PrintTitles) {
969  dstr->Append (StartBoldCol, " Ti", EndBoldCol);
970  }
971  if (PrintAges) {
972  dstr->Append (StartBoldCol, " Age", EndBoldCol);
973  }
974  if (PrintCountries) {
975  dstr->Append (StartBoldCol, " Nat", EndBoldCol);
976  }
977  if (OutputFormat == CROSSTABLE_LaTeX) {
978  dstr->Append (" \\multicolumn{2}{c}{\\bf Score} & ");
979  } else {
980  if (ThreeWin)
981  dstr->Append (" ", StartBoldCol, "Score", EndBoldCol, " ");
982  else
983  dstr->Append (" ", StartBoldCol, " Score ", EndBoldCol, " ");
984  }
985  if (PrintTiebreaks) {
986  dstr->Append (StartBoldCol, "(Tie)", EndBoldCol);
987  }
988 
989  for (uint round = 1; round <= MaxRound; round++) {
990  if (OutputFormat == CROSSTABLE_LaTeX) {
991  dstr->Append (" \\multicolumn{1}{c}{\\bf ", round, "} & ");
992  } else {
993  sprintf (stemp, " %s%*d ", SwissColors ? " " : "",
994  PlayerNumWidth, round);
995  dstr->Append (StartBoldCol, stemp, EndBoldCol);
996  }
997  }
998  if (PrintRatings) {
999  dstr->Append (" ", StartBoldCol, "Perf Chg Percnt", EndBoldCol);
1000  } else
1001  dstr->Append (" ", StartBoldCol, "Percnt", EndBoldCol);
1002  if (PrintTallies && OutputFormat == CROSSTABLE_Html) {
1003  dstr->Append (" ", StartBoldCol, "+/-/=", EndBoldCol);
1004  }
1005  dstr->Append (EndRow, NewLine);
1006 
1007  PrintDashesLine (dstr);
1008 
1009  // Print the rows of players and results:
1010  uint previousScore = 0;
1011  for (player = 0; player < playerLimit; player++) {
1012  uint index = SortedIndex[player];
1013  playerDataT * pdata = PlayerData[index];
1014 
1015  // Print a blank line if we are at a new score group:
1016  if (SeparateScoreGroups && SortOption == CROSSTABLE_SortScore) {
1017  if (player > 0 && pdata->score != previousScore) {
1018  dstr->Append (BlankRowLine);
1019  }
1020  }
1021  previousScore = pdata->score;
1022 
1023  sprintf (stemp, "%*u: ", PlayerNumWidth, player+1);
1024  dstr->Append (StartRow, StartRightCol, stemp, EndRightCol);
1025 
1026  PrintPlayer (dstr, pdata);
1027 
1028  if (OutputFormat == CROSSTABLE_LaTeX) {
1029  sprintf (stemp, " %2u%c%c ", pdata->score / 2, DecimalPointChar,
1030  (pdata->score & 1 ? '5' : '0'));
1031  dstr->Append (StartRightCol, stemp, EndRightCol);
1032  sprintf (stemp, " %2u ", pdata->gameCount);
1033  dstr->Append (StartRightCol, stemp, EndRightCol);
1034  } else {
1035  if (ThreeWin) {
1036  sprintf (stemp, " %2u%c%c ",
1037  pdata->score / 2, DecimalPointChar,
1038  (pdata->score & 1 ? '5' : '0'));
1039  } else {
1040  sprintf (stemp, " %2u%c%c / %2u ",
1041  pdata->score / 2, DecimalPointChar,
1042  (pdata->score & 1 ? '5' : '0'), pdata->gameCount);
1043  }
1044  dstr->Append (StartRightCol, stemp, EndRightCol);
1045  }
1046  if (PrintTiebreaks) {
1047  sprintf (stemp, "%2u%c%c ", pdata->tiebreak / 2,
1048  DecimalPointChar, (pdata->tiebreak & 1 ? '5' : '0'));
1049  dstr->Append (StartRightCol, stemp, EndRightCol);
1050  }
1051 
1052  uint r_won = 0, r_loss = 0, r_draw = 0;
1053  for (uint round = 1; round <= MaxRound; round++) {
1054  clashT * clash = pdata->roundClash[round];
1055  dstr->AddChar (' ');
1056  dstr->Append (StartRightCol);
1057  if (clash == NULL) {
1058  dstr->Append ("...");
1059  if (PlayerNumWidth == 3) { dstr->AddChar ('.'); }
1060  if (SwissColors) { dstr->AddChar ('.'); }
1061  } else {
1062  if (OutputFormat == CROSSTABLE_Hypertext) {
1063  if (CurrentGame == clash->gameNum)
1064  sprintf (stemp, "<green><g_%u>", clash->gameNum);
1065  else
1066  sprintf (stemp, "<blue><g_%u>", clash->gameNum);
1067  dstr->Append (stemp);
1068  }
1069  if (SwissColors) {
1070  sprintf (stemp, "%*d%c%s", PlayerNumWidth,
1071  InvertedIndex[clash->opponent] + 1,
1072  clash->color == WHITE ? 'w' : 'b',
1073  resultStr[clash->result]);
1074  } else {
1075  sprintf (stemp, "%*d%s", PlayerNumWidth,
1076  InvertedIndex[clash->opponent] + 1,
1077  resultStr[clash->result]);
1078  }
1079  dstr->Append (stemp);
1080  if (OutputFormat == CROSSTABLE_Hypertext) {
1081  if (CurrentGame == clash->gameNum)
1082  dstr->Append ("</g></green>");
1083  else
1084  dstr->Append ("</g></blue>");
1085  }
1086  switch (clash->result) {
1087  case 1:
1088  r_won++; break;
1089  case 2:
1090  r_loss++; break;
1091  case 3:
1092  r_draw++; break;
1093  }
1094  }
1095  dstr->Append (EndCol);
1096  }
1097  PrintPerformance (dstr, pdata);
1098  PrintScorePercentage (dstr, pdata);
1099 
1100  if (PrintTallies) {
1101  dstr->Append (StartCol);
1102  sprintf (stemp, " (+%u -%u =%u)", r_won, r_loss, r_draw);
1103  dstr->Append (stemp);
1104  dstr->Append (EndCol);
1105  }
1106 
1107  dstr->Append (EndRow, NewLine);
1108  }
1109 
1110  PrintDashesLine (dstr);
1111  dstr->Append (EndTable);
1112 }
1113 
1114 
1115 void
1116 Crosstable::PrintKnockout (DString * dstr, uint playerLimit)
1117 {
1118  char stemp [1000];
1119  uint player;
1120 
1121  for (uint round = 1; round <= MaxRound; round++) {
1122  if (OutputFormat == CROSSTABLE_LaTeX) {
1123  dstr->Append ("\n\n", round, ":\n\n");
1124  } else {
1125  dstr->Append (round, ":", NewLine);
1126  }
1127  dstr->Append (StartTable);
1128  if (OutputFormat == CROSSTABLE_LaTeX) {
1129  dstr->Append ("\\begin{tabular}{l");
1130  if (PrintRatings) { dstr->Append ("r"); }
1131  if (PrintTitles) { dstr->Append ("r"); }
1132  if (PrintAges) { dstr->Append ("r"); }
1133  if (PrintCountries) { dstr->Append ("l"); }
1134  dstr->Append ("@{\\hspace{4ex}}lr@{ / }r@{\\hspace{4ex}}l");
1135  if (PrintRatings) { dstr->Append ("r"); }
1136  if (PrintTitles) { dstr->Append ("r"); }
1137  if (PrintAges) { dstr->Append ("r"); }
1138  if (PrintCountries) { dstr->Append ("l"); }
1139  dstr->Append ("r}\n");
1140  }
1141  PrintDashesLine (dstr);
1142  for (player = 0; player < playerLimit; player++) {
1143  PlayerData[player]->printed = false;
1144  }
1145  for (player = 0; player < playerLimit; player++) {
1146  uint index = SortedIndex[player];
1147  playerDataT * pdata = PlayerData[index];
1148  clashT * clash = pdata->roundClash[round];
1149  if (clash == NULL) { continue; }
1150  if (pdata->printed) { continue; }
1151  uint opponent = clash->opponent;
1152  // if black first, skip this game till white is first
1153  if (pdata->firstClash[opponent]->color == 1) { continue; }
1154  uint score = 0;
1155  uint nGames = 0;
1156  clash = pdata->firstClash[opponent];
1157  while (clash != 0) {
1158  if (clash->round == round) {
1159  score += RESULT_SCORE[clash->result];
1160  nGames++;
1161  }
1162  clash = clash->next;
1163  }
1164  // Skip this to allow white to be shown first
1165  // if (score < nGames) { continue; }
1166  dstr->Append (StartRow);
1167  PrintPlayer (dstr, pdata);
1168 
1169  dstr->Append (StartCol, " ");
1170  if (OutputFormat == CROSSTABLE_LaTeX) { dstr->Append ("{\\tt "); }
1171  clash = pdata->firstClash[opponent];
1172  for (uint count = 0; count < MaxClashes; count++) {
1173  while (clash != NULL && clash->round != round) {
1174  clash = clash->next;
1175  }
1176  if (clash != NULL) {
1177  if (OutputFormat == CROSSTABLE_Hypertext) {
1178  if (CurrentGame == clash->gameNum)
1179  sprintf (stemp, "<green><g_%u>%c</g></green>",
1180  clash->gameNum,
1181  RESULT_CHAR[clash->result]);
1182  else
1183  sprintf (stemp, "<blue><g_%u>%c</g></blue>",
1184  clash->gameNum,
1185  RESULT_CHAR[clash->result]);
1186  dstr->Append (stemp);
1187  } else {
1188  dstr->AddChar (RESULT_CHAR[clash->result]);
1189  }
1190  clash = clash->next;
1191  } else {
1192  dstr->AddChar (' ');
1193  }
1194  }
1195  if (OutputFormat == CROSSTABLE_LaTeX) { dstr->Append ("}"); }
1196  dstr->Append (" ", EndCol);
1197 
1198  if (OutputFormat == CROSSTABLE_LaTeX) {
1199  sprintf (stemp, " %2u%c%c ", score / 2, DecimalPointChar,
1200  (score & 1 ? '5' : '0'));
1201  dstr->Append (StartRightCol, stemp, EndRightCol);
1202  sprintf (stemp, " %2u ", nGames);
1203  dstr->Append (StartRightCol, stemp, EndRightCol);
1204  } else {
1205  sprintf (stemp, "%2u%c%c / %2u ",
1206  score / 2, DecimalPointChar,
1207  (score & 1 ? '5' : '0'), nGames);
1208  dstr->Append (StartRightCol, stemp, EndRightCol);
1209  }
1210  PrintPlayer (dstr, PlayerData[opponent]);
1211  dstr->Append (EndRow, NewLine);
1212  pdata->printed = true;
1213  PlayerData[opponent]->printed = true;
1214  }
1215  PrintDashesLine (dstr);
1216  dstr->Append (EndTable, NewLine);
1217  }
1218 }
1219 
1220 #endif // WINCE
1221 //////////////////////////////////////////////////////////////////////
1222 // EOF: crosstab.cpp
1223 //////////////////////////////////////////////////////////////////////
uint date_GetYear(dateT date)
Definition: date.h:52
const errorT ERROR_Full
Definition: error.h:49
const uint CROSSTABLE_MaxPlayers
Definition: crosstab.h:26
clashT * lastClash[CROSSTABLE_MaxPlayers]
Definition: crosstab.h:68
uint oppEloScore
Definition: crosstab.h:66
byte resultT
Definition: common.h:187
crosstableModeT BestMode(void)
Definition: crosstab.cpp:399
uint strLength(const char *str)
Definition: misc.h:411
const colorT WHITE
Definition: common.h:207
eloT AvgRating()
Definition: crosstab.cpp:421
const char * getTitle() const
Definition: spellchk.cpp:388
idNumberT id
Definition: crosstab.h:57
bool strEqual(const char *str1, const char *str2)
Definition: misc.h:224
const errorT OK
Definition: error.h:23
const uint CROSSTABLE_MaxRounds
Definition: crosstab.h:27
const uint NUM_RESULT_TYPES
Definition: common.h:186
char * strDuplicate(const char *original)
Definition: misc.cpp:206
uint max(int a, int b)
Definition: crosstab.cpp:237
clashT * roundClash[CROSSTABLE_MaxRounds]
Definition: crosstab.h:70
colorT color
Definition: crosstab.h:34
uint dateT
Definition: common.h:147
#define ASSERT(f)
Definition: common.h:59
crosstableModeT
Definition: crosstab.h:49
const resultT RESULT_Black
Definition: common.h:191
names
Definition: tablebase.tcl:257
clashT * next
Definition: crosstab.h:36
const colorT BLACK
Definition: common.h:208
const resultT RESULT_OPPOSITE[4]
Definition: common.h:198
uint gameCount
Definition: crosstab.h:61
eloT elo
Definition: crosstab.h:59
class SpellChecker - name spelling
Definition: spellchk.h:259
uint score
Definition: crosstab.h:60
const resultT RESULT_Draw
Definition: common.h:192
uint32_t idNumberT
Definition: common.h:152
const dateT ZERO_DATE
Definition: date.h:35
uint oppEloTotal
Definition: crosstab.h:65
uint clashCount[CROSSTABLE_MaxPlayers]
Definition: crosstab.h:69
int ageInYears
Definition: crosstab.h:74
uint strPad(char *target, const char *original, int width, char padding)
Definition: misc.cpp:235
void AddChar(char ch)
Definition: dstring.h:32
const resultT RESULT_White
Definition: common.h:190
uint32_t uint
Definition: common.h:91
bool printed
Definition: crosstab.h:75
static uint Performance(uint oppAvg, uint percentage)
Definition: crosstab.cpp:36
static eloT OpponentElo(eloT player, eloT opponent)
Definition: crosstab.cpp:87
const char RESULT_CHAR[4]
Definition: common.h:195
int comparePlayerData(playerDataT *p1, playerDataT *p2, crosstableSortT option)
Definition: crosstab.cpp:105
char title[8]
Definition: crosstab.h:71
ushort eloT
Definition: common.h:164
uint gameNum
Definition: crosstab.h:32
const uint perf_elodiff[51]
Definition: crosstab.cpp:22
dateT birthdate
Definition: crosstab.h:73
char * name
Definition: crosstab.h:58
unsigned short errorT
Definition: error.h:20
uint tiebreak
Definition: crosstab.h:62
void Append(uint i)
Definition: dstring.h:46
static int RatingChange(eloT player, uint oppAvg, uint percentage, uint count)
Definition: crosstab.cpp:54
const uint RESULT_SCORE[4]
Definition: common.h:194
clashT * firstClash[CROSSTABLE_MaxPlayers]
Definition: crosstab.h:67
dateT getBirthdate() const
Definition: spellchk.cpp:461
Definition: tablebase.tcl:15
crosstableSortT
Definition: crosstab.h:39
const PlayerInfo * getPlayerInfo(const char *name, std::vector< const char *> *bio=0) const
Definition: spellchk.h:351
void strCopy(char *target, const char *original)
Definition: misc.h:298
void PrintTable(DString *dstr, crosstableModeT mode, uint playerLimit, int currentGame)
Definition: crosstab.cpp:438
const errorT ERROR_Corrupt
Definition: error.h:46
uint round
Definition: crosstab.h:35
errorT AddPlayer(idNumberT id, const char *name, eloT elo, const SpellChecker *)
Definition: crosstab.cpp:188
uint oppEloCount
Definition: crosstab.h:64
const char * strPlural(uint x)
Definition: misc.h:168
uint opponent
Definition: crosstab.h:33
const resultT RESULT_None
Definition: common.h:189
static uint FideCategory(eloT rating)
Definition: crosstab.cpp:77
char country[8]
Definition: crosstab.h:72
const errorT ERROR_NotFound
Definition: error.h:50
int strCompare(const char *s1, const char *s2)
Definition: misc.h:280
const char * getLastCountry() const
Definition: spellchk.cpp:415
uint date_GetMonth(dateT date)
Definition: date.h:61
resultT result
Definition: crosstab.h:31
class PlayerInfo - player informations
Definition: spellchk.h:233
errorT AddResult(uint gameNumber, idNumberT white, idNumberT black, resultT result, uint round, dateT date)
Definition: crosstab.cpp:243