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