3 #ifndef OSL_QUIESCENCESEARCH2_TCC
4 #define OSL_QUIESCENCESEARCH2_TCC
30 #ifdef STAT_WIDTH_VS_LIMIT
35 #define quiecence_assert(x,m) assert((x) || state.abort(m))
39 # define QSEARCH_LAST_CHECK_PENALTY
41 # define QSEARCH_PESSIMISTIC_ESCAPE_THREAT
43 # define QSEARCH_THREATMATE
46 #ifdef EXTRA_RICH_QSEARCH
48 # define QSEARCH_SET_MINIMUM_MOVES
91 #ifdef QSEARCH_SET_MINIMUM_MOVES
110 template <
class QSearch2,Player P>
125 result = (*searcher).template searchInternal<PlayerTraits<P>::opponent>
129 template <
class QSearch2,Player P>
142 result = (*searcher).template takeBackValue<PlayerTraits<P>::opponent>
146 template <
class QSearch2,Player P>
159 result = (*searcher).template takeBackOrChase<PlayerTraits<P>::opponent>
163 template <
class Eval, Player P>
179 assert(
state->turn() == Turn);
191 template <
bool has_record>
205 template <
class EvalT>
206 template <osl::Player P>
213 const int margin = pawn_value2/2;
215 base_t::winThreshold(
alt(P)));
218 base_t::winThreshold(P));
220 const int val4 = searchInternal<P>(alpha4, beta4, ev, last_move);
222 return val4 - (beta4-beta);
224 return val4 - (alpha4-alpha);
227 return searchInternal<P>(alpha, beta, ev, last_move);
230 template <
class EvalT>
231 template <osl::Player P, osl::Ptype PTYPE>
237 int beta1,
int beta2,
eval_t const& ev)
239 mask_t pieces = state.state().effectedMask(P).template selectBit<PTYPE>()
247 assert(moves.empty());
250 = examineTakeBack2<P,false,true>(
moves, threat2, threat1,
260 template <
class EvalT>
261 template <osl::Player P, osl::Ptype PTYPE,
bool has_record>
266 eval_t const& ev,
Piece last_move_piece,
int additional_depth)
275 SortCaptureMoves::sortByTakeBack(state.state(),
moves);
277 return examineMoves<P,has_record,has_record,CAPTURE>
278 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
279 additional_depth, last_move_piece.
square());
284 #ifdef STAT_WIDTH_VS_LIMIT
293 Reporter() :
count(0) {}
296 std::cerr <<
"QuiescenceSearch2 " << average.getAverage() << std::endl;
298 void newRoot() { average.add(
count);
count=0; }
299 void add() { ++
count; }
305 template <
class EvalT>
306 template <
osl::Player P,
bool has_record,
bool has_dont_capture,
310 const Move *first,
const Move *last,
311 int& alpha,
int beta,
eval_t const& ev,
312 int additional_depth,
Square dont_capture)
318 #if (! defined NDEBUG) && (! defined OSL_SMP)
319 const bool in_pv = (alpha != beta);
321 while (first != last)
323 const Move move = *first++;
324 if (move_type == CHECK)
331 if (has_dont_capture)
334 if (to == dont_capture)
337 assert((move_type == KING_ESCAPE) || (move_type == UNKNOWN)
338 || (! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move)));
340 if(MoveStackRejections::probe<P>(state.state(),state.history(),state.curDepth(),move,alpha,state.repetitionCounter().checkCount(
alt(P)))){
344 QuiescenceLog::pushMove(
depth(), move, record);
346 const HashKey new_hash = state.currentHash().newHashWithMove(move);
350 = state.repetitionCounter().isAlmostSennichite(new_hash);
351 if (next_sennichite.
isDraw())
353 result = base_t::drawValue();
357 result = base_t::winByFoul(next_sennichite.
winner());
362 #ifdef STAT_WIDTH_VS_LIMIT
363 if (depthFromRoot() == 0)
368 if (has_record && alpha != beta
371 helper_t helper(result,
this, alpha, alpha, new_ev, move,
373 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
376 helper_t helper(result,
this, alpha, beta, new_ev, move,
378 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
383 helper_t helper(result,
this, alpha, beta, new_ev, move,
385 state.doUndoMoveOrPass<P,helper_t>(new_hash, move, helper);
389 if (base_t::isWinValue(P, result) && (! move.
isPass())
391 ::isMember(state.state(), move))
393 result = base_t::winByFoul(
alt(P));
404 if (base_t::isWinValue(P, cur_val))
406 Square king = state.state().kingSquare(
alt(P));
408 record->
setLowerBound(QSearchTraits::CheckmateSpecialDepth, cur_val, move);
412 record->
setLowerBound(QSearchTraits::MaxDepth, cur_val, move);
423 || state.abort(move));
430 state.setKillerMove(move);
433 const int d =
depth();
434 state.historyTable().add(move, d*d);
450 int minusDepthFromRoot,
455 = table.
allocate(key, minusDepthFromRoot);
465 template <
class EvalT>
466 template <osl::Player P,
bool has_record>
471 const bool in_pv = (alpha != beta);
472 #ifndef DONT_USE_CHECKMATE
476 && (state.hasLastRecord(1) && state.lastRecord(1)))
478 = (state.lastRecord(1)->threatmate().status(P).status() == ThreatmateState::CHECK_AFTER_THREATMATE);
480 const int result = ev.value() + base_t::threatmatePenalty(P);
485 const Move last_move = state.lastMove();
486 const Square king = state.state().kingSquare(P);
487 const bool one_hop_prook
491 && ((king.
y() == last_move.
to().
y()
492 && abs(king.
x() - last_move.
to().
x()) < 3)
493 || (king.
x() == last_move.
to().
x()
494 && abs(king.
y() - last_move.
to().
y()) < 3)));
495 if (one_hop_prook && ! has_record) {
498 if (has_record || record) {
500 Move checkmate_move=Move::INVALID();
501 int threatmate_node = 0;
503 threatmate_node += 50;
504 }
else if (one_hop_prook) {
505 threatmate_node += 20;
507 #ifdef QSEARCH_THREATMATE
508 else if ((depthFromRoot() < QSearch2PrivateTraits::ThreatMateDepthFromRoot)
509 && state.tryThreatmate())
510 threatmate_node += 20;
512 bool lose = state.isThreatmateState<P>
516 lose = state.isThreatmateStateShort<P>(2, checkmate_move);
519 const int result = ev.value() + base_t::threatmatePenalty(P);
520 assert(checkmate_move.
isValid());
523 QSearchTraits::CheckmateSpecialDepth);
524 assert(result % 2 == 0);
530 if (! in_pv && has_record) {
531 int static_value, static_value_depth;
533 if (record->
hasStaticValue(static_value, static_value_depth, type)) {
536 assert(static_value % 2 == 0);
539 if (type == QuiescenceRecord::EXACT
540 && (static_value_depth >=
depth())) {
541 assert(static_value % 2 == 0);
546 Move threatmate_move;
548 (state.state(), threatmate_move))
550 const int result = ev.value() + base_t::threatmatePenalty(P);
555 QSearchTraits::CheckmateSpecialDepth);
557 assert(result % 2 == 0);
562 int expect = ev.value() + ev.captureValue(
newPtypeO(P,
GOLD));
563 Piece threat = state.state().findThreatenedPiece(P);
565 expect += ev.captureValue(threat.
ptypeO());
569 const int eval_alpha = alpha;
571 const int result = staticValueWithThreat<P>(ev, eval_alpha, threat1, threat2);
575 ? QuiescenceRecord::UPPER_BOUND
576 : QuiescenceRecord::EXACT,
580 assert(result % 2 == 0);
584 template <
class EvalT>
585 template <osl::Player P>
590 #ifdef STAT_WIDTH_VS_LIMIT
591 if (depthFromRoot() == 0)
595 if (depthFromRoot() == 0)
596 QuiescenceLog::enter(state.state());
598 #ifdef MAKE_PV_IN_QUIESCE2
610 if (state.state().inCheck(
alt(P)))
611 return base_t::winByFoul(P);
613 assert(state.hasLastRecord());
615 =
qallocate(table, state.currentHash(),
depth()-QSearchTraits::MaxDepth,
618 = (state.hasLastRecord(1) && state.lastRecord(1))
619 ? &(state.lastRecord(1)->qrecord) : 0;
620 const bool near_checkmate = parent
621 && (parent->threatmate.maybeThreatmate(
alt(P))
622 || parent->threatmate.mayHaveCheckmate(P)
623 || (parent->threatmate.status(P).status()
624 == ThreatmateState::CHECK_AFTER_THREATMATE));
625 if (! record && near_checkmate)
633 result = searchMain<P,false>(0, alpha, beta, ev, last_move,
634 additional_depth, need_eval_update);
635 if (near_checkmate) {
637 && parent->threatmate.maybeThreatmate(
alt(P)))
639 && parent->threatmate.status(P).status()
640 == ThreatmateState::CHECK_AFTER_THREATMATE)) {
648 const bool is_king_in_check = state.state().inCheck();
651 result = searchMain<P,true>(record, alpha, beta, ev, last_move,
652 additional_depth, need_eval_update);
653 #ifdef MAKE_PV_IN_QUIESCE2
655 state.makePV(record->bestMove());
659 QuiescenceLog::node(
depth(), alpha, beta, result);
661 assert(result % 2 == 0);
665 template <
class EvalT>
669 int static_value = ev.value();
670 if (! (depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot))
673 assert(last_move_piece.
isPiece());
677 EffectUtil::findThreat<EvalT>(state.state(), from, last_move_piece.
ptypeO(),
681 if (targets[0].ptype() ==
KING)
683 if (targets.size() < 2)
686 int threat = eval_t::captureValue(targets[1].ptypeO());
687 if (state.state().hasEffectAt(
alt(P), targets[1].square()))
688 threat += eval_t::captureValue(last_move_piece.
ptypeO());
690 return static_value + threat;
692 int first_threat = eval_t::captureValue(targets[0].ptypeO());
693 if (state.state().hasEffectAt(
alt(P), targets[0].square()))
694 first_threat += eval_t::captureValue(last_move_piece.
ptypeO());
696 first_threat /= SecondThreat;
697 if (targets.size() < 2)
698 return static_value + (first_threat & (~0x1));
700 int second_threat = eval_t::captureValue(targets[1].ptypeO());
701 if (state.state().hasEffectAt(
alt(P), targets[1].square()))
702 second_threat += eval_t::captureValue(last_move_piece.
ptypeO());
704 return static_value + ((first_threat + second_threat) & (~0x1));
707 template <
class EvalT>
708 template <osl::Player P>
715 const Move pass = Move::PASS(P);
718 helper_t helper(result,
this, alpha, beta, ev, pass, 0);
719 const HashKey new_hash = state.currentHash().newHashWithMove(pass);
721 max_depth -= QSearch2PrivateTraits::PassExtraDepth;
722 state.doUndoMoveOrPass<P,helper_t>(new_hash, pass, helper);
723 max_depth += QSearch2PrivateTraits::PassExtraDepth;
728 template <
class EvalT>
729 template <osl::Player P,
bool has_record>
732 int alpha,
int beta,
eval_t& ev,
Move last_move,
735 const bool in_pv = (alpha != beta);
736 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
739 assert((! has_record) || record);
742 assert((last_move == state.lastMove())
743 || ! last_move.
isNormal() || ! state.lastMove().isNormal());
744 #if (!defined OSL_USE_RACE_DETECTOR) && (!defined MINIMAL)
745 state.depth_node_count_quiesce[state.curDepth()]++;
747 #ifndef DONT_USE_CHECKMATE
748 const int node_count_before = node_count;
750 const Square last_to = last_move.
to();
751 int cur_val = base_t::winByCheckmate(
alt(P));
755 || record->
lowerDepth() >= QSearchTraits::HistorySpecialDepth)
765 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
773 #ifndef DONT_USE_CHECKMATE
777 Move checkmate_move=Move::INVALID();
778 if (need_eval_update == BeforeUpdate) {
779 ev.update(state.state(), last_move);
780 need_eval_update = AfterUpdate;
782 bool win = state.isWinningState<P>
785 win = state.isWinningStateShort<P>(2, checkmate_move);
788 const int result = base_t::winByCheckmate(P);
789 assert(checkmate_move.
isValid());
790 assert(state.state().isValidMove(checkmate_move));
792 result, checkmate_move);
798 || record->
upperDepth() >= QSearchTraits::HistorySpecialDepth)
805 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
812 #if (! defined NDEBUG) && (! defined OSL_USE_RACE_DETECTOR)
816 if (need_eval_update == BeforeUpdate) {
817 ev.update(state.state(), last_move);
818 need_eval_update = AfterUpdate;
820 const bool is_king_in_check = state.state().inCheck();
822 if (is_king_in_check)
830 if (state.lastMove(2).isNormal()
831 && state.lastMove(3).isNormal()
832 && state.lastMove(4).isNormal()
833 && state.lastMove(2).to() == last_move.
to()
834 && state.lastMove(3).to() == last_move.
to()
835 && state.lastMove(4).to() == last_move.
to())
841 move_order::CaptureSort::sort(moves.begin(), moves.end());
842 examineMoves<P,has_record,false,KING_ESCAPE>
843 (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
853 assert(! is_king_in_check);
855 PieceMask pins = state.state().pin(
alt(P));
856 Move checkmate_move=Move::INVALID();
857 Square kingSquare=state.state().template kingSquare<PlayerTraits<P>::opponent>();
859 ? ImmediateCheckmate::hasCheckmateMove<P>(state.state(), king_info,kingSquare,checkmate_move)
860 : state.isWinningStateShort<P>(2, checkmate_move)) {
861 const int result = base_t::winByCheckmate(P);
862 assert(checkmate_move.
isValid());
865 assert(state.state().isValidMove(checkmate_move));
867 result, checkmate_move);
873 if (
depth() <= 0 && has_record) {
875 return ev.value() + base_t::threatmatePenalty(P);
877 return ev.value() + base_t::threatmatePenalty(
alt(P));
884 const bool king_escape = (last_ptype ==
KING) && last_capture ==
PTYPE_EMPTY;
887 || (
depth() <= 0 && additional_depth == 0)
889 && ((
depth() + additional_depth <= 0)
891 && last_ptype !=
KING))))
893 if (ev.progress16().value() == 15
894 && state.tryThreatmate()
895 && ImmediateCheckmate::hasCheckmateMove<PlayerTraits<P>::opponent>(state.state()))
896 return ev.value() + base_t::threatmatePenalty(P);
897 const int base = takeBackValue<P>(alpha, beta, ev, last_move);
898 #ifdef QSEARCH_LAST_CHECK_PENALTY
910 const int static_value
912 ? takeBackValue<P>(alpha, beta, ev, last_move)
913 #ifdef QSEARCH_REAL_PASS
914 : ((depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
915 && (! last_move.
isPass()))
916 ? passValue<P>(alpha, beta, ev)
918 : staticValue<P,has_record>(ev, alpha, beta, record))
920 + (OslConfig::evalRandom() ? HashRandom::value(state.currentHash()): 0)
923 assert(static_value % 2 == 0);
924 assert(! isWinValue(
alt(P), static_value));
926 QuiescenceLog::staticValue(
depth(), static_value);
930 cur_val = static_value;
952 Piece last_capture_piece = Piece::EMPTY();
955 state.getBigramKillerMoves(moves);
956 if (examineMoves<P,has_record,false,UNKNOWN>
957 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
969 assert(state.state().template isAlmostValidMove<true>(bestmove_in_record));
970 assert(moves.empty());
971 moves.push_back(bestmove_in_record);
972 if (examineMoves<P,has_record,false,UNKNOWN>
973 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
977 last_capture_piece = state.state().pieceOnBoard(bestmove_in_record.
to());
981 state.getBigramKillerMoves(killer_moves);
982 assert(moves.empty());
985 BOOST_FOREACH(
Move move, killer_moves)
987 if (
std::find(record_moves.begin(), record_moves.end(), move)
988 == record_moves.end())
989 moves.push_back(move);
993 if (examineMoves<P,has_record,false,UNKNOWN>
994 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
998 if (examineMoves<P,has_record,false,UNKNOWN>
999 (record, cur_val, &*record_moves.begin(), &*record_moves.end(), alpha, beta, ev, additional_depth))
1005 assert(moves.empty());
1009 last_capture_piece = state.state().pieceOnBoard(last_to);
1012 if (examineMoves<P,has_record,false,CAPTURE>
1013 (record, cur_val, &*moves.begin(), &*moves.end(),alpha, beta, ev,
1026 const bool has_threatmate
1038 if (examineMoves<P,has_record,false,KING_ESCAPE>
1039 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
1045 if (examineCapture<P,ROOK,has_record>
1046 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1048 if (examineCapture<P,BISHOP,has_record>
1049 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1051 if (examineCapture<P,GOLD,has_record>
1052 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1054 if (examineCapture<P,SILVER,has_record>
1055 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1057 if ((
depth() >= QSearch2PrivateTraits::KnightCaptureDepth)
1061 if (examineCapture<P,KNIGHT,has_record>
1062 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1064 if (examineCapture<P,LANCE,has_record>
1065 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1070 const Move suggested = ev.suggestMove(state.state());
1072 assert(state.state().isAlmostValidMove(suggested));
1074 moves.push_back(suggested);
1075 if (examineMoves<P,has_record,false,UNKNOWN>
1076 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
1077 additional_depth)) {
1083 const Move last2_move = state.lastMove(2);
1093 (king_info.liberty() == 0),
1098 (king_info.liberty() == 0));
1099 if (examineMoves<P,has_record,false,CHECK>
1100 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
1105 const Square my_king = state.state().template kingSquare<P>();
1113 if ((
depth() >= QSearch2PrivateTraits::AttackPinnedDepth)
1119 if (examineMoves<P,has_record,false,ATTACK>
1120 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
1126 if ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot)
1128 && ((depthFromRoot() < QSearch2PrivateTraits::DropDepthFromRoot+2)
1142 if (! state.state().template hasEffectAt<PlayerTraits<P>::opponent>(drop_again)
1144 && state.state().pieceOnBoard(drop_again) == Piece::EMPTY()
1145 && state.state().template hasPieceOnStand<BISHOP>(P))
1146 moves.push_back(
Move(drop_again,
BISHOP, P));
1149 if (examineMoves<P,has_record,true,OTHER>
1150 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev,
1155 if ((
depth() >= QSearch2PrivateTraits::PawnCaptureDepth)
1159 if (examineCapture<P,PAWN,has_record>
1160 (record, cur_val, moves, alpha, beta, ev, last_capture_piece, additional_depth))
1163 if ((
depth() >= QSearch2PrivateTraits::FullPromoteDepth)
1168 if (examineMoves<P,has_record,false,PROMOTE>
1169 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1177 if (examineMoves<P,has_record,false,PROMOTE>
1178 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1184 if (examineMoves<P,has_record,false,PROMOTE>
1185 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1188 if (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
1193 if (examineMoves<P,has_record,false,ESCAPE>
1194 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1198 else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
1202 && state.state().hasEffectByPiece
1203 (state.state().pieceOnBoard(last_to), last2_move.
to()))
1209 if (examineMoves<P,has_record,false,ESCAPE>
1210 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1214 if ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot)
1217 && last_to.template canPromote<P>())
1218 || (state.state().hasEffectAt(P, last_to)
1220 template hasEffectByPtype<ROOK>(
alt(P), last_to)))
1221 || ((depthFromRoot() < QSearch2PrivateTraits::AttackMajorPieceDepthFromRoot+2)
1230 if (examineMoves<P,has_record,true,ATTACK>
1231 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1237 = (state.hasLastRecord(1) && state.lastRecord(1))
1238 ? &(state.lastRecord(1)->qrecord) : 0;
1239 if ((depthFromRoot() < QSearch2PrivateTraits::AttackKing8DepthFromRoot)
1243 || (king_info.liberty() == 0))
1244 && depthFromRoot() < 2+QSearch2PrivateTraits::AttackKing8DepthFromRoot)
1250 if (examineMoves<P,has_record,false,ATTACK>
1251 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1256 if ((depthFromRoot() < QSearch2PrivateTraits::AttackGoldSilverDepthFromRoot)
1263 if (examineMoves<P,has_record,false,ATTACK>
1264 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1268 if ((depthFromRoot() < QSearch2PrivateTraits::AttackKnightDepthFromRoot)
1274 if (examineMoves<P,has_record,false,ATTACK>
1275 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1279 if ((
depth() >= QSearch2PrivateTraits::UtilizePromotedDepth)
1284 const Piece last_piece = state.state().pieceOnBoard(last2_move.
to());
1286 if (last_piece.
owner() == P)
1290 if (examineMoves<P,has_record,true,OTHER>
1291 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1297 if ((depthFromRoot() < QSearch2PrivateTraits::AdvanceBishopDepthFromRoot)
1303 if (examineMoves<P,has_record,true,OTHER>
1304 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1316 if (examineMoves<P,has_record,true,OTHER>
1317 (record, cur_val, &*moves.begin(), &*moves.end(), alpha, beta, ev, additional_depth))
1324 assert(! isWinValue(
alt(P), cur_val));
1325 #ifndef DONT_USE_CHECKMATE
1326 const bool threatmate
1328 int check_after_threatmate = 0;
1331 || (check_after_threatmate = state.countCheckAfterThreatmate(
alt(P),2))))
1334 int checkmate_nodes = (node_count - node_count_before)/2;
1335 if (check_after_threatmate)
1337 if (depthFromRoot() == 1)
1339 const int sacrifice = state.countCheckAfterThreatmateSacrifice(
alt(P),2);
1340 checkmate_nodes =
std::max(checkmate_nodes,
1341 sacrifice*125+check_after_threatmate*50);
1345 checkmate_nodes =
std::max(50, checkmate_nodes);
1352 checkmate_nodes =
std::max(checkmate_nodes, 200);
1355 const bool win = (record && checkmate_nodes >= 50)
1359 || (! has_record && threatmate))
1360 ? state.isWinningStateShort<P>(2, checkmate_move)
1364 const int result = base_t::winByCheckmate(P);
1365 assert(checkmate_move.
isValid());
1366 if (! has_record && ! record)
1368 if (has_record || record) {
1369 assert(state.state().isValidMove(checkmate_move));
1371 result, checkmate_move);
1382 Move checkmate_move=Move::INVALID();
1383 AttackOracleAges oracle_age_dummy;
1384 const bool win_found
1385 = state.isWinningState<P>
1386 (0, checkmate_move, oracle_age_dummy);
1389 const int result = base_t::winByCheckmate(P);
1390 assert(checkmate_move.isValid());
1395 result, checkmate_move);
1418 my_king = Centering3x3::adjustCenter(my_king);
1419 op_king = Centering3x3::adjustCenter(op_king);
1424 && ((! move.
isDrop() && state.longEffectAt(move.
from()).any())
1430 template <
class EvalT>
1431 template <osl::Player P>
1434 int& cur_val,
int& alpha,
int beta,
eval_t const& ev)
1441 const Square my_king = state.state().template kingSquare<P>();
1442 const Square op_king = state.state().template kingSquare<PlayerTraits<P>::opponent>();
1444 BOOST_FOREACH(
Move move, moves)
1446 #ifdef QSEARCH_DEBUG
1447 QuiescenceLog::pushMove(
depth(), move, 0);
1449 const int see = See::see(state.state(), move, state.state().pin(P), state.state().pin(
alt(P)), &eval_t::Piece_Value);
1451 if (see > 0 &&
importantMove(state.state(), move, my_king, op_king))
1456 helper_t helper(result,
this, alpha, beta, new_ev, move);
1458 state.doUndoMoveLight<P,helper_t>(move, helper);
1465 if (! base_t::isWinValue(
alt(P), result))
1475 template <
class EvalT>
1476 template <osl::Player P,
bool calm_move_only,
bool first_normal_move_only>
1480 int beta1,
int beta2,
eval_t const& ev)
1493 assert(state.state().turn() == P);
1495 const Square my_king = state.state().template kingSquare<P>();
1496 const Square op_king = state.state().template kingSquare<PlayerTraits<P>::opponent>();
1498 int best_value = threat2.
value;
1499 BOOST_FOREACH(
Move move, moves)
1502 assert(! ShouldPromoteCut::canIgnoreAndNotDrop<P>(move));
1504 && (state.state().countEffect(
alt(P),to) > state.state().countEffect(P,to)))
1506 #ifdef QSEARCH_DEBUG
1507 QuiescenceLog::pushMove(
depth(), move, 0);
1510 const int see = See::see(state.state(), move, state.state().pin(P), state.state().pin(
alt(P)), &eval_t::Piece_Value);
1511 if (see > 0 &&
importantMove(state.state(), move, my_king, op_king))
1517 helper_t helper(result,
this,
1519 state.doUndoMoveLight<P,helper_t>(move, helper);
1526 if (base_t::isWinValue(
alt(P), result))
1549 if (first_normal_move_only)
1557 assert(! moves.empty());
1560 const Move threat_move = *moves.begin();
1561 if (! first_normal_move_only)
1563 assert(state.lastMove().isPass());
1565 bool cut_by_threat2 =
false;
1569 move_generator::GenerateAddEffectWithEffect::generate<false>
1570 (Opponent, state.state(), threat_move.
to(),
moves);
1575 cut_by_threat2 =
true;
1578 return cut_by_threat2;
1580 else if ((depthFromRoot() < QSearch2PrivateTraits::EscapeFromLastMoveDepthFromRoot)
1584 assert(state.lastMove().isPass());
1586 bool cut_by_threat2 =
false;
1587 const Square to = threat_move.
to();
1588 const Piece target = state.state().pieceOnBoard(to);
1590 = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot);
1591 #ifdef QSEARCH_PESSIMISTIC_ESCAPE_THREAT
1592 if (state.lastMove().isNormal())
1596 const Offset32 offset32(to, state.lastMove().to());
1606 const bool safe_escape
1611 BOOST_FOREACH(
Move move, escape)
1614 new_ev.update(state.state(), Move::PASS(P));
1621 state.doUndoMoveLight<Opponent,helper_t>(move, helper);
1628 state.doUndoMoveLight<Opponent,helper_t>(move, helper);
1643 cut_by_threat2 =
true;
1649 return cut_by_threat2;
1654 template <
class EvalT>
1655 template <osl::Player P>
1660 int best_value = takeBackValue<P>(alpha, beta, ev, last_move);
1668 BOOST_FOREACH(
Move move, moves)
1673 helper_t helper(&state.state(),
1674 state.state().pieceOnBoard(last_move.
to()),
1676 state.doUndoMoveLight<P,helper_t>(move, helper);
1677 if (helper.is_invalid)
1680 int result = new_ev.value();
1681 if (! helper.has_safe_escape)
1682 result += new_ev.captureValue(last_move.
ptypeO());
1683 if (state.state().template hasEffectByPtype<ROOK>(P, move.from()))
1692 template <
class EvalT>
1693 template <osl::Player P>
1702 if (state.state().inCheck(
alt(P)))
1703 return base_t::winByFoul(P);
1707 const Square last_to = last_move.
to();
1709 const Piece last_move_piece = state.state().pieceOnBoard(last_to);
1711 if (state.state().inCheck())
1713 const bool check_by_lance = state.state().hasEffectByPtypeStrict<
LANCE>
1714 (
alt(P), state.state().template kingSquare<P>());
1715 const bool has_safe_move
1717 cur_val = (has_safe_move
1718 ? currentValueWithLastThreat(ev, last_move_piece)
1719 : base_t::winByCheckmate(
alt(P)));
1720 assert(cur_val % 2 == 0);
1724 cur_val = currentValueWithLastThreat(ev, last_move_piece);
1725 assert(cur_val % 2 == 0);
1740 if (examineTakeBack<P>(moves, cur_val, alpha, beta, ev)) {
1741 assert(cur_val % 2 == 0);
1746 assert(cur_val % 2 == 0);
1750 template <
class EvalT>
1751 template <osl::Player P>
1757 assert(! state.state().inCheck());
1758 const int static_value = ev.value();
1760 return static_value;
1762 const int FirstThreat = QSearchTraits::FirstThreat;
1763 const int SecondThreat
1764 = (depthFromRoot() < QSearch2PrivateTraits::EscapeDepthFromRoot)
1766 : QSearchTraits::SecondThreat;
1770 static_value - FirstThreat*(static_value - alpha))
1774 static_value - SecondThreat*(static_value - alpha))
1777 threat1.
value = static_value;
1778 threat2.
value = static_value;
1780 assert(state.state().turn() == P);
1783 assert(! state.state().inCheck());
1789 ev2.update(state.state(), Move::PASS(P));
1792 if (generateAndExamineTakeBack2<O,ROOK>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1794 if (generateAndExamineTakeBack2<O,BISHOP>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1796 if (generateAndExamineTakeBack2<O,GOLD>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1798 if (generateAndExamineTakeBack2<O,SILVER>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1800 if (generateAndExamineTakeBack2<O,KNIGHT>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1802 if (generateAndExamineTakeBack2<O,LANCE>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1806 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1810 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1814 if (examineTakeBack2<O,true,false>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1817 if (
depth() >= QSearch2PrivateTraits::PawnCaptureDepth
1820 if (generateAndExamineTakeBack2<O,PAWN>(moves, threat2, threat1, o_beta1, o_beta2, ev2))
1829 && target.
square().template canPromote<O>()) {
1831 assert(threat1.
value % 2 == 0);
1832 return threat1.
value;
1836 const int result1 = (static_value - (static_value - threat1.
value)/FirstThreat);
1837 const int result2 = (static_value - (static_value - threat2.
value)/SecondThreat);
1840 assert(result % 2 == 0);