Scid  4.6.5
optable.cpp
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////
2 //
3 // FILE: optable.cpp
4 // OpTable and OpLine class methods
5 //
6 // Part of: Scid (Shane's Chess Information Database)
7 // Version: 3.5
8 //
9 // Notice: Copyright (c) 2001-2003 Shane Hudson. All rights reserved.
10 //
11 // Author: Shane Hudson (sgh@users.sourceforge.net)
12 //
13 //////////////////////////////////////////////////////////////////////
14 
15 #include "optable.h"
16 #include "crosstab.h"
17 #include "dstring.h"
18 
19 uint
21 {
22  bool queens = MATSIG_HasQueens (msig);
23  bool rooks = MATSIG_HasRooks (msig);
24  bool minors = MATSIG_HasBishops (msig) || MATSIG_HasKnights (msig);
25  uint idx = EGTHEME_P;
26 
27  if (queens) {
28  if (rooks) {
29  if (minors) { idx = EGTHEME_QRM; } else { idx = EGTHEME_QR; }
30  } else {
31  if (minors) { idx = EGTHEME_QM; } else { idx = EGTHEME_Q; }
32  }
33  } else {
34  if (rooks) {
35  if (minors) { idx = EGTHEME_RM; } else { idx = EGTHEME_R; }
36  } else {
37  if (minors) { idx = EGTHEME_M; } else { idx = EGTHEME_P; }
38  }
39  }
40  return idx;
41 }
42 
43 inline bool posHasIQP (Position * pos, colorT c)
44 {
45  pieceT p = piece_Make (c, PAWN);
46  return (pos->FyleCount (p,C_FYLE) == 0 && pos->FyleCount (p,E_FYLE) == 0
47  && pos->FyleCount (p, D_FYLE) > 0);
48 }
49 
50 inline bool posHasAdvancedPawn (Position * pos, colorT c)
51 {
52  if (c == WHITE) {
53  return (pos->RankCount (WP,RANK_5) > 0 ||
54  pos->RankCount (WP,RANK_6) > 0 ||
55  pos->RankCount (WP,RANK_7) > 0);
56  }
57  return (pos->RankCount (BP,RANK_4) > 0 ||
58  pos->RankCount (BP,RANK_3) > 0 ||
59  pos->RankCount (BP,RANK_2) > 0);
60 }
61 
62 inline bool posHasKPawnStorm (Position * pos, colorT c)
63 {
64  const pieceT* bd = pos->GetBoard();
65  // A kingside pawn storm by White is defined to be a situation
66  // where there is no longer any white pawn on h2, g2, h3 or g3,
67  // but there is a white pawn on the g or h file.
68  if (c == WHITE) {
69  return (bd[G2] != WP && bd[H2] != WP && bd[G3] != WP && bd[H3] != WP
70  && (pos->FyleCount (WP, G_FYLE) > 0 ||
71  pos->FyleCount (WP,H_FYLE) > 0));
72  }
73  return (bd[G7] != BP && bd[H7] != BP && bd[G6] != BP && bd[H6] != BP
74  && (pos->FyleCount (BP, G_FYLE) > 0 ||
75  pos->FyleCount (BP,H_FYLE) > 0));
76 }
77 
78 inline bool posHasOpenFyle (Position * pos, fyleT f)
79 {
80  return (pos->FyleCount (WP, f) == 0 && pos->FyleCount (BP, f) == 0);
81 }
82 
83 void
84 OpLine::Init (void)
85 {
86  GameNumber = 0;
87  White = strDuplicate("");
88  Black = strDuplicate("");
89  Site = strDuplicate("");
90  WhiteID = BlackID = 0;
91  WhiteElo = BlackElo = 0;
92  AvgElo = 0;
93  Date = ZERO_DATE;
94  Result = RESULT_None;
95  Length = 0;
96  StartPly = 0;
97  NumMoves = 0;
98  ShortGame = false;
99  NoteNumber = NoteMoveNum = 0;
100  for (uint i=0; i < OPLINE_MOVES; i++) {
101  Move[i][0] = 0;
102  }
103  for (uint t=0; t < NUM_POSTHEMES; t++) { Theme[t] = 0; }
104  EgTheme = NUM_EGTHEMES;
105 }
106 
107 void
108 OpLine::Init (Game * g, const IndexEntry * ie, gamenumT gameNum,
109  uint maxExtraMoves, uint maxThemeMoveNumber)
110 {
111  White = strDuplicate (g->GetWhiteStr());
112  Black = strDuplicate (g->GetBlackStr());
113  Site = strDuplicate (g->GetSiteStr());
114 
115  WhiteID = ie->GetWhite();
116  BlackID = ie->GetBlack();
117  GameNumber = gameNum;
118 
119  Date = g->GetDate();
120  Result = g->GetResult();
121  NumMoves = (g->GetNumHalfMoves() + 1) / 2;
122  EcoCode = g->GetEco();
123  WhiteElo = g->GetWhiteElo();
124  BlackElo = g->GetBlackElo();
125  AvgElo = g->GetAverageElo();
126  Length = 0;
127  StartPly = g->GetCurrentPly();
128  g->SaveState();
129  if (g->GetCurrentPos()->GetToMove() == BLACK) {
130  g->MoveBackup();
131  }
132  NoteNumber = NoteMoveNum = 0;
133  uint columnMoves = OPTABLE_COLUMNS * 2;
134  uint maxLineMoves = (OPTABLE_COLUMNS + maxExtraMoves) * 2;
135  if (maxLineMoves > OPLINE_MOVES) { maxLineMoves = OPLINE_MOVES; }
136  EgTheme = endgameTheme (ie->GetFinalMatSig());
137 
138  // First read in just the moves that will appear in table columns:
139  uint i = 0;
140  ShortGame = false;
141  while (i < columnMoves) {
142  simpleMoveT * sm = g->GetCurrentMove();
143  if (sm == NULL) {
144  Move[i][0] = 0;
145  ShortGame = true;
146  } else {
147  Length++;
148  g->GetCurrentPos()->MakeSANString (sm, Move[i], SAN_CHECKTEST);
149  strStrip (Move[i], '-');
150  strStrip (Move[i], '=');
151  g->MoveForward();
152  }
153  i++;
154  }
155 
156  // Now read in all the extra note moves:
157  while (i < maxLineMoves) {
158  simpleMoveT * sm = g->GetCurrentMove();
159  if (sm == NULL) {
160  Move[i][0] = 0;
161  ShortGame = true;
162  } else {
163  Length++;
164  g->GetCurrentPos()->MakeSANString (sm, Move[i], SAN_CHECKTEST);
165  strStrip (Move[i], '-');
166  strStrip (Move[i], '=');
167  g->MoveForward();
168  }
169  i++;
170  }
171  if (g->GetCurrentMove() == NULL) { ShortGame = true; }
172 
173  // Now set positional themes:
174  uint maxThemePly = maxThemeMoveNumber * 2;
175  for (i=0; i < NUM_POSTHEMES; i++) { Theme[i] = 0; }
176  g->MoveToPly (0);
177  for (i=0; i < maxThemePly; i++) {
178  if (g->MoveForward() != OK) { break; }
180  }
181 
182  g->RestoreState();
183 }
184 
185 
186 void
187 OpLine::Destroy (void)
188 {
189  delete[] White;
190  delete[] Black;
191  delete[] Site;
192 }
193 
194 
195 void
197 {
198  squareT wk = pos->GetKingSquare (WHITE);
199  squareT bk = pos->GetKingSquare (BLACK);
200  fyleT wkf = square_Fyle (wk);
201  fyleT bkf = square_Fyle (bk);
202 
203  if ((wkf <= C_FYLE && bkf <= C_FYLE) || (wkf >= G_FYLE && bkf >= G_FYLE)) {
204  Theme[POSTHEME_CastSame]++;
205  }
206  if ((wkf <= C_FYLE && bkf >= G_FYLE) || (wkf >= G_FYLE && bkf <= C_FYLE)) {
207  Theme[POSTHEME_CastOpp]++;
208  }
209  if (pos->PieceCount(WQ) == 0 && pos->PieceCount(BQ) == 0) {
210  Theme[POSTHEME_QueenSwap]++;
211  }
212  bool wBPair = (pos->PieceCount (WB) >= 2);
213  bool bBPair = (pos->PieceCount (BB) >= 2);
214  if ((wBPair && !bBPair) || (!wBPair && bBPair)) {
215  Theme[POSTHEME_OneBPair]++;
216  }
217  if (posHasKPawnStorm (pos, WHITE) || posHasKPawnStorm (pos, BLACK)) {
218  Theme[POSTHEME_Kstorm]++;
219  }
220  if (posHasIQP (pos, WHITE)) {
221  Theme[POSTHEME_WIQP]++;
222  }
223  if (posHasIQP (pos, BLACK)) {
224  Theme[POSTHEME_BIQP]++;
225  }
226  if (posHasAdvancedPawn (pos, WHITE)) {
227  Theme[POSTHEME_WAdvPawn]++;
228  }
229  if (posHasAdvancedPawn (pos, BLACK)) {
230  Theme[POSTHEME_BAdvPawn]++;
231  }
232  if (posHasOpenFyle (pos, C_FYLE) || posHasOpenFyle (pos, D_FYLE)
233  || posHasOpenFyle (pos, E_FYLE)) {
234  Theme[POSTHEME_OpenFyle]++;
235  }
236 }
237 
238 
239 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
240 // OpLine::Insert:
241 // Inserts subline as a note of this line.
242 // The final order of notes (linked by the Next field) will be:
243 // (a) subline's notes, (b) subline, (c) this line's original notes.
244 void
246 {
247  OpLine * subsub = subline->Next;
248  subline->Next = Next;
249  if (subsub != NULL) {
250  OpLine * subtail = subsub;
251  while (subtail->Next != NULL) {
252  subtail = subtail->Next;
253  }
254  subtail->Next = subline;
255  Next = subsub;
256  } else {
257  Next = subline;
258  }
259 }
260 
261 uint
263 {
264  uint length = 0;
265  for (length=0; length < OPLINE_MOVES; length++) {
266  if (! strEqual (Move[length], line->Move[length])) { break; }
267  if (strEqual (Move[length], "")) { break; }
268  }
269  return length;
270 }
271 
272 void
273 OpLine::PrintMove (DString * dstr, const char * move, uint format)
274 {
275  char tempTrans[5000];
276 
277  if (format == OPTABLE_Compact) {
278  strcpy(tempTrans, move);
279  transPieces(tempTrans);
280  char *ptr = tempTrans;
281  char ch = *ptr; //*move;
282  while (ch != 0) {
283  if (ch != '+' && ch != 'x') {
284  dstr->AddChar (ch);
285  }
286  ptr++;//move++;
287  ch = *ptr;//*move;
288  }
289  return;
290  }
291 
292  if (format != OPTABLE_LaTeX) {
293  strcpy(tempTrans, move);
294  transPieces(tempTrans);
295  dstr->Append(tempTrans);//(move);
296  return;
297  }
298 
299  // LaTeX format: K,Q,R,B,N are translated to {\K} etc.
300  char ch = *move;
301  while (ch != 0) {
302  switch (ch) {
303  case 'K': case 'Q': case 'R': case 'B': case 'N':
304  dstr->Append ("{\\");
305  dstr->AddChar (ch);
306  dstr->AddChar ('}');
307  break;
308  default:
309  dstr->AddChar (ch);
310  break;
311  }
312  move++;
313  ch = *move;
314  }
315 }
316 
317 void
318 OpLine::PrintNote (DString * dstr, uint movenum, uint start, uint format)
319 {
320  bool wtm = true;
321  const char * preFirstMove = "";
322  const char * postFirstMove = "";
323  if (format == OPTABLE_LaTeX) {
324  preFirstMove = "\\textbf{";
325  postFirstMove = "}";
326  } else if (format == OPTABLE_HTML || format == OPTABLE_CText) {
327  preFirstMove = "<b>";
328  postFirstMove = "</b>";
329  }
330  for (uint i=0; i < Length; i++) {
331  if (i < start) {
332  // do nothing
333  } else {
334  if (i == start) {
335  dstr->Append (preFirstMove, movenum, wtm ? "." : "...");
336  } else if (wtm) {
337  dstr->Append (" ", movenum, ".");
338  } else {
339  dstr->Append (" ");
340  }
341  PrintMove (dstr, Move[i], format);
342  if (i == start) {
343  dstr->Append (postFirstMove);
344  }
345  }
346  if (wtm) {
347  wtm = false;
348  } else {
349  wtm = true;
350  movenum++;
351  }
352  }
353  dstr->Append (" ");
354  PrintSummary (dstr, format, false, false);
355 }
356 
357 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
358 // OpLine::PrintSummary():
359 // Prints the summary for this line. If fullDate is true, the
360 // full date is printed (not just the year). If nmoves is true
361 // or the game continues after the last stored line move, the
362 // number of moves in the game is printed after the result.
363 void
364 OpLine::PrintSummary (DString * dstr, uint format, bool fullDate, bool nmoves)
365 {
366  if (format == OPTABLE_CText && GameNumber > 0) {
367  dstr->Append ("<g_", GameNumber, ">");
368  }
369 
370  const char * resultStr = RESULT_STR[Result];
371  if (format == OPTABLE_LaTeX) {
372  switch (Result) {
373  case RESULT_White: resultStr = "{\\win}"; break;
374  case RESULT_Black: resultStr = "{\\loss}"; break;
375  case RESULT_Draw: resultStr = "{\\draw}"; break;
376  default: resultStr = "*"; break;
377  }
378  }
379  dstr->Append (resultStr);
380  if (nmoves || !ShortGame) {
381  dstr->Append ("(", NumMoves, ")");
382  }
383  const char * preName = "";
384  const char * postName = "";
385  if (format == OPTABLE_CText) {
386  preName = "<darkblue>";
387  postName = "</darkblue>";
388  } else if (format == OPTABLE_HTML) {
389  preName = "<span class=\"player\">";
390  postName = "</span>";
391  }
392 
393  dstr->Append (" ", preName);
394  const char * s = White;
395  while (*s != 0 && *s != ',') {
396  if (format == OPTABLE_LaTeX) {
397  if (*s == '_' || *s == '$' || *s == '%') {
398  dstr->AddChar ('\\');
399  }
400  }
401  dstr->AddChar (*s);
402  s++;
403  }
404  dstr->Append (postName);
405 
406  const char * preElo = " ";
407  const char * postElo = "";
408  const char * sep = " - ";
409  if (format == OPTABLE_LaTeX) {
410  preElo = " \\emph{"; postElo = "}"; sep = " -- ";
411  } else if (format == OPTABLE_HTML) {
412  preElo = " <span class=\"elo\">"; postElo = "</span>";
413  sep = " -- ";
414  } else if (format == OPTABLE_CText) {
415  preElo = " <green>"; postElo = "</green>";
416  }
417 
418  if (WhiteElo > 0) { dstr->Append (preElo, WhiteElo, postElo); }
419  dstr->Append (sep, preName);
420 
421  s = Black;
422  while (*s != 0 && *s != ',') {
423  if (format == OPTABLE_LaTeX) {
424  switch (*s) {
425  case '_':
426  case '$':
427  case '%':
428  case '&':
429  case '#':
430  dstr->AddChar ('\\');
431  break;
432  }
433  }
434  dstr->AddChar (*s);
435  s++;
436  }
437  dstr->Append (postName);
438  if (BlackElo > 0) { dstr->Append (preElo, BlackElo, postElo); }
439  dstr->Append (", ", Site, " ");
440  if (fullDate) {
441  char dateStr [16];
442  date_DecodeToString (Date, dateStr);
443  // Remove any unknown date fields:
444  char * s = (char *) strFirstChar (dateStr+4, '?');
445  if (s != NULL) { s--; *s = 0; }
446  dstr->Append (dateStr);
447  } else {
448  dstr->Append (date_GetYear (Date));
449  }
450 
451  if (format == OPTABLE_CText && GameNumber > 0) {
452  dstr->Append ("</g>");
453  }
454 }
455 
456 
457 ////////////////////////////////////////////////////////////
458 
459 
460 void
461 OpTable::Init (const char * type, Game * g, PBook * ebook)
462 {
463  Type = strDuplicate (type);
464  TargetRows = OPTABLE_DEFAULT_ROWS;
465  MaxTableLines = OPTABLE_MAX_TABLE_LINES;
466  NumRows = 0;
467  NumLines = NumTableLines = 0;
468  SetMaxExtraMoves (1);
469  FilterCount = TheoryCount = 0;
470  NumMoveOrders = 0;
471  Format = OPTABLE_Text;
472  StartLength = 0;
473  WTM = (g->GetCurrentPos()->GetToMove() == WHITE ? true : false);
474  DecimalChar = '.';
475 
476  Results[RESULT_White] = Results[RESULT_Black] = 0;
477  Results[RESULT_Draw] = Results[RESULT_None] = 0;
478  TheoryResults[RESULT_White] = TheoryResults[RESULT_Black] = 0;
479  TheoryResults[RESULT_Draw] = TheoryResults[RESULT_None] = 0;
480  EcoStr = NULL;
481  ExcludeMove[0] = 0;
482 
483  uint i;
484  for (i=0; i < NUM_POSTHEMES; i++) { ThemeCount[i] = 0; }
485 
486  for (i=0; i < NUM_EGTHEMES; i++) {
487  EndgameCount[OPTABLE_Line][i] = EndgameCount[OPTABLE_All][i] = 0;
488  }
489 
490  // Generate the text for each move up to the current position:
491  g->SaveState();
492  while (! g->AtStart()) {
493  if (g->AtVarStart()) {
494  g->MoveExitVariation();
495  continue;
496  }
497  if (ebook != NULL && EcoStr == NULL) {
498  DString dstr;
499  if (ebook->FindOpcode (g->GetCurrentPos(), "eco", &dstr) == OK) {
500  EcoStr = strDuplicate (dstr.Data());
501  }
502  }
503  g->MoveBackup();
504  simpleMoveT * sm = g->GetCurrentMove();
505  if (sm == NULL) { break; }
506  g->GetCurrentPos()->MakeSANString (sm, StartLine[StartLength],
507  SAN_CHECKTEST);
508  StartLength++;
509  if (StartLength >= OPTABLE_MAX_STARTLINE) { break; }
510  }
511  g->RestoreState();
512  // Now the moves are in the StartLine[] array, in reverse order.
513 }
514 
515 
516 void
518 {
519  uint i;
520  for (i=0; i < NumLines; i++) {
521  delete Line[i];
522  }
523  for (i=0; i < NumMoveOrders; i++) {
524 #ifdef WINCE
525  my_Tcl_Free((char*) MoveOrder[i].moves);
526 #else
527  delete MoveOrder[i].moves;
528 #endif
529  }
530  NumLines = NumTableLines = 0;
531  NumMoveOrders = 0;
532  FilterCount = TheoryCount = 0;
533  Results[RESULT_White] = Results[RESULT_Black] = 0;
534  Results[RESULT_Draw] = Results[RESULT_None] = 0;
535  TheoryResults[RESULT_White] = TheoryResults[RESULT_Black] = 0;
536  TheoryResults[RESULT_Draw] = TheoryResults[RESULT_None] = 0;
537  if (EcoStr != NULL) {
538 #ifdef WINCE
539  my_Tcl_Free((char*) EcoStr);
540 #else
541  delete[] EcoStr;
542 #endif
543  EcoStr = NULL;
544  }
545  ExcludeMove[0] = 0;
546 }
547 
548 void
550 {
551  // Clear all notes:
552  for (uint i=0; i < NumTableLines; i++) {
553  Row[i] = Line[i];
554  NLines[i] = 1;
555  RowScore[i] = RESULT_SCORE[Line[i]->Result];
556  Line[i]->Next = NULL;
557  Line[i]->NoteMoveNum = 0;
558  Line[i]->NoteNumber = 0;
559  }
560  NumNotes = 0;
561 }
562 
563 uint
564 OpTable::FormatFromStr (const char * str)
565 {
566  switch (str[0]) {
567  case 'H':
568  case 'h':
569  return OPTABLE_HTML;
570  case 'L':
571  case 'l':
572  return OPTABLE_LaTeX;
573  case 'T':
574  case 't':
575  return OPTABLE_Text;
576  case 'C':
577  case 'c':
578  return OPTABLE_CText;
579  }
580  return OPTABLE_Text;
581 }
582 
583 void
584 OpTable::SetFormat (const char * str)
585 {
586  Format = FormatFromStr (str);
587 }
588 
589 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
590 // OpTable::PercentScore():
591 // Returns the percentage score for White across all
592 // games that have been added to the database.
593 // The integer value returned is the percentage * 10,
594 // e.g. "573" for 57.3%
595 uint
597 {
598  uint percent = Results[RESULT_White] * 2;
599  percent += Results[RESULT_Draw];
600  percent = percent * 500;
601  uint total = Results[RESULT_White] + Results[RESULT_Draw]
602  + Results[RESULT_Black];
603  if (total > 0) { percent = percent / total; }
604  return percent;
605 }
606 
607 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
608 // OpTable::TheoryPercent():
609 // Returns the percentage score for White across all
610 // games except those excluded from the theory table.
611 uint
613  uint percent = TheoryResults[RESULT_White] * 2;
614  percent += TheoryResults[RESULT_Draw];
615  percent = percent * 500;
616  uint total = TheoryResults[RESULT_White] + TheoryResults[RESULT_Draw]
617  + TheoryResults[RESULT_Black];
618  if (total > 0) { percent = percent / total; }
619  return percent;
620 }
621 
622 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
623 // OpTable::TheoryScore:
624 // Returns the score for White (multiplied by 2 to be an
625 // integer value) for all games except those excluded
626 // from the theory table.
627 uint
629 {
630  return TheoryResults[RESULT_White] * 2 + TheoryResults[RESULT_Draw];
631 }
632 
633 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
634 // OpTable::PercentFreq():
635 // Returns the frequency of a particular result as a percentage.
636 // The integer value returned is the percentage * 10.
637 uint
639 {
640  uint percent = Results[result] * 1000;
641  uint total = Results[RESULT_White] + Results[RESULT_Draw] +
642  Results[RESULT_Black] + Results[RESULT_None];
643  if (total > 0) { percent = percent / total; }
644  return percent;
645 }
646 
647 
648 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
649 // OpTable::Add():
650 // Adds the line to the table if possible. If the table is not
651 // yet full, the line is added and no line is deleted. If the
652 // table is full, either the specified line, or an existing
653 // line in the table it replaces, will be deleted.
654 bool
656 {
657  if (! WTM) {
658  strCopy (line->Move[0], StartLine[0]);
659  strStrip (line->Move[0], '-');
660  strStrip (line->Move[0], '=');
661  }
662  for (uint theme=0; theme < NUM_POSTHEMES; theme++) {
663  if (line->Theme[theme] >= POSTHEME_THRESHOLD) { ThemeCount[theme]++; }
664  }
665  Results[line->Result]++;
666  FilterCount++;
667 
668  // Stop here if this line is excluded from the theory table:
669  if (WTM && strEqual (line->Move[0], ExcludeMove)) { return false; }
670  if (!WTM && strEqual (line->Move[1], ExcludeMove)) { return false; }
671 
672  TheoryCount++;
673  TheoryResults[line->Result]++;
674  if (NumLines < OPTABLE_MAX_LINES) {
675  Line[NumLines] = line;
676  NumLines++;
677  if (NumTableLines < MaxTableLines) { NumTableLines++; }
678  return true;
679  }
680 
681  // The table is full, so if this line is to be added, it must
682  // evict an existing line with a smaller average Elo rating.
683 
684  eloT evictElo = line->AvgElo;
685  int evictIndex = -1;
686  for (uint i=0; i < NumLines; i++) {
687  eloT elo = Line[i]->AvgElo;
688  if (elo < evictElo) {
689  evictElo = elo;
690  evictIndex = i;
691  }
692  }
693  if (evictIndex < 0) {
694  return false;
695  }
696  delete Line[evictIndex];
697  Line[evictIndex] = line;
698  return true;
699 }
700 
701 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
702 // int_sqrt(): Integer square root.
703 // Used by OpTable::GuessNumRows().
704 static uint
705 int_sqrt (uint val)
706 {
707  uint guess=0;
708  uint bit;
709  for (bit = 1 << 15; bit != 0; bit >>= 1) {
710  guess ^= bit;
711  /* Can set this bit without going over sqrt(val)? */
712  if (guess * guess > val) {
713  guess ^= bit;
714  }
715  }
716  return guess;
717 }
718 
719 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
720 // OpTable::GuessNumRows():
721 // Sets the target number of rows according to the
722 // number of lines, hopefully choosing a nice value.
723 // The formula is sqrt(NumTableLines*0.75) + 3.
724 void
726 {
727  SetNumRows (int_sqrt((NumTableLines * 3) / 4) + 3);
728 }
729 
730 #ifdef WINCE
731 void
732 OpTable::DumpLines (/*FILE * */ Tcl_Channel fp)
733 {
734  MakeRows();
735  DString * dstr = new DString;
736  char buf[1024];
737  for (uint i=0; i < NumRows; i++) {
738  bool first = true;
739  OpLine * line = Row[i];
740  OpLine * prevLine = NULL;
741  while (line != NULL) {
742  dstr->Clear();
743  if (first) {
744  first = false;
745  line->PrintNote (dstr, (StartLength + 2) / 2, 0, OPTABLE_Text);
746  //fprintf (fp, "ROW %u[%u]: ", i+1, NLines[i]);
747  sprintf (buf, "ROW %u[%u]: ", i+1, NLines[i]);
748  my_Tcl_Write(fp,buf,strlen(buf));
749  } else {
750  //fprintf (fp, " %u-NOTE: ", i+1);
751  sprintf (buf, " %u-NOTE: ", i+1);
752  my_Tcl_Write(fp,buf,strlen(buf));
753  line->PrintNote (dstr, (StartLength + 2) / 2,
754  line->CommonLength(prevLine), OPTABLE_Text);
755  }
756  //fprintf (fp, "%s\n", dstr->Data());
757  sprintf (buf, "%s\n", dstr->Data());
758  my_Tcl_Write(fp,buf,strlen(buf));
759  prevLine = line;
760  line = line->Next;
761  }
762  }
763  delete dstr;
764 }
765 
766 #else
767 void
769 {
770  MakeRows();
771  DString * dstr = new DString;
772  for (uint i=0; i < NumRows; i++) {
773  bool first = true;
774  OpLine * line = Row[i];
775  OpLine * prevLine = NULL;
776  while (line != NULL) {
777  dstr->Clear();
778  if (first) {
779  first = false;
780  line->PrintNote (dstr, (StartLength + 2) / 2, 0, OPTABLE_Text);
781  fprintf (fp, "ROW %u[%u]: ", i+1, NLines[i]);
782  } else {
783  fprintf (fp, " %u-NOTE: ", i+1);
784  line->PrintNote (dstr, (StartLength + 2) / 2,
785  line->CommonLength(prevLine), OPTABLE_Text);
786  }
787  fprintf (fp, "%s\n", dstr->Data());
788  prevLine = line;
789  line = line->Next;
790  }
791  }
792  delete dstr;
793 }
794 #endif
795 
796 bool
797 OpTable::IsRowMergable (uint rownum)
798 {
799  ASSERT (rownum > 0 && rownum < NumRows-1);
800  uint prevLength = Row[rownum]->CommonLength (Row[rownum-1]);
801  uint nextLength = Row[rownum]->CommonLength (Row[rownum+1]);
802  return (nextLength > prevLength);
803 }
804 
805 void
806 OpTable::MergeRow (uint rownum)
807 {
808  ASSERT (rownum < NumRows-1);
809  Row[rownum+1]->Insert (Row[rownum]);
810  NLines[rownum+1] += NLines[rownum];
811  RowScore[rownum+1] += RowScore[rownum];
812  for (uint i=rownum; i < NumRows-1; i++) {
813  NLines[i] = NLines[i+1];
814  Row[i] = Row[i+1];
815  RowScore[i] = RowScore[i+1];
816  }
817  NumRows--;
818 }
819 
820 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
821 // OpTable::SelectTableLines():
822 // Select the NumTableLines highest-rated lines and
823 // move them to the start of the array of lines.
824 void
825 OpTable::SelectTableLines (void)
826 {
827  uint i, j;
828  if (NumLines == NumTableLines) { return; }
829  ASSERT (NumTableLines < NumLines);
830  for (i=0; i < NumTableLines; i++) {
831  uint bestIndex = i;
832  uint bestAvgElo = Line[i]->AvgElo;
833  for (j = i+1; j < NumLines; j++) {
834  if (Line[j]->AvgElo >= bestAvgElo) {
835  bestIndex = j;
836  bestAvgElo = Line[j]->AvgElo;
837  }
838  }
839  if (bestIndex != i) {
840  OpLine * temp = Line[i];
841  Line[i] = Line[bestIndex];
842  Line[bestIndex] = temp;
843  }
844  }
845 }
846 
847 void
849  uint i;
850 
851  if (NumLines == 0) { return; }
852 
853  // Select the NumTableLines highest-rated lines and
854  // make them the first lines in the list:
855  SelectTableLines ();
856  // Sort the table lines:
857  SortTableLines (Line, NumTableLines, 0);
858 
859  // Clear all notes:
860  ClearNotes();
861 
862  NumRows = NumTableLines;
863  if (TargetRows < OPTABLE_MIN_ROWS) { TargetRows = OPTABLE_MIN_ROWS; }
864  if (TargetRows > OPTABLE_MAX_ROWS) { TargetRows = OPTABLE_MAX_ROWS; }
865 
866  // Need to merge all rows with CommonLength >= 2*OPTABLE_COLUMNS here,
867  // and also merge all rows that are complete prefixes of other
868  // rows (that is, where row N+1 contains all the moves of row N and
869  // perhaps extra moves as well).
870 
871  for (i=0; i < NumRows-1;) {
872  uint clength = Row[i]->CommonLength (Row[i+1]);
873  if (clength >= 2*OPTABLE_COLUMNS) {
874  MergeRow (i);
875  } else if (clength == Row[i]->Length) {
876  MergeRow (i);
877  } else {
878  i++;
879  }
880  }
881 
882  // While the number of rows left is greater than the requested number,
883  // keep picking a row and merging it into its successor:
884 
885  while (NumRows > TargetRows) {
886  // Find the best row to merge with the row below it.
887  // The first row can always be merged, other rows might not be
888  // elegible for merging. Given rows N-1, N and N+1, row N can
889  // only be merged into N+1 if CommonLength(N,N+1) is greater
890  // than CommonLength(N-1,N).
891 
892  uint bestcost = NLines[0] + NLines[1];
893  uint bestrow = 0;
894  for (i=1; i < NumRows-1; i++) {
895  if (IsRowMergable (i)) {
896  uint cost = NLines[i] + NLines[i+1];
897  if (cost < bestcost) {
898  bestcost = cost;
899  bestrow = i;
900  }
901  }
902  }
903  MergeRow (bestrow);
904  }
905 
906  // Now go through all note lines and find the move at which they
907  // differ from the main row line:
908 
909  for (i=0; i < NumRows; i++) {
910  OpLine * rowline = Row[i];
911  OpLine * subline = Row[i]->Next;
912  while (subline != NULL) {
913  subline->NoteMoveNum = subline->CommonLength(rowline);
914  subline = subline->Next;
915  }
916  }
917 }
918 
919 // opSortT:
920 // Structure used in OpTable::SortTableLines to keep track of
921 // the frequency of a particular move, and the list of lines
922 // that contain each unique move.
923 //
924 struct opSortT {
925  const char * move;
926  int count;
928 };
929 
930 void
931 OpTable::SortTableLines (OpLine ** lines, uint nlines, uint depth)
932 {
933  uint i, j, nUnique = 0;
934  if (nlines < 2) { return; }
935  if (depth >= OPLINE_MOVES) { return; }
936 
937 #ifdef WINCE
938  opSortT * moves = (opSortT *) my_Tcl_Alloc(sizeof( opSortT [nlines]));
939 #else
940  opSortT * moves = new opSortT [nlines];
941 #endif
942 
943  for (i=0; i < nlines; i++) {
944  bool newMove = true;
945  for (j=0; j < nUnique; j++) {
946  if (strEqual (lines[i]->GetMove(depth), moves[j].move)) {
947  newMove = false;
948  moves[j].count++;
949  lines[i]->Next = moves[j].lineList;
950  moves[j].lineList = lines[i];
951  }
952  }
953  if (newMove) {
954  moves[nUnique].count = 1;
955  moves[nUnique].move = lines[i]->GetMove(depth);
956  lines[i]->Next = NULL;
957  moves[nUnique].lineList = lines[i];
958  nUnique++;
959  }
960  }
961 
962  // Now moves[] stores the number of times each unique next move appears.
963  // Sort moves[]:
964  for (i=0; i < nUnique-1; i++) {
965  for (j=i+1; j < nUnique; j++) {
966  int result = moves[i].count - moves[j].count;
967  // If both moves have one line, sort by average elo:
968  if (result == 0 && moves[i].count == 1) {
969  result = moves[i].lineList->AvgElo - moves[j].lineList->AvgElo;
970  }
971  // If still equal, sort by move notation:
972  if (result == 0) {
973  result = strCompare (moves[i].move, moves[j].move);
974  }
975  // Ensure short lines (with no more moves) come first:
976  if (strEqual (moves[i].move, "")) { result = -1; }
977  if (strEqual (moves[j].move, "")) { result = 1; }
978  // Swap if necessary:
979  if (result > 0) {
980  opSortT temp = moves[i];
981  moves[i] = moves[j];
982  moves[j] = temp;
983  }
984  }
985  }
986 
987  // Now rearrange the lines according to the order of moves:
988  uint count = 0;
989  for (i=0; i < nUnique; i++) {
990  OpLine * line = moves[i].lineList;
991  while (line != NULL) {
992  lines[count] = line;
993  count++;
994  line = line->Next;
995  }
996  }
997 
998  // Now recursively sort each block of unique moves:
999  count = 0;
1000  for (i=0; i < nUnique; i++) {
1001  SortTableLines (lines, moves[i].count, depth+1);
1002  lines += moves[i].count;
1003  }
1004 
1005  // Delete the moves array:
1006 #ifdef WINCE
1007  my_Tcl_Free((char*)moves);
1008 #else
1009  delete[] moves;
1010 #endif
1011 }
1012 
1013 void
1014 OpTable::PrintStemLine (DString * dstr, uint format, bool exclude)
1015 {
1016  for (uint i=0; i < StartLength; i++) {
1017  dstr->Append (" ");
1018  if (i % 2 == 0) { dstr->Append ((i+2)/2, "."); }
1019  OpLine::PrintMove (dstr, StartLine[StartLength-1-i], format);
1020  }
1021  if (exclude && ExcludeMove[0] != 0) {
1022  dstr->Append (" (X ");
1023  dstr->Append ((StartLength+2)/2, StartLength % 2 == 0 ? "." : "...");
1024  OpLine::PrintMove (dstr, ExcludeMove, format);
1025  dstr->Append (")");
1026  }
1027 }
1028 
1029 void
1030 OpTable::PrintTable (DString * dstr, const char * title, const char * comment)
1031 {
1032  ASSERT (title != NULL && comment != NULL);
1033  switch (Format) {
1034  case OPTABLE_LaTeX:
1035  PrintLaTeX (dstr, title, comment);
1036  break;
1037  case OPTABLE_HTML:
1038  PrintHTML (dstr, title, comment);
1039  break;
1040  case OPTABLE_Text:
1041  PrintText (dstr, title, comment, false);
1042  break;
1043  case OPTABLE_CText:
1044  PrintText (dstr, title, comment, true);
1045  break;
1046  }
1047 }
1048 
1049 
1050 void
1051 OpTable::PrintLaTeX (DString * dstr, const char * title, const char * comment)
1052 {
1053  uint i;
1054  MakeRows();
1055  NumNotes = 0;
1056  // Increasing arraystretch above 1.0 adds more whitespace between
1057  // rows making the table more readable:
1058  dstr->Append ("\\renewcommand{\\arraystretch}{1.15}\n");
1059  dstr->Append ("\\twocolumn[\n");
1060  dstr->Append (title);
1061  dstr->Append ("\\begin{center}\n");
1062  dstr->Append ("\\begin{tabular}{r*{", OPTABLE_COLUMNS);
1063  dstr->Append ("}{p{1.15cm}}r@{: }l}\n\\hline\n");
1064  dstr->Append ("\\multicolumn{11}{p{13cm}}{\\textbf{");
1065  PrintStemLine (dstr, OPTABLE_LaTeX, true);
1066  dstr->Append ("}: \\mbox{");
1067  dstr->Append (" +", TheoryResults[RESULT_White]);
1068  dstr->Append (" =", TheoryResults[RESULT_Draw]);
1069  dstr->Append (" --", TheoryResults[RESULT_Black]);
1070  uint score = TheoryScore();
1071  dstr->Append (" (", score/2);
1072  if (score % 2) { dstr->AddChar (DecimalChar); dstr->AddChar ('5'); }
1073  dstr->Append ("/", TheoryCount, ": ");
1074  dstr->Append ((TheoryPercent() + 5) / 10, "\\%)}");
1075  dstr->Append ("} \\\\\n\\hline\n");
1076  for (i=0; i < OPTABLE_COLUMNS; i++) {
1077  dstr->Append (" & ", i + ((StartLength + 2) / 2));
1078  }
1079  dstr->Append (" & \\multicolumn{2}{c}{} \\\\\n");
1080  //dstr->Append ("\\hline\n");
1081 
1082  // Print each row:
1083  for (uint row=0; row < NumRows; row++) {
1084  dstr->Append ("\\textbf{", row+1, "}");
1085  uint nSameMoves = 0;
1086  if (row > 0) { nSameMoves = Row[row]->CommonLength(Row[row-1]); }
1087  for (uint j=0; j < 2*OPTABLE_COLUMNS; j++) {
1088  //dstr->Append (j % 2 == 0 ? " & " : " \\newline ");
1089  if (j % 2 == 0) {
1090  dstr->Append (" & ");
1091  } else if (*(Row[row]->Move[j-1]) != '\0') {
1092  dstr->Append (" \\newline ");
1093  }
1094  if (j < nSameMoves) {
1095  dstr->Append ("...");
1096  } else {
1097  OpLine::PrintMove (dstr, Row[row]->Move[j], OPTABLE_LaTeX);
1098  }
1099 
1100  // Check for a footnote:
1101  if (HasNotes (Row[row], j)) {
1102  dstr->Append ("$^{", NumNotes, "}");
1103  // Compile following section to indicate number of games
1104  // and score in each note:
1105 #if 0
1106  uint ncount = NoteCount(NumNotes);
1107  uint nscore = NoteScore(NumNotes);
1108  dstr->Append ("_{\\mbox{\\tiny ", ncount, ":");
1109  if (ncount == 1) {
1110  switch (nscore) {
1111  case 100: dstr->Append ("+"); break;
1112  case 50: dstr->Append ("="); break;
1113  case 0: dstr->Append ("--"); break;
1114  }
1115  } else {
1116  dstr->Append (nscore, "\\%");
1117  }
1118  dstr->Append ("}}");
1119 #endif
1120  dstr->Append ("$");
1121  }
1122  }
1123 
1124  // Print number of games in this row, and White percentage score:
1125  dstr->Append (" & ", NLines[row], " & ");
1126  uint score = 0;
1127  if (NLines[row] > 0) {
1128  score = (RowScore[row] * 50 + (NLines[row]/2)) / NLines[row];
1129  }
1130  dstr->Append (score, "\\% \\\\\n");
1131  }
1132 
1133  dstr->Append ("\\hline\n");
1134  if (! strEqual (comment, "")) {
1135  dstr->Append ("\\multicolumn{11}{r}{\\em ", comment, "}\n");
1136  }
1137  dstr->Append ("\\end{tabular}\n\\end{center}\n]\n");
1138  PrintNotes (dstr, OPTABLE_LaTeX);
1139 }
1140 
1141 void
1142 OpTable::PrintHTML (DString * dstr, const char * title, const char * comment)
1143 {
1144  uint i;
1145  MakeRows();
1146  NumNotes = 0;
1147  dstr->Append (title);
1148  dstr->Append ("<center>");
1149  PrintStemLine (dstr, OPTABLE_HTML, true);
1150  dstr->Append (": ");
1151  dstr->Append (" +", TheoryResults[RESULT_White]);
1152  dstr->Append (" =", TheoryResults[RESULT_Draw]);
1153  dstr->Append (" -", TheoryResults[RESULT_Black]);
1154  uint score = TheoryScore();
1155  dstr->Append (" (", score/2);
1156  if (score % 2) { dstr->AddChar (DecimalChar); dstr->AddChar ('5'); }
1157  dstr->Append ("/", TheoryCount, ": ");
1158  dstr->Append ((TheoryPercent() + 5) / 10, "%)\n");
1159  dstr->Append ("<table border=0 cellspacing=0 cellpadding=4>\n");
1160  dstr->Append ("<tr><th></th>");
1161  for (i=0; i < OPTABLE_COLUMNS; i++) {
1162  dstr->Append ("<th align=\"left\">", i + ((StartLength + 2) / 2), "</th>");
1163  }
1164  dstr->Append ("</tr>\n");
1165 
1166  // Print each row:
1167  for (uint row=0; row < NumRows; row++) {
1168  dstr->Append ("<tr><th>", row+1, "</th>\n");
1169  uint nSameMoves = 0;
1170  if (row > 0) { nSameMoves = Row[row]->CommonLength(Row[row-1]); }
1171  for (uint j=0; j < 2*OPTABLE_COLUMNS; j++) {
1172  dstr->Append (j % 2 == 0 ? " <td> " : " <br> ");
1173  if (j < nSameMoves) {
1174  dstr->Append ("...");
1175  } else {
1176  OpLine::PrintMove (dstr, Row[row]->Move[j], OPTABLE_HTML);
1177  }
1178 
1179  // Check for a footnote:
1180  if (HasNotes (Row[row], j)) {
1181  dstr->Append ("<sup><a href=\"#note", NumNotes);
1182  dstr->Append ("\">", NumNotes, "</a></sup>");
1183  }
1184  if (j % 2 != 0) { dstr->Append (" </td>\n"); }
1185  }
1186  // Print number of games in this row, and White percentage score:
1187  dstr->Append (" <td>", NLines[row], ": ");
1188  uint score = 0;
1189  if (NLines[row] > 0) {
1190  score = (RowScore[row] * 50 + (NLines[row]/2)) / NLines[row];
1191  }
1192  dstr->Append (score, "% </td> ");
1193  dstr->Append ("</tr>\n");
1194  }
1195  dstr->Append ("</table>");
1196  if (! strEqual (comment, "")) { dstr->Append (comment, "\n"); }
1197  dstr->Append ("</center>");
1198  PrintNotes (dstr, OPTABLE_HTML);
1199 }
1200 
1201 void
1202 OpTable::PrintText (DString * dstr, const char * title, const char * comment,
1203  bool ctext)
1204 {
1205  uint i;
1206  MakeRows();
1207  NumNotes = 0;
1208  const uint cellBytes = 9;
1209  char cell [16];
1210  const char * hrule = "-------------------------------------------------------------------------------\n";
1211  DString * dtemp = new DString;
1212 
1213  dstr->Append (title, "\n");
1214  if (ctext) { dstr->Append ("<tt>"); }
1215  dstr->Append (hrule, " ");
1216  if (StartLength > 0) {
1217  if (ctext) {
1218  dstr->Append ("<darkblue><run importMoveListTrans {");
1219  PrintStemLine (dstr, OPTABLE_Text, false);
1220  dstr->Append ("}>");
1221  }
1222  PrintStemLine (dstr, OPTABLE_Text, true);
1223  if (ctext) { dstr->Append ("</run></darkblue>"); }
1224  dstr->Append (":");
1225  }
1226  dstr->Append (" +", TheoryResults[RESULT_White]);
1227  dstr->Append (" =", TheoryResults[RESULT_Draw]);
1228  dstr->Append (" -", TheoryResults[RESULT_Black]);
1229  uint score = TheoryScore();
1230  dstr->Append (" (", score/2);
1231  if (score % 2) { dstr->AddChar (DecimalChar); dstr->AddChar ('5'); }
1232  dstr->Append ("/", TheoryCount, ": ");
1233  dstr->Append ((TheoryPercent() + 5) / 10, "%)\n");
1234  dstr->Append (hrule, " ");
1235  for (i=0; i < OPTABLE_COLUMNS; i++) {
1236  sprintf (cell, " %3u ", i + ((StartLength + 2) / 2));
1237  dstr->Append (cell);
1238  }
1239  dstr->Append ("\n", hrule);
1240 
1241  DString * wstr = new DString;
1242  DString * bstr = new DString;
1243 
1244  // Print each row:
1245  for (uint row=0; row < NumRows; row++) {
1246  wstr->Clear();
1247  bstr->Clear();
1248  bool wtm = true;
1249  char tempStr [8];
1250  sprintf (tempStr, "%2u ", row+1);
1251  wstr->Append (tempStr);
1252  bstr->Append (" ");
1253  uint nSameMoves = 0;
1254  if (row > 0) { nSameMoves = Row[row]->CommonLength(Row[row-1]); }
1255  for (uint j=0; j < 2*OPTABLE_COLUMNS; j++) {
1256  size_t width = 0;
1257  dtemp->Clear();
1258  if (j < nSameMoves) {
1259  dtemp->Append ("...");
1260  width += 3;
1261  } else {
1262  if (ctext && j >= nSameMoves) {
1263  dtemp->Append ("<darkblue><run importMoveListTrans {");
1264  PrintStemLine (dtemp, OPTABLE_Text, false);
1265  uint x = 0;
1266  if (! WTM) { x = 1; }
1267  for (; x <= j; x++) {
1268  dtemp->Append (" ");
1269  OpLine::PrintMove (dtemp, Row[row]->Move[x],
1270  OPTABLE_Compact);
1271  }
1272  dtemp->Append ("}>");
1273  }
1274  size_t oldwidth = dtemp->Length();
1275  OpLine::PrintMove (dtemp, Row[row]->Move[j], OPTABLE_Compact);
1276  width += dtemp->Length() - oldwidth;
1277  if (ctext && j >= nSameMoves) {
1278  dtemp->Append ("</run></darkblue>");
1279  }
1280  }
1281 
1282  // Check for a footnote:
1283  if (HasNotes (Row[row], j)) {
1284  if (ctext) {
1285  dtemp->Append ("<red><go n", NumNotes, ">");
1286  dtemp->Append ("<N", NumNotes, ">");
1287  }
1288  size_t oldwidth = dtemp->Length();
1289  dtemp->Append ("[", NumNotes, "]");
1290  width += dtemp->Length() - oldwidth;
1291  if (ctext) { dtemp->Append ("</N", NumNotes, "></go></red>"); }
1292  }
1293  // Pad width to full cell width:
1294  while (width < cellBytes) {
1295  dtemp->AddChar (' ');
1296  width++;
1297  }
1298 
1299  if (wtm) {
1300  wtm = false;
1301  wstr->Append (dtemp->Data());
1302  } else {
1303  wtm = true;
1304  bstr->Append (dtemp->Data());
1305  }
1306  }
1307 
1308  // Print number of games in this row, and White percentage score:
1309  sprintf (cell, "%2u:", NLines[row]);
1310  wstr->Append (cell);
1311  uint score = 0;
1312  if (NLines[row] > 0) {
1313  score = (RowScore[row] * 50 + (NLines[row]/2)) / NLines[row];
1314  }
1315  sprintf (cell, "%2u%%", score);
1316  bstr->Append (cell);
1317  dstr->Append (wstr->Data(), "\n", bstr->Data(), "\n\n");
1318  }
1319  dstr->Append (hrule);
1320  if (! strEqual (comment, "")) { dstr->Append (comment, "\n"); }
1321  dstr->Append ("\n");
1322  delete dtemp;
1323  if (ctext) { dstr->Append ("</tt>"); }
1324  PrintNotes (dstr, ctext ? OPTABLE_CText : OPTABLE_Text);
1325 }
1326 
1327 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1328 // OpTable::HasNotes():
1329 // Determines if a particular move number of a main row line has
1330 // any footnotes. If it does, the NumNotes counter is incremented,
1331 // all footnote lines for the new footnote have their NoteMoveNum
1332 // set to the new footnote number, and true is returned.
1333 bool
1334 OpTable::HasNotes (OpLine * line, uint movenum)
1335 {
1336  // Check for a footnote: there will be one if this is the last
1337  // move on the row that will appear in the table, or if there
1338  // is a subline that diverges at this move.
1339 
1340  OpLine * subline = line->Next;
1341  bool noteSeen = false;
1342  bool lastMoveInRow = false;
1343  if (movenum == line->Length-1) { lastMoveInRow = true; }
1344  if ((movenum == 2*OPTABLE_COLUMNS - 1) && (movenum < line->Length)) {
1345  lastMoveInRow = true;
1346  }
1347  if (lastMoveInRow) {
1348  noteSeen = true;
1349  NumNotes++;
1350  line->NoteMoveNum = movenum+1;
1351  line->NoteNumber = NumNotes;
1352  }
1353  while (subline != NULL) {
1354  if (subline->NoteMoveNum == movenum) {
1355  if (! noteSeen) {
1356  noteSeen = true;
1357  NumNotes++;
1358  }
1359  subline->NoteNumber = NumNotes;
1360  }
1361  if (subline->NoteNumber == 0 && lastMoveInRow) {
1362  subline->NoteNumber = NumNotes;
1363  subline->NoteMoveNum = movenum+1;
1364  }
1365  subline = subline->Next;
1366  }
1367  return noteSeen;
1368 }
1369 
1370 uint
1371 OpTable::NoteCount (uint note)
1372 {
1373  uint count = 0;
1374  for (uint n = 0; n < NumTableLines; n++) {
1375  if (Line[n]->NoteNumber == note) { count++; }
1376  }
1377  return count;
1378 }
1379 
1380 uint
1381 OpTable::NoteScore (uint note)
1382 {
1383  uint count = 0;
1384  uint score = 0;
1385  for (uint n = 0; n < NumTableLines; n++) {
1386  if (Line[n]->NoteNumber == note) {
1387  count++;
1388  score += RESULT_SCORE[Line[n]->Result];
1389  }
1390  }
1391  if (count > 0) {
1392  score = (score * 50 + (count/2)) / count;
1393  }
1394  return score;
1395 }
1396 
1397 void
1398 OpTable::PrintNotes (DString * dstr, uint format)
1399 {
1400  if (NumNotes == 0) { return; }
1401 
1402  const char * preNotesList = "\n";
1403  const char * postNotesList = "\n";
1404  const char * para = "\n ";
1405  const char * endNote = "\n\n";
1406  const char * nextGame = ";\n ";
1407 
1408  if (format == OPTABLE_LaTeX) {
1409  para = "\n\n";
1410  nextGame = ";\n";
1411  } else if (format == OPTABLE_HTML) {
1412  preNotesList = "\n\n<ol>\n";
1413  postNotesList = "</ol>\n";
1414  para = "<br>\n"; nextGame = ";\n";
1415  endNote = "</a><p>\n";
1416  } else if (format == OPTABLE_CText) {
1417  nextGame = "; ";
1418  endNote = "</tab>\n\n";
1419  para = "\n ";
1420  }
1421  dstr->Append (preNotesList);
1422 
1423  for (uint note=1; note <= NumNotes; note++) {
1424  if (format == OPTABLE_LaTeX) {
1425  dstr->Append ("\\notenum{", note, "}\n");
1426  } else if (format == OPTABLE_HTML) {
1427  //dstr->Append ("<li><b>", note, "</b> ");
1428  dstr->Append ("<li><a name=\"note", note, "\"></a> ");
1429  } else if (format == OPTABLE_CText) {
1430  dstr->Append ("<tab><red><go N", note, ">");
1431  dstr->Append ("<n", note, ">");
1432  dstr->Append ("[", note, "]");
1433  dstr->Append ("</n", note, "></go></red> ");
1434  } else {
1435  dstr->Append ("[*", note, "*] ");
1436  }
1437  OpLine * prevLine = NULL;
1438  for (int n = NumTableLines-1; n >= 0; n--) {
1439  if (Line[n]->NoteNumber == note) {
1440  uint mnum = Line[n]->NoteMoveNum;
1441  if (prevLine != NULL) {
1442  mnum = Line[n]->CommonLength(prevLine);
1443  if (mnum <= Line[n]->NoteMoveNum &&
1444  prevLine->Length > mnum) {
1445  dstr->Append (".", para);
1446  } else {
1447  dstr->Append (nextGame);
1448  }
1449  }
1450  Line[n]->PrintNote (dstr, (StartLength+2) / 2, mnum, format);
1451  prevLine = Line[n];
1452  }
1453  }
1454  dstr->Append (".", endNote);
1455  }
1456  dstr->Append (postNotesList);
1457 }
1458 
1459 void
1460 OpTable::BestGames (DString * dstr, uint count, const char * rtype)
1461 {
1462  enum {
1463  BEST_White, BEST_Black, BEST_AvgElo, BEST_Oldest, BEST_Newest
1464  };
1465  int rt = BEST_AvgElo;
1466  switch (rtype[0]) {
1467  case 'W':
1468  case 'w': // Fastest White wins, ties resolved by AvgElo
1469  rt = BEST_White; break;
1470  case 'B':
1471  case 'b': // Fastest Black wins, ties resolved by AvgElo
1472  rt = BEST_Black; break;
1473  case 'A':
1474  case 'a': // Highest average rating
1475  rt = BEST_AvgElo; break;
1476  case 'O':
1477  case 'o': // Oldest games
1478  rt = BEST_Oldest; break;
1479  case 'N':
1480  case 'n': // Newest games
1481  rt = BEST_Newest; break;
1482  default:
1483  return;
1484  }
1485 
1486  const char * preNum = " ";
1487  const char * postNum = ": ";
1488  const char * endLine = "\n";
1489  const char * preList = "";
1490  const char * postList = "";
1491 
1492  if (Format == OPTABLE_LaTeX) {
1493  preNum = "\\textbf{";
1494  postNum = ":} ";
1495  endLine = "\\\\\n";
1496  } else if (Format == OPTABLE_HTML) {
1497  preNum = "";
1498  postNum = ": ";
1499  endLine = "<br>\n";
1500  }
1501 
1502  uint i;
1503  for (i=0; i < NumLines; i++) {
1504  Line[i]->Selected = false;
1505  }
1506 
1507  dstr->Append (preList);
1508  bool printFullDate = (rt == BEST_Oldest || rt == BEST_Newest);
1509 
1510  for (uint c=1; c <= count; c++) {
1511  uint bestValue = 0;
1512  int bestIndex = -1;
1513  for (i=0; i < NumLines; i++) {
1514  if (Line[i]->Selected) { continue; }
1515  uint v = 0;
1516  switch (rt) {
1517  case BEST_White:
1518  if (Line[i]->Result != RESULT_White) { continue; }
1519  v = 1000 - Line[i]->NumMoves;
1520  v = (v << 12) + Line[i]->AvgElo;
1521  break;
1522  case BEST_Black:
1523  if (Line[i]->Result != RESULT_Black) { continue; }
1524  v = 1000 - Line[i]->NumMoves;
1525  v = (v << 12) + Line[i]->AvgElo;
1526  break;
1527  case BEST_AvgElo:
1528  v = Line[i]->AvgElo;
1529  break;
1530  case BEST_Oldest:
1531  v = DATE_MAKE(YEAR_MAX,12,31) - Line[i]->Date;
1532  if (Line[i]->Date == ZERO_DATE) { v = 0; }
1533  break;
1534  case BEST_Newest:
1535  v = Line[i]->Date;
1536  break;
1537  default:
1538  ASSERT(0);
1539  break;
1540  }
1541  if (v >= bestValue) {
1542  bestValue = v;
1543  bestIndex = i;
1544  }
1545  }
1546  if (bestIndex < 0) { break; }
1547  char tempStr [10];
1548  sprintf (tempStr, "%2u", c);
1549  dstr->Append (preNum, tempStr, postNum);
1550  Line[bestIndex]->PrintSummary (dstr, Format, printFullDate, true);
1551  if (Line[bestIndex]->NoteNumber != 0) {
1552  if (Format == OPTABLE_LaTeX) {
1553  dstr->Append (" $^{", Line[bestIndex]->NoteNumber, "}$");
1554  } else if (Format == OPTABLE_HTML) {
1555  dstr->Append (" [<a href=\"#note", Line[bestIndex]->NoteNumber);
1556  dstr->Append ("\">", Line[bestIndex]->NoteNumber, "</a>]");
1557  } else if (Format == OPTABLE_CText) {
1558  dstr->Append (" <red><go n", Line[bestIndex]->NoteNumber);
1559  dstr->Append (">[", Line[bestIndex]->NoteNumber,
1560  "]</go></red>");
1561  } else {
1562  dstr->Append (" [", Line[bestIndex]->NoteNumber, "]");
1563  }
1564  }
1565  dstr->Append (endLine);
1566  Line[bestIndex]->Selected = true;
1567  }
1568 
1569  dstr->Append (postList);
1570 }
1571 
1572 // playerFreqT:
1573 // Used in OpTable::TopPlayers() to find the most
1574 // frequent players of a particular color.
1575 //
1576 #define PLAYERFREQ_MAXNOTES 8
1577 struct playerFreqT {
1578  const char * name;
1585  uint oppEloSum; // Sum of opponent Elos.
1586  uint oppEloCount; // Number of games where opponent has Elo rating.
1587  uint oppEloScore; // Score in games where opponent has Elo rating.
1588  uint noteNumber [PLAYERFREQ_MAXNOTES + 1];
1589 };
1590 
1591 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1592 // OpTable::TopPlayers:
1593 // Returns (through dstr) a list of the most frequent players
1594 // of the report line, as White or Black.
1595 void
1597 {
1598  uint i;
1599 
1600  // Set up zero-filled array of player frequencies:
1601  uint largestPlayerID = 0;
1602  for (i=0; i < NumLines; i++) {
1603  uint id = (c == WHITE ? Line[i]->WhiteID : Line[i]->BlackID);
1604  if (id > largestPlayerID) { largestPlayerID = id; }
1605  }
1606 #ifdef WINCE
1607  playerFreqT * pf = (playerFreqT *) my_Tcl_Alloc(sizeof(playerFreqT [largestPlayerID + 1]));
1608 #else
1609  playerFreqT * pf = new playerFreqT [largestPlayerID + 1];
1610 #endif
1611  for (i=0; i <= largestPlayerID; i++) {
1612  pf[i].name = NULL;
1613  pf[i].frequency = 0;
1614  pf[i].minElo = pf[i].maxElo = 0;
1615  pf[i].score = 0;
1616  pf[i].minYear = pf[i].maxYear = 0;
1617  pf[i].oppEloSum = pf[i].oppEloCount = pf[i].oppEloScore = 0;
1618  for (uint n=0; n <= PLAYERFREQ_MAXNOTES; n++) {
1619  pf[i].noteNumber[n] = 0;
1620  }
1621  }
1622 
1623  // Fill in the player frequencies array:
1624  for (i=0; i < NumLines; i++) {
1625  uint id = 0;
1626  eloT elo = 0;
1627  eloT oppElo = 0;
1628  const char * name = NULL;
1629  uint score = 0;
1630  uint year = date_GetYear (Line[i]->Date);
1631  OpLine * line = Line[i];
1632  if (c == WHITE) {
1633  id = line->WhiteID;
1634  elo = line->WhiteElo;
1635  oppElo = line->BlackElo;
1636  name = line->White;
1637  score = RESULT_SCORE[line->Result];
1638  } else {
1639  id = line->BlackID;
1640  elo = line->BlackElo;
1641  oppElo = line->WhiteElo;
1642  name = line->Black;
1643  score = RESULT_SCORE[ RESULT_OPPOSITE[line->Result] ];
1644  }
1645  ASSERT (id <= largestPlayerID);
1646  pf[id].frequency++;
1647  pf[id].name = name;
1648  pf[id].score += score;
1649  if (elo != 0) {
1650  if (pf[id].minElo == 0) { pf[id].minElo = elo; }
1651  if (elo < pf[id].minElo) { pf[id].minElo = elo; }
1652  if (elo > pf[id].maxElo) { pf[id].maxElo = elo; }
1653  }
1654  if (oppElo != 0) {
1655  pf[id].oppEloCount++;
1656  pf[id].oppEloSum += oppElo;
1657  pf[id].oppEloScore += score;
1658  }
1659  if (year != 0) {
1660  if (pf[id].minYear == 0) { pf[id].minYear = year; }
1661  if (year < pf[id].minYear) { pf[id].minYear = year; }
1662  if (year > pf[id].maxYear) { pf[id].maxYear = year; }
1663  }
1664  if (Line[i]->NoteNumber != 0) {
1665  for (uint n=0; n <= PLAYERFREQ_MAXNOTES; n++) {
1666  if (pf[id].noteNumber[n] == Line[i]->NoteNumber) { break; }
1667  if (pf[id].noteNumber[n] == 0) {
1668  pf[id].noteNumber[n] = Line[i]->NoteNumber;
1669  break;
1670  }
1671  }
1672  }
1673  }
1674 
1675  const char * preNum = " ";
1676  const char * postNum = ":";
1677  const char * preElo = "";
1678  const char * postElo = "";
1679  const char * inRange = "-";
1680  const char * percentStr = "%";
1681  const char * startTable = "";
1682  const char * endTable = "";
1683  const char * startRow = "";
1684  const char * endRow = "\n";
1685  const char * startName = "";
1686  const char * endName = "";
1687  const char * nextCell = " ";
1688  const char * startNotes = " [";
1689  const char * endNotes = "]";
1690 
1691  if (Format == OPTABLE_HTML) {
1692  startTable = "<table border=0 cellspacing=0 cellpadding=4>\n";
1693  endTable = "</table>\n";
1694  startRow = "<tr><td align=\"right\">"; endRow = "</td></tr>\n";
1695  nextCell = "</td><td>";
1696  // startTable = "<pre>\n"; endTable = "</pre>\n";
1697  }
1698  if (Format == OPTABLE_CText) {
1699  startRow = "<tt>"; startName = "</tt>";
1700  startNotes = " <red>["; endNotes = "]</red>";
1701  }
1702  if (Format == OPTABLE_LaTeX) {
1703  startTable = "\n\\begin{tabular}{rrrrrl}\n";
1704  endTable = "\\end{tabular}\n";
1705  startRow = " "; endRow = " \\\\ \n";
1706  nextCell = " & "; percentStr = "\\%";
1707  preNum = "\\textbf{"; postNum = ":}";
1708  preElo = " \\emph{"; postElo = "}"; inRange = "--";
1709  startNotes = " $^{"; endNotes = "}$";
1710  }
1711 
1712  dstr->Append (startTable);
1713 
1714  // Now find the "count" most frequent players:
1715  for (uint n=1; n <= count; n++) {
1716  uint maxFreq = 0;
1717  uint maxElo = 0;
1718  int index = 0;
1719  bool found = false;
1720  for (uint id=0; id <= largestPlayerID; id++) {
1721  uint freq = pf[id].frequency;
1722  uint elo = pf[id].maxElo;
1723  if (freq == 0) { continue; }
1724  if ((freq > maxFreq) || (freq == maxFreq && elo > maxElo)) {
1725  found = true;
1726  index = id;
1727  maxFreq = freq;
1728  maxElo = elo;
1729  }
1730  }
1731 
1732  if (found) {
1733  char tempStr [100];
1734  sprintf (tempStr, "%2u", n);
1735  dstr->Append (startRow, preNum, tempStr, postNum);
1736  uint freq = pf[index].frequency;
1737  ASSERT (freq > 0);
1738  ASSERT (pf[index].name != NULL);
1739  sprintf (tempStr, "%3u", freq);
1740  dstr->Append (nextCell, tempStr);
1741 
1742  // Print the year range in which the player played this line:
1743  uint minYear = pf[index].minYear;
1744  uint maxYear = pf[index].maxYear;
1745  if (maxYear == 0) {
1746  strCopy (tempStr, " ");
1747  } else if (minYear == maxYear) {
1748  sprintf (tempStr, " %4u", minYear);
1749  } else {
1750  sprintf (tempStr, "%4u%s%4u",
1751  minYear, inRange, maxYear);
1752  }
1753  dstr->Append (nextCell, " ", tempStr);
1754 
1755  // Print the score with this line:
1756  uint score = (50 * pf[index].score + (freq / 2)) / freq;
1757  sprintf (tempStr, "%3u%s", score, percentStr);
1758  dstr->Append (nextCell, tempStr);
1759 
1760  // Print peak Elo while playing this line:
1761  uint maxElo = pf[index].maxElo;
1762  if (maxElo == 0) {
1763  sprintf (tempStr, "%s %s", preElo, postElo);
1764  } else {
1765  sprintf (tempStr, "%s%4u%s", preElo, maxElo, postElo);
1766  }
1767  dstr->Append (nextCell, " ", tempStr);
1768  dstr->Append (nextCell, " ", startName);
1769  if (Format == OPTABLE_CText) {
1770  dstr->Append ("<pi ", pf[index].name, ">");
1771  }
1772  dstr->Append (pf[index].name);
1773  if (Format == OPTABLE_CText) { dstr->Append ("</pi>"); }
1774  dstr->Append (endName);
1775 
1776  // Print the note numbers containing games by this player:
1777  if (pf[index].noteNumber[0] != 0) {
1778  dstr->Append (startNotes);
1779  for (uint n=0; n < PLAYERFREQ_MAXNOTES; n++) {
1780  if (pf[index].noteNumber[n] == 0) { break; }
1781  if (n > 0) { dstr->Append (","); }
1782  if (Format == OPTABLE_CText) {
1783  dstr->Append ("<go n", pf[index].noteNumber[n]);
1784  dstr->Append (">", pf[index].noteNumber[n], "</go>");
1785 
1786  } else {
1787  dstr->Append (pf[index].noteNumber[n]);
1788  }
1789  }
1790  if (pf[index].noteNumber[PLAYERFREQ_MAXNOTES] != 0) {
1791  dstr->Append (",...");
1792  }
1793  dstr->Append (endNotes);
1794  }
1795  dstr->Append (endRow);
1796  pf[index].frequency = 0;
1797  }
1798  }
1799  dstr->Append (endTable);
1800 
1801  // Delete temporary player frequency data:
1802 #ifdef WINCE
1803  my_Tcl_Free((char*)pf);
1804 #else
1805  delete[] pf;
1806 #endif
1807 }
1808 
1809 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1810 // OpTable::TopEcoCodes:
1811 // Returns (through dstr) a list of the most frequent ECO code
1812 // sections of the report games.
1813 // This is generally only useful for a Player report.
1814 void
1816 {
1817  uint ecoCount [50];
1818  uint ecoScore [50];
1819  uint ecoSubCount[50][10];
1820 
1821  for (uint ecoGroup=0; ecoGroup < 50; ecoGroup++) {
1822  ecoCount[ecoGroup] = 0;
1823  ecoScore[ecoGroup] = 0;
1824  for (uint subCode = 0; subCode < 10; subCode++) {
1825  ecoSubCount[ecoGroup][subCode] = 0;
1826  }
1827  }
1828 
1829  // Fill in the ECO frequencies array:
1830  for (uint i=0; i < NumLines; i++) {
1831  int ecoClass = -1;
1832  int ecoSubCode = -1;
1833  ecoT ecoCode = Line[i]->EcoCode;
1834  if (ecoCode != ECO_None) {
1835  ecoStringT ecoStr;
1836  eco_ToBasicString (ecoCode, ecoStr);
1837  if (ecoStr[0] != 0) {
1838  ecoClass = ((ecoStr[0] - 'A') * 10) + (ecoStr[1] - '0');
1839  if (ecoClass < 0 || ecoClass >= 50) { ecoClass = -1; }
1840  ecoSubCode = (ecoStr[2] - '0');
1841  }
1842  }
1843  if (ecoClass >= 0) {
1844  ecoCount[ecoClass]++;
1845  ecoScore[ecoClass] += RESULT_SCORE[Line[i]->Result];
1846  ecoSubCount[ecoClass][ecoSubCode]++;
1847  }
1848  }
1849 
1850  const char * preNum = " ";
1851  const char * postNum = ":";
1852  const char * inRange = "-";
1853  const char * percentStr = "%";
1854  const char * startTable = "";
1855  const char * endTable = "";
1856  const char * startRow = "";
1857  const char * endRow = "\n";
1858  const char * nextCell = " ";
1859 
1860  if (Format == OPTABLE_HTML) {
1861  startTable = "<table border=0 cellspacing=0 cellpadding=4>\n";
1862  endTable = "</table>\n";
1863  startRow = "<tr><td align=\"right\">"; endRow = "</td></tr>\n";
1864  nextCell = "</td><td align=\"right\">";
1865  // startTable = "<pre>\n"; endTable = "</pre>\n";
1866  }
1867  if (Format == OPTABLE_CText) {
1868  startTable = "<tt>"; endTable = "</tt>";
1869  }
1870  if (Format == OPTABLE_LaTeX) {
1871  startTable = "\n\\begin{tabular}{rlrr}\n";
1872  endTable = "\\end{tabular}\n";
1873  startRow = " "; endRow = " \\\\ \n";
1874  nextCell = " & "; percentStr = "\\%";
1875  preNum = "\\textbf{"; postNum = ":}";
1876  inRange = "--";
1877  }
1878 
1879  dstr->Append (startTable);
1880 
1881  // Now find the "count" most frequent ECO groups:
1882  for (uint n=1; n <= count; n++) {
1883  uint maxFreq = 0;
1884  uint ecoClass = 0;
1885  for (uint i=0; i < 50; i++) {
1886  if (ecoCount[i] > maxFreq) {
1887  ecoClass = i;
1888  maxFreq = ecoCount[i];
1889  }
1890  }
1891  if (maxFreq > 0) {
1892  char ecoStr[8];
1893  strCopy (ecoStr, "A00-E99");
1894  ecoStr[0] = (ecoClass / 10) + 'A';
1895  ecoStr[1] = (ecoClass % 10) + '0';
1896  ecoStr[2] = '0';
1897  ecoStr[3] = 0;
1898 
1899  char tempStr [100];
1900  sprintf (tempStr, "%2u", n);
1901  dstr->Append (startRow, preNum, tempStr, postNum);
1902  dstr->Append (nextCell, ecoStr);
1903  ecoStr[2] = '9';
1904  dstr->Append (inRange, ecoStr);
1905  sprintf (tempStr, "%3u", maxFreq);
1906  dstr->Append (nextCell, tempStr);
1907 
1908  uint score = (50 * ecoScore[ecoClass] + (maxFreq / 2)) / maxFreq;
1909  sprintf (tempStr, "%3u%s", score, percentStr);
1910  dstr->Append (nextCell, tempStr);
1911  dstr->Append (endRow);
1912  ecoCount[ecoClass] = 0;
1913  }
1914  }
1915  dstr->Append (endTable);
1916 }
1917 
1918 uint
1920 {
1921  uint n = 0;
1922  uint sum = 0;
1923  for (uint i=0; i < NumLines; i++) {
1924  if (Line[i]->Result == result) {
1925  n++;
1926  sum += Line[i]->NumMoves;
1927  }
1928  }
1929  if (n == 0) { return 0; }
1930  return (sum / n);
1931 }
1932 
1933 uint
1934 OpTable::AvgElo (colorT color, uint * count, uint * oppScore, uint * oppPerf)
1935 {
1936  uint n = 0;
1937  uint sum = 0;
1938  uint score = 0;
1939  for (uint i=0; i < NumLines; i++) {
1940  eloT elo = (color == WHITE ? Line[i]->WhiteElo : Line[i]->BlackElo);
1941  if (elo > 0) {
1942  n++;
1943  sum += elo;
1944  resultT r = Line[i]->Result;
1945  if (color == WHITE) {
1946  r = RESULT_OPPOSITE[r];
1947  }
1948  if (r == RESULT_White) {
1949  score += 2;
1950  } else if (r == RESULT_Draw || r == RESULT_None) {
1951  score++;
1952  }
1953  }
1954  }
1955  if (count != NULL) { *count = n; }
1956  if (n == 0) {
1957  if (oppScore != NULL) { *oppScore = 0; }
1958  if (oppPerf != NULL) { *oppPerf = 0; }
1959  return 0;
1960  }
1961  uint avgElo = (sum + (n/2)) / n;
1962  uint percent = ((score * 50) + (n/2)) / n;
1963  if (percent > 100) { percent = 100; }
1964  if (oppScore != NULL) { *oppScore = percent; }
1965  if (oppPerf != NULL) {
1966 #ifndef WINCE
1967  *oppPerf = Crosstable::Performance (avgElo, percent);
1968 #endif
1969  }
1970  return (avgElo);
1971 }
1972 
1973 uint
1975 {
1976  uint id = 0;
1977  int index = -1;
1978  DString dstr;
1979  g->GetPartialMoveList (&dstr, g->GetCurrentPly());
1980 
1981  // Search for this move order in the current list:
1982 
1983  for (uint i=0; i < NumMoveOrders; i++) {
1984  if (strEqual (dstr.Data(), MoveOrder[i].moves)) {
1985  index = i;
1986  MoveOrder[i].count++;
1987  id = MoveOrder[i].id;
1988  break;
1989  }
1990  }
1991 
1992  // Add as a new move order if it was not found:
1993 
1994  if (index < 0) {
1995  if (NumMoveOrders == OPTABLE_MAX_LINES) { return 0; }
1996  MoveOrder[NumMoveOrders].count = 1;
1997  MoveOrder[NumMoveOrders].moves = strDuplicate (dstr.Data());
1998  MoveOrder[NumMoveOrders].id = NumMoveOrders + 1;
1999  id = MoveOrder[NumMoveOrders].id;
2000  index = NumMoveOrders;
2001  NumMoveOrders++;
2002  }
2003 
2004  // Keep the array in sorted order, to avoid needing to sort it later:
2005  // The list is sorted by count (highest first), with tied counts
2006  // sorted alphabetically by the move string.
2007 
2008  while (1) {
2009  ASSERT (index >= 0);
2010  if (index <= 0) { break; }
2011  if (MoveOrder[index].count < MoveOrder[index-1].count) { break; }
2012  if (MoveOrder[index].count == MoveOrder[index-1].count &&
2013  strCompare(MoveOrder[index].moves, MoveOrder[index-1].moves) > 0) {
2014  break;
2015  }
2016  // Move the record for the current move order up one slot by
2017  // swapping it with the record before it:
2018  char * tempMoves = MoveOrder[index].moves;
2019  MoveOrder[index].moves = MoveOrder[index-1].moves;
2020  MoveOrder[index-1].moves = tempMoves;
2021  uint tempCount = MoveOrder[index].count;
2022  MoveOrder[index].count = MoveOrder[index-1].count;
2023  MoveOrder[index-1].count = tempCount;
2024  uint tempID = MoveOrder[index].id;
2025  MoveOrder[index].id = MoveOrder[index-1].id;
2026  MoveOrder[index-1].id = tempID;
2027  index--;
2028  }
2029 
2030  return id;
2031 }
2032 
2033 void
2035 {
2036 
2037  const char * preNum = " ";
2038  const char * postNum = ": ";
2039  const char * endLine = "\n";
2040  const char * preList = "";
2041  const char * postList = "";
2042  const char * preCount = " (";
2043  const char * postCount = ")";
2044 
2045  if (Format == OPTABLE_LaTeX) {
2046  preNum = "\\textbf{"; postNum = ":} ";
2047  endLine = "\\\\\n";
2048  preCount = " \\textbf{("; postCount = ")}";
2049  } else if (Format == OPTABLE_HTML) {
2050  preNum = ""; postNum = ": ";
2051  endLine = "<br>\n";
2052  }
2053 
2054  if (count == 0) {
2055  // Just return number of move orders counted, as a string:
2056  dstr->Append (NumMoveOrders);
2057  return;
2058  }
2059 
2060  dstr->Append (preList);
2061 
2062  for (uint i=0; i < count; i++) {
2063  if (i == NumMoveOrders) { break; }
2064  char tempStr [10];
2065  sprintf (tempStr, "%2u", i+1);
2066  dstr->Append (preNum, tempStr, postNum);
2067  if (Format == OPTABLE_CText) {
2068  dstr->Append ("<tab><darkblue>");
2069  dstr->Append ("<run sc_report ", Type, " select mo ");
2070  dstr->Append (MoveOrder[i].id, "; ::windows::stats::Refresh>");
2071  }
2072  OpLine::PrintMove (dstr, MoveOrder[i].moves, Format);
2073  dstr->Append (preCount, MoveOrder[i].count, postCount);
2074  if (Format == OPTABLE_CText) {
2075  dstr->Append ("</run></darkblue></tab>");
2076  }
2077  dstr->Append (endLine);
2078  }
2079  dstr->Append (postList);
2080 }
2081 
2082 void
2083 OpTable::ThemeReport (DString * dstr, uint argc, const char ** argv)
2084 {
2085  const char * endLine = "\n";
2086  const char * percentStr = "%";
2087  const char * startTable = "";
2088  const char * endTable = "";
2089  const char * startRow = " ";
2090  const char * endRow = "\n";
2091  const char * nextCell = " ";
2092  const char * nextCellRight = " ";
2093 
2094  if (argc != (NUM_POSTHEMES + 1)) { return; }
2095 
2096  if (Format == OPTABLE_HTML) {
2097  endLine = "<br>\n";
2098  startTable = "<table border=0 cellspacing=0 cellpadding=4>\n";
2099  endTable = "</table>\n";
2100  startRow = "<tr><td>"; endRow = "</td></tr>\n";
2101  nextCell = "</td><td>"; nextCellRight = "</td><td align=\"right\">";
2102  //startTable = "<pre>\n"; endTable = "</pre>\n";
2103  }
2104  if (Format == OPTABLE_CText) {
2105  startTable = "<tt>"; endTable = "</tt>";
2106  }
2107  if (Format == OPTABLE_LaTeX) {
2108  percentStr = "\\%";
2109  startTable = "\n\\begin{tabular}{lrlr}\n";
2110  endTable = "\\end{tabular}\n";
2111  startRow = ""; endRow = " \\\\ \n";
2112  nextCell = " & "; nextCellRight = nextCell;
2113  }
2114 
2115  // const char * themeName [NUM_POSTHEMES] = {NULL};
2116  // themeName [POSTHEME_CastSame] = "Same-side castling: ";
2117  // themeName [POSTHEME_CastOpp] = "Opposite castling: ";
2118  // themeName [POSTHEME_QueenSwap] = "Queens exchanged: ";
2119  // themeName [POSTHEME_OneBPair] = "Only 1 side has Bishop pair:";
2120  // themeName [POSTHEME_Kstorm] = "Kingside pawn storm: ";
2121  // themeName [POSTHEME_WIQP] = "White Isolated Queen Pawn: ";
2122  // themeName [POSTHEME_BIQP] = "Black Isolated Queen Pawn: ";
2123  // themeName [POSTHEME_WAdvPawn] = "White Pawn on 5/6/7th rank: ";
2124  // themeName [POSTHEME_BAdvPawn] = "Black Pawn on 2/3/4th rank: ";
2125  // themeName [POSTHEME_OpenFyle] = "Open c/d/e file: ";
2126 
2127  char tempStr [250];
2128  //sprintf (tempStr, argv[0], (StartLength + (OPTABLE_COLUMNS * 2)) / 2);
2129  sprintf (tempStr, argv[0], MaxThemeMoveNumber);
2130  dstr->Append (tempStr, endLine);
2131  argc--;
2132  argv++;
2133 
2134  dstr->Append (startTable);
2135  uint leftcol = (NUM_POSTHEMES + 1) / 2;
2136  uint longestLength = 0;
2137  for (uint i=0; i < NUM_POSTHEMES; i++) {
2138  uint len = strLength (argv[i]);
2139  if (len > longestLength) { longestLength = len; }
2140  }
2141 
2142  uint theme = 0;
2143  while (true) {
2144  dstr->Append (theme < leftcol ? startRow : nextCell);
2145  strPad (tempStr, argv[theme], longestLength, ' ');
2146  if (Format == OPTABLE_CText) {
2147  dstr->Append ("<darkblue><run sc_report ", Type, " select theme ");
2148  dstr->Append (theme, "; ::windows::stats::Refresh>");
2149  }
2150  dstr->Append (" ", tempStr);
2151  if (Format == OPTABLE_CText) { dstr->Append ("</run></darkblue>"); }
2152  dstr->Append (nextCellRight);
2153  uint percent = 0;
2154  if (FilterCount > 0) {
2155  percent = ((100 * ThemeCount[theme]) + (FilterCount/2)) / FilterCount;
2156  }
2157  char rstr [16];
2158  sprintf (rstr, "%3u", percent);
2159  dstr->Append (rstr, percentStr);
2160  if (theme < leftcol) {
2161  dstr->Append (" ");
2162  } else {
2163  dstr->Append (endRow);
2164  }
2165  if (theme == NUM_POSTHEMES - 1) { break; }
2166  if (theme < leftcol) {
2167  theme += leftcol;
2168  } else {
2169  theme -= leftcol;
2170  theme++;
2171  }
2172  }
2173  if (NUM_POSTHEMES % 2 == 1) { dstr->Append (endRow); }
2174  dstr->Append (endTable);
2175 }
2176 
2177 void
2178 OpTable::AddEndMaterial (matSigT msig, bool inFilter)
2179 {
2180  uint idx = endgameTheme (msig);
2181  EndgameCount [OPTABLE_All][idx]++;
2182  if (inFilter) {
2183  EndgameCount [OPTABLE_Line][idx]++;
2184  }
2185 }
2186 
2187 void
2188 OpTable::EndMaterialReport (DString * dstr, const char * repGames,
2189  const char * allGames)
2190 {
2191  const char * startTable = "";
2192  const char * endTable = "";
2193  const char * startRow = "";
2194  const char * endRow = "\n";
2195  const char * nextCell = " ";
2196  const char * percentStr = "%";
2197  const char * preNum = "";
2198  const char * postNum = "";
2199 
2200  if (Format == OPTABLE_HTML) {
2201  startTable = "<table border=0 cellspacing=0 cellpadding=4>\n";
2202  endTable = "</table>\n";
2203  startRow = "<tr><td>"; endRow = "</td></tr>\n";
2204  nextCell = "</td><td align=\"right\">";
2205  // startTable = "<pre>\n"; endTable = "</pre>\n";
2206  }
2207  if (Format == OPTABLE_CText) {
2208  startTable = "<tt>"; endTable = "</tt>";
2209  }
2210  if (Format == OPTABLE_LaTeX) {
2211  startTable = "\n\\begin{tabular}{l*{8}{p{0.8cm}}}\n\\hline\n";
2212  endTable = "\\hline\n\\end{tabular}\n";
2213  startRow = ""; endRow = " \\\\ \n";
2214  nextCell = " & "; percentStr = "\\%";
2215  preNum = "\\multicolumn{1}{r}{"; postNum = "}";
2216  }
2217 
2218  char numStr [16];
2219  dstr->Append (startTable);
2220  uint length[2];
2221  length[OPTABLE_Line] = strLength (repGames);
2222  length[OPTABLE_All] = strLength (allGames);
2223 
2224  if (Format == OPTABLE_LaTeX) {
2225  const char * q = " & \\hspace*{\\fill}{\\F Q}\\hspace*{\\fill}";
2226  const char * r = " & \\hspace*{\\fill}{\\F R}\\hspace*{\\fill}";
2227  const char * qr = " & \\hspace*{\\fill}{\\F QR}\\hspace*{\\fill}";
2228  const char * bn = " & \\hspace*{\\fill}{\\F BN}\\hspace*{\\fill}";
2229  const char * p = " & \\hspace*{\\fill}{{\\F p}}\\hspace*{\\fill}";
2230  const char * x = " & ";
2231  dstr->Append (startRow);
2232  dstr->Append (x, x, x, r); dstr->Append (x, q, x, qr);
2233  dstr->Append (endRow, startRow);
2234  dstr->Append (p, bn, r, bn); dstr->Append (q, bn, qr, bn);
2235  dstr->Append (endRow, "\\hline\n");
2236  } else {
2237  dstr->Append(startRow);
2238  uint len = length[OPTABLE_Line];
2239  if (length[OPTABLE_All] > len) { len = length[OPTABLE_All]; }
2240  len++;
2241  for (uint space=0; space < len; space++) { dstr->AddChar (' '); }
2242  char t1[10]; char t2[10];
2243  strcpy(t1, " P"); strcpy(t2, " BN");
2244  transPieces(t1); transPieces(t2);
2245  dstr->Append (nextCell, t1, nextCell, t2);
2246  strcpy(t1, " R"); strcpy(t2, " R,BN");
2247  transPieces(t1); transPieces(t2);
2248  dstr->Append (nextCell, t1, nextCell, t2);
2249  strcpy(t1, " Q"); strcpy(t2, " Q,BN");
2250  transPieces(t1); transPieces(t2);
2251  dstr->Append (nextCell, t1, nextCell, t2);
2252  strcpy(t1, " Q,R"); strcpy(t2, "Q,R,BN");
2253  transPieces(t1); transPieces(t2);
2254  dstr->Append (nextCell, t1, nextCell, t2);
2255 // dstr->Append (nextCell, " P", nextCell, " BN");
2256 // dstr->Append (nextCell, " R", nextCell, " R,BN");
2257 // dstr->Append (nextCell, " Q", nextCell, " Q,BN");
2258 // dstr->Append (nextCell, " Q,R", nextCell, "Q,R,BN");
2259  dstr->Append (endRow);
2260  }
2261  const char * rowName [2] = { repGames, allGames };
2262  for (uint t = OPTABLE_Line; t <= OPTABLE_All; t++) {
2263  dstr->AddChar (' ');
2264  dstr->Append (startRow, rowName[t]);
2265  int diff = length[1-t] - length[t];
2266  while (diff > 0) { dstr->AddChar (' '); diff--; }
2267 
2268  uint i, sum = 0;
2269  for (i=0; i < NUM_EGTHEMES; i++) { sum += EndgameCount[t][i]; }
2270  for (i=0; i < NUM_EGTHEMES; i++) {
2271  uint pc = 0;
2272  if (sum > 0) { pc = ((100 * EndgameCount[t][i]) + (sum/2)) / sum; }
2273  sprintf (numStr, "%5u", pc);
2274  dstr->Append (nextCell);
2275  if (Format == OPTABLE_CText && t == OPTABLE_Line) {
2276  dstr->Append ("<darkblue><run sc_report ", Type);
2277  dstr->Append (" select end ", i, "; ::windows::stats::Refresh>");
2278  }
2279  dstr->Append (preNum, numStr, percentStr, postNum);
2280  if (Format == OPTABLE_CText && t == OPTABLE_Line) {
2281  dstr->Append ("</run></darkblue>");
2282  }
2283  }
2284  dstr->Append (endRow);
2285  }
2286  dstr->Append (endTable);
2287 }
2288 
2289 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2290 // OpTable::SelectGames:
2291 // Given an endgame or opening theme number or note
2292 // number, returns an array with two integer elements
2293 // for every game in the opening report that matches the
2294 // specified theme or note. The type is specified by
2295 // the character 'e' for endgame theme, 'o' for opening
2296 // theme, or 'n' for note number.
2297 // Each pair of elements contains the game number, and
2298 // its start ply. The caller is responsible for deleting
2299 // the allocated array, which ends with a (0,0) pair.
2300 uint *
2301 OpTable::SelectGames (char type, uint number)
2302 {
2303 #ifdef WINCE
2304  uint * matches = (uint *) my_Tcl_Alloc(sizeof( uint [NumLines * 2 + 2]));
2305 #else
2306  uint * matches = new uint [NumLines * 2 + 2];
2307 #endif
2308  uint * match = matches;
2309 
2310  for (uint i=0; i < NumLines; i++) {
2311  OpLine * line = Line[i];
2312  if (line == NULL) { continue; }
2313  if (line->GameNumber == 0) { continue; }
2314  bool selected = false;
2315  if (type == 'e') {
2316  // Only games from one endgame classification:
2317  if (line->EgTheme == number) { selected = true; }
2318  } else if (type == 't') {
2319  // Only games from one positional theme:
2320  if (number < NUM_POSTHEMES
2321  && line->Theme[number] >= POSTHEME_THRESHOLD) {
2322  selected = true;
2323  }
2324  } else if (type == 'n') {
2325  // Only games from one note number:
2326  if (line->NoteNumber == number) { selected = true; }
2327  } else if (type == 'm') {
2328  // Only games from one move order:
2329  if (line->MoveOrderID == number) { selected = true; }
2330  } else if (type == 'a') {
2331  // All games:
2332  selected = true;
2333  }
2334  if (selected) {
2335  *match++ = line->GameNumber;
2336  *match++ = line->StartPly;
2337  }
2338  }
2339  *match++ = 0;
2340  *match++ = 0;
2341  return matches;
2342 }
2343 
2344 //////////////////////////////////////////////////////////////////////
2345 // End of: optable.cpp
2346 //////////////////////////////////////////////////////////////////////
uint oppEloSum
Definition: optable.cpp:1585
uint date_GetYear(dateT date)
Definition: date.h:55
const uint YEAR_MAX
Definition: date.h:42
const uint POSTHEME_CastSame
Definition: optable.h:42
const uint POSTHEME_BIQP
Definition: optable.h:48
byte resultT
Definition: common.h:183
const pieceT BB
Definition: common.h:237
bool posHasAdvancedPawn(Position *pos, colorT c)
Definition: optable.cpp:50
uint strLength(const char *str)
Definition: misc.h:492
const colorT WHITE
Definition: common.h:203
const uint POSTHEME_THRESHOLD
Definition: optable.h:52
void ClearNotes()
Definition: optable.cpp:549
void MakeSANString(simpleMoveT *sm, char *s, sanFlagT flag)
Definition: position.cpp:2114
uint endgameTheme(matSigT msig)
Definition: optable.cpp:20
ushort GetCurrentPly()
Definition: game.h:325
const uint OPTABLE_MAX_ROWS
Definition: optable.h:26
uint AvgElo(colorT color, uint *count, uint *oppScore, uint *oppPerf)
Definition: optable.cpp:1934
uint PercentFreq(resultT result)
Definition: optable.cpp:638
const uint POSTHEME_OneBPair
Definition: optable.h:45
const uint POSTHEME_CastOpp
Definition: optable.h:43
bool AtVarStart()
Definition: game.h:411
bool strEqual(const char *str1, const char *str2)
Definition: misc.h:305
const char * GetBlackStr()
Definition: game.h:442
const errorT OK
Definition: error.h:23
const fyleT D_FYLE
Definition: common.h:360
void Clear()
Definition: optable.cpp:517
const char * strFirstChar(const char *target, char matchChar)
Definition: misc.cpp:297
uint CommonLength(OpLine *line)
Definition: optable.cpp:262
Definition: optable.h:74
const uint OPTABLE_All
Definition: optable.h:65
void AddEndMaterial(matSigT ms, bool inFilter)
Definition: optable.cpp:2178
const fyleT G_FYLE
Definition: common.h:361
const ecoT ECO_None
Definition: common.h:164
char * strDuplicate(const char *original)
Definition: misc.cpp:239
const char * move
Definition: optable.cpp:925
const squareT G6
Definition: common.h:348
const rankT RANK_2
Definition: common.h:355
#define ASSERT(f)
Definition: common.h:67
const squareT H7
Definition: common.h:349
#define PLAYERFREQ_MAXNOTES
Definition: optable.cpp:1576
void GuessNumRows(void)
Definition: optable.cpp:725
const uint OPTABLE_COLUMNS
Definition: optable.h:24
const uint OPTABLE_Text
Definition: optable.h:34
const uint NUM_POSTHEMES
Definition: optable.h:41
const char * Data()
Definition: dstring.h:28
const pieceT BQ
Definition: common.h:237
bool AtStart()
Definition: game.h:405
uint32_t matSigT
Definition: matsig.h:25
const pieceT WQ
Definition: common.h:236
const resultT RESULT_Black
Definition: common.h:187
void MakeRows(void)
Definition: optable.cpp:848
const rankT RANK_3
Definition: common.h:355
const uint OPTABLE_MAX_STARTLINE
Definition: optable.h:32
names
Definition: tablebase.tcl:260
squareT GetKingSquare(colorT c)
Definition: position.h:195
const uint OPTABLE_DEFAULT_ROWS
Definition: optable.h:27
const pieceT BP
Definition: common.h:237
const colorT BLACK
Definition: common.h:204
const uint POSTHEME_OpenFyle
Definition: optable.h:51
bool posHasOpenFyle(Position *pos, fyleT f)
Definition: optable.cpp:78
const resultT RESULT_OPPOSITE[4]
Definition: common.h:194
void PrintHTML(DString *str, const char *title, const char *comment)
Definition: optable.cpp:1142
byte fyleT
Definition: common.h:116
const fyleT H_FYLE
Definition: common.h:361
const uint POSTHEME_WIQP
Definition: optable.h:47
void PrintSummary(DString *dstr, uint format, bool fullDate, bool nmoves)
Definition: optable.cpp:364
char ecoStringT[6]
Definition: common.h:162
const uint EGTHEME_RM
Definition: optable.h:58
static void PrintMove(DString *dstr, const char *move, uint format)
Definition: optable.cpp:273
const uint POSTHEME_Kstorm
Definition: optable.h:46
const fyleT C_FYLE
Definition: common.h:360
void SetFormat(const char *str)
Definition: optable.cpp:584
void date_DecodeToString(dateT date, char *str)
Definition: date.h:90
const char * GetSiteStr()
Definition: game.h:440
const resultT RESULT_Draw
Definition: common.h:188
void MoveToPly(ushort hmNumber)
Definition: game.cpp:830
#define DATE_MAKE(y, m, d)
Definition: date.h:44
const uint OPTABLE_MAX_LINES
Definition: optable.h:30
const dateT ZERO_DATE
Definition: date.h:34
uint minYear
Definition: optable.cpp:1582
const squareT H6
Definition: common.h:348
void Insert(OpLine *subline)
Definition: optable.cpp:245
byte PieceCount(pieceT p)
Definition: position.h:150
void TopPlayers(DString *dstr, colorT c, uint count)
Definition: optable.cpp:1596
matSigT GetFinalMatSig() const
Definition: indexentry.h:329
bool posHasIQP(Position *pos, colorT c)
Definition: optable.cpp:43
colorpct?col?
Definition: ptracker.tcl:77
uint FyleCount(pieceT p, fyleT f)
Definition: position.h:172
const char RESULT_STR[4][4]
Definition: common.h:192
eloT GetBlackElo()
Definition: game.h:448
errorT FindOpcode(Position *pos, const char *opcode, DString *target)
Definition: pbook.cpp:189
const uint OPTABLE_MIN_ROWS
Definition: optable.h:25
void EndMaterialReport(DString *dstr, const char *repGames, const char *allGames)
Definition: optable.cpp:2188
void PrintStemLine(DString *dstr, uint format, bool exclude)
Definition: optable.cpp:1014
const uint POSTHEME_BAdvPawn
Definition: optable.h:50
const pieceT WB
Definition: common.h:236
uint strPad(char *target, const char *original, int width, char padding)
Definition: misc.cpp:268
void AddChar(char ch)
Definition: dstring.h:32
const uint OPTABLE_Line
Definition: optable.h:64
void PrintLaTeX(DString *dstr, const char *title, const char *comment)
Definition: optable.cpp:1051
const squareT H3
Definition: common.h:345
const fyleT E_FYLE
Definition: common.h:360
const resultT RESULT_White
Definition: common.h:186
bool Add(OpLine *line)
Definition: optable.cpp:655
uint32_t uint
Definition: common.h:99
void TopEcoCodes(DString *dstr, uint count)
Definition: optable.cpp:1815
const uint EGTHEME_P
Definition: optable.h:55
const uint EGTHEME_R
Definition: optable.h:57
const squareT H2
Definition: common.h:344
static uint Performance(uint oppAvg, uint percentage)
Definition: crosstab.cpp:36
#define MATSIG_HasBishops(x)
Definition: matsig.h:126
Definition: move.tcl:20
const uint EGTHEME_QR
Definition: optable.h:61
#define MATSIG_HasQueens(x)
Definition: matsig.h:124
const uint OPTABLE_LaTeX
Definition: optable.h:36
const rankT RANK_5
Definition: common.h:355
ushort eloT
Definition: common.h:160
errorT MoveBackup()
Definition: game.cpp:813
uint PercentScore(void)
Definition: optable.cpp:596
int count
Definition: optable.cpp:926
const pieceT PAWN
Definition: common.h:226
Position * GetCurrentPos()
Definition: game.h:348
simpleMoveT * GetCurrentMove()
Definition: game.h:350
const squareT G7
Definition: common.h:349
ushort ecoT
Definition: common.h:161
errorT MoveForward()
Definition: game.cpp:796
const uint OPTABLE_HTML
Definition: optable.h:35
eloT GetAverageElo()
Definition: game.cpp:2955
errorT RestoreState()
Definition: game.cpp:430
const sanFlagT SAN_CHECKTEST
Definition: position.h:40
eloT GetWhiteElo()
Definition: game.h:447
const uint NUM_EGTHEMES
Definition: optable.h:54
void DumpLines(FILE *fp)
Definition: optable.cpp:768
void Append(uint i)
Definition: dstring.h:46
uint RankCount(pieceT p, rankT r)
Definition: position.h:175
ecoT GetEco()
Definition: game.h:453
errorT MoveExitVariation()
Definition: game.cpp:888
bool posHasKPawnStorm(Position *pos, colorT c)
Definition: optable.cpp:62
const uint RESULT_SCORE[4]
Definition: common.h:190
uint TheoryPercent(void)
Definition: optable.cpp:612
const squareT G3
Definition: common.h:345
OpLine * lineList
Definition: optable.cpp:927
Definition: game.h:227
const pieceT WP
Definition: common.h:236
resultT GetResult()
Definition: game.h:446
void ThemeReport(DString *dstr, uint argc, const char **argv)
Definition: optable.cpp:2083
uint oppEloScore
Definition: optable.cpp:1587
uint TheoryScore(void)
Definition: optable.cpp:628
#define MATSIG_HasRooks(x)
Definition: matsig.h:125
const pieceT * GetBoard() const
Definition: position.h:189
const uint OPTABLE_MAX_TABLE_LINES
Definition: optable.h:31
const uint POSTHEME_WAdvPawn
Definition: optable.h:49
void Init(const char *type, Game *g, PBook *ecoBook)
Definition: optable.cpp:461
const uint EGTHEME_QRM
Definition: optable.h:62
const uint EGTHEME_Q
Definition: optable.h:59
const uint OPLINE_MOVES
Definition: optable.h:29
void strCopy(char *target, const char *original)
Definition: misc.h:379
idNumberT GetBlack() const
Definition: indexentry.h:116
const rankT RANK_6
Definition: common.h:355
#define MATSIG_HasKnights(x)
Definition: matsig.h:127
uint frequency
Definition: optable.cpp:1579
uint AvgLength(resultT result)
Definition: optable.cpp:1919
const uint EGTHEME_QM
Definition: optable.h:60
void BestGames(DString *dstr, uint count, const char *rtype)
Definition: optable.cpp:1460
byte colorT
Definition: common.h:112
void PrintNote(DString *dstr, uint movenum, uint start, uint format)
Definition: optable.cpp:318
const char * GetWhiteStr()
Definition: game.h:441
dateT GetDate()
Definition: game.h:444
const uint EGTHEME_M
Definition: optable.h:56
colorT GetToMove()
Definition: position.h:155
uint * SelectGames(char type, uint number)
Definition: optable.cpp:2301
void transPieces(char *s)
Definition: game.cpp:42
const uint POSTHEME_QueenSwap
Definition: optable.h:44
void PrintText(DString *str, const char *title, const char *comment, bool htext)
Definition: optable.cpp:1202
uint noteNumber[PLAYERFREQ_MAXNOTES+1]
Definition: optable.cpp:1588
static uint FormatFromStr(const char *str)
Definition: optable.cpp:564
uint gamenumT
Definition: common.h:159
const resultT RESULT_None
Definition: common.h:185
ushort GetNumHalfMoves()
Definition: game.h:324
const squareT G2
Definition: common.h:344
const rankT RANK_4
Definition: common.h:355
void PopularMoveOrders(DString *dstr, uint count)
Definition: optable.cpp:2034
const rankT RANK_7
Definition: common.h:356
const char * name
Definition: optable.cpp:1578
uint maxYear
Definition: optable.cpp:1583
void eco_ToBasicString(ecoT ecoCode, char *ecoStr)
Definition: misc.h:183
int strCompare(const char *s1, const char *s2)
Definition: misc.h:361
idNumberT GetWhite() const
Definition: indexentry.h:109
void PrintTable(DString *dstr, const char *title, const char *comment)
Definition: optable.cpp:1030
void strStrip(char *str, char ch)
Definition: misc.cpp:329
errorT GetPartialMoveList(DString *str, uint plyCount)
Definition: game.cpp:1854
pieceT piece_Make(colorT c, pieceT p)
Definition: common.h:290
uint AddMoveOrder(Game *g)
Definition: optable.cpp:1974
size_t Length(void)
Definition: dstring.h:30
const uint OPTABLE_CText
Definition: optable.h:37
Definition: pbook.h:38
Definition: indexentry.h:54
uint oppEloCount
Definition: optable.cpp:1586
const char * GetMove(uint depth)
Definition: optable.h:124
void SetPositionalThemes(Position *pos)
Definition: optable.cpp:196
const uint OPTABLE_Compact
Definition: optable.h:38
byte squareT
Definition: common.h:113
byte pieceT
Definition: common.h:111
void SaveState()
Definition: game.cpp:416
fyleT square_Fyle(squareT sq)
Definition: common.h:379
void Clear()
Definition: dstring.h:26