1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
//-----------------------------------------------------------------------------
/** @file libboardgame_base/SgfTree.h
@author Markus Enzenberger
@copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------
#ifndef LIBBOARDGAME_BASE_SGF_TREE_H
#define LIBBOARDGAME_BASE_SGF_TREE_H
#include "SgfNode.h"
namespace libboardgame_base {
//-----------------------------------------------------------------------------
/** SGF tree.
Tree structure of the tree can only be manipulated through member functions
to guarantee a consistent tree structure. Therefore the user is given
only const references to nodes and non-const functions of nodes can only
be called through wrapper functions of the tree (in which case the user
passes in a const reference to the node as an identifier for the node). */
class SgfTree
{
public:
SgfTree();
virtual ~SgfTree() = default;
virtual void init();
/** Initialize from an existing SGF tree.
@param root The root node of the SGF tree; the ownership is transferred
to this class. */
virtual void init(unique_ptr<SgfNode>& root);
/** Check if the tree was modified since the construction or the last call
to init() or clear_modified() */
bool is_modified() const { return m_modified; }
void set_modified(bool is_modified = true) { m_modified = is_modified; }
void clear_modified() { m_modified = false; }
const SgfNode& get_root() const { return *m_root; }
const SgfNode& create_new_child(const SgfNode& node);
/** Truncate a node and its subtree from the tree.
Calling this function deletes the node that is to be truncated and its
complete subtree.
@pre node.has_parent()
@param node The node to be truncated.
@return The parent of the truncated node. */
const SgfNode& truncate(const SgfNode& node);
/** Delete all children but the first. */
void delete_variations(const SgfNode& node);
/** Delete all variations but the main variation. */
void delete_all_variations();
/** Make a node the first child of its parent. */
void make_first_child(const SgfNode& node);
/** Make a node switch place with its previous sibling (if it is not
already the first child). */
void move_up(const SgfNode& node);
/** Make a node switch place with its next sibling (if it is not
already the last child). */
void move_down(const SgfNode& node);
/** Make a node the root node of the tree.
All nodes that are not the given node or in the subtree below it are
deleted. Note that this operation in general creates a semantically
invalid tree (e.g. missing GM or CA property in the new root). You need
to add those after this function. In general, you will also have to
examine the nodes in the path to the node in the original tree and then
make the tree valid again after calling make_root(). Typically, you
will have to look at the moves played before this node and convert them
into setup properties to add to the new root such that the board
position at this node is the same as originally. */
void make_root(const SgfNode& node);
void make_main_variation(const SgfNode& node);
bool contains(const SgfNode& node) const;
template<typename T>
void set_property(const SgfNode& node, const string& id, const T& value);
void set_property(const SgfNode& node, const string& id, const char* value);
template<typename T>
void set_property(const SgfNode& node, const string& id,
const vector<T>& values);
void set_property_remove_empty(const SgfNode& node,
const string& id, const string& value);
bool remove_property(const SgfNode& node, const string& id);
void move_property_to_front(const SgfNode& node, const string& id);
/** See Node::remove_children() */
void remove_children(const SgfNode& node);
/** Get comment.
@return The comment, or an empty string if the node contains no
comment. */
static string get_comment(const SgfNode& node);
void set_comment(const SgfNode& node, const string& s);
void remove_move_annotation(const SgfNode& node);
static double get_good_move(const SgfNode& node);
void set_good_move(const SgfNode& node, double value = 1);
static double get_bad_move(const SgfNode& node);
void set_bad_move(const SgfNode& node, double value = 1);
static bool is_doubtful_move(const SgfNode& node);
void set_doubtful_move(const SgfNode& node);
static bool is_interesting_move(const SgfNode& node);
void set_interesting_move(const SgfNode& node);
void set_charset(const string& charset);
void set_application(const string& name, const string& version = {});
string get_date() const { return m_root->get_property("DT", ""); }
void set_date(const string& date);
/** Get today's date in format YYYY-MM-DD as required by DT property. */
static string get_date_today();
void set_date_today();
string get_event() const { return m_root->get_property("EV", ""); }
void set_event(const string& event);
string get_round() const { return m_root->get_property("RO", ""); }
void set_round(const string& round);
string get_time() const { return m_root->get_property("TM", ""); }
void set_time(const string& time);
bool has_variations() const;
private:
bool m_modified;
unique_ptr<SgfNode> m_root;
SgfNode& non_const(const SgfNode& node);
};
inline SgfNode& SgfTree::non_const(const SgfNode& node)
{
LIBBOARDGAME_ASSERT(contains(node));
return const_cast<SgfNode&>(node);
}
inline void SgfTree::remove_children(const SgfNode& node)
{
if (node.has_children())
m_modified = true;
non_const(node).remove_children();
}
inline void SgfTree::set_charset(const string& charset)
{
set_property_remove_empty(get_root(), "CA", charset);
}
inline void SgfTree::set_date(const string& date)
{
set_property_remove_empty(get_root(), "DT", date);
}
inline void SgfTree::set_event(const string& event)
{
set_property_remove_empty(get_root(), "EV", event);
}
template<typename T>
void SgfTree::set_property(const SgfNode& node, const string& id, const T& value)
{
bool was_changed = non_const(node).set_property(id, value);
if (was_changed)
m_modified = true;
}
template<typename T>
void SgfTree::set_property(const SgfNode& node, const string& id,
const vector<T>& values)
{
bool was_changed = non_const(node).set_property(id, values);
if (was_changed)
m_modified = true;
}
inline void SgfTree::set_round(const string& round)
{
set_property_remove_empty(get_root(), "RO", round);
}
inline void SgfTree::set_time(const string& time)
{
set_property_remove_empty(get_root(), "TM", time);
}
//-----------------------------------------------------------------------------
} // namespace libboardgame_base
#endif // LIBBOARDGAME_BASE_SGF_TREE_H
|