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
|
//-----------------------------------------------------------------------------
/** @file libpentobi_base/BoardUpdater.cpp
@author Markus Enzenberger
@copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------
#include "BoardUpdater.h"
#include "BoardUtil.h"
#include "libboardgame_base/SgfUtil.h"
namespace libpentobi_base {
using libboardgame_base::SgfError;
using libboardgame_base::get_path_from_root;
//-----------------------------------------------------------------------------
namespace {
/** List to hold remaining pieces of a color with one entry for each instance
of the same piece. */
using AllPiecesLeftList =
ArrayList<Piece, PieceInfo::max_instances * Piece::max_pieces>;
/** Helper function used in init_setup. */
void handle_setup_property(const SgfNode& node, const char* id, Color c,
const Board& bd, Setup& setup,
ColorMap<AllPiecesLeftList>& pieces_left)
{
if (! node.has_property(id))
return;
for (auto& s : node.get_multi_property(id))
{
Move mv;
if (! bd.from_string(mv, s))
throw SgfError("invalid move " + s);
Piece piece = bd.get_move_piece(mv);
if (! pieces_left[c].remove(piece))
throw SgfError("piece played twice");
setup.placements[c].push_back(mv);
}
}
/** Helper function used in init_setup. */
void handle_setup_empty(const SgfNode& node, const Board& bd, Setup& setup,
ColorMap<AllPiecesLeftList>& pieces_left)
{
if (! node.has_property("AE"))
return;
for (auto& s : node.get_multi_property("AE"))
{
Move mv;
if (! bd.from_string(mv, s))
throw SgfError("invalid move " + s);
for (Color c : bd.get_colors())
if (setup.placements[c].remove(mv))
{
Piece piece = bd.get_move_piece(mv);
pieces_left[c].push_back(piece);
break;
}
}
}
/** Initialize the board with a new setup position.
Class Board only supports setup positions before any moves are played. To
support setup properties in any node, we create a new setup position from
the current position and the setup properties from the node and initialize
the board with it. */
void init_setup(Board& bd, const SgfNode& node)
{
Setup setup;
get_current_position_as_setup(bd, setup);
ColorMap<AllPiecesLeftList> all_pieces_left;
for (Color c : bd.get_colors())
for (Piece piece : bd.get_pieces_left(c))
for (unsigned i = 0; i < bd.get_nu_piece_instances(piece); ++i)
all_pieces_left[c].push_back(piece);
handle_setup_property(node, "A1", Color(0), bd, setup, all_pieces_left);
handle_setup_property(node, "A2", Color(1), bd, setup, all_pieces_left);
handle_setup_property(node, "A3", Color(2), bd, setup, all_pieces_left);
handle_setup_property(node, "A4", Color(3), bd, setup, all_pieces_left);
// AB, AW are equivalent to A1, A2 but only used in games with two colors
handle_setup_property(node, "AB", Color(0), bd, setup, all_pieces_left);
handle_setup_property(node, "AW", Color(1), bd, setup, all_pieces_left);
handle_setup_empty(node, bd, setup, all_pieces_left);
Color to_play;
if (! libpentobi_base::get_player(node, bd.get_nu_colors(),
setup.to_play))
{
// Try to guess who should be to play based on the setup pieces.
setup.to_play = Color(0);
for (Color c : bd.get_colors())
if (setup.placements[c].size() < setup.placements[Color(0)].size())
{
setup.to_play = c;
break;
}
}
bd.init(&setup);
}
} // namespace
//-----------------------------------------------------------------------------
void BoardUpdater::update(Board& bd, const PentobiTree& tree,
const SgfNode& node)
{
LIBBOARDGAME_ASSERT(tree.contains(node));
bd.init();
get_path_from_root(node, m_path);
for (const auto i : m_path)
{
if (libpentobi_base::has_setup(*i))
init_setup(bd, *i);
auto mv = tree.get_move(*i);
if (! mv.is_null())
{
if (! bd.is_piece_left(mv.color, bd.get_move_piece(mv.move)))
throw SgfError("piece played twice");
bd.play(mv);
}
}
}
//-----------------------------------------------------------------------------
} // namespace libpentobi_base
|