SearchResult UCTSearch::play_simulation(GameState & currstate, UCTNode* const node) { const auto color = currstate.get_to_move(); auto result = SearchResult{}; node->virtual_loss(); if (!node->has_children()) { if (currstate.get_passes() >= 2) { auto score = currstate.final_score(); result = SearchResult::from_score(score); } else if (m_nodes < MAX_TREE_SIZE) { auto mem_full_pct = m_nodes / static_cast<float>(MAX_TREE_SIZE); float eval; auto success = node->create_children(m_nodes, currstate, eval, mem_full_pct); if (success) { result = SearchResult::from_eval(eval); } } } if (node->has_children() && !result.valid()) { auto next = node->uct_select_child(color, node == m_root.get()); if (next != nullptr) { auto move = next->get_move(); currstate.play_move(move); if (move != FastBoard::PASS && currstate.superko()) { next->invalidate(); } else { result = play_simulation(currstate, next); } } } if (result.valid()) { node->update(result.eval()); } node->virtual_loss_undo(); return result; }