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