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 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 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:
Game()227 Game() { Clear(); }
228 void Clear();
229 void strip(bool variations, bool comments, bool NAGs);
230
231 bool HasNonStandardStart(char* outFEN = nullptr) const {
232 if (!StartPos)
233 return false;
234 if (outFEN)
235 StartPos->PrintFEN(outFEN, FEN_ALL_FIELDS);
236 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
SetScidFlags(const char * s,size_t len)243 void SetScidFlags(const char* s, size_t len) {
244 constexpr size_t size = sizeof(ScidFlags) / sizeof(*ScidFlags);
245 std::fill_n(ScidFlags, size, 0);
246 std::copy_n(s, std::min(size - 1, len), ScidFlags);
247 }
SetScidFlags(const char * s)248 void SetScidFlags(const char* s) { SetScidFlags(s, std::strlen(s)); }
249
GetNumHalfMoves()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();
MoveToPly(int hmNumber)274 void MoveToPly(int hmNumber) { // Move to a specified
275 MoveToStart(); // mainline ply in the game.
276 for (int i = 0; i < hmNumber; ++i)
277 MoveForward();
278 }
currentLocation()279 GameSavedPos currentLocation() const {
280 return GameSavedPos{*CurrentPos, CurrentMove, VarDepth};
281 }
restoreLocation(const GameSavedPos & savedPos)282 void restoreLocation(const GameSavedPos& savedPos) {
283 *CurrentPos = savedPos.pos;
284 CurrentMove = savedPos.move;
285 VarDepth = savedPos.varDepth;
286 }
287
288 //////////////////////////////////////////////////////////////
289 // Functions that get information about the current location.
290 //
currentPos()291 const Position* currentPos() const { return CurrentPos.get(); }
GetCurrentPos()292 Position* GetCurrentPos() { // Deprecated, use the const version
293 return CurrentPos.get();
294 }
GetCurrentMove()295 simpleMoveT* GetCurrentMove() { // Deprecated
296 return CurrentMove->endMarker() ? nullptr : &CurrentMove->moveData;
297 }
GetCurrentPly()298 ushort GetCurrentPly() const {
299 auto ply = CurrentPos->GetPlyCounter();
300 return StartPos ? ply - StartPos->GetPlyCounter() : ply;
301 }
GetNumVariations()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.
GetVarLevel()310 uint GetVarLevel() const { return VarDepth; }
GetVarNumber()311 uint GetVarNumber() const {
312 if (VarDepth != 0) {
313 uint varNumber = 0;
314 auto moves = CurrentMove->getParent();
315 for (auto parent = moves.first; parent; varNumber++) {
316 parent = parent->varChild;
317 if (parent == moves.second)
318 return varNumber;
319 }
320 }
321 return 0; // returns 0 if in main line
322 }
323
324 unsigned GetLocationInPGN() const;
325 unsigned GetPgnOffset() const;
326
AtVarStart()327 bool AtVarStart() const { return CurrentMove->prev->startMarker(); }
AtVarEnd()328 bool AtVarEnd() const { return CurrentMove->endMarker(); }
AtStart()329 bool AtStart() const { return (VarDepth == 0 && AtVarStart()); }
AtEnd()330 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);
ClearNags()339 void ClearNags() {
340 CurrentMove->prev->nagCount = 0;
341 CurrentMove->prev->nags[0] = 0;
342 }
GetNags()343 byte* GetNags() const { return CurrentMove->prev->nags; }
GetNextNags()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 */
GetPreviousMoveComment()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 }
GetMoveComment()357 const char* GetMoveComment() const {
358 return CurrentMove->prev->comment.c_str();
359 }
accessMoveComment()360 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);
decltype(extraTags_)376 const decltype(extraTags_) & GetExtraTags() const { return extraTags_; }
ClearExtraTags()377 void ClearExtraTags() { extraTags_.clear(); }
378
379 errorT LoadStandardTags(const IndexEntry* ie, const NameBase* nb);
380
SetEventStr(const char * str)381 void SetEventStr (const char * str) { EventStr = str; }
SetSiteStr(const char * str)382 void SetSiteStr (const char * str) { SiteStr = str; }
SetWhiteStr(const char * str)383 void SetWhiteStr (const char * str) { WhiteStr = str; }
SetBlackStr(const char * str)384 void SetBlackStr (const char * str) { BlackStr = str; }
SetRoundStr(const char * str)385 void SetRoundStr (const char * str) { RoundStr = str; }
SetDate(dateT date)386 void SetDate (dateT date) { Date = date; }
SetEventDate(dateT date)387 void SetEventDate (dateT date) { EventDate = date; }
SetResult(resultT res)388 void SetResult (resultT res) { Result = res; }
SetWhiteElo(eloT elo)389 void SetWhiteElo (eloT elo) { WhiteElo = elo; }
SetBlackElo(eloT elo)390 void SetBlackElo (eloT elo) { BlackElo = elo; }
SetWhiteRatingType(byte b)391 void SetWhiteRatingType (byte b) { WhiteRatingType = b; }
SetBlackRatingType(byte b)392 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);
SetEco(ecoT eco)395 void SetEco (ecoT eco) { EcoCode = eco; }
GetEventStr()396 const char* GetEventStr () const { return EventStr.c_str(); }
GetSiteStr()397 const char* GetSiteStr () const { return SiteStr.c_str(); }
GetWhiteStr()398 const char* GetWhiteStr () const { return WhiteStr.c_str(); }
GetBlackStr()399 const char* GetBlackStr () const { return BlackStr.c_str(); }
GetRoundStr()400 const char* GetRoundStr () const { return RoundStr.c_str(); }
GetDate()401 dateT GetDate () const { return Date; }
GetEventDate()402 dateT GetEventDate () const { return EventDate; }
GetResult()403 resultT GetResult () const { return Result; }
GetWhiteElo()404 eloT GetWhiteElo () const { return WhiteElo; }
GetBlackElo()405 eloT GetBlackElo () const { return BlackElo; }
GetWhiteEstimateElo()406 eloT GetWhiteEstimateElo() const { return WhiteEstimateElo; }
GetBlackEstimateElo()407 eloT GetBlackEstimateElo() const { return BlackEstimateElo; }
GetWhiteRatingType()408 byte GetWhiteRatingType () const { return WhiteRatingType; }
GetBlackRatingType()409 byte GetBlackRatingType () const { return BlackRatingType; }
GetEco()410 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
ResetPgnStyle(void)423 void ResetPgnStyle (void) { PgnStyle = 0; }
ResetPgnStyle(uint flag)424 void ResetPgnStyle (uint flag) { PgnStyle = flag; }
425
GetPgnStyle()426 uint GetPgnStyle () { return PgnStyle; }
SetPgnStyle(uint mask,bool setting)427 void SetPgnStyle (uint mask, bool setting) {
428 if (setting) { AddPgnStyle (mask); } else { RemovePgnStyle (mask); }
429 }
AddPgnStyle(uint mask)430 void AddPgnStyle (uint mask) { PgnStyle |= mask; }
RemovePgnStyle(uint mask)431 void RemovePgnStyle (uint mask) { PgnStyle &= ~mask; }
432
SetPgnFormat(gameFormatT gf)433 void SetPgnFormat (gameFormatT gf) { PgnFormat = gf; }
434 bool SetPgnFormatFromString (const char * str);
435 static bool PgnFormatFromString (const char * str, gameFormatT * fmt);
IsPlainFormat()436 bool IsPlainFormat () { return (PgnFormat == PGN_FORMAT_Plain); }
IsHtmlFormat()437 bool IsHtmlFormat () { return (PgnFormat == PGN_FORMAT_HTML); }
IsLatexFormat()438 bool IsLatexFormat () { return (PgnFormat == PGN_FORMAT_LaTeX); }
IsColorFormat()439 bool IsColorFormat () { return (PgnFormat == PGN_FORMAT_Color); }
440
SetHtmlStyle(uint style)441 void SetHtmlStyle (uint style) { HtmlStyle = style; }
GetHtmlStyle()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);
ExactMatch(Position * pos,ByteBuffer * buf,simpleMoveT * sm)454 inline bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm)
455 { return ExactMatch (pos, buf, sm, GAME_EXACT_MATCH_Exact, NULL); }
ExactMatch(Position * pos,ByteBuffer * buf,simpleMoveT * sm,bool * neverMatch)456 inline bool ExactMatch (Position * pos, ByteBuffer * buf, simpleMoveT * sm,
457 bool * neverMatch)
458 { return ExactMatch (pos, buf, sm, GAME_EXACT_MATCH_Exact, neverMatch); }
ExactMatch(Position * pos,ByteBuffer * buf,simpleMoveT * sm,gameExactMatchT searchType)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
tags_STR(const Game & game,TFunc visitor)474 template <typename TFunc> void tags_STR(const Game& game, TFunc visitor) {
475 char dateBuf[16];
476 visitor("Event", game.GetEventStr());
477 visitor("Site", game.GetSiteStr());
478 date_DecodeToString(game.GetDate(), dateBuf);
479 visitor("Date", dateBuf);
480 visitor("Round", game.GetRoundStr());
481 visitor("White", game.GetWhiteStr());
482 visitor("Black", game.GetBlackStr());
483 visitor("Result", RESULT_LONGSTR[game.GetResult()]);
484 }
485
tags_extra(const Game & game,TFunc visitor)486 template <typename TFunc> void tags_extra(const Game& game, TFunc visitor) {
487 char strBuf[256];
488 if (auto elo = game.GetWhiteElo()) {
489 std::string rType = "White";
490 rType.append(ratingTypeNames[game.GetWhiteRatingType()]);
491 visitor(rType.c_str(), std::to_string(elo).c_str());
492 }
493 if (auto elo = game.GetBlackElo()) {
494 std::string rType = "Black";
495 rType.append(ratingTypeNames[game.GetBlackRatingType()]);
496 visitor(rType.c_str(), std::to_string(elo).c_str());
497 }
498 if (game.GetEco() != ECO_None) {
499 eco_ToExtendedString(game.GetEco(), strBuf);
500 visitor("ECO", strBuf);
501 }
502 if (game.GetEventDate() != ZERO_DATE) {
503 date_DecodeToString(game.GetEventDate(), strBuf);
504 visitor("EventDate", strBuf);
505 }
506 // TODO:
507 // if (*ScidFlags)
508 // visitor("ScidFlags", ScidFlags);
509
510 for (auto& e : game.GetExtraTags()) {
511 visitor(e.first.c_str(), e.second.c_str());
512 }
513 if (game.HasNonStandardStart(strBuf)) {
514 visitor("FEN", strBuf);
515 }
516 }
517
518 } // namespace gamevisit
519
520 namespace gamepos {
521
522 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>
collectPositions(Game & game,TCont & dest)550 inline void collectPositions(Game& game, TCont& dest) {
551 do {
552 if (game.AtVarStart() && !game.AtStart())
553 continue;
554
555 dest.emplace_back();
556 auto& gamepos = dest.back();
557 gamepos.RAVdepth = game.GetVarLevel();
558 gamepos.RAVnum = game.GetVarNumber();
559 char strBuf[256];
560 game.currentPos()->PrintFEN(strBuf, FEN_ALL_FIELDS);
561 gamepos.FEN = strBuf;
562 for (byte* nag = game.GetNags(); *nag; nag++) {
563 gamepos.NAGs.push_back(*nag);
564 }
565 gamepos.comment = game.GetMoveComment();
566 game.GetPrevSAN(strBuf);
567 gamepos.lastMoveSAN = strBuf;
568
569 } while (game.MoveForwardInPGN() == OK);
570 }
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 */
collectPositions(Game & game)578 inline std::vector<GamePos> collectPositions(Game& game) {
579 std::vector<GamePos> res;
580 game.MoveToStart();
581 collectPositions(game, res);
582 return res;
583 }
584
585 } // namespace gamepos
586
587 #endif // #ifndef SCID_GAME_H
588
589 //////////////////////////////////////////////////////////////////////
590 // EOF: game.h
591 //////////////////////////////////////////////////////////////////////
592