int NextCaptureOrCheck(MOVES * m) // used in QuiesceCheck() { int move; switch (m->phase) { case 0: while (m->next < m->last) { move = SelectBest(m); if (BadCapture(m->p, move)) continue; return move; } m->phase = 1; case 1: m->last = GenerateQuietChecks(m->p, m->move); ScoreQuiet(m); m->phase = 2; case 2: while (m->next < m->last) { move = SelectBest(m); if (Swap(m->p, Fsq(move), Tsq(move)) < 0) continue; return move; } } return 0; }
int NextMove(MOVES *m, int *flag) { int move; switch (m->phase) { case 0: // return transposition table move, if legal move = m->trans_move; if (move && Legal(m->p, move)) { m->phase = 1; *flag = MV_HASH; return move; } case 1: // helper phase: generate captures m->last = GenerateCaptures(m->p, m->move); ScoreCaptures(m); m->next = m->move; m->badp = m->bad; m->phase = 2; case 2: // return good captures, save bad ones on the separate list while (m->next < m->last) { move = SelectBest(m); if (move == m->trans_move) continue; if (BadCapture(m->p, move)) { *m->badp++ = move; continue; } *flag = MV_CAPTURE; return move; } case 3: // first killer move move = m->killer1; if (move && move != m->trans_move && m->p->pc[Tsq(move)] == NO_PC && Legal(m->p, move)) { m->phase = 4; *flag = MV_KILLER; return move; } case 4: // second killer move move = m->killer2; if (move && move != m->trans_move && m->p->pc[Tsq(move)] == NO_PC && Legal(m->p, move)) { m->phase = 5; *flag = MV_KILLER; return move; } case 5: // refutation move move = m->ref_move; if (move && move != m->trans_move && m->p->pc[Tsq(move)] == NO_PC && move != m->killer1 && move != m->killer2 && Legal(m->p, move)) { m->phase = 6; *flag = MV_NORMAL; return move; } case 6: // helper phase: generate quiet moves m->last = GenerateQuiet(m->p, m->move); ScoreQuiet(m); m->next = m->move; m->phase = 7; case 7: // return quiet moves while (m->next < m->last) { move = SelectBest(m); if (move == m->trans_move || move == m->killer1 || move == m->killer2 || move == m->ref_move) continue; *flag = MV_NORMAL; return move; } m->next = m->bad; m->phase = 8; case 8: // return bad captures if (m->next < m->badp) { *flag = MV_BADCAPT; return *m->next++; } } return 0; }
int Quiesce(POS *p, int ply, int alpha, int beta, int *pv) { int best, score, move, new_pv[MAX_PLY]; MOVES m[1]; UNDO u[1]; int op = Opp(p->side); // Statistics and attempt at quick exit if (InCheck(p)) return QuiesceFlee(p, ply, alpha, beta, pv); nodes++; CheckTimeout(); if (abort_search) return 0; *pv = 0; if (IsDraw(p)) return DrawScore(p); if (ply >= MAX_PLY - 1) return Eval.Return(p, 1); // Get a stand-pat score and adjust bounds // (exiting if eval exceeds beta) best = Eval.Return(p, 1); if (best >= beta) return best; if (best > alpha) alpha = best; #ifdef USE_QS_HASH // Transposition table read if (TransRetrieve(p->hash_key, &move, &score, alpha, beta, 0, ply)) return score; #endif InitCaptures(p, m); // Main loop while ((move = NextCapture(m))) { // Pruning in quiescence search // (not applicable if we are capturing last enemy piece) if (p->cnt[op][N] + p->cnt[op][B] + p->cnt[op][R] + p->cnt[op][Q] > 1) { // 1. Delta pruning if (best + tp_value[TpOnSq(p, Tsq(move))] + 300 < alpha) continue; // 2. SEE-based pruning of bad captures if (BadCapture(p, move)) continue; } p->DoMove(move, u); if (Illegal(p)) { p->UndoMove(move, u); continue; } score = -Quiesce(p, ply + 1, -beta, -alpha, new_pv); p->UndoMove(move, u); if (abort_search) return 0; // Beta cutoff if (score >= beta) { #ifdef USE_QS_HASH TransStore(p->hash_key, *pv, best, LOWER, 0, ply); #endif return score; } // Adjust alpha and score if (score > best) { best = score; if (score > alpha) { alpha = score; BuildPv(pv, new_pv, move); } } } #ifdef USE_QS_HASH if (*pv) TransStore(p->hash_key, *pv, best, EXACT, 0, ply); else TransStore(p->hash_key, 0, best, UPPER, 0, ply); #endif return best; }