Now I want to implement the hash best move feature, where if the hashed position was found but the depth wasn't deep enough to use or the score wasn't good enough for a cutoff, we at least see if there is a best move which we try first in our sort. Seems to me there are 3 conditions where we do NOT know the best move:
(1) we are on a leaf node (Depth = 0)
(2) there are no moves to make (player is mated or stalemated)
(3) hash score type was a fail low (score was <= Alpha)
So moves that yield Exact scores or Beta cutoff scores get stored as the best move. To implement this, my AlphaBeta() has a local var uiBestMove (an unsigned 32-bit Integer containing all the move info/coordinates) which is passed byRef to iReadHash(), so after the iReadHash() call, uiBestMove is either a move or it's 0 (0 is an impossible value for a move). I then pass uiBestMove to my SortMoveList() routine, and I have an assert in SortMoveList() that if uiBestMove is non-zero, then it must be found in the move list. But that assert fails! I don't know why. With some debugging I found that it only fails on best moves that are beta cutoff moves. It works with exact-score-best-moves. Here is my AlphaBeta() routine (thanks to Bruce Moreland for his sample code):
Code: Select all
Function AlphaBeta(ByVal iDepth As Integer, ByVal iAlpha As Integer, ByVal iBeta As Integer, ByRef iMoveIndex As Integer) As Integer
'iDepth is initially passed in as iMAXPLY
Dim iVal As Integer
Dim iScoreType As Integer
iScoreType = iHASH_ALPHA
Dim uiBestMove As UInteger
uiBestMove = 0
Dim iBestMoveIndex As Integer
iBestMoveIndex = -1
iVal = iReadHash(iDepth, iAlpha, iBeta, uiBestMove)
If iVal <> iVAL_UNKNOWN Then
Return iVal
End If
If iDepth = 0 Then
iVal = iEvaluate() 'if mating score, score is offset by iPly
Call SaveHash(iDepth, iVal, iHASH_EXACT)
'since iDepth is 0, no 'BestMove' is stored
Return iVal
End If
Call GenerateMoves(iDepth) 'for whoever's turn it is
If aMOVENUMS(iDepth) = 0 Then 'mate or stalemate
'if player mated, return mating score
If fInCheck() Then 'for whoever's turn it is
Call SaveHash(iDepth, -iINFINITY + iMAXPLY - iDepth, iHASH_EXACT)
'since aMOVENUMS(iDepth) = 0, no 'BestMove' is stored
Return -iINFINITY + iMAXPLY - iDepth 'player is mated
End If
'player is stalemated, store score of 0 (tie)
Call SaveHash(iDepth, 0, iHASH_EXACT)
'since aMOVENUMS(iDepth) = 0, no 'BestMove' is stored
Return 0
Else
Call SortMoveList(iDepth, uiBestMove)
End If
aMOVES(iDepth) = 0 'move counter for this ply
While aMOVES(iDepth) < aMOVENUMS(iDepth) 'while there are moves left
aMOVES(iDepth) = aMOVES(iDepth) + 1
Call DoMove(aMOVELIST(aMOVES(iDepth), iDepth), False)
iVal = -AlphaBeta(iDepth - 1, -iBeta, -iAlpha, iMoveIndex)
Call UndoMove()
If iVal >= iBeta Then
Call StoreKiller(iDepth) 'killer move is beta cutoff move aMOVELIST(aMOVES(iDepth), iDepth)
Call SaveHash(iDepth, iBeta, iHASH_BETA, aMOVES(iDepth))
'beta cutoff move, which is aMOVELIST(aMOVES(iDepth), iDepth), will be stored as 'BestMove'
Return iBeta
End If
If iVal > iAlpha Then
iScoreType = iHASH_EXACT
iAlpha = iVal
iBestMoveIndex = aMOVES(iDepth)
End If
End While
Call SaveHash(iDepth, iAlpha, iScoreType, iBestMoveIndex) 'save score in hash table (it will be fail-low or exact)
'if score type is iHASH_ALPHA, no 'BestMove' is stored (iBestMoveIndex would still be -1)
'if score type is iHASH_EXACT, the 'BestMove' aMOVELIST(iBestMoveIndex, iDepth) is stored
iMoveIndex = iBestMoveIndex 'so a ply1 move gets set (iMoveIndex is passed byRef)
Return iAlpha
End Function
Code: Select all
Function iReadHash(ByVal iDepth As Integer, ByVal iAlpha As Integer, ByVal iBeta As Integer, ByRef uiBestMove As UInteger) As Integer
'called by AlphaBeta()
Dim iAdjustedScore As Integer
Debug.Assert(ulHash() = ulCURRENT_HASH) 'incremental hash is the same as computing hash from scratch
With aHASH_TABLE(CInt(ulCURRENT_HASH And ulHASHENTRIES))
If .ulHashCode = ulCURRENT_HASH Then 'we found a match in the hash table
If .iDepth >= iDepth Then 'depth searched is >= depth to search now
If Math.Abs(.iScore) > iMINMATESCORE Then
'mating score in hash is really showing the distance to mate (as an offset from +/- infinity)
If .iScore > 0 Then
iAdjustedScore = .iScore - iMAXPLY + iDepth 'this is like hashscore - ply
Else
iAdjustedScore = .iScore + iMAXPLY - iDepth 'this is like hashscore + ply
End If
Else
iAdjustedScore = .iScore 'it wasn't a mating score
End If
If .iScoreType = iHASH_EXACT Then
Return iAdjustedScore
End If
If .iScoreType = iHASH_ALPHA AndAlso iAdjustedScore <= iAlpha Then
Return iAlpha
End If
If .iScoreType = iHASH_BETA AndAlso iAdjustedScore >= iBeta Then
Return iBeta
End If
End If
'remember best move (if any)
uiBestMove = .uiBestMove
End If
Return iVAL_UNKNOWN
End With
End Function
Code: Select all
Sub SaveHash(ByVal iDepth As Integer, ByVal iVal As Integer, ByVal iScoreType As Integer, Optional ByVal iBestMoveIndex As Integer = -1)
'called by AlphaBeta()
If Math.Abs(iVal) > iMINMATESCORE Then
'a mating score is being saved in the hash, so adjust the offset from +/- infinity to be
'the distance from mate, instead of the ply where the mating move is
If iVal > 0 Then
iVal = iVal + iMAXPLY - iDepth 'this is like score + ply
Else
iVal = iVal - iMAXPLY + iDepth 'this is like score - ply
End If
End If
Debug.Assert(ulHash() = ulCURRENT_HASH) 'incremental hash is the same as computing hash from scratch
'[hash table is presently cleared every move]
With aHASH_TABLE(CInt(ulCURRENT_HASH And ulHASHENTRIES))
.ulHashCode = ulCURRENT_HASH
.iScore = iVal
.iScoreType = iScoreType
.iDepth = iDepth
If iBestMoveIndex <> -1 Then
'if score is exact or exceeds beta,
'and not a leaf node,
'and player has a move to make - (not mated/stalemated),
'then store best move
.uiBestMove = aMOVELIST(iBestMoveIndex, iDepth)
Debug.Assert(.uiBestMove <> 0)
Else
'score was fail low (did not exced alpha),
'or position was a leaf node
'or position was over because of mate or stalemate
'so there is no best move
.uiBestMove = 0
End If
End With
End Sub
thank you!
[/code]