I was testing the correctness of my engine's PVS, TT, ID, and move sorting, against plain alpha-beta, and I discovered that PVS gives different results.
I also tested the other features, and they were consistent with the alphaBeta function, so I'm sure the problem is somewhere in the PVS code.
Code: Select all
int Search::PVS(int alpha, int beta, short depth, short ply, bool doNull) {
nodesSearched++;
int pvIndex = ply * (2 * MAX_DEPTH + 1 - ply) / 2;
int pvNextIndex = pvIndex + MAX_DEPTH - ply;
memset(pvArray + pvIndex, MoveUtils::NO_MOVE, sizeof(int) * (pvNextIndex - pvIndex));
int hashFlag = TranspositionTable::HASH_F_ALPHA;
bool isInCheck = board->isInCheck();
int mateScore = MATE_EVAL - ply;
if(alpha >= beta) return alpha;
if(board->isDraw()) return 0;
bool isPV = (beta - alpha > 1);
// retrieving the hashed move and evaluation if there is any
int hashScore = transpositionTable->probeHash(depth, alpha, beta);
if(hashScore != TranspositionTable::VAL_UNKNOWN) {
// we return hashed info only if it is an exact hit in pv nodes
if(!isPV || (hashScore > alpha && hashScore < beta)) {
return hashScore;
}
}
int moves[256];
int num = board->generateLegalMoves(moves);
if(num == 0) {
if(isInCheck) return -mateScore; // checkmate
return 0; // stalemate
}
if(depth <= 0) {
int q = quiescence(alpha, beta);
return q;
}
int currBestMove = MoveUtils::NO_MOVE;
int movesSearched = 0;
for(int idx = 0; idx < num; idx++) {
if(alpha >= beta) return alpha;
board->makeMove(moves[idx]);
// --- PRINCIPAL VARIATION SEARCH ---
int score;
if(!movesSearched) {
score = -PVS(-beta, -alpha, depth-1, ply+1, true);
} else {
score = -PVS(-alpha-1, -alpha, depth-1, ply+1, true);
if(score > alpha && score < beta) {
score = -PVS(-beta, -alpha, depth-1, ply+1, true);
}
}
board->unmakeMove(moves[idx]);
movesSearched++;
if(score > alpha) {
currBestMove = moves[idx];
pvArray[pvIndex] = moves[idx];
copyPv(pvArray + pvIndex + 1, pvArray + pvNextIndex, MAX_DEPTH - ply - 1);
if(score >= beta) {
transpositionTable->recordHash(depth, beta, TranspositionTable::HASH_F_BETA, currBestMove);
// killers and history
return beta;
}
hashFlag = TranspositionTable::HASH_F_EXACT;
alpha = score;
}
}
transpositionTable->recordHash(depth, alpha, hashFlag, currBestMove);
return alpha;
}
Code: Select all
int Search::alphaBeta(int alpha, int beta, short depth, short ply, bool doNull) {
nodesSearched++;
if(alpha >= beta) return alpha;
if(board->isDraw()) return 0;
bool isInCheck = board->isInCheck();
int moves[256];
int num = board->generateLegalMoves(moves);
if(num == 0) {
int mateScore = MATE_EVAL - ply;
if(isInCheck) return -mateScore; // checkmate
return 0; // stalemate
}
if(depth <= 0) {
int q = quiescence(alpha, beta);
return q;
}
int currBestMove = MoveUtils::NO_MOVE;
int movesSearched = 0;
for(int idx = 0; idx < num; idx++) {
if(alpha >= beta) return alpha;
board->makeMove(moves[idx]);
int score = -alphaBeta(-beta, -alpha, depth-1, ply+1, true);
board->unmakeMove(moves[idx]);
movesSearched++;
if(score > alpha) {
currBestMove = moves[idx];
if(depth == currMaxDepth) bestMove = currBestMove;
if(score >= beta) return beta;
alpha = score;
}
}
return alpha;
}
So is there a mistake in my code, or is PVS not supposed to return the same result as alphaBeta?
Thanks!