Line data Source code
1 : //////////////////////////////////////////////////////////////////////
2 : //
3 : // FILE: game.h
4 : // Game class for Scid.
5 : //
6 : // Part of: Scid (Shane's Chess Information Database)
7 : // Version: 3.5
8 : //
9 : // Notice: Copyright (c) 2000-2003 Shane Hudson. All rights reserved.
10 : //
11 : // Author: Shane Hudson (sgh@users.sourceforge.net)
12 : //
13 : //////////////////////////////////////////////////////////////////////
14 :
15 :
16 : #ifndef SCID_GAME_H
17 : #define SCID_GAME_H
18 :
19 : #include "common.h"
20 : #include "date.h"
21 : #include "indexentry.h"
22 : #include "matsig.h"
23 : #include "movetree.h"
24 : #include "namebase.h"
25 : #include "position.h"
26 : #include <forward_list>
27 : #include <memory>
28 : #include <string>
29 : #include <vector>
30 : class ByteBuffer;
31 : class TextBuffer;
32 :
33 : void transPieces(char *s);
34 : char transPiecesChar(char c);
35 :
36 : // Piece letters translation
37 : extern int language; // default to english
38 : // 0 = en, 1 = fr, 2 = es, 3 = de
39 : extern const char * langPieces[];
40 :
41 : //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42 : // Game: Constants
43 :
44 : // Common NAG Annotation symbol values:
45 : const byte
46 : NAG_GoodMove = 1,
47 : NAG_PoorMove = 2,
48 : NAG_ExcellentMove = 3,
49 : NAG_Blunder = 4,
50 : NAG_InterestingMove = 5,
51 : NAG_DubiousMove = 6,
52 : NAG_OnlyMove = 8, // new
53 : NAG_Equal = 10,
54 : NAG_Unclear = 13,
55 : NAG_WhiteSlight = 14,
56 : NAG_BlackSlight = 15,
57 : NAG_WhiteClear = 16,
58 : NAG_BlackClear = 17,
59 : NAG_WhiteDecisive = 18,
60 : NAG_BlackDecisive = 19,
61 : NAG_WhiteCrushing = 20,
62 : NAG_BlackCrushing = 21,
63 : NAG_ZugZwang = 22, // new
64 : NAG_BlackZugZwang = 23, // new
65 : NAG_MoreRoom = 26, // new
66 : NAG_DevelopmentAdvantage = 35, // new
67 : NAG_WithInitiative = 36, //new
68 : NAG_WithAttack = 40, // new
69 : NAG_WithBlackAttack = 41, // new
70 : NAG_Compensation = 44, // from Whites perspective
71 : NAG_SlightCentre = 48, // from Whites perspective
72 : NAG_Centre = 50, // new
73 : NAG_SlightKingSide = 54, // from Whites perspective
74 : NAG_ModerateKingSide = 56, // from Whites perspective
75 : NAG_KingSide = 58, // from Whites perspective
76 : NAG_SlightQueenSide = 60, // from Whites perspective
77 : NAG_ModerateQueenSide = 62, // from Whites perspective
78 : NAG_QueenSide = 64, // from Whites perspective
79 : NAG_SlightCounterPlay = 130, // new
80 : NAG_CounterPlay = 132, // new
81 : NAG_DecisiveCounterPlay = 134, // new
82 : NAG_BlackSlightCounterPlay = 131, // new
83 : NAG_BlackCounterPlay = 133, // new
84 : NAG_BlackDecisiveCounterPlay = 135, // new
85 : NAG_TimeLimit = 136, // new
86 : NAG_WithIdea = 140, // new
87 : NAG_BetterIs = 142, // new
88 : NAG_VariousMoves = 144, // new
89 : NAG_Comment = 145, // new
90 : NAG_Novelty = 146,
91 : NAG_WeakPoint = 147, // new
92 : NAG_Ending = 148, // new
93 : NAG_File = 149, // new
94 : NAG_Diagonal = 150, // new
95 : NAG_BishopPair = 151, // new
96 : NAG_OppositeBishops = 153, // new
97 : NAG_SameBishops = 154, // new
98 : NAG_Etc = 190, // new
99 : NAG_DoublePawns = 191, // new
100 : NAG_SeparatedPawns = 192, // new
101 : NAG_UnitedPawns = 193, // new
102 : NAG_Diagram = 201, // Scid-specific NAGs start at 201.
103 : NAG_See = 210, // new
104 : NAG_Mate = 211, // new
105 : NAG_PassedPawn = 212, // new
106 : NAG_MorePawns = 213, //new
107 : NAG_With = 214, // new
108 : NAG_Without = 215;
109 :
110 : // MAX_NAGS: Maximum id of NAG codes
111 : const byte MAX_NAGS_ARRAY = 215;
112 :
113 : // patternT structure: a pattern filter for material searches.
114 : // It can specify, for example, a white Pawn on the f-fyle, or
115 : // a black Bishop on f2 and white King on e1.
116 : struct patternT
117 : {
118 : pieceT pieceMatch; // EMPTY, WK, BK, etc...
119 : rankT rankMatch; // RANK_1 .. RANK_8 or NO_RANK
120 : fyleT fyleMatch; // A_FYLE .. H_FYLE or NO_FYLE
121 : byte flag; // 0 means this pattern must NOT occur.
122 : patternT * next;
123 : };
124 :
125 : #define GAME_DECODE_NONE 0
126 : #define GAME_DECODE_TAGS 1
127 : #define GAME_DECODE_COMMENTS 2
128 : #define GAME_DECODE_ALL 3
129 :
130 : enum gameExactMatchT {
131 : GAME_EXACT_MATCH_Exact = 0,
132 : GAME_EXACT_MATCH_Pawns,
133 : GAME_EXACT_MATCH_Fyles,
134 : GAME_EXACT_MATCH_Material
135 : };
136 :
137 : enum gameFormatT {
138 : PGN_FORMAT_Plain = 0, // Plain regular PGN output
139 : PGN_FORMAT_HTML = 1, // HTML format
140 : PGN_FORMAT_LaTeX = 2, // LaTeX (with chess12 package) format
141 : PGN_FORMAT_Color = 3 // PGN, with color tags <red> etc
142 : };
143 :
144 : #define PGN_STYLE_TAGS 1
145 : #define PGN_STYLE_COMMENTS 2
146 : #define PGN_STYLE_VARS 4
147 : #define PGN_STYLE_INDENT_COMMENTS 8
148 : #define PGN_STYLE_INDENT_VARS 16
149 : #define PGN_STYLE_SYMBOLS 32 // e.g. "! +-" instead of "$2 $14"
150 : #define PGN_STYLE_SHORT_HEADER 64
151 : #define PGN_STYLE_MOVENUM_SPACE 128 // Space after move numbers.
152 : #define PGN_STYLE_COLUMN 256 // Column style: one move per line.
153 : #define PGN_STYLE_SCIDFLAGS 512
154 : #define PGN_STYLE_STRIP_MARKS 1024 // Strip [%mark] and [%arrow] codes.
155 : #define PGN_STYLE_NO_NULL_MOVES 2048 // Convert null moves to comments.
156 : #define PGN_STYLE_UNICODE 4096 // Use U+2654..U+2659 for figurine
157 :
158 :
159 : void game_printNag (byte nag, char * str, bool asSymbol, gameFormatT format);
160 : byte game_parseNag(std::pair<const char*, const char*> strview);
161 :
162 : uint strGetRatingType (const char * name);
163 :
164 : //////////////////////////////////////////////////////////////////////
165 : // Game: Class Definition
166 :
167 2142 : class Game {
168 : // Header data: tag pairs
169 : std::vector<std::pair<std::string, std::string> > extraTags_;
170 : std::string WhiteStr;
171 : std::string BlackStr;
172 : std::string EventStr;
173 : std::string SiteStr;
174 : std::string RoundStr;
175 : dateT Date;
176 : dateT EventDate;
177 : ecoT EcoCode;
178 : eloT WhiteElo;
179 : eloT BlackElo;
180 : byte WhiteRatingType;
181 : byte BlackRatingType;
182 : resultT Result;
183 : char ScidFlags[22];
184 :
185 : // Position and moves
186 : byte moveChunkUsed_;
187 : std::forward_list<std::unique_ptr<moveT[]> > moveChunks_;
188 : std::unique_ptr<Position> StartPos;
189 2142 : std::unique_ptr<Position> CurrentPos{new Position};
190 : moveT* FirstMove;
191 : moveT* CurrentMove;
192 : uint VarDepth; // Current variation depth.
193 : ushort NumHalfMoves; // Total half moves in the main line.
194 :
195 : // TODO: The following variables should not be part of this class.
196 : bool PromotionsFlag; // Used by MaterialMatch
197 : bool KeepDecodedMoves; // Used by MaterialMatch end ExactMatch
198 :
199 : eloT WhiteEstimateElo;
200 : eloT BlackEstimateElo;
201 :
202 : uint NumMovesPrinted; // Used in recursive WriteMoveList method.
203 : uint PgnStyle; // see PGN_STYLE macros above.
204 : gameFormatT PgnFormat; // see PGN_FORMAT macros above.
205 : uint HtmlStyle; // HTML diagram style, see DumpHtmlBoard method in position.cpp.
206 :
207 : private:
208 : Game(const Game&);
209 : moveT* allocMove();
210 : moveT* NewMove(markerT marker);
211 : void ClearMoves();
212 : bool MakeHomePawnList(byte* pbPawnList);
213 : errorT DecodeVariation(ByteBuffer* buf, byte flags, uint level);
214 : errorT WritePGN(TextBuffer* tb);
215 :
216 : /**
217 : * Contains the information of the current position in the game, so that
218 : * after an operation that alters the location, it can be restored.
219 : */
220 : struct GameSavedPos {
221 : Position pos;
222 : moveT* move;
223 : uint varDepth;
224 : };
225 :
226 : public:
227 4278 : Game() { Clear(); }
228 : void Clear();
229 : void strip(bool variations, bool comments, bool NAGs);
230 :
231 177267 : bool HasNonStandardStart(char* outFEN = nullptr) const {
232 177267 : if (!StartPos)
233 177266 : return false;
234 1 : if (outFEN)
235 1 : StartPos->PrintFEN(outFEN, FEN_ALL_FIELDS);
236 1 : return true;
237 : }
238 :
239 : /// Setup the start position from a FEN string and remove all the moves.
240 : /// If the FEN is invalid the game is not changed.
241 : errorT SetStartFen(const char* fenStr);
242 :
243 0 : void SetScidFlags(const char* s, size_t len) {
244 0 : constexpr size_t size = sizeof(ScidFlags) / sizeof(*ScidFlags);
245 0 : std::fill_n(ScidFlags, size, 0);
246 0 : std::copy_n(s, std::min(size - 1, len), ScidFlags);
247 0 : }
248 : void SetScidFlags(const char* s) { SetScidFlags(s, std::strlen(s)); }
249 :
250 : ushort GetNumHalfMoves() { return NumHalfMoves; }
251 :
252 : //////////////////////////////////////////////////////////////
253 : // Functions to add or delete moves:
254 : //
255 : errorT AddMove(const simpleMoveT* sm);
256 : errorT AddVariation();
257 : errorT DeleteVariation();
258 : errorT FirstVariation();
259 : errorT MainVariation();
260 : void Truncate();
261 : void TruncateStart();
262 :
263 : //////////////////////////////////////////////////////////////
264 : // Functions that move the current location (only CurrentPos,
265 : // CurrentMove and VarDepth are modified by these functions):
266 : //
267 : errorT MoveForward();
268 : errorT MoveBackup();
269 : errorT MoveIntoVariation(uint varNumber);
270 : errorT MoveExitVariation();
271 : errorT MoveForwardInPGN();
272 : errorT MoveToLocationInPGN(unsigned stopLocation);
273 : void MoveToStart();
274 13645 : void MoveToPly(int hmNumber) { // Move to a specified
275 13645 : MoveToStart(); // mainline ply in the game.
276 13645 : for (int i = 0; i < hmNumber; ++i)
277 0 : MoveForward();
278 13645 : }
279 2037 : GameSavedPos currentLocation() const {
280 2037 : return GameSavedPos{*CurrentPos, CurrentMove, VarDepth};
281 : }
282 2037 : void restoreLocation(const GameSavedPos& savedPos) {
283 2037 : *CurrentPos = savedPos.pos;
284 2037 : CurrentMove = savedPos.move;
285 2037 : VarDepth = savedPos.varDepth;
286 2037 : }
287 :
288 : //////////////////////////////////////////////////////////////
289 : // Functions that get information about the current location.
290 : //
291 784181 : const Position* currentPos() const { return CurrentPos.get(); }
292 2345906 : Position* GetCurrentPos() { // Deprecated, use the const version
293 2345906 : return CurrentPos.get();
294 : }
295 : simpleMoveT* GetCurrentMove() { // Deprecated
296 : return CurrentMove->endMarker() ? nullptr : &CurrentMove->moveData;
297 : }
298 3162 : ushort GetCurrentPly() const {
299 3162 : auto ply = CurrentPos->GetPlyCounter();
300 3162 : return StartPos ? ply - StartPos->GetPlyCounter() : ply;
301 : }
302 : uint GetNumVariations() const { return CurrentMove->numVariations; }
303 :
304 : // Each variation has a "level" and a "number".
305 : // - "level" is the number of times that is necessary to call
306 : // MoveExitVariation() to reach the main line.
307 : // - "number" is the ordered position in the list of variations for the
308 : // current root position (first variation is number 0).
309 : // The main line is 0,0.
310 780189 : uint GetVarLevel() const { return VarDepth; }
311 40541 : uint GetVarNumber() const {
312 40541 : if (VarDepth != 0) {
313 40115 : uint varNumber = 0;
314 40115 : auto moves = CurrentMove->getParent();
315 47193 : for (auto parent = moves.first; parent; varNumber++) {
316 47193 : parent = parent->varChild;
317 47193 : if (parent == moves.second)
318 40115 : return varNumber;
319 : }
320 : }
321 426 : return 0; // returns 0 if in main line
322 : }
323 :
324 : unsigned GetLocationInPGN() const;
325 : unsigned GetPgnOffset() const;
326 :
327 2863 : bool AtVarStart() const { return CurrentMove->prev->startMarker(); }
328 9015 : bool AtVarEnd() const { return CurrentMove->endMarker(); }
329 158 : bool AtStart() const { return (VarDepth == 0 && AtVarStart()); }
330 9015 : bool AtEnd() const { return (VarDepth == 0 && AtVarEnd()); }
331 :
332 : //////////////////////////////////////////////////////////////
333 : // Functions that get/set information about the last/next move.
334 : // Notice: when location is at the start of the game or a variation,
335 : // infomation are stored into the START_MARKER.
336 : //
337 : errorT AddNag(byte nag);
338 : errorT RemoveNag(bool isMoveNag);
339 : void ClearNags() {
340 : CurrentMove->prev->nagCount = 0;
341 : CurrentMove->prev->nags[0] = 0;
342 : }
343 1124 : byte* GetNags() const { return CurrentMove->prev->nags; }
344 : byte* GetNextNags() const { return CurrentMove->nags; }
345 :
346 : /**
347 : * Return the comment on the move previously played by CurrentPos->ToMove
348 : * If there are no previous moves, return an empty comment.
349 : */
350 : const char* GetPreviousMoveComment() const {
351 : const moveT* move = CurrentMove->getPrevMove();
352 : if (move)
353 : move = move->getPrevMove();
354 :
355 : return (move) ? move->comment.c_str() : "";
356 : }
357 1147 : const char* GetMoveComment() const {
358 1147 : return CurrentMove->prev->comment.c_str();
359 : }
360 224036 : std::string& accessMoveComment() { return CurrentMove->prev->comment; }
361 : void SetMoveComment(const char* comment);
362 :
363 : const char* GetNextSAN();
364 : void GetSAN(char* str);
365 : void GetPrevSAN(char* str);
366 : void GetPrevMoveUCI(char* str) const;
367 : void GetNextMoveUCI(char* str);
368 :
369 : //////////////////////////////////////////////////////////////
370 : // Functions that get/set the tag pairs:
371 : //
372 : void AddPgnTag(const char* tag, const char* value);
373 : bool RemoveExtraTag(const char* tag);
374 : const char* FindExtraTag(const char* tag) const;
375 : std::string& accessTagValue(const char* tag, size_t tagLen);
376 10020 : const decltype(extraTags_) & GetExtraTags() const { return extraTags_; }
377 : void ClearExtraTags() { extraTags_.clear(); }
378 :
379 : errorT LoadStandardTags(const IndexEntry* ie, const NameBase* nb);
380 :
381 1001 : void SetEventStr (const char * str) { EventStr = str; }
382 1001 : void SetSiteStr (const char * str) { SiteStr = str; }
383 1001 : void SetWhiteStr (const char * str) { WhiteStr = str; }
384 1001 : void SetBlackStr (const char * str) { BlackStr = str; }
385 1001 : void SetRoundStr (const char * str) { RoundStr = str; }
386 3040 : void SetDate (dateT date) { Date = date; }
387 1037 : void SetEventDate (dateT date) { EventDate = date; }
388 3037 : void SetResult (resultT res) { Result = res; }
389 1037 : void SetWhiteElo (eloT elo) { WhiteElo = elo; }
390 1037 : void SetBlackElo (eloT elo) { BlackElo = elo; }
391 1037 : void SetWhiteRatingType (byte b) { WhiteRatingType = b; }
392 1036 : void SetBlackRatingType (byte b) { BlackRatingType = b; }
393 : int setRating(colorT col, const char* ratingType, size_t ratingTypeLen,
394 : std::pair<const char*, const char*> rating);
395 1037 : void SetEco (ecoT eco) { EcoCode = eco; }
396 11055 : const char* GetEventStr () const { return EventStr.c_str(); }
397 11054 : const char* GetSiteStr () const { return SiteStr.c_str(); }
398 11054 : const char* GetWhiteStr () const { return WhiteStr.c_str(); }
399 11054 : const char* GetBlackStr () const { return BlackStr.c_str(); }
400 11054 : const char* GetRoundStr () const { return RoundStr.c_str(); }
401 30 : dateT GetDate () const { return Date; }
402 3 : dateT GetEventDate () const { return EventDate; }
403 2036 : resultT GetResult () const { return Result; }
404 234 : eloT GetWhiteElo () const { return WhiteElo; }
405 234 : eloT GetBlackElo () const { return BlackElo; }
406 : eloT GetWhiteEstimateElo() const { return WhiteEstimateElo; }
407 : eloT GetBlackEstimateElo() const { return BlackEstimateElo; }
408 1 : byte GetWhiteRatingType () const { return WhiteRatingType; }
409 1 : byte GetBlackRatingType () const { return BlackRatingType; }
410 3 : ecoT GetEco () const { return EcoCode; }
411 : eloT GetAverageElo ();
412 :
413 : // PGN conversion
414 : bool CommentEmpty ( const char * comment);
415 : void WriteComment (TextBuffer * tb, const char * preStr,
416 : const char * comment, const char * postStr);
417 : errorT WriteMoveList(TextBuffer* tb, moveT* oldCurrentMove,
418 : bool printMoveNum, bool inComment);
419 : std::pair<const char*, unsigned> WriteToPGN (uint lineWidth = 0,
420 : bool NewLineAtEnd = false,
421 : bool newLineToSpaces = true);
422 :
423 : void ResetPgnStyle (void) { PgnStyle = 0; }
424 2037 : void ResetPgnStyle (uint flag) { PgnStyle = flag; }
425 :
426 : uint GetPgnStyle () { return PgnStyle; }
427 : void SetPgnStyle (uint mask, bool setting) {
428 : if (setting) { AddPgnStyle (mask); } else { RemovePgnStyle (mask); }
429 : }
430 : void AddPgnStyle (uint mask) { PgnStyle |= mask; }
431 : void RemovePgnStyle (uint mask) { PgnStyle &= ~mask; }
432 :
433 2037 : void SetPgnFormat (gameFormatT gf) { PgnFormat = gf; }
434 : bool SetPgnFormatFromString (const char * str);
435 : static bool PgnFormatFromString (const char * str, gameFormatT * fmt);
436 533984 : bool IsPlainFormat () { return (PgnFormat == PGN_FORMAT_Plain); }
437 2007661 : bool IsHtmlFormat () { return (PgnFormat == PGN_FORMAT_HTML); }
438 1554613 : bool IsLatexFormat () { return (PgnFormat == PGN_FORMAT_LaTeX); }
439 10034947 : bool IsColorFormat () { return (PgnFormat == PGN_FORMAT_Color); }
440 :
441 : void SetHtmlStyle (uint style) { HtmlStyle = style; }
442 : uint GetHtmlStyle () { return HtmlStyle; }
443 :
444 : errorT GetPartialMoveList (DString * str, uint plyCount);
445 :
446 : bool MaterialMatch (ByteBuffer * buf, byte * min, byte * max,
447 : patternT * pattern, int minPly, int maxPly,
448 : int matchLength,
449 : bool oppBishops, bool sameBishops,
450 : int minDiff, int maxDiff);
451 : bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm,
452 : gameExactMatchT searchType, bool * neverMatch);
453 : bool VarExactMatch (Position * searchPos, gameExactMatchT searchType);
454 : inline bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm)
455 : { return ExactMatch (pos, buf, sm, GAME_EXACT_MATCH_Exact, NULL); }
456 : inline bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm,
457 : bool * neverMatch)
458 : { return ExactMatch (pos, buf, sm, GAME_EXACT_MATCH_Exact, neverMatch); }
459 : inline bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm,
460 : gameExactMatchT searchType)
461 : { return ExactMatch (pos, buf, sm, searchType, NULL); }
462 :
463 : errorT Encode (ByteBuffer * buf, IndexEntry * ie);
464 : errorT DecodeStart(ByteBuffer* buf, bool decodeTags = false);
465 : errorT DecodeNextMove (ByteBuffer * buf, simpleMoveT * sm);
466 : errorT Decode (ByteBuffer * buf, byte flags);
467 : errorT DecodeTags (ByteBuffer * buf, bool storeTags);
468 :
469 : Game* clone();
470 : };
471 :
472 : namespace gamevisit {
473 :
474 2 : template <typename TFunc> void tags_STR(const Game& game, TFunc visitor) {
475 : char dateBuf[16];
476 2 : visitor("Event", game.GetEventStr());
477 2 : visitor("Site", game.GetSiteStr());
478 2 : date_DecodeToString(game.GetDate(), dateBuf);
479 2 : visitor("Date", dateBuf);
480 2 : visitor("Round", game.GetRoundStr());
481 2 : visitor("White", game.GetWhiteStr());
482 2 : visitor("Black", game.GetBlackStr());
483 2 : visitor("Result", RESULT_LONGSTR[game.GetResult()]);
484 2 : }
485 :
486 2 : template <typename TFunc> void tags_extra(const Game& game, TFunc visitor) {
487 : char strBuf[256];
488 2 : if (auto elo = game.GetWhiteElo()) {
489 2 : std::string rType = "White";
490 1 : rType.append(ratingTypeNames[game.GetWhiteRatingType()]);
491 1 : visitor(rType.c_str(), std::to_string(elo).c_str());
492 : }
493 2 : if (auto elo = game.GetBlackElo()) {
494 2 : std::string rType = "Black";
495 1 : rType.append(ratingTypeNames[game.GetBlackRatingType()]);
496 1 : visitor(rType.c_str(), std::to_string(elo).c_str());
497 : }
498 2 : if (game.GetEco() != ECO_None) {
499 1 : eco_ToExtendedString(game.GetEco(), strBuf);
500 1 : visitor("ECO", strBuf);
501 : }
502 2 : if (game.GetEventDate() != ZERO_DATE) {
503 1 : date_DecodeToString(game.GetEventDate(), strBuf);
504 1 : visitor("EventDate", strBuf);
505 : }
506 : // TODO:
507 : // if (*ScidFlags)
508 : // visitor("ScidFlags", ScidFlags);
509 :
510 5 : for (auto& e : game.GetExtraTags()) {
511 3 : visitor(e.first.c_str(), e.second.c_str());
512 : }
513 2 : if (game.HasNonStandardStart(strBuf)) {
514 1 : visitor("FEN", strBuf);
515 : }
516 2 : }
517 :
518 : } // namespace gamevisit
519 :
520 : namespace gamepos {
521 :
522 6436 : struct GamePos {
523 : uint32_t RAVdepth;
524 : uint32_t RAVnum;
525 : std::string FEN; // "Forsyth-Edwards Notation" describing the position.
526 : std::vector<int> NAGs; // "Numeric Annotation Glyph"
527 : std::string comment; // text annotation of the position.
528 : std::string lastMoveSAN; // move that was played to reach the position.
529 : };
530 :
531 : /**
532 : * Iterate all the positions of a game and store the corresponding GamePos
533 : * objects into a container.
534 : *
535 : * The order of positions and of Recursive Annotation Variations (RAV) follows
536 : * the PGN standard: "The alternate move sequence given by an RAV is one that
537 : * may be legally played by first unplaying the move that appears immediately
538 : * prior to the RAV. Because the RAV is a recursive construct, it may be nested"
539 : * Each position have a RAVdepth and a RAVnum that allows to follow a
540 : * variation from any given position:
541 : * - skip all the next positions with a bigger RAVdepth
542 : * - the variation ends with:
543 : * - a lower RAVdepth or
544 : * - an equal RAVdepth but different RAVnum or
545 : * - the end of @e dest
546 : * @param game: reference to the Game object where the positions are read.
547 : * @param dest: the container where the GamePos objects are appended.
548 : */
549 : template <typename TCont>
550 1270 : inline void collectPositions(Game& game, TCont& dest) {
551 1258 : do {
552 1270 : if (game.AtVarStart() && !game.AtStart())
553 146 : continue;
554 :
555 1124 : dest.emplace_back();
556 1124 : auto& gamepos = dest.back();
557 1124 : gamepos.RAVdepth = game.GetVarLevel();
558 1124 : gamepos.RAVnum = game.GetVarNumber();
559 : char strBuf[256];
560 1124 : game.currentPos()->PrintFEN(strBuf, FEN_ALL_FIELDS);
561 1124 : gamepos.FEN = strBuf;
562 1348 : for (byte* nag = game.GetNags(); *nag; nag++) {
563 224 : gamepos.NAGs.push_back(*nag);
564 : }
565 1124 : gamepos.comment = game.GetMoveComment();
566 1124 : game.GetPrevSAN(strBuf);
567 1124 : gamepos.lastMoveSAN = strBuf;
568 :
569 1270 : } while (game.MoveForwardInPGN() == OK);
570 12 : }
571 :
572 : /**
573 : * Returns all the positions of a game
574 : * @param game: reference to the Game object where the positions are read.
575 : * @returns a std::vector containing the GamePos objects corresponding to all
576 : * the positions of @e game.
577 : */
578 12 : inline std::vector<GamePos> collectPositions(Game& game) {
579 12 : std::vector<GamePos> res;
580 12 : game.MoveToStart();
581 12 : collectPositions(game, res);
582 12 : return res;
583 : }
584 :
585 : } // namespace gamepos
586 :
587 : #endif // #ifndef SCID_GAME_H
588 :
589 : //////////////////////////////////////////////////////////////////////
590 : // EOF: game.h
591 : //////////////////////////////////////////////////////////////////////
|