module BishBosh.Search.AlphaBeta(
extractSelectedTurns,
negaMax,
) where
import BishBosh.Evaluation.QuantifiedGame((<=>), (===))
import Control.Applicative((<|>))
import Control.Arrow((&&&))
import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove
import qualified BishBosh.Component.Turn as Component.Turn
import qualified BishBosh.Data.Exception as Data.Exception
import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree
import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame
import qualified BishBosh.Input.SearchOptions as Input.SearchOptions
import qualified BishBosh.Model.Game as Model.Game
import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation
import qualified BishBosh.Property.Arboreal as Property.Arboreal
import qualified BishBosh.Search.DynamicMoveData as Search.DynamicMoveData
import qualified BishBosh.Search.KillerMoves as Search.KillerMoves
import qualified BishBosh.Search.SearchState as Search.SearchState
import qualified BishBosh.Search.Transpositions as Search.Transpositions
import qualified BishBosh.Search.TranspositionValue as Search.TranspositionValue
import qualified BishBosh.State.InstancesByPosition as State.InstancesByPosition
import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour
import qualified BishBosh.Type.Count as Type.Count
import qualified BishBosh.Type.Crypto as Type.Crypto
import qualified Control.Exception
import qualified Control.Monad.Reader
import qualified Data.Default
import qualified Data.Maybe
import qualified Data.Tree
data Result positionHash = MkResult {
Result positionHash -> DynamicMoveData positionHash
getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData positionHash,
Result positionHash -> QuantifiedGame
getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame,
Result positionHash -> NPositions
getNPositionsEvaluated :: Type.Count.NPositions
}
extractSelectedTurns
:: Type.Count.NPlies
-> Result positionHash
-> (Search.DynamicMoveData.DynamicMoveData positionHash, [Component.Turn.Turn], Type.Count.NPositions)
NPositions
nPlies MkResult {
getDynamicMoveData :: forall positionHash.
Result positionHash -> DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData,
getQuantifiedGame :: forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame = QuantifiedGame
quantifiedGame,
getNPositionsEvaluated :: forall positionHash. Result positionHash -> NPositions
getNPositionsEvaluated = NPositions
nPositionsEvaluated
} = (
DynamicMoveData positionHash
dynamicMoveData,
NPositions -> QuantifiedGame -> [Turn]
Evaluation.QuantifiedGame.getLatestTurns NPositions
nPlies QuantifiedGame
quantifiedGame,
NPositions
nPositionsEvaluated
)
updateKillerMoves :: Model.Game.Game -> Search.DynamicMoveData.Transformation positionHash
updateKillerMoves :: Game -> Transformation positionHash
updateKillerMoves Game
game
| Just Turn
lastTurn <- Game -> Maybe Turn
Model.Game.maybeLastTurn Game
game = if Turn -> Bool
Component.Turn.isCapture Turn
lastTurn
then Transformation positionHash
forall a. a -> a
id
else Transformation KillerMoveKey -> Transformation positionHash
forall positionHash.
Transformation KillerMoveKey -> Transformation positionHash
Search.DynamicMoveData.updateKillerMoves (Transformation KillerMoveKey -> Transformation positionHash)
-> (KillerMoveKey -> Transformation KillerMoveKey)
-> KillerMoveKey
-> Transformation positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NPositions -> KillerMoveKey -> Transformation KillerMoveKey
forall killerMoveKey.
Ord killerMoveKey =>
NPositions -> killerMoveKey -> Transformation killerMoveKey
Search.KillerMoves.insert (
TurnsByLogicalColour Turn -> NPositions
forall turn. TurnsByLogicalColour turn -> NPositions
State.TurnsByLogicalColour.getNPlies (TurnsByLogicalColour Turn -> NPositions)
-> TurnsByLogicalColour Turn -> NPositions
forall a b. (a -> b) -> a -> b
$ Game -> TurnsByLogicalColour Turn
Model.Game.getTurnsByLogicalColour Game
game
) (KillerMoveKey -> Transformation positionHash)
-> KillerMoveKey -> Transformation positionHash
forall a b. (a -> b) -> a -> b
$ Turn -> KillerMoveKey
Search.DynamicMoveData.mkKillerMoveKeyFromTurn Turn
lastTurn
| Bool
otherwise = Exception -> Transformation positionHash
forall a e. Exception e => e -> a
Control.Exception.throw (Exception -> Transformation positionHash)
-> (String -> Exception) -> String -> Transformation positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Exception
Data.Exception.mkNullDatum (String -> Exception) -> (String -> String) -> String -> Exception
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
showString String
"BishBosh.Search.AlphaBeta.updateKillerMoves:\tzero turns have been made; " (String -> Transformation positionHash)
-> String -> Transformation positionHash
forall a b. (a -> b) -> a -> b
$ Game -> String -> String
forall a. Show a => a -> String -> String
shows Game
game String
"."
findTranspositionTerminalQuantifiedGame
:: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash
-> Search.TranspositionValue.TranspositionValue Component.QualifiedMove.QualifiedMove
-> Evaluation.QuantifiedGame.QuantifiedGame
findTranspositionTerminalQuantifiedGame :: PositionHashQuantifiedGameTree positionHash
-> TranspositionValue QualifiedMove -> QuantifiedGame
findTranspositionTerminalQuantifiedGame PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree TranspositionValue QualifiedMove
transpositionValue = QuantifiedGame
-> ([NodeLabel positionHash] -> QuantifiedGame)
-> Maybe [NodeLabel positionHash]
-> QuantifiedGame
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe (
Exception -> QuantifiedGame
forall a e. Exception e => e -> a
Control.Exception.throw (Exception -> QuantifiedGame)
-> (String -> Exception) -> String -> QuantifiedGame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Exception
Data.Exception.mkSearchFailure (String -> Exception) -> (String -> String) -> String -> Exception
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
showString String
"BishBosh.Search.AlphaBeta.findTranspositionTerminalQuantifiedGame:\tEvaluation.PositionHashQuantifiedGameTree.traceMatchingMoveSequence failed; " (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TranspositionValue QualifiedMove -> String -> String
forall a. Show a => a -> String -> String
shows TranspositionValue QualifiedMove
transpositionValue (String -> String) -> (String -> String) -> String -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
showString String
":\n" (String -> QuantifiedGame) -> String -> QuantifiedGame
forall a b. (a -> b) -> a -> b
$ (
MoveNotation
-> NPositions
-> PositionHashQuantifiedGameTree positionHash
-> String
-> String
forall a.
ShowNotationFloat a =>
MoveNotation -> NPositions -> a -> String -> String
Notation.MoveNotation.showsNotationFloatToNDecimals MoveNotation
forall a. Default a => a
Data.Default.def NPositions
3 (PositionHashQuantifiedGameTree positionHash -> String -> String)
-> PositionHashQuantifiedGameTree positionHash -> String -> String
forall a b. (a -> b) -> a -> b
$ NPositions
-> PositionHashQuantifiedGameTree positionHash
-> PositionHashQuantifiedGameTree positionHash
forall tree. Prunable tree => NPositions -> tree -> tree
Property.Arboreal.prune (NPositions -> NPositions
forall a b. (Integral a, Num b) => a -> b
fromIntegral NPositions
inferredSearchDepth) PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
) String
""
) (
(
if NPositions -> Bool
forall a. Integral a => a -> Bool
even NPositions
inferredSearchDepth
then QuantifiedGame -> QuantifiedGame
Evaluation.QuantifiedGame.negateFitness
else QuantifiedGame -> QuantifiedGame
forall a. a -> a
id
) (QuantifiedGame -> QuantifiedGame)
-> ([NodeLabel positionHash] -> QuantifiedGame)
-> [NodeLabel positionHash]
-> QuantifiedGame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NodeLabel positionHash -> QuantifiedGame
forall positionHash. NodeLabel positionHash -> QuantifiedGame
Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame (NodeLabel positionHash -> QuantifiedGame)
-> ([NodeLabel positionHash] -> NodeLabel positionHash)
-> [NodeLabel positionHash]
-> QuantifiedGame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [NodeLabel positionHash] -> NodeLabel positionHash
forall a. [a] -> a
last
) (Maybe [NodeLabel positionHash] -> QuantifiedGame)
-> (QualifiedMoveSequence -> Maybe [NodeLabel positionHash])
-> QualifiedMoveSequence
-> QuantifiedGame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionHashQuantifiedGameTree positionHash
-> QualifiedMoveSequence -> Maybe [NodeLabel positionHash]
forall positionHash.
PositionHashQuantifiedGameTree positionHash
-> QualifiedMoveSequence -> Maybe [NodeLabel positionHash]
Evaluation.PositionHashQuantifiedGameTree.traceMatchingMoveSequence PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree (QualifiedMoveSequence -> QuantifiedGame)
-> QualifiedMoveSequence -> QuantifiedGame
forall a b. (a -> b) -> a -> b
$ TranspositionValue QualifiedMove -> QualifiedMoveSequence
forall qualifiedMove.
TranspositionValue qualifiedMove -> [qualifiedMove]
Search.TranspositionValue.getQualifiedMoves TranspositionValue QualifiedMove
transpositionValue where
inferredSearchDepth :: NPositions
inferredSearchDepth = TranspositionValue QualifiedMove -> NPositions
forall qualifiedMove.
TranspositionValue qualifiedMove -> NPositions
Search.TranspositionValue.inferSearchDepth TranspositionValue QualifiedMove
transpositionValue
updateTranspositions
:: Ord positionHash
=> Search.TranspositionValue.IsOptimal
-> Type.Count.NPlies
-> positionHash
-> [Component.Turn.Turn]
-> Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash
-> Search.DynamicMoveData.Transformation positionHash
updateTranspositions :: Bool
-> NPositions
-> positionHash
-> [Turn]
-> PositionHashQuantifiedGameTree positionHash
-> Transformation positionHash
updateTranspositions Bool
isOptimal NPositions
nPlies positionHash
positionHash [Turn]
turns PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree = Transformation QualifiedMove positionHash
-> Transformation positionHash
forall positionHash.
Transformation QualifiedMove positionHash
-> Transformation positionHash
Search.DynamicMoveData.updateTranspositions (Transformation QualifiedMove positionHash
-> Transformation positionHash)
-> (QualifiedMoveSequence
-> Transformation QualifiedMove positionHash)
-> QualifiedMoveSequence
-> Transformation positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FindFitness QualifiedMove
-> positionHash
-> TranspositionValue QualifiedMove
-> Transformation QualifiedMove positionHash
forall positionHash qualifiedMove.
Ord positionHash =>
FindFitness qualifiedMove
-> positionHash
-> TranspositionValue qualifiedMove
-> Transformation qualifiedMove positionHash
Search.Transpositions.insert (
QuantifiedGame -> WeightedMean
Evaluation.QuantifiedGame.getFitness (QuantifiedGame -> WeightedMean)
-> (TranspositionValue QualifiedMove -> QuantifiedGame)
-> FindFitness QualifiedMove
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PositionHashQuantifiedGameTree positionHash
-> TranspositionValue QualifiedMove -> QuantifiedGame
forall positionHash.
PositionHashQuantifiedGameTree positionHash
-> TranspositionValue QualifiedMove -> QuantifiedGame
findTranspositionTerminalQuantifiedGame PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
) positionHash
positionHash (TranspositionValue QualifiedMove
-> Transformation QualifiedMove positionHash)
-> (QualifiedMoveSequence -> TranspositionValue QualifiedMove)
-> QualifiedMoveSequence
-> Transformation QualifiedMove positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool
-> NPositions
-> QualifiedMoveSequence
-> TranspositionValue QualifiedMove
forall qualifiedMove.
Bool
-> NPositions
-> [qualifiedMove]
-> TranspositionValue qualifiedMove
Search.TranspositionValue.mkTranspositionValue Bool
isOptimal NPositions
nPlies (QualifiedMoveSequence -> Transformation positionHash)
-> QualifiedMoveSequence -> Transformation positionHash
forall a b. (a -> b) -> a -> b
$ (Turn -> QualifiedMove) -> [Turn] -> QualifiedMoveSequence
forall a b. (a -> b) -> [a] -> [b]
map Turn -> QualifiedMove
Component.Turn.getQualifiedMove [Turn]
turns
negaMax
:: Ord positionHash
=> Type.Count.NPlies
-> Search.SearchState.SearchState positionHash
-> Input.SearchOptions.Reader (Result positionHash)
{-# SPECIALISE negaMax :: Type.Count.NPlies -> Search.SearchState.SearchState Type.Crypto.PositionHash -> Input.SearchOptions.Reader (Result Type.Crypto.PositionHash) #-}
negaMax :: NPositions
-> SearchState positionHash -> Reader (Result positionHash)
negaMax NPositions
initialSearchDepth SearchState positionHash
initialSearchState = do
Maybe NPositions
maybeMinimumTranspositionSearchDepth <- (SearchOptions -> Maybe NPositions)
-> ReaderT SearchOptions Identity (Maybe NPositions)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
Control.Monad.Reader.asks SearchOptions -> Maybe NPositions
Input.SearchOptions.maybeMinimumTranspositionSearchDepth
Bool
recordKillerMoves <- (SearchOptions -> Bool) -> ReaderT SearchOptions Identity Bool
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
Control.Monad.Reader.asks SearchOptions -> Bool
Input.SearchOptions.recordKillerMoves
Bool
trapRepeatedPositions <- (SearchOptions -> Bool) -> ReaderT SearchOptions Identity Bool
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
Control.Monad.Reader.asks SearchOptions -> Bool
Input.SearchOptions.getTrapRepeatedPositions
let
getNPlies :: Game -> NPositions
getNPlies = TurnsByLogicalColour Turn -> NPositions
forall turn. TurnsByLogicalColour turn -> NPositions
State.TurnsByLogicalColour.getNPlies (TurnsByLogicalColour Turn -> NPositions)
-> (Game -> TurnsByLogicalColour Turn) -> Game -> NPositions
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Game -> TurnsByLogicalColour Turn
Model.Game.getTurnsByLogicalColour
descend :: Ord positionHash => Evaluation.QuantifiedGame.OpenInterval -> Type.Count.NPlies -> Search.SearchState.SearchState positionHash -> Result positionHash
descend :: OpenInterval
-> NPositions -> SearchState positionHash -> Result positionHash
descend (Maybe QuantifiedGame
maybeAlphaQuantifiedGame, Maybe QuantifiedGame
maybeBetaQuantifiedGame) NPositions
searchDepth SearchState positionHash
searchState
| NPositions
searchDepth NPositions -> NPositions -> Bool
forall a. Eq a => a -> a -> Bool
== NPositions
0 Bool -> Bool -> Bool
|| Game -> Bool
Model.Game.isTerminated Game
game = MkResult :: forall positionHash.
DynamicMoveData positionHash
-> QuantifiedGame -> NPositions -> Result positionHash
MkResult {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData,
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = QuantifiedGame -> QuantifiedGame
Evaluation.QuantifiedGame.negateFitness QuantifiedGame
quantifiedGame,
getNPositionsEvaluated :: NPositions
getNPositionsEvaluated = NPositions
1
}
| Bool
useTranspositions
, Just TranspositionValue QualifiedMove
transpositionValue <- positionHash
-> Transpositions QualifiedMove positionHash
-> Maybe (TranspositionValue QualifiedMove)
forall positionHash qualifiedMove.
Ord positionHash =>
positionHash
-> Transpositions qualifiedMove positionHash
-> Maybe (TranspositionValue qualifiedMove)
Search.Transpositions.find positionHash
positionHash (Transpositions QualifiedMove positionHash
-> Maybe (TranspositionValue QualifiedMove))
-> Transpositions QualifiedMove positionHash
-> Maybe (TranspositionValue QualifiedMove)
forall a b. (a -> b) -> a -> b
$ DynamicMoveData positionHash
-> Transpositions QualifiedMove positionHash
forall positionHash.
DynamicMoveData positionHash
-> Transpositions QualifiedMove positionHash
Search.DynamicMoveData.getTranspositions DynamicMoveData positionHash
dynamicMoveData
, let
selectMaxUsingTranspositions :: Result positionHash
selectMaxUsingTranspositions = (Forest positionHash -> Forest positionHash) -> Result positionHash
selectMaxWithSorter ((Forest positionHash -> Forest positionHash)
-> Result positionHash)
-> (Forest positionHash -> Forest positionHash)
-> Result positionHash
forall a b. (a -> b) -> a -> b
$ Forest positionHash
-> Maybe (Forest positionHash) -> Forest positionHash
forall a. a -> Maybe a -> a
Data.Maybe.fromMaybe (
Exception -> Forest positionHash
forall a e. Exception e => e -> a
Control.Exception.throw (Exception -> Forest positionHash)
-> (String -> Exception) -> String -> Forest positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Exception
Data.Exception.mkSearchFailure (String -> Exception) -> (String -> String) -> String -> Exception
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
showString String
"BishBosh.Search.AlphaBeta.negaMax.descend:\tEvaluation.PositionHashQuantifiedGameTree.promoteMatchingMoveSequence failed; " (String -> Forest positionHash) -> String -> Forest positionHash
forall a b. (a -> b) -> a -> b
$ TranspositionValue QualifiedMove -> String -> String
forall a. Show a => a -> String -> String
shows TranspositionValue QualifiedMove
transpositionValue String
"."
) (Maybe (Forest positionHash) -> Forest positionHash)
-> (Forest positionHash -> Maybe (Forest positionHash))
-> Forest positionHash
-> Forest positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QualifiedMoveSequence
-> Forest positionHash -> Maybe (Forest positionHash)
forall positionHash.
QualifiedMoveSequence
-> Forest positionHash -> Maybe (Forest positionHash)
Evaluation.PositionHashQuantifiedGameTree.promoteMatchingMoveSequence (
TranspositionValue QualifiedMove -> QualifiedMoveSequence
forall qualifiedMove.
TranspositionValue qualifiedMove -> [qualifiedMove]
Search.TranspositionValue.getQualifiedMoves TranspositionValue QualifiedMove
transpositionValue
)
= if TranspositionValue QualifiedMove -> NPositions
forall qualifiedMove.
TranspositionValue qualifiedMove -> NPositions
Search.TranspositionValue.inferSearchDepth TranspositionValue QualifiedMove
transpositionValue NPositions -> NPositions -> Bool
forall a. Ord a => a -> a -> Bool
< NPositions
searchDepth
then Result positionHash
selectMaxUsingTranspositions
else let
transposedQuantifiedGame :: QuantifiedGame
transposedQuantifiedGame = PositionHashQuantifiedGameTree positionHash
-> TranspositionValue QualifiedMove -> QuantifiedGame
forall positionHash.
PositionHashQuantifiedGameTree positionHash
-> TranspositionValue QualifiedMove -> QuantifiedGame
findTranspositionTerminalQuantifiedGame PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree TranspositionValue QualifiedMove
transpositionValue
in if TranspositionValue QualifiedMove -> Bool
forall qualifiedMove. TranspositionValue qualifiedMove -> Bool
Search.TranspositionValue.getIsOptimal TranspositionValue QualifiedMove
transpositionValue
then MkResult :: forall positionHash.
DynamicMoveData positionHash
-> QuantifiedGame -> NPositions -> Result positionHash
MkResult {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData,
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = Bool -> QuantifiedGame -> QuantifiedGame
forall a. (?callStack::CallStack) => Bool -> a -> a
Control.Exception.assert (QuantifiedGame
transposedQuantifiedGame QuantifiedGame -> QuantifiedGame -> Bool
forall a. Eq a => a -> a -> Bool
== Result positionHash -> QuantifiedGame
forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame Result positionHash
selectMaxUsingTranspositions) QuantifiedGame
transposedQuantifiedGame,
getNPositionsEvaluated :: NPositions
getNPositionsEvaluated = NPositions
0
}
else Result positionHash
-> (QuantifiedGame -> Result positionHash)
-> Maybe QuantifiedGame
-> Result positionHash
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe Result positionHash
selectMaxUsingTranspositions (
\QuantifiedGame
betaQuantifiedGame -> if (WeightedMean -> WeightedMean -> Bool)
-> (WeightedMean, WeightedMean) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry WeightedMean -> WeightedMean -> Bool
forall a. Ord a => a -> a -> Bool
(<) ((WeightedMean, WeightedMean) -> Bool)
-> (WeightedMean, WeightedMean) -> Bool
forall a b. (a -> b) -> a -> b
$ (((QuantifiedGame -> WeightedMean) -> QuantifiedGame -> WeightedMean
forall a b. (a -> b) -> a -> b
$ QuantifiedGame
transposedQuantifiedGame) ((QuantifiedGame -> WeightedMean) -> WeightedMean)
-> ((QuantifiedGame -> WeightedMean) -> WeightedMean)
-> (QuantifiedGame -> WeightedMean)
-> (WeightedMean, WeightedMean)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ((QuantifiedGame -> WeightedMean) -> QuantifiedGame -> WeightedMean
forall a b. (a -> b) -> a -> b
$ QuantifiedGame
betaQuantifiedGame)) QuantifiedGame -> WeightedMean
Evaluation.QuantifiedGame.getFitness
then Result positionHash
selectMaxUsingTranspositions
else MkResult :: forall positionHash.
DynamicMoveData positionHash
-> QuantifiedGame -> NPositions -> Result positionHash
MkResult {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData,
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = Bool -> QuantifiedGame -> QuantifiedGame
forall a. (?callStack::CallStack) => Bool -> a -> a
Control.Exception.assert (QuantifiedGame
betaQuantifiedGame QuantifiedGame -> QuantifiedGame -> Bool
forall a. Eq a => a -> a -> Bool
== Result positionHash -> QuantifiedGame
forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame Result positionHash
selectMaxUsingTranspositions) QuantifiedGame
betaQuantifiedGame,
getNPositionsEvaluated :: NPositions
getNPositionsEvaluated = NPositions
0
}
) Maybe QuantifiedGame
maybeBetaQuantifiedGame
| Bool
otherwise = (Forest positionHash -> Forest positionHash) -> Result positionHash
selectMaxWithSorter Forest positionHash -> Forest positionHash
forall a. a -> a
id
where
(PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree, DynamicMoveData positionHash
dynamicMoveData) = SearchState positionHash
-> PositionHashQuantifiedGameTree positionHash
forall positionHash.
SearchState positionHash
-> PositionHashQuantifiedGameTree positionHash
Search.SearchState.getPositionHashQuantifiedGameTree (SearchState positionHash
-> PositionHashQuantifiedGameTree positionHash)
-> (SearchState positionHash -> DynamicMoveData positionHash)
-> SearchState positionHash
-> (PositionHashQuantifiedGameTree positionHash,
DynamicMoveData positionHash)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& SearchState positionHash -> DynamicMoveData positionHash
forall positionHash.
SearchState positionHash -> DynamicMoveData positionHash
Search.SearchState.getDynamicMoveData (SearchState positionHash
-> (PositionHashQuantifiedGameTree positionHash,
DynamicMoveData positionHash))
-> SearchState positionHash
-> (PositionHashQuantifiedGameTree positionHash,
DynamicMoveData positionHash)
forall a b. (a -> b) -> a -> b
$ SearchState positionHash
searchState
useTranspositions :: Bool
useTranspositions = Bool -> (NPositions -> Bool) -> Maybe NPositions -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe Bool
False (NPositions
searchDepth NPositions -> NPositions -> Bool
forall a. Ord a => a -> a -> Bool
>=) Maybe NPositions
maybeMinimumTranspositionSearchDepth
(positionHash
positionHash, QuantifiedGame
quantifiedGame) = PositionHashQuantifiedGameTree positionHash -> positionHash
forall positionHash.
PositionHashQuantifiedGameTree positionHash -> positionHash
Evaluation.PositionHashQuantifiedGameTree.getRootPositionHash (PositionHashQuantifiedGameTree positionHash -> positionHash)
-> (PositionHashQuantifiedGameTree positionHash -> QuantifiedGame)
-> PositionHashQuantifiedGameTree positionHash
-> (positionHash, QuantifiedGame)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& PositionHashQuantifiedGameTree positionHash -> QuantifiedGame
forall positionHash.
PositionHashQuantifiedGameTree positionHash -> QuantifiedGame
Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame (PositionHashQuantifiedGameTree positionHash
-> (positionHash, QuantifiedGame))
-> PositionHashQuantifiedGameTree positionHash
-> (positionHash, QuantifiedGame)
forall a b. (a -> b) -> a -> b
$ PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
game :: Game
game = QuantifiedGame -> Game
Evaluation.QuantifiedGame.getGame QuantifiedGame
quantifiedGame
(NPositions
nPlies, NPositions
nDistinctPositions) = Game -> NPositions
getNPlies (Game -> NPositions)
-> (Game -> NPositions) -> Game -> (NPositions, NPositions)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& InstancesByPosition Position -> NPositions
forall position. InstancesByPosition position -> NPositions
State.InstancesByPosition.getNDistinctPositions (InstancesByPosition Position -> NPositions)
-> (Game -> InstancesByPosition Position) -> Game -> NPositions
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Game -> InstancesByPosition Position
Model.Game.getInstancesByPosition (Game -> (NPositions, NPositions))
-> Game -> (NPositions, NPositions)
forall a b. (a -> b) -> a -> b
$ Game
game
selectMaxWithSorter :: (Forest positionHash -> Forest positionHash) -> Result positionHash
selectMaxWithSorter Forest positionHash -> Forest positionHash
forestSorter = DynamicMoveData positionHash
-> Maybe QuantifiedGame
-> Forest positionHash
-> Result positionHash
selectMax DynamicMoveData positionHash
dynamicMoveData Maybe QuantifiedGame
maybeAlphaQuantifiedGame (Forest positionHash -> Result positionHash)
-> (Tree (NodeLabel positionHash) -> Forest positionHash)
-> Tree (NodeLabel positionHash)
-> Result positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Forest positionHash -> Forest positionHash
forestSorter (Forest positionHash -> Forest positionHash)
-> (Tree (NodeLabel positionHash) -> Forest positionHash)
-> Tree (NodeLabel positionHash)
-> Forest positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
if Bool
recordKillerMoves
then (Forest positionHash -> Forest positionHash)
-> Forest positionHash -> Forest positionHash
forall positionHash.
(Forest positionHash -> Forest positionHash)
-> Forest positionHash -> Forest positionHash
Evaluation.PositionHashQuantifiedGameTree.sortNonCaptureMoves (
LogicalColour
-> (Tree (NodeLabel positionHash) -> KillerMoveKey)
-> KillerMoves KillerMoveKey
-> Forest positionHash
-> Forest positionHash
forall killerMoveKey a.
Ord killerMoveKey =>
LogicalColour
-> (a -> killerMoveKey) -> KillerMoves killerMoveKey -> [a] -> [a]
Search.KillerMoves.sortByHistoryHeuristic (
Game -> LogicalColour
Model.Game.getNextLogicalColour Game
game
) (
Turn -> KillerMoveKey
Search.DynamicMoveData.mkKillerMoveKeyFromTurn (Turn -> KillerMoveKey)
-> (Tree (NodeLabel positionHash) -> Turn)
-> Tree (NodeLabel positionHash)
-> KillerMoveKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QuantifiedGame -> Turn
Evaluation.QuantifiedGame.getLastTurn (QuantifiedGame -> Turn)
-> (Tree (NodeLabel positionHash) -> QuantifiedGame)
-> Tree (NodeLabel positionHash)
-> Turn
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree (NodeLabel positionHash) -> QuantifiedGame
forall positionHash.
BarePositionHashQuantifiedGameTree positionHash -> QuantifiedGame
Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame'
) (KillerMoves KillerMoveKey
-> Forest positionHash -> Forest positionHash)
-> KillerMoves KillerMoveKey
-> Forest positionHash
-> Forest positionHash
forall a b. (a -> b) -> a -> b
$ DynamicMoveData positionHash -> KillerMoves KillerMoveKey
forall positionHash.
DynamicMoveData positionHash -> KillerMoves KillerMoveKey
Search.DynamicMoveData.getKillerMoves DynamicMoveData positionHash
dynamicMoveData
)
else Forest positionHash -> Forest positionHash
forall a. a -> a
id
) (Forest positionHash -> Forest positionHash)
-> (Tree (NodeLabel positionHash) -> Forest positionHash)
-> Tree (NodeLabel positionHash)
-> Forest positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Tree (NodeLabel positionHash) -> Forest positionHash
forall a. Tree a -> Forest a
Data.Tree.subForest (Tree (NodeLabel positionHash) -> Result positionHash)
-> Tree (NodeLabel positionHash) -> Result positionHash
forall a b. (a -> b) -> a -> b
$ PositionHashQuantifiedGameTree positionHash
-> Tree (NodeLabel positionHash)
forall positionHash.
PositionHashQuantifiedGameTree positionHash
-> BarePositionHashQuantifiedGameTree positionHash
Evaluation.PositionHashQuantifiedGameTree.deconstruct PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
selectMax :: DynamicMoveData positionHash
-> Maybe QuantifiedGame
-> Forest positionHash
-> Result positionHash
selectMax DynamicMoveData positionHash
dynamicMoveData' Maybe QuantifiedGame
maybeAlphaQuantifiedGame' (Tree (NodeLabel positionHash)
node : Forest positionHash
remainingNodes)
| Bool
trapRepeatedPositions
, NPositions
nDistinctPositions NPositions -> NPositions -> Bool
forall a. Ord a => a -> a -> Bool
>= NPositions -> NPositions
forall a b. (Integral a, Num b) => a -> b
fromIntegral NPositions
State.InstancesByPosition.leastCyclicPlies
, InstancesByPosition Position -> NPositions
forall position. InstancesByPosition position -> NPositions
State.InstancesByPosition.getNDistinctPositions (
Game -> InstancesByPosition Position
Model.Game.getInstancesByPosition (Game -> InstancesByPosition Position)
-> (QuantifiedGame -> Game)
-> QuantifiedGame
-> InstancesByPosition Position
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QuantifiedGame -> Game
Evaluation.QuantifiedGame.getGame (QuantifiedGame -> InstancesByPosition Position)
-> QuantifiedGame -> InstancesByPosition Position
forall a b. (a -> b) -> a -> b
$ Tree (NodeLabel positionHash) -> QuantifiedGame
forall positionHash.
BarePositionHashQuantifiedGameTree positionHash -> QuantifiedGame
Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame' Tree (NodeLabel positionHash)
node
) NPositions -> NPositions -> Bool
forall a. Eq a => a -> a -> Bool
== NPositions
nDistinctPositions = DynamicMoveData positionHash
-> Maybe QuantifiedGame
-> Forest positionHash
-> Result positionHash
selectMax DynamicMoveData positionHash
dynamicMoveData' (
Maybe QuantifiedGame
maybeAlphaQuantifiedGame' Maybe QuantifiedGame
-> Maybe QuantifiedGame -> Maybe QuantifiedGame
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> QuantifiedGame -> Maybe QuantifiedGame
forall a. a -> Maybe a
Just QuantifiedGame
quantifiedGame''
) Forest positionHash
remainingNodes
| Just QuantifiedGame
betaQuantifiedGame <- Maybe QuantifiedGame
maybeBetaQuantifiedGame
, let fitnessComparedWithBeta :: Ordering
fitnessComparedWithBeta = QuantifiedGame
quantifiedGame'' QuantifiedGame -> QuantifiedGame -> Ordering
<=> QuantifiedGame
betaQuantifiedGame
, Ordering
fitnessComparedWithBeta Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
/= Ordering
LT = Result positionHash
result'' {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = (
if Bool
recordKillerMoves Bool -> Bool -> Bool
&& Bool -> Bool
not (
Ordering
fitnessComparedWithBeta Ordering -> Ordering -> Bool
forall a. Eq a => a -> a -> Bool
== Ordering
EQ Bool -> Bool -> Bool
&& QuantifiedGame
quantifiedGame'' QuantifiedGame -> QuantifiedGame -> Bool
=== QuantifiedGame
betaQuantifiedGame
)
then Game -> Transformation positionHash
forall positionHash. Game -> Transformation positionHash
updateKillerMoves (Game -> Transformation positionHash)
-> Game -> Transformation positionHash
forall a b. (a -> b) -> a -> b
$ QuantifiedGame -> Game
Evaluation.QuantifiedGame.getGame QuantifiedGame
quantifiedGame''
else Transformation positionHash
forall a. a -> a
id
) DynamicMoveData positionHash
dynamicMoveData'',
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = QuantifiedGame
betaQuantifiedGame
}
| Bool
otherwise = let
isFitter :: Bool
isFitter = Bool -> (QuantifiedGame -> Bool) -> Maybe QuantifiedGame -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
Data.Maybe.maybe Bool
True (
\QuantifiedGame
alphaQuantifiedGame -> (WeightedMean -> WeightedMean -> Bool)
-> (WeightedMean, WeightedMean) -> Bool
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry WeightedMean -> WeightedMean -> Bool
forall a. Ord a => a -> a -> Bool
(>) ((WeightedMean, WeightedMean) -> Bool)
-> (WeightedMean, WeightedMean) -> Bool
forall a b. (a -> b) -> a -> b
$ (((QuantifiedGame -> WeightedMean) -> QuantifiedGame -> WeightedMean
forall a b. (a -> b) -> a -> b
$ QuantifiedGame
quantifiedGame'') ((QuantifiedGame -> WeightedMean) -> WeightedMean)
-> ((QuantifiedGame -> WeightedMean) -> WeightedMean)
-> (QuantifiedGame -> WeightedMean)
-> (WeightedMean, WeightedMean)
forall (a :: * -> * -> *) b c c'.
Arrow a =>
a b c -> a b c' -> a b (c, c')
&&& ((QuantifiedGame -> WeightedMean) -> QuantifiedGame -> WeightedMean
forall a b. (a -> b) -> a -> b
$ QuantifiedGame
alphaQuantifiedGame)) QuantifiedGame -> WeightedMean
Evaluation.QuantifiedGame.getFitness
) Maybe QuantifiedGame
maybeAlphaQuantifiedGame'
in NPositions -> Transformation positionHash
forall positionHash. NPositions -> Transformation positionHash
addNPositionsToResult (
Result positionHash -> NPositions
forall positionHash. Result positionHash -> NPositions
getNPositionsEvaluated Result positionHash
result''
) Transformation positionHash -> Transformation positionHash
forall a b. (a -> b) -> a -> b
$ DynamicMoveData positionHash
-> Maybe QuantifiedGame
-> Forest positionHash
-> Result positionHash
selectMax (
(
if Bool
useTranspositions Bool -> Bool -> Bool
&& Bool
isFitter
then Bool
-> NPositions
-> positionHash
-> [Turn]
-> PositionHashQuantifiedGameTree positionHash
-> Transformation positionHash
forall positionHash.
Ord positionHash =>
Bool
-> NPositions
-> positionHash
-> [Turn]
-> PositionHashQuantifiedGameTree positionHash
-> Transformation positionHash
updateTranspositions Bool
False NPositions
nPlies positionHash
positionHash (
NPositions -> QuantifiedGame -> [Turn]
Evaluation.QuantifiedGame.getLatestTurns NPositions
nPlies QuantifiedGame
quantifiedGame''
) PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
else Transformation positionHash
forall a. a -> a
id
) DynamicMoveData positionHash
dynamicMoveData''
) (
if Bool
isFitter
then QuantifiedGame -> Maybe QuantifiedGame
forall a. a -> Maybe a
Just QuantifiedGame
quantifiedGame''
else Maybe QuantifiedGame
maybeAlphaQuantifiedGame'
) Forest positionHash
remainingNodes
where
result'' :: Result positionHash
result''@MkResult {
getDynamicMoveData :: forall positionHash.
Result positionHash -> DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData'',
getQuantifiedGame :: forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame = QuantifiedGame
quantifiedGame''
} = Transformation positionHash
forall positionHash. Transformation positionHash
negateFitnessOfResult Transformation positionHash
-> (SearchState positionHash -> Result positionHash)
-> SearchState positionHash
-> Result positionHash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OpenInterval
-> NPositions -> SearchState positionHash -> Result positionHash
forall positionHash.
Ord positionHash =>
OpenInterval
-> NPositions -> SearchState positionHash -> Result positionHash
descend (
(OpenInterval -> OpenInterval)
-> Maybe QuantifiedGame -> Maybe QuantifiedGame -> OpenInterval
forall a b c. ((a, b) -> c) -> a -> b -> c
curry OpenInterval -> OpenInterval
Evaluation.QuantifiedGame.negateInterval Maybe QuantifiedGame
maybeAlphaQuantifiedGame' Maybe QuantifiedGame
maybeBetaQuantifiedGame
) (
NPositions -> NPositions
forall a. Enum a => a -> a
pred NPositions
searchDepth
) (SearchState positionHash -> Result positionHash)
-> SearchState positionHash -> Result positionHash
forall a b. (a -> b) -> a -> b
$ PositionHashQuantifiedGameTree positionHash
-> DynamicMoveData positionHash -> SearchState positionHash
forall positionHash.
PositionHashQuantifiedGameTree positionHash
-> DynamicMoveData positionHash -> SearchState positionHash
Search.SearchState.mkSearchState (
Tree (NodeLabel positionHash)
-> PositionHashQuantifiedGameTree positionHash
forall positionHash.
BarePositionHashQuantifiedGameTree positionHash
-> PositionHashQuantifiedGameTree positionHash
Evaluation.PositionHashQuantifiedGameTree.fromBarePositionHashQuantifiedGameTree Tree (NodeLabel positionHash)
node
) DynamicMoveData positionHash
dynamicMoveData'
selectMax DynamicMoveData positionHash
dynamicMoveData' Maybe QuantifiedGame
maybeAlphaQuantifiedGame' [] = MkResult :: forall positionHash.
DynamicMoveData positionHash
-> QuantifiedGame -> NPositions -> Result positionHash
MkResult {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData',
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = QuantifiedGame -> Maybe QuantifiedGame -> QuantifiedGame
forall a. a -> Maybe a -> a
Data.Maybe.fromMaybe (
QuantifiedGame -> Maybe QuantifiedGame -> QuantifiedGame
forall a. a -> Maybe a -> a
Data.Maybe.fromMaybe (
Exception -> QuantifiedGame
forall a e. Exception e => e -> a
Control.Exception.throw (Exception -> QuantifiedGame)
-> (String -> Exception) -> String -> QuantifiedGame
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Exception
Data.Exception.mkResultUndefined (String -> Exception) -> (String -> String) -> String -> Exception
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String -> String
showString String
"BishBosh.Search.AlphaBeta.negaMax.descend.selectMax:\tthere are zero nodes to process, but neither alpha nor beta is defined; " (String -> QuantifiedGame) -> String -> QuantifiedGame
forall a b. (a -> b) -> a -> b
$ Game -> String -> String
forall a. Show a => a -> String -> String
shows Game
game String
"."
) Maybe QuantifiedGame
maybeBetaQuantifiedGame
) Maybe QuantifiedGame
maybeAlphaQuantifiedGame',
getNPositionsEvaluated :: NPositions
getNPositionsEvaluated = NPositions
0
}
Result positionHash -> Reader (Result positionHash)
forall (m :: * -> *) a. Monad m => a -> m a
return (Result positionHash -> Reader (Result positionHash))
-> (Result positionHash -> Result positionHash)
-> Result positionHash
-> Reader (Result positionHash)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (
\result :: Result positionHash
result@MkResult {
getDynamicMoveData :: forall positionHash.
Result positionHash -> DynamicMoveData positionHash
getDynamicMoveData = DynamicMoveData positionHash
dynamicMoveData,
getQuantifiedGame :: forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame = QuantifiedGame
quantifiedGame
} -> let
positionHashQuantifiedGameTree :: PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree = SearchState positionHash
-> PositionHashQuantifiedGameTree positionHash
forall positionHash.
SearchState positionHash
-> PositionHashQuantifiedGameTree positionHash
Search.SearchState.getPositionHashQuantifiedGameTree SearchState positionHash
initialSearchState
nPlies :: NPositions
nPlies = Game -> NPositions
getNPlies (Game -> NPositions)
-> (QuantifiedGame -> Game) -> QuantifiedGame -> NPositions
forall b c a. (b -> c) -> (a -> b) -> a -> c
. QuantifiedGame -> Game
Evaluation.QuantifiedGame.getGame (QuantifiedGame -> NPositions) -> QuantifiedGame -> NPositions
forall a b. (a -> b) -> a -> b
$ PositionHashQuantifiedGameTree positionHash -> QuantifiedGame
forall positionHash.
PositionHashQuantifiedGameTree positionHash -> QuantifiedGame
Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
in Result positionHash
result {
getDynamicMoveData :: DynamicMoveData positionHash
getDynamicMoveData = Bool
-> NPositions
-> positionHash
-> [Turn]
-> PositionHashQuantifiedGameTree positionHash
-> Transformation positionHash
forall positionHash.
Ord positionHash =>
Bool
-> NPositions
-> positionHash
-> [Turn]
-> PositionHashQuantifiedGameTree positionHash
-> Transformation positionHash
updateTranspositions Bool
True NPositions
nPlies (
PositionHashQuantifiedGameTree positionHash -> positionHash
forall positionHash.
PositionHashQuantifiedGameTree positionHash -> positionHash
Evaluation.PositionHashQuantifiedGameTree.getRootPositionHash PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree
) (
NPositions -> QuantifiedGame -> [Turn]
Evaluation.QuantifiedGame.getLatestTurns NPositions
nPlies QuantifiedGame
quantifiedGame
) PositionHashQuantifiedGameTree positionHash
positionHashQuantifiedGameTree DynamicMoveData positionHash
dynamicMoveData
}
) (Result positionHash -> Reader (Result positionHash))
-> Result positionHash -> Reader (Result positionHash)
forall a b. (a -> b) -> a -> b
$ OpenInterval
-> NPositions -> SearchState positionHash -> Result positionHash
forall positionHash.
Ord positionHash =>
OpenInterval
-> NPositions -> SearchState positionHash -> Result positionHash
descend OpenInterval
Evaluation.QuantifiedGame.unboundedInterval NPositions
initialSearchDepth SearchState positionHash
initialSearchState
type Transformation positionHash = Result positionHash -> Result positionHash
negateFitnessOfResult :: Transformation positionHash
negateFitnessOfResult :: Transformation positionHash
negateFitnessOfResult result :: Result positionHash
result@MkResult { getQuantifiedGame :: forall positionHash. Result positionHash -> QuantifiedGame
getQuantifiedGame = QuantifiedGame
quantifiedGame } = Result positionHash
result {
getQuantifiedGame :: QuantifiedGame
getQuantifiedGame = QuantifiedGame -> QuantifiedGame
Evaluation.QuantifiedGame.negateFitness QuantifiedGame
quantifiedGame
}
addNPositionsToResult :: Type.Count.NPositions -> Transformation positionHash
addNPositionsToResult :: NPositions -> Transformation positionHash
addNPositionsToResult NPositions
nPositions result :: Result positionHash
result@MkResult { getNPositionsEvaluated :: forall positionHash. Result positionHash -> NPositions
getNPositionsEvaluated = NPositions
nPositionsEvaluated } = Bool -> Transformation positionHash
forall a. (?callStack::CallStack) => Bool -> a -> a
Control.Exception.assert (NPositions
nPositions NPositions -> NPositions -> Bool
forall a. Ord a => a -> a -> Bool
> NPositions
0) Result positionHash
result {
getNPositionsEvaluated :: NPositions
getNPositionsEvaluated = NPositions
nPositions NPositions -> NPositions -> NPositions
forall a. Num a => a -> a -> a
+ NPositions
nPositionsEvaluated
}