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