00001
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
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
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
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
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
00392 makeCapture<P,LANCE>(state, src);
00393 makeCapture<P,BISHOP>(state, src);
00394 makeCapture<P,ROOK>(state, src);
00395
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
00552
00553
00554