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; }
void DfpnSolver::DeleteChildren(DfpnChildren& children, std::vector<DfpnData>& childrenData, bitset_t deleteChildren) const { HexAssert(children.Size() == childrenData.size()); bitset_t deleted; std::vector<HexPoint>::iterator it1 = children.m_children.begin(); std::vector<DfpnData>::iterator it2 = childrenData.begin(); while (it1 != children.m_children.end()) { HexAssert(it2 != childrenData.end()); if (deleteChildren.test(*it1)) { HexAssert(!deleted.test(*it1)); deleted.set(*it1); it1 = children.m_children.erase(it1); it2 = childrenData.erase(it2); } else { ++it1; ++it2; } } HexAssert(children.Size() > 0); HexAssert(children.Size() == childrenData.size()); HexAssert(deleteChildren == deleted); }
// // *b*it *ar*ithmetics (BAR) // template<class T> inline void bar( const Perm_matrix<T>& pmat, //matrix of predefined permutations const bitset_t& b, //bitset aka dummy coded data std::valarray<T>& res) //results are written into res { assert (b.size() == pmat.bitMat_.front().size()); assert (res.size() == pmat.bitMat_.size()); for (size_t i=0; i<res.size(); i++) { res[i] = (b & pmat.bitMat_[i]).count(); } }
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; }
inline bool StoneBoard::IsPlayed(HexPoint cell) const { BenzeneAssert(Const().IsValid(cell)); return m_played.test(cell); }
bool Decompositions::Find(const HexBoard& brd, HexColor color, bitset_t& captured) { // If game is over or decided, don't do any work. HexPoint edge1 = HexPointUtil::colorEdge1(color); HexPoint edge2 = HexPointUtil::colorEdge2(color); const VCSet& cons = brd.Cons(color); if (brd.GetGroups().IsGameOver() || cons.Exists(edge1, edge2, VC::FULL)) { captured.reset(); return false; } /** Compute neighbouring groups of opposite color. NOTE: Assumes that edges that touch are adjacent. See ConstBoard for more details. */ PointToBitset adjTo; PointToBitset adjByMiai; ComputeAdjacentByMiai(brd, adjByMiai); for (GroupIterator g(brd.GetGroups(), color); g; ++g) { bitset_t opptNbs = adjByMiai[g->Captain()] | (g->Nbs() & brd.GetPosition().GetColor(!color)); if (opptNbs.count() >= 2) adjTo[g->Captain()] = opptNbs; } // The two color edges are in the list. If no other groups are, then quit. BenzeneAssert(adjTo.size() >= 2); if (adjTo.size() == 2) { captured.reset(); return false; } // Compute graph representing board from color's perspective. PointToBitset graphNbs; GraphUtil::ComputeDigraph(brd.GetGroups(), color, graphNbs); // Find (ordered) pairs of color groups that are VC-connected and have at // least two adjacent opponent groups in common. PointToBitset::iterator g1, g2; for (g1 = adjTo.begin(); g1 != adjTo.end(); ++g1) { for (g2 = adjTo.begin(); g2 != g1; ++g2) { if ((g1->second & g2->second).count() < 2) continue; if (!cons.Exists(g1->first, g2->first, VC::FULL)) continue; // This is such a pair, so at least one of the two is not an edge. // Find which color edges are not equal to either of these groups. BenzeneAssert(!HexPointUtil::isEdge(g1->first) || !HexPointUtil::isEdge(g2->first)); bool edge1Free = (g1->first != edge1 && g2->first != edge1); bool edge2Free = (g1->first != edge2 && g2->first != edge2); // Find the set of empty cells bounded by these two groups. bitset_t stopSet = graphNbs[g1->first] | graphNbs[g2->first]; bitset_t decompArea; decompArea.reset(); if (edge1Free) decompArea |= GraphUtil::BFS(edge1, graphNbs, stopSet); if (edge2Free) decompArea |= GraphUtil::BFS(edge2, graphNbs, stopSet); decompArea.flip(); decompArea &= brd.GetPosition().GetEmpty(); // If the pair has a VC confined to these cells, then we have // a decomposition - return it. const VCList& vl = cons.GetList(VC::FULL, g1->first, g2->first); for (VCListConstIterator it(vl); it; ++it) { if (BitsetUtil::IsSubsetOf(it->Carrier(), decompArea)) { captured = it->Carrier(); return true; } } } } // No combinatorial decomposition with a VC was found. captured.reset(); return false; }
/** 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 bool Group::IsMember(HexPoint point) const { return m_members.test(point); }
inline std::size_t Group::Size() const { /** @todo Cache group size for speed? */ return m_members.count(); }