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
|