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