00001 //---------------------------------------------------------------------------- 00002 /** @file StoneBoard.hpp 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef STONEBOARD_H 00007 #define STONEBOARD_H 00008 00009 #include "Hex.hpp" 00010 #include "ConstBoard.hpp" 00011 #include "ZobristHash.hpp" 00012 00013 _BEGIN_BENZENE_NAMESPACE_ 00014 00015 //--------------------------------------------------------------------------- 00016 00017 /** Packed representation of a board-state. Useful for storing 00018 board positions in databases, opening books, etc. */ 00019 typedef std::vector<byte> BoardID; 00020 00021 //--------------------------------------------------------------------------- 00022 00023 /** Tracks played stone information. 00024 00025 Each cell on the board is assigned a HexColor, and so every cell 00026 is either EMPTY, BLACK, or WHITE. 00027 00028 Each cell is also marked as 'played' or 'unplayed'. A cell should 00029 be marked as played when it corresponds to an actual move played 00030 in a game; that is, not a fill-in move. This means it is possible 00031 for a cell to be BLACK or WHITE and not played. Played stones 00032 contribute to the board hash and id, unplayed stones do not. 00033 @see Hash(), GetBoardID(), setPlayed(). 00034 */ 00035 class StoneBoard 00036 { 00037 public: 00038 00039 /** Constructs an unusable board. This is to allow StoneBoard to 00040 appear in a stl container. */ 00041 StoneBoard(); 00042 00043 /** Constructs a square board. */ 00044 explicit StoneBoard(unsigned size); 00045 00046 /** Constructs a rectangular board. */ 00047 StoneBoard(unsigned width, unsigned height); 00048 00049 /** Contructs a rectangular board with given state. 00050 See SetPosition(std::string) */ 00051 StoneBoard(unsigned width, unsigned height, const std::string& str); 00052 00053 ~StoneBoard(); 00054 00055 //----------------------------------------------------------------------- 00056 00057 /** Returns reference to ConstBoard. */ 00058 const ConstBoard& Const() const; 00059 00060 /** Same as Const().width() */ 00061 int Width() const; 00062 00063 /** Same as Const().height() */ 00064 int Height() const; 00065 00066 /** Returns zobrist hash for the current position, which depends 00067 only on the played cells; unplayed cells do not contribute to 00068 the hash. Changing the color of an unplayed cell does not 00069 change the hash for the position. Methods that change the 00070 color of played cells internally will always compute a new 00071 hash automatically. */ 00072 hash_t Hash() const; 00073 00074 /** Returns the hash of the position taking the color to play into 00075 account. This will be different than the hash returned by 00076 Hash(). */ 00077 hash_t Hash(HexColor toPlay) const; 00078 00079 /** Returns BoardID for the current board state, looking only at 00080 the played cells. */ 00081 BoardID GetBoardID() const; 00082 00083 /** Returns BoardID as a string. 00084 @todo Moves this out of here? */ 00085 std::string GetBoardIDString() const; 00086 00087 //----------------------------------------------------------------------- 00088 00089 /** Number of played stones on the interior of the board. 00090 Similar to: 00091 @code 00092 num bits = (GetOccupied() & GetPlayed() & GetCells()).count(); 00093 @endcode 00094 */ 00095 std::size_t NumStones() const; 00096 00097 /** Computes whose turn it is on the given board; 00098 IsStandardPosition() must be true to use this method. */ 00099 HexColor WhoseTurn() const; 00100 00101 /** Returns true if position is attainable in a normal game. 00102 That is, FIRST_TO_PLAY went first, and the colors alternated 00103 afterwards. */ 00104 bool IsStandardPosition() const; 00105 00106 //----------------------------------------------------------------------- 00107 00108 /** Returns a string representation of the board. */ 00109 std::string Write() const; 00110 00111 /** Returns a string representation of the board with the cells 00112 marked in the given bitset denoted by a '*'. */ 00113 std::string Write(const bitset_t& b) const; 00114 00115 //----------------------------------------------------------------------- 00116 00117 /** Sets the board to the state encoded by id. 00118 Note this state will have no unplayed stones, so the code: 00119 @code 00120 brd.SetPosition(brd.GetBoardID()); 00121 @endcode 00122 will remove all unplayed stones. 00123 */ 00124 void SetPosition(const BoardID& id); 00125 00126 /** Copies state of brd into this board. */ 00127 void SetPosition(const StoneBoard& brd); 00128 00129 /** Copies only the played state of brd. */ 00130 void SetPositionOnlyPlayed(const StoneBoard& brd); 00131 00132 /** Sets state from string. 00133 String must contain wxh non space characters. Any spacing is 00134 allowed betwen such characters. A '.' is an empty cell, 'B' 00135 and 'W' are played black and white stones, 'b' and 'w' are 00136 filled-in black and white stones. 00137 */ 00138 void SetPosition(const std::string& str); 00139 00140 //----------------------------------------------------------------------- 00141 00142 /** @name Methods defined on cells and edges. 00143 00144 All methods accept and return edge and interior cells only. 00145 Note that PlayMove() (which is not in this section) can play a 00146 move like (BLACK, RESIGN), but getBlack() (which is in this 00147 section) will not return a bitset with the RESIGN move set. 00148 00149 @todo Why did we agree on this? :) 00150 */ 00151 // @{ 00152 00153 /** Returns the set of BLACK stones. */ 00154 bitset_t GetBlack() const; 00155 00156 /** Returns the set of WHITE stones. */ 00157 bitset_t GetWhite() const; 00158 00159 /** Returns color's stones. */ 00160 bitset_t GetColor(HexColor color) const; 00161 00162 /** Returns all empty cells. */ 00163 bitset_t GetEmpty() const; 00164 00165 /** Returns all occupied (not empty) cells. */ 00166 bitset_t GetOccupied() const; 00167 00168 /** Returns true if cell is of color. */ 00169 bool IsColor(HexPoint cell, HexColor color) const; 00170 00171 /** Returns true if cell is empty. */ 00172 bool IsEmpty(HexPoint cell) const; 00173 00174 /** Returns true if cell is occupied (not empty). */ 00175 bool IsOccupied(HexPoint cell) const; 00176 00177 // @} 00178 00179 //----------------------------------------------------------------------- 00180 00181 /** @name Methods defined on all valid moves. */ 00182 // @{ 00183 00184 /** Returns true if cell is BLACK. */ 00185 bool IsBlack(HexPoint cell) const; 00186 00187 /** Returns true if cell is WHITE. */ 00188 bool IsWhite(HexPoint cell) const; 00189 00190 /** Retruns color of cell. */ 00191 HexColor GetColor(HexPoint cell) const; 00192 00193 /** Returns the set of played cells. */ 00194 bitset_t GetPlayed() const; 00195 bitset_t GetPlayed(HexColor color) const; 00196 00197 /** Returns the set of all legal moves; ie, moves that can be 00198 played from this state. */ 00199 bitset_t GetLegal() const; 00200 00201 /** Returns true if cell has been played. */ 00202 bool IsPlayed(HexPoint cell) const; 00203 00204 /** Returns true if cell is a legal move. */ 00205 bool IsLegal(HexPoint cell) const; 00206 00207 // @} 00208 00209 //----------------------------------------------------------------------- 00210 00211 /** @name Methods not modifying Hash() or BoardID() */ 00212 // @{ 00213 00214 /** Adds the cells in b as stones of color. Does not modify 00215 hash. */ 00216 void AddColor(HexColor color, const bitset_t& b); 00217 00218 /** Sets cells in b to EMPTY. Does not modify hash. */ 00219 void RemoveColor(HexColor color, const bitset_t& b); 00220 00221 /** Sets color of cell. Does not modify hash. */ 00222 void SetColor(HexColor color, HexPoint cell); 00223 00224 /** Sets color of cells in bitset. Does not modify hash. */ 00225 void SetColor(HexColor color, const bitset_t& bs); 00226 00227 /** Returns true if rotating the board returns the same board. */ 00228 bool IsSelfRotation() const; 00229 00230 // @} 00231 00232 //----------------------------------------------------------------------- 00233 00234 /** @name Methods modifying Hash() and BoardID() */ 00235 // @{ 00236 00237 /** Clears the board and plays the edge stones. */ 00238 void StartNewGame(); 00239 00240 /** Sets the played stones. These stones, and only these stones, 00241 will contribute to the board hash and board id. Hash is 00242 recomputed. @see Hash(). */ 00243 void SetPlayed(const bitset_t& p); 00244 00245 /** Plays a move of the given color to the board. Adds cell to the 00246 set of played stones. Updates the board hash. 00247 @param color must BLACK or WHITE 00248 @param cell Any valid move, include RESIGN and SWAP_PIECES. 00249 */ 00250 void PlayMove(HexColor color, HexPoint cell); 00251 00252 /** Removes the move from the board, setting cell to EMPTY. Hash 00253 is updated. */ 00254 void UndoMove(HexPoint cell); 00255 00256 /** Rotates the board by 180' about the center. Hash is 00257 updated. */ 00258 void RotateBoard(); 00259 00260 /** Mirrors the board in the diagonal joining acute corners. Note 00261 that this method requires the board to be square. Hash is 00262 updated. */ 00263 void MirrorBoard(); 00264 00265 // @} 00266 00267 //----------------------------------------------------------------------- 00268 00269 /** @name Operators */ 00270 // @{ 00271 00272 /** Two boards are equal if their dimensions match and their sets 00273 of black, white, and played stones are all equal. */ 00274 bool operator==(const StoneBoard& other) const; 00275 00276 /** Returns true if the boards differ. See operator==(). */ 00277 bool operator!=(const StoneBoard& other) const; 00278 00279 // @} 00280 00281 //----------------------------------------------------------------------- 00282 00283 /** @name Iterators */ 00284 // @{ 00285 00286 /** Returns iterator over all stones in colorset. */ 00287 BoardIterator Stones(HexColorSet colorset) const; 00288 00289 /** Returns iterator over all stones of color. */ 00290 BoardIterator Stones(HexColor color) const; 00291 00292 // @} 00293 00294 //----------------------------------------------------------------------- 00295 00296 private: 00297 ConstBoard* m_const; 00298 00299 bitset_t m_played; 00300 00301 bitset_t m_stones[BLACK_AND_WHITE]; 00302 00303 /** @see Hash() */ 00304 ZobristHash m_hash; 00305 00306 mutable bool m_stones_calculated; 00307 00308 mutable std::vector<HexPoint> m_stones_list[NUM_COLOR_SETS]; 00309 00310 void ComputeHash(); 00311 00312 void MarkAsDirty(); 00313 00314 bool IsBlackWhiteDisjoint(); 00315 }; 00316 00317 inline const ConstBoard& StoneBoard::Const() const 00318 { 00319 return *m_const; 00320 } 00321 00322 inline int StoneBoard::Width() const 00323 { 00324 return m_const->Width(); 00325 } 00326 00327 inline int StoneBoard::Height() const 00328 { 00329 return m_const->Height(); 00330 } 00331 00332 inline hash_t StoneBoard::Hash() const 00333 { 00334 return m_hash.Hash(EMPTY); 00335 } 00336 00337 inline hash_t StoneBoard::Hash(HexColor toPlay) const 00338 { 00339 return m_hash.Hash(toPlay); 00340 } 00341 00342 inline bitset_t StoneBoard::GetBlack() const 00343 { 00344 return m_stones[BLACK] & Const().GetLocations(); 00345 } 00346 00347 inline bitset_t StoneBoard::GetWhite() const 00348 { 00349 return m_stones[WHITE] & Const().GetLocations(); 00350 } 00351 00352 inline bitset_t StoneBoard::GetColor(HexColor color) const 00353 { 00354 HexAssert(HexColorUtil::isValidColor(color)); 00355 if (color == EMPTY) return GetEmpty(); 00356 return m_stones[color] & Const().GetLocations(); 00357 } 00358 00359 inline bitset_t StoneBoard::GetEmpty() const 00360 { 00361 return Const().GetLocations() - GetOccupied(); 00362 } 00363 00364 inline bitset_t StoneBoard::GetOccupied() const 00365 { 00366 return (GetBlack() | GetWhite()) & Const().GetLocations(); 00367 } 00368 00369 inline bool StoneBoard::IsBlack(HexPoint cell) const 00370 { 00371 HexAssert(Const().IsValid(cell)); 00372 return m_stones[BLACK].test(cell); 00373 } 00374 00375 inline bool StoneBoard::IsWhite(HexPoint cell) const 00376 { 00377 HexAssert(Const().IsValid(cell)); 00378 return m_stones[WHITE].test(cell); 00379 } 00380 00381 inline bool StoneBoard::IsColor(HexPoint cell, HexColor color) const 00382 { 00383 HexAssert(HexColorUtil::isBlackWhite(color)); 00384 HexAssert(Const().IsLocation(cell)); 00385 return m_stones[color].test(cell); 00386 } 00387 00388 inline bool StoneBoard::IsEmpty(HexPoint cell) const 00389 { 00390 HexAssert(Const().IsLocation(cell)); 00391 return !IsOccupied(cell); 00392 } 00393 00394 inline bool StoneBoard::IsOccupied(HexPoint cell) const 00395 { 00396 HexAssert(Const().IsLocation(cell)); 00397 return (IsBlack(cell) || IsWhite(cell)); 00398 } 00399 00400 inline bitset_t StoneBoard::GetPlayed() const 00401 { 00402 return m_played; 00403 } 00404 00405 inline bitset_t StoneBoard::GetPlayed(HexColor color) const 00406 { 00407 HexAssert(HexColorUtil::isBlackWhite(color)); 00408 return m_played & GetColor(color); 00409 } 00410 00411 inline bool StoneBoard::IsPlayed(HexPoint cell) const 00412 { 00413 HexAssert(Const().IsValid(cell)); 00414 return m_played.test(cell); 00415 } 00416 00417 inline std::size_t StoneBoard::NumStones() const 00418 { 00419 return (GetOccupied() & GetPlayed() & Const().GetCells()).count(); 00420 } 00421 00422 inline bool StoneBoard::operator==(const StoneBoard& other) const 00423 { 00424 return (m_const == other.m_const 00425 && m_stones[BLACK] == other.m_stones[BLACK] 00426 && m_stones[WHITE] == other.m_stones[WHITE] 00427 && m_played == other.m_played); 00428 } 00429 00430 inline bool StoneBoard::operator!=(const StoneBoard& other) const 00431 { 00432 return !(operator==(other)); 00433 } 00434 00435 inline HexColor StoneBoard::WhoseTurn() const 00436 { 00437 HexAssert(IsStandardPosition()); 00438 bitset_t mask = GetPlayed() & Const().GetCells(); 00439 std::size_t first = (GetColor(FIRST_TO_PLAY) & mask).count(); 00440 std::size_t second = (GetColor(!FIRST_TO_PLAY) & mask).count(); 00441 return (first > second) ? !FIRST_TO_PLAY : FIRST_TO_PLAY; 00442 } 00443 00444 inline bool StoneBoard::IsStandardPosition() const 00445 { 00446 std::size_t diff = GetPlayed(BLACK).count() - GetPlayed(WHITE).count(); 00447 return (diff == 1) || (diff == 0); 00448 } 00449 00450 inline BoardIterator StoneBoard::Stones(HexColor color) const 00451 { 00452 return Stones(HexColorSetUtil::Only(color)); 00453 } 00454 00455 /** Prints board to output stream. */ 00456 inline std::ostream& operator<<(std::ostream &os, const StoneBoard& b) 00457 { 00458 os << b.Write(); 00459 return os; 00460 } 00461 00462 //---------------------------------------------------------------------------- 00463 00464 _END_BENZENE_NAMESPACE_ 00465 00466 #endif // STONEBOARD_HPP