00001
00002
00003 #ifndef _QUIESCENCESEARCH2_TCC
00004 #define _QUIESCENCESEARCH2_TCC
00005
00006 #include "osl/search/quiescenceSearch2.h"
00007 #include "osl/search/quiescenceGenerator.h"
00008 #include "osl/search/quiescenceLog.h"
00009 #include "osl/search/searchTable.h"
00010 #include "osl/search/simpleHashRecord.h"
00011 #include "osl/search/simpleHashTable.h"
00012 #include "osl/search/sortCaptureMoves.h"
00013 #include "osl/search/moveStackRejections.h"
00014 #include "osl/checkmate/immediateCheckmate.h"
00015 #include "osl/hash/hashCollision.h"
00016 #include "osl/apply_move/applyMove.h"
00017 #include "osl/apply_move/applyMoveWithPath.h"
00018 #include "osl/effect_util/effectUtil.h"
00019 #include "osl/move_order/captureSort.h"
00020 #include "osl/move_classifier/check_.h"
00021 #include "osl/move_classifier/moveAdaptor.h"
00022 #include "osl/move_classifier/pawnDropCheckmate.h"
00023 #include "osl/move_generator/addEffectWithEffect.h"
00024 #include "osl/effect_util/unblockableEffect.h"
00025 #include "osl/effect_util/neighboring8Direct.h"
00026 #include "osl/eval/see.h"
00027 #include "osl/stat/ratio.h"
00028 #include "osl/hash/hashRandom.h"
00029 #include "osl/oslConfig.h"
00030
00031 #ifdef STAT_WIDTH_VS_LIMIT
00032 # include "osl/stat/average.h"
00033 # include <iostream>
00034 #endif
00035
00036 #define quiecence_assert(x,m) assert((x) || state.abort(m))
00037
00038 #ifdef RICH_QSEARCH
00039
00040 # define QSEARCH_LAST_CHECK_PENALTY
00041
00042 # define QSEARCH_PESSIMISTIC_ESCAPE_THREAT
00043
00044 # define QSEARCH_THREATMATE
00045 #endif
00046
00047 #ifdef EXTRA_RICH_QSEARCH
00048
00049 # define QSEARCH_SET_MINIMUM_MOVES
00050 #endif
00051
00052
00053
00054
00055 const int allocate_depth_in_threatmate = 400;
00056
00057 namespace osl
00058 {
00059 namespace search
00060 {
00061 struct QSearch2PrivateTraits
00062 {
00063 enum {
00064 KnightCaptureDepth = 1,
00065 PawnCaptureDepth = 3,
00066 FullPromoteDepth = 3,
00067 UtilizePromotedDepth = 5,
00068 AttackPinnedDepth = 6,
00069 };
00070 enum {
00071 EscapeDepthFromRoot = 1,
00072 EscapeFromLastMoveDepthFromRoot = 3,
00073 AttackKnightDepthFromRoot = 2,
00074 AttackGoldSilverDepthFromRoot = 2,
00075 DropDepthFromRoot = 2,
00076 AttackMajorPieceDepthFromRoot = 2,
00077 AdvanceBishopDepthFromRoot = 2,
00078 AttackKing8DepthFromRoot = 2,
00079 };
00080 enum {
00081 ThreatMateDepthFromRoot = 2,
00082 };
00083 enum {
00085 PassExtraDepth = 4,
00086 };
00087 enum {
00092 #ifdef QSEARCH_SET_MINIMUM_MOVES
00093 MinimumMoves = 6,
00094 #else
00095 MinimumMoves = 0,
00096 #endif
00097 };
00098 };
00099
00100 struct QSearch2HelperBase
00101 {
00102 int& result;
00103 int alpha, beta;
00104 Move last_move;
00105 QSearch2HelperBase(int& r, int a, int b, Move l)
00106 : result(r), alpha(a), beta(b), last_move(l)
00107 {
00108 }
00109 };
00110
00111 template <class QSearch2,Player P>
00112 struct QSearch2NextMove : public QSearch2HelperBase
00113 {
00114 typedef typename QSearch2::eval_t eval_t;
00115 QSearch2 *searcher;
00116 eval_t& ev;
00117 int additional_depth;
00118 QSearch2NextMove(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l,
00119 int additional)
00120 : QSearch2HelperBase(r, a, b, l),
00121 searcher(s), ev(e), additional_depth(additional)
00122 {
00123 }
00124 void operator()(Position)
00125 {
00126 result = (*searcher).template searchInternal<PlayerTraits<P>::opponent>
00127 (beta, alpha, ev, last_move, additional_depth, QSearch2::BeforeUpdate);
00128 }
00129 };
00130 template <class QSearch2,Player P>
00131 struct QSearch2NextTakeBack : QSearch2HelperBase
00132 {
00133 typedef typename QSearch2::eval_t eval_t;
00134 QSearch2 *searcher;
00135 eval_t& ev;
00136 QSearch2NextTakeBack(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l)
00137 : QSearch2HelperBase(r, a, b, l), searcher(s), ev(e)
00138 {
00139 }
00140 void operator()(Position)
00141 {
00142 ev.update(searcher->currentState(), last_move);
00143 result = (*searcher).template takeBackValue<PlayerTraits<P>::opponent>
00144 (beta, alpha, ev, last_move);
00145 }
00146 };
00147 template <class QSearch2,Player P>
00148 struct QSearch2TakeBackOrChase : QSearch2HelperBase
00149 {
00150 typedef typename QSearch2::eval_t eval_t;
00151 QSearch2 *searcher;
00152 eval_t& ev;
00153 QSearch2TakeBackOrChase(int& r, QSearch2 *s, int a, int b, eval_t& e, Move l)
00154 : QSearch2HelperBase(r, a, b, l), searcher(s), ev(e)
00155 {
00156 }
00157 void operator()(Position)
00158 {
00159 ev.update(searcher->currentState(), last_move);
00160 result = (*searcher).template takeBackOrChase<PlayerTraits<P>::opponent>
00161 (beta, alpha, ev, last_move);
00162 }
00163 };
00164 template <class Eval, Player P>
00165 struct QSearch2SafeEscape
00166 {
00167 const NumEffectState *state;
00168 Eval& eval;
00169 Piece target;
00170 bool has_safe_escape;
00171 bool is_invalid;
00172 Move last_move;
00173 QSearch2SafeEscape(const NumEffectState *s, Piece t, Eval& e, Move l)
00174 : state(s), eval(e), target(t), has_safe_escape(false), is_invalid(false), last_move(l)
00175 {
00176 }
00177 void operator()(Position)
00178 {
00179 const Player Turn = PlayerTraits<P>::opponent;
00180 assert(state->getTurn() == Turn);
00181 if (state->inCheck(alt(Turn)))
00182 {
00183 is_invalid = true;
00184 return;
00185 }
00186 eval.update(*state, last_move);
00187 MoveVector dummy;
00188 has_safe_escape
00189 = QuiescenceGenerator<Turn>::escapeByMoveOnly(*state, target, dummy);
00190 }
00191 };
00192 template <bool has_record>
00193 struct QSearch2Util
00194 {
00195 static bool moreMoves(const QuiescenceRecord *)
00196 {
00197 return false;
00198
00199
00200 }
00201 };
00202 }
00203 }
00204
00205
00206 template <class EvalT>
00207 template <osl::Player P>
00208 int osl::search::QuiescenceSearch2<EvalT>::
00209 searchProbCut(int alpha, int beta, eval_t& ev, Move last_move)
00210 {
00211 if (alpha != beta) {
00212 max_depth = QSearchTraits::MaxDepth/2;
00213 const int pawn_value2 = EvalT::captureValue(newPtypeO(alt(P),PAWN));
00214 const int margin = pawn_value2/2;
00215 const int alpha4 = EvalTraits<P>::max(alpha-margin,
00216 base_t::winThreshold(alt(P)));
00217 assert(EvalTraits<P>::notLessThan(alpha, alpha4));
00218 const int beta4 = EvalTraits<P>::min(beta +margin,
00219 base_t::winThreshold(P));
00220 assert(EvalTraits<P>::notLessThan(beta4, beta));
00221 const int val4 = searchInternal<P>(alpha4, beta4, ev, last_move);
00222 if (EvalTraits<P>::betterThan(val4, beta4))
00223 return val4 - (beta4-beta);
00224 if (EvalTraits<P>::betterThan(alpha4, val4))
00225 return val4 - (alpha4-alpha);
00226 }
00227 max_depth = QSearchTraits::MaxDepth;
00228 return searchInternal<P>(alpha, beta, ev, last_move);
00229 }
00230
00231 template <class EvalT>
00232 template <osl::Player P, osl::Ptype PTYPE>
00233 inline
00234 bool osl::search::QuiescenceSearch2<EvalT>::
00235 generateAndExamineTakeBack2(MoveVector& moves,
00236 QuiescenceThreat& threat2,
00237 QuiescenceThreat& threat1,
00238 int beta1, int beta2, eval_t const& ev)
00239 {
00240 mask_t pieces = state.state().effectedMask(P).template selectBit<PTYPE>()
00241 & state.state().getOnBoardMask(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
00242 if (PTYPE == PAWN || PTYPE == LANCE || PTYPE == KNIGHT)
00243 pieces &= ~state.state().effectedMask(alt(P)).getMask(PtypeFuns<PTYPE>::indexNum);
00244 while (pieces.any())
00245 {
00246 const Piece target = state.state().getPieceOf(pieces.takeOneBit()+PtypeFuns<PTYPE>::indexNum*32);
00247 assert(target.isOnBoardByOwner<PlayerTraits<P>::opponent>());
00248 assert(moves.empty());
00249 QuiescenceGenerator<P>::capture1(currentState(), target.position(), moves);
00250 const bool result
00251 = examineTakeBack2<P,false,true>(moves, threat2, threat1,
00252 beta1, beta2, ev);
00253 moves.clear();
00254 if (result)
00255 return result;
00256 }
00257 return false;
00258 }
00259
00260
00261 template <class EvalT>
00262 template <osl::Player P, osl::Ptype PTYPE, bool has_record>
00263 inline
00264 bool osl::search::QuiescenceSearch2<EvalT>::
00265 examineCapture(QuiescenceRecord *record,
00266 int& cur_val, MoveVector& moves, int& alpha, int beta,
00267 eval_t const& ev, Piece last_move_piece, int additional_depth)
00268 {
00269 assert(alpha % 2);
00270 assert(beta % 2);
00271
00272 {
00273 moves.clear();
00274 QuiescenceGenerator<P>::template capture<PTYPE,true>(state.state(), moves, last_move_piece);
00275
00276 SortCaptureMoves::sortByTakeBack(state.state(), moves);
00277
00278 return examineMoves<P,has_record,has_record,CAPTURE>
00279 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00280 additional_depth, last_move_piece.position());
00281 }
00282 return false;
00283 }
00284
00285 #ifdef STAT_WIDTH_VS_LIMIT
00286 namespace osl
00287 {
00288 namespace
00289 {
00290 struct Reporter
00291 {
00292 stat::Average average;
00293 int count;
00294 Reporter() : count(0) {}
00295 ~Reporter()
00296 {
00297 std::cerr << "QuiescenceSearch2 " << average.getAverage() << std::endl;
00298 }
00299 void newRoot() { average.add(count); count=0; }
00300 void add() { ++count; }
00301 } _reporter;
00302 }
00303 }
00304 #endif
00305
00306 template <class EvalT>
00307 template <osl::Player P, bool has_record, bool has_dont_capture,
00308 osl::search::QSearchTraits::MoveType move_type>
00309 bool osl::search::QuiescenceSearch2<EvalT>::
00310 examineMoves(QuiescenceRecord *record, int& cur_val,
00311 const Move *first, const Move *last,
00312 int& alpha, int beta, eval_t const& ev,
00313 int additional_depth, Position dont_capture)
00314 {
00315 assert(alpha % 2);
00316 assert(beta % 2);
00317
00318 assert(EvalTraits<P>::notLessThan(alpha, cur_val));
00319 #if (! defined NDEBUG) && (! defined OSL_SMP)
00320 const bool in_pv = (alpha != beta);
00321 #endif
00322 while (first != last)
00323 {
00324 const Move move = *first++;
00325 if (move_type == CHECK)
00326 {
00327 if (depth() <= 0
00328 && move.capturePtype() == PTYPE_EMPTY
00329 && ! isMajor(move.ptype()))
00330 continue;
00331 }
00332
00333 if (has_dont_capture)
00334 {
00335 const Position to = move.to();
00336 if (to == dont_capture)
00337 continue;
00338 }
00339 assert((move_type == KING_ESCAPE) || (move_type == UNKNOWN)
00340 || (! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move)));
00341
00342 if(MoveStackRejections::probe<P>(state.state(),state.history(),state.curDepth(),move,alpha,state.repetitionCounter().checkCount(alt(P)))){
00343 continue;
00344 }
00345 #ifdef QSEARCH_DEBUG
00346 QuiescenceLog::pushMove(depth(), move, record);
00347 #endif
00348 const HashKey new_hash = state.currentHash().newHashWithMove(move);
00349 int result;
00350
00351 const Sennichite next_sennichite
00352 = state.repetitionCounter().isAlmostSennichite(new_hash);
00353 if (next_sennichite.isDraw())
00354 {
00355 result = base_t::drawValue();
00356 }
00357 else if (next_sennichite.hasWinner())
00358 {
00359 result = base_t::winByFoul(next_sennichite.winner());
00360 }
00361 else
00362 {
00363 eval_t new_ev = ev;
00364 #ifdef STAT_WIDTH_VS_LIMIT
00365 if (depthFromRoot() == 0)
00366 _reporter.add();
00367 #endif
00368 assert(next_sennichite.isNormal());
00369 typedef QSearch2NextMove<QuiescenceSearch2,P> helper_t;
00370 if (has_record && alpha != beta
00371 && record->bestMove().isNormal()) {
00372
00373 helper_t helper(result, this, alpha, alpha, new_ev, move,
00374 additional_depth);
00375 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00376 if (EvalTraits<P>::betterThan(result, alpha)) {
00377 new_ev = ev;
00378 helper_t helper(result, this, alpha, beta, new_ev, move,
00379 additional_depth);
00380 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00381 }
00382 }
00383 else {
00384
00385 helper_t helper(result, this, alpha, beta, new_ev, move,
00386 additional_depth);
00387 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
00388 }
00389
00390
00391 if (base_t::isWinValue(P, result) && (! move.isPass())
00392 && move_classifier::MoveAdaptor<move_classifier::PawnDropCheckmate<P> >
00393 ::isMember(state.state(), move))
00394 {
00395 result = base_t::winByFoul(alt(P));
00396 }
00397 }
00398 if (EvalTraits<P>::betterThan(result, cur_val))
00399 {
00400 cur_val = result;
00401 if (EvalTraits<P>::betterThan(result, alpha))
00402 {
00403 alpha = result + EvalTraits<P>::delta;
00404 if (has_record)
00405 {
00406 if (base_t::isWinValue(P, cur_val))
00407 {
00408 Position king = state.state().getKingPosition(alt(P));
00409 if (Ptype_Table.hasUnblockableEffect(move.ptypeO(), move.to(), king)) {
00410 record->setLowerBound(QSearchTraits::CheckmateSpecialDepth, cur_val, move);
00411 }
00412 else {
00413
00414 record->setLowerBound(QSearchTraits::MaxDepth, cur_val, move);
00415 }
00416 assert(EvalTraits<P>::notLessThan(result, beta));
00417 return true;
00418 }
00419 else
00420 {
00421 #ifndef OSL_SMP
00422 assert((record->lowerDepth() < depth())
00423 || EvalTraits<P>::notLessThan(cur_val, record->lowerBound())
00424 || in_pv
00425 || state.abort(move));
00426 #endif
00427 record->setLowerBound(depth(), cur_val, move);
00428 }
00429 }
00430 if (EvalTraits<P>::notLessThan(result, beta))
00431 {
00432 state.setKillerMove(move);
00433 if (move.capturePtype() == PTYPE_EMPTY)
00434 {
00435 const int d = depth();
00436 state.historyTable().add(move, d*d);
00437 }
00438 return true;
00439 }
00440 }
00441 }
00442 }
00443 return false;
00444 }
00445
00446 namespace osl
00447 {
00448 namespace search
00449 {
00450 inline QuiescenceRecord *qallocate(SimpleHashTable& table,
00451 const HashKey& key,
00452 int minusDepthFromRoot,
00453 SearchState2Core& state)
00454 {
00455 assert(minusDepthFromRoot <= 0 || minusDepthFromRoot == allocate_depth_in_threatmate);
00456 SimpleHashRecord *record
00457 = table.allocate(key, minusDepthFromRoot);
00458 if (record) {
00459 state.setCurrentRecord(record);
00460 return &record->qrecord;
00461 }
00462 return 0;
00463 }
00464 }
00465 }
00466
00467 template <class EvalT>
00468 template <osl::Player P, bool has_record>
00469 inline
00470 int osl::search::QuiescenceSearch2<EvalT>::
00471 staticValue(eval_t const& ev, int alpha, int beta, QuiescenceRecord *record)
00472 {
00473 const bool in_pv = (alpha != beta);
00474 #ifndef DONT_USE_CHECKMATE
00475 if (! in_pv) {
00476 bool in_threatmate = has_record && record->threatmate.maybeThreatmate(P);
00477 if (! in_threatmate
00478 && (state.hasLastRecord(1) && state.lastRecord(1)))
00479 in_threatmate
00480 = (state.lastRecord(1)->threatmate().status(P).status() == ThreatmateState::CHECK_AFTER_THREATMATE);
00481 if (in_threatmate) {
00482 const int result = ev.value() + base_t::threatmatePenalty(P);
00483 return result;
00484 }
00485 }
00486 if (in_pv) {
00487 const Move last_move = state.lastMove();
00488 const Position king = state.state().getKingPosition(P);
00489 const bool one_hop_prook
00490 = (last_move.isNormal() && last_move.ptype() == PROOK
00491 && (last_move.capturePtype() == GOLD
00492 || last_move.capturePtype() == SILVER)
00493 && ((king.y() == last_move.to().y()
00494 && abs(king.x() - last_move.to().x()) < 3)
00495 || (king.x() == last_move.to().x()
00496 && abs(king.y() - last_move.to().y()) < 3)));
00497 if (one_hop_prook && ! has_record) {
00498 record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
00499 }
00500 if (has_record || record) {
00501
00502 Move checkmate_move=Move::INVALID();
00503 int threatmate_node = 0;
00504 if (record && record->threatmate.maybeThreatmate(P)) {
00505 threatmate_node += 50;
00506 } else if (one_hop_prook) {
00507 threatmate_node += 20;
00508 }
00509 #ifdef QSEARCH_THREATMATE
00510 else if ((depthFromRoot() < QSearch2PrivateTraits::ThreatMateDepthFromRoot)
00511 && state.tryThreatmate())
00512 threatmate_node += 20;
00513 #endif
00514 bool lose = state.isThreatmateState<P>
00515 (record->threatmateNodesLeft(threatmate_node),
00516 checkmate_move);
00517 if (! lose && record->threatmateNodesLeft(2))
00518 lose = state.isThreatmateStateShort<P>(2, checkmate_move);
00519 if (lose)
00520 {
00521 const int result = ev.value() + base_t::threatmatePenalty(P);
00522 assert(checkmate_move.isValid());
00523 record->threatmate.setThreatmate(P, checkmate_move);
00524 record->setStaticValue(QuiescenceRecord::EXACT, result,
00525 QSearchTraits::CheckmateSpecialDepth);
00526 assert(result % 2 == 0);
00527 return result;
00528 }
00529 }
00530 }
00531 #endif
00532 if (! in_pv && has_record) {
00533 if (record->hasStaticValue()) {
00534
00535 if (EvalTraits<P>::betterThan(alpha, record->staticValue())) {
00536 assert(record->staticValue() % 2 == 0);
00537 return record->staticValue();
00538 }
00539 if (record->staticValueType() == QuiescenceRecord::EXACT
00540 && (record->staticValueDepth() >= depth())) {
00541 assert(record->staticValue() % 2 == 0);
00542 return record->staticValue();
00543 }
00544 }
00545 }
00546 Move threatmate_move;
00547 if (ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>
00548 (state.state(), threatmate_move))
00549 {
00550 const int result = ev.value() + base_t::threatmatePenalty(P);
00551 if (has_record)
00552 {
00553 record->threatmate.setThreatmate(P, threatmate_move);
00554 record->setStaticValue(QuiescenceRecord::EXACT, result,
00555 QSearchTraits::CheckmateSpecialDepth);
00556 }
00557 assert(result % 2 == 0);
00558 return result;
00559 }
00560 if (alpha == beta && EvalTraits<P>::betterThan(ev.value(), beta)) {
00561
00562 int expect = ev.value() + ev.captureValue(newPtypeO(P, GOLD));
00563 Piece threat = state.state().findThreatenedPiece(P);
00564 if (threat.isPiece())
00565 expect += ev.captureValue(threat.ptypeO());
00566 if (EvalTraits<P>::betterThan(expect, beta))
00567 return expect;
00568 }
00569 const int eval_alpha = alpha;
00570 QuiescenceThreat threat1, threat2;
00571 const int result = staticValueWithThreat<P>(ev, eval_alpha, threat1, threat2);
00572 if (has_record)
00573 {
00574 record->setStaticValue(EvalTraits<P>::betterThan(eval_alpha, result)
00575 ? QuiescenceRecord::UPPER_BOUND
00576 : QuiescenceRecord::EXACT,
00577 result, depth(),
00578 threat1, threat2);
00579 }
00580 assert(result % 2 == 0);
00581 return result;
00582 }
00583
00584 template <class EvalT>
00585 template <osl::Player P>
00586 int osl::search::QuiescenceSearch2<EvalT>::
00587 searchInternal(int alpha, int beta, eval_t& ev, Move last_move,
00588 int additional_depth, EvalUpdateState need_eval_update)
00589 {
00590 #ifdef STAT_WIDTH_VS_LIMIT
00591 if (depthFromRoot() == 0)
00592 _reporter.newRoot();
00593 #endif
00594 #ifdef QSEARCH_DEBUG
00595 if (depthFromRoot() == 0)
00596 QuiescenceLog::enter(state.state());
00597 #endif
00598 #ifdef MAKE_PV_IN_QUIESCE2
00599 state.initPV();
00600 #endif
00601 ++node_count;
00602 assert(alpha % 2);
00603 assert(beta % 2);
00604 quiecence_assert(EvalTraits<P>::notLessThan(beta, alpha), last_move);
00605 assert(EvalTraits<P>::notLessThan(alpha, base_t::winThreshold(alt(P))));
00606 assert(EvalTraits<P>::notLessThan(base_t::winThreshold(P), beta));
00607 assert(last_move.player() == alt(P));
00608
00609
00610 if (state.state().inCheck(alt(P)))
00611 return base_t::winByFoul(P);
00612
00613 assert(state.hasLastRecord());
00614 QuiescenceRecord *record
00615 = qallocate(table, state.currentHash(), depth()-QSearchTraits::MaxDepth,
00616 state);
00617 const QuiescenceRecord *parent
00618 = (state.hasLastRecord(1) && state.lastRecord(1))
00619 ? &(state.lastRecord(1)->qrecord) : 0;
00620 const bool near_checkmate = parent
00621 && (parent->threatmate.maybeThreatmate(alt(P))
00622 || parent->threatmate.mayHaveCheckmate(P)
00623 || (parent->threatmate.status(P).status()
00624 == ThreatmateState::CHECK_AFTER_THREATMATE));
00625 if (! record && near_checkmate)
00626 {
00627 const int depth = (alpha != beta) ? allocate_depth_in_threatmate : 0;
00628 record
00629 = qallocate(table, state.currentHash(), depth, state);
00630 }
00631 int result;
00632 if (! record) {
00633 result = searchMain<P,false>(0, alpha, beta, ev, last_move,
00634 additional_depth, need_eval_update);
00635 if (near_checkmate) {
00636 if ((EvalTraits<P>::betterThan(alpha, result)
00637 && parent->threatmate.maybeThreatmate(alt(P)))
00638 || (EvalTraits<P>::betterThan(result, alpha)
00639 && parent->threatmate.status(P).status()
00640 == ThreatmateState::CHECK_AFTER_THREATMATE)) {
00641 record
00642 = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
00643 }
00644 }
00645 }
00646 if (record)
00647 {
00648 const bool is_king_in_check = state.state().inCheck();
00649 record->updateThreatmate(P, (parent ? &(parent->threatmate) : 0),
00650 is_king_in_check);
00651 result = searchMain<P,true>(record, alpha, beta, ev, last_move,
00652 additional_depth, need_eval_update);
00653 #ifdef MAKE_PV_IN_QUIESCE2
00654 if ((alpha != beta) && EvalTraits<P>::betterThan(result, alpha))
00655 state.makePV(record->bestMove());
00656 #endif
00657 }
00658 #ifdef QSEARCH_DEBUG
00659 QuiescenceLog::node(depth(), alpha, beta, result);
00660 #endif
00661 assert(result % 2 == 0);
00662 return result;
00663 }
00664
00665 template <class EvalT>
00666 int osl::search::QuiescenceSearch2<EvalT>::
00667 currentValueWithLastThreat(eval_t const& ev, Piece last_move_piece)
00668 {
00669 int static_value = ev.value();
00670 if (! (depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot))
00671 return static_value;
00672
00673 assert(last_move_piece.isPiece());
00674 const Player P = last_move_piece.owner();
00675 PieceVector targets;
00676 const Position from = last_move_piece.position();
00677 EffectUtil::findThreat<EvalT>(state.state(), from, last_move_piece.ptypeO(),
00678 targets);
00679 if (targets.empty())
00680 return static_value;
00681 if (targets[0].ptype() == KING)
00682 {
00683 if (targets.size() < 2)
00684 return static_value;
00685
00686 int threat = eval_t::captureValue(targets[1].ptypeO());
00687 if (state.state().hasEffectBy(alt(P), targets[1].position()))
00688 threat += eval_t::captureValue(last_move_piece.ptypeO());
00689 assert(eval::betterThan(P, threat, 0));
00690 return static_value + threat;
00691 }
00692 int first_threat = eval_t::captureValue(targets[0].ptypeO());
00693 if (state.state().hasEffectBy(alt(P), targets[0].position()))
00694 first_threat += eval_t::captureValue(last_move_piece.ptypeO());
00695 assert(eval::betterThan(P, first_threat, 0));
00696 first_threat /= SecondThreat;
00697 if (targets.size() < 2)
00698 return static_value + (first_threat & (~0x1));
00699
00700 int second_threat = eval_t::captureValue(targets[1].ptypeO());
00701 if (state.state().hasEffectBy(alt(P), targets[1].position()))
00702 second_threat += eval_t::captureValue(last_move_piece.ptypeO());
00703 assert(eval::betterThan(P, second_threat, 0));
00704 return static_value + ((first_threat + second_threat) & (~0x1));
00705 }
00706
00707 template <class EvalT>
00708 template <osl::Player P>
00709 int osl::search::QuiescenceSearch2<EvalT>::
00710 passValue(int alpha, int beta, eval_t const& ev)
00711 {
00712
00713
00714 BOOST_STATIC_ASSERT(QSearch2PrivateTraits::EscapeDepthFromRoot <= 2);
00715 const Move pass = Move::PASS(P);
00716 int result;
00717 typedef QSearch2NextMove<QuiescenceSearch2,P> helper_t;
00718 helper_t helper(result, this, alpha, beta, ev, pass, 0);
00719 const HashKey new_hash = state.currentHash().newHashWithMove(pass);
00720
00721 max_depth -= QSearch2PrivateTraits::PassExtraDepth;
00722 state.doUndoMoveOrPass<P,helper_t>(new_hash, pass, helper);
00723 max_depth += QSearch2PrivateTraits::PassExtraDepth;
00724
00725 return result;
00726 }
00727
00728 template <class EvalT>
00729 template <osl::Player P, bool has_record>
00730 int osl::search::QuiescenceSearch2<EvalT>::
00731 searchMain(QuiescenceRecord *record,
00732 int alpha, int beta, eval_t& ev, Move last_move,
00733 int additional_depth, EvalUpdateState& need_eval_update)
00734 {
00735 const bool in_pv = (alpha != beta);
00736 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00737 static stat::Ratio ratio("QSearch2: cut");
00738 #endif
00739 assert((! has_record) || record);
00740 assert(alpha % 2);
00741 assert(beta % 2);
00742 assert((last_move == state.lastMove())
00743 || ! last_move.isNormal() || ! state.lastMove().isNormal());
00744 #if (!defined OSL_USE_RACE_DETECTOR) && (!defined MINIMAL)
00745 state.depth_node_count_quiesce[state.curDepth()]++;
00746 #endif
00747 const int node_count_before = node_count;
00748 const Position last_to = last_move.to();
00749 int cur_val = base_t::winByCheckmate(alt(P));
00750 if (has_record)
00751 {
00752 if ((! in_pv && record->lowerDepth() >= depth())
00753 || record->lowerDepth() >= QSearchTraits::HistorySpecialDepth)
00754 {
00755 if (EvalTraits<P>::notLessThan(record->lowerBound(), cur_val))
00756 {
00757 cur_val = record->lowerBound();
00758 if (EvalTraits<P>::betterThan(record->lowerBound(), alpha))
00759 {
00760 alpha = record->lowerBound() + EvalTraits<P>::delta;
00761 if (EvalTraits<P>::betterThan(record->lowerBound(), beta))
00762 {
00763 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00764 ratio.add(true);
00765 #endif
00766 return record->lowerBound();
00767 }
00768 }
00769 }
00770 }
00771 #ifndef DONT_USE_CHECKMATE
00772 assert(record);
00773
00774 if (in_pv) {
00775 Move checkmate_move=Move::INVALID();
00776 if (need_eval_update == BeforeUpdate) {
00777 ev.update(state.state(), last_move);
00778 need_eval_update = AfterUpdate;
00779 }
00780 bool win = state.isWinningState<P>
00781 (0, checkmate_move);
00782 if (! win && record->threatmate.mayHaveCheckmate(alt(P))) {
00783 win = state.isWinningStateShort<P>(2, checkmate_move);
00784 }
00785 if (win) {
00786 const int result = base_t::winByCheckmate(P);
00787 assert(checkmate_move.isValid());
00788 assert(state.state().isValidMove(checkmate_move));
00789 record->setLowerBound(QSearchTraits::CheckmateSpecialDepth,
00790 result, checkmate_move);
00791 return result;
00792 }
00793 }
00794 #endif
00795 if ((! in_pv && record->upperDepth() >= depth())
00796 || record->upperDepth() >= QSearchTraits::HistorySpecialDepth)
00797 {
00798 if (EvalTraits<P>::betterThan(beta, record->upperBound()))
00799 {
00800 beta = record->upperBound() - EvalTraits<P>::delta;
00801 if (EvalTraits<P>::betterThan(alpha, record->upperBound()))
00802 {
00803 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00804 ratio.add(true);
00805 #endif
00806 return record->upperBound();
00807 }
00808 }
00809 }
00810 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
00811 ratio.add(false);
00812 #endif
00813 }
00814 if (need_eval_update == BeforeUpdate) {
00815 ev.update(state.state(), last_move);
00816 need_eval_update = AfterUpdate;
00817 }
00818 const bool is_king_in_check = state.state().inCheck();
00819 MoveVector moves;
00820 if (is_king_in_check)
00821 {
00822 if (last_move.isNormal() && last_move.capturePtype() != PTYPE_EMPTY
00823 && unpromote(last_move.capturePtype()) == ROOK
00824 && unpromote(last_move.ptype()) != ROOK)
00825 ++additional_depth;
00826 else
00827
00828 if (state.lastMove(2).isNormal()
00829 && state.lastMove(3).isNormal()
00830 && state.lastMove(4).isNormal()
00831 && state.lastMove(2).to() == last_move.to()
00832 && state.lastMove(3).to() == last_move.to()
00833 && state.lastMove(4).to() == last_move.to())
00834 ++additional_depth;
00835
00836 {
00837 QuiescenceGenerator<P>::escapeKing(state.state(), moves);
00838
00839 move_order::CaptureSort::sort(moves.begin(), moves.end());
00840 examineMoves<P,has_record,false,KING_ESCAPE>
00841 (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
00842 additional_depth);
00843 }
00844 if (has_record)
00845 {
00846 if (EvalTraits<P>::betterThan(beta, cur_val))
00847 record->setUpperBound(depth(), cur_val);
00848 }
00849 return cur_val;
00850 }
00851 assert(! is_king_in_check);
00852 King8Info king_info(state.state().Iking8Info(alt(P)));
00853 PieceMask pins = ev.pins(alt(P));
00854 Move checkmate_move=Move::INVALID();
00855 Position kingPosition=state.state().template getKingPosition<PlayerTraits<P>::opponent>();
00856 if ((depth() <= 4)
00857 ? ImmediateCheckmate::hasCheckmateMove<P>(state.state(), king_info,kingPosition,checkmate_move)
00858 : state.isWinningStateShort<P>(2, checkmate_move)) {
00859 const int result = base_t::winByCheckmate(P);
00860 assert(checkmate_move.isValid());
00861 if(has_record)
00862 {
00863 assert(state.state().isValidMove(checkmate_move));
00864 record->setLowerBound(QSearchTraits::CheckmateSpecialDepth,
00865 result, checkmate_move);
00866 }
00867 return result;
00868 }
00869
00870
00871 if (depth() <= 0 && has_record) {
00872 if (record->threatmate.maybeThreatmate(P))
00873 return ev.value() + base_t::threatmatePenalty(P);
00874 if (record->threatmate.mayHaveCheckmate(alt(P)))
00875 return ev.value() + base_t::threatmatePenalty(alt(P));
00876 }
00877
00878 const Ptype last_capture = last_move.isNormal()
00879 ? last_move.capturePtype() : PTYPE_EMPTY;
00880 const Ptype last_ptype = last_move.isNormal()
00881 ? last_move.ptype() : PTYPE_EMPTY;
00882 const bool king_escape = (last_ptype == KING) && last_capture == PTYPE_EMPTY;
00883
00884 if ((depth() + std::min(additional_depth,2) <= -2)
00885 || (depth() <= 0 && additional_depth == 0)
00886 || (! king_escape
00887 && ((depth() + additional_depth <= 0)
00888 || (depth() <= 0 && last_capture != PTYPE_EMPTY
00889 && last_ptype != KING))))
00890 {
00891 if (ev.progress16().value() == 15
00892 && state.tryThreatmate()
00893 && ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>(state.state()))
00894 return ev.value() + base_t::threatmatePenalty(P);
00895 const int base = takeBackValue<P>(alpha, beta, ev, last_move);
00896 #ifdef QSEARCH_LAST_CHECK_PENALTY
00897 if ((last_move.ptype() == KING)
00898 && (last_capture == PTYPE_EMPTY))
00899 {
00900
00901
00902 return base+eval_t::captureValue(newPtypeO(alt(P), KNIGHT));
00903 }
00904 #endif
00905 return base;
00906 }
00907
00908 const int static_value
00909 = ((depth() <= 0)
00910 ? takeBackValue<P>(alpha, beta, ev, last_move)
00911 #ifdef QSEARCH_REAL_PASS
00912 : ((depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
00913 && (! last_move.isPass()))
00914 ? passValue<P>(alpha, beta, ev)
00915 #endif
00916 : staticValue<P,has_record>(ev, alpha, beta, record))
00917 #ifndef MINIMAL
00918 + (OslConfig::evalRandom() ? HashRandom::value(state.currentHash()): 0)
00919 #endif
00920 ;
00921 assert(static_value % 2 == 0);
00922 assert(! isWinValue(alt(P), static_value));
00923 #ifdef QSEARCH_DEBUG
00924 QuiescenceLog::staticValue(depth(), static_value);
00925 #endif
00926 if (EvalTraits<P>::notLessThan(static_value, cur_val))
00927 {
00928 cur_val = static_value;
00929 if (EvalTraits<P>::betterThan(cur_val, alpha))
00930 {
00931 alpha = cur_val + EvalTraits<P>::delta;
00932 if (has_record)
00933 {
00934 #ifndef OSL_SMP
00935 assert((record->lowerDepth() < depth())
00936 || EvalTraits<P>::notLessThan(cur_val, record->lowerBound())
00937 || in_pv);
00938 #endif
00939 record->setLowerBound(depth(), cur_val, record->bestMove());
00940 }
00941 if (EvalTraits<P>::betterThan(cur_val, beta))
00942 return cur_val;
00943 }
00944 }
00945
00946
00947 assert(alpha == EvalTraits<P>::max(alpha, cur_val + EvalTraits<P>::delta));
00948 assert(EvalTraits<P>::notLessThan(beta, alpha));
00949
00950 Piece last_capture_piece = Piece::EMPTY();
00951 if (! has_record)
00952 {
00953 state.getBigramKillerMoves(moves);
00954 if (examineMoves<P,has_record,false,UNKNOWN>
00955 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00956 additional_depth))
00957 return cur_val;
00958 moves.clear();
00959 }
00960 else
00961 {
00962
00963
00964 const Move bestmove_in_record=record->bestMove();
00965 if (bestmove_in_record.isNormal())
00966 {
00967 assert(state.state().template isAlmostValidMove<true>(bestmove_in_record));
00968 assert(moves.empty());
00969 moves.push_back(bestmove_in_record);
00970 if (examineMoves<P,has_record,false,UNKNOWN>
00971 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00972 additional_depth))
00973 return cur_val;
00974 moves.clear();
00975 last_capture_piece = state.state().getPieceOnBoard(bestmove_in_record.to());
00976 }
00977
00978 MoveVector killer_moves;
00979 state.getBigramKillerMoves(killer_moves);
00980 assert(moves.empty());
00981 MoveVector record_moves;
00982 record->loadMoves(record_moves);
00983 BOOST_FOREACH(Move move, killer_moves)
00984 {
00985 if (std::find(record_moves.begin(), record_moves.end(), move)
00986 == record_moves.end())
00987 moves.push_back(move);
00988 }
00989 record->addKillerMoves(moves);
00990
00991 if (examineMoves<P,has_record,false,UNKNOWN>
00992 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
00993 additional_depth))
00994 return cur_val;
00995
00996 if (examineMoves<P,has_record,false,UNKNOWN>
00997 (record, cur_val, &*record_moves.begin(), &*record_moves.end(), alpha, beta, ev, additional_depth))
00998 return cur_val;
00999 moves.clear();
01000 }
01001
01002
01003 assert(moves.empty());
01004 if (((! has_record) || record->movesEmpty())
01005 && (! last_to.isPieceStand()))
01006 {
01007 last_capture_piece = state.state().getPieceOnBoard(last_to);
01008 QuiescenceGenerator<P>::capture(state.state(),
01009 last_capture_piece.position(), moves);
01010 if (examineMoves<P,has_record,false,CAPTURE>
01011 (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
01012 additional_depth))
01013 {
01014 if (has_record)
01015 {
01016
01017 record->addKillerMoves(moves);
01018 }
01019 return cur_val;
01020 }
01021 }
01022
01023
01024 const bool has_threatmate
01025 = has_record
01026 && record->threatmate.isThreatmate(P)
01027 #ifdef OSL_SMP
01028 && record->threatmate.threatmateMove(P).isNormal()
01029 #endif
01030 ;
01031 if (has_threatmate)
01032 {
01033 moves.clear();
01034 QuiescenceGenerator<P>::breakThreatmate
01035 (state.state(), record->threatmate.threatmateMove(P), pins, moves);
01036 if (examineMoves<P,has_record,false,KING_ESCAPE>
01037 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01038 additional_depth))
01039 return cur_val;
01040 }
01041
01042
01043 if (examineCapture<P,ROOK,has_record>
01044 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01045 return cur_val;
01046 if (examineCapture<P,BISHOP,has_record>
01047 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01048 return cur_val;
01049 if (examineCapture<P,GOLD,has_record>
01050 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01051 return cur_val;
01052 if (examineCapture<P,SILVER,has_record>
01053 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01054 return cur_val;
01055 if ((depth() >= QSearch2PrivateTraits::KnightCaptureDepth)
01056 || max_depth <= 2
01057 || QSearch2Util<has_record>::moreMoves(record))
01058 {
01059 if (examineCapture<P,KNIGHT,has_record>
01060 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01061 return cur_val;
01062 if (examineCapture<P,LANCE,has_record>
01063 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01064 return cur_val;
01065 }
01066
01067 {
01068 const Move suggested = ev.suggestMove(state.state());
01069 if (suggested.isNormal()) {
01070 assert(state.state().isAlmostValidMove(suggested));
01071 moves.clear();
01072 moves.push_back(suggested);
01073 if (examineMoves<P,has_record,false,UNKNOWN>
01074 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01075 additional_depth)) {
01076 return cur_val;
01077 }
01078 }
01079 }
01080
01081 const Move last2_move = state.lastMove(2);
01082 if ((depth() > 2
01083 || (depth() > 0 && !(has_record && record->threatmate.maybeThreatmate(P)))
01084 || (last2_move.isNormal() && last2_move.capturePtype() == ROOK))
01085 && ! (! in_pv && has_record && record->threatmate.maybeThreatmate(P)))
01086 {
01087 moves.clear();
01088
01089 if (has_record)
01090 QuiescenceGenerator<P>::check(state.state(), pins,
01091 (king_info.liberty() == 0),
01092 record->sendOffPosition<P>(state.state()),
01093 moves);
01094 else
01095 QuiescenceGenerator<P>::check(state.state(), pins, moves,
01096 (king_info.liberty() == 0));
01097 if (examineMoves<P,has_record,false,CHECK>
01098 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01099 additional_depth))
01100 return cur_val;
01101 }
01102
01103 const Position my_king = state.state().template getKingPosition<P>();
01104
01105 if (depth() <= 0)
01106 goto finish;
01107
01108 if (! in_pv
01109 && EvalTraits<P>::betterThan(alpha, ev.value() + (400+350*2+100*depth())*ev.captureValue(newPtypeO(alt(P),PAWN))/200))
01110 goto king_walk;
01111 if ((depth() >= QSearch2PrivateTraits::AttackPinnedDepth)
01112 || QSearch2Util<has_record>::moreMoves(record))
01113 {
01114 {
01115 moves.clear();
01116 QuiescenceGenerator<P>::attackToPinned(state.state(), pins, moves);
01117 if (examineMoves<P,has_record,false,ATTACK>
01118 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01119 additional_depth))
01120 return cur_val;
01121 }
01122 }
01123
01124 if ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot)
01125 || (isMajorBasic(last2_move.capturePtype())
01126 && ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot+2)
01127 || (has_record && record->movesSizeLessThan(4))
01128 ))
01129 || QSearch2Util<has_record>::moreMoves(record))
01130 {
01131 {
01132 moves.clear();
01133 QuiescenceGenerator<P>::dropMajorPiece3(state.state(), moves, state.historyTable());
01134 if (last_move.isNormal() && isPiece(last_move.capturePtype())
01135 && unpromote(last_move.capturePtype())== BISHOP
01136 && last2_move.isNormal() && last2_move.capturePtype() == BISHOP
01137 && unpromote(last2_move.ptype()) == BISHOP)
01138 {
01139 const Position drop_again = last2_move.from();
01140 if (! state.state().template hasEffectBy<PlayerTraits<P>::opponent>(drop_again)
01141
01142 && state.state().getPieceOnBoard(drop_again) == Piece::EMPTY()
01143 && state.state().template hasPieceOnStand<BISHOP>(P))
01144 moves.push_back(Move(drop_again, BISHOP, P));
01145 }
01146
01147 if (examineMoves<P,has_record,true,OTHER>
01148 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
01149 additional_depth))
01150 return cur_val;
01151 }
01152 }
01153 if ((depth() >= QSearch2PrivateTraits::PawnCaptureDepth)
01154 || max_depth <= 2
01155 || QSearch2Util<has_record>::moreMoves(record))
01156 {
01157 if (examineCapture<P,PAWN,has_record>
01158 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
01159 return cur_val;
01160 }
01161 if ((depth() >= QSearch2PrivateTraits::FullPromoteDepth)
01162 || max_depth <= 2)
01163 {
01164 moves.clear();
01165 QuiescenceGenerator<P>::promote(state.state(), pins, moves);
01166 if (examineMoves<P,has_record,false,PROMOTE>
01167 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01168 return cur_val;
01169 }
01170 else
01171 {
01172 moves.clear();
01173 QuiescenceGenerator<P>::template promoteN<ROOK,2>(state.state(), moves, state.historyTable());
01174 QuiescenceGenerator<P>::template promoteN<BISHOP,2>(state.state(), moves, state.historyTable());
01175 if (examineMoves<P,has_record,false,PROMOTE>
01176 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01177 return cur_val;
01178 moves.clear();
01179 QuiescenceGenerator<P>::template promoteN<PAWN,2>(state.state(), moves, state.historyTable());
01180 QuiescenceGenerator<P>::template promoteN<LANCE,1>(state.state(), moves, state.historyTable());
01181 QuiescenceGenerator<P>::template promoteN<KNIGHT,1>(state.state(), moves, state.historyTable());
01182 if (examineMoves<P,has_record,false,PROMOTE>
01183 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01184 return cur_val;
01185 }
01186 if (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
01187 {
01188 {
01189 moves.clear();
01190 QuiescenceGenerator<P>::escapeAll(state.state(), moves);
01191 if (examineMoves<P,has_record,false,ESCAPE>
01192 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01193 return cur_val;
01194 }
01195 }
01196 else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
01197 || (last_move.isDrop() && isMajorBasic(last_move.ptype()))
01198 || (last_move.isNormal() && last2_move.isNormal()
01199 && isMajor(last2_move.ptype())
01200 && state.state().hasEffectByPiece
01201 (state.state().getPieceOnBoard(last_to), last2_move.to()))
01202 || QSearch2Util<has_record>::moreMoves(record))
01203 {
01204 {
01205 moves.clear();
01206 QuiescenceGenerator<P>::template escapeFromLastMove<EvalT>(state.state(), last_move, moves);
01207 if (examineMoves<P,has_record,false,ESCAPE>
01208 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01209 return cur_val;
01210 }
01211 }
01212 if ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot)
01213 || (isMajor(last_move.ptype())
01214 && last_move.capturePtype() != PTYPE_EMPTY
01215 && last_to.template canPromote<P>())
01216 || (state.state().hasEffectBy(P, last_to)
01217 && (state.state().
01218 template hasEffectByPtype<ROOK>(alt(P), last_to)))
01219 || ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot+2)
01220 && ((last2_move.capturePtype()==KNIGHT)
01221 || (last2_move.capturePtype()==LANCE)
01222 || (last2_move.capturePtype()==BISHOP)))
01223 || QSearch2Util<has_record>::moreMoves(record))
01224 {
01225 {
01226 moves.clear();
01227 QuiescenceGenerator<P>::attackMajorPiece(state.state(), pins, moves);
01228 if (examineMoves<P,has_record,true,ATTACK>
01229 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01230 return cur_val;
01231 }
01232 }
01233 {
01234 const QuiescenceRecord *parent
01235 = (state.hasLastRecord(1) && state.lastRecord(1))
01236 ? &(state.lastRecord(1)->qrecord) : 0;
01237 if ((depthFromRoot() < QSearch2PrivateTraits::AttackKing8DepthFromRoot)
01238 || (last_move.isNormal() && last_move.ptype() == KING
01239 && last_move.capturePtype() != PTYPE_EMPTY)
01240 || (((parent && parent->threatmate.isThreatmate(alt(P)))
01241 || (king_info.liberty() == 0))
01242 && depthFromRoot() < 2+QSearch2PrivateTraits::AttackKing8DepthFromRoot)
01243 || QSearch2Util<has_record>::moreMoves(record))
01244 {
01245 {
01246 moves.clear();
01247 QuiescenceGenerator<P>::attackKing8(state.state(), pins, moves);
01248 if (examineMoves<P,has_record,false,ATTACK>
01249 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01250 return cur_val;
01251 }
01252 }
01253 }
01254 if ((depthFromRoot() < QSearch2PrivateTraits::AttackGoldSilverDepthFromRoot)
01255 || QSearch2Util<has_record>::moreMoves(record))
01256 {
01257 {
01258 moves.clear();
01259 QuiescenceGenerator<P>::attackGoldWithPawn(state.state(), pins, moves);
01260 QuiescenceGenerator<P>::attackSilverWithPawn(state.state(), pins, moves);
01261 if (examineMoves<P,has_record,false,ATTACK>
01262 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01263 return cur_val;
01264 }
01265 }
01266 if ((depthFromRoot() < QSearch2PrivateTraits::AttackKnightDepthFromRoot)
01267 || QSearch2Util<has_record>::moreMoves(record))
01268 {
01269 {
01270 moves.clear();
01271 QuiescenceGenerator<P>::attackKnightWithPawn(state.state(), pins, moves);
01272 if (examineMoves<P,has_record,false,ATTACK>
01273 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01274 return cur_val;
01275 }
01276 }
01277 if ((depth() >= QSearch2PrivateTraits::UtilizePromotedDepth)
01278 || QSearch2Util<has_record>::moreMoves(record))
01279 {
01280 if (last2_move.isNormal())
01281 {
01282 const Piece last_piece = state.state().getPieceOnBoard(last2_move.to());
01283 assert(last_piece.isPiece());
01284 if (last_piece.owner() == P)
01285 {
01286 moves.clear();
01287 QuiescenceGenerator<P>::utilizePromoted(state.state(), last_piece, moves);
01288 if (examineMoves<P,has_record,true,OTHER>
01289 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01290 return cur_val;
01291 }
01292 }
01293 }
01294
01295 if ((depthFromRoot() < QSearch2PrivateTraits::AdvanceBishopDepthFromRoot)
01296 || QSearch2Util<has_record>::moreMoves(record))
01297 {
01298 {
01299 moves.clear();
01300 QuiescenceGenerator<P>::advanceBishop(state.state(), moves);
01301 if (examineMoves<P,has_record,true,OTHER>
01302 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01303 return cur_val;
01304 }
01305 }
01306 king_walk:
01307 if (has_threatmate
01308 || (! my_king.template canPromote<PlayerTraits<P>::opponent>()
01309 && last2_move.isNormal() && last2_move.ptype() == KING))
01310 {
01311 {
01312 moves.clear();
01313 QuiescenceGenerator<P>::kingWalk(state.state(), moves);
01314 if (examineMoves<P,has_record,true,OTHER>
01315 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
01316 return cur_val;
01317 }
01318 }
01319 finish:
01320
01321 assert(EvalTraits<P>::betterThan(beta, cur_val));
01322 assert(! isWinValue(alt(P), cur_val));
01323 #ifndef DONT_USE_CHECKMATE
01324 const bool threatmate
01325 = EvalTraits<P>::betterThan(ev.captureValue(newPtypeO(P,KING)), cur_val);
01326 int check_after_threatmate = 0;
01327 if (in_pv
01328 && (threatmate
01329 || (check_after_threatmate = state.countCheckAfterThreatmate(alt(P),2))))
01330 {
01331
01332 int checkmate_nodes = (node_count - node_count_before)/2;
01333 if (check_after_threatmate)
01334 {
01335 if (depthFromRoot() == 1)
01336 {
01337 const int sacrifice = state.countCheckAfterThreatmateSacrifice(alt(P),2);
01338 checkmate_nodes = std::max(checkmate_nodes,
01339 sacrifice*125+check_after_threatmate*50);
01340 }
01341 else
01342 {
01343 checkmate_nodes = std::max(50, checkmate_nodes);
01344 }
01345 }
01346 if (threatmate)
01347 {
01348 if (! has_record)
01349 record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01350 checkmate_nodes = std::max(checkmate_nodes, 200);
01351 }
01352 Move check_move;
01353 const bool win = (record && checkmate_nodes >= 50)
01354 ? state.isWinningState<P>(record->checkmateNodesLeft(checkmate_nodes),
01355 checkmate_move)
01356 : (((record && record->checkmateNodesLeft(2))
01357 || (! has_record && threatmate))
01358 ? state.isWinningStateShort<P>(2, checkmate_move)
01359 : false);
01360 if (win)
01361 {
01362 const int result = base_t::winByCheckmate(P);
01363 assert(checkmate_move.isValid());
01364 if (! has_record && ! record)
01365 record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01366 if (has_record || record) {
01367 assert(state.state().isValidMove(checkmate_move));
01368 record->setLowerBound(QSearchTraits::CheckmateSpecialDepth,
01369 result, checkmate_move);
01370 }
01371 return result;
01372 }
01373 }
01374 #if 0
01375
01376
01377 if (! has_record)
01378 {
01379 assert(! record);
01380 Move checkmate_move=Move::INVALID();
01381 AttackOracleAges oracle_age_dummy;
01382 const bool win_found
01383 = state.isWinningState<P>
01384 (0, checkmate_move, oracle_age_dummy);
01385 if (win_found)
01386 {
01387 const int result = base_t::winByCheckmate(P);
01388 assert(checkmate_move.isValid());
01389 record = qallocate(table, state.currentHash(), allocate_depth_in_threatmate, state);
01390 if (record)
01391 {
01392 record->setLowerBound(QSearchTraits::CheckmateSpecialDepth,
01393 result, checkmate_move);
01394 }
01395 return result;
01396 }
01397 }
01398 #endif
01399 #endif
01400
01401 if (has_record)
01402 {
01403 if (EvalTraits<P>::betterThan(beta, cur_val))
01404 record->setUpperBound(depth(), cur_val);
01405 }
01406 return cur_val;
01407 }
01408
01409 namespace osl
01410 {
01411 inline bool importantMove(const NumEffectState& state, Move move,
01412 Position my_king, Position op_king)
01413 {
01414 if (Neighboring8Direct::hasEffect(state, move.ptypeO(), move.to(), op_king))
01415 return true;
01416 return move.capturePtype() != PTYPE_EMPTY
01417 && Neighboring8Direct::hasEffect(state, move.capturePtypeO(), move.to(), my_king);
01418 }
01419 }
01420
01421 template <class EvalT>
01422 template <osl::Player P>
01423 bool osl::search::QuiescenceSearch2<EvalT>::
01424 examineTakeBack(const MoveVector& moves,
01425 int& cur_val, int& alpha, int beta, eval_t const& ev)
01426 {
01427 assert(alpha % 2);
01428 assert(beta % 2);
01429 assert(EvalTraits<P>::betterThan(alpha, cur_val));
01430 assert(EvalTraits<P>::notLessThan(beta, alpha));
01431
01432 const Position my_king = state.state().template getKingPosition<P>();
01433 const Position op_king = state.state().template getKingPosition<PlayerTraits<P>::opponent>();
01434
01435 BOOST_FOREACH(Move move, moves)
01436 {
01437 #ifdef QSEARCH_DEBUG
01438 QuiescenceLog::pushMove(depth(), move, 0);
01439 #endif
01440 const int see = See::see(state.state(), move, ev.pins(P), ev.pins(alt(P)));
01441 int result;
01442 if (see > 0 && importantMove(state.state(), move, my_king, op_king))
01443 {
01444 eval_t new_ev = ev;
01445
01446 typedef QSearch2NextTakeBack<QuiescenceSearch2,P> helper_t;
01447 helper_t helper(result, this, alpha, beta, new_ev, move);
01448
01449 state.doUndoMoveLight<P,helper_t>(move, helper);
01450 }
01451 else
01452 {
01453 result = ev.value() + see*eval_t::seeScale()*EvalTraits<P>::delta;
01454 }
01455
01456 if (! base_t::isWinValue(alt(P), result))
01457 {
01458 cur_val = EvalTraits<P>::max(cur_val, result);
01459 return EvalTraits<P>::notLessThan(result, beta);
01460 }
01461 }
01462 assert(EvalTraits<P>::betterThan(beta, cur_val));
01463 return false;
01464 }
01465
01466 template <class EvalT>
01467 template <osl::Player P, bool calm_move_only, bool first_normal_move_only>
01468 bool osl::search::QuiescenceSearch2<EvalT>::
01469 examineTakeBack2(const MoveVector& moves,
01470 QuiescenceThreat& threat2, QuiescenceThreat& threat1,
01471 int beta1, int beta2, eval_t const& ev)
01472 {
01473 if (moves.empty())
01474 return false;
01475
01476 using move_classifier::Check;
01477 using move_classifier::MoveAdaptor;
01478 assert(beta1 % 2);
01479 assert(beta2 % 2);
01480 assert(EvalTraits<P>::notLessThan(threat1.value, threat2.value));
01481 assert(EvalTraits<P>::betterThan(beta1, threat1.value));
01482 assert(EvalTraits<P>::betterThan(beta2, threat2.value));
01483 assert(EvalTraits<P>::notLessThan(beta1, beta2));
01484 assert(state.state().getTurn() == P);
01485
01486 const Position my_king = state.state().template getKingPosition<P>();
01487 const Position op_king = state.state().template getKingPosition<PlayerTraits<P>::opponent>();
01488
01489 int best_value = threat2.value;
01490 BOOST_FOREACH(Move move, moves)
01491 {
01492 const Position to = move.to();
01493 assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move));
01494 if (calm_move_only
01495 && (state.state().countEffect(alt(P),to) > state.state().countEffect(P,to)))
01496 continue;
01497 #ifdef QSEARCH_DEBUG
01498 QuiescenceLog::pushMove(depth(), move, 0);
01499 #endif
01500 int result;
01501 const int see = See::see(state.state(), move, ev.pins(P), ev.pins(alt(P)));
01502 if (see > 0 && importantMove(state.state(), move, my_king, op_king))
01503 {
01504 eval_t new_ev = ev;
01505
01506 const int beta = EvalTraits<P>::notLessThan(threat1.value, beta2) ? beta2 : beta1;
01507 typedef QSearch2NextTakeBack<QuiescenceSearch2,P> helper_t;
01508 helper_t helper(result, this,
01509 threat2.value+EvalTraits<P>::delta, beta, new_ev, move);
01510 state.doUndoMoveLight<P,helper_t>(move, helper);
01511 }
01512 else
01513 {
01514 result = ev.value() + see*eval_t::seeScale()*EvalTraits<P>::delta;
01515 }
01516
01517 if (base_t::isWinValue(alt(P), result))
01518 continue;
01519
01520
01521 if (EvalTraits<P>::betterThan(result, best_value))
01522 {
01523 best_value = result;
01524 if (EvalTraits<P>::notLessThan(best_value, threat1.value))
01525 {
01526 threat2 = threat1;
01527 threat1 = QuiescenceThreat(best_value, move);
01528 if (EvalTraits<P>::betterThan(threat1.value, beta1)
01529 || EvalTraits<P>::betterThan(threat2.value, beta2))
01530 return true;
01531 }
01532 else
01533 {
01534 assert(EvalTraits<P>::notLessThan(best_value, threat2.value));
01535 threat2 = QuiescenceThreat(best_value, move);
01536 if (EvalTraits<P>::betterThan(threat2.value, beta2))
01537 return true;
01538 }
01539 }
01540 if (first_normal_move_only)
01541 break;
01542 }
01543 return false;
01544
01545
01546
01547
01548 assert(! moves.empty());
01549 if (! EvalTraits<P>::betterThan(best_value, threat2.value))
01550 return false;
01551 const Move threat_move = *moves.begin();
01552 if (! first_normal_move_only)
01553 {
01554 assert(state.lastMove().isPass());
01555 state.popPass();
01556 bool cut_by_threat2 = false;
01557
01558 const Player Opponent = PlayerTraits<P>::opponent;
01559 MoveVector moves;
01560 move_generator::GenerateAddEffectWithEffect::generate<false>
01561 (Opponent, state.state(), threat_move.to(), moves);
01562 if (moves.empty())
01563 {
01564 threat2 = QuiescenceThreat(best_value, threat_move);
01565 if (EvalTraits<P>::betterThan(threat2.value, beta2))
01566 cut_by_threat2 = true;
01567 }
01568 state.pushPass();
01569 return cut_by_threat2;
01570 }
01571 else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
01572 || (unpromote(moves[0].capturePtype()) == ROOK)
01573 || (unpromote(moves[0].capturePtype()) == BISHOP))
01574 {
01575 assert(state.lastMove().isPass());
01576 state.popPass();
01577 bool cut_by_threat2 = false;
01578 const Position to = threat_move.to();
01579 const Piece target = state.state().getPieceOnBoard(to);
01580 bool tried_escape
01581 = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot);
01582 #ifdef QSEARCH_PESSIMISTIC_ESCAPE_THREAT
01583 if (state.lastMove().isNormal())
01584 {
01585
01586
01587 const Offset32 offset32(to, state.lastMove().to());
01588 const EffectContent effect
01589 = Ptype_Table.getEffect(state.lastMove().ptypeO(),offset32);
01590 tried_escape = effect.hasEffect();
01591 }
01592 #endif
01593 if (! tried_escape)
01594 {
01595 const Player Opponent = PlayerTraits<P>::opponent;
01596 MoveVector escape;
01597 const bool safe_escape
01598 = QuiescenceGenerator<Opponent>::escapeByMoveOnly(state.state(),
01599 target, escape);
01600 if (safe_escape)
01601 goto finish;
01602 BOOST_FOREACH(Move move, escape)
01603 {
01604 eval_t new_ev = ev;
01605 new_ev.update(state.state(), Move::PASS(P));
01606 int result;
01607 if (isMajor(move.ptype()))
01608 {
01609 typedef QSearch2TakeBackOrChase<QuiescenceSearch2,Opponent> helper_t;
01610 helper_t helper(result, this, best_value+EvalTraits<Opponent>::delta,
01611 threat2.value+EvalTraits<P>::delta, new_ev, move);
01612 state.doUndoMoveLight<Opponent,helper_t>(move, helper);
01613 }
01614 else
01615 {
01616 typedef QSearch2NextTakeBack<QuiescenceSearch2,Opponent> helper_t;
01617 helper_t helper(result, this, best_value+EvalTraits<Opponent>::delta,
01618 threat2.value+EvalTraits<P>::delta, new_ev, move);
01619 state.doUndoMoveLight<Opponent,helper_t>(move, helper);
01620 }
01621 if (EvalTraits<Opponent>::betterThan(result, best_value))
01622 {
01623 best_value = result;
01624 if (EvalTraits<Opponent>::notLessThan(result, threat2.value))
01625 break;
01626 }
01627 }
01628 }
01629 if (EvalTraits<P>::betterThan(best_value, threat2.value))
01630 {
01631 threat2 = QuiescenceThreat(best_value, threat_move);
01632 if (EvalTraits<P>::betterThan(threat2.value, beta2))
01633 {
01634 cut_by_threat2 = true;
01635 goto finish;
01636 }
01637 }
01638 finish:
01639 state.pushPass();
01640 return cut_by_threat2;
01641 }
01642 return false;
01643 }
01644
01645 template <class EvalT>
01646 template <osl::Player P>
01647 int osl::search::QuiescenceSearch2<EvalT>::
01648 takeBackOrChase(int alpha, int beta, eval_t const& ev, Move last_move)
01649 {
01650 assert(last_move.isNormal());
01651 int best_value = takeBackValue<P>(alpha, beta, ev, last_move);
01652 if (EvalTraits<P>::betterThan(best_value, beta))
01653 return best_value;
01654
01655 MoveVector moves;
01656 QuiescenceGenerator<P>::capture1(state.state(), last_move.from(), moves);
01657 if (moves.empty())
01658 return best_value;
01659 BOOST_FOREACH(Move move, moves)
01660 {
01661 eval_t new_ev = ev;
01662
01663 typedef QSearch2SafeEscape<eval_t, P> helper_t;
01664 helper_t helper(&state.state(),
01665 state.state().getPieceOnBoard(last_move.to()),
01666 new_ev, move);
01667 state.doUndoMoveLight<P,helper_t>(move, helper);
01668 if (helper.is_invalid)
01669 continue;
01670
01671 int result = new_ev.value();
01672 if (! helper.has_safe_escape)
01673 result += new_ev.captureValue(last_move.ptypeO());
01674 if (state.state().template hasEffectByPtype<ROOK>(P, move.from()))
01675 result += (new_ev.captureValue(newPtypeO(alt(P),PROOK))
01676 - new_ev.captureValue(newPtypeO(alt(P),ROOK)));
01677 best_value = EvalTraits<P>::max(result, best_value);
01678 break;
01679 }
01680 return best_value;
01681 }
01682
01683 template <class EvalT>
01684 template <osl::Player P>
01685 int osl::search::QuiescenceSearch2<EvalT>::
01686 takeBackValue(int alpha, int beta, eval_t const& ev, Move last_move)
01687 {
01688 assert(alpha % 2);
01689 assert(beta % 2);
01690
01691 ++node_count;
01692 assert(EvalTraits<P>::notLessThan(beta, alpha));
01693 if (state.state().inCheck(alt(P)))
01694 return base_t::winByFoul(P);
01695 if (last_move.isPass())
01696 return ev.value();
01697
01698 const Position last_to = last_move.to();
01699 MoveVector moves;
01700 const Piece last_move_piece = state.state().getPieceOnBoard(last_to);
01701 int cur_val;
01702 if (state.state().inCheck())
01703 {
01704 const bool check_by_lance = state.state().hasEffectByPtypeStrict<LANCE>
01705 (alt(P), state.state().getKingPosition<P>());
01706 const bool has_safe_move
01707 = QuiescenceGenerator<P>::escapeKingInTakeBack(state.state(), moves, check_by_lance);
01708 cur_val = (has_safe_move
01709 ? currentValueWithLastThreat(ev, last_move_piece)
01710 : base_t::winByCheckmate(alt(P)));
01711 assert(cur_val % 2 == 0);
01712 }
01713 else
01714 {
01715 cur_val = currentValueWithLastThreat(ev, last_move_piece);
01716 assert(cur_val % 2 == 0);
01717 if (EvalTraits<P>::betterThan(cur_val, beta))
01718 return cur_val;
01719 QuiescenceGenerator<P>::capture1(state.state(),
01720 last_move_piece.position(), moves);
01721 }
01722 if (EvalTraits<P>::betterThan(cur_val, alpha))
01723 {
01724 alpha = cur_val + EvalTraits<P>::delta;
01725 if (EvalTraits<P>::betterThan(cur_val, beta)) {
01726 return cur_val;
01727 }
01728 }
01729
01730 assert(EvalTraits<P>::betterThan(alpha, cur_val));
01731 if (examineTakeBack<P>(moves, cur_val, alpha, beta, ev)) {
01732 assert(cur_val % 2 == 0);
01733 return cur_val;
01734 }
01735
01736
01737 assert(cur_val % 2 == 0);
01738 return cur_val;
01739 }
01740
01741 template <class EvalT>
01742 template <osl::Player P>
01743 int osl::search::QuiescenceSearch2<EvalT>::
01744 staticValueWithThreat(eval_t const& ev, int alpha,
01745 QuiescenceThreat& threat1, QuiescenceThreat& threat2)
01746 {
01747 assert(alpha % 2);
01748 assert(! state.state().inCheck());
01749 const int static_value = ev.value();
01750 if (EvalTraits<P>::notLessThan(alpha, static_value))
01751 return static_value;
01752 const Player O = PlayerTraits<P>::opponent;
01753 const int FirstThreat = QSearchTraits::FirstThreat;
01754 const int SecondThreat
01755 = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
01756 ? 1
01757 : QSearchTraits::SecondThreat;
01758
01759 const int o_beta1
01760 = (EvalTraits<O>::min(base_t::winByCheckmate(O),
01761 static_value - FirstThreat*(static_value - alpha))
01762 - ((FirstThreat % 2) ? 0 : EvalTraits<O>::delta));
01763 const int o_beta2
01764 = (EvalTraits<O>::min(base_t::winByCheckmate(O),
01765 static_value - SecondThreat*(static_value - alpha))
01766 - ((SecondThreat % 2) ? 0 : EvalTraits<O>::delta));
01767
01768 threat1.value = static_value;
01769 threat2.value = static_value;
01770
01771 assert(state.state().getTurn() == P);
01772 const Move last_move = state.lastMove();
01773 state.pushPass();
01774
01775 assert(! state.state().inCheck());
01776
01777 assert(EvalTraits<O>::betterThan(o_beta1, threat1.value));
01778 assert(EvalTraits<O>::betterThan(o_beta2, threat1.value));
01779 assert(EvalTraits<O>::notLessThan(o_beta1, o_beta2));
01780 EvalT ev2(ev);
01781 ev2.update(state.state(), Move::PASS(P));
01782
01783 MoveVector moves;
01784 if (generateAndExamineTakeBack2<O,ROOK>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01785 goto finish;
01786 if (generateAndExamineTakeBack2<O,BISHOP>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01787 goto finish;
01788 if (generateAndExamineTakeBack2<O,GOLD>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01789 goto finish;
01790 if (generateAndExamineTakeBack2<O,SILVER>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01791 goto finish;
01792 if (generateAndExamineTakeBack2<O,KNIGHT>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01793 goto finish;
01794 if (generateAndExamineTakeBack2<O,LANCE>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01795 goto finish;
01796
01797 QuiescenceGenerator<O>::template promoteN<ROOK,1>(state.state(), moves, state.historyTable());
01798 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01799 goto finish;
01800 moves.clear();
01801 QuiescenceGenerator<O>::template promoteN<BISHOP,1>(state.state(), moves, state.historyTable());
01802 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01803 goto finish;
01804 moves.clear();
01805 QuiescenceGenerator<O>::template promoteN<PAWN,1>(state.state(), moves, state.historyTable());
01806 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01807 goto finish;
01808 moves.clear();
01809 if (depth() >= QSearch2PrivateTraits::PawnCaptureDepth
01810 || max_depth <= 2)
01811 {
01812 if (generateAndExamineTakeBack2<O,PAWN>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
01813 goto finish;
01814 }
01815 finish:
01816 state.popPass();
01817
01818 if (threat1.move == threat2.move && threat1.move.isNormal()) {
01819 const Piece target = state.state().getPieceOnBoard(threat1.move.to());
01820 if (isMajorBasic(target.ptype())
01821 && target.position().template canPromote<O>()) {
01822 assert(alt(target.owner()) == O);
01823 assert(threat1.value % 2 == 0);
01824 return threat1.value;
01825 }
01826 }
01827
01828 const int result1 = (static_value - (static_value - threat1.value)/FirstThreat);
01829 const int result2 = (static_value - (static_value - threat2.value)/SecondThreat);
01830
01831 const int result = EvalTraits<O>::max(result1, result2) & (~0x1);
01832 assert(result % 2 == 0);
01833 return result;
01834 }
01835
01836 #endif
01837
01838
01839
01840