Line data Source code
1 : /*
2 : * Copyright (c) 1999-2002 Shane Hudson
3 : * Copyright (c) 2006-2009 Pascal Georges
4 : * Copyright (C) 2014-2017 Fulvio Benini
5 :
6 : * This file is part of Scid (Shane's Chess Information Database).
7 : *
8 : * Scid is free software: you can redistribute it and/or modify
9 : * it under the terms of the GNU General Public License as published by
10 : * the Free Software Foundation.
11 : *
12 : * Scid is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with Scid. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #ifndef SCID_INDEXENTRY_H
22 : #define SCID_INDEXENTRY_H
23 :
24 : #include "common.h"
25 : #include "date.h"
26 : #include "matsig.h"
27 : #include "namebase.h"
28 :
29 : // Length is encoded as 17bits uint
30 : #define MAX_GAME_LENGTH 131072
31 :
32 : // HPSIG_SIZE = size of HomePawnData array in an IndexEntry.
33 : // It is nine bytes: the first byte contains the number of valid entries
34 : // in the array, and the next 8 bytes contain up to 16 half-byte entries.
35 : const uint HPSIG_SIZE = 9;
36 :
37 : const eloT MAX_ELO = 4000; // Since we store Elo Ratings in 12 bits
38 :
39 : const byte CUSTOM_FLAG_MASK[] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5 };
40 :
41 : // Total on-disk size per index entry: currently 47 bytes.
42 : const uint INDEX_ENTRY_SIZE = 47;
43 : const uint OLD_INDEX_ENTRY_SIZE = 46;
44 :
45 :
46 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 : // Class IndexEntry: one of these per game in the index file.
48 : //
49 : // It contains more than just the location of the game data in the main
50 : // data file. For fast searching, it also store some other important
51 : // values: players, event, site, date, result, eco, gamelength.
52 : //
53 : // It takes 56 bytes.
54 : class IndexEntry {
55 : uint64_t offset_ : 46; // Start of gamefile record for this game.
56 : uint64_t gameDataSize_ : 18; // Length of gamefile record for this game.
57 :
58 : uint64_t storedLineCode_ : 8;
59 : uint64_t whiteID_ : 28;
60 : uint64_t blackID_ : 28;
61 :
62 : uint32_t eventID_ : 28;
63 : uint32_t whiteEloType_ : 4;
64 :
65 : uint32_t siteID_ : 28;
66 : uint32_t blackEloType_ : 4;
67 :
68 : uint32_t roundID_ : 28;
69 : uint32_t result_ : 4;
70 :
71 : uint32_t whiteElo_ : 12;
72 : uint32_t date_ : 20;
73 :
74 : uint32_t blackElo_ : 12;
75 : uint32_t eventDate_ : 20;
76 :
77 : uint32_t numHalfMoves_ : 10;
78 : uint32_t flags_ : 22;
79 :
80 : uint32_t finalMatSig_ : 24; // material of the final position in the game
81 : uint32_t nVariations_ : 4;
82 : uint32_t nComments_ : 4;
83 :
84 : uint16_t ECOcode_;
85 :
86 : uint8_t nNags_ : 4;
87 :
88 : byte HomePawnData [HPSIG_SIZE]; // homePawnSig data.
89 :
90 : public:
91 9015 : void Init() { std::memset(this, 0, sizeof(IndexEntry)); }
92 :
93 : template <class T> errorT Write (T* file, versionT version) const;
94 :
95 : // get functions
96 837378 : uint64_t GetOffset() const { return offset_; }
97 967378 : uint32_t GetLength() const { return gameDataSize_; }
98 964114 : idNumberT GetWhite() const { return whiteID_; }
99 838301 : eloT GetWhiteElo() const { return whiteElo_; }
100 718354 : byte GetWhiteRatingType() const { return whiteEloType_; }
101 1068099 : idNumberT GetBlack() const { return blackID_; }
102 913741 : eloT GetBlackElo() const { return blackElo_; }
103 718354 : byte GetBlackRatingType() const { return blackEloType_; }
104 924929 : idNumberT GetEvent() const { return eventID_; }
105 1141795 : idNumberT GetSite() const { return siteID_; }
106 1071901 : idNumberT GetRound() const { return roundID_; }
107 848872 : dateT GetDate() const { return date_; }
108 827822 : dateT GetEventDate() const { return eventDate_; }
109 1577122 : resultT GetResult() const { return result_; }
110 542771 : uint GetVariationCount() const { return DecodeCount(nVariations_); }
111 564566 : uint GetCommentCount() const { return DecodeCount(nComments_); }
112 526713 : uint GetNagCount() const { return DecodeCount(nNags_); }
113 899862 : uint16_t GetNumHalfMoves() const { return numHalfMoves_; }
114 821354 : matSigT GetFinalMatSig() const { return finalMatSig_; }
115 821354 : byte GetStoredLineCode() const { return storedLineCode_; }
116 821416 : ecoT GetEcoCode() const { return ECOcode_; }
117 3185066 : bool GetFlag(uint32_t mask) const { return (flags_ & mask) == mask; }
118 104000 : const byte* GetHomePawnData() const { return HomePawnData; }
119 3813354 : byte* GetHomePawnData() { return HomePawnData; }
120 :
121 : // set functions, assert that the value is not truncated.
122 316357 : void SetOffset(uint64_t offset) {
123 316357 : offset_ = offset;
124 316357 : ASSERT(GetOffset() == offset);
125 316357 : }
126 316357 : void SetLength(size_t length) {
127 316357 : gameDataSize_ = length;
128 316357 : ASSERT(GetLength() == length);
129 316357 : }
130 319357 : void SetWhite(idNumberT id) {
131 319357 : whiteID_ = id;
132 319357 : ASSERT(GetWhite() == id);
133 319357 : }
134 313354 : void SetWhiteElo(eloT elo) {
135 313354 : whiteElo_ = elo;
136 313354 : ASSERT(GetWhiteElo() == elo);
137 313354 : }
138 313354 : void SetWhiteRatingType(byte b) {
139 313354 : whiteEloType_ = b;
140 313354 : ASSERT(GetWhiteRatingType() == b);
141 313354 : }
142 319357 : void SetBlack(idNumberT id) {
143 319357 : blackID_ = id;
144 319357 : ASSERT(GetBlack() == id);
145 319357 : }
146 313354 : void SetBlackElo(eloT elo) {
147 313354 : blackElo_ = elo;
148 313354 : ASSERT(GetBlackElo() == elo);
149 313354 : }
150 313354 : void SetBlackRatingType(byte b) {
151 313354 : blackEloType_ = b;
152 313354 : ASSERT(GetBlackRatingType() == b);
153 313354 : }
154 319357 : void SetEvent(idNumberT id) {
155 319357 : eventID_ = id;
156 319357 : ASSERT(GetEvent() == id);
157 319357 : }
158 319357 : void SetSite(idNumberT id) {
159 319357 : siteID_ = id;
160 319357 : ASSERT(GetSite() == id);
161 319357 : }
162 319357 : void SetRound(idNumberT id) {
163 319357 : roundID_ = id;
164 319357 : ASSERT(GetRound() == id);
165 319357 : }
166 313354 : void SetDate(dateT date) {
167 313354 : date_ = date;
168 313354 : ASSERT(GetDate() == date);
169 313354 : }
170 313354 : void SetEventDate(dateT edate) {
171 313354 : eventDate_ = edate;
172 313354 : ASSERT(GetEventDate() == edate);
173 313354 : }
174 313354 : void SetResult(resultT res) {
175 313354 : result_ = res;
176 313354 : ASSERT(GetResult() == res);
177 313354 : }
178 209015 : void SetVariationCount(unsigned x) { nVariations_ = EncodeCount(x); }
179 209015 : void SetCommentCount(unsigned x) { nComments_ = EncodeCount(x); }
180 209015 : void SetNagCount(unsigned x) { nNags_ = EncodeCount(x); }
181 204339 : void SetRawVariationCount(unsigned x) {
182 204339 : nVariations_ = x;
183 204339 : ASSERT(x == nVariations_);
184 204339 : }
185 204339 : void SetRawCommentCount(unsigned x) {
186 204339 : nComments_ = x;
187 204339 : ASSERT(x == nComments_);
188 204339 : }
189 204339 : void SetRawNagCount(unsigned x) {
190 204339 : nNags_ = x;
191 204339 : ASSERT(x == nNags_);
192 204339 : }
193 313354 : void SetNumHalfMoves(ushort b) {
194 313354 : numHalfMoves_ = b;
195 313354 : ASSERT(GetNumHalfMoves() == b);
196 313354 : }
197 313354 : void SetFinalMatSig(matSigT ms) {
198 313354 : finalMatSig_ = ms;
199 313354 : ASSERT(GetFinalMatSig() == ms);
200 313354 : }
201 313354 : void SetStoredLineCode(byte b) {
202 313354 : storedLineCode_ = b;
203 313354 : ASSERT(GetStoredLineCode() == b);
204 313354 : }
205 313354 : void SetEcoCode(ecoT eco) {
206 313354 : ECOcode_ = eco;
207 313354 : ASSERT(GetEcoCode() == eco);
208 313354 : }
209 1303754 : void SetFlag(uint32_t flagMask, bool set) {
210 1303754 : if (set)
211 625887 : flags_ |= flagMask;
212 : else
213 677867 : flags_ &= ~flagMask;
214 1303754 : }
215 :
216 : // Handy functions that do not directly access member vars.
217 67762 : uint GetYear () const { return date_GetYear (GetDate()); }
218 : uint GetMonth() const { return date_GetMonth (GetDate()); }
219 : uint GetDay () const { return date_GetDay (GetDate()); }
220 :
221 : void SetPlayer(colorT col, idNumberT id) {
222 : return (col == BLACK) ? SetBlack(id) : SetWhite(id);
223 : }
224 :
225 6356 : const char* GetWhiteName (const NameBase* nb) const {
226 6356 : return nb->GetName (NAME_PLAYER, GetWhite());
227 : }
228 5017 : const char* GetBlackName (const NameBase* nb) const {
229 5017 : return nb->GetName (NAME_PLAYER, GetBlack());
230 : }
231 7695 : const char* GetEventName (const NameBase* nb) const {
232 7695 : return nb->GetName (NAME_EVENT, GetEvent());
233 : }
234 197200 : const char* GetSiteName (const NameBase* nb) const {
235 197200 : return nb->GetName (NAME_SITE, GetSite());
236 : }
237 5017 : const char* GetRoundName (const NameBase* nb) const {
238 5017 : return nb->GetName (NAME_ROUND, GetRound());
239 : }
240 70461 : eloT GetWhiteElo (const NameBase* nb) const {
241 70461 : eloT r = GetWhiteElo();
242 70461 : if (r == 0 && nb != 0) return nb->GetElo (GetWhite());
243 60467 : return r;
244 : }
245 145901 : eloT GetBlackElo (const NameBase* nb) const {
246 145901 : eloT r = GetBlackElo();
247 145901 : if (r == 0 && nb != 0) return nb->GetElo (GetBlack());
248 112817 : return r;
249 : }
250 : byte GetRating(const NameBase* nb) const;
251 :
252 100000 : bool GetStartFlag () const { return GetFlag(1 << IDX_FLAG_START); }
253 100000 : bool GetPromotionsFlag () const { return GetFlag(1 << IDX_FLAG_PROMO); }
254 100000 : bool GetUnderPromoFlag() const { return GetFlag(1 << IDX_FLAG_UPROMO); }
255 100000 : bool GetCommentsFlag () const { return (GetCommentCount() > 0); }
256 100000 : bool GetVariationsFlag () const { return (GetVariationCount() > 0); }
257 100000 : bool GetNagsFlag () const { return (GetNagCount() > 0); }
258 166066 : bool GetDeleteFlag () const { return GetFlag(1 << IDX_FLAG_DELETE); }
259 :
260 : static uint CharToFlag (char ch);
261 : static uint32_t CharToFlagMask (char flag);
262 : static uint32_t StrToFlagMask (const char* flags);
263 : uint GetFlagStr(char* dest, const char* flags) const;
264 :
265 109015 : void SetStartFlag (bool b) { SetFlag(1 << IDX_FLAG_START, b); }
266 109015 : void SetPromotionsFlag (bool b) { SetFlag(1 << IDX_FLAG_PROMO, b); }
267 109015 : void SetUnderPromoFlag (bool b) { SetFlag(1 << IDX_FLAG_UPROMO, b); }
268 100000 : void SetDeleteFlag (bool b) { SetFlag(1 << IDX_FLAG_DELETE, b); }
269 463355 : void clearFlags() { return SetFlag(IDX_MASK_ALLFLAGS, false); }
270 :
271 : enum {
272 : // IndexEntry Flag types:
273 : IDX_FLAG_START = 0, // Game has own start position.
274 : IDX_FLAG_PROMO = 1, // Game contains promotion(s).
275 : IDX_FLAG_UPROMO = 2, // Game contains promotion(s).
276 : IDX_FLAG_DELETE = 3, // Game marked for deletion.
277 : IDX_FLAG_WHITE_OP = 4, // White openings flag.
278 : IDX_FLAG_BLACK_OP = 5, // Black openings flag.
279 : IDX_FLAG_MIDDLEGAME = 6, // Middlegames flag.
280 : IDX_FLAG_ENDGAME = 7, // Endgames flag.
281 : IDX_FLAG_NOVELTY = 8, // Novelty flag.
282 : IDX_FLAG_PAWN = 9, // Pawn structure flag.
283 : IDX_FLAG_TACTICS = 10, // Tactics flag.
284 : IDX_FLAG_KSIDE = 11, // Kingside play flag.
285 : IDX_FLAG_QSIDE = 12, // Queenside play flag.
286 : IDX_FLAG_BRILLIANCY = 13, // Brilliancy or good play.
287 : IDX_FLAG_BLUNDER = 14, // Blunder or bad play.
288 : IDX_FLAG_USER = 15, // User-defined flag.
289 : IDX_FLAG_CUSTOM1 = 16, // Custom flag.
290 : IDX_FLAG_CUSTOM2 = 17, // Custom flag.
291 : IDX_FLAG_CUSTOM3 = 18, // Custom flag.
292 : IDX_FLAG_CUSTOM4 = 19, // Custom flag.
293 : IDX_FLAG_CUSTOM5 = 20, // Custom flag.
294 : IDX_FLAG_CUSTOM6 = 21, // Custom flag.
295 : IDX_NUM_FLAGS = 22,
296 : };
297 : static const uint32_t IDX_MASK_ALLFLAGS = 0xFFFFFFFF;
298 :
299 : private:
300 627045 : static uint EncodeCount (uint x) {
301 627045 : if (x <= 10) { return x; }
302 251081 : if (x <= 12) { return 10; }
303 238999 : if (x <= 17) { return 11; } // 11 indicates 15 (13-17)
304 208776 : if (x <= 24) { return 12; } // 12 indicates 20 (18-24)
305 166242 : if (x <= 34) { return 13; } // 13 indicates 30 (25-34)
306 105448 : if (x <= 44) { return 14; } // 14 indicates 40 (35-44)
307 45165 : return 15; // 15 indicates 50 or more
308 : }
309 1634050 : static uint DecodeCount (uint x) {
310 : static uint countCodes[16] = {0,1,2,3,4,5,6,7,8,9,10,15,20,30,40,50};
311 1634050 : return countCodes[x & 15];
312 : }
313 : };
314 :
315 :
316 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
317 : // IndexEntry::Write():
318 : // Writes a single index entry to an open index file.
319 : // INDEX_ENTRY_SIZE must be updated
320 104000 : template <class T> errorT IndexEntry::Write(T* file, versionT version) const {
321 104000 : if (version < 400) // Cannot write old-version index files:
322 0 : return ERROR_FileVersion;
323 :
324 : char buf[INDEX_ENTRY_SIZE];
325 104000 : char* buf_it = buf;
326 4160000 : auto WriteOneByte = [&buf_it](uint8_t v) { *buf_it++ = v; };
327 3640000 : auto WriteTwoBytes = [&WriteOneByte](uint16_t v) {
328 1768000 : WriteOneByte(static_cast<uint8_t>(v >> 8));
329 1768000 : WriteOneByte(static_cast<uint8_t>(v));
330 1768000 : };
331 728000 : auto WriteFourBytes = [&WriteTwoBytes](uint32_t v) {
332 312000 : WriteTwoBytes(static_cast<uint16_t>(v >> 16));
333 312000 : WriteTwoBytes(static_cast<uint16_t>(v));
334 312000 : };
335 :
336 104000 : const IndexEntry* ie = this;
337 :
338 104000 : ASSERT(ie->GetOffset() < (1ULL << 32));
339 104000 : WriteFourBytes(static_cast<uint32_t>(ie->GetOffset()));
340 :
341 104000 : ASSERT(ie->GetLength() < (1ULL << 17));
342 104000 : WriteTwoBytes(static_cast<uint16_t>(ie->GetLength()));
343 104000 : uint8_t len_flags = static_cast<uint8_t>(ie->GetLength() >> 9) & 0x80;
344 104000 : len_flags |= static_cast<uint8_t>(ie->flags_ >> 16) & 0x3F;
345 104000 : WriteOneByte(len_flags);
346 104000 : WriteTwoBytes(static_cast<uint16_t>(ie->flags_));
347 :
348 : // WhiteID and BlackID are 20-bit values, EventID and SiteID are
349 : // 19-bit values, and RoundID is an 18-bit value.
350 : // WhiteID high 4 bits = bits 4-7 of WhiteBlack_High.
351 : // BlackID high 4 bits = bits 0-3 of WhiteBlack_High.
352 : // EventID high 3 bits = bits 5-7 of EventSiteRnd_high.
353 : // SiteID high 3 bits = bits 2-4 of EventSiteRnd_high.
354 : // RoundID high 2 bits = bits 0-1 of EventSiteRnd_high.
355 104000 : ASSERT(std::max(ie->GetWhite(), ie->GetBlack()) < (1ULL << 20));
356 104000 : uint32_t WhiteID_Low = ie->GetWhite();
357 104000 : uint32_t BlackID_Low = ie->GetBlack();
358 104000 : uint32_t WhiteBlack_High = (WhiteID_Low & 0x0F0000) >> 12;
359 104000 : WhiteBlack_High |= (BlackID_Low & 0x0F0000) >> 16;
360 104000 : WriteOneByte(static_cast<uint8_t>(WhiteBlack_High));
361 104000 : WriteTwoBytes(static_cast<uint16_t>(WhiteID_Low));
362 104000 : WriteTwoBytes(static_cast<uint16_t>(BlackID_Low));
363 :
364 104000 : ASSERT(std::max(ie->GetEvent(), ie->GetSite()) < (1ULL << 19));
365 104000 : ASSERT(ie->GetRound() < (1ULL << 18));
366 104000 : uint32_t EventID_Low = ie->GetEvent();
367 104000 : uint32_t SiteID_Low = ie->GetSite();
368 104000 : uint32_t RoundID_Low = ie->GetRound();
369 104000 : uint32_t EventSiteRnd_High = (EventID_Low & 0x070000) >> 11;
370 104000 : EventSiteRnd_High |= (SiteID_Low & 0x070000) >> 14;
371 104000 : EventSiteRnd_High |= (RoundID_Low & 0x030000) >> 16;
372 104000 : WriteOneByte(static_cast<uint8_t>(EventSiteRnd_High));
373 104000 : WriteTwoBytes(static_cast<uint16_t>(EventID_Low));
374 104000 : WriteTwoBytes(static_cast<uint16_t>(SiteID_Low));
375 104000 : WriteTwoBytes(static_cast<uint16_t>(RoundID_Low));
376 :
377 104000 : uint16_t varCounts = ie->nVariations_ & 0x0F;
378 104000 : varCounts |= static_cast<uint16_t>(ie->nComments_ & 0x0F) << 4;
379 104000 : varCounts |= static_cast<uint16_t>(ie->nNags_ & 0x0F) << 8;
380 104000 : varCounts |= static_cast<uint16_t>(ie->GetResult() & 0x0F) << 12;
381 104000 : WriteTwoBytes(varCounts);
382 :
383 104000 : WriteTwoBytes(ie->GetEcoCode());
384 :
385 : // Due to a compact encoding format, the EventDate
386 : // must be within a few years of the Date.
387 104000 : uint32_t date = ie->GetDate() & 0xFFFFF;
388 104000 : uint32_t edate = ie->GetEventDate();
389 104000 : uint32_t eyear = date_GetYear(edate);
390 104000 : uint32_t dyear = date_GetYear(date);
391 104000 : if ((eyear + 3) < dyear || eyear > (dyear + 3)) {
392 99656 : edate = ZERO_DATE;
393 : } else {
394 4344 : eyear = (eyear + 4 - dyear) & 7;
395 4344 : edate = (eyear << 9) | (date_GetMonth(edate) << 5) | date_GetDay(edate);
396 : }
397 104000 : WriteFourBytes((edate << 20) | date);
398 :
399 : // Elo ratings and rating types: 2 bytes each.
400 104000 : uint16_t wElo = std::min(MAX_ELO, ie->GetWhiteElo());
401 104000 : wElo |= static_cast<uint16_t>(ie->GetWhiteRatingType()) << 12;
402 104000 : uint16_t bElo = std::min(MAX_ELO, ie->GetBlackElo());
403 104000 : bElo |= static_cast<uint16_t>(ie->GetBlackRatingType()) << 12;
404 104000 : WriteTwoBytes(wElo);
405 104000 : WriteTwoBytes(bElo);
406 :
407 104000 : ASSERT(ie->GetFinalMatSig() < (1ULL << 24));
408 104000 : ASSERT(ie->GetStoredLineCode() < (1ULL << 8));
409 104000 : uint32_t FinalMatSig = ie->GetFinalMatSig();
410 104000 : FinalMatSig |= static_cast<uint32_t>(ie->GetStoredLineCode()) << 24;
411 104000 : WriteFourBytes(FinalMatSig);
412 :
413 : // The first byte of HomePawnData has high bits of the NumHalfMoves
414 : // counter in its top two bits:
415 104000 : uint16_t nMoves = ie->GetNumHalfMoves();
416 104000 : ASSERT(nMoves < (1ULL << 10));
417 104000 : WriteOneByte(static_cast<uint8_t>(nMoves));
418 104000 : uint8_t pawnData0 = static_cast<uint8_t>(nMoves >> 8) << 6;
419 :
420 : // Write the 9-byte homePawnData array:
421 104000 : const byte* pb = ie->GetHomePawnData();
422 104000 : pawnData0 |= *pb & 0x3F;
423 104000 : WriteOneByte(pawnData0);
424 104000 : std::copy(pb + 1, pb + HPSIG_SIZE, buf_it);
425 :
426 104000 : return file->sputn(buf, INDEX_ENTRY_SIZE) == INDEX_ENTRY_SIZE
427 104000 : ? OK
428 104000 : : ERROR_FileWrite;
429 : }
430 :
431 33129 : inline byte IndexEntry::GetRating(const NameBase* nb) const {
432 33129 : eloT welo = GetWhiteElo();
433 33129 : eloT belo = GetBlackElo();
434 33129 : if (welo == 0) { welo = nb->GetElo (GetWhite()); }
435 33129 : if (belo == 0) { belo = nb->GetElo (GetBlack()); }
436 33129 : int rating = static_cast<int>(welo + belo) / 140;
437 :
438 : // Bonus for comments or Nags
439 33129 : if (GetCommentCount() > 2 || GetNagCount() > 2) {
440 47 : if (rating < 21) { // Missing elo
441 0 : rating = 40;
442 : } else {
443 47 : rating += 6;
444 : }
445 : }
446 :
447 : // Early draw penalty
448 33129 : if (GetResult() == RESULT_Draw) {
449 13204 : uint moves = GetNumHalfMoves();
450 13204 : if (moves < 80) {
451 7471 : rating -= 3;
452 7471 : if (moves < 60) {
453 5088 : rating -= 2;
454 5088 : if (moves < 40) rating -= 2;
455 : }
456 : }
457 : }
458 :
459 33129 : if (rating < 0) return 0;
460 33074 : else return static_cast<byte> (rating);
461 : }
462 :
463 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
464 : // IndexEntry::CharToFlag():
465 : // Returns the flag number corresponding to the given character.
466 : inline uint
467 : IndexEntry::CharToFlag (char ch)
468 : {
469 : uint flag = 0;
470 : switch (toupper(ch)) {
471 : case 'D': flag = IDX_FLAG_DELETE; break;
472 : case 'W': flag = IDX_FLAG_WHITE_OP; break;
473 : case 'B': flag = IDX_FLAG_BLACK_OP; break;
474 : case 'M': flag = IDX_FLAG_MIDDLEGAME; break;
475 : case 'E': flag = IDX_FLAG_ENDGAME; break;
476 : case 'N': flag = IDX_FLAG_NOVELTY; break;
477 : case 'P': flag = IDX_FLAG_PAWN; break;
478 : case 'T': flag = IDX_FLAG_TACTICS; break;
479 : case 'K': flag = IDX_FLAG_KSIDE; break;
480 : case 'Q': flag = IDX_FLAG_QSIDE; break;
481 : case '!': flag = IDX_FLAG_BRILLIANCY; break;
482 : case '?': flag = IDX_FLAG_BLUNDER; break;
483 : case 'U': flag = IDX_FLAG_USER; break;
484 : case '1': flag = IDX_FLAG_CUSTOM1; break;
485 : case '2': flag = IDX_FLAG_CUSTOM2; break;
486 : case '3': flag = IDX_FLAG_CUSTOM3; break;
487 : case '4': flag = IDX_FLAG_CUSTOM4; break;
488 : case '5': flag = IDX_FLAG_CUSTOM5; break;
489 : case '6': flag = IDX_FLAG_CUSTOM6; break;
490 : }
491 : return flag;
492 : }
493 :
494 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
495 : // IndexEntry::CharToFlagMask():
496 : // Transform a char in a mask that can be used with GetFlag() and SetFlag()
497 19000 : inline uint32_t IndexEntry::CharToFlagMask(char flag)
498 : {
499 19000 : switch (toupper(flag)) {
500 0 : case 'S': return 1 << IDX_FLAG_START;
501 0 : case 'X': return 1 << IDX_FLAG_PROMO;
502 0 : case 'Y': return 1 << IDX_FLAG_UPROMO;
503 1000 : case 'D': return 1 << IDX_FLAG_DELETE;
504 1000 : case 'W': return 1 << IDX_FLAG_WHITE_OP;
505 1000 : case 'B': return 1 << IDX_FLAG_BLACK_OP;
506 1000 : case 'M': return 1 << IDX_FLAG_MIDDLEGAME;
507 1000 : case 'E': return 1 << IDX_FLAG_ENDGAME;
508 1000 : case 'N': return 1 << IDX_FLAG_NOVELTY;
509 1000 : case 'P': return 1 << IDX_FLAG_PAWN;
510 1000 : case 'T': return 1 << IDX_FLAG_TACTICS;
511 1000 : case 'K': return 1 << IDX_FLAG_KSIDE;
512 1000 : case 'Q': return 1 << IDX_FLAG_QSIDE;
513 1000 : case '!': return 1 << IDX_FLAG_BRILLIANCY;
514 1000 : case '?': return 1 << IDX_FLAG_BLUNDER;
515 1000 : case 'U': return 1 << IDX_FLAG_USER;
516 1000 : case '1': return 1 << IDX_FLAG_CUSTOM1;
517 1000 : case '2': return 1 << IDX_FLAG_CUSTOM2;
518 1000 : case '3': return 1 << IDX_FLAG_CUSTOM3;
519 1000 : case '4': return 1 << IDX_FLAG_CUSTOM4;
520 1000 : case '5': return 1 << IDX_FLAG_CUSTOM5;
521 1000 : case '6': return 1 << IDX_FLAG_CUSTOM6;
522 : }
523 :
524 0 : ASSERT(0);
525 : return 0;
526 : }
527 :
528 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
529 : // IndexEntry::StrToFlagMask():
530 : // Transform a string in a mask that can be used with GetFlag() and SetFlag()
531 9015 : inline uint32_t IndexEntry::StrToFlagMask(const char* flags)
532 : {
533 9015 : if (flags == 0) return 0;
534 :
535 9015 : uint32_t res = 0;
536 9015 : while (*flags != 0) {
537 0 : res |= IndexEntry::CharToFlagMask(*(flags++));
538 : }
539 9015 : return res;
540 : }
541 :
542 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
543 : // IndexEntry::GetFlagStr():
544 : // Fills in the provided flag string with information on the
545 : // user-settable flags set for this game.
546 : // Returns the number of specified flags that are turned on.
547 : inline uint
548 1000 : IndexEntry::GetFlagStr(char* dest, const char* flags) const
549 : {
550 1000 : if (flags == NULL) { flags = "DWBMENPTKQ!?U123456"; }
551 1000 : uint count = 0;
552 39000 : while (*flags != 0) {
553 19000 : uint32_t mask = CharToFlagMask(*flags);
554 19000 : ASSERT(mask != 0);
555 19000 : if (GetFlag(mask)) {
556 0 : *dest++ = *flags;
557 0 : count++;
558 : }
559 19000 : flags++;
560 : }
561 1000 : *dest = 0;
562 1000 : return count;
563 : }
564 :
565 : #endif
|