Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoUctPureRandomGenerator.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoUctPureRandomGenerator.h */
00003 //----------------------------------------------------------------------------
00004 
00005 #ifndef GOUCT_PURERANDOMGENERATOR_H
00006 #define GOUCT_PURERANDOMGENERATOR_H
00007 
00008 #include <vector>
00009 #include "GoBoard.h"
00010 #include "GoUctUtil.h"
00011 #include "SgWrite.h"
00012 
00013 //----------------------------------------------------------------------------
00014 
00015 /** Randomly select from empty points on the board.
00016     Finds and shuffles the empty points on the board at the beginning
00017     to avoid repeated loops over the board to find empty points.
00018 */
00019 template<class BOARD>
00020 class GoUctPureRandomGenerator
00021 {
00022 public:
00023     GoUctPureRandomGenerator(const BOARD& bd, SgRandom& random);
00024 
00025     /** Finds and shuffles the empty points currently on the board. */
00026     void Start();
00027 
00028     /** Update state.
00029         Must be called after each play on the board.
00030     */
00031     void OnPlay();
00032 
00033     /** Return a list of points that are currently potentially empty.
00034         As a side-benefit, the generator can be used to get the list of empty
00035         points on the board to speed up full-board loops over empty points
00036         or to get a shuffled list of the empty points (e.g. for finding
00037         legal moves when expanding a node in the in-tree-phase of UCT).
00038         Points in the list are candidates, they still have to be tested, if
00039         they are really empty.
00040     */
00041     const std::vector<SgPoint>& Candidates() const;
00042 
00043     /** Generate a pure random move.
00044         Randomly select an empty point on the board that fulfills
00045         GoUctUtil::GeneratePoint() for the color currently to play on the
00046         board.
00047     */
00048     SgPoint Generate(SgBalancer& balancer);
00049 
00050     /** Generate a move using the fillboard heuristic.
00051         Tries @c numberTries times to select a point on the board and
00052         returns it, if it is empty and all adjacent and diagonal neighbors are
00053         empty. Otherwise it returns SG_NULLMOVE. Using this heuristic before
00054         any other heuristics is helpful to increase playout diversity on large
00055         boards. See section 6.1 of:
00056         Chatriot, Gelly, Hoock, Perez, Rimmel, Teytaud:
00057         <a href="http://www.lri.fr/~teytaud/eg.pdf">
00058         Combining expert, offline, transient and online learning in
00059         Monte-Carlo exploration</a>
00060      */
00061     SgPoint GenerateFillboardMove(int numberTries);
00062 
00063 private:
00064     const BOARD& m_bd;
00065 
00066     float m_invNuPoints;
00067 
00068     float m_nuEmptyFloat;
00069 
00070     SgRandom& m_random;
00071 
00072     /** Points that are potentially empty. */
00073     std::vector<SgPoint> m_candidates;
00074 
00075     bool Empty3x3(SgPoint p) const;
00076 
00077     void CheckConsistency() const;
00078 
00079     void Insert(SgPoint p);
00080 };
00081 
00082 template<class BOARD>
00083 GoUctPureRandomGenerator<BOARD>::GoUctPureRandomGenerator(const BOARD& bd,
00084                                                           SgRandom& random)
00085     : m_bd(bd),
00086       m_random(random)
00087 {
00088     m_candidates.reserve(GO_MAX_NUM_MOVES);
00089 }
00090 
00091 template<class BOARD>
00092 inline const std::vector<SgPoint>&
00093 GoUctPureRandomGenerator<BOARD>::Candidates()
00094     const
00095 {
00096     return m_candidates;
00097 }
00098 
00099 template<class BOARD>
00100 inline void GoUctPureRandomGenerator<BOARD>::CheckConsistency() const
00101 {
00102 #if 0 // Expensive check, enable only for debugging
00103     for (GoBoard::Iterator it(m_bd); it; ++it)
00104     {
00105         SgPoint p = *it;
00106         if (m_bd.IsEmpty(p))
00107             if (find(m_candidates.begin(), m_candidates.end(), p)
00108                 == m_candidates.end())
00109             {
00110                 SgDebug() << m_bd
00111                           << "Candidates: " << SgWritePointList(m_candidates)
00112                           << "does not contain: " << SgWritePoint(p)
00113                           << "\nm_bd.CapturedStones(): "
00114                           << SgWriteSPointList<SG_MAX_ONBOARD + 1>
00115                                                    (m_bd.CapturedStones())
00116                           << "Last move: "
00117                           << SgWritePoint(m_bd.GetLastMove()) << '\n';
00118                 SG_ASSERT(false);
00119             }
00120     }
00121 #endif
00122 }
00123 
00124 template<class BOARD>
00125 inline bool GoUctPureRandomGenerator<BOARD>::Empty3x3(SgPoint p)
00126     const
00127 {
00128     return (m_bd.NumEmptyNeighbors(p) == 4
00129             && m_bd.NumEmptyDiagonals(p) == 4);
00130 }
00131 
00132 template<class BOARD>
00133 inline SgPoint GoUctPureRandomGenerator<BOARD>::Generate(SgBalancer& balancer)
00134 {
00135     CheckConsistency();
00136     SgBlackWhite toPlay = m_bd.ToPlay();
00137     size_t i = m_candidates.size();
00138     while (true)
00139     {
00140         if (i == 0)
00141             break;
00142         --i;
00143         SgPoint p = m_candidates[i];
00144         if (! m_bd.IsEmpty(p))
00145         {
00146             m_candidates[i] = m_candidates[m_candidates.size() - 1];
00147             m_candidates.pop_back();
00148             continue;
00149         }
00150         if (GoUctUtil::GeneratePoint(m_bd, balancer, p, toPlay))
00151         {
00152             CheckConsistency();
00153             return p;
00154         }
00155     }
00156     CheckConsistency();
00157     return SG_NULLMOVE;
00158 }
00159 
00160 template<class BOARD>
00161 inline SgPoint GoUctPureRandomGenerator<BOARD>::GenerateFillboardMove(
00162                                                               int numberTries)
00163 {
00164     float effectiveTries = numberTries * m_nuEmptyFloat * m_invNuPoints;
00165     size_t i = m_candidates.size();
00166     while (effectiveTries > 1.f)
00167     {
00168         if (i == 0)
00169             return SG_NULLMOVE;
00170         --i;
00171         SgPoint p = m_candidates[i];
00172         if (! m_bd.IsEmpty(p))
00173         {
00174             m_candidates[i] = m_candidates[m_candidates.size() - 1];
00175             m_candidates.pop_back();
00176             continue;
00177         }
00178         if (Empty3x3(p))
00179             return p;
00180         effectiveTries -= 1.f;
00181     }
00182     // Remaning fractional number of tries
00183     if (m_random.Int(100) > 100 * effectiveTries)
00184         return SG_NULLMOVE;
00185     while (true)
00186     {
00187         if (i == 0)
00188             break;
00189         --i;
00190         SgPoint p = m_candidates[i];
00191         if (! m_bd.IsEmpty(p))
00192         {
00193             m_candidates[i] = m_candidates[m_candidates.size() - 1];
00194             m_candidates.pop_back();
00195             continue;
00196         }
00197         if (Empty3x3(p))
00198             return p;
00199         break;
00200     }
00201     return SG_NULLMOVE;
00202 }
00203 
00204 template<class BOARD>
00205 inline void GoUctPureRandomGenerator<BOARD>::OnPlay()
00206 {
00207     SgPoint lastMove = m_bd.GetLastMove();
00208     if (lastMove != SG_NULLMOVE && lastMove != SG_PASS
00209         && ! m_bd.IsEmpty(lastMove))
00210         m_nuEmptyFloat -= 1.f;
00211     const GoPointList& capturedStones = m_bd.CapturedStones();
00212     if (! capturedStones.IsEmpty())
00213     {
00214         // Don't remove stone played, too expensive, check later in Generate()
00215         // that generated point is still empty
00216         for (GoPointList::Iterator it(capturedStones); it; ++it)
00217             Insert(*it);
00218         m_nuEmptyFloat += capturedStones.Length();
00219     }
00220     CheckConsistency();
00221 }
00222 
00223 /** Insert new candidate at random place. */
00224 template<class BOARD>
00225 inline void GoUctPureRandomGenerator<BOARD>::Insert(SgPoint p)
00226 {
00227     size_t size = m_candidates.size();
00228     if (size == 0)
00229         m_candidates.push_back(p);
00230     else
00231     {
00232         SgPoint& swapPoint = m_candidates[m_random.Int(size)];
00233         m_candidates.push_back(swapPoint);
00234         swapPoint = p;
00235     }
00236 }
00237 
00238 template<class BOARD>
00239 inline void GoUctPureRandomGenerator<BOARD>::Start()
00240 {
00241     m_nuEmptyFloat = 0;
00242     m_candidates.clear();
00243     for (typename BOARD::Iterator it(m_bd); it; ++it)
00244         if (m_bd.IsEmpty(*it))
00245         {
00246             Insert(*it);
00247             m_nuEmptyFloat += 1.f;
00248         }
00249     m_invNuPoints = 1.f / (m_bd.Size() * m_bd.Size());
00250     CheckConsistency();
00251 }
00252 
00253 //----------------------------------------------------------------------------
00254 
00255 #endif // GOUCT_PURERANDOMGENERATOR_H


17 Jun 2010 Doxygen 1.4.7