module BishBosh.State.InstancesByPosition(
leastCyclicPlies,
InstancesByPosition(),
countConsecutiveRepeatablePlies,
countPositionRepetitions,
getNDistinctPositions,
mkInstancesByPosition,
mkSingleton,
insertPosition,
deletePosition,
anyInstancesByPosition
) where
import qualified BishBosh.Component.Move as Component.Move
import qualified BishBosh.Data.Exception as Data.Exception
import qualified BishBosh.Property.Reflectable as Property.Reflectable
import qualified BishBosh.State.Board as State.Board
import qualified Control.DeepSeq
import qualified Control.Exception
import qualified Data.Foldable
import qualified Data.Map
import qualified Data.Map.Strict
leastCyclicPlies :: Component.Move.NMoves
leastCyclicPlies = 4
type NBoardsByPosition position = Data.Map.Map position State.Board.NBoards
newtype InstancesByPosition position = MkInstancesByPosition {
getNBoardsByPosition :: NBoardsByPosition position
} deriving Eq
instance Control.DeepSeq.NFData position => Control.DeepSeq.NFData (InstancesByPosition position) where
rnf MkInstancesByPosition { getNBoardsByPosition = m } = Control.DeepSeq.rnf m
instance (
Ord position,
Property.Reflectable.ReflectableOnX position
) => Property.Reflectable.ReflectableOnX (InstancesByPosition position) where
reflectOnX MkInstancesByPosition { getNBoardsByPosition = m } = MkInstancesByPosition $ Data.Map.mapKeys Property.Reflectable.reflectOnX m
mkInstancesByPosition :: NBoardsByPosition position -> InstancesByPosition position
mkInstancesByPosition nBoardsByPosition
| Data.Foldable.any (< 1) nBoardsByPosition = Control.Exception.throw $ Data.Exception.mkOutOfBounds "BishBosh.State.InstancesByPosition.mkInstancesByPosition:\teach specified position must have been visited at least once."
| otherwise = MkInstancesByPosition nBoardsByPosition
mkSingleton :: position -> InstancesByPosition position
mkSingleton position = MkInstancesByPosition $ Data.Map.singleton position 1
countConsecutiveRepeatablePlies :: InstancesByPosition position -> Component.Move.NMoves
countConsecutiveRepeatablePlies MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.foldl' (+) (
negate 1
) m
countPositionRepetitions :: InstancesByPosition position -> State.Board.NBoards
countPositionRepetitions MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.foldl' (
(+) . pred
) 0 m
getNDistinctPositions :: InstancesByPosition position -> State.Board.NBoards
getNDistinctPositions MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.size m
anyInstancesByPosition
:: (State.Board.NBoards -> Bool)
-> InstancesByPosition position
-> Bool
anyInstancesByPosition predicate MkInstancesByPosition { getNBoardsByPosition = m } = Data.Foldable.any predicate m
type Transformation position = InstancesByPosition position -> InstancesByPosition position
insertPosition
:: Ord position
=> Bool
-> position
-> Transformation position
insertPosition isRepeatable position MkInstancesByPosition { getNBoardsByPosition = m } = MkInstancesByPosition $ if isRepeatable
then Data.Map.Strict.insertWith (const succ) position 1 m
else Data.Map.singleton position 1
deletePosition :: Ord position => position -> Transformation position
deletePosition position MkInstancesByPosition { getNBoardsByPosition = m } = Control.Exception.assert (Data.Map.member position m) . MkInstancesByPosition $ Data.Map.update (
\n -> if n == 1
then Nothing
else Just $ pred n
) position m