00001 //---------------------------------------------------------------------------- 00002 /** @file GoUctPatterns.h 00003 */ 00004 //---------------------------------------------------------------------------- 00005 00006 #ifndef GOUCT_PATTERNS_H 00007 #define GOUCT_PATTERNS_H 00008 00009 #include "GoBoard.h" 00010 #include "GoBoardUtil.h" 00011 #include "SgBoardColor.h" 00012 #include "SgBWArray.h" 00013 #include "SgPoint.h" 00014 00015 //---------------------------------------------------------------------------- 00016 00017 /** Some hard-coded pattern matching routines to match patterns used by MoGo. 00018 See <a href="http://hal.inria.fr/docs/00/11/72/66/PDF/MoGoReport.pdf"> 00019 Modification of UCT with Patterns in Monte-Carlo Go</a>. 00020 00021 The move is always in the center of the pattern or at the middle edge 00022 point (lower line) for edge patterns. The patterns are matched for both 00023 colors, unless specified otherwise. Notation: 00024 @verbatim 00025 O White x = Black or Empty 00026 X = Black o = White or Empty 00027 . = Empty B = Black to Play 00028 ? = Don't care W = White to Play 00029 @endverbatim 00030 00031 Patterns for Hane. <br> 00032 True is returned if any pattern is matched. 00033 @verbatim 00034 X O X X O . X O ? X O O 00035 . . . . . . X . . . . . 00036 ? ? ? ? . ? ? . ? ? . ? B 00037 @endverbatim 00038 00039 Patterns for Cut1. <br> 00040 True is returned if the first pattern is matched, but not the next two. 00041 @verbatim 00042 X O ? X O ? X O ? 00043 O . ? O . O O . . 00044 ? ? ? ? . ? ? O ? 00045 @endverbatim 00046 00047 Pattern for Cut2. 00048 @verbatim 00049 ? X ? 00050 O . O 00051 x x x 00052 @endverbatim 00053 00054 Pattern for Edge. <br> 00055 True is returned if any pattern is matched. 00056 @verbatim 00057 X . ? ? X ? ? X O ? X O ? X O 00058 O . ? o . O ? . ? B ? . o W O . X W 00059 @endverbatim 00060 */ 00061 template<class BOARD> 00062 class GoUctPatterns 00063 { 00064 public: 00065 GoUctPatterns(const BOARD& bd); 00066 00067 /** Match any of the patterns. */ 00068 bool MatchAny(SgPoint p) const; 00069 00070 private: 00071 /** 3^5 = size of edge pattern table */ 00072 static const int GOUCT_POWER3_5 = 3 * 3 * 3 * 3 * 3; 00073 00074 /** 3^8 = size of center pattern table. */ 00075 static const int GOUCT_POWER3_8 = 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3; 00076 00077 /** See m_edgeTable. */ 00078 typedef SgArray<bool, GOUCT_POWER3_5> GoUctEdgePatternTable; 00079 00080 /** See m_table. */ 00081 typedef SgArray<bool, GOUCT_POWER3_8> GoUctPatternTable; 00082 00083 const BOARD& m_bd; 00084 00085 /** lookup table for 8-neighborhood of a move candidate */ 00086 SgBWArray<GoUctPatternTable> m_table; 00087 00088 /** lookup table on the edge of board */ 00089 SgBWArray<GoUctEdgePatternTable> m_edgeTable; 00090 00091 static bool CheckCut1(const GoBoard& bd, SgPoint p, SgBlackWhite c, 00092 int cDir, int otherDir); 00093 00094 static bool CheckCut2(const GoBoard& bd, SgPoint p, const SgBlackWhite c, 00095 int cDir, int otherDir); 00096 00097 static bool CheckHane1(const GoBoard& bd, SgPoint p, SgBlackWhite c, 00098 SgBlackWhite opp, int cDir, int otherDir); 00099 00100 static int CodeOf8Neighbors(const BOARD& bd, SgPoint p); 00101 00102 static int CodeOfEdgeNeighbors(const BOARD& bd, SgPoint p); 00103 00104 static int EdgeDirection(GoBoard& bd, SgPoint p, int index); 00105 00106 static int EBWCodeOfPoint(const BOARD& bd, SgPoint p); 00107 00108 static int FindDir(const GoBoard& bd, SgPoint p, SgBlackWhite c); 00109 00110 static void InitCenterPatternTable(SgBWArray<GoUctPatternTable>& table); 00111 00112 static void InitEdgePatternTable(SgBWArray<GoUctEdgePatternTable>& 00113 edgeTable); 00114 00115 static bool MatchCut(const GoBoard& bd, SgPoint p); 00116 00117 static bool MatchEdge(const GoBoard& bd, SgPoint p, const int nuBlack, 00118 const int nuWhite); 00119 00120 static bool MatchHane(const GoBoard& bd, SgPoint p, const int nuBlack, 00121 const int nuWhite); 00122 00123 static bool MatchAnyPattern(const GoBoard& bd, SgPoint p); 00124 00125 static int OtherDir(int dir); 00126 00127 static int SetupCodedEdgePosition(GoBoard& bd, int code); 00128 00129 static int SetupCodedPosition(GoBoard& bd, int code); 00130 00131 /** Match any of the center patterns. */ 00132 bool MatchAnyCenter(SgPoint p) const; 00133 00134 /** Match any of the edge patterns. */ 00135 bool MatchAnyEdge(SgPoint p) const; 00136 }; 00137 00138 template<class BOARD> 00139 GoUctPatterns<BOARD>::GoUctPatterns(const BOARD& bd) 00140 : m_bd(bd) 00141 { 00142 InitCenterPatternTable(m_table); 00143 InitEdgePatternTable(m_edgeTable); 00144 } 00145 00146 template<class BOARD> 00147 bool GoUctPatterns<BOARD>::CheckHane1(const GoBoard& bd, SgPoint p, 00148 SgBlackWhite c, SgBlackWhite opp, 00149 int cDir, int otherDir) 00150 { 00151 return bd.IsColor(p + cDir, c) 00152 && bd.IsColor(p + cDir + otherDir, opp) 00153 && bd.IsColor(p + cDir - otherDir, opp) 00154 && bd.IsEmpty(p + otherDir) 00155 && bd.IsEmpty(p - otherDir) 00156 ; 00157 } 00158 00159 template<class BOARD> 00160 bool GoUctPatterns<BOARD>::CheckCut1(const GoBoard& bd, SgPoint p, 00161 SgBlackWhite c, int cDir, int otherDir) 00162 { 00163 SG_ASSERT_BW(c); 00164 return bd.IsColor(p + otherDir, c) 00165 && bd.IsColor(p + cDir + otherDir, SgOppBW(c)); 00166 } 00167 00168 template<class BOARD> 00169 bool GoUctPatterns<BOARD>::CheckCut2(const GoBoard& bd, SgPoint p, 00170 const SgBlackWhite c, int cDir, 00171 int otherDir) 00172 { 00173 SG_ASSERT_BW(c); 00174 SG_ASSERT(bd.IsColor(p + cDir, c)); 00175 const SgBlackWhite opp = SgOppBW(c); 00176 return bd.IsColor(p - cDir, c) 00177 && ( ( bd.IsColor(p + otherDir, opp) 00178 && ! bd.IsColor(p - otherDir + cDir, c) 00179 && ! bd.IsColor(p - otherDir - cDir, c) 00180 ) 00181 || 00182 ( bd.IsColor(p - otherDir, opp) 00183 && ! bd.IsColor(p + otherDir + cDir, c) 00184 && ! bd.IsColor(p + otherDir - cDir, c) 00185 ) 00186 ); 00187 } 00188 00189 template<class BOARD> 00190 inline int GoUctPatterns<BOARD>::CodeOf8Neighbors(const BOARD& bd, SgPoint p) 00191 { 00192 SG_ASSERT(bd.Line(p) > 1); 00193 int code = (((((( EBWCodeOfPoint(bd, p - SG_NS - SG_WE) * 3 00194 + EBWCodeOfPoint(bd, p - SG_NS)) * 3 00195 + EBWCodeOfPoint(bd, p - SG_NS + SG_WE)) * 3 00196 + EBWCodeOfPoint(bd, p - SG_WE)) * 3 00197 + EBWCodeOfPoint(bd, p + SG_WE)) * 3 00198 + EBWCodeOfPoint(bd, p + SG_NS - SG_WE)) * 3 00199 + EBWCodeOfPoint(bd, p + SG_NS)) * 3 00200 + EBWCodeOfPoint(bd, p + SG_NS + SG_WE); 00201 SG_ASSERT(code >= 0); 00202 SG_ASSERT(code < GOUCT_POWER3_8); 00203 return code; 00204 } 00205 00206 template<class BOARD> 00207 inline int GoUctPatterns<BOARD>::CodeOfEdgeNeighbors(const BOARD& bd, 00208 SgPoint p) 00209 { 00210 SG_ASSERT(bd.Line(p) == 1); 00211 SG_ASSERT(bd.Pos(p) > 1); 00212 const int up = bd.Up(p); 00213 const int other = OtherDir(up); 00214 int code = (((EBWCodeOfPoint(bd, p + other) * 3 00215 + EBWCodeOfPoint(bd, p + up + other)) * 3 00216 + EBWCodeOfPoint(bd, p + up)) * 3 00217 + EBWCodeOfPoint(bd, p + up - other)) * 3 00218 + EBWCodeOfPoint(bd, p - other); 00219 SG_ASSERT(code >= 0); 00220 SG_ASSERT(code < GOUCT_POWER3_5); 00221 return code; 00222 } 00223 00224 template<class BOARD> 00225 inline int GoUctPatterns<BOARD>::EBWCodeOfPoint(const BOARD& bd, SgPoint p) 00226 { 00227 SG_ASSERT(bd.IsValidPoint(p)); 00228 BOOST_STATIC_ASSERT(SG_BLACK == 0); 00229 BOOST_STATIC_ASSERT(SG_WHITE == 1); 00230 BOOST_STATIC_ASSERT(SG_EMPTY == 2); 00231 return bd.GetColor(p); 00232 } 00233 00234 template<class BOARD> 00235 int GoUctPatterns<BOARD>::EdgeDirection(GoBoard& bd, SgPoint p, int index) 00236 { 00237 const int up = bd.Up(p); 00238 switch (index) 00239 { 00240 case 0: 00241 return OtherDir(up); 00242 case 1: 00243 return up + OtherDir(up); 00244 case 2: 00245 return up; 00246 case 3: 00247 return up - OtherDir(up); 00248 default: 00249 SG_ASSERT(index == 4); 00250 return - OtherDir(up); 00251 } 00252 } 00253 00254 /** Find direction of a neighboring stone in color c */ 00255 template<class BOARD> 00256 int GoUctPatterns<BOARD>::FindDir(const GoBoard& bd, SgPoint p, 00257 SgBlackWhite c) 00258 { 00259 if (bd.IsColor(p + SG_NS, c)) 00260 return SG_NS; 00261 if (bd.IsColor(p - SG_NS, c)) 00262 return -SG_NS; 00263 if (bd.IsColor(p + SG_WE, c)) 00264 return SG_WE; 00265 SG_ASSERT(bd.IsColor(p - SG_WE, c)); 00266 return -SG_WE; 00267 } 00268 00269 template<class BOARD> 00270 void GoUctPatterns<BOARD>::InitEdgePatternTable( 00271 SgBWArray<GoUctEdgePatternTable>& edgeTable) 00272 { 00273 GoBoard bd(5); 00274 const SgPoint p = SgPointUtil::Pt(1, 3); 00275 for (int i = 0; i < GOUCT_POWER3_5; ++i) 00276 { 00277 int count = SetupCodedEdgePosition(bd, i); 00278 for(SgBWIterator it; it; ++it) 00279 { 00280 bd.SetToPlay(*it); 00281 edgeTable[*it][i] = MatchAnyPattern(bd, p) ? 1 : 0; 00282 } 00283 while (count-- > 0) 00284 bd.Undo(); 00285 } 00286 } 00287 00288 template<class BOARD> 00289 void GoUctPatterns<BOARD>::InitCenterPatternTable( 00290 SgBWArray<GoUctPatternTable>& table) 00291 { 00292 GoBoard bd(5); 00293 const SgPoint p = SgPointUtil::Pt(3, 3); 00294 for (int i = 0; i < GOUCT_POWER3_8; ++i) 00295 { 00296 int count = SetupCodedPosition(bd, i); 00297 for(SgBWIterator it; it; ++it) 00298 { 00299 bd.SetToPlay(*it); 00300 table[*it][i] = MatchAnyPattern(bd, p) ? 1 : 0; 00301 } 00302 while (count-- > 0) 00303 bd.Undo(); 00304 } 00305 } 00306 00307 template<class BOARD> 00308 bool GoUctPatterns<BOARD>::MatchCut(const GoBoard& bd, SgPoint p) 00309 { 00310 if (bd.Num8EmptyNeighbors(p) > 6) 00311 return false; 00312 00313 const int nuEmpty = bd.NumEmptyNeighbors(p); 00314 //cut1 00315 const SgEmptyBlackWhite c1 = bd.GetColor(p + SG_NS); 00316 if ( c1 != SG_EMPTY 00317 && bd.NumNeighbors(p, c1) >= 2 00318 && ! (bd.NumNeighbors(p, c1) == 3 && nuEmpty == 1) 00319 && ( CheckCut1(bd, p, c1, SG_NS, SG_WE) 00320 || CheckCut1(bd, p, c1, SG_NS, -SG_WE) 00321 ) 00322 ) 00323 return true; 00324 const SgEmptyBlackWhite c2 = bd.GetColor(p - SG_NS); 00325 if ( c2 != SG_EMPTY 00326 && bd.NumNeighbors(p, c2) >= 2 00327 && ! (bd.NumNeighbors(p, c2) == 3 && nuEmpty == 1) 00328 && ( CheckCut1(bd, p, c2, -SG_NS, SG_WE) 00329 || CheckCut1(bd, p, c2, -SG_NS, -SG_WE) 00330 ) 00331 ) 00332 return true; 00333 //cut2 00334 if ( c1 != SG_EMPTY 00335 && bd.NumNeighbors(p, c1) == 2 00336 && bd.NumNeighbors(p, SgOppBW(c1)) > 0 00337 && bd.NumDiagonals(p, c1) <= 2 00338 && CheckCut2(bd, p, c1, SG_NS, SG_WE) 00339 ) 00340 return true; 00341 const SgEmptyBlackWhite c3 = bd.GetColor(p + SG_WE); 00342 if ( c3 != SG_EMPTY 00343 && bd.NumNeighbors(p, c3) == 2 00344 && bd.NumNeighbors(p, SgOppBW(c3)) > 0 00345 && bd.NumDiagonals(p, c3) <= 2 00346 && CheckCut2(bd, p, c3, SG_WE, SG_NS) 00347 ) 00348 return true; 00349 return false; 00350 } 00351 00352 template<class BOARD> 00353 bool GoUctPatterns<BOARD>::MatchEdge(const GoBoard& bd, SgPoint p, 00354 const int nuBlack, const int nuWhite) 00355 { 00356 const int up = bd.Up(p); 00357 const int side = OtherDir(up); 00358 const int nuEmpty = bd.NumEmptyNeighbors(p); 00359 const SgEmptyBlackWhite upColor = bd.GetColor(p + up); 00360 // edge1 00361 if ( nuEmpty > 0 00362 && (nuBlack > 0 || nuWhite > 0) 00363 && upColor == SG_EMPTY 00364 ) 00365 { 00366 const SgEmptyBlackWhite c1 = bd.GetColor(p + side); 00367 if (c1 != SG_EMPTY && bd.GetColor(p + side + up) == SgOppBW(c1)) 00368 return true; 00369 const SgEmptyBlackWhite c2 = bd.GetColor(p - side); 00370 if (c2 != SG_EMPTY && bd.GetColor(p - side + up) == SgOppBW(c2)) 00371 return true; 00372 } 00373 00374 // edge2 00375 if ( upColor != SG_EMPTY 00376 && ( (upColor == SG_BLACK && nuBlack == 1 && nuWhite > 0) 00377 || (upColor == SG_WHITE && nuWhite == 1 && nuBlack > 0) 00378 ) 00379 ) 00380 return true; 00381 00382 const SgBlackWhite toPlay = bd.ToPlay(); 00383 // edge3 00384 if ( upColor == toPlay 00385 && bd.NumDiagonals(p, SgOppBW(upColor)) > 0 00386 ) 00387 return true; 00388 00389 // edge4 00390 if ( upColor == SgOppBW(toPlay) 00391 && bd.NumNeighbors(p, upColor) <= 2 00392 && bd.NumDiagonals(p, toPlay) > 0 00393 ) 00394 { 00395 if ( bd.GetColor(p + side + up) == toPlay 00396 && bd.GetColor(p + side) != upColor 00397 ) 00398 return true; 00399 if ( bd.GetColor(p - side + up) == toPlay 00400 && bd.GetColor(p - side) != upColor 00401 ) 00402 return true; 00403 } 00404 // edge5 00405 if ( upColor == SgOppBW(toPlay) 00406 && bd.NumNeighbors(p, upColor) == 2 00407 && bd.NumNeighbors(p, toPlay) == 1 00408 ) 00409 { 00410 if ( bd.GetColor(p + side + up) == toPlay 00411 && bd.GetColor(p + side) == upColor 00412 ) 00413 return true; 00414 if ( bd.GetColor(p - side + up) == toPlay 00415 && bd.GetColor(p - side) == upColor 00416 ) 00417 return true; 00418 } 00419 return false; 00420 } 00421 00422 template<class BOARD> 00423 bool GoUctPatterns<BOARD>::MatchHane(const GoBoard& bd, SgPoint p, 00424 const int nuBlack, const int nuWhite) 00425 { 00426 const int nuEmpty = bd.NumEmptyNeighbors(p); 00427 if (nuEmpty < 2 || nuEmpty > 3) 00428 return false; 00429 if ( (nuBlack < 1 || nuBlack > 2) 00430 && (nuWhite < 1 || nuWhite > 2) 00431 ) 00432 return false; 00433 if (nuEmpty == 2) // hane3 pattern 00434 { 00435 if (nuBlack == 1 && nuWhite == 1) 00436 { 00437 const int dirB = FindDir(bd, p, SG_BLACK); 00438 const int dirW = FindDir(bd, p, SG_WHITE); 00439 if (! bd.IsEmpty(p + dirB + dirW)) 00440 return true; 00441 } 00442 } 00443 else if (nuEmpty == 3) // hane2 or hane4 00444 { 00445 SG_ASSERT(nuBlack + nuWhite == 1); 00446 const SgBlackWhite col = (nuBlack == 1) ? SG_BLACK : SG_WHITE; 00447 const SgBlackWhite opp = SgOppBW(col); 00448 const int dir = FindDir(bd, p, col); 00449 const int otherDir = OtherDir(dir); 00450 if ( bd.IsEmpty(p + dir + otherDir) 00451 && bd.IsColor(p + dir - otherDir, opp) 00452 ) 00453 return true; // hane2 00454 if ( bd.IsEmpty(p + dir - otherDir) 00455 && bd.IsColor(p + dir + otherDir, opp) 00456 ) 00457 return true; // hane2 00458 if (bd.ToPlay() == opp) 00459 { 00460 const SgEmptyBlackWhite c1 = bd.GetColor(p + dir + otherDir); 00461 if (c1 != SG_EMPTY) 00462 { 00463 const SgEmptyBlackWhite c2 = 00464 bd.GetColor(p + dir - otherDir); 00465 if (SgOppBW(c1) == c2) 00466 return true; // hane4 00467 } 00468 } 00469 } 00470 00471 // hane1 pattern 00472 const int nuBlackDiag = bd.NumDiagonals(p, SG_BLACK); 00473 if ( nuBlackDiag >= 2 00474 && nuWhite > 0 00475 && ( CheckHane1(bd, p, SG_WHITE, SG_BLACK, SG_NS, SG_WE) 00476 || CheckHane1(bd, p, SG_WHITE, SG_BLACK, -SG_NS, SG_WE) 00477 || CheckHane1(bd, p, SG_WHITE, SG_BLACK, SG_WE, SG_NS) 00478 || CheckHane1(bd, p, SG_WHITE, SG_BLACK, -SG_WE, SG_NS) 00479 ) 00480 ) 00481 return true; 00482 const int nuWhiteDiag = bd.NumDiagonals(p, SG_WHITE); 00483 if ( nuWhiteDiag >= 2 00484 && nuBlack > 0 00485 && ( CheckHane1(bd, p, SG_BLACK, SG_WHITE, SG_NS, SG_WE) 00486 || CheckHane1(bd, p, SG_BLACK, SG_WHITE, -SG_NS, SG_WE) 00487 || CheckHane1(bd, p, SG_BLACK, SG_WHITE, SG_WE, SG_NS) 00488 || CheckHane1(bd, p, SG_BLACK, SG_WHITE, -SG_WE, SG_NS) 00489 ) 00490 ) 00491 return true; 00492 return false; 00493 } 00494 00495 template<class BOARD> 00496 inline bool GoUctPatterns<BOARD>::MatchAnyCenter(SgPoint p) const 00497 { 00498 return m_table[m_bd.ToPlay()][CodeOf8Neighbors(m_bd, p)]; 00499 } 00500 00501 template<class BOARD> 00502 inline bool GoUctPatterns<BOARD>::MatchAnyEdge(SgPoint p) const 00503 { 00504 return m_edgeTable[m_bd.ToPlay()][CodeOfEdgeNeighbors(m_bd, p)]; 00505 } 00506 00507 template<class BOARD> 00508 inline bool GoUctPatterns<BOARD>::MatchAny(SgPoint p) const 00509 { 00510 // Quick refutation using the incremental neighbor counts of the board: 00511 // all patterns have at least one adjacent stone 00512 if ( m_bd.NumNeighbors(p, SG_BLACK) == 0 00513 && m_bd.NumNeighbors(p, SG_WHITE) == 0 00514 ) 00515 return false; 00516 if (m_bd.Line(p) > 1) 00517 return MatchAnyCenter(p); 00518 else if (m_bd.Pos(p) > 1) 00519 return MatchAnyEdge(p); 00520 else 00521 return false; 00522 } 00523 00524 /** Procedural matching function - used to initialize the table. */ 00525 template<class BOARD> 00526 bool GoUctPatterns<BOARD>::MatchAnyPattern(const GoBoard& bd, SgPoint p) 00527 { 00528 SG_ASSERT(bd.IsEmpty(p)); 00529 const int nuBlack = bd.NumNeighbors(p, SG_BLACK); 00530 const int nuWhite = bd.NumNeighbors(p, SG_WHITE); 00531 00532 // Quick refutation using the incremental neighbor counts of the board 00533 // All patterns have at least one adjacent stone 00534 if (nuBlack == 0 && nuWhite == 0) 00535 return false; 00536 00537 // Filter edge moves on (1,1) points in corners 00538 if (bd.Pos(p) == 1) 00539 return false; 00540 if (bd.Line(p) == 1) 00541 return MatchEdge(bd, p, nuBlack, nuWhite); 00542 else // Center 00543 return MatchHane(bd, p, nuBlack, nuWhite) 00544 || MatchCut(bd, p); 00545 } 00546 00547 template<class BOARD> 00548 inline int GoUctPatterns<BOARD>::OtherDir(int dir) 00549 { 00550 if (dir == SG_NS || dir == -SG_NS) 00551 return SG_WE; 00552 return SG_NS; 00553 } 00554 00555 template<class BOARD> 00556 int GoUctPatterns<BOARD>::SetupCodedEdgePosition(GoBoard& bd, int code) 00557 { 00558 const SgPoint p = SgPointUtil::Pt(1, 3); 00559 int count = 0; 00560 for (int i = 4; i >= 0; --i) // decoding gives points in reverse order 00561 { 00562 const SgPoint nb = p + EdgeDirection(bd, p, i); 00563 int c = code % 3; 00564 code /= 3; 00565 if (c != SG_EMPTY) 00566 { 00567 ++count; 00568 bd.Play(nb, c); 00569 } 00570 } 00571 return count; 00572 } 00573 00574 template<class BOARD> 00575 int GoUctPatterns<BOARD>::SetupCodedPosition(GoBoard& bd, int code) 00576 { 00577 const SgPoint p = SgPointUtil::Pt(3, 3); 00578 int count = 0; 00579 for (int i = 7; i >= 0; --i) // decoding gives points in reverse order 00580 { 00581 const SgPoint nb = p + SgNb8Iterator::Direction(i); 00582 int c = code % 3; 00583 code /= 3; 00584 if (c != SG_EMPTY) 00585 { 00586 ++count; 00587 bd.Play(nb, c); 00588 } 00589 } 00590 return count; 00591 } 00592 00593 //---------------------------------------------------------------------------- 00594 00595 #endif // GOUCT_PATTERNS_H