Scid  4.7.0
pbook.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1999-2000 Shane Hudson
3  * Copyright (C) 2017 Fulvio Benini
4 
5  * This file is part of Scid (Shane's Chess Information Database).
6  *
7  * Scid is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation.
10  *
11  * Scid is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "pbook.h"
22 #include "common.h"
23 #include "misc.h"
24 #include "position.h"
25 #include <fstream>
26 
27 namespace {
28 
29 inline const char *
30 epd_findOpcode (const char * epdStr, const char * opcode)
31 {
32  const char * s = epdStr;
33  while (*s != 0) {
34  while (*s == ' ' || *s == '\n') { s++; }
35  if (strIsPrefix (opcode, s)) {
36  const char *codeEnd = s + strLength(opcode);
37  if (*codeEnd == ' ') {
38  return codeEnd + 1;
39  }
40  }
41  while (*s != '\n' && *s != 0) { s++; }
42  }
43  return NULL;
44 }
45 
46 
47 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48 // Position::ReadLine():
49 // Parse a sequence of moves separated by whitespace and
50 // move numbers, e.g. "1.e4 e5 2.Nf3" or "e4 e5 Nf3".
51 //
52 errorT ReadLine(Position& pos, const char* s) {
53  while (true) {
54  while (!isalpha(static_cast<unsigned char>(*s)) && *s != 0) {
55  s++;
56  }
57  if (*s == '\0')
58  return OK;
59 
60  const char* begin = s;
61  while (!isspace(static_cast<unsigned char>(*s)) && *s != '\0') {
62  s++;
63  }
64 
65  simpleMoveT sm;
66  errorT err = pos.ParseMove(&sm, begin, s);
67  if (err != OK)
68  return err;
69 
70  pos.DoSimpleMove(&sm);
71  }
72 }
73 
74 
75 
76 } // namespace
77 
78 std::pair<const char*, const char*> PBook::findECOstr(Position* pos) const {
79  auto range = pos_.equal_range(pos->HashValue());
80  if (range.first == pos_.end())
81  return std::make_pair(nullptr, nullptr);
82 
83  char cboard[36];
84  pos->PrintCompactStr(cboard);
85  auto it = std::find_if(range.first, range.second,
86  [&](const std::pair<const unsigned, bookDataT>& data) {
87  return std::equal(cboard, cboard + 36,
88  data.second.compactStr.get());
89  });
90  if (it == range.second)
91  return std::make_pair(nullptr, nullptr);
92 
93  const char* end = NULL;
94  const char* begin = epd_findOpcode(it->second.comment.get(), "eco");
95  if (begin != NULL) {
96  end = begin;
97  while (*end != '\0' && *end != '\n') {
98  ++end;
99  }
100  }
101  return std::make_pair(begin, end);
102 }
103 
104 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~
105 // PBook::EcoSummary():
106 // Produce a summary from the PBook for the specified ECO code prefix.
107 std::string PBook::EcoSummary(const char* ecoPrefix) const {
108  std::string dstr;
109  uint depth = strLength (ecoPrefix);
110  const char * prevEcoStr = "";
111  for (const char* comment : comments_) {
112  const char * ecoStr = epd_findOpcode (comment, "eco");
113  if (ecoStr != NULL && strIsPrefix (ecoPrefix, ecoStr)) {
114  if (depth < 3 && strPrefix (ecoStr, prevEcoStr) >= depth+1) {
115  continue;
116  }
117  prevEcoStr = ecoStr;
118  while (*ecoStr != '\n' && *ecoStr != 0) {
119  dstr.push_back(*ecoStr);
120  ecoStr++;
121  }
122  dstr.append(" ");
123  const char* movesStr = epd_findOpcode(comment, "moves");
124  while (*movesStr != '\n' && *movesStr != 0) {
125  dstr.push_back(*movesStr);
126  movesStr++;
127  }
128  dstr.push_back('\n');
129  }
130  }
131  return dstr;
132 }
133 
134 std::pair<errorT, std::unique_ptr<PBook> >
135 PBook::ReadEcoFile(const char* FileName) {
136  std::filebuf fp;
137  if (!fp.open(FileName, std::ios::in | std::ios::binary))
138  return std::make_pair(ERROR_FileOpen, nullptr);
139 
140  std::unique_ptr<PBook> pb(new PBook);
141  pb->LineCount = 1;
142  Position std_start;
143  std_start.StdStart();
144  std::string text;
145  std::string moves;
146  ecoStringT ecoStr;
147  ecoT ecoCode;
148  int ch;
149  errorT err = OK;
150  bool done = false;
151 
152  // Loop to read in and add all positions:
153 
154  while (!done) {
155  // Find the next ECO code:
156  while (true) {
157  ch = fp.sbumpc();
158  if (ch == EOF) { done = true; break; }
159  if (ch == '\n') { pb->LineCount++; }
160  if (ch >= 'A' && ch <= 'E') { break; }
161  if (ch == '#') {
162  while (ch != '\n' && ch != EOF) {
163  ch = fp.sbumpc();
164  }
165  if (ch == EOF) { done = true; }
166  pb->LineCount++;
167  }
168  }
169  if (done) { break; }
170 
171  // Read in the rest of the ECO code:
172  ecoStr[0] = ch;
173  ch = fp.sbumpc();
174  if (ch < '0' || ch > '9') { goto corrupt; }
175  ecoStr[1] = ch;
176  ch = fp.sbumpc();
177  if (ch < '0' || ch > '9') { goto corrupt; }
178  ecoStr[2] = ch;
179  ecoStr[3] = 0;
180 
181  // Now check for optional extra part of code, e.g. "A00a1":
182  ch = fp.sbumpc();
183  if (ch >= 'a' && ch <= 'z') {
184  ecoStr[3] = ch; ecoStr[4] = 0;
185  ch = fp.sbumpc();
186  if (ch >= '1' && ch <= '4') {
187  ecoStr[4] = ch; ecoStr[5] = 0;
188  }
189  }
190 
191  // Now put ecoCode in the text string and read the text in quotes:
192  ecoCode = eco_FromString (ecoStr);
193  eco_ToExtendedString (ecoCode, ecoStr);
194  text.clear();
195  text.append("eco ");
196  text.append(ecoStr);
197  text.append(" [");
198 
199  // Find the start of the text:
200  while ((ch = fp.sbumpc()) != '"') {
201  if (ch == EOF) { goto corrupt; }
202  }
203  while ((ch = fp.sbumpc()) != '"') {
204  if (ch == EOF) { goto corrupt; }
205  text.push_back((char) ch);
206  }
207  text.append("]\n");
208 
209  // Now read the position:
210  moves.clear();
211  char prev = 0;
212  while ((ch = fp.sbumpc()) != '*') {
213  if (ch == EOF) { goto corrupt; }
214  if (ch == '\n') {
215  ch = ' ';
216  pb->LineCount++;
217  }
218  if (ch != ' ' || prev != ' ') {
219  moves.push_back((char) ch);
220  }
221  prev = ch;
222  }
223  Position pos (std_start);
224  err = ReadLine(pos, moves.c_str());
225  if (err != OK) { goto corrupt; }
226  text.append("moves ");
227  text.append(strTrimLeft(moves.c_str()));
228  text.push_back('\n');
229 
230  char* cboard = new char[36];
231  pos.PrintCompactStr(cboard);
232  auto it = pb->pos_.emplace(
233  pos.HashValue(), bookDataT{cboard, strDuplicate(text.c_str())});
234  pb->comments_.push_back(it->second.comment.get());
235  pb->LeastMaterial = std::min(pb->LeastMaterial, pos.TotalMaterial());
236  }
237  return std::pair<errorT, std::unique_ptr<PBook> >(OK, std::move(pb));
238 
239 corrupt:
240  return std::make_pair(ERROR_Corrupt, nullptr);
241 }
242 
243 //////////////////////////////////////////////////////////////////////
244 // EOF: pbook.cpp
245 //////////////////////////////////////////////////////////////////////
void PrintCompactStr(char *cboard)
Definition: position.cpp:2578
uint strLength(const char *str)
Definition: misc.h:411
const char * strTrimLeft(const char *target, const char *trimChars)
Definition: misc.cpp:314
const errorT OK
Definition: error.h:23
bool strIsPrefix(const char *prefix, const char *longStr)
Definition: misc.h:331
static std::pair< errorT, std::unique_ptr< PBook > > ReadEcoFile(const char *FileName)
Read a file with a list of ECO codes and creates a PBook object.
Definition: pbook.cpp:135
char * strDuplicate(const char *original)
Definition: misc.cpp:206
void DoSimpleMove(simpleMoveT *sm)
Definition: position.cpp:1578
uint strPrefix(const char *s1, const char *s2)
Definition: misc.h:314
char ecoStringT[6]
Definition: common.h:166
uint TotalMaterial()
Definition: position.h:172
uint32_t uint
Definition: common.h:91
std::string EcoSummary(const char *ecoPrefix) const
Definition: pbook.cpp:107
void StdStart()
Definition: position.h:152
errorT ParseMove(simpleMoveT *sm, const char *str)
Definition: position.cpp:2373
uint HashValue(void)
Definition: position.h:226
ushort ecoT
Definition: common.h:165
void eco_ToExtendedString(ecoT ecoCode, char *ecoStr)
Definition: misc.h:113
unsigned short errorT
Definition: error.h:20
ecoT eco_FromString(const char *ecoStr)
Definition: misc.cpp:36
const errorT ERROR_Corrupt
Definition: error.h:46
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
const errorT ERROR_FileOpen
Definition: error.h:31
A PBook is a collection of chess positions, each with the corresponding ECO code, a mnemonic name...
Definition: pbook.h:37