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;
}