Implement QSEE pruning
This commit is contained in:
parent
25677ae2c6
commit
ec309c9d4d
|
@ -187,6 +187,7 @@ proc getEstimatedMoveScore(self: SearchManager, move: Move, ply: int): int =
|
||||||
|
|
||||||
if move.isTactical():
|
if move.isTactical():
|
||||||
let seeScore = self.board.position.see(move)
|
let seeScore = self.board.position.see(move)
|
||||||
|
when not defined(SEE2):
|
||||||
# We want to prioritize good captures (see > 0), but if the capture
|
# We want to prioritize good captures (see > 0), but if the capture
|
||||||
# is bad then at least we sort it with MVVLVA
|
# is bad then at least we sort it with MVVLVA
|
||||||
if seeScore < 0 and (move.isCapture() or move.isEnPassant()):
|
if seeScore < 0 and (move.isCapture() or move.isEnPassant()):
|
||||||
|
@ -218,6 +219,43 @@ proc getEstimatedMoveScore(self: SearchManager, move: Move, ply: int): int =
|
||||||
else:
|
else:
|
||||||
# If the capture is good then we just use the SEE score + the offset
|
# If the capture is good then we just use the SEE score + the offset
|
||||||
return seeScore + GOOD_SEE_OFFSET
|
return seeScore + GOOD_SEE_OFFSET
|
||||||
|
else:
|
||||||
|
# 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():
|
if move.isQuiet():
|
||||||
# History heuristic bonus
|
# History heuristic bonus
|
||||||
|
@ -341,6 +379,9 @@ proc qsearch(self: var SearchManager, ply: int, alpha, beta: Score): Score =
|
||||||
var bestScore = score
|
var bestScore = score
|
||||||
var alpha = max(alpha, score)
|
var alpha = max(alpha, score)
|
||||||
for move in moves:
|
for move in moves:
|
||||||
|
# Skip bad captures (gains 52.9 +/- 25.2)
|
||||||
|
if self.board.position.see(move) < 0:
|
||||||
|
continue
|
||||||
self.board.doMove(move)
|
self.board.doMove(move)
|
||||||
inc(self.nodeCount)
|
inc(self.nodeCount)
|
||||||
let score = -self.qsearch(ply + 1, -beta, -alpha)
|
let score = -self.qsearch(ply + 1, -beta, -alpha)
|
||||||
|
|
Loading…
Reference in New Issue