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