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