Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoBoard.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoBoard.h
00003     Go board with basic board and blocks.
00004 
00005     GoBoard defines a Go board that implements the rules of Go and provides
00006     a lot of helper functions to get blocks, liberties, adjacent blocks,
00007     and so on.
00008 */
00009 //----------------------------------------------------------------------------
00010 
00011 #ifndef GO_BOARD_H
00012 #define GO_BOARD_H
00013 
00014 #include <bitset>
00015 #include <cstring>
00016 #include <stdint.h>
00017 #include <boost/static_assert.hpp>
00018 #include "GoPlayerMove.h"
00019 #include "GoRules.h"
00020 #include "GoSetup.h"
00021 #include "SgArray.h"
00022 #include "SgBoardConst.h"
00023 #include "SgBoardColor.h"
00024 #include "SgMarker.h"
00025 #include "SgBWArray.h"
00026 #include "SgBWSet.h"
00027 #include "SgHash.h"
00028 #include "SgNbIterator.h"
00029 #include "SgPoint.h"
00030 #include "SgPointArray.h"
00031 #include "SgPointIterator.h"
00032 #include "SgPointSet.h"
00033 #include "SgSList.h"
00034 
00035 //----------------------------------------------------------------------------
00036 
00037 /** Board size to choose at startup. */
00038 const int GO_DEFAULT_SIZE = (SG_MAX_SIZE >= 19 ? 19 : SG_MAX_SIZE);
00039 
00040 /** Maximum number of moves in game.
00041     HEURISTIC: Longest possible game.
00042 */
00043 const int GO_MAX_NUM_MOVES = (3 * SG_MAX_SIZE * SG_MAX_SIZE);
00044 
00045 //----------------------------------------------------------------------------
00046 
00047 /** Flags for moves. */
00048 enum GoMoveInfoFlag
00049 {
00050     /** The move was a repetition move. */
00051     GO_MOVEFLAG_REPETITION,
00052 
00053     /** The move caused self-removal of stones. */
00054     GO_MOVEFLAG_SUICIDE,
00055 
00056     /** The move captured one or more enemy stones. */
00057     GO_MOVEFLAG_CAPTURING,
00058 
00059     /** The move was illegal according to the current rules and allow ko
00060         settings.
00061     */
00062     GO_MOVEFLAG_ILLEGAL,
00063 
00064     _GO_NU_MOVEFLAG
00065 };
00066 
00067 typedef std::bitset<_GO_NU_MOVEFLAG> GoMoveInfo;
00068 
00069 //----------------------------------------------------------------------------
00070 
00071 /** Static list having enough room for all points on board and SG_PASS. */
00072 typedef SgSList<SgPoint,SG_MAX_ONBOARD + 1> GoPointList;
00073 
00074 /** Static list having enough room for longest move sequence supported by
00075     GoBoard.
00076 */
00077 typedef SgSList<SgPoint,GO_MAX_NUM_MOVES> GoSequence;
00078 
00079 //----------------------------------------------------------------------------
00080 
00081 /** Go board.
00082     It maintains the state of each point when playing moves and taking them
00083     back. Setup stones are only supported in the initial position.
00084     It provides basic information about the board state, e.g. blocks and
00085     liberties.
00086     The actual storage representation and updating of stones and liberties is
00087     encapsulated, it can only be accessed with GoBoard::LibertyIterator,
00088     GoBoard::LibertyCopyIterator, and GoBoard::StoneIterator.
00089 
00090     Boards are thread-safe (w.r.t. different instances) after construction
00091     (the constructor is not thread-safe, because it uses global variables
00092     via SgBoardConst).
00093 
00094     @see
00095     - @ref goboardko
00096     - @ref goboardhash
00097 */
00098 class GoBoard
00099 {
00100 public:
00101     /** Maximum number of immediate ko recaptures for GoBoard::m_koColor.
00102         Enforced only if ko modifies hash
00103         @see KoModifiesHash()
00104     */
00105     static const int MAX_KOLEVEL = 3;
00106 
00107     /** Marker that can be used in client code.
00108         This marker is never used by this class, it is intended for external
00109         functions that operate on the board and can profit from the fast clear
00110         operation of SgMarker (if reused), but cannot store its own
00111         marker (or don't want to use a global variable for thread-safety).
00112         Since only one function can use this marker at a time, you should
00113         assert with SgReserveMarker that the marker is not used in a
00114         conflicting way.
00115     */
00116     mutable SgMarker m_userMarker;
00117 
00118     explicit GoBoard(int size = GO_DEFAULT_SIZE,
00119                      const GoSetup& setup = GoSetup(),
00120                      const GoRules& rules = GoRules());
00121 
00122     ~GoBoard();
00123 
00124     const SgBoardConst& BoardConst() const;
00125 
00126     /** Number of calls to Play since creation of this board. */
00127     uint64_t CountPlay() const;
00128 
00129     /** Re-initializes the board with new size.
00130         Keeps old GoRules.
00131     */
00132     void Init(int size, const GoSetup& setup = GoSetup());
00133 
00134     /** Re-initializes the board with new size and rules. */
00135     void Init(int size, const GoRules& rules,
00136               const GoSetup& setup = GoSetup());
00137 
00138     /** Non-const access to current game rules.
00139         The game rules are attached to a GoBoard for convenient access
00140         by the players only.
00141         The players and the class GoBoard should not assume that they are
00142         immutable; they can be changed from the outside using this function at
00143         anytime.
00144     */
00145     GoRules& Rules();
00146 
00147     /** Current game rules. */
00148     const GoRules& Rules() const;
00149 
00150     /** Return the size of this board. */
00151     SgGrid Size() const;
00152 
00153     /** Check if sufficient space on internal stacks.
00154         Should be checked before executing a move.
00155         If the internal stacks overflow, assertions will (hopefully)
00156         trigger in debug mode, but undefined behaviour occurs in release mode.
00157     */
00158     bool StackOverflowLikely() const;
00159 
00160     /** Check if move at point would be the first move there. */
00161     bool IsFirst(SgPoint p) const;
00162 
00163     /** Check if board is in a definitely new situation,
00164         with no possibility of repetition */
00165     bool IsNewPosition() const;
00166 
00167     /** Check if point is occupied by a stone.
00168         Can be called with border points.
00169     */
00170     bool Occupied(SgPoint p) const;
00171 
00172     bool IsEmpty(SgPoint p) const;
00173 
00174     bool IsBorder(SgPoint p) const;
00175 
00176     bool IsColor(SgPoint p, int c) const;
00177 
00178     SgBoardColor GetColor(SgPoint p) const;
00179 
00180     SgBlackWhite GetStone(SgPoint p) const;
00181 
00182     /** %Player whose turn it is to play. */
00183     SgBlackWhite ToPlay() const;
00184 
00185     /** Opponent of player whose turn it is to play. */
00186     SgBlackWhite Opponent() const;
00187 
00188     /** Set the current player. */
00189     void SetToPlay(SgBlackWhite player);
00190 
00191     /** See SgBoardConst::Line */
00192     SgGrid Line(SgPoint p) const;
00193 
00194     /** See SgBoardConst::Pos */
00195     SgGrid Pos(SgPoint p) const;
00196 
00197     /** Returns the offset to the point on the line above this point.
00198         Returns zero for points outside the board, and for the center
00199         point(s).
00200     */
00201     int Up(SgPoint p) const;
00202 
00203     /** Returns the offset along left side of the board.
00204         Left and right are as seen from the edge toward the center of the
00205         board.
00206         Returns zero for the same points as Up does.
00207     */
00208     int Left(SgPoint p) const;
00209 
00210     /** Returns the offset along right side of the board.
00211         @see Left for more info.
00212     */
00213     int Right(SgPoint p) const;
00214 
00215     /** Same as Left/Right, but the side is passed in as an index (0 or 1). */
00216     int Side(SgPoint p, int index) const;
00217 
00218     bool IsSuicide(SgPoint p, SgBlackWhite toPlay) const;
00219 
00220     bool IsValidPoint(SgPoint p) const;
00221 
00222     bool HasEmptyNeighbors(SgPoint p) const;
00223 
00224     int NumEmptyNeighbors(SgPoint p) const;
00225 
00226     /** Includes diagonals. */
00227     int Num8EmptyNeighbors(SgPoint p) const;
00228 
00229     bool HasNeighbors(SgPoint p, SgBlackWhite c) const;
00230 
00231     int NumNeighbors(SgPoint p, SgBlackWhite c) const;
00232 
00233     /** Includes diagonals. */
00234     int Num8Neighbors(SgPoint p, SgBlackWhite c) const;
00235 
00236     bool HasDiagonals(SgPoint p, SgBoardColor c) const;
00237 
00238     int NumDiagonals(SgPoint p, SgBoardColor c) const;
00239 
00240     int NumEmptyDiagonals(SgPoint p) const;
00241 
00242     bool HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const;
00243 
00244     /** @name Point sets */
00245     //@{
00246 
00247     SgPointSet Occupied() const;
00248 
00249     const SgPointSet& All(SgBlackWhite color) const;
00250 
00251     const SgPointSet& AllEmpty() const;
00252 
00253     const SgPointSet& AllPoints() const;
00254 
00255     /** See SgBoardConst::Corners */
00256     const SgPointSet& Corners() const;
00257 
00258     /** See SgBoardConst::Edges */
00259     const SgPointSet& Edges() const;
00260 
00261     /** See SgBoardConst::Centers */
00262     const SgPointSet& Centers() const;
00263 
00264     /** See SgBoardConst::SideExtensions */
00265     const SgPointSet& SideExtensions() const;
00266 
00267     /** See SgBoardConst::LineSet */
00268     const SgPointSet& LineSet(SgGrid line) const;
00269 
00270     //@}
00271 
00272     bool InCorner(SgPoint p) const;
00273 
00274     bool OnEdge(SgPoint p) const;
00275 
00276     bool InCenter(SgPoint p) const;
00277 
00278     /** See SgBoardConst::FirstBoardPoint */
00279     int FirstBoardPoint() const;
00280 
00281     /** See SgBoardConst::FirstBoardPoint */
00282     int LastBoardPoint() const;
00283 
00284     /** Information about the most recent call to Play.
00285         Guaranteed to be valid only directly after a call to Play.
00286         @see GoMoveInfoFlag
00287     */
00288     bool LastMoveInfo(GoMoveInfoFlag flag) const;
00289 
00290     GoMoveInfo GetLastMoveInfo() const;
00291 
00292     void AllowKoRepetition(bool allowKo);
00293 
00294     /** Make all repetition moves legal.
00295         @see @ref goboardko
00296     */
00297     void AllowAnyRepetition(bool allowAny);
00298 
00299     /** Enable modification of hash code by Ko moves.
00300         Can be used if Ko repetition is allowed.
00301         @warning You have to disable it in the same position, where it was
00302         enabled, otherwise the incremental update of the hash code does not
00303         work; use KoHashModifier in GoBoardUtil to do this automatically.
00304     */
00305     void SetKoModifiesHash(bool modify);
00306 
00307     bool KoRepetitionAllowed() const;
00308 
00309     /** Are all repetition moves legal?
00310         @see @ref goboardko
00311     */
00312     bool AnyRepetitionAllowed() const;
00313 
00314     bool KoModifiesHash() const;
00315 
00316     /** Play a move.
00317         Move needs to be SG_PASS or on-board empty point.
00318         If move is not legal according to the current GoRules, the
00319         move flag isIllegal will be set.
00320         After playing the color to play ys the opposite color of the color
00321         of the move.
00322     */
00323     void Play(SgPoint p, SgBlackWhite player);
00324 
00325     /** Play a move for the current player.
00326         @see Play(SgPoint,SgBlackWhite);
00327     */
00328     void Play(SgPoint p);
00329 
00330     /** Play a move.
00331         @see Play(SgPoint,SgBlackWhite);
00332     */
00333     void Play(GoPlayerMove move);
00334 
00335     /** Undo the most recent move. */
00336     void Undo();
00337 
00338     /** Whether there is any move to undo. */
00339     bool CanUndo() const;
00340 
00341     /** Check whether the move at 'p' is legal.
00342         Since it's not clear how 'p' was arrived at, any value of 'p' is
00343         admissible, even out of point range and on border points; just return
00344         false on such input.
00345         LastMoveInfo is guaranteed to be vaild after this call.
00346         Suicide moves are only legal, if SetSelfRemovalAllowed(true) was
00347         called.
00348     */
00349     bool IsLegal(int p, SgBlackWhite player) const;
00350 
00351     /** Check whether the move at 'p' is legal for color to play.
00352         @see IsLegal(int, SgBlackWhite).
00353     */
00354     bool IsLegal(int p) const;
00355 
00356     bool IsSuicide(SgPoint p) const;
00357 
00358     /** Whether the most recent move captured any stones. */
00359     bool CapturingMove() const;
00360 
00361     /** The stones removed from the board by the most recent move.
00362         Can be used for incremental update of other data structures.
00363         Includes captures and suicide stones.
00364         Only valid directly after a GoBoard::Play, otherwise undefined.
00365     */
00366     const GoPointList& CapturedStones() const;
00367 
00368     /** The stones captured by the most recent move.
00369         @see CapturedStones
00370     */
00371     int NuCapturedStones() const;
00372 
00373     /** The total number of stones of 'color' that have been
00374         captured by the opponent throughout the game. */
00375     int NumPrisoners(SgBlackWhite color) const;
00376 
00377     /** Setup information of the first position. */
00378     const GoSetup& Setup() const;
00379 
00380     /** Return the current number moves. */
00381     int MoveNumber() const;
00382 
00383     /** Return move with a certain move number.
00384         @param i The move number (starting with 0).
00385         @return The ith move.
00386      */
00387     GoPlayerMove Move(int i) const;
00388 
00389     /** Return last move played.
00390         @return The last move played or SG_NULLMOVE, if
00391         - No move was played yet
00392         - The last move was not by the opposite color of the current player
00393     */
00394     SgPoint GetLastMove() const;
00395 
00396     /** 2nd Last move = last move by ToPlay().
00397         Conditions similar to GetLastMove().
00398     */
00399     SgPoint Get2ndLastMove() const;
00400 
00401     /** Point which is currently illegal due to simple ko rule.
00402         Note that there could be more points illegal if superko rules
00403         are used.
00404         @return The ko point or SG_NULLPOINT, if none exists.
00405     */
00406     SgPoint KoPoint() const;
00407 
00408     /** Return hash code for this position.
00409         @warning Hash code for empty positions is always 0, independent of
00410         the board size.
00411     */
00412     const SgHashCode& GetHashCode() const;
00413 
00414     /** Return hash code for this position, modified by whose turn it
00415         is to play.
00416         Note that GetHashCode() != GetHashCodeInclToPlay(), regardless
00417         of whose turn it is to play.
00418     */
00419     SgHashCode GetHashCodeInclToPlay() const;
00420 
00421     /** Return the number of stones in the block at 'p'.
00422         Not defined for empty or border points.
00423     */
00424     int NumStones(SgPoint p) const;
00425 
00426     /** Return NumStones(p) == 1. */
00427     bool IsSingleStone(SgPoint p) const;
00428 
00429     /** Return whether the two stones are located in the same block.
00430         Return false if one of the stones is an empty or border point.
00431     */
00432     bool AreInSameBlock(SgPoint stone1, SgPoint stone2) const;
00433 
00434     /** Return the smallest point of the block at a point.
00435         Requires: Occupied(p) <br>
00436     */
00437     SgPoint Anchor(SgPoint p) const;
00438 
00439     /** Efficient combined test if point is occupied and belongs to a block.
00440         @return true, if point is occupied and belongs to the block with
00441         the given anchor.
00442     */
00443     bool IsInBlock(SgPoint p, SgPoint anchor) const;
00444 
00445     /** Check if empty point is a liberty of block.
00446         @param p The point the check.
00447         @param anchor The anchor of the block.
00448         @return true If point is liberty of block.
00449     */
00450     bool IsLibertyOfBlock(SgPoint p, SgPoint anchor) const;
00451 
00452     /** Get adjacent opponent blocks with a maximum number of liberties for a
00453         given block.
00454         Not defined for empty points.
00455         @param p The block to check.
00456         @param maxLib The maximum number of liberties of the neighbors.
00457         @param anchors Resulting neighbor anchors and an additional END_POINT.
00458         @param maxAnchors Array size of anchors (for detecting overflow in
00459         debug mode)
00460         @return Number of anchors (without the END_POINT)
00461     */
00462     int AdjacentBlocks(SgPoint p, int maxLib, SgPoint anchors[],
00463                        int maxAnchors) const;
00464 
00465     /** %List anchor of each block of color 'c' adjacent to the
00466         empty point 'p'.
00467         Assert if 'p' is not empty.
00468         Fill an array of points, terminated by END_POINT.
00469     */
00470     void NeighborBlocks(SgPoint p, SgBlackWhite c, SgPoint anchors[]) const;
00471 
00472     /** %List anchor of each block of color 'c' with at most 'maxLib'
00473         liberties adjacent to the empty point 'p'.
00474         Assert if 'p' is not empty.
00475         Fill an array of points, terminated by END_POINT.
00476     */
00477     void NeighborBlocks(SgPoint p, SgBlackWhite c, int maxLib,
00478                         SgPoint anchors[]) const;
00479 
00480     /** Number of stones currently on the board. */
00481     const SgBWArray<int>& TotalNumStones() const;
00482 
00483     int TotalNumStones(SgBlackWhite color) const;
00484 
00485     /** Number of empty points currently on the board. */
00486     int TotalNumEmpty() const;
00487 
00488     /** Return the liberty of 'blockInAtari' which must have exactly
00489         one liberty.
00490     */
00491     SgPoint TheLiberty(SgPoint blockInAtari) const;
00492 
00493     /** Return the number of liberties of the block at 'p'.
00494         Not defined for empty or border points.
00495     */
00496     int NumLiberties(SgPoint p) const;
00497 
00498     /** Return whether block has at most n liberties. */
00499     bool AtMostNumLibs(SgPoint block, int n) const;
00500 
00501     /** Return whether block has at least n liberties. */
00502     bool AtLeastNumLibs(SgPoint block, int n) const;
00503 
00504     /** Return whether the number of liberties of the block at 'p' is one.
00505         Requires: Occupied(p)
00506     */
00507     bool InAtari(SgPoint p) const;
00508 
00509     /** Check if point is occupied and in atari.
00510         Faster than Occupied(p) || InAtari(p).
00511         May be called for border points.
00512     */
00513     bool OccupiedInAtari(SgPoint p) const;
00514 
00515     /** Return whether playing colour c at p can capture anything,
00516         ignoring any possible repetition.
00517     */
00518     bool CanCapture(SgPoint p, SgBlackWhite c) const;
00519 
00520     /** %Player who has immediately retaken a ko.
00521         It is SG_EMPTY if no player has done it.
00522     */
00523     SgEmptyBlackWhite KoColor() const;
00524 
00525     /** Number of times that KoColor has immediately retaken a ko. */
00526     int KoLevel() const;
00527 
00528     /** %Player who will lose any ko.
00529         KoLoser is a player who is a priori determined to lose ko fights.
00530         therefore he is never allowed to become 'KoColor'
00531         If KoLoser is empty, no such prior bias is assumed.
00532     */
00533     SgEmptyBlackWhite KoLoser() const;
00534 
00535     /** See KoLoser. */
00536     void SetKoLoser(SgEmptyBlackWhite color);
00537 
00538     /** Checks whether all the board data structures are in a consistent
00539         state.
00540     */
00541     void CheckConsistency() const;
00542 
00543     /** Remember current position for quickly undoing a sequence of moves.
00544         Note that for short sequences of moves this can take longer than
00545         incrementally restoring the state by multiple calls to Undo().
00546     */
00547     void TakeSnapshot();
00548 
00549     /** Restore a snapshot.
00550         Can only be called, if previously TakeSnapshot() was called and
00551         the current position is a followup position of the snapshot position.
00552         RestoreSnapshot() can used multiple times for the same snapshot.
00553         @see TakeSnapshot()
00554     */
00555     void RestoreSnapshot();
00556 
00557 private:
00558     /** Data related to a block of stones on the board. */
00559     class Block
00560     {
00561     public:
00562         /** Upper limit for liberties.
00563             Proof?
00564         */
00565         static const int MAX_LIBERTIES = (SG_MAX_SIZE / 3) * 2 * SG_MAX_SIZE;
00566 
00567         typedef SgSList<SgPoint,MAX_LIBERTIES> LibertyList;
00568 
00569         typedef LibertyList::Iterator LibertyIterator;
00570 
00571         typedef GoPointList::Iterator StoneIterator;
00572 
00573         SgPoint Anchor() const { return m_anchor; }
00574 
00575         void UpdateAnchor(SgPoint p) { if (p < m_anchor) m_anchor = p; }
00576 
00577         void AppendLiberty(SgPoint p) { m_liberties.PushBack(p); }
00578 
00579         void AppendStone(SgPoint p) { m_stones.PushBack(p); }
00580 
00581         SgBlackWhite Color() const { return m_color; }
00582 
00583         void ExcludeLiberty(SgPoint p) { m_liberties.Exclude(p); }
00584 
00585         void Init(SgBlackWhite c, SgPoint anchor)
00586         {
00587             SG_ASSERT_BW(c);
00588             m_color = c;
00589             m_anchor = anchor;
00590             m_stones.SetTo(anchor);
00591             m_liberties.Clear();
00592         }
00593 
00594         void Init(SgBlackWhite c, SgPoint anchor, GoPointList stones,
00595                   LibertyList liberties)
00596         {
00597             SG_ASSERT_BW(c);
00598             SG_ASSERT(stones.Contains(anchor));
00599             m_color = c;
00600             m_anchor = anchor;
00601             m_stones = stones;
00602             m_liberties = liberties;
00603         }
00604 
00605         const LibertyList& Liberties() const { return m_liberties; }
00606 
00607         int NumLiberties() const { return m_liberties.Length(); }
00608 
00609         int NumStones() const { return m_stones.Length(); }
00610 
00611         void PopStone() { m_stones.PopBack(); }
00612 
00613         void SetAnchor(SgPoint p) { m_anchor = p; }
00614 
00615         const GoPointList& Stones() const { return m_stones; }
00616 
00617     private:
00618         SgPoint m_anchor;
00619 
00620         SgBlackWhite m_color;
00621 
00622         LibertyList m_liberties;
00623 
00624         GoPointList m_stones;
00625     };
00626 
00627     /** Board hash code.
00628         @see @ref goboardhash
00629     */
00630     class HashCode
00631     {
00632     public:
00633         void Clear();
00634 
00635         const SgHashCode& Get() const;
00636 
00637         SgHashCode GetInclToPlay(SgBlackWhite toPlay) const;
00638 
00639         void XorCaptured(int moveNumber, SgPoint firstCapturedStone);
00640 
00641         void XorStone(SgPoint p, SgBlackWhite c);
00642 
00643         void XorWinKo(int level, SgBlackWhite c);
00644 
00645     private:
00646         // Index ranges used in global Zobrist table
00647         static const int START_INDEX_TOPLAY = 1;
00648         static const int END_INDEX_TOPLAY = 2;
00649         static const int START_INDEX_STONES = 3;
00650         static const int END_INDEX_STONES = 2 * SG_MAXPOINT;
00651         static const int START_INDEX_WINKO = 2 * SG_MAXPOINT + 1;
00652         static const int END_INDEX_WINKO = 2 * SG_MAXPOINT + SG_MAX_SIZE + 1;
00653         static const int START_INDEX_CAPTURES
00654         = 2 * SG_MAXPOINT + SG_MAX_SIZE + 2;
00655         static const int END_INDEX_CAPTURES = 3 * SG_MAXPOINT + 63;
00656 
00657         // Certain values for SG_MAX_SIZE and WIN_KO_LEVEL can break the
00658         // assumption that the above ranges don't overlap
00659         BOOST_STATIC_ASSERT(START_INDEX_TOPLAY >= 0);
00660         BOOST_STATIC_ASSERT(END_INDEX_TOPLAY > START_INDEX_TOPLAY);
00661         BOOST_STATIC_ASSERT(START_INDEX_STONES > END_INDEX_TOPLAY);
00662         BOOST_STATIC_ASSERT(END_INDEX_STONES > START_INDEX_STONES);
00663         BOOST_STATIC_ASSERT(END_INDEX_WINKO > START_INDEX_WINKO);
00664         BOOST_STATIC_ASSERT(START_INDEX_CAPTURES > END_INDEX_WINKO);
00665         BOOST_STATIC_ASSERT(END_INDEX_CAPTURES > START_INDEX_CAPTURES);
00666         BOOST_STATIC_ASSERT(START_INDEX_WINKO + MAX_KOLEVEL * 3 - 1
00667                             <= END_INDEX_WINKO);
00668         BOOST_STATIC_ASSERT(END_INDEX_CAPTURES
00669                         < SgHashZobristTable::MAX_HASH_INDEX);
00670 
00671         SgHashCode m_hash;
00672     };
00673 
00674     /** Information to undo a move.
00675         Holds information necessary to undo a play.
00676     */
00677     struct StackEntry
00678     {
00679         /** Color of the move. */
00680         SgBlackWhite m_color;
00681 
00682         /** Location of the move. */
00683         SgPoint m_point;
00684 
00685         /** Old value of m_isFirst[m_point].
00686             Only defined if m_point is not SG_PASS
00687         */
00688         bool m_isFirst;
00689 
00690         /** Old value of m_isNewPosition */
00691         bool m_isNewPosition;
00692 
00693         Block* m_stoneAddedTo;
00694 
00695         /** @name Only defined if m_stoneAddedTo != 0 */
00696         //@{
00697 
00698         SgPoint m_oldAnchor;
00699 
00700         SgSList<SgPoint,4> m_newLibs;
00701 
00702         SgSList<Block*,4> m_merged;
00703 
00704         //@}
00705 
00706         /** @name Only defined if m_type == PLAY */
00707         //@{
00708 
00709         /** Old value of m_toPlay */
00710         SgBlackWhite m_toPlay;
00711 
00712         /** Old value of m_hash */
00713         HashCode m_hash;
00714 
00715         /** Old value of m_koPoint */
00716         SgPoint m_koPoint;
00717 
00718         /** Old value of m_koLevel */
00719         int m_koLevel;
00720 
00721         /** Old value of m_koColor */
00722         SgEmptyBlackWhite m_koColor;
00723 
00724         /** Old value of m_koLoser */
00725         SgEmptyBlackWhite m_koLoser;
00726 
00727         /** Old value of m_koModifiesHash */
00728         bool m_koModifiesHash;
00729 
00730         Block* m_suicide;
00731 
00732         SgSList<Block*,4> m_killed;
00733         //@}
00734     };
00735 
00736     /** Data that can be restored quickly with TakeSnapshot/RestoreSnapshot.
00737         Corresponds to the current state, excluding block data (which is
00738         stored in the stack m_blockList), data, which is only defined
00739         immediately after a function call, ot data, which is not expected
00740         to change during a TakeSnapshot/RestoreSnapshot (e.g. rules)
00741     */
00742     struct State
00743     {
00744         /** Point which is currently illegal for simple Ko rule. */
00745         SgPoint m_koPoint;
00746 
00747         /** Whose turn it is to play. */
00748         SgBlackWhite m_toPlay;
00749 
00750         /** Hash code for this board position. */
00751         HashCode m_hash;
00752 
00753         SgBWSet m_all;
00754 
00755         SgPointSet m_empty;
00756 
00757         SgArray<Block*,SG_MAXPOINT> m_block;
00758 
00759         /** Number of prisoners of each color */
00760         SgBWArray<int> m_prisoners;
00761 
00762         /** Number of stones currently on the board. */
00763         SgBWArray<int> m_numStones;
00764 
00765         /** Number of 'illegal' ko recaptures by m_koColor. */
00766         int m_koLevel;
00767 
00768         /** The current board position. */
00769         SgArray<int,SG_MAXPOINT> m_color;
00770 
00771         /** Number of black and white neighbors. */
00772         SgArray<int,SG_MAXPOINT> m_nuNeighborsEmpty;
00773 
00774         /** Number of black and white neighbors. */
00775         SgBWArray<SgArray<int,SG_MAXPOINT> > m_nuNeighbors;
00776 
00777         /** Flag if point has not been modified yet. */
00778         SgArray<bool,SG_MAXPOINT> m_isFirst;
00779 
00780         /** Flag if position is definitely new (no possibility of repetition),
00781             set to true when move is played at any point for the first time,
00782             and set to false at the next capture. */
00783         bool m_isNewPosition;
00784     };
00785 
00786     struct Snapshot
00787     {
00788         /** Move number; -1, if no snapshot was made. */
00789         int m_moveNumber;
00790 
00791         int m_blockListSize;
00792 
00793         State m_state;
00794 
00795         /** State of blocks currently on the board. */
00796         SgPointArray<Block> m_blockArray;
00797     };
00798 
00799     State m_state;
00800 
00801     std::auto_ptr<Snapshot> m_snapshot;
00802 
00803     /** See CountPlay */
00804     uint64_t m_countPlay;
00805 
00806     /** Data that's constant for this board size. */
00807     SgBoardConst m_const;
00808 
00809     /** The current board size. */
00810     SgGrid m_size;
00811 
00812     /** Rules for this board.
00813         Can be modified anytime with GoBoard::Rules()
00814     */
00815     GoRules m_rules;
00816 
00817     /** Setup stones in the root position. */
00818     GoSetup m_setup;
00819 
00820     GoMoveInfo m_moveInfo;
00821 
00822     /** Block data (stored in a stack).
00823         Maximum number: A move can create zero or one new block.
00824     */
00825     SgSList<Block,GO_MAX_NUM_MOVES>* m_blockList;
00826 
00827     // The following members are mutable since they're used while computing
00828     // stones and liberties, but are either restored to their previous setting
00829     // (stack), or don't matter to the client (marks).
00830 
00831     mutable SgMarker m_marker;
00832 
00833     GoPointList m_capturedStones;
00834 
00835     /** Arbitrary repetition for both players. */
00836     bool m_allowAnyRepetition;
00837 
00838     /** Allow take-back of ko repetition. */
00839     bool m_allowKoRepetition;
00840 
00841     bool m_koModifiesHash;
00842 
00843     SgEmptyBlackWhite m_koColor;
00844 
00845     /** m_koLoser can never become m_koColor. */
00846     SgEmptyBlackWhite m_koLoser;
00847 
00848     SgArray<bool,SG_MAXPOINT> m_isBorder;
00849 
00850     SgSList<StackEntry,GO_MAX_NUM_MOVES>* m_moves;
00851 
00852     static bool IsPass(SgPoint p);
00853 
00854     /** Not implemented. */
00855     GoBoard(const GoBoard&);
00856 
00857     /** Not implemented. */
00858     GoBoard& operator=(const GoBoard&);
00859 
00860     /** Check if move violates Ko rule.
00861         Sets isRepetition and updates m_koLevel, m_koColor and hash
00862         (if KoModifiesHash)
00863         @return false if isRepetition
00864     */
00865     bool CheckKo(SgBlackWhite player);
00866 
00867     void AddLibToAdjBlocks(SgPoint p);
00868 
00869     void AddLibToAdjBlocks(SgPoint p, SgBlackWhite c);
00870 
00871     void AddStoneToBlock(SgPoint p, SgBlackWhite c, Block* block,
00872                          StackEntry& entry);
00873 
00874     Block& CreateNewBlock();
00875 
00876     void CreateSingleStoneBlock(SgPoint p, SgBlackWhite c);
00877 
00878     SgSList<Block*,4> GetAdjacentBlocks(SgPoint p) const;
00879 
00880     SgSList<Block*,4> GetAdjacentBlocks(SgPoint p, SgBlackWhite c) const;
00881 
00882     void InitBlock(GoBoard::Block& block, SgBlackWhite c, SgPoint anchor);
00883 
00884     bool IsAdjacentTo(SgPoint p, const Block* block) const;
00885 
00886     void MergeBlocks(SgPoint p, SgBlackWhite c,
00887                      const SgSList<Block*,4>& adjBlocks);
00888 
00889     void RemoveLibAndKill(SgPoint p, SgBlackWhite opp, StackEntry& entry);
00890 
00891     void RemoveLibFromAdjBlocks(SgPoint p, SgBlackWhite c);
00892 
00893     void RestoreKill(Block* block, SgBlackWhite c);
00894 
00895     void UpdateBlocksAfterAddStone(SgPoint p, SgBlackWhite c,
00896                                    StackEntry& entry);
00897 
00898     void UpdateBlocksAfterUndo(const StackEntry& entry);
00899 
00900     void CheckConsistencyBlock(SgPoint p) const;
00901 
00902     bool FullBoardRepetition() const;
00903 
00904     /** Kill own block if no liberties.
00905         Sets isSuicide flag.
00906         @return false if move was suicide and suicide not allowed by current
00907         rules
00908     */
00909     bool CheckSuicide(SgPoint p, StackEntry& entry);
00910 
00911     void AddStone(SgPoint p, SgBlackWhite c);
00912 
00913     void RemoveStone(SgPoint p);
00914 
00915     void AddStoneForUndo(SgPoint p, SgBlackWhite c);
00916 
00917     void RemoveStoneForUndo(SgPoint p);
00918 
00919     void KillBlock(const Block* block);
00920 
00921     bool HasLiberties(SgPoint p) const;
00922 
00923     /** Restore state. */
00924     void RestoreState(const StackEntry& entry);
00925 
00926     /** Save state.
00927         @param entry The stack entry to save information to; must already
00928         have a valid m_type field.
00929     */
00930     void SaveState(StackEntry& entry);
00931 
00932     friend class LibertyCopyIterator;
00933     friend class LibertyIterator;
00934     friend class StoneIterator;
00935 
00936 public:
00937     /** Iterate through all the stones of a block.
00938         Point 'p' must be occupied.
00939         Also, the stones can only be accessed for the current board position.
00940     */
00941     class StoneIterator
00942     {
00943     public:
00944         StoneIterator(const GoBoard& bd, SgPoint p);
00945 
00946         /** Advance the state of the iteration to the next stone. */
00947         void operator++();
00948 
00949         /** Return the current stone. */
00950         SgPoint operator*() const;
00951 
00952         /** Return true if iteration is valid, otherwise false. */
00953         operator bool() const;
00954 
00955     private:
00956         /** Iterator over original list in GoBoard::Block::StoneList.
00957             No copy of list is necessary, even if moves are played and undone
00958             while iterating over the list, since the implementation of GoBoard
00959             does guarantee that the order of the block's stone list is
00960             preserved.
00961         */
00962         GoBoard::Block::StoneIterator m_it;
00963 
00964         const GoBoard& m_board;
00965 
00966 #ifndef NDEBUG
00967         uint64_t m_countPlay;
00968 #endif
00969 
00970         /** Not implemented. */
00971         StoneIterator(const StoneIterator&);
00972 
00973         /** Not implemented. */
00974         StoneIterator& operator=(const StoneIterator&);
00975     };
00976 
00977     /** Iterate through all points. */
00978     class Iterator
00979         : public SgPointRangeIterator
00980     {
00981     public:
00982         Iterator(const GoBoard& bd);
00983     };
00984 
00985     /** Iterate through all the liberties of a block.
00986         Point 'p' must be occupied.
00987         Liberties should only be accessed for the current board position.
00988         No moves are allowed to be executed during the iteration.
00989     */
00990     class LibertyIterator
00991     {
00992     public:
00993         LibertyIterator(const GoBoard& bd, SgPoint p);
00994 
00995         /** Advance the state of the iteration to the next liberty. */
00996         void operator++();
00997 
00998         /** Return the current liberty. */
00999         SgPoint operator*() const;
01000 
01001         /** Return true if iteration is valid, otherwise false. */
01002         operator bool() const;
01003 
01004     private:
01005         Block::LibertyList::Iterator m_it;
01006 
01007         const GoBoard& m_board;
01008 
01009 #ifndef NDEBUG
01010         uint64_t m_countPlay;
01011 #endif
01012 
01013         /** Not implemented. */
01014         LibertyIterator(const LibertyIterator&);
01015 
01016         /** Not implemented. */
01017         LibertyIterator& operator=(const LibertyIterator&);
01018     };
01019 
01020     /** Iterate through all the liberties of a block.
01021         Point 'p' must be occupied.
01022         Like GoBoard::LibertyIterator, but allows moves to be executed during
01023         the iteration (uses a copy of the liberty list, if required by the
01024         implementation).
01025     */
01026     class LibertyCopyIterator
01027     {
01028     public:
01029         LibertyCopyIterator(const GoBoard& bd, SgPoint p);
01030 
01031         /** Advance the state of the iteration to the next liberty. */
01032         void operator++();
01033 
01034         /** Return the current liberty. */
01035         int operator*() const;
01036 
01037         /** Return true if iteration is valid, otherwise false. */
01038         operator bool() const;
01039 
01040     private:
01041         /** Copy of liberty list.
01042             Necessary, because if moves are played and undone while iterating
01043             over liberty list, the implementation of GoBoard does not
01044             guarantee, that the order of the block's liberty list is
01045             preserved.
01046         */
01047         Block::LibertyList m_liberties;
01048 
01049         Block::LibertyList::Iterator m_it;
01050 
01051         const GoBoard& m_board;
01052 
01053 #ifndef NDEBUG
01054         SgHashCode m_oldHash;
01055 #endif
01056 
01057         /** Not implemented. */
01058         LibertyCopyIterator(const LibertyCopyIterator&);
01059 
01060         /** Not implemented. */
01061         LibertyCopyIterator& operator=(const LibertyCopyIterator&);
01062     };
01063 };
01064 
01065 inline GoBoard::StoneIterator::StoneIterator(const GoBoard& bd, SgPoint p)
01066     : m_it(bd.m_state.m_block[p]->Stones()),
01067       m_board(bd)
01068 {
01069     SG_ASSERT(m_board.Occupied(p));
01070 #ifndef NDEBUG
01071     m_countPlay = m_board.CountPlay();
01072 #endif
01073 }
01074 
01075 inline void GoBoard::StoneIterator::operator++()
01076 {
01077     ++m_it;
01078 }
01079 
01080 inline SgPoint GoBoard::StoneIterator::operator*() const
01081 {
01082     SG_ASSERT(m_board.CountPlay() == m_countPlay);
01083     return *m_it;
01084 }
01085 
01086 inline GoBoard::StoneIterator::operator bool() const
01087 {
01088     return m_it;
01089 }
01090 
01091 inline GoBoard::Iterator::Iterator(const GoBoard& bd)
01092     : SgPointRangeIterator(bd.BoardConst().BoardIterAddress(),
01093                            bd.BoardConst().BoardIterEnd())
01094 {
01095 }
01096 
01097 inline GoBoard::LibertyIterator::LibertyIterator(const GoBoard& bd, SgPoint p)
01098     : m_it(bd.m_state.m_block[p]->Liberties()),
01099       m_board(bd)
01100 {
01101     SG_ASSERT(m_board.Occupied(p));
01102 #ifndef NDEBUG
01103     m_countPlay = m_board.CountPlay();
01104 #endif
01105 }
01106 
01107 inline void GoBoard::LibertyIterator::operator++()
01108 {
01109     ++m_it;
01110 }
01111 
01112 inline SgPoint GoBoard::LibertyIterator::operator*() const
01113 {
01114     SG_ASSERT(m_board.CountPlay() == m_countPlay);
01115     return *m_it;
01116 }
01117 
01118 inline GoBoard::LibertyIterator::operator bool() const
01119 {
01120     return m_it;
01121 }
01122 
01123 inline GoBoard::LibertyCopyIterator::LibertyCopyIterator(const GoBoard& bd,
01124                                                          SgPoint p)
01125     : m_liberties(bd.m_state.m_block[p]->Liberties()),
01126       m_it(m_liberties),
01127       m_board(bd)
01128 {
01129     SG_ASSERT(m_board.Occupied(p));
01130 #ifndef NDEBUG
01131     m_oldHash = m_board.GetHashCode();
01132 #endif
01133 }
01134 
01135 inline void GoBoard::LibertyCopyIterator::operator++()
01136 {
01137     ++m_it;
01138 }
01139 
01140 inline int GoBoard::LibertyCopyIterator::operator*() const
01141 {
01142     SG_ASSERT(m_board.GetHashCode() == m_oldHash);
01143     return *m_it;
01144 }
01145 
01146 inline GoBoard::LibertyCopyIterator::operator bool() const
01147 {
01148     return m_it;
01149 }
01150 
01151 inline void GoBoard::HashCode::Clear()
01152 {
01153     m_hash.Clear();
01154 }
01155 
01156 inline const SgHashCode& GoBoard::HashCode::Get() const
01157 {
01158     return m_hash;
01159 }
01160 
01161 inline SgHashCode GoBoard::HashCode::GetInclToPlay(SgBlackWhite toPlay) const
01162 {
01163     SgHashCode hash = m_hash;
01164     BOOST_STATIC_ASSERT(SG_BLACK == 0);
01165     BOOST_STATIC_ASSERT(SG_WHITE == 1);
01166     int index = toPlay + 1;
01167     SG_ASSERTRANGE(index, START_INDEX_TOPLAY, END_INDEX_TOPLAY);
01168     SgHashUtil::XorZobrist(hash, index);
01169     return hash;
01170 }
01171 
01172 inline void GoBoard::HashCode::XorCaptured(int moveNumber,
01173                                            SgPoint firstCapturedStone)
01174 {
01175     int index = 2 * SG_MAXPOINT + moveNumber % 64 + firstCapturedStone;
01176     SG_ASSERTRANGE(index, START_INDEX_CAPTURES, END_INDEX_CAPTURES);
01177     SgHashUtil::XorZobrist(m_hash, index);
01178 }
01179 
01180 inline void GoBoard::HashCode::XorStone(SgPoint p, SgBlackWhite c)
01181 {
01182     SG_ASSERT_BOARDRANGE(p);
01183     SG_ASSERT_BW(c);
01184     BOOST_STATIC_ASSERT(SG_BLACK == 0);
01185     BOOST_STATIC_ASSERT(SG_WHITE == 1);
01186     int index = p + c * SG_MAXPOINT;
01187     SG_ASSERTRANGE(index, START_INDEX_STONES, END_INDEX_STONES);
01188     SgHashUtil::XorZobrist(m_hash, index);
01189 }
01190 
01191 inline void GoBoard::HashCode::XorWinKo(int level, SgBlackWhite c)
01192 {
01193     SG_ASSERT(level > 0 && level <= MAX_KOLEVEL);
01194     SG_ASSERT_BW(c);
01195     BOOST_STATIC_ASSERT(SG_BLACK == 0);
01196     BOOST_STATIC_ASSERT(SG_WHITE == 1);
01197     int index = level + MAX_KOLEVEL * c + 2 * SG_MAXPOINT;
01198     SG_ASSERTRANGE(index, START_INDEX_WINKO, END_INDEX_WINKO);
01199     SgHashUtil::XorZobrist(m_hash, index);
01200 }
01201 
01202 inline const SgPointSet& GoBoard::All(SgBlackWhite color) const
01203 {
01204     return m_state.m_all[color];
01205 }
01206 
01207 inline const SgPointSet& GoBoard::AllEmpty() const
01208 {
01209     return m_state.m_empty;
01210 }
01211 
01212 inline void GoBoard::AllowAnyRepetition(bool allowAny)
01213 {
01214     m_allowAnyRepetition = allowAny;
01215 }
01216 
01217 inline void GoBoard::AllowKoRepetition(bool allowKo)
01218 {
01219     m_allowKoRepetition = allowKo;
01220 }
01221 
01222 inline const SgPointSet& GoBoard::AllPoints() const
01223 {
01224     return SgPointSet::AllPoints(Size());
01225 }
01226 
01227 inline SgPoint GoBoard::Anchor(SgPoint p) const
01228 {
01229     SG_ASSERT(Occupied(p));
01230     return m_state.m_block[p]->Anchor();
01231 }
01232 
01233 inline bool GoBoard::AnyRepetitionAllowed() const
01234 {
01235     return m_allowAnyRepetition;
01236 }
01237 
01238 inline bool GoBoard::AreInSameBlock(SgPoint p1, SgPoint p2) const
01239 {
01240     return Occupied(p1) && Occupied(p2) && Anchor(p1) == Anchor(p2);
01241 }
01242 
01243 inline bool GoBoard::AtLeastNumLibs(SgPoint block, int n) const
01244 {
01245     return NumLiberties(block) >= n;
01246 }
01247 
01248 inline bool GoBoard::AtMostNumLibs(SgPoint block, int n) const
01249 {
01250     return NumLiberties(block) <= n;
01251 }
01252 
01253 inline bool GoBoard::CanUndo() const
01254 {
01255     return (m_moves->Length() > 0);
01256 }
01257 
01258 inline const GoPointList& GoBoard::CapturedStones() const
01259 {
01260     return m_capturedStones;
01261 }
01262 
01263 inline bool GoBoard::CapturingMove() const
01264 {
01265     return ! m_capturedStones.IsEmpty();
01266 }
01267 
01268 inline const SgPointSet& GoBoard::Centers() const
01269 {
01270     return m_const.Centers();
01271 }
01272 
01273 inline const SgPointSet& GoBoard::Corners() const
01274 {
01275     return m_const.Corners();
01276 }
01277 
01278 inline uint64_t GoBoard::CountPlay() const
01279 {
01280     return m_countPlay;
01281 }
01282 
01283 inline const SgPointSet& GoBoard::Edges() const
01284 {
01285     return m_const.Edges();
01286 }
01287 
01288 inline int GoBoard::FirstBoardPoint() const
01289 {
01290     return m_const.FirstBoardPoint();
01291 }
01292 
01293 inline const SgBoardConst& GoBoard::BoardConst() const
01294 {
01295     return m_const;
01296 }
01297 
01298 inline SgPoint GoBoard::Get2ndLastMove() const
01299 {
01300     int moveNumber = MoveNumber();
01301     if (moveNumber < 2)
01302         return SG_NULLMOVE;
01303     const StackEntry& entry1 = (*m_moves)[moveNumber - 1];
01304     const StackEntry& entry2 = (*m_moves)[moveNumber - 2];
01305     SgBlackWhite toPlay = ToPlay();
01306     if (entry1.m_color != SgOppBW(toPlay) || entry2.m_color != toPlay)
01307         return SG_NULLMOVE;
01308     return entry2.m_point;
01309 }
01310 
01311 inline SgBoardColor GoBoard::GetColor(SgPoint p) const
01312 {
01313     return m_state.m_color[p];
01314 }
01315 
01316 inline const SgHashCode& GoBoard::GetHashCode() const
01317 {
01318     return m_state.m_hash.Get();
01319 }
01320 
01321 inline SgHashCode GoBoard::GetHashCodeInclToPlay() const
01322 {
01323     return m_state.m_hash.GetInclToPlay(ToPlay());
01324 }
01325 
01326 inline SgPoint GoBoard::GetLastMove() const
01327 {
01328     int moveNumber = MoveNumber();
01329     if (moveNumber == 0)
01330         return SG_NULLMOVE;
01331     const StackEntry& entry = (*m_moves)[moveNumber - 1];
01332     if (entry.m_color != SgOppBW(ToPlay()))
01333         return SG_NULLMOVE;
01334     return entry.m_point;
01335 }
01336 
01337 inline GoMoveInfo GoBoard::GetLastMoveInfo() const
01338 {
01339     return m_moveInfo;
01340 }
01341 
01342 inline SgBlackWhite GoBoard::GetStone(SgPoint p) const
01343 {
01344     SG_ASSERT(Occupied(p));
01345     return m_state.m_color[p];
01346 }
01347 
01348 inline bool GoBoard::HasDiagonals(SgPoint p, SgBoardColor c) const
01349 {
01350     return (IsColor(p - SG_NS - SG_WE, c)
01351             || IsColor(p - SG_NS + SG_WE, c)
01352             || IsColor(p + SG_NS - SG_WE, c)
01353             || IsColor(p + SG_NS + SG_WE, c));
01354 }
01355 
01356 inline bool GoBoard::HasEmptyNeighbors(SgPoint p) const
01357 {
01358     return m_state.m_nuNeighborsEmpty[p] != 0;
01359 }
01360 
01361 inline bool GoBoard::HasLiberties(SgPoint p) const
01362 {
01363     return NumLiberties(p) > 0;
01364 }
01365 
01366 inline bool GoBoard::HasNeighbors(SgPoint p, SgBlackWhite c) const
01367 {
01368     return (m_state.m_nuNeighbors[c][p] > 0);
01369 }
01370 
01371 inline bool GoBoard::HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const
01372 {
01373     return HasNeighbors(p, c) || HasDiagonals(p, c);
01374 }
01375 
01376 inline bool GoBoard::InAtari(SgPoint p) const
01377 {
01378     SG_ASSERT(Occupied(p));
01379     return AtMostNumLibs(p, 1);
01380 }
01381 
01382 inline bool GoBoard::IsInBlock(SgPoint p, SgPoint anchor) const
01383 {
01384     SG_ASSERT(Occupied(anchor));
01385     SG_ASSERT(Anchor(anchor) == anchor);
01386     const Block* b = m_state.m_block[p];
01387     return (b != 0 && b->Anchor() == anchor);
01388 }
01389 
01390 inline bool GoBoard::IsLibertyOfBlock(SgPoint p, SgPoint anchor) const
01391 {
01392     SG_ASSERT(IsEmpty(p));
01393     SG_ASSERT(Occupied(anchor));
01394     SG_ASSERT(Anchor(anchor) == anchor);
01395     const Block* b = m_state.m_block[anchor];
01396     if (m_state.m_nuNeighbors[b->Color()][p] == 0)
01397         return false;
01398     return (   m_state.m_block[p - SG_NS] == b
01399             || m_state.m_block[p - SG_WE] == b
01400             || m_state.m_block[p + SG_WE] == b
01401             || m_state.m_block[p + SG_NS] == b);
01402 }
01403 
01404 inline bool GoBoard::CanCapture(SgPoint p, SgBlackWhite c) const
01405 {
01406     SgBlackWhite opp = SgOppBW(c);
01407     for (SgNb4Iterator nb(p); nb; ++nb)
01408         if (IsColor(*nb, opp) && AtMostNumLibs(*nb, 1))
01409             return true;
01410     return false;
01411 }
01412 
01413 inline bool GoBoard::InCenter(SgPoint p) const
01414 {
01415     return Centers()[p];
01416 }
01417 
01418 inline bool GoBoard::InCorner(SgPoint p) const
01419 {
01420     return Corners()[p];
01421 }
01422 
01423 inline void GoBoard::Init(int size, const GoSetup& setup)
01424 {
01425     Init(size, m_rules, setup);
01426 }
01427 
01428 inline bool GoBoard::IsSuicide(SgPoint p, SgBlackWhite toPlay) const
01429 {
01430     if (HasEmptyNeighbors(p))
01431         return false;
01432     SgBlackWhite opp = SgOppBW(toPlay);
01433     for (SgNb4Iterator it(p); it; ++it)
01434     {
01435         if (IsBorder(*it))
01436             continue;
01437         SgEmptyBlackWhite c = GetColor(*it);
01438         if (c == toPlay && NumLiberties(*it) > 1)
01439             return false;
01440         if (c == opp && NumLiberties(*it) == 1)
01441             return false;
01442     }
01443     return true;
01444 }
01445 
01446 inline bool GoBoard::IsBorder(SgPoint p) const
01447 {
01448     SG_ASSERT(p != SG_PASS);
01449     return m_isBorder[p];
01450 }
01451 
01452 inline bool GoBoard::IsColor(SgPoint p, int c) const
01453 {
01454     SG_ASSERT(p != SG_PASS);
01455     SG_ASSERT_EBW(c);
01456     return m_state.m_color[p] == c;
01457 }
01458 
01459 inline bool GoBoard::IsEmpty(SgPoint p) const
01460 {
01461     SG_ASSERT(p != SG_PASS);
01462     return m_state.m_color[p] == SG_EMPTY;
01463 }
01464 
01465 inline bool GoBoard::IsFirst(SgPoint p) const
01466 {
01467     SG_ASSERT(IsEmpty(p));
01468     return m_state.m_isFirst[p];
01469 }
01470 
01471 inline bool GoBoard::IsLegal(int p, SgBlackWhite player) const
01472 {
01473     SG_ASSERT_BW(player);
01474     if (IsPass(p))
01475         return true;
01476     SG_ASSERT(SgPointUtil::InBoardRange(p));
01477     if (! IsEmpty(p))
01478         return false;
01479     // Suicide
01480     if (! Rules().AllowSuicide() && IsSuicide(p, player))
01481         return false;
01482     // Repetition
01483     if (IsFirst(p))
01484         return true;
01485     if (p == m_state.m_koPoint && m_state.m_toPlay == player)
01486         return (AnyRepetitionAllowed() || KoRepetitionAllowed());
01487     if (Rules().GetKoRule() == GoRules::SIMPLEKO)
01488         return true;
01489     if (IsNewPosition() && ! CanCapture(p, player))
01490         return true;
01491     // None of the easy cases, so check by executing move. Casting away
01492     // const is okay since board is restored to exactly the same state,
01493     // appears const to the client.
01494     GoBoard* bd = const_cast<GoBoard*>(this);
01495     bd->Play(p, player);
01496     bool isLegal = ! LastMoveInfo(GO_MOVEFLAG_ILLEGAL);
01497     bd->Undo();
01498     return isLegal;
01499 }
01500 
01501 inline bool GoBoard::IsNewPosition() const
01502 {
01503     return m_state.m_isNewPosition;
01504 }
01505 
01506 inline bool GoBoard::IsLegal(int p) const
01507 {
01508     return IsLegal(p, ToPlay());
01509 }
01510 
01511 /** Check if point is a pass move or a coupon move, which is handled like a
01512     pass move.
01513 */
01514 inline bool GoBoard::IsPass(SgPoint p)
01515 {
01516     return (p == SG_PASS || SgMoveUtil::IsCouponMove(p));
01517 }
01518 
01519 inline bool GoBoard::IsSingleStone(SgPoint p) const
01520 {
01521     return (Occupied(p) && NumNeighbors(p, GetColor(p)) == 0);
01522 }
01523 
01524 inline bool GoBoard::IsSuicide(SgPoint p) const
01525 {
01526     return IsSuicide(p, ToPlay());
01527 }
01528 
01529 inline bool GoBoard::IsValidPoint(SgPoint p) const
01530 {
01531     return SgPointUtil::InBoardRange(p) && ! IsBorder(p);
01532 }
01533 
01534 inline SgEmptyBlackWhite GoBoard::KoColor() const
01535 {
01536     return m_koColor;
01537 }
01538 
01539 inline int GoBoard::KoLevel() const
01540 {
01541     return m_state.m_koLevel;
01542 }
01543 
01544 inline SgEmptyBlackWhite GoBoard::KoLoser() const
01545 {
01546     return m_koLoser;
01547 }
01548 
01549 inline bool GoBoard::KoModifiesHash() const
01550 {
01551     return m_koModifiesHash;
01552 }
01553 
01554 inline SgPoint GoBoard::KoPoint() const
01555 {
01556     return m_state.m_koPoint;
01557 }
01558 
01559 inline bool GoBoard::KoRepetitionAllowed() const
01560 {
01561     return m_allowKoRepetition;
01562 }
01563 
01564 inline int GoBoard::LastBoardPoint() const
01565 {
01566     return m_const.LastBoardPoint();
01567 }
01568 
01569 inline bool GoBoard::LastMoveInfo(GoMoveInfoFlag flag) const
01570 {
01571     return m_moveInfo.test(flag);
01572 }
01573 
01574 inline int GoBoard::Left(SgPoint p) const
01575 {
01576     return m_const.Left(p);
01577 }
01578 
01579 inline SgGrid GoBoard::Line(SgPoint p) const
01580 {
01581     return m_const.Line(p);
01582 }
01583 
01584 inline const SgPointSet& GoBoard::LineSet(SgGrid line) const
01585 {
01586     return m_const.LineSet(line);
01587 }
01588 
01589 inline int GoBoard::MoveNumber() const
01590 {
01591     return m_moves->Length();
01592 }
01593 
01594 inline int GoBoard::Num8Neighbors(SgPoint p, int c) const
01595 {
01596     return NumNeighbors(p, c) + NumDiagonals(p, c);
01597 }
01598 
01599 inline int GoBoard::Num8EmptyNeighbors(SgPoint p) const
01600 {
01601     return NumEmptyNeighbors(p) + NumEmptyDiagonals(p);
01602 }
01603 
01604 inline int GoBoard::NuCapturedStones() const
01605 {
01606     return m_capturedStones.Length();
01607 }
01608 
01609 inline int GoBoard::NumDiagonals(SgPoint p, SgBoardColor c) const
01610 {
01611     int n = 0;
01612     if (IsColor(p - SG_NS - SG_WE, c))
01613         ++n;
01614     if (IsColor(p - SG_NS + SG_WE, c))
01615         ++n;
01616     if (IsColor(p + SG_NS - SG_WE, c))
01617         ++n;
01618     if (IsColor(p + SG_NS + SG_WE, c))
01619         ++n;
01620     return n;
01621 }
01622 
01623 inline int GoBoard::NumEmptyDiagonals(SgPoint p) const
01624 {
01625     return NumDiagonals(p, SG_EMPTY);
01626 }
01627 
01628 inline int GoBoard::NumEmptyNeighbors(SgPoint p) const
01629 {
01630     return m_state.m_nuNeighborsEmpty[p];
01631 }
01632 
01633 inline int GoBoard::NumLiberties(SgPoint p) const
01634 {
01635     SG_ASSERT(IsValidPoint(p));
01636     SG_ASSERT(Occupied(p));
01637     return m_state.m_block[p]->NumLiberties();
01638 }
01639 
01640 inline int GoBoard::NumNeighbors(SgPoint p, SgBlackWhite c) const
01641 {
01642     return m_state.m_nuNeighbors[c][p];
01643 }
01644 
01645 inline int GoBoard::NumPrisoners(SgBlackWhite color) const
01646 {
01647     return m_state.m_prisoners[color];
01648 }
01649 
01650 inline int GoBoard::NumStones(SgPoint block) const
01651 {
01652     SG_ASSERT(Occupied(block));
01653     return m_state.m_block[block]->NumStones();
01654 }
01655 
01656 inline SgPointSet GoBoard::Occupied() const
01657 {
01658     return m_state.m_all[SG_BLACK] | m_state.m_all[SG_WHITE];
01659 }
01660 
01661 inline bool GoBoard::Occupied(SgPoint p) const
01662 {
01663     return (m_state.m_block[p] != 0);
01664 }
01665 
01666 inline bool GoBoard::OccupiedInAtari(SgPoint p) const
01667 {
01668     const Block* b = m_state.m_block[p];
01669     return (b != 0 && b->NumLiberties() <= 1);
01670 }
01671 
01672 inline bool GoBoard::OnEdge(SgPoint p) const
01673 {
01674     return Edges()[p];
01675 }
01676 
01677 inline SgBlackWhite GoBoard::Opponent() const
01678 {
01679     return SgOppBW(m_state.m_toPlay);
01680 }
01681 
01682 inline void GoBoard::Play(GoPlayerMove move)
01683 {
01684     Play(move.Point(), move.Color());
01685 }
01686 
01687 inline void GoBoard::Play(SgPoint p)
01688 {
01689     Play(p, ToPlay());
01690 }
01691 
01692 inline SgGrid GoBoard::Pos(SgPoint p) const
01693 {
01694     return m_const.Pos(p);
01695 }
01696 
01697 inline int GoBoard::Right(SgPoint p) const
01698 {
01699     return m_const.Right(p);
01700 }
01701 
01702 inline GoRules& GoBoard::Rules()
01703 {
01704     return m_rules;
01705 }
01706 
01707 inline const GoRules& GoBoard::Rules() const
01708 {
01709     return m_rules;
01710 }
01711 
01712 inline void GoBoard::SetKoLoser(SgEmptyBlackWhite color)
01713 {
01714     SG_ASSERT(KoLevel() == 0);
01715     m_koLoser = color;
01716 }
01717 
01718 inline void GoBoard::SetKoModifiesHash(bool modify)
01719 {
01720     m_koModifiesHash = modify;
01721 }
01722 
01723 inline void GoBoard::SetToPlay(SgBlackWhite player)
01724 {
01725     SG_ASSERT_BW(player);
01726     m_state.m_toPlay = player;
01727 }
01728 
01729 inline const GoSetup& GoBoard::Setup() const
01730 {
01731     return m_setup;
01732 }
01733 
01734 inline int GoBoard::Side(SgPoint p, int index) const
01735 {
01736     return m_const.Side(p, index);
01737 }
01738 
01739 inline const SgPointSet& GoBoard::SideExtensions() const
01740 {
01741     return m_const.SideExtensions();
01742 }
01743 
01744 inline SgGrid GoBoard::Size() const
01745 {
01746     return m_size;
01747 }
01748 
01749 inline SgPoint GoBoard::TheLiberty(SgPoint p) const
01750 {
01751     SG_ASSERT(Occupied(p));
01752     SG_ASSERT(NumLiberties(p) == 1);
01753     return m_state.m_block[p]->Liberties()[0];
01754 }
01755 
01756 inline SgBlackWhite GoBoard::ToPlay() const
01757 {
01758     return m_state.m_toPlay;
01759 }
01760 
01761 inline int GoBoard::TotalNumEmpty() const
01762 {
01763     return (Size() * Size() - m_state.m_numStones[SG_BLACK]
01764             - m_state.m_numStones[SG_WHITE]);
01765 }
01766 
01767 inline const SgBWArray<int>& GoBoard::TotalNumStones() const
01768 {
01769     return m_state.m_numStones;
01770 }
01771 
01772 inline int GoBoard::TotalNumStones(SgBlackWhite color) const
01773 {
01774     return m_state.m_numStones[color];
01775 }
01776 
01777 inline int GoBoard::Up(SgPoint p) const
01778 {
01779     return m_const.Up(p);
01780 }
01781 
01782 //----------------------------------------------------------------------------
01783 
01784 #endif // GO_BOARD_H
01785 


17 Jun 2010 Doxygen 1.4.7