00001 //---------------------------------------------------------------------------- 00002 /** @file ProofUtil.hpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef PROOFUTIL_HPP 00007 #define PROOFUTIL_HPP 00008 00009 #include "Hex.hpp" 00010 #include "BenzeneSolver.hpp" 00011 #include "StoneBoard.hpp" 00012 #include "ICEngine.hpp" 00013 #include "SolverDB.hpp" 00014 #include "SortedSequence.hpp" 00015 00016 _BEGIN_BENZENE_NAMESPACE_ 00017 00018 //---------------------------------------------------------------------------- 00019 00020 /** Deduce equivalent states, etc. */ 00021 namespace ProofUtil 00022 { 00023 /** Compute the maximum possible proof. */ 00024 bitset_t MaximumProofSet(const HexBoard& brd, HexColor toPlay); 00025 00026 /** The proof for a losing state is the union the proofs for each 00027 move. This function returns the proof defined by all opponent 00028 semi-connctions as well as any ice deductions. 00029 @note The proof is for the opponent of toPlay. 00030 @todo Argh, document this better. */ 00031 bitset_t InitialProofForOpponent(const HexBoard& brd, HexColor toPlay); 00032 00033 /** Gives all cells outside of the proof to loser, computes fillin 00034 using ice, removes any cell in proof that is filled-in. 00035 Returns true if proof was shrunk. */ 00036 bool ShrinkProof(bitset_t& proof, const StoneBoard& board, 00037 HexColor loser, const ICEngine& ice); 00038 00039 /** Computes and stores in db the transpostions of this proof on 00040 the given boardstate. Returns number of db entries 00041 successfully added or updated. */ 00042 template<class HASH, class DB, class DATA> 00043 int StoreTranspositions(SolverDB<HASH,DB,DATA>& db, const DATA& data, 00044 const HexState& state, const bitset_t& proof, 00045 HexColor winner); 00046 00047 /** Computes and stores in db the flipped transpostions of this 00048 proof on the given boardstate. Returns number of db entries 00049 successfully added or updated. */ 00050 template<class HASH, class DB, class DATA> 00051 int StoreFlippedStates(SolverDB<HASH,DB,DATA>& db, const DATA& data, 00052 const HexState& state, const bitset_t& proof, 00053 HexColor winner); 00054 } 00055 00056 //---------------------------------------------------------------------------- 00057 00058 template<class HASH, class DB, class DATA> 00059 int ProofUtil::StoreTranspositions(SolverDB<HASH,DB,DATA>& db, 00060 const DATA& data, const HexState& state, 00061 const bitset_t& proof, HexColor winner) 00062 { 00063 boost::function_requires< HasFlagsConcept<DATA> >(); 00064 const StoneBoard& brd = state.Position(); 00065 00066 // Number of non-fillin game stones played 00067 int numBlack = (brd.GetPlayed(BLACK) & brd.Const().GetCells()).count(); 00068 int numWhite = (brd.GetPlayed(WHITE) & brd.Const().GetCells()).count(); 00069 HexAssert(numBlack + numWhite == brd.NumStones()); 00070 00071 // Loser can use all his stones as well as all those outside the proof 00072 HexColor loser = !winner; 00073 bitset_t outside = (~proof & brd.GetEmpty()) 00074 | (brd.GetColor(loser) & brd.Const().GetCells()); 00075 00076 // Winner can use all of his stones 00077 bitset_t winners = brd.GetColor(winner) & brd.Const().GetCells(); 00078 00079 // Store the players' stones as lists of sorted indices 00080 std::vector<HexPoint> black, white; 00081 std::vector<HexPoint>& lose_list = (loser == BLACK) ? black : white; 00082 std::vector<HexPoint>& winn_list = (loser == BLACK) ? white : black; 00083 BitsetUtil::BitsetToVector(outside, lose_list); 00084 BitsetUtil::BitsetToVector(winners, winn_list); 00085 00086 HexAssert(black.size() >= (unsigned)numBlack); 00087 HexAssert(white.size() >= (unsigned)numWhite); 00088 00089 // Write each transposition 00090 int count = 0; 00091 HexState myState(state); 00092 StoneBoard& board = myState.Position(); 00093 SortedSequence bseq(black.size(), numBlack); 00094 while (!bseq.finished()) 00095 { 00096 SortedSequence wseq(white.size(), numWhite); 00097 while (!wseq.finished()) 00098 { 00099 // Convert the indices into cells 00100 board.StartNewGame(); 00101 for (int i = 0; i < numBlack; ++i) 00102 board.PlayMove(BLACK, black[bseq[i]]); 00103 for (int i = 0; i < numWhite; ++i) 00104 board.PlayMove(WHITE, white[wseq[i]]); 00105 00106 // Mark state as transposition if the current one is not 00107 // the original. 00108 DATA ss(data); 00109 if (board.Hash() != brd.Hash()) 00110 ss.m_flags |= SolverDataFlags::TRANSPOSITION; 00111 db.Put(myState, ss); 00112 ++count; 00113 00114 ++wseq; 00115 } 00116 ++bseq; 00117 } 00118 return count; 00119 } 00120 00121 template<class HASH, class DB, class DATA> 00122 int ProofUtil::StoreFlippedStates(SolverDB<HASH,DB,DATA>& db, const DATA& data, 00123 const HexState& state, const bitset_t& proof, 00124 HexColor winner) 00125 { 00126 boost::function_requires< HasFlagsConcept<DATA> >(); 00127 boost::function_requires< HasMirrorConcept<DATA> >(); 00128 const StoneBoard& brd = state.Position(); 00129 00130 // Start by computing the flipped board position. 00131 // This involves mirroring the stones and *flipping their colour*. 00132 bitset_t flippedBlack = BoardUtils::Mirror(brd.Const(), 00133 brd.GetPlayed(WHITE) & brd.Const().GetCells()); 00134 bitset_t flippedWhite = BoardUtils::Mirror(brd.Const(), 00135 brd.GetPlayed(BLACK) & brd.Const().GetCells()); 00136 StoneBoard flippedBrd(brd.Width(), brd.Height()); 00137 flippedBrd.AddColor(BLACK, flippedBlack); 00138 flippedBrd.AddColor(WHITE, flippedWhite); 00139 flippedBrd.SetPlayed(flippedBlack | flippedWhite); 00140 00141 00142 HexColor flippedWinner = !winner; 00143 bitset_t flippedProof = BoardUtils::Mirror(brd.Const(), proof); 00144 bitset_t flippedOutside = (~flippedProof & flippedBrd.GetEmpty()); 00145 00146 // Determine what stones we can add or remove. 00147 bool canAddFlippedBlack = false; 00148 bitset_t flippedBlackToAdd; 00149 bool canRemoveFlippedWhite = false; 00150 bitset_t flippedWhiteToRemove; 00151 // To switch player to move (while keeping parity valid), we must 00152 // either add one stone to flippedBlack or else delete 1 stone 00153 // from flippedWhite. Note that we can always add winner stones or 00154 // delete loser stones without changing the value, and we can add 00155 // loser stones if the proof set does not cover all empty cells. 00156 if (flippedWinner == BLACK) 00157 { 00158 canAddFlippedBlack = true; 00159 flippedBlackToAdd = flippedBrd.GetEmpty(); 00160 canRemoveFlippedWhite = true; 00161 flippedWhiteToRemove = flippedWhite; 00162 } 00163 else 00164 { 00165 HexAssert(flippedWinner == WHITE); 00166 canAddFlippedBlack = flippedOutside.any(); 00167 flippedBlackToAdd = flippedOutside; 00168 } 00169 HexAssert(canAddFlippedBlack != flippedBlackToAdd.none()); 00170 HexAssert(BitsetUtil::IsSubsetOf(flippedBlackToAdd,flippedBrd.GetEmpty())); 00171 HexAssert(canRemoveFlippedWhite != flippedWhiteToRemove.none()); 00172 HexAssert(BitsetUtil::IsSubsetOf(flippedWhiteToRemove,flippedWhite)); 00173 00174 // Now we can create and store the desired flipped states. 00175 DATA ss(data); 00176 ss.Mirror(brd.Const()); 00177 ss.m_flags |= SolverDataFlags::TRANSPOSITION; 00178 ss.m_flags |= SolverDataFlags::MIRROR_TRANSPOSITION; 00179 00180 int count = 0; 00181 if (canAddFlippedBlack) 00182 { 00183 for (BitsetIterator i(flippedBlackToAdd); i; ++i) 00184 { 00185 flippedBrd.PlayMove(BLACK, *i); 00186 HexAssert(!state.ToPlay() == flippedBrd.WhoseTurn()); 00187 db.Put(HexState(flippedBrd, WHITE), ss); 00188 flippedBrd.UndoMove(*i); 00189 ++count; 00190 } 00191 } 00192 if (canRemoveFlippedWhite) 00193 { 00194 for (BitsetIterator i(flippedWhiteToRemove); i; ++i) 00195 { 00196 flippedBrd.UndoMove(*i); 00197 HexAssert(!state.ToPlay() == flippedBrd.WhoseTurn()); 00198 db.Put(HexState(flippedBrd, WHITE), ss); 00199 flippedBrd.PlayMove(WHITE, *i); 00200 ++count; 00201 } 00202 } 00203 return count; 00204 } 00205 00206 //---------------------------------------------------------------------------- 00207 00208 _END_BENZENE_NAMESPACE_ 00209 00210 #endif // PROOFUTIL_HPP