00001 //---------------------------------------------------------------------------- 00002 /** @file GoUctBoard.h 00003 Go board optimized for Monte-Carlo. 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #ifndef GOUCT_BOARD_H 00008 #define GOUCT_BOARD_H 00009 00010 #include <bitset> 00011 #include <cstring> 00012 #include <stdint.h> 00013 #include <boost/static_assert.hpp> 00014 #include "GoBoard.h" 00015 #include "GoBoardUtil.h" 00016 #include "GoPlayerMove.h" 00017 #include "SgArray.h" 00018 #include "SgBoardConst.h" 00019 #include "SgBoardColor.h" 00020 #include "SgMarker.h" 00021 #include "SgBWArray.h" 00022 #include "SgNbIterator.h" 00023 #include "SgPoint.h" 00024 #include "SgPointArray.h" 00025 #include "SgPointIterator.h" 00026 #include "SgSList.h" 00027 00028 //---------------------------------------------------------------------------- 00029 00030 /** Go board optimized for Monte-Carlo. 00031 In contrast to class GoBoard, this board makes certain assumptions 00032 that are usually true for Monte-Carlo simulations for better efficiency: 00033 - No undo 00034 - Alternating play 00035 - Simple-Ko rule 00036 - Suicide not allowed 00037 00038 Otherwise, the member functions are named like in class GoBoard to allow 00039 writing utility functions that use the board class as a template parameter 00040 (as long as they use only the functionality shared by both board classes) 00041 */ 00042 class GoUctBoard 00043 { 00044 public: 00045 /** Marker that can be used in client code. 00046 This marker is never used by this class, it is intended for external 00047 functions that operate on the board and can profit from the fast clear 00048 operation of SgMarker (if reused), but cannot store its own 00049 marker (or don't want to use a global variable for thread-safety). 00050 Since only one function can use this marker at a time, you should 00051 assert with SgReserveMarker that the marker is not used in a 00052 conflicting way. 00053 */ 00054 mutable SgMarker m_userMarker; 00055 00056 explicit GoUctBoard(const GoBoard& bd); 00057 00058 ~GoUctBoard(); 00059 00060 const SgBoardConst& BoardConst() const; 00061 00062 /** Re-initializes the board from GoBoard position. */ 00063 void Init(const GoBoard& bd); 00064 00065 /** Return the size of this board. */ 00066 SgGrid Size() const; 00067 00068 /** Check if point is occupied by a stone. 00069 Can be called with border points. 00070 */ 00071 bool Occupied(SgPoint p) const; 00072 00073 bool IsEmpty(SgPoint p) const; 00074 00075 bool IsBorder(SgPoint p) const; 00076 00077 bool IsColor(SgPoint p, int c) const; 00078 00079 SgBoardColor GetColor(SgPoint p) const; 00080 00081 SgBlackWhite GetStone(SgPoint p) const; 00082 00083 /** %Player whose turn it is to play. */ 00084 SgBlackWhite ToPlay() const; 00085 00086 /** Opponent of player whose turn it is to play. */ 00087 SgBlackWhite Opponent() const; 00088 00089 /** See SgBoardConst::Line */ 00090 SgGrid Line(SgPoint p) const; 00091 00092 /** See SgBoardConst::Pos */ 00093 SgGrid Pos(SgPoint p) const; 00094 00095 /** Returns the offset to the point on the line above this point. 00096 Returns zero for points outside the board, and for the center 00097 point(s). 00098 */ 00099 int Up(SgPoint p) const; 00100 00101 /** Returns the offset along left side of the board. 00102 Left and right are as seen from the edge toward the center of the 00103 board. 00104 Returns zero for the same points as Up does. 00105 */ 00106 int Left(SgPoint p) const; 00107 00108 /** Returns the offset along right side of the board. 00109 @see Left for more info. 00110 */ 00111 int Right(SgPoint p) const; 00112 00113 /** Same as Left/Right, but the side is passed in as an index (0 or 1). */ 00114 int Side(SgPoint p, int index) const; 00115 00116 bool IsSuicide(SgPoint p, SgBlackWhite toPlay) const; 00117 00118 bool IsValidPoint(SgPoint p) const; 00119 00120 bool HasEmptyNeighbors(SgPoint p) const; 00121 00122 int NumEmptyNeighbors(SgPoint p) const; 00123 00124 /** Includes diagonals. */ 00125 int Num8EmptyNeighbors(SgPoint p) const; 00126 00127 bool HasNeighbors(SgPoint p, SgBlackWhite c) const; 00128 00129 int NumNeighbors(SgPoint p, SgBlackWhite c) const; 00130 00131 /** Includes diagonals. */ 00132 int Num8Neighbors(SgPoint p, SgBlackWhite c) const; 00133 00134 bool HasDiagonals(SgPoint p, SgBoardColor c) const; 00135 00136 int NumDiagonals(SgPoint p, SgBoardColor c) const; 00137 00138 int NumEmptyDiagonals(SgPoint p) const; 00139 00140 bool HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const; 00141 00142 bool InCorner(SgPoint p) const; 00143 00144 bool OnEdge(SgPoint p) const; 00145 00146 bool InCenter(SgPoint p) const; 00147 00148 /** See SgBoardConst::FirstBoardPoint */ 00149 int FirstBoardPoint() const; 00150 00151 /** See SgBoardConst::FirstBoardPoint */ 00152 int LastBoardPoint() const; 00153 00154 /** Play a move for the current player. 00155 @see Play(SgPoint,SgBlackWhite); 00156 */ 00157 void Play(SgPoint p); 00158 00159 /** Check whether the move at 'p' is legal. 00160 Since it's not clear how 'p' was arrived at, any value of 'p' is 00161 admissible, even out of point range and on border points; just return 00162 false on such input. 00163 */ 00164 bool IsLegal(int p, SgBlackWhite player) const; 00165 00166 /** Check whether the move at 'p' is legal for color to play. 00167 @see IsLegal(int, SgBlackWhite). 00168 */ 00169 bool IsLegal(int p) const; 00170 00171 bool IsSuicide(SgPoint p) const; 00172 00173 /** Whether the most recent move captured any stones. */ 00174 bool CapturingMove() const; 00175 00176 /** The stones removed from the board by the most recent move. 00177 Can be used for incremental update of other data structures. 00178 Only valid directly after a GoUctBoard::Play, otherwise undefined. 00179 */ 00180 const GoPointList& CapturedStones() const; 00181 00182 /** The stones captured by the most recent move. 00183 @see CapturedStones 00184 */ 00185 int NuCapturedStones() const; 00186 00187 /** The total number of stones of 'color' that have been 00188 captured by the opponent throughout the game. */ 00189 int NumPrisoners(SgBlackWhite color) const; 00190 00191 /** Return last move played. 00192 @return The last move played or SG_NULLMOVE, if 00193 - No move was played yet 00194 - The last move was not by the opposite color of the current player 00195 */ 00196 SgPoint GetLastMove() const; 00197 00198 /** 2nd Last move = last move by ToPlay(). 00199 Conditions similar to GetLastMove(). 00200 */ 00201 SgPoint Get2ndLastMove() const; 00202 00203 /** Return the number of stones in the block at 'p'. 00204 Not defined for empty or border points. 00205 */ 00206 int NumStones(SgPoint p) const; 00207 00208 /** Return NumStones(p) == 1. */ 00209 bool IsSingleStone(SgPoint p) const; 00210 00211 /** Return whether the two stones are located in the same block. 00212 Return false if one of the stones is an empty or border point. 00213 */ 00214 bool AreInSameBlock(SgPoint stone1, SgPoint stone2) const; 00215 00216 /** Return a reference point in the block at a point. 00217 @note In contrast to GoBoard, the anchor point is not guaranteed 00218 to be the smallest point (this functionality is not needed in 00219 Monte-Carlo) 00220 Requires: Occupied(p). 00221 */ 00222 SgPoint Anchor(SgPoint p) const; 00223 00224 /** See GoBoard::IsInBlock */ 00225 bool IsInBlock(SgPoint p, SgPoint anchor) const; 00226 00227 /** See GoBoard::IsLibertyOfBlock */ 00228 bool IsLibertyOfBlock(SgPoint p, SgPoint anchor) const; 00229 00230 /** Get adjacent opponent blocks with a maximum number of liberties for a 00231 given block. 00232 Not defined for empty points. 00233 @param p The block to check. 00234 @param maxLib The maximum number of liberties of the neighbors. 00235 @param anchors Resulting neighbor anchors and an additional END_POINT. 00236 @param maxAnchors Array size of anchors (for detecting overflow in 00237 debug mode) 00238 @return Number of anchors (without the END_POINT) 00239 */ 00240 int AdjacentBlocks(SgPoint p, int maxLib, SgPoint anchors[], 00241 int maxAnchors) const; 00242 00243 /** %List anchor of each block of color 'c' adjacent to the 00244 empty point 'p'. 00245 Assert if 'p' is not empty. 00246 Fill an array of points, terminated by END_POINT. 00247 */ 00248 void NeighborBlocks(SgPoint p, SgBlackWhite c, SgPoint anchors[]) const; 00249 00250 /** %List anchor of each block of color 'c' with at most 'maxLib' 00251 liberties adjacent to the empty point 'p'. 00252 Assert if 'p' is not empty. 00253 Fill an array of points, terminated by END_POINT. 00254 */ 00255 void NeighborBlocks(SgPoint p, SgBlackWhite c, int maxLib, 00256 SgPoint anchors[]) const; 00257 00258 /** Return the liberty of 'blockInAtari' which must have exactly 00259 one liberty. 00260 */ 00261 SgPoint TheLiberty(SgPoint blockInAtari) const; 00262 00263 /** Return the number of liberties of the block at 'p'. 00264 Not defined for empty or border points. 00265 */ 00266 int NumLiberties(SgPoint p) const; 00267 00268 /** Return whether block has at most n liberties. */ 00269 bool AtMostNumLibs(SgPoint block, int n) const; 00270 00271 /** Return whether block has at least n liberties. */ 00272 bool AtLeastNumLibs(SgPoint block, int n) const; 00273 00274 /** Return whether the number of liberties of the block at 'p' is one. 00275 Requires: Occupied(p) 00276 */ 00277 bool InAtari(SgPoint p) const; 00278 00279 /** Check if point is occupied and in atari. 00280 Faster than Occupied(p) || InAtari(p). 00281 May be called for border points. 00282 */ 00283 bool OccupiedInAtari(SgPoint p) const; 00284 00285 /** Return whether playing colour c at p can capture anything, 00286 ignoring any possible repetition. 00287 */ 00288 bool CanCapture(SgPoint p, SgBlackWhite c) const; 00289 00290 /** Checks whether all the board data structures are in a consistent 00291 state. 00292 */ 00293 void CheckConsistency() const; 00294 00295 private: 00296 /** Data related to a block of stones on the board. */ 00297 struct Block 00298 { 00299 public: 00300 /** Upper limit for liberties. 00301 Proof? 00302 */ 00303 static const int MAX_LIBERTIES = (SG_MAX_SIZE / 3) * 2 * SG_MAX_SIZE; 00304 00305 typedef SgSList<SgPoint,MAX_LIBERTIES> LibertyList; 00306 00307 typedef LibertyList::Iterator LibertyIterator; 00308 00309 typedef GoPointList::Iterator StoneIterator; 00310 00311 SgPoint m_anchor; 00312 00313 SgBlackWhite m_color; 00314 00315 LibertyList m_liberties; 00316 00317 GoPointList m_stones; 00318 00319 void InitSingleStoneBlock(SgBlackWhite c, SgPoint anchor) 00320 { 00321 SG_ASSERT_BW(c); 00322 m_color = c; 00323 m_anchor = anchor; 00324 m_stones.SetTo(anchor); 00325 m_liberties.Clear(); 00326 } 00327 00328 void InitNewBlock(SgBlackWhite c, SgPoint anchor) 00329 { 00330 SG_ASSERT_BW(c); 00331 m_color = c; 00332 m_anchor = anchor; 00333 m_stones.Clear(); 00334 m_liberties.Clear(); 00335 } 00336 }; 00337 00338 SgPoint m_lastMove; 00339 00340 SgPoint m_secondLastMove; 00341 00342 /** Point which is currently illegal for simple Ko rule. */ 00343 SgPoint m_koPoint; 00344 00345 /** Whose turn it is to play. */ 00346 SgBlackWhite m_toPlay; 00347 00348 SgArray<Block*,SG_MAXPOINT> m_block; 00349 00350 /** Number of prisoners of each color */ 00351 SgBWArray<int> m_prisoners; 00352 00353 /** The current board position. */ 00354 SgArray<int,SG_MAXPOINT> m_color; 00355 00356 /** Number of black and white neighbors. */ 00357 SgArray<int,SG_MAXPOINT> m_nuNeighborsEmpty; 00358 00359 /** Number of black and white neighbors. */ 00360 SgBWArray<SgArray<int,SG_MAXPOINT> > m_nuNeighbors; 00361 00362 /** Data that's constant for this board size. */ 00363 SgBoardConst m_const; 00364 00365 /** The current board size. */ 00366 SgGrid m_size; 00367 00368 SgPointArray<Block> m_blockArray; 00369 00370 mutable SgMarker m_marker; 00371 00372 SgMarker m_marker2; 00373 00374 GoPointList m_capturedStones; 00375 00376 SgArray<bool,SG_MAXPOINT> m_isBorder; 00377 00378 /** Not implemented. */ 00379 GoUctBoard(const GoUctBoard&); 00380 00381 /** Not implemented. */ 00382 GoUctBoard& operator=(const GoUctBoard&); 00383 00384 void AddLibToAdjBlocks(SgPoint p, SgBlackWhite c); 00385 00386 void AddStoneToBlock(SgPoint p, Block* block); 00387 00388 void CreateSingleStoneBlock(SgPoint p, SgBlackWhite c); 00389 00390 void InitSize(const GoBoard& bd); 00391 00392 bool IsAdjacentTo(SgPoint p, const Block* block) const; 00393 00394 void MergeBlocks(SgPoint p, const SgSList<Block*,4>& adjBlocks); 00395 00396 void RemoveLibAndKill(SgPoint p, SgBlackWhite opp, 00397 SgSList<Block*,4>& ownAdjBlocks); 00398 00399 void UpdateBlocksAfterAddStone(SgPoint p, SgBlackWhite c, 00400 const SgSList<Block*,4>& adjBlocks); 00401 00402 void CheckConsistencyBlock(SgPoint p) const; 00403 00404 bool FullBoardRepetition() const; 00405 00406 void AddStone(SgPoint p, SgBlackWhite c); 00407 00408 void KillBlock(const Block* block); 00409 00410 bool HasLiberties(SgPoint p) const; 00411 00412 public: 00413 friend class LibertyIterator; 00414 friend class StoneIterator; 00415 00416 /** Iterate through all points on the given board. */ 00417 class Iterator 00418 : public SgPointRangeIterator 00419 { 00420 public: 00421 Iterator(const GoUctBoard& bd); 00422 }; 00423 00424 /** Iterate through all the liberties of a block. 00425 Point 'p' must be occupied. 00426 Liberties should only be accessed for the current board position. 00427 No moves are allowed to be executed during the iteration. 00428 */ 00429 class LibertyIterator 00430 { 00431 public: 00432 LibertyIterator(const GoUctBoard& bd, SgPoint p); 00433 00434 /** Advance the state of the iteration to the next liberty. */ 00435 void operator++(); 00436 00437 /** Return the current liberty. */ 00438 SgPoint operator*() const; 00439 00440 /** Return true if iteration is valid, otherwise false. */ 00441 operator bool() const; 00442 00443 private: 00444 GoUctBoard::Block::LibertyList::Iterator m_it; 00445 00446 const GoUctBoard& m_board; 00447 00448 /** Not implemented. */ 00449 LibertyIterator(const LibertyIterator&); 00450 00451 /** Not implemented. */ 00452 LibertyIterator& operator=(const LibertyIterator&); 00453 }; 00454 00455 /** Iterate through all the stones of a block. 00456 Point 'p' must be occupied. 00457 Also, the stones can only be accessed for the current board position. 00458 */ 00459 class StoneIterator 00460 { 00461 public: 00462 StoneIterator(const GoUctBoard& bd, SgPoint p); 00463 00464 /** Advance the state of the iteration to the next stone. */ 00465 void operator++(); 00466 00467 /** Return the current stone. */ 00468 SgPoint operator*() const; 00469 00470 /** Return true if iteration is valid, otherwise false. */ 00471 operator bool() const; 00472 00473 private: 00474 GoUctBoard::Block::StoneIterator m_it; 00475 00476 const GoUctBoard& m_board; 00477 00478 /** Not implemented. */ 00479 StoneIterator(const StoneIterator&); 00480 00481 /** Not implemented. */ 00482 StoneIterator& operator=(const StoneIterator&); 00483 }; 00484 }; 00485 00486 inline std::ostream& operator<<(std::ostream& out, const GoUctBoard& bd) 00487 { 00488 return GoWriteBoard(out, bd); 00489 } 00490 00491 inline GoUctBoard::Iterator::Iterator(const GoUctBoard& bd) 00492 : SgPointRangeIterator(bd.BoardConst().BoardIterAddress(), 00493 bd.BoardConst().BoardIterEnd()) 00494 { 00495 } 00496 00497 inline GoUctBoard::LibertyIterator::LibertyIterator(const GoUctBoard& bd, 00498 SgPoint p) 00499 : m_it(bd.m_block[p]->m_liberties), 00500 m_board(bd) 00501 { 00502 SG_ASSERT(m_board.Occupied(p)); 00503 } 00504 00505 inline void GoUctBoard::LibertyIterator::operator++() 00506 { 00507 ++m_it; 00508 } 00509 00510 inline SgPoint GoUctBoard::LibertyIterator::operator*() const 00511 { 00512 return *m_it; 00513 } 00514 00515 inline GoUctBoard::LibertyIterator::operator bool() const 00516 { 00517 return m_it; 00518 } 00519 00520 inline GoUctBoard::StoneIterator::StoneIterator(const GoUctBoard& bd, 00521 SgPoint p) 00522 : m_it(bd.m_block[p]->m_stones), 00523 m_board(bd) 00524 { 00525 SG_ASSERT(m_board.Occupied(p)); 00526 } 00527 00528 inline void GoUctBoard::StoneIterator::operator++() 00529 { 00530 ++m_it; 00531 } 00532 00533 inline SgPoint GoUctBoard::StoneIterator::operator*() const 00534 { 00535 return *m_it; 00536 } 00537 00538 inline GoUctBoard::StoneIterator::operator bool() const 00539 { 00540 return m_it; 00541 } 00542 00543 inline int GoUctBoard::AdjacentBlocks(SgPoint point, int maxLib, 00544 SgPoint anchors[], int maxAnchors) const 00545 { 00546 SG_DEBUG_ONLY(maxAnchors); 00547 SG_ASSERT(Occupied(point)); 00548 const SgBlackWhite other = SgOppBW(GetStone(point)); 00549 int n = 0; 00550 SgReserveMarker reserve(m_marker); 00551 SG_UNUSED(reserve); 00552 m_marker.Clear(); 00553 for (StoneIterator it(*this, point); it; ++it) 00554 { 00555 if (NumNeighbors(*it, other) > 0) 00556 { 00557 SgPoint p = *it; 00558 if (IsColor(p - SG_NS, other) 00559 && m_marker.NewMark(Anchor(p - SG_NS)) 00560 && AtMostNumLibs(p - SG_NS, maxLib)) 00561 anchors[n++] = Anchor(p - SG_NS); 00562 if (IsColor(p - SG_WE, other) 00563 && m_marker.NewMark(Anchor(p - SG_WE)) 00564 && AtMostNumLibs(p - SG_WE, maxLib)) 00565 anchors[n++] = Anchor(p - SG_WE); 00566 if (IsColor(p + SG_WE, other) 00567 && m_marker.NewMark(Anchor(p + SG_WE)) 00568 && AtMostNumLibs(p + SG_WE, maxLib)) 00569 anchors[n++] = Anchor(p + SG_WE); 00570 if (IsColor(p + SG_NS, other) 00571 && m_marker.NewMark(Anchor(p + SG_NS)) 00572 && AtMostNumLibs(p + SG_NS, maxLib)) 00573 anchors[n++] = Anchor(p + SG_NS); 00574 } 00575 }; 00576 // Detect array overflow. 00577 SG_ASSERT(n < maxAnchors); 00578 anchors[n] = SG_ENDPOINT; 00579 return n; 00580 } 00581 00582 inline SgPoint GoUctBoard::Anchor(SgPoint p) const 00583 { 00584 SG_ASSERT(Occupied(p)); 00585 return m_block[p]->m_anchor; 00586 } 00587 00588 inline bool GoUctBoard::AreInSameBlock(SgPoint p1, SgPoint p2) const 00589 { 00590 return Occupied(p1) && Occupied(p2) && Anchor(p1) == Anchor(p2); 00591 } 00592 00593 inline bool GoUctBoard::AtLeastNumLibs(SgPoint block, int n) const 00594 { 00595 return NumLiberties(block) >= n; 00596 } 00597 00598 inline bool GoUctBoard::AtMostNumLibs(SgPoint block, int n) const 00599 { 00600 return NumLiberties(block) <= n; 00601 } 00602 00603 inline const GoPointList& GoUctBoard::CapturedStones() const 00604 { 00605 return m_capturedStones; 00606 } 00607 00608 inline bool GoUctBoard::CapturingMove() const 00609 { 00610 return ! m_capturedStones.IsEmpty(); 00611 } 00612 00613 inline int GoUctBoard::FirstBoardPoint() const 00614 { 00615 return m_const.FirstBoardPoint(); 00616 } 00617 00618 inline const SgBoardConst& GoUctBoard::BoardConst() const 00619 { 00620 return m_const; 00621 } 00622 00623 inline SgPoint GoUctBoard::Get2ndLastMove() const 00624 { 00625 return m_secondLastMove; 00626 } 00627 00628 inline SgBoardColor GoUctBoard::GetColor(SgPoint p) const 00629 { 00630 return m_color[p]; 00631 } 00632 00633 inline SgPoint GoUctBoard::GetLastMove() const 00634 { 00635 return m_lastMove; 00636 } 00637 00638 inline SgBlackWhite GoUctBoard::GetStone(SgPoint p) const 00639 { 00640 SG_ASSERT(Occupied(p)); 00641 return m_color[p]; 00642 } 00643 00644 inline bool GoUctBoard::HasDiagonals(SgPoint p, SgBoardColor c) const 00645 { 00646 return (IsColor(p - SG_NS - SG_WE, c) 00647 || IsColor(p - SG_NS + SG_WE, c) 00648 || IsColor(p + SG_NS - SG_WE, c) 00649 || IsColor(p + SG_NS + SG_WE, c)); 00650 } 00651 00652 inline bool GoUctBoard::HasEmptyNeighbors(SgPoint p) const 00653 { 00654 return m_nuNeighborsEmpty[p] != 0; 00655 } 00656 00657 inline bool GoUctBoard::HasLiberties(SgPoint p) const 00658 { 00659 return NumLiberties(p) > 0; 00660 } 00661 00662 inline bool GoUctBoard::HasNeighbors(SgPoint p, SgBlackWhite c) const 00663 { 00664 return (m_nuNeighbors[c][p] > 0); 00665 } 00666 00667 inline bool GoUctBoard::HasNeighborsOrDiags(SgPoint p, SgBlackWhite c) const 00668 { 00669 return HasNeighbors(p, c) || HasDiagonals(p, c); 00670 } 00671 00672 inline bool GoUctBoard::InAtari(SgPoint p) const 00673 { 00674 SG_ASSERT(Occupied(p)); 00675 return AtMostNumLibs(p, 1); 00676 } 00677 00678 inline bool GoUctBoard::IsInBlock(SgPoint p, SgPoint anchor) const 00679 { 00680 SG_ASSERT(Occupied(anchor)); 00681 const Block* b = m_block[p]; 00682 return (b != 0 && b->m_anchor == anchor); 00683 } 00684 00685 inline bool GoUctBoard::IsLibertyOfBlock(SgPoint p, SgPoint anchor) const 00686 { 00687 SG_ASSERT(IsEmpty(p)); 00688 SG_ASSERT(Occupied(anchor)); 00689 SG_ASSERT(Anchor(anchor) == anchor); 00690 const Block* b = m_block[anchor]; 00691 if (m_nuNeighbors[b->m_color][p] == 0) 00692 return false; 00693 return ( m_block[p - SG_NS] == b 00694 || m_block[p - SG_WE] == b 00695 || m_block[p + SG_WE] == b 00696 || m_block[p + SG_NS] == b); 00697 } 00698 00699 inline bool GoUctBoard::CanCapture(SgPoint p, SgBlackWhite c) const 00700 { 00701 SgBlackWhite opp = SgOppBW(c); 00702 for (SgNb4Iterator nb(p); nb; ++nb) 00703 if (IsColor(*nb, opp) && AtMostNumLibs(*nb, 1)) 00704 return true; 00705 return false; 00706 } 00707 00708 inline bool GoUctBoard::IsSuicide(SgPoint p, SgBlackWhite toPlay) const 00709 { 00710 if (HasEmptyNeighbors(p)) 00711 return false; 00712 SgBlackWhite opp = SgOppBW(toPlay); 00713 for (SgNb4Iterator it(p); it; ++it) 00714 { 00715 if (IsBorder(*it)) 00716 continue; 00717 SgEmptyBlackWhite c = GetColor(*it); 00718 if (c == toPlay && NumLiberties(*it) > 1) 00719 return false; 00720 if (c == opp && NumLiberties(*it) == 1) 00721 return false; 00722 } 00723 return true; 00724 } 00725 00726 inline bool GoUctBoard::IsBorder(SgPoint p) const 00727 { 00728 SG_ASSERT(p != SG_PASS); 00729 return m_isBorder[p]; 00730 } 00731 00732 inline bool GoUctBoard::IsColor(SgPoint p, int c) const 00733 { 00734 SG_ASSERT(p != SG_PASS); 00735 SG_ASSERT_EBW(c); 00736 return m_color[p] == c; 00737 } 00738 00739 inline bool GoUctBoard::IsEmpty(SgPoint p) const 00740 { 00741 SG_ASSERT(p != SG_PASS); 00742 return m_color[p] == SG_EMPTY; 00743 } 00744 00745 inline bool GoUctBoard::IsLegal(int p, SgBlackWhite player) const 00746 { 00747 SG_ASSERT_BW(player); 00748 if (p == SG_PASS) 00749 return true; 00750 SG_ASSERT(SgPointUtil::InBoardRange(p)); 00751 if (! IsEmpty(p)) 00752 return false; 00753 // Suicide 00754 if (IsSuicide(p, player)) 00755 return false; 00756 // Repetition 00757 if (p == m_koPoint && m_toPlay == player) 00758 return false; 00759 return true; 00760 } 00761 00762 inline bool GoUctBoard::IsLegal(int p) const 00763 { 00764 return IsLegal(p, ToPlay()); 00765 } 00766 00767 inline bool GoUctBoard::IsSingleStone(SgPoint p) const 00768 { 00769 return (Occupied(p) && NumNeighbors(p, GetColor(p)) == 0); 00770 } 00771 00772 inline bool GoUctBoard::IsSuicide(SgPoint p) const 00773 { 00774 return IsSuicide(p, ToPlay()); 00775 } 00776 00777 inline bool GoUctBoard::IsValidPoint(SgPoint p) const 00778 { 00779 return SgPointUtil::InBoardRange(p) && ! IsBorder(p); 00780 } 00781 00782 inline int GoUctBoard::LastBoardPoint() const 00783 { 00784 return m_const.LastBoardPoint(); 00785 } 00786 00787 inline int GoUctBoard::Left(SgPoint p) const 00788 { 00789 return m_const.Left(p); 00790 } 00791 00792 inline SgGrid GoUctBoard::Line(SgPoint p) const 00793 { 00794 return m_const.Line(p); 00795 } 00796 00797 inline void GoUctBoard::NeighborBlocks(SgPoint p, SgBlackWhite c, int maxLib, 00798 SgPoint anchors[]) const 00799 { 00800 SG_ASSERT(IsEmpty(p)); 00801 SgReserveMarker reserve(m_marker); 00802 SG_UNUSED(reserve); 00803 m_marker.Clear(); 00804 int i = 0; 00805 if (NumNeighbors(p, c) > 0) 00806 { 00807 if (IsColor(p - SG_NS, c) && m_marker.NewMark(Anchor(p - SG_NS)) 00808 && AtMostNumLibs(p - SG_NS, maxLib)) 00809 anchors[i++] = Anchor(p - SG_NS); 00810 if (IsColor(p - SG_WE, c) && m_marker.NewMark(Anchor(p - SG_WE)) 00811 && AtMostNumLibs(p - SG_WE, maxLib)) 00812 anchors[i++] = Anchor(p - SG_WE); 00813 if (IsColor(p + SG_WE, c) && m_marker.NewMark(Anchor(p + SG_WE)) 00814 && AtMostNumLibs(p + SG_WE, maxLib)) 00815 anchors[i++] = Anchor(p + SG_WE); 00816 if (IsColor(p + SG_NS, c) && m_marker.NewMark(Anchor(p + SG_NS)) 00817 && AtMostNumLibs(p + SG_NS, maxLib)) 00818 anchors[i++] = Anchor(p + SG_NS); 00819 } 00820 anchors[i] = SG_ENDPOINT; 00821 } 00822 00823 inline int GoUctBoard::Num8Neighbors(SgPoint p, SgBlackWhite c) const 00824 { 00825 return NumNeighbors(p, c) + NumDiagonals(p, c); 00826 } 00827 00828 inline int GoUctBoard::Num8EmptyNeighbors(SgPoint p) const 00829 { 00830 return NumEmptyNeighbors(p) + NumEmptyDiagonals(p); 00831 } 00832 00833 inline int GoUctBoard::NuCapturedStones() const 00834 { 00835 return m_capturedStones.Length(); 00836 } 00837 00838 inline int GoUctBoard::NumDiagonals(SgPoint p, SgBoardColor c) const 00839 { 00840 int n = 0; 00841 if (IsColor(p - SG_NS - SG_WE, c)) 00842 ++n; 00843 if (IsColor(p - SG_NS + SG_WE, c)) 00844 ++n; 00845 if (IsColor(p + SG_NS - SG_WE, c)) 00846 ++n; 00847 if (IsColor(p + SG_NS + SG_WE, c)) 00848 ++n; 00849 return n; 00850 } 00851 00852 inline int GoUctBoard::NumEmptyDiagonals(SgPoint p) const 00853 { 00854 return NumDiagonals(p, SG_EMPTY); 00855 } 00856 00857 inline int GoUctBoard::NumEmptyNeighbors(SgPoint p) const 00858 { 00859 return m_nuNeighborsEmpty[p]; 00860 } 00861 00862 inline int GoUctBoard::NumLiberties(SgPoint p) const 00863 { 00864 SG_ASSERT(IsValidPoint(p)); 00865 SG_ASSERT(Occupied(p)); 00866 return m_block[p]->m_liberties.Length(); 00867 } 00868 00869 inline int GoUctBoard::NumNeighbors(SgPoint p, SgBlackWhite c) const 00870 { 00871 return m_nuNeighbors[c][p]; 00872 } 00873 00874 inline int GoUctBoard::NumPrisoners(SgBlackWhite color) const 00875 { 00876 return m_prisoners[color]; 00877 } 00878 00879 inline int GoUctBoard::NumStones(SgPoint block) const 00880 { 00881 SG_ASSERT(Occupied(block)); 00882 return m_block[block]->m_stones.Length(); 00883 } 00884 00885 inline bool GoUctBoard::Occupied(SgPoint p) const 00886 { 00887 return (m_block[p] != 0); 00888 } 00889 00890 inline bool GoUctBoard::OccupiedInAtari(SgPoint p) const 00891 { 00892 const Block* b = m_block[p]; 00893 return (b != 0 && b->m_liberties.Length() <= 1); 00894 } 00895 00896 inline SgBlackWhite GoUctBoard::Opponent() const 00897 { 00898 return SgOppBW(m_toPlay); 00899 } 00900 00901 inline SgGrid GoUctBoard::Pos(SgPoint p) const 00902 { 00903 return m_const.Pos(p); 00904 } 00905 00906 inline int GoUctBoard::Right(SgPoint p) const 00907 { 00908 return m_const.Right(p); 00909 } 00910 00911 inline int GoUctBoard::Side(SgPoint p, int index) const 00912 { 00913 return m_const.Side(p, index); 00914 } 00915 00916 inline SgGrid GoUctBoard::Size() const 00917 { 00918 return m_size; 00919 } 00920 00921 inline SgPoint GoUctBoard::TheLiberty(SgPoint p) const 00922 { 00923 SG_ASSERT(Occupied(p)); 00924 SG_ASSERT(NumLiberties(p) == 1); 00925 return m_block[p]->m_liberties[0]; 00926 } 00927 00928 inline SgBlackWhite GoUctBoard::ToPlay() const 00929 { 00930 return m_toPlay; 00931 } 00932 00933 inline int GoUctBoard::Up(SgPoint p) const 00934 { 00935 return m_const.Up(p); 00936 } 00937 00938 //---------------------------------------------------------------------------- 00939 00940 #endif // GOUCT_BOARD_H 00941