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 //----------------------------------------------------------------------------