bool ProofUtil::ShrinkProof(bitset_t& proof, const StoneBoard& board, HexColor loser, const ICEngine& ice) { StoneBoard brd(board.Width(), board.Height()); PatternState pastate(brd); Groups groups; // Give loser all cells outside proof bitset_t cells_outside_proof = (~proof & brd.Const().GetCells()); brd.AddColor(loser, cells_outside_proof); // Give winner only his stones inside proof; HexColor winner = !loser; brd.AddColor(winner, board.GetPlayed(winner) & proof); pastate.Update(); GroupBuilder::Build(brd, groups); // Compute fillin and remove captured cells from the proof InferiorCells inf; ice.ComputeFillin(loser, groups, pastate, inf, HexColorSetUtil::Only(loser)); HexAssert(inf.Captured(winner).none()); bitset_t filled = inf.Dead() | inf.Captured(loser); bitset_t shrunk_proof = proof - filled; bool shrunkTheProof = shrunk_proof.count() < proof.count(); proof = shrunk_proof; return shrunkTheProof; }
HexPoint BenzenePlayer::CheckEndgame(HexBoard& brd, HexColor color, bitset_t& consider, double& score) { if (EndgameUtil::IsDeterminedState(brd, color, score)) return EndgameUtil::PlayDeterminedState(brd, color); else { consider = EndgameUtil::MovesToConsider(brd, color); BenzeneAssert(consider.any()); } score = 0; if (consider.count() == 1 && !m_search_singleton) { HexPoint move = static_cast<HexPoint> (BitsetUtil::FindSetBit(consider)); LogInfo() << "Mustplay is singleton!\n"; return move; } return INVALID_POINT; }
/** Does a 1-ply search. For each move in the consider set, if the move is a win, returns true and the move. If the move is a loss, prune it out of the consider set if there are non-losing moves in the consider set. If all moves are losing, perform no pruning, search will resist. Returns true if there is a win, false otherwise. @todo Is it true that MoHex will resist in the strongest way possible? */ bool MoHexPlayer::PerformPreSearch(HexBoard& brd, HexColor color, bitset_t& consider, double maxTime, PointSequence& winningSequence) { bitset_t losing; HexColor other = !color; PointSequence seq; bool foundWin = false; SgTimer elapsed; Resistance resist; resist.Evaluate(brd); std::vector<HexPoint> moves; SortConsiderSet(consider, resist, moves); for (std::size_t i = 0; i < moves.size() && !foundWin; ++i) { if (elapsed.GetTime() > maxTime) { LogInfo() << "PreSearch: max time reached " << '(' << i << '/' << moves.size() << ").\n"; break; } brd.PlayMove(color, moves[i]); seq.push_back(moves[i]); if (EndgameUtil::IsLostGame(brd, other)) // Check for winning move { winningSequence = seq; foundWin = true; } else if (EndgameUtil::IsWonGame(brd, other)) losing.set(moves[i]); seq.pop_back(); brd.UndoMove(); } // Abort if we found a one-move win if (foundWin) return true; // Backing up cannot cause this to happen, right? BenzeneAssert(!EndgameUtil::IsDeterminedState(brd, color)); // Use the backed-up ice info to shrink the moves to consider if (m_backup_ice_info) { bitset_t new_consider = EndgameUtil::MovesToConsider(brd, color) & consider; if (new_consider.count() < consider.count()) { consider = new_consider; LogFine() << "$$$$$$ new moves to consider $$$$$$" << brd.Write(consider) << '\n'; } } // Subtract any losing moves from the set we consider, unless all of them // are losing (in which case UCT search will find which one resists the // loss well). if (losing.any()) { if (BitsetUtil::IsSubsetOf(consider, losing)) LogInfo() << "************************************\n" << " All UCT root children are losing!!\n" << "************************************\n"; else { LogFine() << "Removed losing moves: " << brd.Write(losing) << '\n'; consider = consider - losing; } } BenzeneAssert(consider.any()); LogInfo() << "Moves to consider:\n" << brd.Write(consider) << '\n'; return false; }
inline std::size_t Group::Size() const { /** @todo Cache group size for speed? */ return m_members.count(); }