moveGenerator.cc
Go to the documentation of this file.
00001 /* moveGenerator.cc
00002  */
00003 #include "osl/search/moveGenerator.h"
00004 #include "osl/search/searchState2.h"
00005 #include "osl/search/shouldPromoteCut.h"
00006 #include "osl/search/sortCaptureMoves.h"
00007 #include "osl/search/breakThreatmate.h"
00008 #include "osl/search/analyzer/categoryMoveVector.h"
00009 #include "osl/move_generator/capture_.h"
00010 #include "osl/move_generator/escape_.h"
00011 #include "osl/move_generator/promote_.h"
00012 #include "osl/move_generator/addEffect_.h"
00013 #include "osl/move_generator/allMoves.h"
00014 #include "osl/move_generator/attackToPinned.h"
00015 #include "osl/move_action/store.h"
00016 #include "osl/move_classifier/check_.h"
00017 #include "osl/move_classifier/safeMove.h"
00018 #include "osl/move_classifier/moveAdaptor.h"
00019 #include "osl/effect_util/effectUtil.h"
00020 #include "osl/rating/featureSet.h"
00021 #include "osl/rating/ratingEnv.h"
00022 #include "osl/eval/pieceEval.h"
00023 #include "osl/eval/progressEval.h"
00024 #include "osl/eval/ml/openMidEndingEval.h"
00025 #include "osl/stat/average.h"
00026 #include <boost/foreach.hpp>
00027 #include <iostream>
00028 #include <iomanip>
00029 
00030 // #define STAT_WIDTH_VS_LIMIT
00031 
00032 #ifndef NDEBUG
00033 #  define SAFE_MOVE_ONLY
00034 #endif
00035 const int max_see = 20000;
00036 
00037 static const osl::rating::FeatureSet *static_feature_set;
00038 static const osl::rating::FeatureSet& feature_set()
00039 {
00040   return *static_feature_set;
00041 }
00042 
00043 void osl::search::MoveGenerator::initOnce()
00044 {
00045   if (static_feature_set == 0)
00046     static_feature_set = &rating::StandardFeatureSet::instance();
00047 }
00048 
00049 namespace osl
00050 {
00051   namespace search
00052   {
00053     const CArray2d<MoveGenerator::generator_t, 2, MoveGenerator::FINISH> MoveGenerator::Generators = {{
00054       {
00055         0,
00056         &MoveGenerator::generateKingEscape<BLACK>,
00057         &MoveGenerator::generateTakeBack<BLACK>,
00058         &MoveGenerator::generateBreakThreatmate<BLACK>,
00059         &MoveGenerator::generateCapture<BLACK>,
00060         0,
00061         &MoveGenerator::generateTesuji<BLACK>,
00062         &MoveGenerator::generateAll<BLACK>,
00063       },
00064       {
00065         0,
00066         &MoveGenerator::generateKingEscape<WHITE>,
00067         &MoveGenerator::generateTakeBack<WHITE>,
00068         &MoveGenerator::generateBreakThreatmate<WHITE>,
00069         &MoveGenerator::generateCapture<WHITE>,
00070         0,
00071         &MoveGenerator::generateTesuji<WHITE>,
00072         &MoveGenerator::generateAll<WHITE>,
00073       }
00074     }};
00075     const CArray<const char *, MoveGenerator::FINISH> MoveGenerator::GeneratorNames = {{
00076       "INITIAL", "KING_ESCAPE", "TAKEBACK", "BREAK_THREATMATE", "TACTICAL", "SENTINEL", "TESUJI", "ALL", 
00077     }};
00078 #ifdef STAT_WIDTH_VS_LIMIT
00079     struct WidthVSLimit 
00080     {
00081       CArray<stat::Average,10> averages;
00082 
00083       ~WidthVSLimit()
00084       {
00085         report();
00086       }
00087       stat::Average& average(int limit) 
00088       {
00089         limit /= 100 - 3;
00090         return averages[std::min(std::max(limit,0),(int)averages.size()-1)];
00091       }
00092       void report()
00093       {
00094         std::cerr << "WidthVSLimit@MoveGenerator\n";
00095         for (int limit=300; limit<300+(int)averages.size()*100; limit+=100) {
00096           std::cerr << std::setw(5) << limit << " " << average(limit).getAverage() << std::endl;
00097         }
00098       }
00099     } Width_VS_Limit;
00100 #endif
00101     template
00102     void MoveGenerator::init<osl::eval::ProgressEval>(
00103       int limit, const SimpleHashRecord *record, const osl::eval::ProgressEval&,
00104       const NumEffectState&, bool in_pv, Move hash_move, bool quiesce);
00105     template
00106     void MoveGenerator::init<osl::eval::ml::OpenMidEndingEval>(
00107       int limit, const SimpleHashRecord *record,
00108       const osl::eval::ml::OpenMidEndingEval&,
00109       const NumEffectState&, bool in_pv, Move hash_move, bool quiesce);
00110   }
00111 }
00112 
00113 /* ------------------------------------------------------------------------- */
00114 
00115 osl::search::
00116 MoveMarker::MoveMarker() : cur(1) 
00117 {
00118   marker.fill(0);
00119 }
00120 
00121 void osl::search::
00122 MoveMarker::clear() 
00123 {
00124   ++cur;
00125   if (cur == 0) {
00126     marker.fill(0);
00127     cur = 1;
00128   }
00129 }
00130 
00131 bool osl::search::
00132 MoveMarker::registerIfNew(const NumEffectState& state, Move m)
00133 {
00134   value_t& val = marker(toIndex(m), pieceIndex(state, m));
00135   if (val == cur)
00136     return false;
00137   val = cur;
00138   return true;
00139 }
00140 
00141 bool osl::search::
00142 MoveMarker::registered(const NumEffectState& state, Move m) const
00143 {
00144   return marker(toIndex(m), pieceIndex(state, m)) == cur;
00145 }
00146 
00147 /* ------------------------------------------------------------------------- */
00148 
00149 osl::search::
00150 MoveGenerator::MoveGenerator() : record(0), progress(16)
00151 {
00152 }
00153 
00154 int osl::search::
00155 MoveGenerator::captureValue(Ptype ptype)
00156 {
00157   if (! isPiece(ptype))
00158     return 0;
00159   int result 
00160     = eval::Ptype_Eval_Table.captureValue(newPtypeO(WHITE, ptype));
00161   assert(result >= 0);
00162   return result;
00163 }
00164 
00165 template <class EvalT>
00166 void osl::search::
00167 MoveGenerator::init(int l, const SimpleHashRecord *r,
00168                     const EvalT& eval,
00169                     const NumEffectState& state, bool in_pv, Move hash_move,
00170                     bool quiesce) 
00171 {
00172   assert(r);
00173   assert(l > 0);
00174   limit = l;
00175   record = r;
00176   cur_state = INITIAL;
00177   moves.clear();
00178   cur_index = tried = 0;
00179   progress = eval.progress32();
00180   eval_suggestion = eval.suggestMove(state);
00181 
00182   marker.clear();
00183   env.make(state, state.pin(state.turn()), state.pin(alt(state.turn())),
00184            eval.progress16());
00185   if (hash_move.isNormal())
00186     marker.registerMove(state, hash_move);
00187 #ifndef MINIMAL
00188   in_quiesce = quiesce;
00189 #endif
00190   this->in_pv = in_pv;
00191 }
00192 
00193 void osl::search::
00194 MoveGenerator::dump() const
00195 {
00196   std::cerr << "generator " << cur_state << " index " << cur_index 
00197             << " limit " << limit << " tried " << tried << "\n";
00198   std::cerr << moves.size() << "\n"
00199 #ifndef MINIMAL
00200    << moves
00201 #endif
00202     ;
00203 }
00204 
00205 template <osl::Player P>
00206 const osl::MoveLogProb osl::search::
00207 MoveGenerator::nextTacticalMoveWithGeneration(const SearchState2& state) 
00208 {       
00209   assert(record);
00210   while (true) {
00211     assert(cur_index >= moves.size());
00212     if (cur_state == KING_ESCAPE && record->inCheck()) {
00213       cur_state = FINISH;
00214       break;
00215     }
00216     if (++cur_state >= TACTICAL_FINISH)
00217       break;
00218     // generate
00219     assert(Generators[playerToIndex(P)][cur_state]);
00220     (this->*Generators[playerToIndex(P)][cur_state])(state);
00221     if (cur_index < moves.size()) {
00222       ++tried;
00223       return moves[cur_index++];
00224     } 
00225   }
00226   return MoveLogProb();
00227 }
00228 
00229 template <osl::Player P>
00230 const osl::MoveLogProb osl::search::
00231 MoveGenerator::nextMoveWithGeneration(const SearchState2& state) 
00232 {       
00233   assert(record);
00234   while (true) {
00235     assert(cur_index >= moves.size());
00236     if (++cur_state >= FINISH)
00237       break;
00238     // generate
00239     assert(Generators[playerToIndex(P)][cur_state]);
00240     (this->*Generators(playerToIndex(P), cur_state))(state);
00241     if (cur_index < moves.size()) {
00242       ++tried;
00243       return moves[cur_index++];
00244     } 
00245   }
00246   return MoveLogProb();
00247 }
00248 
00249 template <osl::Player P>
00250 void osl::search::
00251 MoveGenerator::generateKingEscape(const SearchState2& sstate)
00252 {
00253   env.history = sstate.history();
00254   if (! record->inCheck()) 
00255     return;
00256 
00257   const NumEffectState& state = sstate.state();
00258   const Piece king = state.kingPiece<P>();
00259   assert(state.hasEffectAt(alt(P), king.square()));
00260 
00261   MoveVector src;
00262   move_generator::GenerateEscape<P>::generate(state,king,src);
00263   size_t last = src.size();
00264   for (size_t i=0; i<last; ++i)
00265     if (src[i].hasIgnoredUnpromote<P>())
00266       src.push_back(src[i].unpromote());
00267 
00268   if (src.size() == 1) {
00269     moves.push_back(MoveLogProb(src[0], 20));
00270     return;
00271   }
00272   BOOST_FOREACH(Move move, src) {
00273     const int prob = std::min(limit, feature_set().logProbKingEscape(state, env, move));
00274     assert(prob > 0);
00275     moves.push_back(MoveLogProb(move, prob));
00276   }
00277   moves.sortByProbability();
00278 }
00279 
00280 
00281 
00282 template <osl::Player P>
00283 void osl::search::
00284 MoveGenerator::generateBreakThreatmate(const SearchState2& sstate)
00285 {
00286   const NumEffectState& state = sstate.state();
00287   const Move threatmate_move = record->threatmate().threatmateMove(state.turn());
00288   if (! threatmate_move.isNormal())
00289     return;
00290   BreakThreatmate::generate(limit, state, threatmate_move, moves);
00291   BOOST_FOREACH(const MoveLogProb& move, moves)
00292     marker.registerMove(state, move.move());
00293 }
00294 
00295 template <osl::Player P>
00296 void osl::search::
00297 MoveGenerator::generateTakeBack(const SearchState2& sstate)
00298 {
00299   using namespace move_action;
00300   const Move last_move = sstate.lastMove();
00301   if (! last_move.isNormal())
00302     return;
00303   const Square last_to = last_move.to();
00304   
00305   const NumEffectState& state = sstate.state();
00306 #ifndef MINIMAL
00307   if (in_quiesce)
00308     return quiesceCapture<P>(state, last_to);
00309 #endif
00310   MoveVector src;
00311   move_generator::GenerateCapture::generate(state, last_to, src);
00312 
00313   assert(moves.empty());
00314   BOOST_FOREACH(Move move, src) {
00315     assert(! ShouldPromoteCut::canIgnoreMove<P>(move));
00316     const int prob = feature_set().logProbTakeBack(state, env, move);
00317 #ifdef OSL_SMP
00318     if (! move.isDrop() && move.ptype() != KING
00319         && env.my_pin.test(state.pieceOnBoard(move.from()).number())) {
00320       if (move_classifier::KingOpenMove<P>::isMember(state, move.ptype(), move.from(), move.to()))
00321         continue;
00322     }
00323 #endif
00324     if (prob <= std::min(200, limit) && marker.registerIfNew(state, move))
00325       moves.push_back(MoveLogProb(move, prob));
00326   }
00327   moves.sortByProbability();
00328 }
00329 
00330 namespace osl
00331 {
00332   template <Player P, Ptype PTYPE>
00333   static void makeCapture(const NumEffectState& state, 
00334                                        MoveVector& out)
00335   {
00336     move_action::Store store(out);
00337     mask_t pieces = state.piecesOnBoard(alt(P)).template selectBit<PTYPE>() 
00338       & state.effectedMask(P).getMask(PtypeFuns<PTYPE>::indexNum);
00339     while (pieces.any())
00340     {
00341       const Piece p = state.pieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00342       assert(p.isOnBoardByOwner<PlayerTraits<P>::opponent>());
00343       move_generator::GenerateCapture::generate(P,state, p.square(), store);
00344     }
00345   }
00346 }
00347 
00348 template <osl::Player P>
00349 void osl::search::
00350 MoveGenerator::addCapture(const NumEffectState& state, const RatingEnv& env, const MoveVector& src)
00351 {
00352 #ifndef MINIMAL
00353   if (in_quiesce) {
00354     BOOST_FOREACH(Move move, src) {
00355       assert(!ShouldPromoteCut::canIgnoreMove<P>(move));
00356       const int see = PieceEval::computeDiffAfterMoveForRP(state, move);
00357       if (see < 0)
00358         continue;
00359       moves.push_back(MoveLogProb(move, max_see - see));
00360     }
00361     return;
00362   }
00363 #endif
00364   BOOST_FOREACH(Move move, src) {
00365     assert(! ShouldPromoteCut::canIgnoreMove<P>(move));
00366 #ifdef SAFE_MOVE_ONLY
00367     if (! move.isDrop() && move.ptype() != KING
00368         && env.my_pin.test(state.pieceOnBoard(move.from()).number())) {
00369       if (move_classifier::KingOpenMove<P>::isMember(state, move.ptype(), move.from(), move.to()))
00370         continue;
00371     }
00372 #endif
00373     const int prob = feature_set().logProbSeePlus(state, env, move);
00374     // const int prob = feature_set().logProbTakeBack(state, env, move);
00375     if (prob <= 200 && marker.registerIfNew(state, move)) {
00376       moves.push_back(MoveLogProb(move, prob));
00377     }
00378   }
00379   return;
00380 }
00381 
00382 template <osl::Player P>
00383 void osl::search::
00384 MoveGenerator::generateCapture(const SearchState2& sstate)
00385 {
00386   using namespace move_action;
00387 
00388   const NumEffectState& state = sstate.state();
00389   MoveVector src;
00390 #if 1
00391   // lance, bishop, rook
00392   makeCapture<P,LANCE>(state, src);
00393   makeCapture<P,BISHOP>(state, src);
00394   makeCapture<P,ROOK>(state, src);
00395   // knight, silver, gold
00396   makeCapture<P,KNIGHT>(state, src);
00397   makeCapture<P,SILVER>(state, src);
00398   makeCapture<P,GOLD>(state, src);
00399 #else
00400   makeCaptureOtherThanPawn<P>(state, src);
00401 #endif
00402   addCapture<P>(state, env, src);
00403 }
00404 
00405 template <osl::Player P>
00406 void osl::search::
00407 MoveGenerator::generateTesuji(const SearchState2& sstate)
00408 {
00409   const NumEffectState& state = sstate.state();
00410   if (! state.inCheck() && eval_suggestion.isNormal()
00411       && marker.registerIfNew(state, eval_suggestion)) {
00412     assert(sstate.state().isValidMove(eval_suggestion));
00413     moves.push_back(MoveLogProb(eval_suggestion, 250));
00414   }
00415 #ifndef MINIMAL
00416   if (in_quiesce) {
00417     MoveVector src;
00418     move_generator::Promote<P>::generate(state, src);
00419     makeCapture<P,PAWN>(state, src);
00420     addCapture<P>(state, env, src);
00421   }
00422 #endif
00423 }
00424 
00425 #ifndef MINIMAL
00426 template <osl::Player P>
00427 void osl::search::
00428 MoveGenerator::quiesceCapture(const NumEffectState& state, Square to)
00429 {
00430   MoveVector moves;
00431   move_generator::GenerateCapture::generate(state, to, moves);
00432 
00433   BOOST_FOREACH(Move move, moves) {
00434     assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(move));
00435     int see = PieceEval::computeDiffAfterMoveForRP(state, move);
00436     if (see < 0)
00437       continue;
00438     this->moves.push_back(MoveLogProb(move, max_see - see));
00439   }
00440   this->moves.sortByProbabilityReverse();
00441 }
00442 #endif
00443 
00444 template <osl::Player P>
00445 void osl::search::
00446 MoveGenerator::generateAll(const SearchState2& sstate)
00447 {
00448 #ifndef MINIMAL
00449   if (in_quiesce) 
00450     return;
00451 #endif
00452   const NumEffectState& state = sstate.state();
00453   MoveLogProbVector all;
00454   feature_set().generateLogProb(state, env, limit, all, in_pv);
00455 #ifdef STAT_WIDTH_VS_LIMIT
00456   const size_t moves_size_before = moves.size();
00457 #endif
00458   BOOST_FOREACH(const MoveLogProb& move, all) {
00459     assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(move.move()));
00460     const Move m = move.move();
00461     int limit = move.logProb();
00462     if (this->limit >= 400) {
00463       using namespace move_classifier;
00464       if (m.isCaptureOrPromotion()
00465           || (in_pv && MoveAdaptor<Check<P> >::isMember(state, move.move())))
00466         limit = std::min(limit, 400);
00467     }
00468     if (limit <= this->limit
00469         && marker.registerIfNew(state, move.move())) {
00470 #ifndef NDEBUG
00471       if (! m.isDrop()) {
00472         assert(! (env.my_pin.test(state.pieceOnBoard(m.from()).number())
00473                   && move_classifier::KingOpenMove<P>::isMember(state, m.ptype(), m.from(), m.to())));
00474         assert(! (m.ptype() == KING && state.hasEffectAt(alt(P), m.to())));
00475       }
00476 #endif
00477       moves.push_back(MoveLogProb(move.move(), limit));
00478     }
00479   }
00480 #ifdef STAT_WIDTH_VS_LIMIT
00481   Width_VS_Limit.average(limit).add(moves.size() - moves_size_before);
00482 #endif
00483 }
00484 
00485 #ifndef MINIMAL
00486 void osl::search::
00487 MoveGenerator::generateAll(Player P, const SearchState2& state, 
00488                            analyzer::CategoryMoveVector& out)
00489 {
00490   assert(moves.size() == 0);
00491 
00492   for (int i=0; i<FINISH; ++i) {
00493     if (! Generators[playerToIndex(P)][i])
00494       continue;
00495     (this->*Generators[playerToIndex(P)][i])(state);
00496     out.push_front(analyzer::CategoryMoves(moves, GeneratorNames[i]));
00497     bool generated = moves.size();
00498     moves.clear();    
00499     if (i == KING_ESCAPE && generated)
00500       break;
00501   }
00502   out.reverse();
00503 }
00504 #endif
00505 
00506 template <osl::Player P>
00507 void
00508 #if (defined __GNUC__) && (! defined GPSONE) && (! defined GPSUSIONE)
00509 __attribute__ ((used))
00510 #endif
00511   osl::search::
00512 MoveGenerator::generateAll(const SearchState2& state, MoveLogProbVector& out) 
00513 {
00514   using namespace move_classifier;
00515   for (MoveLogProb m = nextTacticalMove<P>(state);
00516        m.validMove(); m = nextTacticalMove<P>(state)) {
00517     assert(state.state().isValidMove(m.move()));
00518     if (ConditionAdaptor<SafeMove>::isMember(state.state(), m.move()))
00519       out.push_back(m);
00520   }
00521   for (MoveLogProb m = nextMove<P>(state); m.validMove(); 
00522        m = nextMove<P>(state)) {
00523     assert(state.state().isValidMove(m.move()));
00524     if (ConditionAdaptor<SafeMove>::isMember(state.state(), m.move()))
00525       out.push_back(m);
00526   }
00527 }
00528 
00529 void osl::search::
00530 MoveGenerator::generateAll(Player P, const SearchState2& state, MoveLogProbVector& out) 
00531 {
00532   if (P==BLACK)
00533     generateAll<BLACK>(state, out);
00534   else
00535     generateAll<WHITE>(state, out);
00536 }
00537 
00538 namespace osl
00539 {
00540   namespace search
00541   {
00542     template const MoveLogProb MoveGenerator::nextMoveWithGeneration<BLACK>(const SearchState2&);
00543     template const MoveLogProb MoveGenerator::nextMoveWithGeneration<WHITE>(const SearchState2&);
00544 
00545     template const MoveLogProb MoveGenerator::nextTacticalMoveWithGeneration<BLACK>(const SearchState2&);
00546     template const MoveLogProb MoveGenerator::nextTacticalMoveWithGeneration<WHITE>(const SearchState2&);
00547   }
00548 }
00549 
00550 /* ------------------------------------------------------------------------- */
00551 // ;;; Local Variables:
00552 // ;;; mode:c++
00553 // ;;; c-basic-offset:2
00554 // ;;; End:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines