Index   Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

GoUctPlayoutPolicy.h

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file GoUctPlayoutPolicy.h */
00003 //----------------------------------------------------------------------------
00004 
00005 #ifndef GOUCT_PLAYOUTPOLICY_H
00006 #define GOUCT_PLAYOUTPOLICY_H
00007 
00008 #include <iostream>
00009 #include <boost/array.hpp>
00010 #include "GoBoardUtil.h"
00011 #include "GoEyeUtil.h"
00012 #include "GoUctPatterns.h"
00013 #include "GoUctPureRandomGenerator.h"
00014 
00015 //----------------------------------------------------------------------------
00016 
00017 /** Parameters for GoUctPlayoutPolicy. */
00018 class GoUctPlayoutPolicyParam
00019 {
00020 public:
00021     /** Enable collection of statistics.
00022         Has a negative impact on performance. Default is false. */
00023     bool m_statisticsEnabled;
00024 
00025     /** Use Nakade heuristic.
00026         See section 6.2 of: Chatriot, Gelly, Hoock, Perez, Rimmel, Teytaud:
00027         <a href="http://www.lri.fr/~teytaud/eg.pdf">
00028         Combining expert, offline, transient and online learning in
00029         Monte-Carlo exploration</a> */
00030     bool m_useNakadeHeuristic;
00031 
00032     /** See GoUctPureRandomGenerator::GenerateFillboardMove.
00033         Default is 0 */
00034     int m_fillboardTries;
00035 
00036     GoUctPlayoutPolicyParam();
00037 };
00038 
00039 //----------------------------------------------------------------------------
00040 
00041 /** Move types used in GoUctPlayoutPolicy. */
00042 enum GoUctPlayoutPolicyType
00043 {
00044     GOUCT_FILLBOARD,
00045 
00046     GOUCT_NAKADE,
00047 
00048     GOUCT_ATARI_CAPTURE,
00049 
00050     GOUCT_ATARI_DEFEND,
00051 
00052     GOUCT_LOWLIB,
00053 
00054     GOUCT_PATTERN,
00055 
00056     GOUCT_CAPTURE,
00057 
00058     GOUCT_RANDOM,
00059 
00060     GOUCT_SELFATARI_CORRECTION,
00061 
00062     GOUCT_CLUMP_CORRECTION,
00063 
00064     GOUCT_PASS,
00065 
00066     _GOUCT_NU_DEFAULT_PLAYOUT_TYPE
00067 };
00068 
00069 const char* GoUctPlayoutPolicyTypeStr(GoUctPlayoutPolicyType type);
00070 
00071 //----------------------------------------------------------------------------
00072 
00073 /** Statistics collected by GoUctPlayoutPolicy */
00074 struct GoUctPlayoutPolicyStat
00075 {
00076     /** Number of moves generated. */
00077     std::size_t m_nuMoves;
00078 
00079     /** Length of sequences of consecutive non-pure-random moves. */
00080     SgUctStatistics m_nonRandLen;
00081 
00082     /** Length of list of equivalent best moves.
00083         Does not include the length of the move list for pure random moves. */
00084     SgUctStatistics m_moveListLen;
00085 
00086     /** Number of moves of a certain type. */
00087     boost::array<std::size_t,_GOUCT_NU_DEFAULT_PLAYOUT_TYPE> m_nuMoveType;
00088 
00089     void Clear();
00090 
00091     void Write(std::ostream& out) const;
00092 };
00093 
00094 //----------------------------------------------------------------------------
00095 
00096 /** Default playout policy for usage in GoUctGlobalSearch.
00097     Parametrized by the board class to make it usable with both GoBoard
00098     and GoUctBoard.
00099     If all heuristics are disabled, the policy plays purely random moves.
00100     The order and types of the heuristics are inspired by the first
00101     technical report about the MoGo program.
00102     Instances of this class must be thread-safe during a search. */
00103 template<class BOARD>
00104 class GoUctPlayoutPolicy
00105 {
00106 public:
00107     /** Constructor.
00108         @param bd
00109         @param param The parameters. The policy stores a reference to @c param
00110         to allow changing the parameters of a group of playout policies later.
00111         Therefore the lifetime of @c param must exceed the lifetime of the
00112         policy. */
00113     GoUctPlayoutPolicy(const BOARD& bd, const GoUctPlayoutPolicyParam& param);
00114 
00115 
00116     /** @name Functions needed by all playout policies. */
00117     // @{
00118 
00119     /** Generate a move
00120         Generates a random move in the following order:
00121         -# Atari heuristic (if enabled)
00122         -# Proximity heuristic (if enabled) (using patterns if enabled)
00123         -# Capture heuristic (if enabled)
00124         -# Purely random */
00125     SgPoint GenerateMove();
00126 
00127     void EndPlayout();
00128 
00129     void StartPlayout();
00130 
00131     void OnPlay();
00132 
00133     /** Return the type of the last move generated. */
00134     GoUctPlayoutPolicyType MoveType() const;
00135 
00136     // @} // @name
00137 
00138 
00139     /** @name Statistics */
00140     // @{
00141 
00142     /** Return current statistics.
00143         The statistics are only collected, if enabled with
00144         EnableStatistics(). */
00145     const GoUctPlayoutPolicyStat& Statistics(SgBlackWhite color) const;
00146 
00147     void ClearStatistics();
00148 
00149     // @} // @name
00150 
00151 
00152     /** Return the list of equivalent best moves from last move generation.
00153         The played move was randomly selected from this list. */
00154     GoPointList GetEquivalentBestMoves() const;
00155 
00156     /** Make pattern matcher available for other uses.
00157         Avoids that a user of the playout policy who also wants to use the
00158         pattern matcher for other purposes needs to allocate a second
00159         matcher (Use case: prior knowledge) */
00160     const GoUctPatterns<BOARD>& Patterns() const;
00161 
00162 private:
00163     /** A function that possibly corrects a given point */
00164     typedef bool Corrector(const BOARD&, SgPoint&);
00165 
00166     /** Incrementally keeps track of blocks in atari. */
00167     class CaptureGenerator
00168     {
00169     public:
00170         CaptureGenerator(const BOARD& bd);
00171 
00172         void StartPlayout();
00173 
00174         void OnPlay();
00175 
00176         /** Generate capture moves.
00177             @param[out] moves The resulting list of capture moves. The passed
00178             in list is expected to be empty. */
00179         void Generate(GoPointList& moves);
00180 
00181     private:
00182         const BOARD& m_bd;
00183 
00184         /** Anchor stones of blocks that need to be checked for atari. */
00185         std::vector<SgPoint> m_candidates;
00186     };
00187 
00188     /** Use patterns around last own move, too */
00189     static const bool SECOND_LAST_MOVE_PATTERNS = true;
00190 
00191     /** Shift move to neighbor if it would make an ugly clump.
00192         See GoUctUtil::DoClumpCorrection */
00193     static const bool USE_CLUMP_CORRECTION = false;
00194 
00195     static const bool DEBUG_CORRECT_MOVE = false;
00196 
00197     const BOARD& m_bd;
00198 
00199     const GoUctPlayoutPolicyParam& m_param;
00200 
00201     GoUctPatterns<BOARD> m_patterns;
00202 
00203     /** m_moves have already been checked, skip GeneratePoint test.  */
00204     bool m_checked;
00205 
00206     /** Type of the last generated move. */
00207     GoUctPlayoutPolicyType m_moveType;
00208 
00209     /** See GoUctPlayoutPolicyStat::m_nonRandLen. */
00210     std::size_t m_nonRandLen;
00211 
00212     /** Last move.
00213         Stored in member variable to avoid multiple calls to
00214         GoBoard::GetLastMove during GenerateMove. */
00215     SgPoint m_lastMove;
00216 
00217     /** List of equivalent best moves generated by the policy.
00218         The highest priority heuristic will generate all moves in this list.
00219         Moves in this list are not yet checked, if they are legal.
00220         This list is not used in GenerateMove(), if a pure random move
00221         is generated. */
00222     GoPointList m_moves;
00223 
00224     SgRandom m_random;
00225 
00226     /** Balancer for GoUctUtil::IsMutualAtari(). */
00227     mutable SgBalancer m_balancer;
00228     
00229     CaptureGenerator m_captureGenerator;
00230 
00231     GoUctPureRandomGenerator<BOARD> m_pureRandomGenerator;
00232 
00233     SgBWArray<GoUctPlayoutPolicyStat> m_statistics;
00234 
00235     /** Try to correct the proposed move, typically by moving it to a
00236         'better' point such as other liberty or neighbor.
00237         Examples implemented: self-ataries, clumps. */
00238     bool CorrectMove(typename GoUctPlayoutPolicy<BOARD>::Corrector& corrFunction,
00239                      SgPoint& mv, GoUctPlayoutPolicyType moveType);
00240 
00241     /** Captures if last move was self-atari */
00242     bool GenerateAtariCaptureMove();
00243 
00244     /** Generate escapes if last move was atari. */
00245     bool GenerateAtariDefenseMove();
00246 
00247     /** Generate low lib moves around lastMove */
00248     bool GenerateLowLibMove(SgPoint lastMove);
00249 
00250     bool GenerateNakadeMove();
00251 
00252     void GenerateNakadeMove(SgPoint p);
00253 
00254     /** Generate pattern move around last two moves */
00255     bool GeneratePatternMove();
00256 
00257     void GeneratePatternMove(SgPoint p);
00258 
00259     void GeneratePatternMove2(SgPoint p, SgPoint lastMove);
00260 
00261     void GeneratePureRandom();
00262 
00263     bool GeneratePoint(SgPoint p) const;
00264 
00265     /** Does playing on a liberty increase number of liberties for block?
00266         If yes, add to m_moves.
00267         Disabled if both liberties are simple chain libs, e.g. bamboo. */
00268     void PlayGoodLiberties(SgPoint block);
00269 
00270     /** see GoUctUtil::SelectRandom */
00271     SgPoint SelectRandom();
00272 
00273     /** Add statistics for most recently generated move. */
00274     void UpdateStatistics();
00275 };
00276 
00277 template<class BOARD>
00278 GoUctPlayoutPolicy<BOARD>::CaptureGenerator::CaptureGenerator(const BOARD& bd)
00279     : m_bd(bd)
00280 {
00281     m_candidates.reserve(GO_MAX_NUM_MOVES);
00282 }
00283 
00284 template<class BOARD>
00285 void GoUctPlayoutPolicy<BOARD>::CaptureGenerator::StartPlayout()
00286 {
00287     m_candidates.clear();
00288     for (typename BOARD::Iterator it(m_bd); it; ++it)
00289     {
00290         const SgPoint p = *it;
00291         if (m_bd.Occupied(p) && m_bd.Anchor(p) == p && m_bd.InAtari(p))
00292             m_candidates.push_back(p);
00293     }
00294 }
00295 
00296 template<class BOARD>
00297 void GoUctPlayoutPolicy<BOARD>::CaptureGenerator::OnPlay()
00298 {
00299     SgPoint lastMove = m_bd.GetLastMove();
00300     if (lastMove == SG_NULLMOVE || lastMove == SG_PASS)
00301         return;
00302     if (m_bd.OccupiedInAtari(lastMove))
00303         m_candidates.push_back(m_bd.Anchor(lastMove));
00304     if (m_bd.NumNeighbors(lastMove, m_bd.ToPlay()) == 0)
00305         return;
00306     if (m_bd.OccupiedInAtari(lastMove + SG_NS))
00307         m_candidates.push_back(m_bd.Anchor(lastMove + SG_NS));
00308     if (m_bd.OccupiedInAtari(lastMove - SG_NS))
00309         m_candidates.push_back(m_bd.Anchor(lastMove - SG_NS));
00310     if (m_bd.OccupiedInAtari(lastMove + SG_WE))
00311         m_candidates.push_back(m_bd.Anchor(lastMove + SG_WE));
00312     if (m_bd.OccupiedInAtari(lastMove - SG_WE))
00313         m_candidates.push_back(m_bd.Anchor(lastMove - SG_WE));
00314 }
00315 
00316 template<class BOARD>
00317 void GoUctPlayoutPolicy<BOARD>::CaptureGenerator::Generate(GoPointList& moves)
00318 {
00319     SG_ASSERT(moves.IsEmpty());
00320     const SgBlackWhite opp = m_bd.Opponent();
00321     // For efficiency reasons, this function does not check, if the same
00322     // move is generated multiple times (and will therefore played with
00323     // higher probabilty, if there are also other capture moves), because in
00324     // nearly all cases, there is zero or one global capture move on the
00325     // board. Most captures are done immediately by the atari heuristic
00326     for (size_t i = 0; i < m_candidates.size(); ++i)
00327     {
00328         const SgPoint p = m_candidates[i];
00329         if (! m_bd.OccupiedInAtari(p))
00330         {
00331             m_candidates[i] = m_candidates[m_candidates.size() - 1];
00332             m_candidates.pop_back();
00333             --i;
00334             continue;
00335         }
00336         if (m_bd.GetColor(p) == opp)
00337             moves.PushBack(m_bd.TheLiberty(p));
00338     }
00339 }
00340 
00341 template<class BOARD>
00342 GoUctPlayoutPolicy<BOARD>::GoUctPlayoutPolicy(const BOARD& bd,
00343                                         const GoUctPlayoutPolicyParam& param)
00344     : m_bd(bd),
00345       m_param(param),
00346       m_patterns(bd),
00347       m_checked(false),
00348       m_balancer(100), 
00349       m_captureGenerator(bd),
00350       m_pureRandomGenerator(bd, m_random)
00351 {
00352     ClearStatistics();
00353 }
00354 
00355 template<class BOARD>
00356 void GoUctPlayoutPolicy<BOARD>::ClearStatistics()
00357 {
00358     m_statistics[SG_BLACK].Clear();
00359     m_statistics[SG_WHITE].Clear();
00360 }
00361 
00362 template<class BOARD>
00363 bool GoUctPlayoutPolicy<BOARD>::CorrectMove(
00364                     typename GoUctPlayoutPolicy<BOARD>::Corrector& corrFunction,
00365                     SgPoint& mv, GoUctPlayoutPolicyType moveType)
00366 {
00367 #if DEBUG
00368     const SgPoint oldMv = mv;
00369 #endif
00370     if (! corrFunction(m_bd, mv))
00371         return false;
00372 
00373     m_moves.SetTo(mv);
00374     m_moveType = moveType;
00375 
00376 #if DEBUG
00377     if (DEBUG_CORRECT_MOVE)
00378         SgDebug() << m_bd
00379                   << "Replace " << SgWriteMove(oldMv, m_bd.ToPlay())
00380                   << " by " << SgWriteMove(mv, m_bd.ToPlay()) << '\n';
00381 #endif
00382     return true;
00383 }
00384 
00385 template<class BOARD>
00386 void GoUctPlayoutPolicy<BOARD>::EndPlayout()
00387 {
00388 }
00389 
00390 template<class BOARD>
00391 bool GoUctPlayoutPolicy<BOARD>::GenerateAtariCaptureMove()
00392 {
00393     SG_ASSERT(! SgIsSpecialMove(m_lastMove));
00394     if (m_bd.InAtari(m_lastMove))
00395     {
00396         SgMove mv = m_bd.TheLiberty(m_lastMove);
00397         m_moves.PushBack(mv);
00398         return true;
00399     }
00400     return false;
00401 }
00402 
00403 template<class BOARD>
00404 bool GoUctPlayoutPolicy<BOARD>::GenerateAtariDefenseMove()
00405 {
00406     SG_ASSERT(m_moves.IsEmpty());
00407     SG_ASSERT(! SgIsSpecialMove(m_lastMove));
00408     SgBlackWhite toPlay = m_bd.ToPlay();
00409     if (m_bd.NumNeighbors(m_lastMove, toPlay) == 0)
00410         return false;
00411     SgArrayList<SgPoint,4> anchorList;
00412     for (SgNb4Iterator it(m_lastMove); it; ++it)
00413     {
00414         if (m_bd.GetColor(*it) != toPlay || ! m_bd.InAtari(*it))
00415             continue;
00416         SgPoint anchor = m_bd.Anchor(*it);
00417         if (anchorList.Contains(anchor))
00418             continue;
00419         anchorList.PushBack(anchor);
00420 
00421         // Check if move on last liberty would escape the atari
00422         SgPoint theLiberty = m_bd.TheLiberty(anchor);
00423         if (! GoBoardUtil::SelfAtari(m_bd, theLiberty))
00424             m_moves.PushBack(theLiberty);
00425 
00426         // Capture adjacent blocks
00427         for (GoAdjBlockIterator<BOARD> it2(m_bd, anchor, 1); it2; ++it2)
00428         {
00429             SgPoint oppLiberty = m_bd.TheLiberty(*it2);
00430             // If opponent's last liberty is not my last liberty, we know
00431             // that we will have two liberties after capturing (my last
00432             // liberty + at least one stone captured). If both last liberties
00433             // are the same, we already checked above with
00434             // GoBoardUtil::SelfAtari(theLiberty), if the move escapes the
00435             // atari
00436             if (oppLiberty != theLiberty)
00437                 m_moves.PushBack(oppLiberty);
00438         }
00439     }
00440     return ! m_moves.IsEmpty();
00441 }
00442 
00443 template<class BOARD>
00444 void GoUctPlayoutPolicy<BOARD>::PlayGoodLiberties(SgPoint block)
00445 {
00446     SgPoint ignoreOther;
00447     if (! GoBoardUtil::IsSimpleChain(m_bd, block, ignoreOther))
00448         for (typename BOARD::LibertyIterator it(m_bd, block); it; ++it)
00449             if (  GoUctUtil::GainsLiberties(m_bd, block, *it)
00450                && ! GoBoardUtil::SelfAtari(m_bd, *it)
00451                )
00452                 m_moves.PushBack(*it);
00453 }
00454 
00455 template<class BOARD>
00456 bool GoUctPlayoutPolicy<BOARD>::GenerateLowLibMove(SgPoint lastMove)
00457 {
00458     SG_ASSERT(! SgIsSpecialMove(lastMove));
00459     SG_ASSERT(! m_bd.IsEmpty(lastMove));
00460     SG_ASSERT(m_moves.IsEmpty());
00461     
00462     const SgBlackWhite toPlay = m_bd.ToPlay();
00463 
00464     // take liberty of last move
00465     if (m_bd.NumLiberties(lastMove) == 2)
00466     {
00467         const SgPoint anchor = m_bd.Anchor(lastMove);
00468         PlayGoodLiberties(anchor);
00469     }
00470 
00471     if (m_bd.NumNeighbors(lastMove, toPlay) != 0)
00472     {
00473         // play liberties of neighbor blocks
00474         SgArrayList<SgPoint,4> ourLowLibBlocks;
00475         for (SgNb4Iterator it(lastMove); it; ++it)
00476         {
00477             if (m_bd.GetColor(*it) == toPlay
00478                 && m_bd.NumLiberties(*it) == 2)
00479             {
00480                 const SgPoint anchor = m_bd.Anchor(*it);
00481                 if (! ourLowLibBlocks.Contains(anchor))
00482                 {
00483                     ourLowLibBlocks.PushBack(anchor);
00484                     PlayGoodLiberties(anchor);
00485                 }
00486             }
00487         }
00488     }
00489 
00490     return ! m_moves.IsEmpty();
00491 }
00492 
00493 template<class BOARD>
00494 SG_ATTR_FLATTEN SgPoint GoUctPlayoutPolicy<BOARD>::GenerateMove()
00495 {
00496     m_moves.Clear();
00497     m_checked = false;
00498 
00499     SgPoint mv = SG_NULLMOVE;
00500 
00501     if (m_param.m_fillboardTries > 0)
00502     {
00503         m_moveType = GOUCT_FILLBOARD;
00504         mv = m_pureRandomGenerator.GenerateFillboardMove(
00505                                                     m_param.m_fillboardTries);
00506     }
00507 
00508     m_lastMove = m_bd.GetLastMove();
00509     if (mv == SG_NULLMOVE
00510         && ! SgIsSpecialMove(m_lastMove) // skip if Pass or Null
00511         && ! m_bd.IsEmpty(m_lastMove) // skip if move was suicide
00512        )
00513     {
00514         if (m_param.m_useNakadeHeuristic && GenerateNakadeMove())
00515         {
00516             m_moveType = GOUCT_NAKADE;
00517             mv = SelectRandom();
00518         }
00519         if (mv == SG_NULLMOVE && GenerateAtariCaptureMove())
00520         {
00521             m_moveType = GOUCT_ATARI_CAPTURE;
00522             mv = SelectRandom();
00523         }
00524         if (mv == SG_NULLMOVE && GenerateAtariDefenseMove())
00525         {
00526             m_moveType = GOUCT_ATARI_DEFEND;
00527             mv = SelectRandom();
00528         }
00529         if (mv == SG_NULLMOVE && GenerateLowLibMove(m_lastMove))
00530         {
00531             m_moveType = GOUCT_LOWLIB;
00532             mv = SelectRandom();
00533         }
00534         if (mv == SG_NULLMOVE && GeneratePatternMove())
00535         {
00536             m_moveType = GOUCT_PATTERN;
00537             mv = SelectRandom();
00538         }
00539     }
00540     if (mv == SG_NULLMOVE)
00541     {
00542         m_moveType = GOUCT_CAPTURE;
00543         m_captureGenerator.Generate(m_moves);
00544         mv = SelectRandom();
00545     }
00546     if (mv == SG_NULLMOVE)
00547     {
00548         m_moveType = GOUCT_RANDOM;
00549         mv = m_pureRandomGenerator.Generate(m_balancer);
00550     }
00551 
00552     if (mv == SG_NULLMOVE)
00553     {
00554         m_moveType = GOUCT_PASS;
00555         mv = SG_PASS;
00556     }
00557     else
00558     {
00559         SG_ASSERT(m_bd.IsLegal(mv));
00560         m_checked = CorrectMove(GoUctUtil::DoSelfAtariCorrection, mv,
00561                                 GOUCT_SELFATARI_CORRECTION);
00562         if (USE_CLUMP_CORRECTION && ! m_checked)
00563             CorrectMove(GoUctUtil::DoClumpCorrection, mv,
00564                         GOUCT_CLUMP_CORRECTION);
00565     }
00566     SG_ASSERT(m_bd.IsLegal(mv));
00567     SG_ASSERT(mv == SG_PASS || ! m_bd.IsSuicide(mv));
00568 
00569     if (m_param.m_statisticsEnabled)
00570         UpdateStatistics();
00571 
00572     return mv;
00573 }
00574 
00575 /** Nakade heuristic.
00576     If there is a region of three empty points adjacent to last move, play in
00577     the center of the region. */
00578 template<class BOARD>
00579 bool GoUctPlayoutPolicy<BOARD>::GenerateNakadeMove()
00580 {
00581     SG_ASSERT(m_moves.IsEmpty());
00582     SG_ASSERT(! SgIsSpecialMove(m_lastMove));
00583     GenerateNakadeMove(m_lastMove + SG_NS);
00584     GenerateNakadeMove(m_lastMove - SG_NS);
00585     GenerateNakadeMove(m_lastMove + SG_WE);
00586     GenerateNakadeMove(m_lastMove - SG_WE);
00587     // Ignore duplicates in move list, happens rarely
00588     return ! m_moves.IsEmpty();
00589 }
00590 
00591 template<class BOARD>
00592 void GoUctPlayoutPolicy<BOARD>::GenerateNakadeMove(SgPoint p)
00593 {
00594     SgBlackWhite toPlay = m_bd.ToPlay();
00595     if (m_bd.IsEmpty(p) && m_bd.NumNeighbors(p, toPlay) == 0)
00596     {
00597         int numEmptyNeighbors = m_bd.NumEmptyNeighbors(p);
00598         if (numEmptyNeighbors == 2)
00599         {
00600             int n = 0;
00601             for (SgNb4Iterator it(p); it; ++it)
00602                 if (m_bd.IsEmpty(*it))
00603                 {
00604                     if (m_bd.NumEmptyNeighbors(*it) != 1
00605                         || m_bd.NumNeighbors(*it, toPlay) > 0)
00606                         return;
00607                     if (++n > 2)
00608                         break;
00609                 }
00610             m_moves.PushBack(p);
00611         }
00612         else if (numEmptyNeighbors == 1)
00613         {
00614             for (SgNb4Iterator it(p); it; ++it)
00615                 if (m_bd.IsEmpty(*it))
00616                 {
00617                     if (m_bd.NumEmptyNeighbors(*it) != 2
00618                         || m_bd.NumNeighbors(*it, toPlay) > 0)
00619                         return;
00620                     for (SgNb4Iterator it2(*it); it2; ++it2)
00621                         if (m_bd.IsEmpty(*it2) && *it2 != p)
00622                         {
00623                             if (m_bd.NumEmptyNeighbors(*it2) == 1
00624                                 && m_bd.NumNeighbors(*it2, toPlay) == 0)
00625                                 m_moves.PushBack(*it);
00626                             break;
00627                         }
00628                     break;
00629                 }
00630 
00631         }
00632     }
00633 }
00634 
00635 /** Pattern heuristic.
00636     Use patterns (only in 3x3 neighborhood of last move)
00637     @see GoUctPatterns */
00638 template<class BOARD>
00639 bool GoUctPlayoutPolicy<BOARD>::GeneratePatternMove()
00640 {
00641     SG_ASSERT(m_moves.IsEmpty());
00642     SG_ASSERT(! SgIsSpecialMove(m_lastMove));
00643     GeneratePatternMove(m_lastMove + SG_NS - SG_WE);
00644     GeneratePatternMove(m_lastMove + SG_NS);
00645     GeneratePatternMove(m_lastMove + SG_NS + SG_WE);
00646     GeneratePatternMove(m_lastMove - SG_WE);
00647     GeneratePatternMove(m_lastMove + SG_WE);
00648     GeneratePatternMove(m_lastMove - SG_NS - SG_WE);
00649     GeneratePatternMove(m_lastMove - SG_NS);
00650     GeneratePatternMove(m_lastMove - SG_NS + SG_WE);
00651     if (SECOND_LAST_MOVE_PATTERNS)
00652     {
00653         const SgPoint lastMove2 = m_bd.Get2ndLastMove();
00654         if (! SgIsSpecialMove(lastMove2))
00655         {
00656             GeneratePatternMove2(lastMove2 + SG_NS - SG_WE, m_lastMove);
00657             GeneratePatternMove2(lastMove2 + SG_NS,         m_lastMove);
00658             GeneratePatternMove2(lastMove2 + SG_NS + SG_WE, m_lastMove);
00659             GeneratePatternMove2(lastMove2 - SG_WE,         m_lastMove);
00660             GeneratePatternMove2(lastMove2 + SG_WE,         m_lastMove);
00661             GeneratePatternMove2(lastMove2 - SG_NS - SG_WE, m_lastMove);
00662             GeneratePatternMove2(lastMove2 - SG_NS,         m_lastMove);
00663             GeneratePatternMove2(lastMove2 - SG_NS + SG_WE, m_lastMove);
00664         }
00665     }
00666     return ! m_moves.IsEmpty();
00667 }
00668 
00669 template<class BOARD>
00670 inline void GoUctPlayoutPolicy<BOARD>::GeneratePatternMove(SgPoint p)
00671 {
00672     if (m_bd.IsEmpty(p)
00673         && m_patterns.MatchAny(p)
00674         && ! GoBoardUtil::SelfAtari(m_bd, p))
00675         m_moves.PushBack(p);
00676 }
00677 
00678 template<class BOARD>
00679 inline void GoUctPlayoutPolicy<BOARD>::GeneratePatternMove2(SgPoint p,
00680                                                             SgPoint lastMove)
00681 {
00682     if (m_bd.IsEmpty(p)
00683         && ! SgPointUtil::In8Neighborhood(lastMove, p)
00684         && m_patterns.MatchAny(p)
00685         && ! GoBoardUtil::SelfAtari(m_bd, p))
00686         m_moves.PushBack(p);
00687 }
00688 
00689 template<class BOARD>
00690 inline bool GoUctPlayoutPolicy<BOARD>::GeneratePoint(SgPoint p) const
00691 {
00692     return GoUctUtil::GeneratePoint(m_bd, m_balancer, p, m_bd.ToPlay());
00693 }
00694 
00695 template<class BOARD>
00696 GoPointList GoUctPlayoutPolicy<BOARD>::GetEquivalentBestMoves() const
00697 {
00698     GoPointList result;
00699     if (m_moveType == GOUCT_RANDOM)
00700     {
00701         for (typename BOARD::Iterator it(m_bd); it; ++it)
00702             if (m_bd.IsEmpty(*it) && GeneratePoint(*it))
00703                 result.PushBack(*it);
00704     }
00705     // Move in m_moves are not checked yet, if legal etc.
00706     for (GoPointList::Iterator it(m_moves); it; ++it)
00707         if (m_checked || GeneratePoint(*it))
00708             result.PushBack(*it);
00709     return result;
00710 }
00711 
00712 template<class BOARD>
00713 GoUctPlayoutPolicyType GoUctPlayoutPolicy<BOARD>::MoveType()
00714     const
00715 {
00716     return m_moveType;
00717 }
00718 
00719 template<class BOARD>
00720 void GoUctPlayoutPolicy<BOARD>::OnPlay()
00721 {
00722     m_captureGenerator.OnPlay();
00723     m_pureRandomGenerator.OnPlay();
00724 }
00725 
00726 
00727 template<class BOARD>
00728 const GoUctPatterns<BOARD>& GoUctPlayoutPolicy<BOARD>::Patterns()
00729     const
00730 {
00731     return m_patterns;
00732 }
00733 
00734 template<class BOARD>
00735 inline SgPoint GoUctPlayoutPolicy<BOARD>::SelectRandom()
00736 {
00737     return GoUctUtil::SelectRandom(m_bd, m_bd.ToPlay(), m_moves, m_random, 
00738                                    m_balancer);
00739 }
00740 
00741 /*
00742 template<class BOARD>
00743 const GoUctPlayoutPolicyStat&
00744 GoUctPlayoutPolicy<BOARD>::Statistics() const
00745 {
00746     return Statistics(m_bd.ToPlay());
00747 } */
00748 
00749 template<class BOARD>
00750 const GoUctPlayoutPolicyStat&
00751 GoUctPlayoutPolicy<BOARD>::Statistics(SgBlackWhite color) const
00752 {
00753     return m_statistics[color];
00754 }
00755 
00756 template<class BOARD>
00757 void GoUctPlayoutPolicy<BOARD>::StartPlayout()
00758 {
00759     m_captureGenerator.StartPlayout();
00760     m_pureRandomGenerator.Start();
00761     m_nonRandLen = 0;
00762 }
00763 
00764 template<class BOARD>
00765 void GoUctPlayoutPolicy<BOARD>::UpdateStatistics()
00766 {
00767     GoUctPlayoutPolicyStat& statistics = m_statistics[m_bd.ToPlay()];
00768     ++statistics.m_nuMoves;
00769     ++statistics.m_nuMoveType[m_moveType];
00770     if (m_moveType == GOUCT_RANDOM)
00771     {
00772         if (m_nonRandLen > 0)
00773         {
00774             statistics.m_nonRandLen.Add(float(m_nonRandLen));
00775             m_nonRandLen = 0;
00776         }
00777     }
00778     else
00779     {
00780         ++m_nonRandLen;
00781         statistics.m_moveListLen.Add(float(GetEquivalentBestMoves().Length()));
00782     }
00783 }
00784 
00785 //----------------------------------------------------------------------------
00786 
00787 template<class BOARD>
00788 class GoUctPlayoutPolicyFactory
00789 {
00790 public:
00791     /** Constructor.
00792         @param param Playout policy parameters. Stores a reference. Lifetime
00793         of the argument must exceed the lifetime of this factory and created
00794         objects. */
00795     GoUctPlayoutPolicyFactory(const GoUctPlayoutPolicyParam& param);
00796 
00797     GoUctPlayoutPolicy<BOARD>* Create(const BOARD& bd);
00798 
00799 private:
00800     const GoUctPlayoutPolicyParam& m_param;
00801 };
00802 
00803 template<class BOARD>
00804 GoUctPlayoutPolicyFactory<BOARD>
00805 ::GoUctPlayoutPolicyFactory(const GoUctPlayoutPolicyParam& param)
00806     : m_param(param)
00807 {
00808 }
00809 
00810 template<class BOARD>
00811 GoUctPlayoutPolicy<BOARD>*
00812 GoUctPlayoutPolicyFactory<BOARD>::Create(const BOARD& bd)
00813 {
00814     return new GoUctPlayoutPolicy<BOARD>(bd, m_param);
00815 }
00816 
00817 //----------------------------------------------------------------------------
00818 
00819 #endif // GOUCT_PLAYOUTPOLICY_H


Sun Mar 13 2011 Doxygen 1.7.1