Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

StoneBoard.hpp

Go to the documentation of this file.
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


6 Jan 2011 Doxygen 1.6.3