void Checkers::play() { currentPlayer = 1; std::vector<int> MoveStart; std::vector<int> MoveEnd; std::vector<int> AIMove; currentState.Display(); while (terminalStatus != true) { //currentState.Display(); switch (currentPlayer) { case 1: MoveStart = player1.getmoveStart(); MoveEnd = player1.getmoveEnd(MoveStart); while (!LegalMove(MoveStart, MoveEnd, currentState) && getPiece(MoveStart) == 1 && !checkEmpty(MoveEnd)) { MoveStart = player1.getmoveStart(); //swap values to match how table is laid out std::swap(MoveStart[0], MoveStart[1]); MoveEnd = player1.getmoveEnd(MoveStart); std::swap(MoveEnd[0], MoveEnd[1]); } currentState.FullMove(MoveStart, MoveEnd); //std::cout << MoveStart[0] << " " << MoveStart[1] << " to " << MoveEnd[0] << " " << MoveEnd[1] << std::endl; currentPlayer = 2; break; case 2: AIMove = player2.getmove(currentState); //swap locations when moving, due to way Move is written to work with human inputs. MoveStart = { AIMove[1],AIMove[0] }; MoveEnd = { AIMove[3],AIMove[2] }; currentState.FullMove(MoveStart, MoveEnd); currentPlayer = 1; break; } //std::cout << MoveStart[0] << " " << MoveStart[1] << " to " << MoveEnd[0] << " " << MoveEnd[1] << std::endl; //currentState.FullMove(MoveStart, MoveEnd); } }
// 不吃子着法生成器 int PositionStruct::GenNonCapMoves(MoveStruct *lpmvs) const { int i, sqSrc, sqDst, x, y, nSideTag; SlideMoveStruct *lpsmv; uint8_t *lpucsqDst, *lpucsqPin; MoveStruct *lpmvsCurr; // 生成不吃子着法的过程包括以下几个步骤: lpmvsCurr = lpmvs; nSideTag = SIDE_TAG(sdPlayer); // 1. 生成帅(将)的着法 sqSrc = ucsqPieces[nSideTag + KING_FROM]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKingMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); // 找到一个着法后,首先判断是否吃到棋子 if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } // 2. 生成仕(士)的着法 for (i = ADVISOR_FROM; i <= ADVISOR_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqAdvisorMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } // 3. 生成相(象)的着法 for (i = BISHOP_FROM; i <= BISHOP_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqBishopMoves[sqSrc]; lpucsqPin = PreGen.ucsqBishopPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0 && ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 4. 生成马的着法 for (i = KNIGHT_FROM; i <= KNIGHT_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKnightMoves[sqSrc]; lpucsqPin = PreGen.ucsqKnightPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0 && ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 5. 生成车和炮的着法,没有必要判断是否吃到本方棋子 for (i = ROOK_FROM; i <= CANNON_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucNonCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst --; } sqDst = lpsmv->ucNonCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst ++; } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucNonCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst -= 16; } sqDst = lpsmv->ucNonCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); while (sqDst != sqSrc) { __ASSERT(ucpcSquares[sqDst] == 0); __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; sqDst += 16; } } } // 6. 生成兵(卒)的着法 for (i = PAWN_FROM; i <= PAWN_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqPawnMoves[sdPlayer][sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[sqDst] == 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->dwmv = MOVE(sqSrc, sqDst); lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } return lpmvsCurr - lpmvs; }
// 吃子着法生成器,按MVV(LVA)设定分值 int PositionStruct::GenCapMoves(MoveStruct *lpmvs) const { int i, sqSrc, sqDst, pcCaptured; int x, y, nSideTag, nOppSideTag; bool bCanPromote; SlideMoveStruct *lpsmv; uint8_t *lpucsqDst, *lpucsqPin; MoveStruct *lpmvsCurr; // 生成吃子着法的过程包括以下几个步骤: lpmvsCurr = lpmvs; nSideTag = SIDE_TAG(sdPlayer); nOppSideTag = OPP_SIDE_TAG(sdPlayer); bCanPromote = PreEval.bPromotion && CanPromote(); // 1. 生成帅(将)的着法 sqSrc = ucsqPieces[nSideTag + KING_FROM]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKingMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); // 找到一个着法后,首先判断吃到的棋子是否是对方棋子,技巧是利用"nOppSideTag"的标志(16和32颠倒), // 如果是对方棋子,则保存MVV(LVA)值,即如果被吃子无保护,则只记MVV,否则记MVV-LVA(如果MVV>LVA的话)。 pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 5); // 帅(将)的价值是5 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } // 2. 生成仕(士)的着法 for (i = ADVISOR_FROM; i <= ADVISOR_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqAdvisorMoves[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 1); // 仕(士)的价值是1 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } if (bCanPromote && CAN_PROMOTE(sqSrc)) { lpmvsCurr->wmv = MOVE(sqSrc, sqSrc); lpmvsCurr->wvl = 0; lpmvsCurr ++; } } } // 3. 生成相(象)的着法 for (i = BISHOP_FROM; i <= BISHOP_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqBishopMoves[sqSrc]; lpucsqPin = PreGen.ucsqBishopPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 1); // 相(象)的价值是1 lpmvsCurr ++; } } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } if (bCanPromote && CAN_PROMOTE(sqSrc)) { lpmvsCurr->wmv = MOVE(sqSrc, sqSrc); lpmvsCurr->wvl = 0; lpmvsCurr ++; } } } // 4. 生成马的着法 for (i = KNIGHT_FROM; i <= KNIGHT_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqKnightMoves[sqSrc]; lpucsqPin = PreGen.ucsqKnightPins[sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); if (ucpcSquares[*lpucsqPin] == 0) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 马的价值是3 lpmvsCurr ++; } } lpucsqDst ++; sqDst = *lpucsqDst; lpucsqPin ++; } } } // 5. 生成车的着法 for (i = ROOK_FROM; i <= ROOK_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucRookCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } sqDst = lpsmv->ucRookCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucRookCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } sqDst = lpsmv->ucRookCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 4); // 车的价值是4 lpmvsCurr ++; } } } } // 6. 生成炮的着法 for (i = CANNON_FROM; i <= CANNON_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); x = FILE_X(sqSrc); y = RANK_Y(sqSrc); lpsmv = RankMovePtr(x, y); sqDst = lpsmv->ucCannonCap[0] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } sqDst = lpsmv->ucCannonCap[1] + RANK_DISP(y); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } lpsmv = FileMovePtr(x, y); sqDst = lpsmv->ucCannonCap[0] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } sqDst = lpsmv->ucCannonCap[1] + FILE_DISP(x); __ASSERT_SQUARE(sqDst); if (sqDst != sqSrc) { pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 3); // 炮的价值是3 lpmvsCurr ++; } } } } // 7. 生成兵(卒)的着法 for (i = PAWN_FROM; i <= PAWN_TO; i ++) { sqSrc = ucsqPieces[nSideTag + i]; if (sqSrc != 0) { __ASSERT_SQUARE(sqSrc); lpucsqDst = PreGen.ucsqPawnMoves[sdPlayer][sqSrc]; sqDst = *lpucsqDst; while (sqDst != 0) { __ASSERT_SQUARE(sqDst); pcCaptured = ucpcSquares[sqDst]; if ((pcCaptured & nOppSideTag) != 0) { __ASSERT(LegalMove(MOVE(sqSrc, sqDst))); lpmvsCurr->wmv = MOVE(sqSrc, sqDst); lpmvsCurr->wvl = MvvLva(sqDst, pcCaptured, 2); // 兵(卒)的价值是2 lpmvsCurr ++; } lpucsqDst ++; sqDst = *lpucsqDst; } } } return lpmvsCurr - lpmvs; }
static int negascout(struct SearchData *sd, int alpha, int beta, const int depth, int node_type #if MP ,int exclusiveP #endif /* MP */ ) { struct Position *p = sd->position; struct SearchStatus *st; int best = -INF; int bestm = M_NONE; int tmp; int talpha; int incheck; int lmove; int move; int extend = 0; int threat = FALSE; int reduce_extensions; int next_type; int was_futile = FALSE; #if FUTILITY int is_futile; int optimistic = 0; #endif #if MP int deferred_cnt = 0; int deferred_list[MAX_DEFERRED]; int deferred_depth[MAX_DEFERRED]; #endif EnterNode(sd); Nodes++; /* check for search termination */ if (sd->master && TerminateSearch(sd)) { AbortSearch = TRUE; goto EXIT; } /* max search depth reached */ if (sd->ply >= MaxDepth) goto EXIT; /* * Check for insufficent material or theoretical draw. */ if ( /* InsufMat(p) || CheckDraw(p) || */ Repeated(p, FALSE)) { best = 0; goto EXIT; } /* * check extension */ incheck = InCheck(p, p->turn); if (incheck && p->material[p->turn] > 0) { extend += CheckExtend(p); ChkExt++; } /* * Check the hashtable */ st = sd->current; HTry++; #if MP switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply, exclusiveP, sd->localHashTable)) #else switch (ProbeHT(p->hkey, &tmp, depth, &(st->st_hashmove), &threat, sd->ply)) #endif /* MP */ { case ExactScore: HHit++; best = tmp; goto EXIT; case UpperBound: if (tmp <= alpha) { HHit++; best = tmp; goto EXIT; } break; case LowerBound: if (tmp >= beta) { HHit++; best = tmp; goto EXIT; } break; case Useless: threat = !incheck && MateThreat(p, OPP(p->turn)); break; #if MP case OnEvaluation: best = -ON_EVALUATION; goto EXIT; #endif } /* * Probe EGTB */ if (depth > EGTBDepth && ProbeEGTB(p, &tmp, sd->ply)) { best = tmp; goto EXIT; } /* * Probe recognizers */ switch (ProbeRecognizer(p, &tmp)) { case ExactScore: best = tmp; goto EXIT; case LowerBound: if (tmp >= beta) { best = tmp; goto EXIT; } break; case UpperBound: if (tmp <= alpha) { best = tmp; goto EXIT; } break; } #if NULLMOVE /* * Null move search. * See Christian Donninger, "Null Move and Deep Search" * ICCA Journal Volume 16, No. 3, pp. 137-143 */ if (!incheck && node_type == CutNode && !threat) { int next_depth; int nms; next_depth = depth - ReduceNullMove; if (next_depth > 0) { next_depth = depth - ReduceNullMoveDeep; } DoNull(p); if (next_depth < 0) { nms = -quies(sd, -beta, -beta+1, 0); } else { #if MP nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode, 0); #else nms = -negascout(sd, -beta, -beta+1, next_depth, AllNode); #endif } UndoNull(p); if (AbortSearch) goto EXIT; if (nms >= beta) { if (p->nonPawn[p->turn] >= Value[Queen]) { best = nms; goto EXIT; } else { if (next_depth < 0) { nms = quies(sd, beta-1, beta, 0); } else { #if MP nms = negascout(sd, beta-1, beta, next_depth, CutNodeNoNull, 0); #else nms = negascout(sd, beta-1, beta, next_depth, CutNodeNoNull); #endif } if (nms >= beta) { best = nms; goto EXIT; } else { extend += ExtendZugzwang; ZZExt++; } } } else if (nms <= -CMLIMIT) { threat = TRUE; } } #endif /* NULLMOVE */ lmove = (p->actLog-1)->gl_Move; reduce_extensions = (sd->ply > 2*sd->depth); talpha = alpha; switch (node_type) { case AllNode: next_type = CutNode; break; case CutNode: case CutNodeNoNull: next_type = AllNode; break; default: next_type = PVNode; break; } #if FUTILITY is_futile = !incheck && !threat && alpha < CMLIMIT && alpha > -CMLIMIT; if (is_futile) { if (p->turn == White) { optimistic = MaterialBalance(p) + MaxPos; } else { optimistic = -MaterialBalance(p) + MaxPos; } } #endif /* FUTILITY */ /* * Internal iterative deepening. If we do not have a move, we try * a shallow search to find a good candidate. */ if (depth > 2*OnePly && ((alpha + 1) != beta) && !LegalMove(p, st->st_hashmove)) { int useless; #if MP useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode, 0); #else useless = negascout(sd, alpha, beta, depth-2*OnePly, PVNode); #endif st->st_hashmove = sd->pv_save[sd->ply+1]; } /* * Search all legal moves */ while ((move = incheck ? NextEvasion(sd) : NextMove(sd)) != M_NONE) { int next_depth = extend; if (move & M_CANY && !MayCastle(p, move)) continue; /* * recapture extension */ if ((move & M_CAPTURE) && (lmove & M_CAPTURE) && M_TO(move) == M_TO(lmove) && IsRecapture(p->piece[M_TO(move)], (p->actLog-1)->gl_Piece)) { RCExt += 1; next_depth += ExtendRecapture[TYPE(p->piece[M_TO(move)])]; } /* * passed pawn push extension */ if (TYPE(p->piece[M_FROM(move)]) == Pawn && p->nonPawn[OPP(p->turn)] <= Value[Queen]) { int to = M_TO(move); if (((p->turn == White && to >= a7) || (p->turn == Black && to <= h2)) && IsPassed(p, to, p->turn) && SwapOff(p, move) >= 0) { next_depth += ExtendPassedPawn; PPExt += 1; } } /* * limit extensions to sensible range. */ if (reduce_extensions) next_depth /= 2; next_depth += depth - OnePly; #if FUTILITY /* * Futility cutoffs */ if (is_futile) { if (next_depth < 0 && !IsCheckingMove(p, move)) { tmp = optimistic + ScoreMove(p, move); if (tmp <= alpha) { if (tmp > best) { best = tmp; bestm = move; was_futile = TRUE; } continue; } } #if EXTENDED_FUTILITY /* * Extended futility cutoffs and limited razoring. * See Ernst A. Heinz, "Extended Futility Pruning" * ICCA Journal Volume 21, No. 2, pp 75-83 */ else if (next_depth >= 0 && next_depth < OnePly && !IsCheckingMove(p, move)) { tmp = optimistic + ScoreMove(p, move) + (3*Value[Pawn]); if (tmp <= alpha) { if (tmp > best) { best = tmp; bestm = move; was_futile = TRUE; } continue; } } #if RAZORING else if (next_depth >= OnePly && next_depth < 2*OnePly && !IsCheckingMove(p, move)) { tmp = optimistic + ScoreMove(p, move) + (6*Value[Pawn]); if (tmp <= alpha) { next_depth -= OnePly; } } #endif /* RAZORING */ #endif /* EXTENDED_FUTILITY */ } #endif /* FUTILITY */ DoMove(p, move); if (InCheck(p, OPP(p->turn))) { UndoMove(p, move); } else { /* * Check extension */ if (p->material[p->turn] > 0 && InCheck(p, p->turn)) { next_depth += (reduce_extensions) ? ExtendInCheck>>1 : ExtendInCheck; } /* * Recursively search this position. If depth is exhausted, use * quies, otherwise use negascout. */ if (next_depth < 0) { tmp = -quies(sd, -beta, -talpha, 0); } else if (bestm != M_NONE && !was_futile) { #if MP tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type, bestm != M_NONE); if (tmp != ON_EVALUATION && tmp > talpha && tmp < beta) { tmp = -negascout(sd, -beta, -tmp, next_depth, node_type == PVNode ? PVNode : AllNode, bestm != M_NONE); } #else tmp = -negascout(sd, -talpha-1, -talpha, next_depth, next_type); if (tmp > talpha && tmp < beta) { tmp = -negascout(sd, -beta, -tmp, next_depth, node_type == PVNode ? PVNode : AllNode); } #endif /* MP */ } else { #if MP tmp = -negascout(sd, -beta, -talpha, next_depth, next_type, bestm != M_NONE); #else tmp = -negascout(sd, -beta, -talpha, next_depth, next_type); #endif /* MP */ } UndoMove(p, move); if (AbortSearch) goto EXIT; #if MP if (tmp == ON_EVALUATION) { /* * This child is ON_EVALUATION. Remember move and * depth. */ deferred_list[deferred_cnt] = move; deferred_depth[deferred_cnt] = next_depth; deferred_cnt++; } else { #endif /* MP */ /* * beta cutoff, enter move in Killer/Countermove table */ if (tmp >= beta) { if (!(move & M_TACTICAL)) { PutKiller(sd, move); sd->counterTab[p->turn][lmove & 4095] = move; } StoreResult(sd, tmp, alpha, beta, move, depth, threat); best = tmp; goto EXIT; } /* * Improvement on best move to date */ if (tmp > best) { best = tmp; bestm = move; was_futile = FALSE; if (best > talpha) { talpha = best; } } next_type = CutNode; #if MP } #endif /* MP */ } }