Scid  4.7.0
movetree.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Fulvio Benini
3 
4  * This file is part of Scid (Shane's Chess Information Database).
5  *
6  * Scid is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation.
9  *
10  * Scid is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Scid. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 /** @file
21  * A tree graph of moves representing a game.
22  */
23 
24 #ifndef SCID_MOVETREE_H
25 #define SCID_MOVETREE_H
26 
27 #include "common.h"
28 #include "movelist.h"
29 #include <string>
30 
31 enum markerT : byte { NO_MARKER = 0, START_MARKER = 1, END_MARKER = 2 };
32 
33 // MAX_NAGS is the maximum number of NAGs (annotation symbols) a single
34 // move can have:
35 #define MAX_NAGS 8
36 
37 // This class creates a tree graph of moves representing a game.
38 //
39 // For each node there are two edges: *next* (to the next move) and *varChild*
40 // (to an alternative line). For example the graph for the move sequence
41 // "1.d4 (1.e4 e5 ( 1...c5)) (1.c4) 1...d5 2.c4" is:
42 // clang-format off
43 // (START_MARKER, pgn_1) --next-> (d4, pgn_2) --next-> (d5, pgn_10) --next-> (c4, pgn_11) --next-> (END_MARKER, none)
44 // |
45 // |-child-> (START_MARKER, pgn_3) --next-> (e4, pgn_4) --next-> (e5, pgn_5) --next-> (END_MARKER, none)
46 // | |
47 // | |-child-> (START_MARKER, pgn_6) --next-> (c5, pgn_7) --next-> (END_MARKER, none)
48 // |
49 // |-child-> (START_MARKER, pgn_8) --next-> (c4, pgn_9) --next-> (END_MARKER, none)
50 // clang-format on
51 // The graph illustrates also that:
52 // - each variation starts and ends with two nodes containing a START_MARKER
53 // and a END_MARKER instead of a move. This implies that *next* never points
54 // to a START_MARKER node and *varChild* always point to a START_MARKER.
55 // - multiple variations are stored as a list of children. In the example there
56 // are two alternatives to "1.d4": "1.e4" is stored as direct child of "1.d4",
57 // instead "1.c4" is stored as the child of the START_MARKER of "1.e4".
58 // - when represented as a PGN string, the moves creates a sequence that can be
59 // counted (each new variation is counted as an additional move). This is used
60 // to specify a location in the game.
61 //
62 struct moveT {
63  simpleMoveT moveData; // piece moving, target square etc
67  char san[10]; // SAN representation of move
68  markerT marker; // can be NO_MARKER, START_MARKER or END_MARKER
72  std::string comment;
73 
74  void clear() {
75  moveData.clear();
76  prev = nullptr;
77  next = nullptr;
78  varChild = nullptr;
79  std::fill_n(san, sizeof(san), '\0');
80  marker = NO_MARKER;
81  numVariations = 0;
82  nagCount = 0;
83  std::fill_n(nags, sizeof(nags), 0);
84  comment.clear();
85  }
86 
87  bool startMarker() const { return marker == START_MARKER; }
88  bool endMarker() const { return marker == END_MARKER; }
89  bool isNull() const { return moveData.isNullMove(); }
90 
91  template <typename TNew>
92  moveT* cloneLine(moveT* parent, TNew newMove) const {
93  const moveT* orig = this;
94  moveT* top = newMove();
95  *top = *orig;
96  top->prev = parent;
97  parent = top;
98  if (orig->varChild) {
99  auto root = parent->startMarker() ? parent->prev : parent;
100  parent->varChild = orig->varChild->cloneLine(root, newMove);
101  }
102 
103  while (orig->next) {
104  orig = orig->next;
105  auto copy = newMove();
106  *copy = *orig;
107  parent->setNext(copy);
108  parent = copy;
109  if (orig->varChild) {
110  auto root = parent->startMarker() ? parent->prev : parent;
111  parent->varChild = orig->varChild->cloneLine(root, newMove);
112  }
113  }
114  return top;
115  }
116 
117  void swapLine(moveT& move) {
118  ASSERT(prev && move.prev);
119  ASSERT(!startMarker() && !move.startMarker());
120  ASSERT(!endMarker() && !move.endMarker());
121  // Swap lines
122  auto swap_tmp = move.prev;
123  prev->setNext(&move);
124  swap_tmp->setNext(this);
125  // Swap children
126  std::swap(varChild, move.varChild);
127  std::swap(numVariations, move.numVariations);
128  auto updateParentLink = [](moveT& parent) {
129  for (auto tmp = parent.varChild; tmp; tmp = tmp->varChild) {
130  tmp->prev = &parent;
131  }
132  };
133  updateParentLink(*this);
134  updateParentLink(move);
135  }
136 
137  const moveT* getPrevMove() const {
138  if (!startMarker() && !prev->startMarker())
139  return prev;
140 
141  auto root = getParent().first;
142  return root ? root->getPrevMove() : nullptr;
143  }
144 
145  std::pair<const moveT*, const moveT*> getParent() const {
146  const moveT* varStart = this;
147  while (!varStart->startMarker()) {
148  varStart = varStart->prev;
149  }
150  return {varStart->prev, varStart};
151  }
152 
153  std::pair<moveT*, moveT*> getParent() {
154  moveT* varStart = this;
155  while (!varStart->startMarker()) {
156  varStart = varStart->prev;
157  }
158  return {varStart->prev, varStart};
159  }
160 
161  const moveT* nextMoveInPGN() const {
162  if (endMarker()) {
163  auto parent = getParent();
164  auto nextVar = parent.second->varChild;
165  return (nextVar) ? nextVar
166  : (parent.first) ? parent.first->next : nullptr;
167  }
168  return (startMarker() || !varChild) ? next : varChild;
169  }
170 
171  void setNext(moveT* move) {
172  ASSERT(move);
173  this->next = move;
174  move->prev = this;
175  }
176 
177  void insertChild(moveT* varStart, int pos) {
178  ASSERT(!this->startMarker() && !this->endMarker());
179  ASSERT(this != varStart);
180  ASSERT(varStart->startMarker());
181  auto parent = this;
182  for (; parent->varChild && pos != 0; --pos) {
183  parent = parent->varChild;
184  }
185  varStart->varChild = varStart;
186  std::swap(parent->varChild, varStart->varChild);
187 
188  varStart->prev = this;
189  ++numVariations;
190  }
191 
192  void appendChild(moveT* varStart) { insertChild(varStart, -1); }
193 
194  void detachChild(moveT* varStart) {
195  ASSERT(this != varStart);
196  ASSERT(varStart->startMarker());
197  auto parent = this;
198  while (parent->varChild != varStart) {
199  parent = parent->varChild;
200  }
201  std::swap(parent->varChild, varStart->varChild);
202  --numVariations;
203  };
204 };
205 
206 #endif // SCID_MOVETREE_H
unsigned char byte
Definition: common.h:89
simpleMoveT moveData
Definition: movetree.h:63
markerT
Definition: movetree.h:31
#define ASSERT(f)
Definition: common.h:59
const moveT * getPrevMove() const
Definition: movetree.h:137
moveT * prev
Definition: movetree.h:64
Definition: movetree.h:62
void swapLine(moveT &move)
Definition: movetree.h:117
void insertChild(moveT *varStart, int pos)
Definition: movetree.h:177
void detachChild(moveT *varStart)
Definition: movetree.h:194
markerT marker
Definition: movetree.h:68
std::string comment
Definition: movetree.h:72
bool isNull() const
Definition: movetree.h:89
std::pair< moveT *, moveT * > getParent()
Definition: movetree.h:153
void appendChild(moveT *varStart)
Definition: movetree.h:192
bool isNullMove() const
Definition: movelist.h:52
Definition: move.tcl:20
byte numVariations
Definition: movetree.h:69
#define MAX_NAGS
Definition: movetree.h:35
byte nags[MAX_NAGS]
Definition: movetree.h:71
void clear()
Definition: movetree.h:74
bool startMarker() const
Definition: movetree.h:87
void setNext(moveT *move)
Definition: movetree.h:171
char san[10]
Definition: movetree.h:67
moveT * varChild
Definition: movetree.h:66
moveT * next
Definition: movetree.h:65
byte nagCount
Definition: movetree.h:70
moveT * cloneLine(moveT *parent, TNew newMove) const
Definition: movetree.h:92
bool endMarker() const
Definition: movetree.h:88
std::pair< const moveT *, const moveT * > getParent() const
Definition: movetree.h:145
const moveT * nextMoveInPGN() const
Definition: movetree.h:161
void clear()
Definition: movelist.h:74