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, eval.pins(state.getTurn()), eval.pins(alt(state.getTurn())),
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.getKingPiece<P>();
00259 assert(state.hasEffectBy(alt(P), king.position()));
00260
00261 MoveVector src;
00262 move_generator::GenerateEscape<P>::generate(state,king,src);
00263
00264 if (src.size() == 1) {
00265 moves.push_back(MoveLogProb(src[0], 20));
00266 return;
00267 }
00268 BOOST_FOREACH(Move move, src) {
00269 const int prob = std::min(limit, feature_set().logProbKingEscape(state, env, move));
00270 assert(prob > 0);
00271 moves.push_back(MoveLogProb(move, prob));
00272 }
00273 moves.sortByProbability();
00274 }
00275
00276
00277
00278 template <osl::Player P>
00279 void osl::search::
00280 MoveGenerator::generateBreakThreatmate(const SearchState2& sstate)
00281 {
00282 const NumEffectState& state = sstate.state();
00283 const Move threatmate_move = record->threatmate().threatmateMove(state.getTurn());
00284 if (! threatmate_move.isNormal())
00285 return;
00286 BreakThreatmate::generate(limit, state, threatmate_move, moves);
00287 BOOST_FOREACH(const MoveLogProb& move, moves)
00288 marker.registerMove(state, move.getMove());
00289 }
00290
00291 template <osl::Player P>
00292 void osl::search::
00293 MoveGenerator::generateTakeBack(const SearchState2& sstate)
00294 {
00295 using namespace move_action;
00296 const Move last_move = sstate.lastMove();
00297 if (! last_move.isNormal())
00298 return;
00299 const Position last_to = last_move.to();
00300
00301 const NumEffectState& state = sstate.state();
00302 #ifndef MINIMAL
00303 if (in_quiesce)
00304 return quiesceCapture<P>(state, last_to);
00305 #endif
00306 MoveVector src;
00307 move_generator::GenerateCapture::generate(state, last_to, src);
00308
00309 assert(moves.empty());
00310 BOOST_FOREACH(Move move, src) {
00311 assert(! ShouldPromoteCut::canIgnoreMove<P>(move));
00312 const int prob = feature_set().logProbTakeBack(state, env, move);
00313 #ifdef OSL_SMP
00314 if (! move.isDrop() && move.ptype() != KING
00315 && env.my_pin.test(state.getPieceOnBoard(move.from()).number())) {
00316 if (move_classifier::KingOpenMove<P>::isMember(state, move.ptype(), move.from(), move.to()))
00317 continue;
00318 }
00319 #endif
00320 if (prob <= std::min(200, limit) && marker.registerIfNew(state, move))
00321 moves.push_back(MoveLogProb(move, prob));
00322 }
00323 moves.sortByProbability();
00324 }
00325
00326 namespace osl
00327 {
00328 template <Player P, Ptype PTYPE>
00329 static void makeCapture(const NumEffectState& state,
00330 MoveVector& out)
00331 {
00332 move_action::Store store(out);
00333 mask_t pieces = state.getOnBoardMask(alt(P)).template selectBit<PTYPE>()
00334 & state.effectedMask(P).getMask(PtypeFuns<PTYPE>::indexNum);
00335 while (pieces.any())
00336 {
00337 const Piece p = state.getPieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00338 assert(p.isOnBoardByOwner<PlayerTraits<P>::opponent>());
00339 move_generator::GenerateCapture::generate(P,state, p.position(), store);
00340 }
00341 }
00342 }
00343
00344 template <osl::Player P>
00345 void osl::search::
00346 MoveGenerator::addCapture(const NumEffectState& state, const RatingEnv& env, const MoveVector& src)
00347 {
00348 #ifndef MINIMAL
00349 if (in_quiesce) {
00350 BOOST_FOREACH(Move move, src) {
00351 assert(!ShouldPromoteCut::canIgnoreMove<P>(move));
00352 const int see = PieceEval::computeDiffAfterMoveForRP(state, move);
00353 if (see < 0)
00354 continue;
00355 moves.push_back(MoveLogProb(move, max_see - see));
00356 }
00357 return;
00358 }
00359 #endif
00360 BOOST_FOREACH(Move move, src) {
00361 assert(! ShouldPromoteCut::canIgnoreMove<P>(move));
00362 #ifdef SAFE_MOVE_ONLY
00363 if (! move.isDrop() && move.ptype() != KING
00364 && env.my_pin.test(state.getPieceOnBoard(move.from()).number())) {
00365 if (move_classifier::KingOpenMove<P>::isMember(state, move.ptype(), move.from(), move.to()))
00366 continue;
00367 }
00368 #endif
00369 const int prob = feature_set().logProbSeePlus(state, env, move);
00370
00371 if (prob <= 200 && marker.registerIfNew(state, move)) {
00372 moves.push_back(MoveLogProb(move, prob));
00373 }
00374 }
00375 return;
00376 }
00377
00378 template <osl::Player P>
00379 void osl::search::
00380 MoveGenerator::generateCapture(const SearchState2& sstate)
00381 {
00382 using namespace move_action;
00383
00384 const NumEffectState& state = sstate.state();
00385 MoveVector src;
00386 #if 1
00387
00388 makeCapture<P,LANCE>(state, src);
00389 makeCapture<P,BISHOP>(state, src);
00390 makeCapture<P,ROOK>(state, src);
00391
00392 makeCapture<P,KNIGHT>(state, src);
00393 makeCapture<P,SILVER>(state, src);
00394 makeCapture<P,GOLD>(state, src);
00395 #else
00396 makeCaptureOtherThanPawn<P>(state, src);
00397 #endif
00398 addCapture<P>(state, env, src);
00399 }
00400
00401 template <osl::Player P>
00402 void osl::search::
00403 MoveGenerator::generateTesuji(const SearchState2& sstate)
00404 {
00405 const NumEffectState& state = sstate.state();
00406 if (! state.inCheck() && eval_suggestion.isNormal()
00407 && marker.registerIfNew(state, eval_suggestion)) {
00408 assert(sstate.state().isValidMove(eval_suggestion));
00409 moves.push_back(MoveLogProb(eval_suggestion, 250));
00410 }
00411 #ifndef MINIMAL
00412 if (in_quiesce) {
00413 MoveVector src;
00414 move_generator::Promote<P>::generate(state, src);
00415 makeCapture<P,PAWN>(state, src);
00416 addCapture<P>(state, env, src);
00417 }
00418 #endif
00419 }
00420
00421 #ifndef MINIMAL
00422 template <osl::Player P>
00423 void osl::search::
00424 MoveGenerator::quiesceCapture(const NumEffectState& state, Position to)
00425 {
00426 MoveVector moves;
00427 move_generator::GenerateCapture::generate(state, to, moves);
00428
00429 BOOST_FOREACH(Move move, moves) {
00430 assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(move));
00431 int see = PieceEval::computeDiffAfterMoveForRP(state, move);
00432 if (see < 0)
00433 continue;
00434 this->moves.push_back(MoveLogProb(move, max_see - see));
00435 }
00436 this->moves.sortByProbabilityReverse();
00437 }
00438 #endif
00439
00440 template <osl::Player P>
00441 void osl::search::
00442 MoveGenerator::generateAll(const SearchState2& sstate)
00443 {
00444 #ifndef MINIMAL
00445 if (in_quiesce)
00446 return;
00447 #endif
00448 const NumEffectState& state = sstate.state();
00449 MoveLogProbVector all;
00450 feature_set().generateLogProb(state, env, limit, all, in_pv);
00451 #ifdef STAT_WIDTH_VS_LIMIT
00452 const size_t moves_size_before = moves.size();
00453 #endif
00454 BOOST_FOREACH(const MoveLogProb& move, all) {
00455 assert(!ShouldPromoteCut::canIgnoreAndNotDrop<P>(move.getMove()));
00456 const Move m = move.getMove();
00457 int limit = move.getLogProb();
00458 if (this->limit >= 400) {
00459 using namespace move_classifier;
00460 if (m.capturePtype() != PTYPE_EMPTY
00461 || m.isPromote()
00462 || (in_pv && MoveAdaptor<Check<P> >::isMember(state, move.getMove())))
00463 limit = std::min(limit, 400);
00464 }
00465 if (limit <= this->limit
00466 && marker.registerIfNew(state, move.getMove())) {
00467 #ifndef NDEBUG
00468 if (! m.isDrop()) {
00469 assert(! (env.my_pin.test(state.getPieceOnBoard(m.from()).number())
00470 && move_classifier::KingOpenMove<P>::isMember(state, m.ptype(), m.from(), m.to())));
00471 assert(! (m.ptype() == KING && state.hasEffectBy(alt(P), m.to())));
00472 }
00473 #endif
00474 moves.push_back(MoveLogProb(move.getMove(), limit));
00475 }
00476 }
00477 #ifdef STAT_WIDTH_VS_LIMIT
00478 Width_VS_Limit.average(limit).add(moves.size() - moves_size_before);
00479 #endif
00480 }
00481
00482 #ifndef MINIMAL
00483 void osl::search::
00484 MoveGenerator::generateAll(Player P, const SearchState2& state,
00485 analyzer::CategoryMoveVector& out)
00486 {
00487 assert(moves.size() == 0);
00488
00489 for (int i=0; i<FINISH; ++i) {
00490 if (! Generators[playerToIndex(P)][i])
00491 continue;
00492 (this->*Generators[playerToIndex(P)][i])(state);
00493 out.push_front(analyzer::CategoryMoves(moves, GeneratorNames[i]));
00494 bool generated = moves.size();
00495 moves.clear();
00496 if (i == KING_ESCAPE && generated)
00497 break;
00498 }
00499 out.reverse();
00500 }
00501 #endif
00502
00503 template <osl::Player P>
00504 void
00505 #if (defined __GNUC__) && (! defined GPSONE) && (! defined GPSUSIONE)
00506 __attribute__ ((used))
00507 #endif
00508 osl::search::
00509 MoveGenerator::generateAll(const SearchState2& state, MoveLogProbVector& out)
00510 {
00511 using namespace move_classifier;
00512 for (MoveLogProb m = nextTacticalMove<P>(state);
00513 m.validMove(); m = nextTacticalMove<P>(state)) {
00514 assert(state.state().isValidMove(m.getMove()));
00515 if (ConditionAdaptor<SafeMove>::isMember(state.state(), m.getMove()))
00516 out.push_back(m);
00517 }
00518 for (MoveLogProb m = nextMove<P>(state); m.validMove();
00519 m = nextMove<P>(state)) {
00520 assert(state.state().isValidMove(m.getMove()));
00521 if (ConditionAdaptor<SafeMove>::isMember(state.state(), m.getMove()))
00522 out.push_back(m);
00523 }
00524 }
00525
00526 void osl::search::
00527 MoveGenerator::generateAll(Player P, const SearchState2& state, MoveLogProbVector& out)
00528 {
00529 if (P==BLACK)
00530 generateAll<BLACK>(state, out);
00531 else
00532 generateAll<WHITE>(state, out);
00533 }
00534
00535 namespace osl
00536 {
00537 namespace search
00538 {
00539 template const MoveLogProb MoveGenerator::nextMoveWithGeneration<BLACK>(const SearchState2&);
00540 template const MoveLogProb MoveGenerator::nextMoveWithGeneration<WHITE>(const SearchState2&);
00541
00542 template const MoveLogProb MoveGenerator::nextTacticalMoveWithGeneration<BLACK>(const SearchState2&);
00543 template const MoveLogProb MoveGenerator::nextTacticalMoveWithGeneration<WHITE>(const SearchState2&);
00544 }
00545 }
00546
00547
00548
00549
00550
00551