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


Sun Mar 13 2011 Doxygen 1.7.1