Implement QSEE pruning
This commit is contained in:
parent
25677ae2c6
commit
ec309c9d4d
|
@ -187,37 +187,75 @@ proc getEstimatedMoveScore(self: SearchManager, move: Move, ply: int): int =
|
|||
|
||||
if move.isTactical():
|
||||
let seeScore = self.board.position.see(move)
|
||||
# We want to prioritize good captures (see > 0), but if the capture
|
||||
# is bad then at least we sort it with MVVLVA
|
||||
if seeScore < 0 and (move.isCapture() or move.isEnPassant()):
|
||||
# Implementation of MVVLVA: Most Valuable Victim Least Valuable Aggressor.
|
||||
# We prioritize moves that capture the most valuable pieces, and as a
|
||||
# second goal we want to use our least valuable pieces to do so (this
|
||||
# is why we multiply the score of the captured piece by a constant, to give
|
||||
# it priority)
|
||||
let capturedScore = MVV_LVA_MULTIPLIER * self.board.position.getPieceScore(move.targetSquare)
|
||||
result = capturedScore - self.board.position.getPieceScore(move.startSquare)
|
||||
|
||||
# If the capture is also a promotion we want to give it an even bigger bonus
|
||||
if move.isPromotion():
|
||||
var piece: Piece
|
||||
case move.getPromotionType():
|
||||
of PromoteToBishop:
|
||||
piece = Piece(kind: Bishop, color: sideToMove)
|
||||
of PromoteToKnight:
|
||||
piece = Piece(kind: Knight, color: sideToMove)
|
||||
of PromoteToRook:
|
||||
piece = Piece(kind: Rook, color: sideToMove)
|
||||
of PromoteToQueen:
|
||||
piece = Piece(kind: Queen, color: sideToMove)
|
||||
else:
|
||||
discard # Unreachable
|
||||
result += PROMOTION_MULTIPLIER * self.board.position.getPieceScore(piece, move.targetSquare)
|
||||
when not defined(SEE2):
|
||||
# We want to prioritize good captures (see > 0), but if the capture
|
||||
# is bad then at least we sort it with MVVLVA
|
||||
if seeScore < 0 and (move.isCapture() or move.isEnPassant()):
|
||||
# Implementation of MVVLVA: Most Valuable Victim Least Valuable Aggressor.
|
||||
# We prioritize moves that capture the most valuable pieces, and as a
|
||||
# second goal we want to use our least valuable pieces to do so (this
|
||||
# is why we multiply the score of the captured piece by a constant, to give
|
||||
# it priority)
|
||||
let capturedScore = MVV_LVA_MULTIPLIER * self.board.position.getPieceScore(move.targetSquare)
|
||||
result = capturedScore - self.board.position.getPieceScore(move.startSquare)
|
||||
|
||||
# If the capture is also a promotion we want to give it an even bigger bonus
|
||||
if move.isPromotion():
|
||||
var piece: Piece
|
||||
case move.getPromotionType():
|
||||
of PromoteToBishop:
|
||||
piece = Piece(kind: Bishop, color: sideToMove)
|
||||
of PromoteToKnight:
|
||||
piece = Piece(kind: Knight, color: sideToMove)
|
||||
of PromoteToRook:
|
||||
piece = Piece(kind: Rook, color: sideToMove)
|
||||
of PromoteToQueen:
|
||||
piece = Piece(kind: Queen, color: sideToMove)
|
||||
else:
|
||||
discard # Unreachable
|
||||
result += PROMOTION_MULTIPLIER * self.board.position.getPieceScore(piece, move.targetSquare)
|
||||
|
||||
return result + BAD_SEE_OFFSET
|
||||
return result + BAD_SEE_OFFSET
|
||||
else:
|
||||
# If the capture is good then we just use the SEE score + the offset
|
||||
return seeScore + GOOD_SEE_OFFSET
|
||||
else:
|
||||
# If the capture is good then we just use the SEE score + the offset
|
||||
return seeScore + GOOD_SEE_OFFSET
|
||||
# We want to prioritize good captures (see > 0) and then sort
|
||||
# them with MVVLVA. Of course, good captures will be placed
|
||||
# before bad captures regardless of what MVVLVA has to say
|
||||
# about them
|
||||
if move.isCapture() or move.isEnPassant():
|
||||
# Implementation of MVVLVA: Most Valuable Victim Least Valuable Aggressor.
|
||||
# We prioritize moves that capture the most valuable pieces, and as a
|
||||
# second goal we want to use our least valuable pieces to do so (this
|
||||
# is why we multiply the score of the captured piece by a constant, to give
|
||||
# it priority)
|
||||
let capturedScore = MVV_LVA_MULTIPLIER * self.board.position.getPieceScore(move.targetSquare)
|
||||
result = capturedScore - self.board.position.getPieceScore(move.startSquare)
|
||||
|
||||
# If the capture is also a promotion we want to give it an even bigger bonus
|
||||
if move.isPromotion():
|
||||
var piece: Piece
|
||||
case move.getPromotionType():
|
||||
of PromoteToBishop:
|
||||
piece = Piece(kind: Bishop, color: sideToMove)
|
||||
of PromoteToKnight:
|
||||
piece = Piece(kind: Knight, color: sideToMove)
|
||||
of PromoteToRook:
|
||||
piece = Piece(kind: Rook, color: sideToMove)
|
||||
of PromoteToQueen:
|
||||
piece = Piece(kind: Queen, color: sideToMove)
|
||||
else:
|
||||
discard # Unreachable
|
||||
result += PROMOTION_MULTIPLIER * self.board.position.getPieceScore(piece, move.targetSquare)
|
||||
result += seeScore
|
||||
# We use >= instead of > because we're evaluating promotions by
|
||||
# their SEE scores as well, which would move them all to the back
|
||||
# in cases where a promotion ends up with no material loss
|
||||
if seeScore >= 0:
|
||||
return result + GOOD_SEE_OFFSET
|
||||
else:
|
||||
return result + BAD_SEE_OFFSET
|
||||
|
||||
if move.isQuiet():
|
||||
# History heuristic bonus
|
||||
|
@ -341,6 +379,9 @@ proc qsearch(self: var SearchManager, ply: int, alpha, beta: Score): Score =
|
|||
var bestScore = score
|
||||
var alpha = max(alpha, score)
|
||||
for move in moves:
|
||||
# Skip bad captures (gains 52.9 +/- 25.2)
|
||||
if self.board.position.see(move) < 0:
|
||||
continue
|
||||
self.board.doMove(move)
|
||||
inc(self.nodeCount)
|
||||
let score = -self.qsearch(ply + 1, -beta, -alpha)
|
||||
|
|
Loading…
Reference in New Issue