void GoAutoBook::ExportToOldFormat(GoAutoBookState& state, std::ostream& out, std::set<SgHashCode>& seen) const { if (seen.count(state.GetHashCode())) return; SgBookNode node; if (! Get(state, node)) return; if (node.IsTerminal() || node.IsLeaf()) return; seen.insert(state.GetHashCode()); SgPoint move = FindBestChild(state); // If no move to play here, do not include it in the book if (move == SG_NULLMOVE) return; const GoBoard& brd = state.Board(); out << brd.Size() << ' '; for (int i = 0; i < brd.MoveNumber(); ++i) out << ' ' << SgWritePoint(brd.Move(i).Point()); out << " | " << SgWritePoint(move); out << '\n'; for (GoBoard::Iterator it(brd); it; ++it) if (brd.IsLegal(*it)) { state.Play(*it); ExportToOldFormat(state, out, seen); state.Undo(); } }
void GoAutoBook::TruncateByDepth(int depth, GoAutoBookState& state, GoAutoBook& other, std::set<SgHashCode>& seen) const { if (seen.count(state.GetHashCode())) return; SgBookNode node; if (! Get(state, node)) return; seen.insert(state.GetHashCode()); if (depth == 0) { // Set this node to be a leaf: copy its heuristic value into // its propagated value and set count to 0. node.m_count = 0; node.m_priority = SgBookNode::LEAF_PRIORITY; node.m_value = node.m_heurValue; other.Put(state, node); return; } other.Put(state, node); if (node.IsLeaf() || node.IsTerminal()) return; for (GoBoard::Iterator it(state.Board()); it; ++it) { if (state.Board().IsLegal(*it)) { state.Play(*it); TruncateByDepth(depth - 1, state, other, seen); state.Undo(); } } }
SgMove GoAutoBook::FindBestChild(GoAutoBookState& state) const { std::size_t bestCount = 0; SgMove bestMove = SG_NULLMOVE; float bestScore = 100.0f; SgBookNode node; if (!Get(state, node)) return SG_NULLMOVE; if (node.IsLeaf()) return SG_NULLMOVE; for (GoBoard::Iterator it(state.Board()); it; ++it) { if (state.Board().IsLegal(*it)) { state.Play(*it); if (m_disabled.count(state.GetHashCode()) > 0) SgDebug() << "Ignoring disabled move " << SgWritePoint(*it) << '\n'; // NOTE: Terminal nodes aren't supported at this time, so // we ignore them here. else if (Get(state, node) && !node.IsTerminal() && node.m_count >= m_param.m_usageCountThreshold) { if (m_param.m_selectType == GO_AUTOBOOK_SELECT_COUNT) { // Select by count, tiebreak by value. if (node.m_count > bestCount) { bestCount = node.m_count; bestMove = *it; bestScore = node.m_value; } // NOTE: do not have access to inverse function, // so we're minimizing here as a temporary solution. else if (node.m_count == bestCount && node.m_value < bestScore) { bestMove = *it; bestScore = node.m_value; } } else if (m_param.m_selectType == GO_AUTOBOOK_SELECT_VALUE) { // NOTE: do not have access to inverse function, // so we're minimizing here as a temporary solution. if (node.m_value < bestScore) { bestMove = *it; bestScore = node.m_value; } } } state.Undo(); } } return bestMove; }
SgMove GoAutoBook::FindBestChild(GoAutoBookState& state) const { std::size_t bestCount = 0; SgMove bestMove = SG_NULLMOVE; SgMove bestIgnoredMove = SG_NULLMOVE; float bestScore = 100.0f; float bestIgnoredMoveScore = 100.0f; SgBookNode node; // Check for forced moves first // Note this will check for forced moves even if the current // state is not in the book. for (GoBoard::Iterator it(state.Board()); it; ++it) { if (state.Board().IsLegal(*it)) { state.Play(*it); if (m_forced.count(state.GetHashCode()) > 0) { SgDebug() << "Playing forced move " << SgWritePoint(*it) << '\n'; return *it; } state.Undo(); } } if (! Get(state, node)) return SG_NULLMOVE; if (node.IsLeaf()) return SG_NULLMOVE; for (GoBoard::Iterator it(state.Board()); it; ++it) { if (state.Board().IsLegal(*it)) { state.Play(*it); if (m_disabled.count(state.GetHashCode()) > 0) SgDebug() << "Ignoring disabled move " << SgWritePoint(*it) << '\n'; // NOTE: Terminal nodes aren't supported at this time, so // we ignore them here. else if ( Get(state, node) && ! node.IsTerminal() ) { if (node.m_count >= m_param.m_usageCountThreshold) { if (m_param.m_selectType == GO_AUTOBOOK_SELECT_COUNT) { // Select by count, tiebreak by value. if (node.m_count > bestCount) { bestCount = node.m_count; bestMove = *it; bestScore = node.m_value; } // NOTE: do not have access to inverse function, // so we're minimizing here as a temporary solution. else if (node.m_count == bestCount && node.m_value < bestScore) { bestMove = *it; bestScore = node.m_value; } } else if (m_param.m_selectType == GO_AUTOBOOK_SELECT_VALUE) { // NOTE: do not have access to inverse function, // so we're minimizing here as a temporary solution. if (node.m_value < bestScore) { bestMove = *it; bestScore = node.m_value; } } } else // node.m_count < m_param.m_usageCountThreshold if ( m_param.m_selectType == GO_AUTOBOOK_SELECT_VALUE && node.m_value < bestIgnoredMoveScore ) { bestIgnoredMove = *it; bestIgnoredMoveScore = node.m_value; } } state.Undo(); } } if (bestMove != SG_NULLMOVE && bestIgnoredMoveScore < bestScore) { SgDebug() << "Ignoring autobook move " << SgWritePoint(bestMove) << " since best ignored inverse value " << std::setprecision(5) << bestIgnoredMoveScore << " of move " << SgWritePoint(bestIgnoredMove) << " is better than best value above usage threshold " << bestScore << '\n'; return SG_NULLMOVE; } return bestMove; }