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


17 Jun 2010 Doxygen 1.4.7