-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathBook.cpp
121 lines (108 loc) · 3.74 KB
/
Book.cpp
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
//-----------------------------------------------------------------------------
/** @file libpentobi_base/Book.cpp
@author Markus Enzenberger
@copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------
#include "Book.h"
#include "BoardUtil.h"
#include "libboardgame_base/Log.h"
#include "libboardgame_base/TreeReader.h"
//-----------------------------------------------------------------------------
namespace libpentobi_base {
using libboardgame_base::TreeReader;
//-----------------------------------------------------------------------------
Book::Book(Variant variant)
: m_tree(variant)
{
get_transforms(variant, m_transforms, m_inv_transforms);
}
Move Book::genmove(const Board& bd, Color c)
{
if (bd.has_setup())
// Book cannot handle setup positions
return Move::null();
Move mv;
for (unsigned i = 0; i < m_transforms.size(); ++i)
if (genmove(bd, c, mv, *m_transforms[i], *m_inv_transforms[i]))
return mv;
return Move::null();
}
bool Book::genmove(const Board& bd, Color c, Move& mv,
const PointTransform& transform,
const PointTransform& inv_transform)
{
LIBBOARDGAME_ASSERT(! bd.has_setup());
auto node = &m_tree.get_root();
for (unsigned i = 0; i < bd.get_nu_moves(); ++i)
{
ColorMove color_mv = bd.get_move(i);
color_mv.move = get_transformed(bd, color_mv.move, transform);
node = m_tree.find_child_with_move(*node, color_mv);
if (node == nullptr)
return false;
}
node = select_child(bd, c, m_tree, *node, inv_transform);
if (node == nullptr)
return false;
mv = get_transformed(bd, m_tree.get_move(*node).move, inv_transform);
return true;
}
void Book::load(istream& in)
{
TreeReader reader;
try
{
reader.read(in);
}
catch (const TreeReader::ReadError& e)
{
throw runtime_error(string("could not read book: ") + e.what());
}
unique_ptr<SgfNode> root = reader.move_tree();
m_tree.init(root);
get_transforms(m_tree.get_variant(), m_transforms, m_inv_transforms);
}
const SgfNode* Book::select_child(const Board& bd, Color c,
const PentobiTree& tree, const SgfNode& node,
const PointTransform& inv_transform)
{
unsigned nu_children = node.get_nu_children();
if (nu_children == 0)
return nullptr;
vector<const SgfNode*> good_moves;
for (unsigned i = 0; i < nu_children; ++i)
{
auto& child = node.get_child(i);
ColorMove color_mv = tree.get_move(child);
if (color_mv.is_null())
{
LIBBOARDGAME_LOG("WARNING: Book contains nodes without moves");
continue;
}
if (color_mv.color != c)
{
LIBBOARDGAME_LOG("WARNING: Book contains non-alternating move sequences");
continue;
}
auto mv = get_transformed(bd, color_mv.move, inv_transform);
if (! bd.is_legal(color_mv.color, mv))
{
LIBBOARDGAME_LOG("WARNING: Book contains illegal move");
continue;
}
if (SgfTree::get_good_move(child) > 0)
{
LIBBOARDGAME_LOG(bd.to_string(mv), " !");
good_moves.push_back(&child);
}
else
LIBBOARDGAME_LOG(bd.to_string(mv));
}
if (good_moves.empty())
return nullptr;
LIBBOARDGAME_LOG("Book moves: ", good_moves.size());
auto nu_good_moves = static_cast<unsigned>(good_moves.size());
return good_moves[m_random.generate() % nu_good_moves];
}
//-----------------------------------------------------------------------------
} // namespace libpentobi_base