Main   Namespaces   Classes   Hierarchy   Annotated   Files   Compound   Global   Pages  

WolvePlayer.cpp

Go to the documentation of this file.
00001 //----------------------------------------------------------------------------
00002 /** @file WolvePlayer.cpp
00003  */
00004 //----------------------------------------------------------------------------
00005 
00006 #include "BitsetIterator.hpp"
00007 #include "VCSet.hpp"
00008 #include "HexEval.hpp"
00009 #include "Misc.hpp"
00010 #include "EndgameUtils.hpp"
00011 #include "SequenceHash.hpp"
00012 #include "WolvePlayer.hpp"
00013 
00014 using namespace benzene;
00015 
00016 //----------------------------------------------------------------------------
00017 
00018 WolvePlayer::WolvePlayer()
00019     : BenzenePlayer(),
00020       m_tt(16), 
00021       m_plywidth(),
00022       m_search_depths(),
00023       m_panic_time(240)
00024 {
00025     m_plywidth.push_back(20);
00026     m_plywidth.push_back(20);
00027     m_plywidth.push_back(20);
00028     m_plywidth.push_back(20);
00029     m_search_depths.push_back(1);
00030     m_search_depths.push_back(2);
00031     m_search_depths.push_back(4);
00032     m_search.SetTT(&m_tt);
00033 }
00034 
00035 WolvePlayer::~WolvePlayer()
00036 {
00037 }
00038 
00039 //----------------------------------------------------------------------------
00040 
00041 /** Reduce search strength if running out of time. */
00042 void WolvePlayer::CheckPanicMode(double timeRemaining,
00043                                  std::vector<int>& search_depths,
00044                                  std::vector<int>& plywidth)
00045 {
00046     // If low on time, set a maximum search depth of 4.
00047     if (m_panic_time >= 0.01 && timeRemaining < m_panic_time)
00048     {
00049     std::vector<int> new_search_depths;
00050     for (std::size_t i = 0; i < search_depths.size(); ++i)
00051         if (search_depths[i] <= 4)
00052         new_search_depths.push_back(search_depths[i]);
00053     search_depths = new_search_depths;
00054         // We also ensure plywidth is at least 15
00055         for (std::size_t i = 0; i < plywidth.size(); ++i)
00056             plywidth[i] = std::max(plywidth[i], 15);
00057     LogWarning() << "############# PANIC MODE #############\n";
00058     }
00059 }
00060 
00061 /** Generates a move in the given gamestate using alphabeta. */
00062 HexPoint WolvePlayer::Search(const HexState& state, const Game& game,
00063                              HexBoard& brd, const bitset_t& consider,
00064                              double maxTime, double& score)
00065 {
00066     UNUSED(game);
00067     std::vector<int> search_depths = m_search_depths;
00068     std::vector<int> plywidth = m_plywidth;
00069 
00070     CheckPanicMode(maxTime, search_depths, plywidth);
00071 
00072     m_search.SetRootMovesToConsider(consider);
00073     LogInfo() << "Using consider set:" << brd.Write(consider) << '\n'
00074           << "Plywidths: " << MiscUtil::PrintVector(plywidth) << '\n'
00075           << "Depths: " << MiscUtil::PrintVector(search_depths) << '\n';
00076 
00077     std::vector<HexPoint> PV;
00078     score = m_search.Search(brd, state.ToPlay(), plywidth, 
00079                             search_depths, -1, PV);
00080 
00081     LogInfo() << m_search.DumpStats() << '\n';
00082 
00083     HexAssert(PV.size() > 0);
00084     return PV[0];
00085 }
00086 
00087 //----------------------------------------------------------------------------
00088 
00089 WolveSearch::WolveSearch()
00090     : m_varTT(16),           // 16bit variation trans-table
00091       m_backup_ice_info(true)
00092 {
00093 }
00094 
00095 WolveSearch::~WolveSearch()
00096 {
00097 }
00098 
00099 void WolveSearch::OnStartSearch()
00100 {
00101     m_varTT.Clear();  // *MUST* clear old variation TT!
00102     m_consider.clear();
00103 }
00104 
00105 void WolveSearch::EnteredNewState()
00106 {
00107 }
00108 
00109 HexEval WolveSearch::Evaluate()
00110 {
00111     Resistance resist;
00112     ComputeResistance(resist);
00113     HexEval score = (m_toplay == BLACK) ? resist.Score() : -resist.Score();
00114     LogFine() << "Score for " << m_toplay << ": " << score << '\n';
00115     return score;
00116 }
00117 
00118 void WolveSearch::GenerateMoves(std::vector<HexPoint>& moves)
00119 {
00120     Resistance resist;
00121     ComputeResistance(resist);
00122 
00123     // Get moves to consider:
00124     //   1) from the variation tt, if this variation has been visited before.
00125     //   2) from the passed in consider set, if at the root.
00126     //   3) from computing it ourselves.
00127     bitset_t consider;
00128 
00129     VariationInfo varInfo;
00130     if (m_varTT.Get(SequenceHash::Hash(m_sequence), varInfo))
00131     {
00132         LogFine() << "Using consider set from TT.\n"
00133           << HexPointUtil::ToString(m_sequence) << '\n'
00134           << m_brd << '\n';
00135         consider = varInfo.consider;
00136     } 
00137     else if (m_current_depth == 0)
00138     {
00139         LogFine() << "Using root consider set.\n";
00140         consider = m_rootMTC;
00141     }
00142     else 
00143     {
00144         LogFine() << "Computing our own consider set.\n";
00145         consider = EndgameUtils::MovesToConsider(*m_brd, m_toplay);
00146     }
00147 
00148     m_consider.push_back(consider);
00149     HexAssert((int)m_consider.size() == m_current_depth+1);
00150 
00151     // Order the moves
00152     moves.clear();
00153     std::vector<std::pair<HexEval, HexPoint> > mvsc;
00154     for (BitsetIterator it(consider); it; ++it) 
00155     {
00156         // Prefer the best move from the TT if possible
00157         HexEval score = (*it == m_tt_bestmove) 
00158             ? 10000
00159             : resist.Score(*it);
00160         mvsc.push_back(std::make_pair(-score, *it));
00161     }
00162     // NOTE: To ensure we are deterministic, we must use stable_sort.
00163     stable_sort(mvsc.begin(), mvsc.end());
00164     for (std::size_t i = 0; i < mvsc.size(); ++i)
00165         moves.push_back(mvsc[i].second);
00166 }
00167 
00168 void WolveSearch::ExecuteMove(HexPoint move)
00169 {
00170     m_brd->PlayMove(m_toplay, move);
00171 }
00172 
00173 void WolveSearch::UndoMove(HexPoint move)
00174 {
00175     UNUSED(move);
00176     m_brd->UndoMove();
00177 }
00178 
00179 void WolveSearch::AfterStateSearched()
00180 {
00181     if (m_backup_ice_info) 
00182     {
00183         // Store new consider set in varTT
00184         bitset_t old_consider = m_consider[m_current_depth];
00185         bitset_t new_consider 
00186             = EndgameUtils::MovesToConsider(*m_brd, m_toplay) & old_consider;
00187         hash_t hash = SequenceHash::Hash(m_sequence);
00188         m_varTT.Put(hash, VariationInfo(m_current_depth, new_consider));
00189     }
00190     m_consider.pop_back();
00191 }
00192 
00193 void WolveSearch::OnSearchComplete()
00194 {
00195 }
00196 
00197 /** Computes resistance on game board using vcs from filled-in
00198     board. */
00199 void WolveSearch::ComputeResistance(Resistance& resist)
00200 {
00201     StoneBoard plain(m_brd->Width(), m_brd->Height());
00202     plain.SetPosition(m_brd->GetPosition());
00203     Groups groups;
00204     GroupBuilder::Build(plain, groups);
00205     AdjacencyGraph graphs[BLACK_AND_WHITE];
00206     ResistanceUtil::AddAdjacencies(*m_brd, graphs);
00207     resist.Evaluate(groups, graphs);
00208 }
00209 
00210 //----------------------------------------------------------------------------


6 Jan 2011 Doxygen 1.6.3