00001 //---------------------------------------------------------------------------- 00002 /** @file GoUctDefaultRootFilter.cpp 00003 See GoUctDefaultRootFilter.h 00004 */ 00005 //---------------------------------------------------------------------------- 00006 00007 #include "SgSystem.h" 00008 #include "GoUctDefaultRootFilter.h" 00009 00010 #include "GoBensonSolver.h" 00011 #include "GoBoard.h" 00012 #include "GoBoardUtil.h" 00013 #include "GoModBoard.h" 00014 #include "GoSafetySolver.h" 00015 #include "SgWrite.h" 00016 00017 using namespace std; 00018 00019 //---------------------------------------------------------------------------- 00020 00021 /** Return true, if point is on edge line and no stone is within a 00022 Manhattan distance of 4. 00023 */ 00024 bool IsEmptyEdge(const GoBoard& bd, SgPoint p) 00025 { 00026 if (bd.Occupied(p)) 00027 return false; 00028 int size = bd.Size(); 00029 int col = SgPointUtil::Col(p); 00030 int row = SgPointUtil::Row(p); 00031 if (! (col == 1 || col == size || row == 1 || row == size)) 00032 return false; 00033 for (int deltaCol = -4; deltaCol <= 4; ++deltaCol) 00034 for (int deltaRow = -4; deltaRow <= 4; ++deltaRow) 00035 { 00036 if (col + deltaCol < 1 || col + deltaCol > size 00037 || row + deltaRow < 1 || row + deltaRow > size 00038 || abs(deltaCol) + abs(deltaRow) > 4) 00039 continue; 00040 if (bd.Occupied(SgPointUtil::Pt(col + deltaCol, 00041 row + deltaRow))) 00042 return false; 00043 } 00044 return true; 00045 } 00046 00047 //---------------------------------------------------------------------------- 00048 00049 GoUctDefaultRootFilter::GoUctDefaultRootFilter(const GoBoard& bd) 00050 : m_bd(bd), 00051 m_checkLadders(true), 00052 m_minLadderLength(6) 00053 { 00054 } 00055 00056 vector<SgPoint> GoUctDefaultRootFilter::Get() 00057 { 00058 vector<SgPoint> rootFilter; 00059 SgBlackWhite toPlay = m_bd.ToPlay(); 00060 SgBlackWhite opp = SgOppBW(toPlay); 00061 00062 // Safe territory 00063 00064 GoModBoard modBoard(m_bd); 00065 GoBoard& bd = modBoard.Board(); 00066 00067 SgBWSet alternateSafe; 00068 bool isAllAlternateSafe = false; 00069 // Alternate safety is used to prune moves only in opponent territory 00070 // and only if everything is alive under alternate play. This ensures that 00071 // capturing moves that are not liberties of dead blocks and ko threats 00072 // will not be pruned. This alternate safety pruning is not going to 00073 // improve or worsen playing strength, but may cause earlier passes, 00074 // which is nice in games against humans 00075 GoSafetySolver safetySolver(bd); 00076 safetySolver.FindSafePoints(&alternateSafe); 00077 isAllAlternateSafe = (alternateSafe.Both() == bd.AllPoints()); 00078 00079 // Benson solver guarantees that capturing moves of dead blocks are 00080 // liberties of the dead blocks and that no move in Benson safe territory 00081 // is a ko threat 00082 GoBensonSolver bensonSolver(bd); 00083 SgBWSet unconditionalSafe; 00084 bensonSolver.FindSafePoints(&unconditionalSafe); 00085 00086 for (GoBoard::Iterator it(bd); it; ++it) 00087 { 00088 SgPoint p = *it; 00089 if (m_bd.IsLegal(p)) 00090 { 00091 bool isUnconditionalSafe = unconditionalSafe[toPlay].Contains(p); 00092 bool isUnconditionalSafeOpp = unconditionalSafe[opp].Contains(p); 00093 bool isAlternateSafeOpp = alternateSafe[opp].Contains(p); 00094 bool hasOppNeighbors = bd.HasNeighbors(p, opp); 00095 // Always generate capturing moves in own safe territory, even 00096 // if current rules do no use CaptureDead(), because the UCT 00097 // player always scores with Tromp-Taylor after two passes in the 00098 // in-tree phase 00099 if ((isAllAlternateSafe && isAlternateSafeOpp) 00100 || isUnconditionalSafeOpp 00101 || (isUnconditionalSafe && ! hasOppNeighbors)) 00102 rootFilter.push_back(p); 00103 } 00104 } 00105 00106 // Loosing ladder defense moves 00107 if (m_checkLadders) 00108 for (GoBlockIterator it(m_bd); it; ++it) 00109 { 00110 SgPoint p = *it; 00111 if (m_bd.GetStone(p) == toPlay && m_bd.InAtari(p)) 00112 { 00113 if (m_ladder.Ladder(m_bd, p, toPlay, &m_ladderSequence, 00114 false/*twoLibIsEscape*/) < 0) 00115 { 00116 if (m_ladderSequence.Length() >= m_minLadderLength) 00117 rootFilter.push_back(m_bd.TheLiberty(p)); 00118 } 00119 } 00120 00121 } 00122 00123 // Moves on edge line, if no stone is near 00124 for (GoBoard::Iterator it(m_bd); it; ++it) 00125 { 00126 SgPoint p = *it; 00127 if (IsEmptyEdge(m_bd, p)) 00128 rootFilter.push_back(p); 00129 } 00130 00131 return rootFilter; 00132 } 00133 00134 //----------------------------------------------------------------------------