bool EndgameUtil::IsWonGame(const HexBoard& brd, HexColor color, bitset_t& proof) { if (brd.GetGroups().GetWinner() == color) { proof = StonesInProof(brd, color); return true; } VC vc; const HexPoint edge1 = HexPointUtil::colorEdge1(color); const HexPoint edge2 = HexPointUtil::colorEdge2(color); if (brd.Cons(color).SmallestVC(edge1, edge2, VC::SEMI, vc)) { proof = vc.Carrier() | StonesInProof(brd, color); return true; } if (brd.Cons(color).SmallestVC(edge1, edge2, VC::FULL, vc)) { proof = vc.Carrier() | StonesInProof(brd, color); return true; } return false; }
bitset_t ProofUtil::InitialProofForOpponent(const HexBoard& brd, HexColor toPlay) { // Add opponent played stones and deduction set. const InferiorCells& inf = brd.GetInferiorCells(); bitset_t proof = brd.GetPosition().GetPlayed(!toPlay); proof |= inf.DeductionSet(!toPlay); // Add all semi-connections from the mustplay. const VCList& lst = brd.Cons(!toPlay).GetList(VC::SEMI, HexPointUtil::colorEdge1(!toPlay), HexPointUtil::colorEdge2(!toPlay)); const bool useGreedy = brd.Builder().Parameters().use_greedy_union; proof |= useGreedy ? lst.getGreedyUnion() : lst.getUnion(); // Add reversable reversers. // The carriers do NOT need to be included in the proof, since // they are captured by the (losing) player, not his opponent (for // whom we are building the proof set). // TODO: Currently, we just add the first reverser: we should see // if any reverser is already in the proof, since then we wouldn't // need to add one. for (BitsetIterator p(inf.Reversible()); p; ++p) { const std::set<HexPoint>& reversers = inf.Reversers(*p); proof.set(*reversers.begin()); } // Add vulnerable killers and their carriers. // TODO: Currently, we just add the first killer: we should see if // any killer is already in the proof, since then we wouldn't need // to add one. for (BitsetIterator p(inf.Vulnerable()); p; ++p) { const std::set<VulnerableKiller>& killers = inf.Killers(*p); proof.set((*killers.begin()).killer()); proof |= ((*killers.begin()).carrier()); } return proof; }
bool EndgameUtil::IsLostGame(const HexBoard& brd, HexColor color, bitset_t& proof) { if (brd.GetGroups().GetWinner() == !color) { proof = StonesInProof(brd, !color); return true; } VC vc; if (brd.Cons(!color).SmallestVC(HexPointUtil::colorEdge1(!color), HexPointUtil::colorEdge2(!color), VC::FULL, vc)) { proof = vc.Carrier() | StonesInProof(brd, !color); return true; } if (ComputeConsiderSet(brd, color).none()) { proof = brd.GetPosition().GetEmpty() | StonesInProof(brd, !color); return true; } return false; }
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; }