bishbosh 0.1.2.0 → 0.1.3.0
raw patch · 135 files changed
+3890/−3256 lines, 135 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- BishBosh.Attribute.ANSIColourCode: bracket :: GraphicsRendition -> String -> ShowS
- BishBosh.Attribute.ANSIColourCode: instance Data.Default.Class.Default BishBosh.Attribute.ANSIColourCode.ANSIColourCode
- BishBosh.Attribute.ANSIColourCode: instance GHC.Show.Show BishBosh.Attribute.ANSIColourCode.ANSIColourCode
- BishBosh.Attribute.ANSIColourCode: mkBgColourCode :: PhysicalColour -> ANSIColourCode
- BishBosh.Attribute.ANSIColourCode: mkFgColourCode :: PhysicalColour -> ANSIColourCode
- BishBosh.Attribute.ANSIColourCode: selectGraphicsRendition :: IsBold -> ANSIColourCode -> GraphicsRendition
- BishBosh.Attribute.ANSIColourCode: type GraphicsRendition = String
- BishBosh.Attribute.ColourScheme: data ColourScheme
- BishBosh.Attribute.ColourScheme: instance Control.DeepSeq.NFData BishBosh.Attribute.ColourScheme.ColourScheme
- BishBosh.Attribute.ColourScheme: instance Data.Default.Class.Default BishBosh.Attribute.ColourScheme.ColourScheme
- BishBosh.Attribute.ColourScheme: instance GHC.Classes.Eq BishBosh.Attribute.ColourScheme.ColourScheme
- BishBosh.Attribute.ColourScheme: instance GHC.Show.Show BishBosh.Attribute.ColourScheme.ColourScheme
- BishBosh.Attribute.ColourScheme: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Attribute.ColourScheme.ColourScheme
- BishBosh.Attribute.ColourScheme: tag :: String
- BishBosh.Attribute.Direction: advanceDirection :: LogicalColour -> Ordering
- BishBosh.Attribute.Direction: areAligned :: Direction -> Direction -> Bool
- BishBosh.Attribute.Direction: attackDirectionsForPawn :: LogicalColour -> [Direction]
- BishBosh.Attribute.Direction: data Direction
- BishBosh.Attribute.Direction: diagonals :: [Direction]
- BishBosh.Attribute.Direction: e :: Direction
- BishBosh.Attribute.Direction: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance BishBosh.Property.Opposable.Opposable BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance BishBosh.Property.Orientated.Orientated BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance Control.DeepSeq.NFData BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Classes.Eq BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Classes.Ord BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Enum.Bounded BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Ix.Ix BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Read.Read BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance GHC.Show.Show BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Attribute.Direction.Direction
- BishBosh.Attribute.Direction: listArrayByDirection :: IArray a e => [e] -> a Direction e
- BishBosh.Attribute.Direction: mkDirection :: Ordering -> Ordering -> Direction
- BishBosh.Attribute.Direction: n :: Direction
- BishBosh.Attribute.Direction: nDistinctDirections :: NDirections
- BishBosh.Attribute.Direction: ne :: Direction
- BishBosh.Attribute.Direction: nw :: Direction
- BishBosh.Attribute.Direction: opposites :: [(Direction, Direction)]
- BishBosh.Attribute.Direction: parallels :: [Direction]
- BishBosh.Attribute.Direction: s :: Direction
- BishBosh.Attribute.Direction: se :: Direction
- BishBosh.Attribute.Direction: sw :: Direction
- BishBosh.Attribute.Direction: tag :: String
- BishBosh.Attribute.Direction: type ArrayByDirection = Array Direction
- BishBosh.Attribute.Direction: w :: Direction
- BishBosh.Attribute.LogicalColour: Black :: LogicalColour
- BishBosh.Attribute.LogicalColour: White :: LogicalColour
- BishBosh.Attribute.LogicalColour: arrayByLogicalColour :: IArray a e => [(LogicalColour, e)] -> a LogicalColour e
- BishBosh.Attribute.LogicalColour: data LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance BishBosh.Property.Opposable.Opposable BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance Control.DeepSeq.NFData BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Classes.Eq BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Classes.Ord BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Enum.Bounded BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Enum.Enum BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Ix.Ix BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Read.Read BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance GHC.Show.Show BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Attribute.LogicalColour.LogicalColour
- BishBosh.Attribute.LogicalColour: isBlack :: LogicalColour -> Bool
- BishBosh.Attribute.LogicalColour: listArrayByLogicalColour :: IArray a e => [e] -> a LogicalColour e
- BishBosh.Attribute.LogicalColour: nDistinctLogicalColours :: NLogicalColours
- BishBosh.Attribute.LogicalColour: range :: [LogicalColour]
- BishBosh.Attribute.LogicalColour: tag :: String
- BishBosh.Attribute.LogicalColour: type ArrayByLogicalColour = Array LogicalColour
- BishBosh.Attribute.LogicalColour: type UArrayByLogicalColour = UArray LogicalColour
- BishBosh.Attribute.LogicalColourOfSquare: black :: LogicalColourOfSquare
- BishBosh.Attribute.LogicalColourOfSquare: data LogicalColourOfSquare
- BishBosh.Attribute.LogicalColourOfSquare: instance GHC.Classes.Eq BishBosh.Attribute.LogicalColourOfSquare.LogicalColourOfSquare
- BishBosh.Attribute.LogicalColourOfSquare: instance GHC.Enum.Bounded BishBosh.Attribute.LogicalColourOfSquare.LogicalColourOfSquare
- BishBosh.Attribute.LogicalColourOfSquare: isBlack :: LogicalColourOfSquare -> Bool
- BishBosh.Attribute.LogicalColourOfSquare: white :: LogicalColourOfSquare
- BishBosh.Attribute.PhysicalColour: black :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: blue :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: cyan :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: data PhysicalColour
- BishBosh.Attribute.PhysicalColour: green :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance BishBosh.Property.Opposable.Opposable BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance Control.DeepSeq.NFData BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance GHC.Classes.Eq BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance GHC.Enum.Bounded BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance GHC.Enum.Enum BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance GHC.Read.Read BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance GHC.Show.Show BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Attribute.PhysicalColour.PhysicalColour
- BishBosh.Attribute.PhysicalColour: magenta :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: red :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: white :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: yellow :: PhysicalColour
- BishBosh.Attribute.Rank: type UArrayByRank = UArray Rank
- BishBosh.Cartesian.Coordinates: fromIx :: Int -> Coordinates
- BishBosh.Cartesian.Vector: isDiagonal :: Vector -> Bool
- BishBosh.Cartesian.Vector: isParallel :: Vector -> Bool
- BishBosh.Cartesian.Vector: isStraight :: Vector -> Bool
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue)
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance GHC.Classes.Eq pieceSquareValue => GHC.Classes.Eq (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue)
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance GHC.Show.Show pieceSquareValue => GHC.Show.Show (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue)
- BishBosh.Evaluation.Fitness: measurePieceSquareValue :: Num pieceSquareValue => PieceSquareByCoordinatesByRank pieceSquareValue -> Game -> pieceSquareValue
- BishBosh.Evaluation.Fitness: measurePieceSquareValueIncrementally :: Num pieceSquareValue => pieceSquareValue -> PieceSquareByCoordinatesByRank pieceSquareValue -> Game -> pieceSquareValue
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoves :: [QualifiedMove] -> Forest positionHash -> Maybe (Forest positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoves :: PositionHashQuantifiedGameTree positionHash -> [QualifiedMove] -> Maybe [NodeLabel positionHash]
- BishBosh.Evaluation.QuantifiedGame: compareFitness :: QuantifiedGame -> QuantifiedGame -> Ordering
- BishBosh.Input.EvaluationOptions: instance (GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.EvaluationOptions: instance (GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.EvaluationOptions: instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.EvaluationOptions: instance Data.Default.Class.Default (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.EvaluationOptions: instance GHC.Classes.Eq pieceSquareValue => GHC.Classes.Eq (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.EvaluationOptions: instance GHC.Show.Show pieceSquareValue => GHC.Show.Show (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue)
- BishBosh.Input.Options: instance (GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.Options: instance (GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.Options: instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.Options: instance Data.Default.Class.Default (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.Options: instance GHC.Classes.Eq pieceSquareValue => GHC.Classes.Eq (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.Options: instance GHC.Show.Show pieceSquareValue => GHC.Show.Show (BishBosh.Input.Options.Options pieceSquareValue)
- BishBosh.Input.PieceSquareTable: inClosedUnitInterval :: (Num pieceSquareValue, Ord pieceSquareValue) => Assocs rank pieceSquareValue -> Bool
- BishBosh.Input.PieceSquareTable: instance (GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.PieceSquareTable.PieceSquareTable pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance (GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.PieceSquareTable.PieceSquareTable pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance Data.Default.Class.Default (BishBosh.Input.PieceSquareTable.PieceSquareTable pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance GHC.Classes.Eq pieceSquareValue => GHC.Classes.Eq (BishBosh.Input.PieceSquareTable.PieceSquareTable pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance GHC.Show.Show pieceSquareValue => GHC.Show.Show (BishBosh.Input.PieceSquareTable.PieceSquareTable pieceSquareValue)
- BishBosh.Property.Arboreal: instance BishBosh.Property.Arboreal.Prunable (Data.Tree.Tree a)
- BishBosh.State.CoordinatesByRankByLogicalColour: fromMaybePieceByCoordinates :: MaybePieceByCoordinates -> CoordinatesByRankByLogicalColour
- BishBosh.State.CoordinatesByRankByLogicalColour: movePiece :: Move -> Piece -> Maybe Rank -> Either Coordinates (Maybe Rank) -> Transformation
- BishBosh.State.MaybePieceByCoordinates: movePiece :: Move -> Piece -> Maybe Coordinates -> Transformation
+ BishBosh.Attribute.MoveType: getMaybePromotedRank :: MoveType -> Maybe Rank
+ BishBosh.Cartesian.Coordinates: applyAlongDirectionsFrom :: ([Coordinates] -> [a]) -> Coordinates -> Maybe [Direction] -> [a]
+ BishBosh.Cartesian.Coordinates: instance BishBosh.Property.Opposable.Opposable BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Enum.Enum BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Colour.ANSIColourCode: bracket :: GraphicsRendition -> String -> ShowS
+ BishBosh.Colour.ANSIColourCode: instance Data.Default.Class.Default BishBosh.Colour.ANSIColourCode.ANSIColourCode
+ BishBosh.Colour.ANSIColourCode: instance GHC.Show.Show BishBosh.Colour.ANSIColourCode.ANSIColourCode
+ BishBosh.Colour.ANSIColourCode: mkBgColourCode :: PhysicalColour -> ANSIColourCode
+ BishBosh.Colour.ANSIColourCode: mkFgColourCode :: PhysicalColour -> ANSIColourCode
+ BishBosh.Colour.ANSIColourCode: selectGraphicsRendition :: IsBold -> ANSIColourCode -> GraphicsRendition
+ BishBosh.Colour.ANSIColourCode: type GraphicsRendition = String
+ BishBosh.Colour.ColourScheme: data ColourScheme
+ BishBosh.Colour.ColourScheme: instance Control.DeepSeq.NFData BishBosh.Colour.ColourScheme.ColourScheme
+ BishBosh.Colour.ColourScheme: instance Data.Default.Class.Default BishBosh.Colour.ColourScheme.ColourScheme
+ BishBosh.Colour.ColourScheme: instance GHC.Classes.Eq BishBosh.Colour.ColourScheme.ColourScheme
+ BishBosh.Colour.ColourScheme: instance GHC.Show.Show BishBosh.Colour.ColourScheme.ColourScheme
+ BishBosh.Colour.ColourScheme: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Colour.ColourScheme.ColourScheme
+ BishBosh.Colour.ColourScheme: tag :: String
+ BishBosh.Colour.LogicalColour: Black :: LogicalColour
+ BishBosh.Colour.LogicalColour: White :: LogicalColour
+ BishBosh.Colour.LogicalColour: arrayByLogicalColour :: IArray a e => [(LogicalColour, e)] -> a LogicalColour e
+ BishBosh.Colour.LogicalColour: data LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance BishBosh.Property.Opposable.Opposable BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance Control.DeepSeq.NFData BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Classes.Eq BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Classes.Ord BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Enum.Bounded BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Enum.Enum BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Ix.Ix BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Read.Read BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance GHC.Show.Show BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Colour.LogicalColour.LogicalColour
+ BishBosh.Colour.LogicalColour: isBlack :: LogicalColour -> Bool
+ BishBosh.Colour.LogicalColour: listArrayByLogicalColour :: IArray a e => [e] -> a LogicalColour e
+ BishBosh.Colour.LogicalColour: nDistinctLogicalColours :: NLogicalColours
+ BishBosh.Colour.LogicalColour: range :: [LogicalColour]
+ BishBosh.Colour.LogicalColour: tag :: String
+ BishBosh.Colour.LogicalColour: type ArrayByLogicalColour = Array LogicalColour
+ BishBosh.Colour.LogicalColourOfSquare: black :: LogicalColourOfSquare
+ BishBosh.Colour.LogicalColourOfSquare: data LogicalColourOfSquare
+ BishBosh.Colour.LogicalColourOfSquare: instance GHC.Classes.Eq BishBosh.Colour.LogicalColourOfSquare.LogicalColourOfSquare
+ BishBosh.Colour.LogicalColourOfSquare: instance GHC.Enum.Bounded BishBosh.Colour.LogicalColourOfSquare.LogicalColourOfSquare
+ BishBosh.Colour.LogicalColourOfSquare: isBlack :: LogicalColourOfSquare -> Bool
+ BishBosh.Colour.LogicalColourOfSquare: white :: LogicalColourOfSquare
+ BishBosh.Colour.PhysicalColour: black :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: blue :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: cyan :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: data PhysicalColour
+ BishBosh.Colour.PhysicalColour: green :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance BishBosh.Property.Opposable.Opposable BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance Control.DeepSeq.NFData BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance GHC.Classes.Eq BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance GHC.Enum.Bounded BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance GHC.Enum.Enum BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance GHC.Read.Read BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance GHC.Show.Show BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Colour.PhysicalColour.PhysicalColour
+ BishBosh.Colour.PhysicalColour: magenta :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: red :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: white :: PhysicalColour
+ BishBosh.Colour.PhysicalColour: yellow :: PhysicalColour
+ BishBosh.Component.Piece: isQueen :: Piece -> Bool
+ BishBosh.Component.PieceSquareByCoordinatesByRank: instance Control.DeepSeq.NFData BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank
+ BishBosh.Component.PieceSquareByCoordinatesByRank: instance GHC.Classes.Eq BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank
+ BishBosh.Component.PieceSquareByCoordinatesByRank: instance GHC.Show.Show BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank
+ BishBosh.Component.QualifiedMove: type QualifiedMoveSequence = [QualifiedMove]
+ BishBosh.Data.RoseTree: prune :: Int -> Transformation a
+ BishBosh.Direction.Diagonal: data Diagonal
+ BishBosh.Direction.Diagonal: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance BishBosh.Property.Opposable.Opposable BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance BishBosh.Property.Orientated.Orientated BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance Control.DeepSeq.NFData BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance GHC.Classes.Eq BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance GHC.Classes.Ord BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance GHC.Enum.Enum BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance GHC.Read.Read BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Diagonal: instance GHC.Show.Show BishBosh.Direction.Diagonal.Diagonal
+ BishBosh.Direction.Direction: areAligned :: Direction -> Direction -> Bool
+ BishBosh.Direction.Direction: attackDirectionsForPawn :: LogicalColour -> [Direction]
+ BishBosh.Direction.Direction: data Direction
+ BishBosh.Direction.Direction: diagonals :: [Direction]
+ BishBosh.Direction.Direction: e :: Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.Opposable.Opposable BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.Orientated.Orientated BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance BishBosh.Property.Rotatable.Rotatable BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance Control.DeepSeq.NFData BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Classes.Eq BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Classes.Ord BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Enum.Bounded BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Ix.Ix BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Read.Read BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: instance GHC.Show.Show BishBosh.Direction.Direction.Direction
+ BishBosh.Direction.Direction: listArrayByDirection :: IArray a e => [e] -> a Direction e
+ BishBosh.Direction.Direction: n :: Direction
+ BishBosh.Direction.Direction: ne :: Direction
+ BishBosh.Direction.Direction: nw :: Direction
+ BishBosh.Direction.Direction: opposites :: [(Direction, Direction)]
+ BishBosh.Direction.Direction: parallels :: [Direction]
+ BishBosh.Direction.Direction: s :: Direction
+ BishBosh.Direction.Direction: se :: Direction
+ BishBosh.Direction.Direction: sw :: Direction
+ BishBosh.Direction.Direction: type ArrayByDirection = Array Direction
+ BishBosh.Direction.Direction: w :: Direction
+ BishBosh.Direction.Horizontal: data Horizontal
+ BishBosh.Direction.Horizontal: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance BishBosh.Property.Opposable.Opposable BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance GHC.Classes.Eq BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance GHC.Classes.Ord BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance GHC.Enum.Enum BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance GHC.Read.Read BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: instance GHC.Show.Show BishBosh.Direction.Horizontal.Horizontal
+ BishBosh.Direction.Horizontal: nHorizontals :: NDirections
+ BishBosh.Direction.Parallel: data Parallel
+ BishBosh.Direction.Parallel: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance BishBosh.Property.Opposable.Opposable BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance BishBosh.Property.Orientated.Orientated BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance Control.DeepSeq.NFData BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance GHC.Classes.Eq BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance GHC.Classes.Ord BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance GHC.Enum.Enum BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance GHC.Read.Read BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: instance GHC.Show.Show BishBosh.Direction.Parallel.Parallel
+ BishBosh.Direction.Parallel: nParallels :: NDirections
+ BishBosh.Direction.Vertical: data Vertical
+ BishBosh.Direction.Vertical: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance BishBosh.Property.Opposable.Opposable BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance GHC.Classes.Eq BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance GHC.Classes.Ord BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance GHC.Enum.Enum BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance GHC.Read.Read BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: instance GHC.Show.Show BishBosh.Direction.Vertical.Vertical
+ BishBosh.Direction.Vertical: nVerticals :: NDirections
+ BishBosh.Evaluation.Fitness: measurePieceSquareValueDifference :: PieceSquareByCoordinatesByRank -> Game -> Base
+ BishBosh.Evaluation.Fitness: measurePieceSquareValueDifferenceIncrementally :: Base -> PieceSquareByCoordinatesByRank -> Game -> Base
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoveSequence :: QualifiedMoveSequence -> Forest positionHash -> Maybe (Forest positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoveSequence :: PositionHashQuantifiedGameTree positionHash -> QualifiedMoveSequence -> Maybe [NodeLabel positionHash]
+ BishBosh.Evaluation.QuantifiedGame: (<=>) :: QuantifiedGame -> QuantifiedGame -> Ordering
+ BishBosh.Evaluation.QuantifiedGame: (===) :: QuantifiedGame -> QuantifiedGame -> Bool
+ BishBosh.Evaluation.QuantifiedGame: infix 4 ===
+ BishBosh.Input.EvaluationOptions: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.EvaluationOptions: instance Control.DeepSeq.NFData BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.EvaluationOptions: instance Data.Default.Class.Default BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.EvaluationOptions: instance GHC.Classes.Eq BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.EvaluationOptions: instance GHC.Show.Show BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.EvaluationOptions: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.EvaluationOptions.EvaluationOptions
+ BishBosh.Input.Options: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Input.Options.Options
+ BishBosh.Input.Options: instance Control.DeepSeq.NFData BishBosh.Input.Options.Options
+ BishBosh.Input.Options: instance Data.Default.Class.Default BishBosh.Input.Options.Options
+ BishBosh.Input.Options: instance GHC.Classes.Eq BishBosh.Input.Options.Options
+ BishBosh.Input.Options: instance GHC.Show.Show BishBosh.Input.Options.Options
+ BishBosh.Input.Options: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.Options.Options
+ BishBosh.Input.PieceSquareTable: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Input.PieceSquareTable.PieceSquareTable
+ BishBosh.Input.PieceSquareTable: instance Data.Default.Class.Default BishBosh.Input.PieceSquareTable.PieceSquareTable
+ BishBosh.Input.PieceSquareTable: instance GHC.Classes.Eq BishBosh.Input.PieceSquareTable.PieceSquareTable
+ BishBosh.Input.PieceSquareTable: instance GHC.Show.Show BishBosh.Input.PieceSquareTable.PieceSquareTable
+ BishBosh.Input.PieceSquareTable: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.PieceSquareTable.PieceSquareTable
+ BishBosh.Model.GameTree: type BareGameTree = Tree Game
+ BishBosh.Property.Orientated: instance (BishBosh.Property.Orientated.Orientated l, BishBosh.Property.Orientated.Orientated r) => BishBosh.Property.Orientated.Orientated (Data.Either.Either l r)
+ BishBosh.Property.Orientated: isHorizontal :: Orientated a => a -> Bool
+ BishBosh.Property.Orientated: isVertical :: Orientated a => a -> Bool
+ BishBosh.Property.SelfValidating: instance (BishBosh.Property.SelfValidating.SelfValidating a, BishBosh.Property.SelfValidating.SelfValidating b) => BishBosh.Property.SelfValidating.SelfValidating (a, b)
+ BishBosh.State.Board: instance BishBosh.Property.SelfValidating.SelfValidating BishBosh.State.Board.Board
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.Property.SelfValidating.SelfValidating BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.StateProperty.Mutator.Mutator BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.StateProperty.View.View BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: type BareCoordinatesByRankByLogicalColour = ArrayByLogicalColour CoordinatesByRank
+ BishBosh.State.MaybePieceByCoordinates: findAttackerInDirections :: MaybePieceByCoordinates -> LogicalColour -> Coordinates -> Maybe [Direction] -> [(Coordinates, Rank)]
+ BishBosh.State.MaybePieceByCoordinates: findBlockingPieces :: MaybePieceByCoordinates -> Coordinates -> Maybe [Direction] -> [LocatedPiece]
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.SelfValidating.SelfValidating BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.StateProperty.View.View BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.StateProperty.Censor: findInvalidity :: Censor censor => censor -> [String]
+ BishBosh.StateProperty.Hashable: instance (BishBosh.StateProperty.Hashable.Hashable f, BishBosh.StateProperty.Hashable.Hashable s, BishBosh.StateProperty.Hashable.Hashable t) => BishBosh.StateProperty.Hashable.Hashable (f, s, t)
+ BishBosh.StateProperty.Hashable: instance (BishBosh.StateProperty.Hashable.Hashable l, BishBosh.StateProperty.Hashable.Hashable r) => BishBosh.StateProperty.Hashable.Hashable (l, r)
+ BishBosh.StateProperty.Hashable: instance BishBosh.StateProperty.Hashable.Hashable a => BishBosh.StateProperty.Hashable.Hashable (GHC.Maybe.Maybe a)
+ BishBosh.StateProperty.Hashable: instance BishBosh.StateProperty.Hashable.Hashable a => BishBosh.StateProperty.Hashable.Hashable [a]
+ BishBosh.StateProperty.Mutator: movePiece :: Mutator mutator => Move -> Piece -> Maybe Rank -> Either Coordinates (Maybe Rank) -> mutator -> mutator
+ BishBosh.StateProperty.Seeker: findInvalidity :: Seeker seeker => seeker -> [String]
+ BishBosh.StateProperty.View: class View view
+ BishBosh.StateProperty.View: fromAssocs :: View view => [LocatedPiece] -> view
+ BishBosh.StateProperty.View: toAssocs :: Seeker seeker => seeker -> [LocatedPiece]
+ BishBosh.StateProperty.View: translate :: (Seeker seeker, View view) => seeker -> view
+ BishBosh.Type.Mass: type Base = Double
- BishBosh.Cartesian.Coordinates: extrapolate :: Direction -> Coordinates -> [Coordinates]
+ BishBosh.Cartesian.Coordinates: extrapolate :: Coordinates -> Direction -> [Coordinates]
- BishBosh.Cartesian.Coordinates: isEnPassantRank :: LogicalColour -> Coordinates -> Bool
+ BishBosh.Cartesian.Coordinates: isEnPassantRank :: Coordinates -> LogicalColour -> Bool
- BishBosh.Cartesian.Coordinates: isPawnsFirstRank :: LogicalColour -> Coordinates -> Bool
+ BishBosh.Cartesian.Coordinates: isPawnsFirstRank :: Coordinates -> LogicalColour -> Bool
- BishBosh.Cartesian.Coordinates: translate :: ((X, Y) -> (X, Y)) -> Coordinates -> Coordinates
+ BishBosh.Cartesian.Coordinates: translate :: ((X, Y) -> (X, Y)) -> Transformation
- BishBosh.Cartesian.Vector: isPawnAttack :: LogicalColour -> Vector -> Bool
+ BishBosh.Cartesian.Vector: isPawnAttack :: Vector -> LogicalColour -> Bool
- BishBosh.Cartesian.Vector: matchesPawnDoubleAdvance :: LogicalColour -> Vector -> Bool
+ BishBosh.Cartesian.Vector: matchesPawnDoubleAdvance :: Vector -> LogicalColour -> Bool
- BishBosh.Cartesian.Vector: maybeTranslate :: Coordinates -> Vector -> Maybe Coordinates
+ BishBosh.Cartesian.Vector: maybeTranslate :: Vector -> Coordinates -> Maybe Coordinates
- BishBosh.Cartesian.Vector: translate :: Coordinates -> Vector -> Coordinates
+ BishBosh.Cartesian.Vector: translate :: Vector -> Coordinates -> Coordinates
- BishBosh.Component.Accountant: sumPieceSquareValueByLogicalColour :: (Accountant accountant, Num pieceSquareValue) => PieceSquareByCoordinatesByRank pieceSquareValue -> NPieces -> accountant -> [pieceSquareValue]
+ BishBosh.Component.Accountant: sumPieceSquareValueByLogicalColour :: Accountant accountant => PieceSquareByCoordinatesByRank -> accountant -> NPieces -> [Base]
- BishBosh.Component.Move: isPawnDoubleAdvance :: LogicalColour -> Move -> Bool
+ BishBosh.Component.Move: isPawnDoubleAdvance :: Move -> LogicalColour -> Bool
- BishBosh.Component.Piece: canMoveBetween :: Coordinates -> Coordinates -> Piece -> Bool
+ BishBosh.Component.Piece: canMoveBetween :: Piece -> Coordinates -> Coordinates -> Bool
- BishBosh.Component.Piece: findAttackDestinations :: Coordinates -> Piece -> [Coordinates]
+ BishBosh.Component.Piece: findAttackDestinations :: Piece -> Coordinates -> [Coordinates]
- BishBosh.Component.Piece: isPawnPromotion :: Coordinates -> Piece -> Bool
+ BishBosh.Component.Piece: isPawnPromotion :: Piece -> Coordinates -> Bool
- BishBosh.Component.PieceSquareByCoordinatesByRank: data PieceSquareByCoordinatesByRank pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: data PieceSquareByCoordinatesByRank
- BishBosh.Component.PieceSquareByCoordinatesByRank: findPieceSquareValue :: PieceSquareByCoordinatesByRank pieceSquareValue -> NPieces -> LogicalColour -> Rank -> Coordinates -> pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: findPieceSquareValue :: PieceSquareByCoordinatesByRank -> NPieces -> LogicalColour -> Rank -> Coordinates -> PieceSquareValue
- BishBosh.Component.PieceSquareByCoordinatesByRank: formatForGNUPlot :: (pieceSquareValue -> ShowS) -> ShowS -> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue) -> PieceSquareByCoordinatesByRank pieceSquareValue -> ShowS
+ BishBosh.Component.PieceSquareByCoordinatesByRank: formatForGNUPlot :: PieceSquareByCoordinatesByRank -> (PieceSquareValue -> ShowS) -> ShowS -> (PieceSquareValueByNPieces -> PieceSquareValue) -> ShowS
- BishBosh.Component.PieceSquareByCoordinatesByRank: interpolatePieceSquareValues :: Fractional pieceSquareValue => pieceSquareValue -> pieceSquareValue -> PieceSquareValueByNPieces pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: interpolatePieceSquareValues :: PieceSquareValue -> PieceSquareValue -> PieceSquareValueByNPieces
- BishBosh.Component.PieceSquareByCoordinatesByRank: mkPieceSquareByCoordinatesByRank :: (Rank -> EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue) -> PieceSquareByCoordinatesByRank pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: mkPieceSquareByCoordinatesByRank :: (Rank -> EitherPieceSquareValueByNPiecesByCoordinates) -> PieceSquareByCoordinatesByRank
- BishBosh.Component.Turn: isPawnDoubleAdvance :: LogicalColour -> Turn -> Bool
+ BishBosh.Component.Turn: isPawnDoubleAdvance :: Turn -> LogicalColour -> Bool
- BishBosh.Component.Zobrist: dereferenceRandomByCastleableRooksXByLogicalColour :: LogicalColour -> X -> Zobrist positionHash -> Maybe positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByCastleableRooksXByLogicalColour :: Zobrist positionHash -> LogicalColour -> X -> Maybe positionHash
- BishBosh.Component.Zobrist: dereferenceRandomByCoordinatesByRankByLogicalColour :: Index -> Zobrist positionHash -> positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByCoordinatesByRankByLogicalColour :: Zobrist positionHash -> Index -> positionHash
- BishBosh.Component.Zobrist: dereferenceRandomByEnPassantAbscissa :: X -> Zobrist positionHash -> positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByEnPassantAbscissa :: Zobrist positionHash -> X -> positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: maybeRandomlySelectOnymousQualifiedMove :: (Bits positionHash, RandomGen randomGen) => randomGen -> PreferVictories -> MatchSwitches -> Game -> PositionHashQualifiedMoveTree positionHash -> Maybe (QualifiedMove, [Name])
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: maybeRandomlySelectOnymousQualifiedMove :: (Bits positionHash, RandomGen randomGen) => randomGen -> PreferVictories -> MatchSwitches -> PositionHashQualifiedMoveTree positionHash -> Game -> Maybe (QualifiedMove, [Name])
- BishBosh.Evaluation.Fitness: evaluateFitness :: (Fractional pieceSquareValue, Real pieceSquareValue) => Maybe pieceSquareValue -> Game -> Reader pieceSquareValue WeightedMeanAndCriterionValues
+ BishBosh.Evaluation.Fitness: evaluateFitness :: Maybe Base -> Game -> Reader WeightedMeanAndCriterionValues
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: mkPositionHashQuantifiedGameTree :: (Bits positionHash, Fractional pieceSquareValue, Real pieceSquareValue) => EvaluationOptions pieceSquareValue -> SearchOptions -> Zobrist positionHash -> MoveFrequency -> Game -> PositionHashQuantifiedGameTree positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: mkPositionHashQuantifiedGameTree :: Bits positionHash => EvaluationOptions -> SearchOptions -> Zobrist positionHash -> MoveFrequency -> Game -> PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.QuantifiedGame: fromGame :: (Fractional pieceSquareValue, Real pieceSquareValue) => Maybe pieceSquareValue -> Game -> Reader pieceSquareValue QuantifiedGame
+ BishBosh.Evaluation.QuantifiedGame: fromGame :: Maybe Base -> Game -> Reader QuantifiedGame
- BishBosh.Input.EvaluationOptions: data EvaluationOptions pieceSquareValue
+ BishBosh.Input.EvaluationOptions: data EvaluationOptions
- BishBosh.Input.EvaluationOptions: mkEvaluationOptions :: Fractional pieceSquareValue => RankValues -> CriteriaWeights -> IncrementalEvaluation -> Maybe (PieceSquareTablePair pieceSquareValue) -> EvaluationOptions pieceSquareValue
+ BishBosh.Input.EvaluationOptions: mkEvaluationOptions :: RankValues -> CriteriaWeights -> IncrementalEvaluation -> Maybe PieceSquareTablePair -> EvaluationOptions
- BishBosh.Input.EvaluationOptions: type Reader pieceSquareValue = Reader (EvaluationOptions pieceSquareValue)
+ BishBosh.Input.EvaluationOptions: type Reader = Reader EvaluationOptions
- BishBosh.Input.Options: data Options pieceSquareValue
+ BishBosh.Input.Options: data Options
- BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions pieceSquareValue -> SearchOptions -> IOOptions -> Options pieceSquareValue
+ BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions -> SearchOptions -> IOOptions -> Options
- BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation
- BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation
- BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation
- BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation
- BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation
- BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation pieceSquareValue
+ BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation
- BishBosh.Input.Options: swapSearchDepth :: Transformation pieceSquareValue
+ BishBosh.Input.Options: swapSearchDepth :: Transformation
- BishBosh.Input.PieceSquareTable: data PieceSquareTable pieceSquareValue
+ BishBosh.Input.PieceSquareTable: data PieceSquareTable
- BishBosh.Input.PieceSquareTable: dereference :: Rank -> PieceSquareTable pieceSquareValue -> Maybe (ArrayByCoordinates pieceSquareValue)
+ BishBosh.Input.PieceSquareTable: dereference :: Rank -> PieceSquareTable -> Maybe PieceSquareValueByCoordinates
- BishBosh.Input.PieceSquareTable: findUndefinedRanks :: PieceSquareTable pieceSquareValue -> Set Rank
+ BishBosh.Input.PieceSquareTable: findUndefinedRanks :: PieceSquareTable -> Set Rank
- BishBosh.Input.PieceSquareTable: mkPieceSquareTable :: (Fractional pieceSquareValue, Ord pieceSquareValue, Show pieceSquareValue) => Normalise -> ReflectOnY -> Assocs Rank pieceSquareValue -> PieceSquareTable pieceSquareValue
+ BishBosh.Input.PieceSquareTable: mkPieceSquareTable :: Normalise -> ReflectOnY -> Assocs Rank Base -> PieceSquareTable
- BishBosh.Input.PieceSquareTable: normaliseToUnitInterval :: (Fractional pieceSquareValue, Ord pieceSquareValue) => Assocs rank pieceSquareValue -> Assocs rank pieceSquareValue
+ BishBosh.Input.PieceSquareTable: normaliseToUnitInterval :: (Fractional pieceSquareValueIn, Real pieceSquareValueIn, Fractional pieceSquareValueOut) => Assocs rank pieceSquareValueIn -> Assocs rank pieceSquareValueOut
- BishBosh.Input.RankValues: findRankValue :: Rank -> RankValues -> RankValue
+ BishBosh.Input.RankValues: findRankValue :: RankValues -> Rank -> RankValue
- BishBosh.Model.Game: countPliesAvailableTo :: LogicalColour -> Game -> NPlies
+ BishBosh.Model.Game: countPliesAvailableTo :: Game -> LogicalColour -> NPlies
- BishBosh.Model.Game: findQualifiedMovesAvailableTo :: LogicalColour -> Game -> [QualifiedMove]
+ BishBosh.Model.Game: findQualifiedMovesAvailableTo :: Game -> LogicalColour -> [QualifiedMove]
- BishBosh.Model.Game: isValidEitherQualifiedMove :: EitherQualifiedMove -> Game -> Bool
+ BishBosh.Model.Game: isValidEitherQualifiedMove :: Game -> EitherQualifiedMove -> Bool
- BishBosh.Model.Game: isValidQualifiedMove :: QualifiedMove -> Game -> Bool
+ BishBosh.Model.Game: isValidQualifiedMove :: Game -> QualifiedMove -> Bool
- BishBosh.Model.Game: mkAvailableQualifiedMovesFor :: LogicalColour -> Game -> AvailableQualifiedMoves
+ BishBosh.Model.Game: mkAvailableQualifiedMovesFor :: Game -> LogicalColour -> AvailableQualifiedMoves
- BishBosh.Model.Game: validateEitherQualifiedMove :: EitherQualifiedMove -> Game -> Maybe String
+ BishBosh.Model.Game: validateEitherQualifiedMove :: Game -> EitherQualifiedMove -> Maybe String
- BishBosh.Model.Game: validateQualifiedMove :: QualifiedMove -> Game -> Maybe String
+ BishBosh.Model.Game: validateQualifiedMove :: Game -> QualifiedMove -> Maybe String
- BishBosh.State.Board: exposesKing :: LogicalColour -> Move -> Board -> Bool
+ BishBosh.State.Board: exposesKing :: Board -> LogicalColour -> Move -> Bool
- BishBosh.State.Board: findAttackersOf :: LogicalColour -> Coordinates -> Board -> [(Coordinates, Rank)]
+ BishBosh.State.Board: findAttackersOf :: Board -> LogicalColour -> Coordinates -> [(Coordinates, Rank)]
- BishBosh.State.Board: findAttacksBy :: Piece -> Coordinates -> Board -> [Coordinates]
+ BishBosh.State.Board: findAttacksBy :: Board -> Piece -> Coordinates -> [Coordinates]
- BishBosh.State.Board: isKingChecked :: LogicalColour -> Board -> Bool
+ BishBosh.State.Board: isKingChecked :: Board -> LogicalColour -> Bool
- BishBosh.State.Board: sumPieceSquareValueByLogicalColour :: Num pieceSquareValue => PieceSquareByCoordinatesByRank pieceSquareValue -> Board -> ArrayByLogicalColour pieceSquareValue
+ BishBosh.State.Board: sumPieceSquareValueByLogicalColour :: PieceSquareByCoordinatesByRank -> Board -> ArrayByLogicalColour Base
- BishBosh.State.CastleableRooksByLogicalColour: canCastle :: LogicalColour -> CastleableRooksByLogicalColour -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: canCastle :: CastleableRooksByLogicalColour -> LogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: canCastleWith :: LogicalColour -> Coordinates -> CastleableRooksByLogicalColour -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: canCastleWith :: CastleableRooksByLogicalColour -> LogicalColour -> Coordinates -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: hasCastled :: LogicalColour -> CastleableRooksByLogicalColour -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: hasCastled :: CastleableRooksByLogicalColour -> LogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: listIncrementalRandoms :: CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour -> Zobrist random -> [random]
+ BishBosh.State.CastleableRooksByLogicalColour: listIncrementalRandoms :: Zobrist random -> CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour -> [random]
- BishBosh.State.CastleableRooksByLogicalColour: locateForLogicalColour :: LogicalColour -> CastleableRooksByLogicalColour -> Maybe [X]
+ BishBosh.State.CastleableRooksByLogicalColour: locateForLogicalColour :: CastleableRooksByLogicalColour -> LogicalColour -> Maybe [X]
- BishBosh.State.CoordinatesByRankByLogicalColour: dereference :: LogicalColour -> Rank -> CoordinatesByRankByLogicalColour -> [Coordinates]
+ BishBosh.State.CoordinatesByRankByLogicalColour: dereference :: CoordinatesByRankByLogicalColour -> LogicalColour -> Rank -> [Coordinates]
- BishBosh.State.CoordinatesByRankByLogicalColour: findPiecesOfColour :: LogicalColour -> CoordinatesByRankByLogicalColour -> [LocatedPiece]
+ BishBosh.State.CoordinatesByRankByLogicalColour: findPiecesOfColour :: CoordinatesByRankByLogicalColour -> LogicalColour -> [LocatedPiece]
- BishBosh.State.CoordinatesByRankByLogicalColour: getKingsCoordinates :: LogicalColour -> CoordinatesByRankByLogicalColour -> Coordinates
+ BishBosh.State.CoordinatesByRankByLogicalColour: getKingsCoordinates :: CoordinatesByRankByLogicalColour -> LogicalColour -> Coordinates
- BishBosh.State.MaybePieceByCoordinates: dereference :: Coordinates -> MaybePieceByCoordinates -> Maybe Piece
+ BishBosh.State.MaybePieceByCoordinates: dereference :: MaybePieceByCoordinates -> Coordinates -> Maybe Piece
- BishBosh.State.MaybePieceByCoordinates: findAttackerInDirection :: LogicalColour -> Direction -> Coordinates -> MaybePieceByCoordinates -> Maybe (Coordinates, Rank)
+ BishBosh.State.MaybePieceByCoordinates: findAttackerInDirection :: MaybePieceByCoordinates -> LogicalColour -> Coordinates -> Direction -> Maybe (Coordinates, Rank)
- BishBosh.State.MaybePieceByCoordinates: findBlockingPiece :: Direction -> Coordinates -> MaybePieceByCoordinates -> Maybe LocatedPiece
+ BishBosh.State.MaybePieceByCoordinates: findBlockingPiece :: MaybePieceByCoordinates -> Coordinates -> Direction -> Maybe LocatedPiece
- BishBosh.State.MaybePieceByCoordinates: inferMoveType :: Move -> Maybe Rank -> MaybePieceByCoordinates -> MoveType
+ BishBosh.State.MaybePieceByCoordinates: inferMoveType :: MaybePieceByCoordinates -> Move -> Maybe Rank -> MoveType
- BishBosh.State.MaybePieceByCoordinates: isClear :: Coordinates -> Coordinates -> MaybePieceByCoordinates -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isClear :: MaybePieceByCoordinates -> Coordinates -> Coordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isEnPassantMove :: Move -> MaybePieceByCoordinates -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isEnPassantMove :: MaybePieceByCoordinates -> Move -> Bool
- BishBosh.State.MaybePieceByCoordinates: isObstructed :: Coordinates -> Coordinates -> MaybePieceByCoordinates -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isObstructed :: MaybePieceByCoordinates -> Coordinates -> Coordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isOccupied :: Coordinates -> MaybePieceByCoordinates -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isOccupied :: MaybePieceByCoordinates -> Coordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isVacant :: Coordinates -> MaybePieceByCoordinates -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isVacant :: MaybePieceByCoordinates -> Coordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: listDestinationsFor :: Coordinates -> Piece -> MaybePieceByCoordinates -> [(Coordinates, Maybe Rank)]
+ BishBosh.State.MaybePieceByCoordinates: listDestinationsFor :: MaybePieceByCoordinates -> Coordinates -> Piece -> [(Coordinates, Maybe Rank)]
- BishBosh.State.MaybePieceByCoordinates: show2D :: Column -> ColourScheme -> Bool -> (X, Y) -> MaybePieceByCoordinates -> String
+ BishBosh.State.MaybePieceByCoordinates: show2D :: MaybePieceByCoordinates -> Column -> ColourScheme -> Bool -> (X, Y) -> String
- BishBosh.State.TurnsByLogicalColour: dereference :: LogicalColour -> TurnsByLogicalColour turn -> [turn]
+ BishBosh.State.TurnsByLogicalColour: dereference :: TurnsByLogicalColour turn -> LogicalColour -> [turn]
- BishBosh.State.TurnsByLogicalColour: update :: TurnsByLogicalColour turn -> [(LogicalColour, [turn])] -> TurnsByLogicalColour turn
+ BishBosh.State.TurnsByLogicalColour: update :: [(LogicalColour, [turn])] -> Transformation turn
- BishBosh.StateProperty.Hashable: hash :: (Bits positionHash, Hashable hashable) => hashable -> Zobrist positionHash -> positionHash
+ BishBosh.StateProperty.Hashable: hash :: (Bits positionHash, Hashable hashable) => Zobrist positionHash -> hashable -> positionHash
- BishBosh.StateProperty.Hashable: listRandoms :: Hashable hashable => hashable -> Zobrist positionHash -> [positionHash]
+ BishBosh.StateProperty.Hashable: listRandoms :: Hashable hashable => Zobrist positionHash -> hashable -> [positionHash]
- BishBosh.StateProperty.Seeker: findProximateKnights :: Seeker seeker => LogicalColour -> Coordinates -> seeker -> [Coordinates]
+ BishBosh.StateProperty.Seeker: findProximateKnights :: Seeker seeker => seeker -> LogicalColour -> Coordinates -> [Coordinates]
- BishBosh.Type.Mass: type CriterionWeight = Double
+ BishBosh.Type.Mass: type CriterionWeight = Base
- BishBosh.Type.Mass: type PieceSquareValue = CriterionValue
+ BishBosh.Type.Mass: type PieceSquareValue = Base
- BishBosh.Type.Mass: type RankValue = CriterionValue
+ BishBosh.Type.Mass: type RankValue = Base
Files
- bishbosh.cabal +23/−16
- bishbosh.spec +1/−1
- changelog.markdown +25/−9
- makefile +13/−9
- src-exe/BishBosh/Play.hs +7/−28
- src-exe/BishBosh/State/PlayState.hs +23/−46
- src-exe/BishBosh/UI/CECP.hs +37/−71
- src-exe/BishBosh/UI/Raw.hs +44/−72
- src-exe/Duel/Data/Options.hs +5/−5
- src-exe/Duel/Process/Intermediary.hs +9/−12
- src-exe/Main.hs +14/−17
- src-lib/BishBosh/Attribute/ANSIColourCode.hs +0/−76
- src-lib/BishBosh/Attribute/ColourScheme.hs +0/−159
- src-lib/BishBosh/Attribute/Direction.hs +0/−265
- src-lib/BishBosh/Attribute/LogicalColour.hs +0/−144
- src-lib/BishBosh/Attribute/LogicalColourOfSquare.hs +0/−59
- src-lib/BishBosh/Attribute/MoveType.hs +9/−14
- src-lib/BishBosh/Attribute/PhysicalColour.hs +0/−119
- src-lib/BishBosh/Attribute/Rank.hs +0/−5
- src-lib/BishBosh/Cartesian/Coordinates.hs +148/−131
- src-lib/BishBosh/Cartesian/Ordinate.hs +11/−11
- src-lib/BishBosh/Cartesian/Vector.hs +60/−49
- src-lib/BishBosh/Colour/ANSIColourCode.hs +76/−0
- src-lib/BishBosh/Colour/ColourScheme.hs +159/−0
- src-lib/BishBosh/Colour/LogicalColour.hs +151/−0
- src-lib/BishBosh/Colour/LogicalColourOfSquare.hs +59/−0
- src-lib/BishBosh/Colour/PhysicalColour.hs +119/−0
- src-lib/BishBosh/Component/Accountant.hs +5/−5
- src-lib/BishBosh/Component/CastlingMove.hs +7/−7
- src-lib/BishBosh/Component/Move.hs +26/−14
- src-lib/BishBosh/Component/Piece.hs +67/−63
- src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs +53/−31
- src-lib/BishBosh/Component/QualifiedMove.hs +5/−0
- src-lib/BishBosh/Component/Turn.hs +5/−5
- src-lib/BishBosh/Component/Zobrist.hs +19/−19
- src-lib/BishBosh/ContextualNotation/PGN.hs +3/−3
- src-lib/BishBosh/ContextualNotation/PositionHashQualifiedMoveTree.hs +48/−57
- src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs +6/−3
- src-lib/BishBosh/ContextualNotation/StandardAlgebraic.hs +20/−16
- src-lib/BishBosh/Data/RoseTree.hs +15/−2
- src-lib/BishBosh/Direction/Diagonal.hs +114/−0
- src-lib/BishBosh/Direction/Direction.hs +180/−0
- src-lib/BishBosh/Direction/Horizontal.hs +66/−0
- src-lib/BishBosh/Direction/Parallel.hs +104/−0
- src-lib/BishBosh/Direction/Vertical.hs +66/−0
- src-lib/BishBosh/Evaluation/Fitness.hs +42/−65
- src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs +27/−41
- src-lib/BishBosh/Evaluation/QuantifiedGame.hs +25/−22
- src-lib/BishBosh/Input/CommandLineOption.hs +1/−0
- src-lib/BishBosh/Input/EvaluationOptions.hs +25/−32
- src-lib/BishBosh/Input/NativeUIOptions.hs +4/−4
- src-lib/BishBosh/Input/Options.hs +20/−25
- src-lib/BishBosh/Input/PieceSquareTable.hs +44/−50
- src-lib/BishBosh/Input/RankValues.hs +2/−2
- src-lib/BishBosh/Input/SearchOptions.hs +9/−9
- src-lib/BishBosh/Input/UIOptions.hs +2/−2
- src-lib/BishBosh/Metric/CriterionValue.hs +6/−6
- src-lib/BishBosh/Metric/CriterionWeight.hs +6/−6
- src-lib/BishBosh/Metric/RankValue.hs +8/−8
- src-lib/BishBosh/Metric/WeightedMeanAndCriterionValues.hs +1/−1
- src-lib/BishBosh/Model/Game.hs +172/−169
- src-lib/BishBosh/Model/GameTree.hs +7/−5
- src-lib/BishBosh/Model/MoveFrequency.hs +14/−14
- src-lib/BishBosh/Model/PositionHashTree.hs +2/−1
- src-lib/BishBosh/Property/Arboreal.hs +0/−13
- src-lib/BishBosh/Property/Orientated.hs +24/−4
- src-lib/BishBosh/Property/Rotatable.hs +3/−1
- src-lib/BishBosh/Property/SelfValidating.hs +5/−0
- src-lib/BishBosh/Rule/GameTerminationReason.hs +6/−6
- src-lib/BishBosh/Rule/Result.hs +7/−7
- src-lib/BishBosh/Search/AlphaBeta.hs +28/−43
- src-lib/BishBosh/Search/KillerMoves.hs +11/−11
- src-lib/BishBosh/State/Board.hs +121/−134
- src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs +34/−38
- src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs +120/−80
- src-lib/BishBosh/State/EnPassantAbscissa.hs +21/−18
- src-lib/BishBosh/State/MaybePieceByCoordinates.hs +162/−146
- src-lib/BishBosh/State/Position.hs +8/−11
- src-lib/BishBosh/State/TurnsByLogicalColour.hs +28/−28
- src-lib/BishBosh/StateProperty/Censor.hs +22/−3
- src-lib/BishBosh/StateProperty/Hashable.hs +19/−5
- src-lib/BishBosh/StateProperty/Mutator.hs +20/−7
- src-lib/BishBosh/StateProperty/Seeker.hs +36/−10
- src-lib/BishBosh/StateProperty/View.hs +48/−0
- src-lib/BishBosh/Text/ShowColouredPrefix.hs +9/−9
- src-lib/BishBosh/Time/GameClock.hs +6/−6
- src-lib/BishBosh/Type/Crypto.hs +3/−3
- src-lib/BishBosh/Type/Mass.hs +53/−12
- src-test/BishBosh/Test/HUnit/Attribute/Direction.hs +0/−46
- src-test/BishBosh/Test/HUnit/Attribute/LogicalColour.hs +0/−41
- src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs +6/−6
- src-test/BishBosh/Test/HUnit/Colour/LogicalColour.hs +41/−0
- src-test/BishBosh/Test/HUnit/Component/Move.hs +14/−14
- src-test/BishBosh/Test/HUnit/Component/Piece.hs +14/−14
- src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs +8/−8
- src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs +13/−13
- src-test/BishBosh/Test/HUnit/Direction/Direction.hs +46/−0
- src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs +14/−14
- src-test/BishBosh/Test/HUnit/Input/Options.hs +1/−4
- src-test/BishBosh/Test/HUnit/Model/Game.hs +18/−22
- src-test/BishBosh/Test/HUnit/Model/GameTree.hs +5/−5
- src-test/BishBosh/Test/HUnit/Search/Search.hs +2/−3
- src-test/BishBosh/Test/HUnit/State/Board.hs +93/−93
- src-test/BishBosh/Test/QuickCheck/Attribute/Direction.hs +0/−87
- src-test/BishBosh/Test/QuickCheck/Attribute/LogicalColour.hs +0/−56
- src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs +21/−11
- src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs +30/−15
- src-test/BishBosh/Test/QuickCheck/Colour/LogicalColour.hs +56/−0
- src-test/BishBosh/Test/QuickCheck/Component/Move.hs +11/−3
- src-test/BishBosh/Test/QuickCheck/Component/QualifiedMove.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Component/Turn.hs +6/−6
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs +3/−1
- src-test/BishBosh/Test/QuickCheck/Direction/Direction.hs +116/−0
- src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs +4/−3
- src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs +20/−24
- src-test/BishBosh/Test/QuickCheck/Input/Options.hs +3/−15
- src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs +3/−20
- src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Model/Game.hs +53/−57
- src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs +1/−2
- src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Rule/Result.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/Search/Search.hs +3/−2
- src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs +2/−9
- src-test/BishBosh/Test/QuickCheck/State/Board.hs +40/−26
- src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs +9/−9
- src-test/BishBosh/Test/QuickCheck/StateProperty/Hashable.hs +5/−9
- src-test/BishBosh/Test/QuickCheck/StateProperty/Mutator.hs +90/−0
- src-test/BishBosh/Test/QuickCheck/StateProperty/View.hs +65/−0
- src-test/BishBosh/Test/QuickCheck/Type/Mass.hs +39/−0
- src-test/BishBosh/Test/QuickCheck/UI/Command.hs +2/−2
- src-test/HUnit.hs +5/−5
- src-test/QuickCheck.hs +8/−4
bishbosh.cabal view
@@ -16,7 +16,7 @@ -- along with BishBosh. If not, see <http://www.gnu.org/licenses/>. Name: bishbosh-Version: 0.1.2.0+Version: 0.1.3.0 Copyright: (C) 2018 Dr. Alistair Ward License: GPL-3.0-or-later License-file: LICENSE@@ -79,6 +79,7 @@ Default: False -- Whether, to wrap common types in 'newtype' for increased type-safety. CAVEAT: there's a ~10% performance-penalty.+-- CAVEAT: partly incompatible with 'narrownumbers'. flag newtypewrappers Description: Wrap common types in newtype for increased type-safety. Manual: True@@ -92,7 +93,8 @@ Description: Link with package "polyparse" when available, rather than "parsec". Default: True --- Whether to use precise (rational) types rather than floating-point. CAVEAT: incompatible with 'narrownumbers'.+-- Whether to use precise (rational) types rather than floating-point.+-- CAVEAT: conceptually incompatible with 'narrownumbers'. flag precision Description: Use precise numerical types. CAVEAT: this is incompatible with either 'unboxedarrays' or 'narrownumbers'. Manual: True@@ -105,7 +107,7 @@ Default: True -- Whether to use unboxed arrays where possible.--- CAVEAT: incompatble with the flag 'precision'.+-- CAVEAT: incompatible with the flag 'precision', & to some extent 'newtypewrappers'. flag unboxedarrays Description: Use unboxed arrays. Manual: True@@ -170,19 +172,18 @@ Hs-source-dirs: src-lib Exposed-modules:- BishBosh.Attribute.ANSIColourCode BishBosh.Attribute.CaptureMoveSortAlgorithm- BishBosh.Attribute.ColourScheme- BishBosh.Attribute.Direction- BishBosh.Attribute.LogicalColour- BishBosh.Attribute.LogicalColourOfSquare BishBosh.Attribute.MoveType- BishBosh.Attribute.PhysicalColour BishBosh.Attribute.Rank BishBosh.Cartesian.Abscissa BishBosh.Cartesian.Coordinates BishBosh.Cartesian.Ordinate BishBosh.Cartesian.Vector+ BishBosh.Colour.ANSIColourCode+ BishBosh.Colour.ColourScheme+ BishBosh.Colour.LogicalColour+ BishBosh.Colour.LogicalColourOfSquare+ BishBosh.Colour.PhysicalColour BishBosh.Component.Accountant BishBosh.Component.CastlingMove BishBosh.Component.EitherQualifiedMove@@ -207,6 +208,11 @@ BishBosh.Data.Num BishBosh.Data.Ratio BishBosh.Data.RoseTree+ BishBosh.Direction.Diagonal+ BishBosh.Direction.Direction+ BishBosh.Direction.Horizontal+ BishBosh.Direction.Parallel+ BishBosh.Direction.Vertical BishBosh.Evaluation.Fitness BishBosh.Evaluation.PositionHashQuantifiedGameTree BishBosh.Evaluation.QuantifiedGame@@ -275,6 +281,7 @@ BishBosh.StateProperty.Hashable BishBosh.StateProperty.Mutator BishBosh.StateProperty.Seeker+ BishBosh.StateProperty.View BishBosh.State.TurnsByLogicalColour BishBosh.Text.AutoComplete BishBosh.Text.Case@@ -370,9 +377,6 @@ if flag(threaded) GHC-options: -threaded - if flag(unboxedarrays) && !flag(precision)- CPP-Options: -DUSE_UNBOXED_ARRAYS- -- N.B.: The Haskell package 'unix' may be available on MS-Windows, but building it will probably be laborious. if flag(unix) Other-modules: BishBosh.Concurrent.SignalHandlers@@ -403,11 +407,10 @@ Autogen-modules: Paths_bishbosh Other-modules:- BishBosh.Test.HUnit.Attribute.Direction- BishBosh.Test.HUnit.Attribute.LogicalColour BishBosh.Test.HUnit.Attribute.Rank BishBosh.Test.HUnit.Cartesian.Coordinates BishBosh.Test.HUnit.Cartesian.Vector+ BishBosh.Test.HUnit.Colour.LogicalColour BishBosh.Test.HUnit.Component.CastlingMove BishBosh.Test.HUnit.Component.Move BishBosh.Test.HUnit.Component.Piece@@ -415,6 +418,7 @@ BishBosh.Test.HUnit.ContextualNotation.PGN BishBosh.Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic+ BishBosh.Test.HUnit.Direction.Direction BishBosh.Test.HUnit.Evaluation.Fitness BishBosh.Test.HUnit.Input.Options BishBosh.Test.HUnit.Model.Game@@ -441,12 +445,11 @@ Other-modules: BishBosh.Test.QuickCheck.Attribute.CaptureMoveSortAlgorithm- BishBosh.Test.QuickCheck.Attribute.Direction- BishBosh.Test.QuickCheck.Attribute.LogicalColour BishBosh.Test.QuickCheck.Attribute.MoveType BishBosh.Test.QuickCheck.Attribute.Rank BishBosh.Test.QuickCheck.Cartesian.Coordinates BishBosh.Test.QuickCheck.Cartesian.Vector+ BishBosh.Test.QuickCheck.Colour.LogicalColour BishBosh.Test.QuickCheck.Component.Move BishBosh.Test.QuickCheck.Component.Piece BishBosh.Test.QuickCheck.Component.QualifiedMove@@ -459,6 +462,7 @@ BishBosh.Test.QuickCheck.ContextualNotation.StandardAlgebraic BishBosh.Test.QuickCheck.Data.Foldable BishBosh.Test.QuickCheck.Data.Integral+ BishBosh.Test.QuickCheck.Direction.Direction BishBosh.Test.QuickCheck.Evaluation.PositionHashQuantifiedGameTree BishBosh.Test.QuickCheck.Input.CECPFeatures BishBosh.Test.QuickCheck.Input.CECPOptions@@ -496,12 +500,15 @@ BishBosh.Test.QuickCheck.State.Position BishBosh.Test.QuickCheck.StateProperty.Censor BishBosh.Test.QuickCheck.StateProperty.Hashable+ BishBosh.Test.QuickCheck.StateProperty.Mutator BishBosh.Test.QuickCheck.StateProperty.Seeker+ BishBosh.Test.QuickCheck.StateProperty.View BishBosh.Test.QuickCheck.State.TurnsByLogicalColour BishBosh.Test.QuickCheck.Text.Encoding BishBosh.Test.QuickCheck.Time.StopWatch BishBosh.Test.QuickCheck.Type.Count BishBosh.Test.QuickCheck.Type.Length+ BishBosh.Test.QuickCheck.Type.Mass BishBosh.Test.QuickCheck.UI.Command BishBosh.Test.QuickCheck.UI.PrintObject BishBosh.Test.QuickCheck.UI.ReportObject
bishbosh.spec view
@@ -24,7 +24,7 @@ Summary: BishBosh is a chess-game. Name: bishbosh-Version: 0.1.2.0+Version: 0.1.3.0 Release: 1 License: GPLv3 # From '/usr/share/doc/packages/rpm/GROUPS'.
changelog.markdown view
@@ -27,7 +27,7 @@ ## 0.0.0.8 * Corrected the parsing of FEN when an Enpassant-destination defined on file **b** was erroneously interpreted as a bishop in the previous **CastleableRooks** field.-* Added parent class **BishBosh.Property.ExtendedPositionDescription.EPD** for **Property.ForsythEdwards.FEN**, for which the latter typically has a default implementation of both methods.+* Added parent type-class **BishBosh.Property.ExtendedPositionDescription.EPD** for **Property.ForsythEdwards.FEN**, for which the latter typically has a default implementation of both methods. ## 0.1.0.0 ### Bug-fixes:@@ -68,10 +68,10 @@ **Component.CastlingMove** | Forked from module **Component.Move**. **Data.Enum** | Currently single-function. **Data.Foldable** | Currently single-function.-**Property.FixedMembership** | Defines a class to which sum-types can conform.+**Property.FixedMembership** | Defines a type-class to which sum-types can conform. **StateProperty.Censor** | Relocated from directory **State/**.-**StateProperty.Mutator** | defines a class to express the dual implementations within **State.Board**.-**StateProperty.Seeker** | defines a class to express the dual implementations within **State.Board**.+**StateProperty.Mutator** | defines a type-class to express the dual implementations within **State.Board**.+**StateProperty.Seeker** | defines a type-class to express the dual implementations within **State.Board**. **Text.Case** | Forked from **Text.ShowList** to contain case-related operations. **Text.Prefix** | Forked from **Text.ShowList** to define the constant prefixes of log-messages. -----------------------------------------@@ -96,11 +96,11 @@ **BishBosh.Time.GameClock** | Contains two **BishBosh.Time.StopWatch**es to enable module **Duel.Process.Intermediary** to measure the time used by each player. **BishBosh.Property.Switchable** | Exports a type-class, which both **BishBosh.Time.StopWatch** & **BishBosh.Time.GameClock** implement, to expose their functionality. **BishBosh.Property.SelfValidating** | Exports a type-class, which both **BishBosh.Time.GameClock** & **Duel.Data.Options** implement, to validate themselves.-**BishBosh.Type.Countable** | Defines newtypes to enhance type-safety, replacing type-synonyms for **Int**. There is a performance-degradation, so this enhancement can be disabled using a new cabal-flag.+**BishBosh.Type.Countable** | Defines *newtype*s to enhance type-safety, replacing type-synonyms for **Int**. There is a performance-degradation, so this enhancement can be disabled using a new cabal-flag. **BishBosh.Type.Crypto** | Self-documentation.-**BishBosh.Type.Length** | Replaced the polymorphic type-parameters **row** & **column** with newtypes to enhance type-safety.+**BishBosh.Type.Length** | Replaced the polymorphic type-parameters **row** & **column** with *newtype*s to enhance type-safety. **BishBosh.Type.Mass** | Self-documentation.-**BishBosh.Metric.RankValue** | Replaced the polymorphic type-parameter **rankValue**, with a newtype & a smart-constructor to guard permissible bounds.+**BishBosh.Metric.RankValue** | Replaced the polymorphic type-parameter **rankValue**, with a *newtype* & a smart-constructor to guard permissible bounds. ### Duel: * Added command-line option **--verifyConfiguration**, to request that the mutual compatibility of the two configuration-files be verified before forwarding each to a forked instance of **bishbosh**.@@ -110,7 +110,7 @@ * Refactored functions **BishBosh.ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition**, **BishBosh.Model.MoveFrequency.insertMoves** & **BishBosh.Model.GameTree.toMoveFrequency**. * Evaluation-criteria: + Moved **BishBosh.Attribute.**{**CriterionValue**, **CriterionWeight**, **WeightedMeanAndCriterionValues**} to a new directory **Metric/**- + Implemented classes [**Num**, **Fractional**, **Real**] for data-types **BishBosh.Metric.**{**CriterionValue.CriterionValue**, **CriterionWeight.CriterionWeight**}, nullifying the requirement for exports.+ + Implemented type-classes [**Num**, **Fractional**, **Real**] for data-types **BishBosh.Metric.**{**CriterionValue.CriterionValue**, **CriterionWeight.CriterionWeight**}, nullifying the requirement for exports. + Replaced the pointless polymorphic payloads in data-types **BishBosh.Metric.**{**CriterionValue.CriterionValue**, **CriterionWeight.CriterionWeight**, **WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues**} with concrete types. * Moved **BishBosh.Attribute.RankValues** to **BishBosh.Input**. * Checked that (with the possible exception of the King) the Queen is configured as the most valuable rank.@@ -134,7 +134,7 @@ + Amended **BishBosh.Evaluation.Fitness.measurePieceSquareValueIncrementally** to forward Castling moves to **measurePieceSquareValue**. + Polymorphism: * Replaced the polymorphic type **distance** in **BishBosh.Component.Vector**, with two concrete types **BishBosh.Type.Length.[XY]**. Removed the type **BishBosh.Type.Length.Distance**.- * Replaced the polymorphic type-parameters **x** & **y** with newtypes to:+ * Replaced the polymorphic type-parameters **x** & **y** with *newtype*s to: + eliminate the fragile **RULE** pragmas required to switch to memoised function-implementations for specific type-parameters, + eliminate chains of **SPECIALISE** pragmas down the call-stack to hot-spots. + allow external calls from [**Text.ParserCombinators.Poly.Lazy.runParser**, **Text.ParserCombinators.Parsec.parse**], to access specialised implementations (see previous items),@@ -145,4 +145,20 @@ + Added type **BishBosh.Type.Count.NCoordinates** for use by function **BishBosh.Cartesian.Coordinates.nSquares**. + Added a method **BishBosh.StateProperty.Seeker.countPawnsByFileByLogicalColour** including a default implementation, & relocated the implementation from module **BishBosh.State.CoordinatesByRankByLogicalColour**. + Added a type-class **BishBosh.Component.Account.Accountant**, with a single method used to sum piece-square values; thus permiting a common interface between the implementations in **BishBosh.State.CoordinatesByRankByLogicalColour** & **BishBosh.State.MaybePieceByCoordinates**.++## 0.1.3.0+* Efficiency:+ + Replaced the polymorphic type-parameter **pieceSquareValue** with a *newtype*, to then implement *unboxed* arrays without cluttering interfaces with type-constraint **Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue**; performance-improvement was regrettably insignificant.+ + Added some strictness to **BishBosh.Board.{exposesKing, movePiece, sumPieceSquareValueByLogicalColour}** & **BishBosh.Game.applyQualifiedMove**.+ + Added function **BishBosh.Cartesian.Coordinates.applyAlongDirectionsFrom** to reduce sequential indexing by direction when extrapolating in all directions; deployed in new functions **BishBosh.State.MaybePieceByCoordinates.{findBlockingPieces, findAttackerInDirections}**+ + Refactored function **BishBosh.Cartesian.Vector.toMaybeDirection** to eliminate call to **BishBosh.Property.Orientated.isStraight**.+ + Refactored function **BishBosh.Component.Piece.canMoveBetween** to remove **let**-binding.+ + Refactored function **BishBosh.State.EnPassantAbscissa.mkMaybeEnPassantAbscissa** to reduce calls to **BishBosh.State.MaybePieceByCoordinates.{findAttackerInDirection, findBlockingPiece}**.+* Structural:+ + Added method **BishBosh.StateProperty.Mutator.movePiece** & implemented whole type-class in module **BishBosh.State.CoordinatesByRankByLogicalColour**.+ + Implemented type-class **BishBosh.Property.SelfValidating.SelfValidating** in modules **BishBosh.State.{MaybePieceByCoordinates, CoordinatesByRankByLogicalColour, Board}**.+ + Created a new type-class **BishBosh.StateProperty.View.View** (implemented in **BishBosh.State.{MaybePieceByCoordinates, CoordinatesByRankByLogicalColour}**), to abstract construction of a view & translation between views.+ + Rewrote module **BishBosh.Attribute.Direction** to remove the 9th invalid state from the data-structure, & to express the division between *parallel* & *diagonal* instances; which degraded performance slightly. Added new methods to class **BishBosh.Property.Orientated.Orientated**.+ + Relocated colour-related modules from **BishBosh/Attribute/** to **BishBosh/Colour/**.+ + Re-ordered the parameters of functions which access record-structures, to make the record the first parameter; cf. those that mutate the record-structure, which receive it last.
makefile view
@@ -53,33 +53,37 @@ test: @for FLAG in -polyparse newtypewrappers narrownumbers unboxedarrays -hxtrelaxng -threaded precision; do\ echo $${FLAG};\- stack '$@' --flag="$(PACKAGE_NAME):$${FLAG}" $(GHC_OPTIONS) || break;\+ stack '$@' --flag="$(PACKAGE_NAME):$${FLAG}" $(GHC_OPTIONS) '$(PACKAGE_NAME):test:hunit-tests' '$(PACKAGE_NAME):test:quickcheck-tests' || break;\ done # Compile with random CPP-flags & run the test-suites. randomTest: FLAGS=$$(shuf --echo -- hxtrelaxng narrownumbers newtypewrappers polyparse precision threaded unboxedarrays | head --lines=3 | sed -e '1s/^/-/' -e 's/\(.*\)/--flag=$(PACKAGE_NAME):\1/');\ echo $${FLAGS};\- stack test $${FLAGS} $(GHC_OPTIONS)+ stack test $${FLAGS} $(GHC_OPTIONS) '$(PACKAGE_NAME):test:hunit-tests' '$(PACKAGE_NAME):test:quickcheck-tests' # Profile a single-threaded build, to access entry-counts. prof:- @stack install --profile --flag='bishbosh:-threaded' $(GHC_OPTIONS);- sleep 16; # Let the test-machine reach a quiescent state.+ @stack install --profile --flag='$(PACKAGE_NAME):-threaded' $(GHC_OPTIONS) '$(PACKAGE_NAME):exe:$(PACKAGE_NAME)';+ sleep 32; # Let the test-machine reach a quiescent state. @$(PACKAGE_NAME) -i 'config/Raw/$(PACKAGE_NAME)_$@.xml' +RTS -p -RTS # Profile. profN2:- @stack install --profile $(GHC_OPTIONS);+ @stack install --profile $(GHC_OPTIONS) '$(PACKAGE_NAME):exe:$(PACKAGE_NAME)'; @$(PACKAGE_NAME) -i 'config/Raw/$(PACKAGE_NAME)_prof.xml' +RTS -p -N2 -RTS -# Install this product.-$(BIN_DIR)/$(PACKAGE_NAME) $(BIN_DIR)/duel:- @stack install $(GHC_OPTIONS)+# Install 'bishbosh'.+$(BIN_DIR)/$(PACKAGE_NAME):+ @stack install $(GHC_OPTIONS) '$(PACKAGE_NAME):exe:$(PACKAGE_NAME)' # Run the installed application as an xboard-engine. xboard: $(BIN_DIR)/$(PACKAGE_NAME)- @$@ -fcp '$(PACKAGE_NAME) -i "config/CECP/$(PACKAGE_NAME)_black.xml" +RTS -N2 -RTS'+ @$@ -fcp '$(PACKAGE_NAME) -i 'config/CECP/$(PACKAGE_NAME)_black.xml' +RTS -N2 -RTS'++# Install 'duel'.+$(BIN_DIR)/duel: $(BIN_DIR)/$(PACKAGE_NAME)+ @stack install $(GHC_OPTIONS) '$(PACKAGE_NAME):exe:duel' # Start a battle. duel: $(BIN_DIR)/duel
src-exe/BishBosh/Play.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -58,10 +57,8 @@ import qualified BishBosh.State.PlayState as State.PlayState import qualified BishBosh.Text.ShowColouredPrefix as Text.ShowColouredPrefix import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Mass as Type.Mass import qualified BishBosh.UI.CECP as UI.CECP import qualified BishBosh.UI.Raw as UI.Raw-import qualified Control.DeepSeq import qualified Control.Exception import qualified Control.Monad import qualified Data.Bits@@ -72,37 +69,19 @@ import qualified System.Random import System.FilePath((</>)) -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | Plays the game according to the specified configuration. play :: (- Control.DeepSeq.NFData pieceSquareValue,-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.FiniteBits positionHash,- Fractional pieceSquareValue,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- System.Random.Random positionHash,- System.Random.RandomGen randomGen+ Data.Bits.FiniteBits positionHash,+ Ord positionHash,+ System.Random.Random positionHash,+ System.Random.RandomGen randomGen ) => Input.Verbosity.Verbosity -> randomGen- -> Input.Options.Options pieceSquareValue+ -> Input.Options.Options -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -- ^ Standard openings.- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)-{-# SPECIALISE play- :: System.Random.RandomGen randomGen- => Input.Verbosity.Verbosity- -> randomGen- -> Input.Options.Options Type.Mass.PieceSquareValue- -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)- #-}+ -> IO (State.PlayState.PlayState positionHash)+{-# SPECIALISE play :: Input.Verbosity.Verbosity -> System.Random.StdGen -> Input.Options.Options -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> IO (State.PlayState.PlayState Type.Crypto.PositionHash) #-} play verbosity randomGen options qualifiedMoveForest = Data.Maybe.maybe ( return {-to IO-monad-} Data.Default.def {-game-} ) (
src-exe/BishBosh/State/PlayState.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -82,40 +81,30 @@ import qualified Data.Ord import qualified Factory.Math.Statistics -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | The type threaded through the sequence of /game/s during play.-data PlayState pieceSquareValue positionHash = MkPlayState {+data PlayState positionHash = MkPlayState { getCriterionValues :: [[Metric.CriterionValue.CriterionValue]], -- ^ The /criterion-value/s accumulated during the game. getZobrist :: Component.Zobrist.Zobrist positionHash, -- ^ The constant hash-codes used to construct position-hashes. getMoveFrequency :: Model.GameTree.MoveFrequency, -- ^ The constant frequency of moves extracted from file. getSearchState :: Search.SearchState.SearchState positionHash,- getOptions :: Input.Options.Options pieceSquareValue, -- ^ The constant options by which the game is configured.+ getOptions :: Input.Options.Options, -- ^ The constant options by which the game is configured. getMaybeApplicationTerminationReason :: Maybe State.ApplicationTerminationReason.ApplicationTerminationReason -- ^ Whether the game has terminated. } -- | Constructor.-initialise :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Real pieceSquareValue- )- => Input.Options.Options pieceSquareValue+initialise+ :: Data.Bits.Bits positionHash+ => Input.Options.Options -> Component.Zobrist.Zobrist positionHash -> Model.GameTree.MoveFrequency -> Model.Game.Game- -> PlayState pieceSquareValue positionHash+ -> PlayState positionHash {-# SPECIALISE initialise- :: Input.Options.Options Type.Mass.PieceSquareValue+ :: Input.Options.Options -> Component.Zobrist.Zobrist Type.Crypto.PositionHash -> Model.GameTree.MoveFrequency -> Model.Game.Game- -> PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash+ -> PlayState Type.Crypto.PositionHash #-} initialise options zobrist moveFrequency game = MkPlayState { getCriterionValues = [],@@ -129,27 +118,21 @@ } -- | Accessor.-getGame :: PlayState pieceSquareValue positionHash -> Model.Game.Game+getGame :: PlayState positionHash -> Model.Game.Game getGame MkPlayState { getSearchState = searchState } = Evaluation.QuantifiedGame.getGame . Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame $ Search.SearchState.getPositionHashQuantifiedGameTree searchState -- | The type of a function used to transform a 'PlayState'.-type Transformation pieceSquareValue positionHash = PlayState pieceSquareValue positionHash -> PlayState pieceSquareValue positionHash+type Transformation positionHash = PlayState positionHash -> PlayState positionHash -- | Mutator.-setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash -> Transformation pieceSquareValue positionHash+setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash -> Transformation positionHash setPositionHashQuantifiedGameTree positionHashQuantifiedGameTree playState@MkPlayState { getSearchState = searchState } = playState { getSearchState = searchState { Search.SearchState.getPositionHashQuantifiedGameTree = positionHashQuantifiedGameTree } } -- | Reconstruct the /positionHashQuantifiedGameTree/ (in the /searchState/), with the apex set to the specified game.-reconstructPositionHashQuantifiedGameTree :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Real pieceSquareValue- ) => Model.Game.Game -> Transformation pieceSquareValue positionHash+reconstructPositionHashQuantifiedGameTree :: Data.Bits.Bits positionHash => Model.Game.Game -> Transformation positionHash+{-# SPECIALISE reconstructPositionHashQuantifiedGameTree :: Model.Game.Game -> Transformation Type.Crypto.PositionHash #-} reconstructPositionHashQuantifiedGameTree game playState@MkPlayState { getZobrist = zobrist, getMoveFrequency = moveFrequency,@@ -161,14 +144,8 @@ ) playState -- | Reset to the initial state.-resetPositionHashQuantifiedGameTree :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Real pieceSquareValue- ) => Transformation pieceSquareValue positionHash+resetPositionHashQuantifiedGameTree :: Data.Bits.Bits positionHash => Transformation positionHash+{-# SPECIALISE resetPositionHashQuantifiedGameTree :: Transformation Type.Crypto.PositionHash #-} resetPositionHashQuantifiedGameTree playState = reconstructPositionHashQuantifiedGameTree Data.Default.def playState { getCriterionValues = [], getMaybeApplicationTerminationReason = Nothing@@ -178,14 +155,14 @@ updateWithAutomaticMove :: [Metric.CriterionValue.CriterionValue] -> Search.SearchState.SearchState positionHash- -> Transformation pieceSquareValue positionHash+ -> Transformation positionHash updateWithAutomaticMove criterionValues searchState playState = playState { getCriterionValues = criterionValues : getCriterionValues playState, getSearchState = searchState } -- | Mutator.-updateWithManualMove :: Model.Game.Game -> Transformation pieceSquareValue positionHash+updateWithManualMove :: Model.Game.Game -> Transformation positionHash updateWithManualMove game playState@MkPlayState { getSearchState = searchState } = setPositionHashQuantifiedGameTree ( Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.State.PlayState.updateWithManualMove:\tEvaluation.PositionHashQuantifiedGameTree.reduce failed."@@ -205,7 +182,7 @@ Floating standardDeviation, Fractional mean )- => PlayState pieceSquareValue positionHash+ => PlayState positionHash -> [(mean, standardDeviation)] calculateCriterionValueStatistics MkPlayState { getCriterionValues = criterionValues } = map ( (@@ -216,7 +193,7 @@ ) $ Data.List.transpose criterionValues -- | Resignation by the player who currently holds the choice of move.-resign :: Transformation pieceSquareValue positionHash+resign :: Transformation positionHash resign playState@MkPlayState { getSearchState = searchState } = setPositionHashQuantifiedGameTree ( Evaluation.PositionHashQuantifiedGameTree.resign $ Search.SearchState.getPositionHashQuantifiedGameTree searchState ) playState@@ -224,7 +201,7 @@ -- | Given a string from which either a /move/ can't be parsed or the one that can is illegal, returns the closest matches amongst the currently available /move/s. suggestCorrections :: String -- ^ Move-string.- -> PlayState pieceSquareValue positionHash+ -> PlayState positionHash -> [String] -- ^ Suggested corrections. suggestCorrections moveString playState@MkPlayState { getOptions = options } | Model.Game.isTerminated game = []@@ -236,12 +213,12 @@ -- | Whether the game in the first /play-state/ has more plies than that in the second. hasMorePlies- :: PlayState pieceSquareValue positionHash- -> PlayState pieceSquareValue positionHash+ :: PlayState positionHash+ -> PlayState positionHash -> Bool hasMorePlies playState playState' = Data.Ord.comparing (State.TurnsByLogicalColour.getNPlies . Model.Game.getTurnsByLogicalColour . getGame) playState playState' == GT -- | Whether the user has requested application-termination, or the configured maximum number of turns has been reached.-hasApplicationTerminationBeenRequested :: PlayState pieceSquareValue positionHash -> Bool+hasApplicationTerminationBeenRequested :: PlayState positionHash -> Bool hasApplicationTerminationBeenRequested MkPlayState { getMaybeApplicationTerminationReason = maybeApplicationTerminationReason } = Data.Maybe.isJust maybeApplicationTerminationReason
src-exe/BishBosh/UI/CECP.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts, ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -106,10 +106,6 @@ import qualified System.Random import qualified ToolShed.System.Random -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | Used in output to prefix hints. hintTag :: String hintTag = "Hint:"@@ -169,7 +165,7 @@ showsThinking :: Property.ShowFloat.ShowFloat stoppedWatch => Type.Count.NPlies -- ^ Search-depth.- -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue+ -> Input.EvaluationOptions.EvaluationOptions -> Type.Mass.WeightedMean -> stoppedWatch -> Type.Count.NPositions -- ^ Nodes searched.@@ -179,7 +175,7 @@ shows searchDepth, shows . (round :: Type.Mass.RankValue -> Int) $ 100 {-centi-Pawns-} * ( uncurry (/) . (- Input.RankValues.calculateMaximumTotalValue &&& realToFrac . Input.RankValues.findRankValue Attribute.Rank.Pawn+ Input.RankValues.calculateMaximumTotalValue &&& realToFrac . (`Input.RankValues.findRankValue` Attribute.Rank.Pawn) ) $ Input.EvaluationOptions.getRankValues evaluationOptions ) * realToFrac weightedMean, Property.ShowFloat.showsFloat (shows . (round :: Double -> Int) . (* 100)) stoppedWatch,@@ -191,31 +187,17 @@ * Since the user can also request roll-back to an earlier game before then requesting a new move, a new game is returned rather than just the requested move. -}-readMove :: forall pieceSquareValue positionHash randomGen. (- Control.DeepSeq.NFData pieceSquareValue,-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- System.Random.RandomGen randomGen+readMove :: forall positionHash randomGen. (+ Data.Bits.Bits positionHash,+ Ord positionHash,+ System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)-{-# SPECIALISE readMove- :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash- -> randomGen- -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)- #-}+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash)+{-# SPECIALISE readMove :: ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> System.Random.StdGen -> Time.StopWatch.StopWatch -> State.PlayState.PlayState Type.Crypto.PositionHash -> IO (State.PlayState.PlayState Type.Crypto.PositionHash) #-} readMove positionHashQualifiedMoveTree randomGen = slave where slave runningWatch playState = let (game, options) = State.PlayState.getGame &&& State.PlayState.getOptions $ playState@@ -235,7 +217,7 @@ \cecpOptions -> let displaySAN = Input.CECPOptions.getDisplaySAN cecpOptions - onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState positionHash) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -253,7 +235,7 @@ ) ( flip (ContextualNotation.StandardAlgebraic.showTurn explicitEnpassant) game ) . Model.Game.maybeLastTurn $ Evaluation.QuantifiedGame.getGame quantifiedGame- else Notation.MoveNotation.showNotation moveNotation $ Evaluation.QuantifiedGame.getLastTurn (quantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame)+ else Notation.MoveNotation.showNotation moveNotation $ Evaluation.QuantifiedGame.getLastTurn quantifiedGame _ -> Control.Exception.throwIO . Data.Exception.mkRequestFailure . showString "BishBosh.UI.CECP.readMove.slave.onCommand:\tunexpectedly failed to find any moves; " $ shows game "." -- CAVEAT: the game should have been terminated. ) ( \(qualifiedMove, _) -> putStrLn . showString hintTag . showChar ' ' $ if displaySAN@@ -261,7 +243,7 @@ else Notation.MoveNotation.showNotation moveNotation qualifiedMove ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen ( Input.StandardOpeningOptions.getPreferVictories . Input.SearchOptions.getStandardOpeningOptions $ searchOptions- ) tryToMatchSwitches game positionHashQualifiedMoveTree+ ) tryToMatchSwitches positionHashQualifiedMoveTree game return {-to IO-monad-} playState -- N.B.: though one could merely call "eventLoop", a new random-generator is desirable in case an alternative hint is requested. onCommand (UI.Command.Print printObject) = do@@ -274,22 +256,19 @@ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowPrefix.showsPrefixInfo "quitting on request." return {-to IO-monad-} playState { State.PlayState.getMaybeApplicationTerminationReason = Just State.ApplicationTerminationReason.byRequest }- onCommand (UI.Command.Report reportObject) = do+ onCommand (UI.Command.Report reportObject) = let+ showMoves :: Notation.MoveNotation.ShowNotation a => [a] -> ShowS+ showMoves = Text.ShowList.showsFormattedList' (Notation.MoveNotation.showsNotation moveNotation)+ in do putStrLn . tellUser =<< ( case reportObject of- UI.ReportObject.AvailableMoves -> return {-to IO-monad-} . ($ ".") . Text.ShowList.showsFormattedList (- showChar '|'- ) (- Notation.MoveNotation.showsNotation moveNotation- ) . Model.Game.findQualifiedMovesAvailableToNextPlayer+ UI.ReportObject.AvailableMoves -> return {-to IO-monad-} . ($ ".") . showMoves . Model.Game.findQualifiedMovesAvailableToNextPlayer UI.ReportObject.Board -> return {-to IO-monad-} . show . Model.Game.getBoard UI.ReportObject.EPD -> return {-to IO-monad-} . Property.ExtendedPositionDescription.showEPD UI.ReportObject.FEN -> return {-to IO-monad-} . Property.ForsythEdwards.showFEN UI.ReportObject.Game -> return {-to IO-monad-} . show UI.ReportObject.MaxPositionInstances -> return {-to IO-monad-} . show . State.InstancesByPosition.findMaximumInstances . Model.Game.getInstancesByPosition- UI.ReportObject.Moves -> return {-to IO-monad-} . ($ "") . Text.ShowList.showsFormattedList' (- Notation.MoveNotation.showsNotation moveNotation- ) . Model.Game.listTurnsChronologically+ UI.ReportObject.Moves -> return {-to IO-monad-} . ($ ".") . showMoves . Model.Game.listTurnsChronologically UI.ReportObject.PGN -> fmap ($ ".") . ContextualNotation.PGN.showsGame UI.ReportObject.ReversiblePlyCount -> return {-to IO-monad-} . show . State.InstancesByPosition.countConsecutiveRepeatablePlies . Model.Game.getInstancesByPosition ) game@@ -320,7 +299,7 @@ } } onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState positionHash) rollBack nPlies | (game', _) : _ <- drop (fromIntegral $ pred nPlies) $ Model.Game.rollBack game = return {-to IO-monad-} $ State.PlayState.reconstructPositionHashQuantifiedGameTree game' playState | otherwise = onCommand UI.Command.Restart@@ -386,7 +365,7 @@ return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash)+ eventLoop :: IO (State.PlayState.PlayState positionHash) eventLoop = getLine >>= \line -> do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "received \"" $ showString line "\"." @@ -434,7 +413,7 @@ [(name, _result)] -> showString ":\t" . showString name _ -> id ) ""- ) $ ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches game positionHashQualifiedMoveTree+ ) $ ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches positionHashQualifiedMoveTree game eventLoop "computer" -> eventLoop -- No action required.@@ -973,10 +952,10 @@ maybePaused = Input.CECPOptions.getMaybePaused cecpOptions - moveCommand :: String -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ moveCommand :: String -> IO (State.PlayState.PlayState positionHash) moveCommand moveString = case Notation.MoveNotation.readsQualifiedMove moveNotation moveString of [(eitherQualifiedMove, "")]- | Just errorMessage <- Model.Game.validateEitherQualifiedMove eitherQualifiedMove game -> do+ | Just errorMessage <- Model.Game.validateEitherQualifiedMove game eitherQualifiedMove -> do Control.Monad.unless (verbosity == minBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixError . shows moveString . showString " is illegal; " $ shows errorMessage "." putStrLn $ mkIllegalMoveMessage errorMessage moveString@@ -996,7 +975,7 @@ ) $ Model.Game.maybeLastTurn game' ) . showString " was requested after " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." - case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition game' positionHashQualifiedMoveTree of+ case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition positionHashQualifiedMoveTree game' of [] -> return () onymousQualifiedMoves -> System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "matches archived game(s):" $ ContextualNotation.QualifiedMoveForest.showsNames ( Input.IOOptions.getMaybeMaximumPGNNames ioOptions@@ -1023,29 +1002,16 @@ ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall pieceSquareValue positionHash randomGen. (- Control.DeepSeq.NFData pieceSquareValue,-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- System.Random.RandomGen randomGen+takeTurns :: forall positionHash randomGen. (+ Data.Bits.Bits positionHash,+ Ord positionHash,+ System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)-{-# SPECIALISE takeTurns- :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash- -> randomGen- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)- #-}+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash)+{-# SPECIALISE takeTurns :: ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> System.Random.StdGen -> State.PlayState.PlayState Type.Crypto.PositionHash -> IO (State.PlayState.PlayState Type.Crypto.PositionHash) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = do mVar <- Control.Concurrent.newEmptyMVar @@ -1066,8 +1032,8 @@ :: Maybe (Concurrent.Pondering.Pondering Component.Move.Move) -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash) slave maybePondering maybeMaximumPlies ~(randomGen' : randomGens) playState' = let (game', (searchOptions', uiOptions')) = State.PlayState.getGame &&& (Input.Options.getSearchOptions &&& Input.IOOptions.getUIOptions . Input.Options.getIOOptions) . State.PlayState.getOptions $ playState' -- Deconstruct. (ponderMode, isPostMode) = const (@@ -1083,7 +1049,7 @@ do playState'' <- readMove positionHashQualifiedMoveTree randomGen' runningWatch playState' -- Read the user's command or move. - (,) playState'' `fmap` (+ (,) playState'' <$> ( if playState' `State.PlayState.hasMorePlies` playState'' then {-rolled-back-} Data.Maybe.maybe ( return {-to IO-monad-} Nothing@@ -1165,7 +1131,7 @@ State.PlayState.updateWithAutomaticMove ( Metric.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) searchState' playState'- ) `fmap` if ponderMode && Input.SearchOptions.getUsePondering searchOptions+ ) <$> if ponderMode && Input.SearchOptions.getUsePondering searchOptions then case continuation of quantifiedGame' {-1st move after ours in optimal move-sequence-} : _ -> fmap Just . ( \positionHashQuantifiedGameTree'' -> Concurrent.Pondering.ponder (@@ -1213,7 +1179,7 @@ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen' ) ( Input.StandardOpeningOptions.getPreferVictories &&& Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions- ) game' positionHashQualifiedMoveTree -- Determine whether the automated player's move can be decided by a search of recorded games or we must decide ourself.+ ) positionHashQualifiedMoveTree game' -- Determine whether the automated player's move can be decided by a search of recorded games or we must decide ourself. ) ( if Input.UIOptions.isCECPManualMode uiOptions' then Nothing
src-exe/BishBosh/UI/Raw.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts, ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -68,7 +68,6 @@ import qualified BishBosh.Time.StopWatch as Time.StopWatch import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Mass as Type.Mass import qualified BishBosh.UI.Command as UI.Command import qualified BishBosh.UI.PrintObject as UI.PrintObject import qualified BishBosh.UI.ReportObject as UI.ReportObject@@ -88,40 +87,22 @@ import qualified System.Random import qualified ToolShed.System.Random -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- {- | * Reads a command-sequence from the user, terminating in either a request to move or to exit the game. * Since the user can also request roll-back to an earlier game before then requesting a new move, a new game is returned rather than just the requested move. -}-readMove :: forall pieceSquareValue positionHash randomGen. (- Control.DeepSeq.NFData pieceSquareValue,-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- System.Random.RandomGen randomGen+readMove :: forall positionHash randomGen. (+ Data.Bits.Bits positionHash,+ Ord positionHash,+ System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)-{-# SPECIALISE readMove- :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash- -> randomGen- -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)- #-}+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash)+{-# SPECIALISE readMove :: ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> System.Random.StdGen -> Time.StopWatch.StopWatch -> State.PlayState.PlayState Type.Crypto.PositionHash -> IO (State.PlayState.PlayState Type.Crypto.PositionHash) #-} readMove positionHashQualifiedMoveTree randomGen runningWatch playState = let (game, options) = State.PlayState.getGame &&& State.PlayState.getOptions $ playState (searchOptions, ioOptions) = Input.Options.getSearchOptions &&& Input.Options.getIOOptions $ options@@ -137,7 +118,9 @@ in ( \nativeUIOptions -> let show2D :: Model.Game.Game -> String- show2D = State.MaybePieceByCoordinates.show2D (+ show2D g = State.MaybePieceByCoordinates.show2D (+ State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard g+ ) ( snd {-columns-} $ Input.NativeUIOptions.getBoardMagnification nativeUIOptions ) ( Input.NativeUIOptions.getColourScheme nativeUIOptions@@ -145,9 +128,9 @@ Input.NativeUIOptions.getDepictFigurine nativeUIOptions ) ( Notation.MoveNotation.getOrigin moveNotation- ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard+ ) - onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState positionHash) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -173,7 +156,7 @@ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen ) ( Input.StandardOpeningOptions.getPreferVictories &&& Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions- ) game positionHashQualifiedMoveTree+ ) positionHashQualifiedMoveTree game return {-to IO-monad-} playState -- N.B.: though one could merely call "eventLoop", a new random-generator is desirable in case an alternative hint is requested. onCommand (UI.Command.Print printObject) = do@@ -186,21 +169,18 @@ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowColouredPrefix.showsPrefixInfo "quitting on request." return {-to IO-monad-} playState { State.PlayState.getMaybeApplicationTerminationReason = Just State.ApplicationTerminationReason.byRequest }- onCommand (UI.Command.Report reportObject) = do+ onCommand (UI.Command.Report reportObject) = let+ showMoves :: Notation.MoveNotation.ShowNotation a => [a] -> ShowS+ showMoves = Text.ShowList.showsFormattedList' (Notation.MoveNotation.showsNotation moveNotation)+ in do ($ game) $ case reportObject of- UI.ReportObject.AvailableMoves -> putStrLn . ($ ".") . Text.ShowList.showsFormattedList (- showChar '|'- ) (- Notation.MoveNotation.showsNotation moveNotation- ) . Model.Game.findQualifiedMovesAvailableToNextPlayer+ UI.ReportObject.AvailableMoves -> putStrLn . ($ ".") . showMoves . Model.Game.findQualifiedMovesAvailableToNextPlayer UI.ReportObject.Board -> putStrLn . show2D UI.ReportObject.EPD -> putStrLn . Property.ExtendedPositionDescription.showEPD UI.ReportObject.FEN -> putStrLn . Property.ForsythEdwards.showFEN UI.ReportObject.Game -> print UI.ReportObject.MaxPositionInstances -> print . State.InstancesByPosition.findMaximumInstances . Model.Game.getInstancesByPosition- UI.ReportObject.Moves -> putStrLn . ($ "") . Text.ShowList.showsFormattedList' (- Notation.MoveNotation.showsNotation moveNotation- ) . Model.Game.listTurnsChronologically+ UI.ReportObject.Moves -> putStrLn . ($ ".") . showMoves . Model.Game.listTurnsChronologically UI.ReportObject.PGN -> putStrLn . ($ ".") <=< ContextualNotation.PGN.showsGame UI.ReportObject.ReversiblePlyCount -> print . State.InstancesByPosition.countConsecutiveRepeatablePlies . Model.Game.getInstancesByPosition @@ -216,7 +196,7 @@ return {-to IO-monad-} $ State.PlayState.resetPositionHashQuantifiedGameTree playState onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState positionHash) rollBack nPlies | (game', _) : _ <- drop (fromIntegral $ pred nPlies) $ Model.Game.rollBack game = do Control.Monad.when (verbosity == maxBound) . putStrLn $ show2D game'@@ -288,7 +268,7 @@ return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash)+ eventLoop :: IO (State.PlayState.PlayState positionHash) eventLoop = getLine >>= \line -> case Data.List.Extra.trim line of "?" -> onCommand $ UI.Command.Print UI.PrintObject.Help ':' : s -> (@@ -310,7 +290,7 @@ corrections = State.PlayState.suggestCorrections s playState in case Notation.MoveNotation.readsQualifiedMove moveNotation s of [(eitherQualifiedMove, "")]- | Just errorMessage <- Model.Game.validateEitherQualifiedMove eitherQualifiedMove game -> do+ | Just errorMessage <- Model.Game.validateEitherQualifiedMove game eitherQualifiedMove -> do System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixError . shows s . showString " is illegal; " $ shows errorMessage "." Control.Monad.unless (null corrections) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "did you mean " $ shows corrections " ?"@@ -330,7 +310,7 @@ ) $ Model.Game.maybeLastTurn game' ) . showString " was requested after " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." - case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition game' positionHashQualifiedMoveTree of+ case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition positionHashQualifiedMoveTree game' of [] -> return {-to IO-monad-} () onymousQualifiedMoves -> System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "matches archived game(s):" $ ContextualNotation.QualifiedMoveForest.showsNames maybeMaximumPGNNames ( concatMap (@@ -359,29 +339,16 @@ ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall pieceSquareValue positionHash randomGen. (- Control.DeepSeq.NFData pieceSquareValue,-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- System.Random.RandomGen randomGen+takeTurns :: forall positionHash randomGen. (+ Data.Bits.Bits positionHash,+ Ord positionHash,+ System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)-{-# SPECIALISE takeTurns- :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash- -> randomGen- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)- #-}+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash)+{-# SPECIALISE takeTurns :: ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> System.Random.StdGen -> State.PlayState.PlayState Type.Crypto.PositionHash -> IO (State.PlayState.PlayState Type.Crypto.PositionHash) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = let options = State.PlayState.getOptions playState @@ -398,7 +365,9 @@ let show2D :: Model.Game.Game -> String- show2D = State.MaybePieceByCoordinates.show2D (+ show2D game = State.MaybePieceByCoordinates.show2D (+ State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard game+ ) ( snd {-columns-} $ Input.NativeUIOptions.getBoardMagnification nativeUIOptions ) ( Input.NativeUIOptions.getColourScheme nativeUIOptions@@ -406,14 +375,14 @@ Input.NativeUIOptions.getDepictFigurine nativeUIOptions ) ( Notation.MoveNotation.getOrigin moveNotation- ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard+ ) slave :: Maybe (Concurrent.Pondering.Pondering Component.Move.Move) -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState pieceSquareValue positionHash- -> IO (State.PlayState.PlayState pieceSquareValue positionHash)+ -> State.PlayState.PlayState positionHash+ -> IO (State.PlayState.PlayState positionHash) slave maybePondering maybeMaximumPlies ~(randomGen' : randomGens) playState' = let (game', searchOptions') = State.PlayState.getGame &&& Input.Options.getSearchOptions . State.PlayState.getOptions $ playState' -- Deconstruct. in Data.Maybe.maybe (@@ -424,7 +393,7 @@ do playState'' <- readMove positionHashQualifiedMoveTree randomGen' runningWatch playState' -- Block reading a command-sequence terminating in a move from a manual player. - (,) playState'' `fmap` (+ (,) playState'' <$> ( if playState' `State.PlayState.hasMorePlies` playState'' then {-rolled-back-} Data.Maybe.maybe ( return {-to IO-monad-} Nothing@@ -444,7 +413,10 @@ ) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowColouredPrefix.showsPrefixInfo "failed to find any suitable archived move." let- search ss = Control.Monad.Reader.runReader (Search.Search.search searchDepth' ss) searchOptions'+ search ss = Control.Monad.Reader.runReader (+ Search.Search.search searchDepth' ss+ ) searchOptions'+ searchResult = search $ State.PlayState.getSearchState playState' Data.Maybe.maybe (@@ -492,7 +464,7 @@ State.PlayState.updateWithAutomaticMove ( Metric.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) searchState' playState'- ) `fmap` if Input.SearchOptions.getUsePondering searchOptions+ ) <$> if Input.SearchOptions.getUsePondering searchOptions then case continuation of quantifiedGame' {-1st move after ours in optimal move-sequence-} : _ -> fmap Just . ( \positionHashQuantifiedGameTree'' -> Concurrent.Pondering.ponder (@@ -538,7 +510,7 @@ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen' ) ( Input.StandardOpeningOptions.getPreferVictories &&& Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions- ) game' positionHashQualifiedMoveTree -- Determine whether the automated player's move can be decided by a search of recorded games or we must decide ourself.+ ) positionHashQualifiedMoveTree game' -- Determine whether the automated player's move can be decided by a search of recorded games or we must decide ourself. ) ( Model.Game.getNextLogicalColour game' `Map.lookup` Input.SearchOptions.getSearchDepthByLogicalColour searchOptions' -- Determinate whether the next player is manual. ) >>= (
src-exe/Duel/Data/Options.hs view
@@ -46,13 +46,13 @@ appendInputConfigFilePath ) where -import qualified Control.Exception-import qualified Data.Default-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.Verbosity as Input.Verbosity import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.Type.Count as Type.Count+import qualified Control.Exception+import qualified Data.Default import qualified System.FilePath -- | Container for all command-line options.@@ -77,7 +77,7 @@ instance Property.SelfValidating.SelfValidating Options where findInvalidity = Property.SelfValidating.findErrors [- ((/= Attribute.LogicalColour.nDistinctLogicalColours) . fromIntegral . length . getInputConfigFilePaths, "There must be exactly one configuration file for White & one for Black.")+ ((/= Colour.LogicalColour.nDistinctLogicalColours) . fromIntegral . length . getInputConfigFilePaths, "There must be exactly one configuration file for White & one for Black.") ] -- | Mutator.@@ -109,7 +109,7 @@ appendInputConfigFilePath s options | fromIntegral ( length inputConfigFilePaths- ) == Attribute.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkRedundantData . showString "Duel.Data.Options:\texactly " . shows Attribute.LogicalColour.nDistinctLogicalColours . showString " file-paths are required:\t" $ shows inputConfigFilePaths "."+ ) == Colour.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkRedundantData . showString "Duel.Data.Options:\texactly " . shows Colour.LogicalColour.nDistinctLogicalColours . showString " file-paths are required:\t" $ shows inputConfigFilePaths "." | otherwise = options { getInputConfigFilePaths = s : inputConfigFilePaths } where inputConfigFilePaths = getInputConfigFilePaths options
src-exe/Duel/Process/Intermediary.hs view
@@ -44,7 +44,7 @@ import Control.Arrow((&&&), (|||)) import Control.Category((>>>))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.CommandLineOption as Input.CommandLineOption import qualified BishBosh.Input.IOOptions as Input.IOOptions@@ -62,7 +62,6 @@ import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Time.GameClock as Time.GameClock import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Mass as Type.Mass import qualified BishBosh.UI.Command as UI.Command import qualified BishBosh.UI.ReportObject as UI.ReportObject import qualified Control.Exception@@ -118,9 +117,9 @@ -- | Read either a move or a game-termination reason from the specified handle. readMove :: Input.Verbosity.Verbosity- -> Type.Count.NSeconds -- ^ Read-timout.- -> Attribute.LogicalColour.LogicalColour -- ^ Whose turn it is.- -> System.IO.Handle -- ^ Output handle from which data should be read.+ -> Type.Count.NSeconds -- ^ Read-timout.+ -> Colour.LogicalColour.LogicalColour -- ^ Whose turn it is.+ -> System.IO.Handle -- ^ Output handle from which data should be read. -> IO (Either Rule.GameTerminationReason.GameTerminationReason MoveNotation) readMove verbosity readTimeout logicalColour stdOut = do Control.Monad.when (verbosity == maxBound) . IO.Logger.printInfo . showString "Waiting " . (@@ -150,10 +149,10 @@ -- | Read either a move from the first handle & write it to the second. copyMove :: Input.Verbosity.Verbosity- -> Type.Count.NSeconds -- ^ Read-timout.- -> Attribute.LogicalColour.LogicalColour -- ^ Whose turn it is.- -> System.IO.Handle -- ^ Output handle from which move should be read.- -> System.IO.Handle -- ^ Input handle to which move should be forwarded.+ -> Type.Count.NSeconds -- ^ Read-timout.+ -> Colour.LogicalColour.LogicalColour -- ^ Whose turn it is.+ -> System.IO.Handle -- ^ Output handle from which move should be read.+ -> System.IO.Handle -- ^ Input handle to which move should be forwarded. -> IO (Maybe Rule.GameTerminationReason.GameTerminationReason) copyMove verbosity readTimeout logicalColour stdOut stdIn = do readMove verbosity readTimeout logicalColour stdOut >>= return {-to IO-monad-} . Just ||| (@@ -331,9 +330,7 @@ ] configFilePath >>> HXT.arr ( \inputOptions -> (- Input.SearchOptions.identifyAutomatedPlayers $ Input.Options.getSearchOptions (- inputOptions :: Input.Options.Options Type.Mass.PieceSquareValue -- Arbitrary concrete type.- ),+ Input.SearchOptions.identifyAutomatedPlayers $ Input.Options.getSearchOptions inputOptions, Input.UIOptions.getMoveNotation . Input.IOOptions.getUIOptions $ Input.Options.getIOOptions inputOptions, null . Input.IOOptions.getPGNOptionsList $ Input.Options.getIOOptions inputOptions )
src-exe/Main.hs view
@@ -90,12 +90,9 @@ #endif #ifdef USE_UNIX-import qualified BishBosh.Concurrent.SignalHandlers as Concurrent.SignalHandlers+import qualified BishBosh.Concurrent.SignalHandlers as Concurrent.SignalHandlers #endif --- Define concrete types to resolve the underlying polymorphic functions.-type Options = Input.Options.Options Type.Mass.PieceSquareValue- writeXMLToFile :: HXT.XmlPickler pickleable => System.FilePath.FilePath -- ^ Destination.@@ -152,7 +149,7 @@ optDescrList :: [ G.OptDescr ( Maybe (Input.CommandLineOption.Flag, Maybe String {-optional value-}), -- Record command-line specifications.- Input.CommandLineOption.CommandLineOption Options -- Defines the action to take on receipt of a command-line option.+ Input.CommandLineOption.CommandLineOption Input.Options.Options -- Defines the action to take on receipt of a command-line option. ) -- Pair. ] optDescrList = [@@ -235,12 +232,12 @@ defaultRandomSeed = 0 -- Unary options-mutators.- setPrintMoveTree, setVerbosity, setOutputConfigFilePath :: String -> Input.CategorisedCommandLineOptions.OptionsMutator Options+ setPrintMoveTree, setVerbosity, setOutputConfigFilePath :: String -> Input.CategorisedCommandLineOptions.OptionsMutator Input.Options.Options setPrintMoveTree = Input.Options.setMaybePrintMoveTree . Just . Input.CommandLineOption.readArg setVerbosity = Input.Options.setVerbosity . Input.CommandLineOption.readArg setOutputConfigFilePath = Input.Options.setMaybeOutputConfigFilePath . Just - setRandomSeed :: Maybe String -> Input.CategorisedCommandLineOptions.OptionsMutator Options+ setRandomSeed :: Maybe String -> Input.CategorisedCommandLineOptions.OptionsMutator Input.Options.Options setRandomSeed = Input.Options.setMaybeRandomSeed . Just . Data.Maybe.maybe defaultRandomSeed Input.CommandLineOption.readBoundedIntegral -- Nullary I/O-actions.@@ -259,14 +256,14 @@ showsVersion :: Data.Version.Version -> ShowS showsVersion = foldr (.) id . Data.List.intersperse (showChar '.') . map shows . Data.Version.versionBranch - checkPickler = Control.Monad.void . HXT.runX $ HXT.constA (Data.Default.def :: Options) >>> HXT.checkPickler HXT.xpickle+ checkPickler = Control.Monad.void . HXT.runX $ HXT.constA (Data.Default.def :: Input.Options.Options) >>> HXT.checkPickler HXT.xpickle generateDTD :: Maybe String -> Input.CategorisedCommandLineOptions.IOAction- generateDTD hxtTraceLevel = Control.Monad.void . HXT.runX $ HXT.constA (undefined :: Options) >>> HXT.xpickleWriteDTD HXT.xpickle [+ generateDTD hxtTraceLevel = Control.Monad.void . HXT.runX $ HXT.constA (undefined :: Input.Options.Options) >>> HXT.xpickleWriteDTD HXT.xpickle [ HXT.withTrace $ Data.Maybe.maybe 0 Input.CommandLineOption.readBoundedIntegral hxtTraceLevel -- Valid values in closed interval [0, 4] ] "-" {-stdout-} -- CAVEAT: this DTD requires manual correction of defaulted attributes, which are erroneously defined as 'REQUIRED' rather than 'IMPLIED'. - formatPieceSquareTableForGNUPlot :: Input.CategorisedCommandLineOptions.ContextualIOAction Options+ formatPieceSquareTableForGNUPlot :: Input.CategorisedCommandLineOptions.ContextualIOAction Input.Options.Options formatPieceSquareTableForGNUPlot options = Data.Maybe.maybe ( Control.Exception.throwIO $ Data.Exception.mkNullDatum "the piece-square table is undefined." ) (@@ -275,17 +272,17 @@ \gamePhase -> showChar Component.PieceSquareByCoordinatesByRank.gnuPlotComment . showString gamePhase . showString "-game:\n" ) ["Opening", "End"] ) $ map (- \selector -> Component.PieceSquareByCoordinatesByRank.formatForGNUPlot (+ \selector -> Component.PieceSquareByCoordinatesByRank.formatForGNUPlot pieceSquareByCoordinatesByRank ( Property.ShowFloat.showsFloatToN' ( Input.UIOptions.getNDecimalDigits . Input.IOOptions.getUIOptions $ Input.Options.getIOOptions options -- PieceSquareValue formatter. ) . (- realToFrac :: Type.Mass.PieceSquareValue -> Input.PieceSquareTable.IOFormat -- N.B.: required when compiled with 'USE_PRECISION'.+ realToFrac :: Type.Mass.PieceSquareValue -> Input.PieceSquareTable.IOFormat ) ) ( showChar '\t' -- Column-delimiter. ) ( ! selector Component.PieceSquareByCoordinatesByRank.nPiecesBounds -- Select from interpolated values.- ) pieceSquareByCoordinatesByRank+ ) ) [snd, fst] ) . Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank $ Input.Options.getEvaluationOptions options @@ -332,9 +329,9 @@ hxtTraceLevel :: Int hxtTraceLevel = fromEnum preVerbosity `min` 2 {-CAVEAT: HXT trace-levels 3 & 4 are too verbose-} - processInputOptions :: Options -> IO Options+ processInputOptions :: Input.Options.Options -> IO Input.Options.Options processInputOptions options = let- options' :: Options+ options' :: Input.Options.Options options' = ( \o -> ( if Data.Maybe.isNothing . Input.IOOptions.getMaybePersistence $ Input.Options.getIOOptions o@@ -428,7 +425,7 @@ ) ( \absolutePGNDatabaseFilePath -> either ( Control.Exception.throw . Data.Exception.mkParseFailure- ) id `fmap` ContextualNotation.PGNDatabase.parseIO absolutePGNDatabaseFilePath (+ ) id <$> ContextualNotation.PGNDatabase.parseIO absolutePGNDatabaseFilePath ( Input.PGNOptions.getMaybeDecompressor pgnOptions ) ( Input.PGNOptions.getIsStrictlySequential pgnOptions@@ -449,7 +446,7 @@ ) Property.Empty.empty {-QualifiedMoveForest-} (Input.IOOptions.getPGNOptionsList ioOptions) let- maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash)+ maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Type.Crypto.PositionHash) in Control.Monad.when ( verbosity /= minBound && Data.Maybe.isJust maybeApplicationTerminationReason ) . System.IO.hPutStrLn System.IO.stderr . showsInfoPrefix . showString "application terminated " $ shows (Data.Maybe.fromJust maybeApplicationTerminationReason) "."
− src-lib/BishBosh/Attribute/ANSIColourCode.hs
@@ -1,76 +0,0 @@-{-- Copyright (C) 2021 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Defines the encoding of colours for rendering on a terminal; <https://en.wikipedia.org/wiki/ANSI_escape_code>.--}--module BishBosh.Attribute.ANSIColourCode(--- * Types--- ** Type-synonyms--- ANSIColourCode(),--- IsBold,- GraphicsRendition,--- * Functions- selectGraphicsRendition,- bracket,--- ** Constructors- mkFgColourCode,- mkBgColourCode-) where--import qualified BishBosh.Attribute.PhysicalColour as Attribute.PhysicalColour-import qualified Data.Default---- | A colour-code as used by terminal-emulators.-newtype ANSIColourCode = MkANSIColourCode {- deconstruct :: Int-}--instance Show ANSIColourCode where- showsPrec precedence MkANSIColourCode { deconstruct = i } = showsPrec precedence i--instance Data.Default.Default ANSIColourCode where- def = MkANSIColourCode 0---- | The font-weight of a character.-type IsBold = Bool---- | An escape-sequence used to control a terminal.-type GraphicsRendition = String---- | Constructor: offset the specified colour-code, so that it applies to the foreground.-mkFgColourCode :: Attribute.PhysicalColour.PhysicalColour -> ANSIColourCode-mkFgColourCode = MkANSIColourCode . (+ 30) . fromEnum {-CAVEAT: relies on the PhysicalColour's constructor-order-}---- | Constructor: offset the specified colour-code, so that it applies to the background.-mkBgColourCode :: Attribute.PhysicalColour.PhysicalColour -> ANSIColourCode-mkBgColourCode = MkANSIColourCode . (+ 40) . fromEnum {-CAVEAT: relies on the PhysicalColour's constructor-order-}---- | Generate the escape-sequence required to change a terminal to the specified physical colour.-selectGraphicsRendition :: IsBold -> ANSIColourCode -> GraphicsRendition-selectGraphicsRendition isBold parameter = showString "\x1b[" . shows parameter $ (if isBold then showString ";1" else id) "m"---- | Render the specified string according to instructions, then revert to the default.-bracket :: GraphicsRendition -> String -> ShowS-bracket graphicsRendition s = showString graphicsRendition . showString s . showString (- selectGraphicsRendition False Data.Default.def- )-
− src-lib/BishBosh/Attribute/ColourScheme.hs
@@ -1,159 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Defines the physical colour used to represent each component of the board.--}--module BishBosh.Attribute.ColourScheme (--- * Types--- ** Data-types- ColourScheme(--- MkColourScheme,- getDarkPieceColour,- getLightPieceColour,- getDarkSquareColour,- getLightSquareColour- ),--- * Constants- tag,--- darkSquareColourTag,--- lightSquareColourTag,--- darkPieceColourTag,--- lightPieceColourTag,--- * Functions--- ** Constructor--- mkColourScheme-) where--import qualified BishBosh.Attribute.PhysicalColour as Attribute.PhysicalColour-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified Control.Arrow-import qualified Control.DeepSeq-import qualified Control.Exception-import qualified Data.Default-import qualified Text.XML.HXT.Arrow.Pickle as HXT---- | Used to qualify XML.-tag :: String-tag = "colourScheme"--darkPieceColourTag, darkSquareColourTag, lightPieceColourTag, lightSquareColourTag :: String-[darkPieceColourTag, darkSquareColourTag, lightPieceColourTag, lightSquareColourTag] = [showString brightness $ showString component "Colour" | brightness <- ["dark", "light"], component <- ["Piece", "Square"]] -- List-comprehension.---- | Defines the command-line options.-data ColourScheme = MkColourScheme {- getDarkPieceColour :: Attribute.PhysicalColour.PhysicalColour, -- ^ The physical colour of the dark pieces.- getLightPieceColour :: Attribute.PhysicalColour.PhysicalColour, -- ^ The physical colour of the light pieces.- getDarkSquareColour :: Attribute.PhysicalColour.PhysicalColour, -- ^ The physical colour of the dark squares of the board.- getLightSquareColour :: Attribute.PhysicalColour.PhysicalColour -- ^ The physical colour of the light squares of the board.-} deriving Eq--instance Control.DeepSeq.NFData ColourScheme where- rnf MkColourScheme {- getDarkPieceColour = darkPieceColour,- getLightPieceColour = lightPieceColour,- getDarkSquareColour = darkSquareColour,- getLightSquareColour = lightSquareColour- } = Control.DeepSeq.rnf (- darkPieceColour,- lightPieceColour,- darkSquareColour,- lightSquareColour- )--instance Show ColourScheme where- showsPrec _ MkColourScheme {- getDarkPieceColour = darkPieceColour,- getLightPieceColour = lightPieceColour,- getDarkSquareColour = darkSquareColour,- getLightSquareColour = lightSquareColour- } = Text.ShowList.showsAssociationList' $ map (Control.Arrow.second shows) [- (- darkPieceColourTag,- darkPieceColour- ), (- lightPieceColourTag,- lightPieceColour- ), (- darkSquareColourTag,- darkSquareColour- ), (- lightSquareColourTag,- lightSquareColour- )- ]--instance Data.Default.Default ColourScheme where- def = MkColourScheme {- getDarkPieceColour = Attribute.PhysicalColour.blue,- getLightPieceColour = Property.Opposable.getOpposite $ getDarkPieceColour Data.Default.def,- getDarkSquareColour = Attribute.PhysicalColour.black,- getLightSquareColour = Property.Opposable.getOpposite $ getDarkSquareColour Data.Default.def- }--instance HXT.XmlPickler ColourScheme where- xpickle = HXT.xpElem tag . HXT.xpWrap (- \(a, b, c, d) -> mkColourScheme a b c d, -- Construct.- \MkColourScheme {- getDarkPieceColour = darkPieceColour,- getLightPieceColour = lightPieceColour,- getDarkSquareColour = darkSquareColour,- getLightSquareColour = lightSquareColour- } -> (- darkPieceColour,- lightPieceColour,- darkSquareColour,- lightSquareColour- ) -- Deconstruct.- ) $ HXT.xp4Tuple (- getDarkPieceColour def `HXT.xpDefault` HXT.xpAttr darkPieceColourTag HXT.xpickle- ) (- getLightPieceColour def `HXT.xpDefault` HXT.xpAttr lightPieceColourTag HXT.xpickle- ) (- getDarkSquareColour def `HXT.xpDefault` HXT.xpAttr darkSquareColourTag HXT.xpickle- ) (- getLightSquareColour def `HXT.xpDefault` HXT.xpAttr lightSquareColourTag HXT.xpickle- ) where- def :: ColourScheme- def = Data.Default.def---- | Smart constructor.-mkColourScheme- :: Attribute.PhysicalColour.PhysicalColour -- ^ Dark piece.- -> Attribute.PhysicalColour.PhysicalColour -- ^ Light piece.- -> Attribute.PhysicalColour.PhysicalColour -- ^ Dark square.- -> Attribute.PhysicalColour.PhysicalColour -- ^ Light square.- -> ColourScheme-mkColourScheme darkPieceColour lightPieceColour darkSquareColour lightSquareColour- | darkPieceColour `elem` bgColours = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Attribute.ColourScheme.mkColourScheme:\t" . showString darkPieceColourTag . Text.ShowList.showsAssociation . shows darkPieceColour . showString " must differ from the physical colour of both squares; " $ shows bgColours "."- | lightPieceColour `elem` bgColours = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Attribute.ColourScheme.mkColourScheme:\t" . showString lightPieceColourTag . Text.ShowList.showsAssociation . shows lightPieceColour . showString " must differ from the physical colour of both squares; " $ shows bgColours "."- | darkSquareColour == lightSquareColour = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Attribute.ColourScheme.mkColourScheme:\tthe physical colours of " . shows lightSquareColourTag . showString " & " $ shows darkSquareColourTag ", must differ."- | otherwise = MkColourScheme {- getDarkPieceColour = darkPieceColour,- getLightPieceColour = lightPieceColour,- getDarkSquareColour = darkSquareColour,- getLightSquareColour = lightSquareColour- }- where- bgColours = [darkSquareColour, lightSquareColour]-
− src-lib/BishBosh/Attribute/Direction.hs
@@ -1,265 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Describes a /direction/ in two parts; the sense of change in the /x/-coordinate & the sense of change in the /y/-coordinate.-- * The IO-format uses a more concise & familiar format based on 8 points of the compass.-- * CAVEAT: this separation of /direction/ into orthogonal components is driven by the typical use-case,- but requires that one guards against accidental construction of a degenerate 9th /direction/ which defines a change in neither direction.--}--module BishBosh.Attribute.Direction(--- * Types--- ** Type-synonyms- ArrayByDirection,--- ** Data-types- Direction(--- MkDirection,- getXDirection,- getYDirection- ),--- * Constants- nw,- n,- ne,- w,- e,- sw,- s,- se,- tag,- nDistinctDirections,- parallels,- diagonals,--- range,- opposites,--- * Functions--- getOpposite,- advanceDirection,- attackDirectionsForPawn,- listArrayByDirection,--- ** Constructor- mkDirection,--- ** Predicates- areAligned-) where--import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Orientated as Property.Orientated-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Type.Count as Type.Count-import qualified Control.DeepSeq-import qualified Control.Exception-import qualified Data.Array.IArray-import qualified Data.List.Extra-import qualified Text.XML.HXT.Arrow.Pickle as HXT-import qualified Text.XML.HXT.Arrow.Pickle.Schema---- | Used to qualify XML.-tag :: String-tag = "direction"---- | Constant direction.-nw :: Direction-nw = MkDirection LT GT---- | Constant direction.-n :: Direction-n = MkDirection EQ GT---- | Constant direction.-ne :: Direction-ne = MkDirection GT GT---- | Constant direction.-w :: Direction-w = MkDirection LT EQ---- | Constant direction.-e :: Direction-e = MkDirection GT EQ---- | Constant direction.-sw :: Direction-sw = MkDirection LT LT---- | Constant direction.-s :: Direction-s = MkDirection EQ LT---- | Constant direction.-se :: Direction-se = MkDirection GT LT---- | Define a /direction/ by the sense of change to /x/ & /y/ coordinates.-data Direction = MkDirection {- getXDirection :: ! Ordering, -- ^ The sense of the change in the /x/-coordinate.- getYDirection :: ! Ordering -- ^ The sense of the change in the /y/-coordinate.-} deriving (Eq, Ord)--instance Bounded Direction where- minBound = sw- maxBound = ne--instance Control.DeepSeq.NFData Direction where- rnf MkDirection {- getXDirection = xDirection,- getYDirection = yDirection- } = xDirection `seq` yDirection `seq` ()--instance Show Direction where- showsPrec _ MkDirection {- getXDirection = xDirection,- getYDirection = yDirection- } = (- case yDirection of- LT -> showChar 'S'- EQ -> id- GT -> showChar 'N'- ) . (- case xDirection of- LT -> showChar 'W'- EQ -> id- GT -> showChar 'E'- )--instance Read Direction where- readsPrec _ ss = let- s' = Data.List.Extra.trimStart ss- in case Data.List.Extra.upper s' of- 'S' : remainder -> case remainder of- 'W' : _ -> [(sw, drop 2 s')]- 'E' : _ -> [(se, drop 2 s')]- _ -> [(s, tail s')]- 'N' : remainder -> case remainder of- 'W' : _ -> [(nw, drop 2 s')]- 'E' : _ -> [(ne, drop 2 s')]- _ -> [(n, tail s')]- 'W' : _ -> [(w, tail s')]- 'E' : _ -> [(e, tail s')]- _ -> [] -- No parse.--instance Property.Opposable.Opposable Direction where- getOpposite MkDirection {- getXDirection = xDirection,- getYDirection = yDirection- } = MkDirection {- getXDirection = Property.Opposable.getOpposite xDirection,- getYDirection = Property.Opposable.getOpposite yDirection- }--instance Property.Orientated.Orientated Direction where- isDiagonal MkDirection { getXDirection = xDirection, getYDirection = yDirection } = xDirection /= EQ && yDirection /= EQ- isParallel MkDirection { getXDirection = xDirection, getYDirection = yDirection } = xDirection == EQ || yDirection == EQ- isStraight = const True--instance Property.Reflectable.ReflectableOnX Direction where- reflectOnX direction@MkDirection { getYDirection = yDirection } = direction {- getYDirection = Property.Opposable.getOpposite yDirection- }--instance Property.Reflectable.ReflectableOnY Direction where- reflectOnY direction@MkDirection { getXDirection = xDirection } = direction {- getXDirection = Property.Opposable.getOpposite xDirection- }--instance HXT.XmlPickler Direction where- xpickle = HXT.xpWrap (read, show) . HXT.xpAttr tag . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range--instance Data.Array.IArray.Ix Direction where- range (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) Property.FixedMembership.members- inRange (lower, upper) _ = Control.Exception.assert (lower == minBound && upper == maxBound) True- index (lower, upper) (MkDirection xDirection yDirection) = Control.Exception.assert (lower == minBound && upper == maxBound) $ case xDirection of- LT -> case yDirection of- LT -> 0- EQ -> 1- GT -> 2- EQ -> case yDirection of- LT -> 3- EQ -> Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.Attribute.Direction.index:\tundefined direction."- GT -> 4- GT -> case yDirection of- LT -> 5- EQ -> 6- GT -> 7---- | The ordered /direction/s in which /royalty/ can move.-range :: [Direction]-range = [sw, w, nw, s, n, se, e, ne]--instance Property.FixedMembership.FixedMembership Direction where- members = range---- | Smart constructor.-mkDirection- :: Ordering -- ^ The sense of the change in the /x/-coordinate.- -> Ordering -- ^ The sense of the change in the /y/-coordinate.- -> Direction-mkDirection EQ EQ = Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.Attribute.Direction.mkDirection:\till-defined."-mkDirection xDirection yDirection = MkDirection xDirection yDirection---- | The ordered /direction/s in which a @Rook@ can move.-parallels :: [Direction]-parallels = [w, s, n, e]---- | The ordered /direction/s in which a @Bishop@ can move.-diagonals :: [Direction]-diagonals = [sw, nw, se, ne]---- | The constant number of distinct /direction/s.-nDistinctDirections :: Type.Count.NDirections-nDistinctDirections = fromIntegral $ length range--{- |- * Returns a list of /direction/s, each paired with its anti-parallel.-- * CAVEAT: each /direction/ only appears once in the list, on an arbitrary side of a pair.--}-opposites :: [(Direction, Direction)]-opposites = map (id &&& Property.Opposable.getOpposite) [sw, w, nw, s]---- | The /y/-direction in which a @Pawn@ of the specified /logical colour/ advances.-advanceDirection :: Attribute.LogicalColour.LogicalColour -> Ordering-advanceDirection Attribute.LogicalColour.Black = LT -- Black moves down.-advanceDirection _ = GT -- White moves up.---- | The /direction/s in which a @Pawn@ can attack.-attackDirectionsForPawn :: Attribute.LogicalColour.LogicalColour -> [Direction]-attackDirectionsForPawn logicalColour = map (`MkDirection` advanceDirection logicalColour) [LT, GT]---- | Whether the two /direction/s specified, are either parallel or anti-parallel.-areAligned :: Direction -> Direction -> Bool-areAligned direction = uncurry (||) . ((== direction) &&& (== Property.Opposable.getOpposite direction))---- | A boxed array indexed by /direction/, of arbitrary elements.-type ArrayByDirection = Data.Array.IArray.Array {-Boxed-} Direction---- | Array-constructor.-listArrayByDirection :: Data.Array.IArray.IArray a e => [e] -> a Direction e-listArrayByDirection = Data.Array.IArray.listArray (minBound, maxBound)-
− src-lib/BishBosh/Attribute/LogicalColour.hs
@@ -1,144 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines the data-type which represents the logical (rather than physical) colour of /piece/s & (conceptually) of the two players.-- * N.B.: conceptually different from the logical colour of squares on the board.--}--module BishBosh.Attribute.LogicalColour(--- * Types--- ** Type-synonyms- ArrayByLogicalColour,- UArrayByLogicalColour,--- ** Data-types- LogicalColour(..),--- * Constants- tag,- range,- nDistinctLogicalColours,--- * Functions--- ** Constructor- listArrayByLogicalColour,- arrayByLogicalColour,--- ** Predicates- isBlack--- isWhite-) where--import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Type.Count as Type.Count-import qualified Control.DeepSeq-import qualified Control.Exception-import qualified Data.Array.IArray-import qualified Data.Array.Unboxed-import qualified Data.List.Extra-import qualified Text.XML.HXT.Arrow.Pickle as HXT-import qualified Text.XML.HXT.Arrow.Pickle.Schema---- | Used to qualify XML.-tag :: String-tag = "logicalColour"---- | The sum-type of /logical colour/s associated with either a piece, or (conceptually) a player.-data LogicalColour- = Black- | White- deriving (- Bounded,- Enum,- Eq,- Ord,- Read,- Show- )--instance Control.DeepSeq.NFData LogicalColour where- rnf _ = ()--instance Data.Array.IArray.Ix LogicalColour where- range (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) range- inRange (lower, upper) logicalColour = Control.Exception.assert (logicalColour >= lower && logicalColour <= upper) True- index (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) . fromEnum---- | The constant ascending range of /logical colour/s.-range :: [LogicalColour]-range = [minBound, maxBound]--instance Property.FixedMembership.FixedMembership LogicalColour where- members = range---- | The constant number of distinct /logical colour/s.-nDistinctLogicalColours :: Type.Count.NLogicalColours-nDistinctLogicalColours = fromIntegral $ length range--instance HXT.XmlPickler LogicalColour where- xpickle = HXT.xpAttr tag . HXT.xpWrap (read, show) . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range--instance Property.Opposable.Opposable LogicalColour where- getOpposite Black = White- getOpposite _ = Black--instance Property.ExtendedPositionDescription.ReadsEPD LogicalColour where- readsEPD s = case Data.List.Extra.trimStart s of- 'b' : remainder -> [(Black, remainder)]- 'w' : remainder -> [(White, remainder)]- _ -> []--instance Property.ExtendedPositionDescription.ShowsEPD LogicalColour where- showsEPD = showChar . \case- Black -> 'b'- White -> 'w'--instance Property.ForsythEdwards.ReadsFEN LogicalColour--instance Property.ForsythEdwards.ShowsFEN LogicalColour---- | Whether the specified /logical colour/ is @Black@.-isBlack :: LogicalColour -> Bool-{-# INLINE isBlack #-}-isBlack Black = True-isBlack _ = False---- | Whether the specified /logical colour/ is @White@.-isWhite :: LogicalColour -> Bool-isWhite = not . isBlack---- | A boxed array indexed by /logical colour/, of arbitrary elements.-type ArrayByLogicalColour = Data.Array.IArray.Array LogicalColour---- | An unboxed array indexed by /logical colour/, of fixed-size values.-type UArrayByLogicalColour = Data.Array.Unboxed.UArray LogicalColour---- | Array-constructor from an ordered list of elements.-listArrayByLogicalColour :: Data.Array.IArray.IArray a e => [e] -> a LogicalColour e-listArrayByLogicalColour = Data.Array.IArray.listArray (minBound, maxBound)---- | Array-constructor from an association-list.-arrayByLogicalColour :: Data.Array.IArray.IArray a e => [(LogicalColour, e)] -> a LogicalColour e-arrayByLogicalColour = Data.Array.IArray.array (minBound, maxBound)-
− src-lib/BishBosh/Attribute/LogicalColourOfSquare.hs
@@ -1,59 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines the data-type which represents the logical (rather than physical) colour of the squares on a chess-board.-- * N.B.: conceptually different from the logical colour of pieces.--}--module BishBosh.Attribute.LogicalColourOfSquare(--- * Types--- ** Data-type- LogicalColourOfSquare(),--- * Constants- black,- white,--- * Functions--- ** Predicate- isBlack-) where--import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour---- | The logical colour of a square of the board, cf. of a piece or (conceptually) of a player.-newtype LogicalColourOfSquare = MkLogicalColourOfSquare {- deconstruct :: Attribute.LogicalColour.LogicalColour-} deriving (Eq, Bounded)---- | Constant.-black :: LogicalColourOfSquare-black = MkLogicalColourOfSquare Attribute.LogicalColour.Black---- | Constant.-white :: LogicalColourOfSquare-white = MkLogicalColourOfSquare Attribute.LogicalColour.White---- | Whether the specified /logical colour/ is @Black@.-isBlack :: LogicalColourOfSquare -> Bool-isBlack MkLogicalColourOfSquare { deconstruct = logicalColour } = Attribute.LogicalColour.isBlack logicalColour-
src-lib/BishBosh/Attribute/MoveType.hs view
@@ -45,7 +45,6 @@ -- ** Predicates isCastle, isEnPassant,--- isNormal, isCapture, isPromotion, isQuiet,@@ -53,7 +52,8 @@ isAcyclic, -- ** Query getMaybeExplicitlyTakenRank,- getMaybeImplicitlyTakenRank+ getMaybeImplicitlyTakenRank,+ getMaybePromotedRank ) where import qualified BishBosh.Attribute.Rank as Attribute.Rank@@ -210,11 +210,6 @@ isEnPassant EnPassant = True isEnPassant _ = False --- | Whether the /move/ was neither @EnPassant@ nor @Castle@.-isNormal :: MoveType -> Bool-isNormal (Normal _ _) = True-isNormal _ = False- -- | Whether a piece was captured, including @Pawn@s taken En-passant. isCapture :: MoveType -> Bool {-# INLINE isCapture #-}@@ -223,8 +218,7 @@ -- | Whether the /move/ includes @Pawn@-promotion. isPromotion :: MoveType -> Bool-isPromotion Normal { getMaybePromotionRank = Just _ } = True-isPromotion _ = False+isPromotion = Data.Maybe.isJust . getMaybePromotedRank -- | <https://www.chessprogramming.org/Quiet_Moves>. isQuiet :: MoveType -> Bool@@ -248,11 +242,7 @@ * CAVEAT: one can't infer from a negative result that the move can be repeated, since the mover may have been a @Pawn@. -} isAcyclic :: MoveType -> Bool-isAcyclic Normal {- getMaybeTakenRank = Nothing,- getMaybePromotionRank = Nothing-} = False-isAcyclic _ = True+isAcyclic = not . isSimple -- Neither capture, promotion, castling nor en-passant can be repeated. -- | Query whether a /piece/ was explicitly taken, excluding @Pawn@s taken En-passant. getMaybeExplicitlyTakenRank :: MoveType -> Maybe Attribute.Rank.Rank@@ -263,6 +253,11 @@ getMaybeImplicitlyTakenRank :: MoveType -> Maybe Attribute.Rank.Rank getMaybeImplicitlyTakenRank EnPassant = Just Attribute.Rank.Pawn getMaybeImplicitlyTakenRank moveType = getMaybeExplicitlyTakenRank moveType++-- | Query the rank to which a piece was promoted.+getMaybePromotedRank :: MoveType -> Maybe Attribute.Rank.Rank+getMaybePromotedRank Normal { getMaybePromotionRank = maybePromotionRank } = maybePromotionRank+getMaybePromotedRank _ = Nothing -- | Returns the mutator required to adjust the number of pieces after a move. nPiecesMutator :: Enum nPieces => MoveType -> (nPieces -> nPieces)
− src-lib/BishBosh/Attribute/PhysicalColour.hs
@@ -1,119 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines the data-type which represents the physical (rather than logical) colour of the /board/ & of /piece/s.-- * The number of physical colours used to represent the /board/ & /piece/s can be greater than the two /logical colour/s required,- but is limited in practice, since the terminal (optionally) used to render the image, typically can't cope with with a large number.--}--module BishBosh.Attribute.PhysicalColour(--- * Types--- ** Data-types- PhysicalColour(),--- * Constants--- range,- black,- red,- green,- yellow,- blue,- magenta,- cyan,- white-) where--import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Control.DeepSeq-import qualified Text.XML.HXT.Arrow.Pickle as HXT-import qualified Text.XML.HXT.Arrow.Pickle.Schema--{- |- * Defines the sum-type of physical colours which can typically be rendered by a terminal.-- * CAVEAT: the constructor-order both facilitates conversion to an ANSI Colour-code & the derivation of the complementary colour.--}-data PhysicalColour- = Black- | Red- | Green- | Yellow- | Blue- | Magenta- | Cyan- | White- deriving (Enum, Eq, Read, Show)--instance Control.DeepSeq.NFData PhysicalColour where- rnf _ = ()--instance Bounded PhysicalColour where- minBound = black- maxBound = white--instance HXT.XmlPickler PhysicalColour where- xpickle = HXT.xpWrap (read, show) . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range--instance Property.Opposable.Opposable PhysicalColour where- getOpposite physicalColour = toEnum $ fromEnum (maxBound :: PhysicalColour) - fromEnum physicalColour -- N.B. the complementary colour---- | The constant complete range of values.-range :: [PhysicalColour]-range = [minBound .. maxBound]--instance Property.FixedMembership.FixedMembership PhysicalColour where- members = range---- | Constant.-black :: PhysicalColour-black = Black---- | Constant.-red :: PhysicalColour-red = Red---- | Constant.-green :: PhysicalColour-green = Green---- | Constant.-yellow :: PhysicalColour-yellow = Yellow---- | Constant.-blue :: PhysicalColour-blue = Blue---- | Constant.-magenta :: PhysicalColour-magenta = Magenta---- | Constant.-cyan :: PhysicalColour-cyan = Cyan---- | Constant.-white :: PhysicalColour-white = White-
src-lib/BishBosh/Attribute/Rank.hs view
@@ -31,7 +31,6 @@ -- ** Type-synonyms EvaluateRank, ArrayByRank,- UArrayByRank, -- ** Data-types Rank(..), -- * Constants@@ -64,7 +63,6 @@ import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray-import qualified Data.Array.Unboxed import qualified Data.Char import qualified Data.List import qualified Data.Ord@@ -208,9 +206,6 @@ -- | A boxed array indexed by /rank/, of arbitrary values. type ArrayByRank = Data.Array.IArray.Array Rank---- | An unboxed array indexed by /rank/, of fixed-size values.-type UArrayByRank = Data.Array.Unboxed.UArray Rank -- | Array-constructor from an ordered list of elements. listArrayByRank :: Data.Array.IArray.IArray a e => [e] -> a Rank e
src-lib/BishBosh/Cartesian/Coordinates.hs view
@@ -34,7 +34,9 @@ -- ** Type-synonyms -- Transformation, ArrayByCoordinates,--- UArrayByCoordinates,+#ifdef USE_UNBOXED_ARRAYS+ UArrayByCoordinates,+#endif -- * Constants tag, topLeft,@@ -45,6 +47,7 @@ -- * Functions -- extrapolate', extrapolate,+ applyAlongDirectionsFrom, interpolate, getLogicalColourOfSquare, kingsStartingCoordinates,@@ -61,12 +64,9 @@ -- maybeAdvance, retreat, maybeRetreat,--- rotate, -- ** Constructors mkCoordinates, mkMaybeCoordinates,--- toIx,- fromIx, mkRelativeCoordinates, listArrayByCoordinates, arrayByCoordinates,@@ -79,32 +79,35 @@ import Control.Arrow((&&&), (***)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Attribute.LogicalColourOfSquare as Attribute.LogicalColourOfSquare-import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa-import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Property.Rotatable as Property.Rotatable-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa+import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Colour.LogicalColourOfSquare as Colour.LogicalColourOfSquare+import qualified BishBosh.Direction.Direction as Direction.Direction+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.Rotatable as Property.Rotatable+import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Type.Length as Type.Length+import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray-import qualified Data.Array.Unboxed import qualified Data.Foldable import qualified Data.List-import qualified Data.Map as Map+import qualified Data.Map as Map import qualified Data.Maybe #ifdef USE_PARALLEL import qualified Control.Parallel.Strategies #endif +#ifdef USE_UNBOXED_ARRAYS+import qualified Data.Array.Unboxed+#endif+ -- | Used to qualify XML. tag :: String tag = "coordinates"@@ -115,22 +118,6 @@ getY :: ! Type.Length.Y -- ^ Ordinate. } deriving Eq -instance Control.DeepSeq.NFData Coordinates where- rnf MkCoordinates { getX = x, getY = y } = Control.DeepSeq.rnf (x, y)--instance Show Coordinates where- showsPrec precedence MkCoordinates { getX = x, getY = y } = showsPrec precedence (x, y)--instance Read Coordinates where- readsPrec precedence s = [- (coordinates, remainder) |- ((x, y), remainder) <- readsPrec precedence s,- coordinates <- Data.Maybe.maybeToList $ mkMaybeCoordinates x y- ] -- List-comprehension.--instance Ord Coordinates where- MkCoordinates { getX = x, getY = y } `compare` MkCoordinates { getX = x', getY = y' } = (y, x) `compare` (y', x') -- N.B.: x is less significant than y, as required by the implementation of 'Data.Array.IArray.Ix.inRange'.- instance Bounded Coordinates where minBound = MkCoordinates { getX = Cartesian.Abscissa.xMin,@@ -141,11 +128,48 @@ getY = Cartesian.Ordinate.yMax } -- Top Right. +instance Control.DeepSeq.NFData Coordinates where+ rnf MkCoordinates { getX = x, getY = y } = Control.DeepSeq.rnf (x, y)+ instance Data.Array.IArray.Ix Coordinates where range (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) Property.FixedMembership.members inRange (lower, upper) coordinates = Control.Exception.assert (coordinates >= lower && coordinates <= upper) True- index (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) . toIx+ index (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) . fromEnum +instance Enum Coordinates where+ toEnum = (+ \(y, x) -> MkCoordinates {+ getX = Cartesian.Abscissa.fromIx x,+ getY = Cartesian.Ordinate.fromIx y+ }+ ) . (`divMod` fromIntegral Cartesian.Abscissa.xLength)++ fromEnum MkCoordinates {+ getX = x,+ getY = y+ } = fromIntegral Cartesian.Abscissa.xLength * Cartesian.Ordinate.toIx y + Cartesian.Abscissa.toIx x++instance Ord Coordinates where+ MkCoordinates { getX = x, getY = y } `compare` MkCoordinates { getX = x', getY = y' } = (y, x) `compare` (y', x') -- N.B.: x is less significant than y, as required by the implementation of 'Data.Array.IArray.Ix.inRange'.++instance Show Coordinates where+ showsPrec precedence MkCoordinates { getX = x, getY = y } = showsPrec precedence (x, y)++instance Read Coordinates where+ readsPrec precedence s = [+ (coordinates, remainder) |+ (Just coordinates, remainder) <- Control.Arrow.first (uncurry mkMaybeCoordinates) `map` readsPrec precedence s+ ] -- List-comprehension.++instance Property.Opposable.Opposable Coordinates where+ getOpposite MkCoordinates {+ getX = x,+ getY = y+ } = MkCoordinates {+ getX = Cartesian.Abscissa.reflect x,+ getY = Cartesian.Ordinate.reflect y+ }+ instance Property.Reflectable.ReflectableOnX Coordinates where reflectOnX coordinates@MkCoordinates { getY = y } = coordinates { getY = Cartesian.Ordinate.reflect y } @@ -153,9 +177,21 @@ reflectOnY coordinates@MkCoordinates { getX = x } = coordinates { getX = Cartesian.Abscissa.reflect x } instance Property.Rotatable.Rotatable Coordinates where- rotate90 = rotate Attribute.Direction.w- rotate180 = rotate Attribute.Direction.s- rotate270 = rotate Attribute.Direction.e+ rotate90 MkCoordinates {+ getX = x,+ getY = y+ } = MkCoordinates {+ getX = fromIntegral $! Cartesian.Ordinate.reflect y,+ getY = fromIntegral x+ } -- +90 degrees, i.e. anti-clockwise.+ rotate180 = Property.Opposable.getOpposite+ rotate270 MkCoordinates {+ getX = x,+ getY = y+ } = MkCoordinates {+ getX = fromIntegral y,+ getY = fromIntegral $! Cartesian.Abscissa.reflect x+ } -- -90 degrees, i.e. clockwise. -- | Constant. topLeft :: Coordinates@@ -208,32 +244,15 @@ | inBounds x y = Just MkCoordinates { getX = x, getY = y } | otherwise = Nothing --- | Convert to an array-index.-toIx :: Coordinates -> Int-toIx MkCoordinates {- getX = x,- getY = y-} = fromIntegral Cartesian.Abscissa.xLength * Cartesian.Ordinate.toIx y + Cartesian.Abscissa.toIx x--{- |- * Construct from the specified array-index.-- * CAVEAT: assumes that the array is indexed by the whole range of /coordinates/.--}-fromIx :: Int -> Coordinates-fromIx = (- \(y, x) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx x,- getY = Cartesian.Ordinate.fromIx y- }- ) . (`divMod` fromIntegral Cartesian.Abscissa.xLength)+-- | The type of a function which changes one set of /coordinates/ to another.+type Transformation = Coordinates -> Coordinates {- | * Translate the specified /coordinates/ using the specified mapping. * CAVEAT: the caller must ensure that the results are legal. -}-translate :: ((Type.Length.X, Type.Length.Y) -> (Type.Length.X, Type.Length.Y)) -> Coordinates -> Coordinates+translate :: ((Type.Length.X, Type.Length.Y) -> (Type.Length.X, Type.Length.Y)) -> Transformation translate transformation MkCoordinates { getX = x, getY = y@@ -259,7 +278,7 @@ :: (Type.Length.X -> Type.Length.X) -- ^ Translation. -> Coordinates -> Maybe Coordinates-maybeTranslateX transformation coordinates@MkCoordinates { getX = x } = (\x' -> coordinates { getX = x' }) `fmap` Cartesian.Abscissa.maybeTranslate transformation x+maybeTranslateX transformation coordinates@MkCoordinates { getX = x } = (\x' -> coordinates { getX = x' }) <$> Cartesian.Abscissa.maybeTranslate transformation x {- | * Translate the specified ordinate.@@ -274,7 +293,7 @@ :: (Type.Length.Y -> Type.Length.Y) -- ^ Translation. -> Coordinates -> Maybe Coordinates-maybeTranslateY transformation coordinates@MkCoordinates { getY = y } = (\y' -> coordinates { getY = y' }) `fmap` Cartesian.Ordinate.maybeTranslate transformation y+maybeTranslateY transformation coordinates@MkCoordinates { getY = y } = (\y' -> coordinates { getY = y' }) <$> Cartesian.Ordinate.maybeTranslate transformation y {- | * Construct /coordinates/ relative to 'minBound'.@@ -290,18 +309,18 @@ * CAVEAT: the caller must ensure that the results are legal. -} advance- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance.+ :: Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance. -> Transformation-advance logicalColour = translateY $ if Attribute.LogicalColour.isBlack logicalColour+advance logicalColour = translateY $ if Colour.LogicalColour.isBlack logicalColour then pred else succ -- | Where legal, move one step towards the opponent. maybeAdvance- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance.+ :: Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance. -> Coordinates -- ^ The location from which to advanced. -> Maybe Coordinates-maybeAdvance logicalColour = maybeTranslateY $ if Attribute.LogicalColour.isBlack logicalColour+maybeAdvance logicalColour = maybeTranslateY $ if Colour.LogicalColour.isBlack logicalColour then pred else succ @@ -311,13 +330,13 @@ * CAVEAT: the caller must ensure that the results are legal. -} retreat- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat.+ :: Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat. -> Transformation retreat = advance . Property.Opposable.getOpposite -- | Where legal, move one step away from the opponent. maybeRetreat- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat.+ :: Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat. -> Coordinates -- ^ The location from which to retreat. -> Maybe Coordinates maybeRetreat = maybeAdvance . Property.Opposable.getOpposite@@ -328,24 +347,41 @@ -- | Generates a line of /coordinates/, starting just after the specified source & proceeding in the specified /direction/ to the edge of the board. extrapolate'- :: Attribute.Direction.Direction -- ^ The direction in which to proceed.- -> Coordinates -- ^ The point from which to start.+ :: Coordinates -- ^ The point from which to start.+ -> Direction.Direction.Direction -- ^ The direction in which to proceed. -> [Coordinates]-extrapolate' direction MkCoordinates {+extrapolate' MkCoordinates { getX = x, getY = y-} = zipWith MkCoordinates (- case Attribute.Direction.getXDirection direction of- GT -> [succ x .. Cartesian.Abscissa.xMax]- LT -> let startX = pred x in startX `seq` [startX, pred startX .. Cartesian.Abscissa.xMin]- EQ -> repeat x- ) (- case Attribute.Direction.getYDirection direction of- GT -> [succ y .. Cartesian.Ordinate.yMax]- LT -> let startY = pred y in startY `seq` [startY, pred startY .. Cartesian.Ordinate.yMin]- EQ -> repeat y- )+} direction = uncurry (zipWith MkCoordinates) $ if Property.Orientated.isParallel direction+ then if Property.Orientated.isVertical direction+ then doVertical+ else doHorizontal+ else doDiagonal+ where+ xIncreasing, xDecreasing :: [Type.Length.X]+ xIncreasing = [succ x .. Cartesian.Abscissa.xMax]+ xDecreasing = let startX = pred x in startX `seq` [startX, pred startX .. Cartesian.Abscissa.xMin] + yIncreasing, yDecreasing :: [Type.Length.Y]+ yIncreasing = [succ y .. Cartesian.Ordinate.yMax]+ yDecreasing = let startY = pred y in startY `seq` [startY, pred startY .. Cartesian.Ordinate.yMin]++ doVertical, doHorizontal, doDiagonal :: ([Type.Length.X], [Type.Length.Y])+ doVertical = (+ repeat x,+ if direction == Direction.Direction.s then yDecreasing else yIncreasing+ ) -- Pair.+ doHorizontal = (+ if direction == Direction.Direction.w then xDecreasing else xIncreasing,+ repeat y+ ) -- Pair.+ doDiagonal+ | direction == Direction.Direction.sw = (xDecreasing, yDecreasing)+ | direction == Direction.Direction.se = (xIncreasing, yDecreasing)+ | direction == Direction.Direction.nw = (xDecreasing, yIncreasing)+ | otherwise {-NE-} = (xIncreasing, yIncreasing)+ {- | * Generates a line of /coordinates/, starting just after the specified source & proceeding in the specified /direction/ to the edge of the board. @@ -353,22 +389,34 @@ In consequence, it is typically automatically avoided using a rewrite-rule to lookup an array of the results from all possible calls. -} extrapolate- :: Attribute.Direction.Direction -- ^ The direction in which to proceed.- -> Coordinates -- ^ The point from which to start.+ :: Coordinates -- ^ The point from which to start.+ -> Direction.Direction.Direction -- ^ The direction in which to proceed. -> [Coordinates]-extrapolate direction coordinates = extrapolationsByDirectionByCoordinates ! coordinates ! direction+extrapolate coordinates direction = extrapolationsByDirectionByCoordinates ! coordinates ! direction -- | The constant lists of /coordinates/, extrapolated from every /coordinate/ in the /board/, in every /direction/.-extrapolationsByDirectionByCoordinates :: ArrayByCoordinates (Attribute.Direction.ArrayByDirection [Coordinates])+extrapolationsByDirectionByCoordinates :: ArrayByCoordinates (Direction.Direction.ArrayByDirection [Coordinates]) extrapolationsByDirectionByCoordinates = listArrayByCoordinates #ifdef USE_PARALLEL . Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq) #endif $ map (- \coordinates -> Attribute.Direction.listArrayByDirection $ map (`extrapolate'` coordinates) Property.FixedMembership.members- ) Property.FixedMembership.members+ \coordinates -> Direction.Direction.listArrayByDirection $ extrapolate' coordinates `map` Property.FixedMembership.members {-direction-}+ ) Property.FixedMembership.members {-coordinates-} --- | The list of /coordinates/, between every permutation of source & valid destination on the /board/.+-- | Apply the specified function to each line of /coordinates/ extrapolated from the specified central hub, in each of the specified /direction/s.+applyAlongDirectionsFrom+ :: ([Coordinates] -> [a]) -- ^ Individually map each straight line of coordinates extrapolated from the central hub.+ -> Coordinates -- ^ The central hub from which to extrapolate.+ -> Maybe [Direction.Direction.Direction] -- ^ The directions in which to extrapolate; 'Nothing' implies omnidirectional.+ -> [a]+applyAlongDirectionsFrom f from = Data.Maybe.maybe (+ Data.Foldable.foldMap f $ extrapolationsByDirectionByCoordinates ! from -- Traverse all directions from this coordinate, without repeatedly converting direction to an array-index.+ ) (+ concatMap $ f . (extrapolationsByDirectionByCoordinates ! from !)+ )++-- | The constant lists of /coordinates/, between every permutation of source & valid destination on the /board/. interpolationsByDestinationBySource :: ArrayByCoordinates (Map.Map Coordinates [Coordinates]) interpolationsByDestinationBySource = Data.Array.IArray.amap ( Map.fromList . map (@@ -386,40 +434,7 @@ interpolate :: Coordinates -> Coordinates -> [Coordinates] interpolate coordinatesSource coordinatesDestination = interpolationsByDestinationBySource ! coordinatesSource Map.! coordinatesDestination --- | The type of a function which changes one set of /coordinates/ to another.-type Transformation = Coordinates -> Coordinates- {- |- * Rotates the specified /coordinates/, so that the @Black@ pieces start on the specified side of the board; a /direction/ of @N@ involves no change.-- * CAVEAT: one can only request an integral multiple of 90 degrees.--}-rotate :: Attribute.Direction.Direction -> Transformation-rotate direction coordinates@MkCoordinates {- getX = x,- getY = y-} = case Attribute.Direction.getXDirection &&& Attribute.Direction.getYDirection $ direction of- (EQ, GT) -> coordinates- (LT, EQ) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx yDistance',- getY = Cartesian.Ordinate.fromIx xDistance- } -- +90 degrees, i.e. anti-clockwise.- (EQ, LT) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx xDistance',- getY = Cartesian.Ordinate.fromIx yDistance'- } -- 180 degrees.- (GT, EQ) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx yDistance,- getY = Cartesian.Ordinate.fromIx xDistance'- } -- -90 degrees, i.e. clockwise.- _ -> Control.Exception.throw . Data.Exception.mkRequestFailure . showString "BishBosh.Cartesian.Coordinates.rotate:\tunable to rotate to direction" . Text.ShowList.showsAssociation $ shows direction "."- where- xDistance = Cartesian.Abscissa.toIx x- yDistance = Cartesian.Ordinate.toIx y- xDistance' = fromIntegral (pred Cartesian.Abscissa.xLength) - xDistance- yDistance' = fromIntegral (pred Cartesian.Ordinate.yLength) - yDistance--{- | * Measures the signed distance between source & destination /coordinates/. * N.B.: this isn't the /irrational/ distance a rational crow would fly, but rather the integral /x/ & /y/ components of that path.@@ -439,42 +454,44 @@ } = (x' - x, y' - y) -- | The /logical colour/ of the specified square.-getLogicalColourOfSquare :: Coordinates -> Attribute.LogicalColourOfSquare.LogicalColourOfSquare+getLogicalColourOfSquare :: Coordinates -> Colour.LogicalColourOfSquare.LogicalColourOfSquare getLogicalColourOfSquare coordinates | uncurry (==) . ( even *** even- ) $ measureDistance minBound coordinates = Attribute.LogicalColourOfSquare.black- | otherwise = Attribute.LogicalColourOfSquare.white+ ) $ measureDistance minBound coordinates = Colour.LogicalColourOfSquare.black+ | otherwise = Colour.LogicalColourOfSquare.white -- | Whether the specified squares have the same /logical colour/. areSquaresIsochromatic :: [Coordinates] -> Bool areSquaresIsochromatic = uncurry (||) . (all (== minBound) &&& all (== maxBound)) . map getLogicalColourOfSquare -- | The conventional starting /coordinates/ for the @King@ of the specified /logical colour/.-kingsStartingCoordinates :: Attribute.LogicalColour.LogicalColour -> Coordinates+kingsStartingCoordinates :: Colour.LogicalColour.LogicalColour -> Coordinates kingsStartingCoordinates logicalColour = MkCoordinates { getX = Cartesian.Abscissa.kingsFile, getY = Cartesian.Ordinate.firstRank logicalColour } -- | The conventional starting /coordinates/ for each @Rook@.-rooksStartingCoordinates :: Attribute.LogicalColour.LogicalColour -> [Coordinates]-rooksStartingCoordinates Attribute.LogicalColour.Black = [topLeft, maxBound]+rooksStartingCoordinates :: Colour.LogicalColour.LogicalColour -> [Coordinates]+rooksStartingCoordinates Colour.LogicalColour.Black = [topLeft, maxBound] rooksStartingCoordinates _ = [minBound, bottomRight] -- | Whether the specified /coordinates/ are where a @Pawn@ of the specified /logical colour/ starts.-isPawnsFirstRank :: Attribute.LogicalColour.LogicalColour -> Coordinates -> Bool-isPawnsFirstRank logicalColour MkCoordinates { getY = y } = y == Cartesian.Ordinate.pawnsFirstRank logicalColour+isPawnsFirstRank :: Coordinates -> Colour.LogicalColour.LogicalColour -> Bool+isPawnsFirstRank MkCoordinates { getY = y } = (== y) . Cartesian.Ordinate.pawnsFirstRank -- | Whether a @Pawn@ is currently on the appropriate /rank/ to take an opponent's @Pawn@ /en-passant/.-isEnPassantRank :: Attribute.LogicalColour.LogicalColour -> Coordinates -> Bool-isEnPassantRank logicalColour MkCoordinates { getY = y } = y == Cartesian.Ordinate.enPassantRank logicalColour+isEnPassantRank :: Coordinates -> Colour.LogicalColour.LogicalColour -> Bool+isEnPassantRank MkCoordinates { getY = y } = (== y) . Cartesian.Ordinate.enPassantRank -- | A boxed array indexed by /coordinates/, of arbitrary elements. type ArrayByCoordinates = Data.Array.IArray.Array Coordinates +#ifdef USE_UNBOXED_ARRAYS -- | An unboxed array indexed by /coordinates/, of fixed-size elements. type UArrayByCoordinates = Data.Array.Unboxed.UArray Coordinates+#endif -- | Array-constructor from an ordered list of elements. listArrayByCoordinates :: Data.Array.IArray.IArray a e => [e] -> a Coordinates e
src-lib/BishBosh/Cartesian/Ordinate.hs view
@@ -49,10 +49,10 @@ inBounds ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception -- | The constant length of the /y/-axis.@@ -79,24 +79,24 @@ fromIx = (+ yMin) . fromIntegral -- | The /rank/ from which /piece/s conventionally start.-firstRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y-firstRank Attribute.LogicalColour.Black = yMax+firstRank :: Colour.LogicalColour.LogicalColour -> Type.Length.Y+firstRank Colour.LogicalColour.Black = yMax firstRank _ = yMin -- | The final /rank/; i.e. the one on which a @Pawn@ is promoted.-lastRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y+lastRank :: Colour.LogicalColour.LogicalColour -> Type.Length.Y lastRank = firstRank . Property.Opposable.getOpposite -- | The /rank/ from which @Pawn@s conventionally start.-pawnsFirstRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y+pawnsFirstRank :: Colour.LogicalColour.LogicalColour -> Type.Length.Y {-# INLINE pawnsFirstRank #-}-pawnsFirstRank Attribute.LogicalColour.Black = pred yMax+pawnsFirstRank Colour.LogicalColour.Black = pred yMax pawnsFirstRank _ = succ yMin -- | The /rank/ from which a @Pawn@ may capture /en-passant/.-enPassantRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y+enPassantRank :: Colour.LogicalColour.LogicalColour -> Type.Length.Y {-# INLINE enPassantRank #-}-enPassantRank Attribute.LogicalColour.Black = fromIx 3+enPassantRank Colour.LogicalColour.Black = fromIx 3 enPassantRank _ = fromIx 4 -- | Reflects about the mid-point of the axis.
src-lib/BishBosh/Cartesian/Vector.hs view
@@ -41,23 +41,23 @@ measureDistance, -- ** Predicates -- hasDistance,- isDiagonal,- isParallel,- isStraight, isPawnAttack, isKnightsMove, isKingsMove, matchesPawnDoubleAdvance ) where -import Control.Arrow((&&&), (***))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Orientated as Property.Orientated-import qualified BishBosh.Type.Length as Type.Length+import Control.Arrow((***))+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Direction.Direction as Direction.Direction+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq+import qualified Control.Exception -- | The distance between two /coordinates/. data Vector = MkVector {@@ -78,9 +78,19 @@ } = MkVector (negate xDistance) (negate yDistance) instance Property.Orientated.Orientated Vector where- isDiagonal = isDiagonal- isParallel = isParallel+ isVertical MkVector { getXDistance = xDistance } = xDistance == 0 + isHorizontal MkVector { getYDistance = yDistance } = yDistance == 0++ isParallel MkVector { getXDistance = 0 } = True+ isParallel MkVector { getYDistance = 0 } = True+ isParallel _ = False++ isDiagonal MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+ } = abs xDistance == fromIntegral (abs yDistance)+ -- | Whether the vector has a non-zero length (or a well-defined direction). hasDistance :: Type.Length.X -> Type.Length.Y -> Bool hasDistance 0 0 = False@@ -93,36 +103,17 @@ -> Vector measureDistance source destination = uncurry MkVector $ Cartesian.Coordinates.measureDistance source destination --- | Whether the specified /vector/ is at 45 degrees to an edge of the board, i.e. any move a @Bishop@ could make.-isDiagonal :: Vector -> Bool-{-# INLINE isDiagonal #-}-isDiagonal MkVector {- getXDistance = xDistance,- getYDistance = yDistance-} = fromEnum (abs xDistance) == fromEnum (abs yDistance)---- | Whether the specified /vector/ is parallel to an edge of the board, i.e. any move a @Rook@ could make.-isParallel :: Vector -> Bool-{-# INLINE isParallel #-}-isParallel MkVector { getXDistance = 0 } = True-isParallel MkVector { getYDistance = 0 } = True-isParallel _ = False---- | Whether the specified /vector/ is either parallel or at 45 degrees to an edge of the board, i.e. any move a @Queen@ could make.-isStraight :: Vector -> Bool-isStraight = uncurry (||) . (isParallel &&& isDiagonal)- {- | * The list of attack-vectors for a @Pawn@. * N.B.: the @Pawn@'s ability to advance without taking, isn't dealt with here. -}-attackVectorsForPawn :: Attribute.LogicalColour.LogicalColour -> [Vector]+attackVectorsForPawn :: Colour.LogicalColour.LogicalColour -> [Vector] attackVectorsForPawn logicalColour = [ MkVector { getXDistance = x, getYDistance = (- if Attribute.LogicalColour.isBlack logicalColour+ if Colour.LogicalColour.isBlack logicalColour then negate -- Black moves down. else id -- White moves up. ) 1@@ -155,12 +146,12 @@ * CAVEAT: if the move started at the first rank, then it can't be a @Pawn@, but that's beyond the scope of this module (since a /Vector/ doesn't define absolute /coordinate/s). -}-isPawnAttack :: Attribute.LogicalColour.LogicalColour -> Vector -> Bool+isPawnAttack :: Vector -> Colour.LogicalColour.LogicalColour -> Bool {-# INLINE isPawnAttack #-}-isPawnAttack logicalColour MkVector {+isPawnAttack MkVector { getXDistance = xDistance, getYDistance = yDistance-} = abs xDistance == 1 && yDistance == if Attribute.LogicalColour.isBlack logicalColour+} logicalColour = abs xDistance == 1 && yDistance == if Colour.LogicalColour.isBlack logicalColour then negate 1 else 1 @@ -189,34 +180,54 @@ * CAVEAT: passing this test doesn't guarantee that it is a @Pawn@'s double-advance move, since the move may not relate to a @Pawn@, or could be invalid. -}-matchesPawnDoubleAdvance :: Attribute.LogicalColour.LogicalColour -> Vector -> Bool-matchesPawnDoubleAdvance logicalColour MkVector {+matchesPawnDoubleAdvance :: Vector -> Colour.LogicalColour.LogicalColour -> Bool+matchesPawnDoubleAdvance MkVector { getXDistance = 0, getYDistance = yDistance-} = yDistance == if Attribute.LogicalColour.isBlack logicalColour then negate 2 else 2+} logicalColour = yDistance == if Colour.LogicalColour.isBlack logicalColour then negate 2 else 2 matchesPawnDoubleAdvance _ _ = False -- | Translate the specified /coordinates/ by the specified /vector/.-translate :: Cartesian.Coordinates.Coordinates -> Vector -> Cartesian.Coordinates.Coordinates-translate coordinates MkVector {+translate :: Vector -> Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates+translate MkVector { getXDistance = xDistance, getYDistance = yDistance-} = Cartesian.Coordinates.translate ((+ xDistance) *** (+ yDistance)) coordinates+} = Cartesian.Coordinates.translate $ (+ xDistance) *** (+ yDistance) -- | Where legal, translate the specified /coordinates/ by the specified /vector/.-maybeTranslate :: Cartesian.Coordinates.Coordinates -> Vector -> Maybe Cartesian.Coordinates.Coordinates-maybeTranslate coordinates MkVector {+maybeTranslate :: Vector -> Cartesian.Coordinates.Coordinates -> Maybe Cartesian.Coordinates.Coordinates+maybeTranslate MkVector { getXDistance = xDistance, getYDistance = yDistance-} = Cartesian.Coordinates.maybeTranslate ((+ xDistance) *** (+ yDistance)) coordinates+} = Cartesian.Coordinates.maybeTranslate $ (+ xDistance) *** (+ yDistance) {- | * Where possible, converts the specified /vector/ into a /direction/. * @Nothing@ is returned for those /vector/s which don't translate into a legal /direction/ (e.g. a @Knight@'s move). -}-toMaybeDirection :: Vector -> Maybe Attribute.Direction.Direction-toMaybeDirection vector@(MkVector xDistance yDistance)- | isStraight vector = Just $ Attribute.Direction.mkDirection (xDistance `compare` 0) (yDistance `compare` 0)- | otherwise = Nothing+toMaybeDirection :: Vector -> Maybe Direction.Direction.Direction+toMaybeDirection vector@(MkVector xDistance yDistance) = case (xDistance `compare` 0, yDistance `compare` 0) of+ (LT, ySense) -> case ySense of+ LT+ | xDistance == yDistance' -> Just Direction.Direction.sw+ | otherwise -> Nothing+ EQ -> Just Direction.Direction.w+ GT+ | negate xDistance == yDistance' -> Just Direction.Direction.nw+ | otherwise -> Nothing+ (EQ, ySense) -> Just $ case ySense of+ LT -> Direction.Direction.s+ EQ -> Control.Exception.throw . Data.Exception.mkRequestFailure . showString "BishBosh.Cartesian.Vector.toMaybeDirection:\tundefined direction" . Text.ShowList.showsAssociation $ shows vector "."+ GT -> Direction.Direction.n+ (GT, ySense) -> case ySense of+ LT+ | xDistance == negate yDistance' -> Just Direction.Direction.se+ | otherwise -> Nothing+ EQ -> Just Direction.Direction.e+ GT+ | xDistance == yDistance' -> Just Direction.Direction.ne+ | otherwise -> Nothing+ where+ yDistance' = fromIntegral yDistance
+ src-lib/BishBosh/Colour/ANSIColourCode.hs view
@@ -0,0 +1,76 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines the encoding of colours for rendering on a terminal; <https://en.wikipedia.org/wiki/ANSI_escape_code>.+-}++module BishBosh.Colour.ANSIColourCode(+-- * Types+-- ** Type-synonyms+-- ANSIColourCode(),+-- IsBold,+ GraphicsRendition,+-- * Functions+ selectGraphicsRendition,+ bracket,+-- ** Constructors+ mkFgColourCode,+ mkBgColourCode+) where++import qualified BishBosh.Colour.PhysicalColour as Colour.PhysicalColour+import qualified Data.Default++-- | A colour-code as used by terminal-emulators.+newtype ANSIColourCode = MkANSIColourCode {+ deconstruct :: Int+}++instance Show ANSIColourCode where+ showsPrec precedence MkANSIColourCode { deconstruct = i } = showsPrec precedence i++instance Data.Default.Default ANSIColourCode where+ def = MkANSIColourCode 0++-- | The font-weight of a character.+type IsBold = Bool++-- | An escape-sequence used to control a terminal.+type GraphicsRendition = String++-- | Constructor: offset the specified colour-code, so that it applies to the foreground.+mkFgColourCode :: Colour.PhysicalColour.PhysicalColour -> ANSIColourCode+mkFgColourCode = MkANSIColourCode . (+ 30) . fromEnum {-CAVEAT: relies on the PhysicalColour's constructor-order-}++-- | Constructor: offset the specified colour-code, so that it applies to the background.+mkBgColourCode :: Colour.PhysicalColour.PhysicalColour -> ANSIColourCode+mkBgColourCode = MkANSIColourCode . (+ 40) . fromEnum {-CAVEAT: relies on the PhysicalColour's constructor-order-}++-- | Generate the escape-sequence required to change a terminal to the specified physical colour.+selectGraphicsRendition :: IsBold -> ANSIColourCode -> GraphicsRendition+selectGraphicsRendition isBold parameter = showString "\x1b[" . shows parameter $ (if isBold then showString ";1" else id) "m"++-- | Render the specified string according to instructions, then revert to the default.+bracket :: GraphicsRendition -> String -> ShowS+bracket graphicsRendition s = showString graphicsRendition . showString s . showString (+ selectGraphicsRendition False Data.Default.def+ )+
+ src-lib/BishBosh/Colour/ColourScheme.hs view
@@ -0,0 +1,159 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines the physical colour used to represent each component of the board.+-}++module BishBosh.Colour.ColourScheme (+-- * Types+-- ** Data-types+ ColourScheme(+-- MkColourScheme,+ getDarkPieceColour,+ getLightPieceColour,+ getDarkSquareColour,+ getLightSquareColour+ ),+-- * Constants+ tag,+-- darkSquareColourTag,+-- lightSquareColourTag,+-- darkPieceColourTag,+-- lightPieceColourTag,+-- * Functions+-- ** Constructor+-- mkColourScheme+) where++import qualified BishBosh.Colour.PhysicalColour as Colour.PhysicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified Control.Arrow+import qualified Control.DeepSeq+import qualified Control.Exception+import qualified Data.Default+import qualified Text.XML.HXT.Arrow.Pickle as HXT++-- | Used to qualify XML.+tag :: String+tag = "colourScheme"++darkPieceColourTag, darkSquareColourTag, lightPieceColourTag, lightSquareColourTag :: String+[darkPieceColourTag, darkSquareColourTag, lightPieceColourTag, lightSquareColourTag] = [showString brightness $ showString component "Colour" | brightness <- ["dark", "light"], component <- ["Piece", "Square"]] -- List-comprehension.++-- | Defines the command-line options.+data ColourScheme = MkColourScheme {+ getDarkPieceColour :: Colour.PhysicalColour.PhysicalColour, -- ^ The physical colour of the dark pieces.+ getLightPieceColour :: Colour.PhysicalColour.PhysicalColour, -- ^ The physical colour of the light pieces.+ getDarkSquareColour :: Colour.PhysicalColour.PhysicalColour, -- ^ The physical colour of the dark squares of the board.+ getLightSquareColour :: Colour.PhysicalColour.PhysicalColour -- ^ The physical colour of the light squares of the board.+} deriving Eq++instance Control.DeepSeq.NFData ColourScheme where+ rnf MkColourScheme {+ getDarkPieceColour = darkPieceColour,+ getLightPieceColour = lightPieceColour,+ getDarkSquareColour = darkSquareColour,+ getLightSquareColour = lightSquareColour+ } = Control.DeepSeq.rnf (+ darkPieceColour,+ lightPieceColour,+ darkSquareColour,+ lightSquareColour+ )++instance Show ColourScheme where+ showsPrec _ MkColourScheme {+ getDarkPieceColour = darkPieceColour,+ getLightPieceColour = lightPieceColour,+ getDarkSquareColour = darkSquareColour,+ getLightSquareColour = lightSquareColour+ } = Text.ShowList.showsAssociationList' $ map (Control.Arrow.second shows) [+ (+ darkPieceColourTag,+ darkPieceColour+ ), (+ lightPieceColourTag,+ lightPieceColour+ ), (+ darkSquareColourTag,+ darkSquareColour+ ), (+ lightSquareColourTag,+ lightSquareColour+ )+ ]++instance Data.Default.Default ColourScheme where+ def = MkColourScheme {+ getDarkPieceColour = Colour.PhysicalColour.blue,+ getLightPieceColour = Property.Opposable.getOpposite $ getDarkPieceColour Data.Default.def,+ getDarkSquareColour = Colour.PhysicalColour.black,+ getLightSquareColour = Property.Opposable.getOpposite $ getDarkSquareColour Data.Default.def+ }++instance HXT.XmlPickler ColourScheme where+ xpickle = HXT.xpElem tag . HXT.xpWrap (+ \(a, b, c, d) -> mkColourScheme a b c d, -- Construct.+ \MkColourScheme {+ getDarkPieceColour = darkPieceColour,+ getLightPieceColour = lightPieceColour,+ getDarkSquareColour = darkSquareColour,+ getLightSquareColour = lightSquareColour+ } -> (+ darkPieceColour,+ lightPieceColour,+ darkSquareColour,+ lightSquareColour+ ) -- Deconstruct.+ ) $ HXT.xp4Tuple (+ getDarkPieceColour def `HXT.xpDefault` HXT.xpAttr darkPieceColourTag HXT.xpickle+ ) (+ getLightPieceColour def `HXT.xpDefault` HXT.xpAttr lightPieceColourTag HXT.xpickle+ ) (+ getDarkSquareColour def `HXT.xpDefault` HXT.xpAttr darkSquareColourTag HXT.xpickle+ ) (+ getLightSquareColour def `HXT.xpDefault` HXT.xpAttr lightSquareColourTag HXT.xpickle+ ) where+ def :: ColourScheme+ def = Data.Default.def++-- | Smart constructor.+mkColourScheme+ :: Colour.PhysicalColour.PhysicalColour -- ^ Dark piece.+ -> Colour.PhysicalColour.PhysicalColour -- ^ Light piece.+ -> Colour.PhysicalColour.PhysicalColour -- ^ Dark square.+ -> Colour.PhysicalColour.PhysicalColour -- ^ Light square.+ -> ColourScheme+mkColourScheme darkPieceColour lightPieceColour darkSquareColour lightSquareColour+ | darkPieceColour `elem` bgColours = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Colour.ColourScheme.mkColourScheme:\t" . showString darkPieceColourTag . Text.ShowList.showsAssociation . shows darkPieceColour . showString " must differ from the physical colour of both squares; " $ shows bgColours "."+ | lightPieceColour `elem` bgColours = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Colour.ColourScheme.mkColourScheme:\t" . showString lightPieceColourTag . Text.ShowList.showsAssociation . shows lightPieceColour . showString " must differ from the physical colour of both squares; " $ shows bgColours "."+ | darkSquareColour == lightSquareColour = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Colour.ColourScheme.mkColourScheme:\tthe physical colours of " . shows lightSquareColourTag . showString " & " $ shows darkSquareColourTag ", must differ."+ | otherwise = MkColourScheme {+ getDarkPieceColour = darkPieceColour,+ getLightPieceColour = lightPieceColour,+ getDarkSquareColour = darkSquareColour,+ getLightSquareColour = lightSquareColour+ }+ where+ bgColours = [darkSquareColour, lightSquareColour]+
+ src-lib/BishBosh/Colour/LogicalColour.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE CPP, LambdaCase #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines the data-type which represents the logical (rather than physical) colour of /piece/s & (conceptually) of the two players.++ * N.B.: conceptually different from the logical colour of squares on the board.+-}++module BishBosh.Colour.LogicalColour(+-- * Types+-- ** Type-synonyms+ ArrayByLogicalColour,+#ifdef USE_UNBOXED_ARRAYS+ UArrayByLogicalColour,+#endif+-- ** Data-types+ LogicalColour(..),+-- * Constants+ tag,+ range,+ nDistinctLogicalColours,+-- * Functions+-- ** Constructor+ listArrayByLogicalColour,+ arrayByLogicalColour,+-- ** Predicates+ isBlack+-- isWhite+) where++import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Type.Count as Type.Count+import qualified Control.DeepSeq+import qualified Control.Exception+import qualified Data.Array.IArray+import qualified Data.List.Extra+import qualified Text.XML.HXT.Arrow.Pickle as HXT+import qualified Text.XML.HXT.Arrow.Pickle.Schema++#ifdef USE_UNBOXED_ARRAYS+import qualified Data.Array.Unboxed+#endif++-- | Used to qualify XML.+tag :: String+tag = "logicalColour"++-- | The sum-type of /logical colour/s associated with either a piece, or (conceptually) a player.+data LogicalColour+ = Black+ | White+ deriving (+ Bounded,+ Enum,+ Eq,+ Ord,+ Read,+ Show+ )++instance Control.DeepSeq.NFData LogicalColour where+ rnf _ = ()++instance Data.Array.IArray.Ix LogicalColour where+ range (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) range+ inRange (lower, upper) logicalColour = Control.Exception.assert (logicalColour >= lower && logicalColour <= upper) True+ index (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) . fromEnum++-- | The constant ascending range of /logical colour/s.+range :: [LogicalColour]+range = [minBound, maxBound]++instance Property.FixedMembership.FixedMembership LogicalColour where+ members = range++-- | The constant number of distinct /logical colour/s.+nDistinctLogicalColours :: Type.Count.NLogicalColours+nDistinctLogicalColours = fromIntegral $ length range++instance HXT.XmlPickler LogicalColour where+ xpickle = HXT.xpAttr tag . HXT.xpWrap (read, show) . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range++instance Property.Opposable.Opposable LogicalColour where+ getOpposite Black = White+ getOpposite _ = Black++instance Property.ExtendedPositionDescription.ReadsEPD LogicalColour where+ readsEPD s = case Data.List.Extra.trimStart s of+ 'b' : remainder -> [(Black, remainder)]+ 'w' : remainder -> [(White, remainder)]+ _ -> []++instance Property.ExtendedPositionDescription.ShowsEPD LogicalColour where+ showsEPD = showChar . \case+ Black -> 'b'+ White -> 'w'++instance Property.ForsythEdwards.ReadsFEN LogicalColour++instance Property.ForsythEdwards.ShowsFEN LogicalColour++-- | Whether the specified /logical colour/ is @Black@.+isBlack :: LogicalColour -> Bool+{-# INLINE isBlack #-}+isBlack Black = True+isBlack _ = False++-- | Whether the specified /logical colour/ is @White@.+isWhite :: LogicalColour -> Bool+isWhite = not . isBlack++-- | A boxed array indexed by /logical colour/, of arbitrary elements.+type ArrayByLogicalColour = Data.Array.IArray.Array LogicalColour++#ifdef USE_UNBOXED_ARRAYS+-- | An unboxed array indexed by /logical colour/, of fixed-size values.+type UArrayByLogicalColour = Data.Array.Unboxed.UArray LogicalColour+#endif++-- | Array-constructor from an ordered list of elements.+listArrayByLogicalColour :: Data.Array.IArray.IArray a e => [e] -> a LogicalColour e+listArrayByLogicalColour = Data.Array.IArray.listArray (minBound, maxBound)++-- | Array-constructor from an association-list.+arrayByLogicalColour :: Data.Array.IArray.IArray a e => [(LogicalColour, e)] -> a LogicalColour e+arrayByLogicalColour = Data.Array.IArray.array (minBound, maxBound)+
+ src-lib/BishBosh/Colour/LogicalColourOfSquare.hs view
@@ -0,0 +1,59 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines the data-type which represents the logical (rather than physical) colour of the squares on a chess-board.++ * N.B.: conceptually different from the logical colour of pieces.+-}++module BishBosh.Colour.LogicalColourOfSquare(+-- * Types+-- ** Data-type+ LogicalColourOfSquare(),+-- * Constants+ black,+ white,+-- * Functions+-- ** Predicate+ isBlack+) where++import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour++-- | The logical colour of a square of the board, cf. of a piece or (conceptually) of a player.+newtype LogicalColourOfSquare = MkLogicalColourOfSquare {+ deconstruct :: Colour.LogicalColour.LogicalColour+} deriving (Eq, Bounded)++-- | Constant.+black :: LogicalColourOfSquare+black = MkLogicalColourOfSquare Colour.LogicalColour.Black++-- | Constant.+white :: LogicalColourOfSquare+white = MkLogicalColourOfSquare Colour.LogicalColour.White++-- | Whether the specified /logical colour/ is @Black@.+isBlack :: LogicalColourOfSquare -> Bool+isBlack MkLogicalColourOfSquare { deconstruct = logicalColour } = Colour.LogicalColour.isBlack logicalColour+
+ src-lib/BishBosh/Colour/PhysicalColour.hs view
@@ -0,0 +1,119 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines the data-type which represents the physical (rather than logical) colour of the /board/ & of /piece/s.++ * The number of physical colours used to represent the /board/ & /piece/s can be greater than the two /logical colour/s required,+ but is limited in practice, since the terminal (optionally) used to render the image, typically can't cope with with a large number.+-}++module BishBosh.Colour.PhysicalColour(+-- * Types+-- ** Data-types+ PhysicalColour(),+-- * Constants+-- range,+ black,+ red,+ green,+ yellow,+ blue,+ magenta,+ cyan,+ white+) where++import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified Control.DeepSeq+import qualified Text.XML.HXT.Arrow.Pickle as HXT+import qualified Text.XML.HXT.Arrow.Pickle.Schema++{- |+ * Defines the sum-type of physical colours which can typically be rendered by a terminal.++ * CAVEAT: the constructor-order both facilitates conversion to an ANSI Colour-code & the derivation of the complementary colour.+-}+data PhysicalColour+ = Black+ | Red+ | Green+ | Yellow+ | Blue+ | Magenta+ | Cyan+ | White+ deriving (Enum, Eq, Read, Show)++instance Control.DeepSeq.NFData PhysicalColour where+ rnf _ = ()++instance Bounded PhysicalColour where+ minBound = black+ maxBound = white++instance HXT.XmlPickler PhysicalColour where+ xpickle = HXT.xpWrap (read, show) . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range++instance Property.Opposable.Opposable PhysicalColour where+ getOpposite physicalColour = toEnum $ fromEnum (maxBound :: PhysicalColour) - fromEnum physicalColour -- N.B. the complementary colour++-- | The constant complete range of values.+range :: [PhysicalColour]+range = [minBound .. maxBound]++instance Property.FixedMembership.FixedMembership PhysicalColour where+ members = range++-- | Constant.+black :: PhysicalColour+black = Black++-- | Constant.+red :: PhysicalColour+red = Red++-- | Constant.+green :: PhysicalColour+green = Green++-- | Constant.+yellow :: PhysicalColour+yellow = Yellow++-- | Constant.+blue :: PhysicalColour+blue = Blue++-- | Constant.+magenta :: PhysicalColour+magenta = Magenta++-- | Constant.+cyan :: PhysicalColour+cyan = Cyan++-- | Constant.+white :: PhysicalColour+white = White+
src-lib/BishBosh/Component/Accountant.hs view
@@ -23,20 +23,20 @@ -} module BishBosh.Component.Accountant(--- * Type-classes+-- * Type-class Accountant(..) ) where import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Type.Mass as Type.Mass -- | An interface which may be implemented by data which can total piece-square values. class Accountant accountant where -- | Calculate the total value of the /coordinates/ occupied by the /piece/s of either side. sumPieceSquareValueByLogicalColour- :: Num pieceSquareValue- => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue- -> Type.Count.NPieces -- ^ The number of pieces (of any logical colour or rank) remaining on the board; used to gauge progress through the game.+ :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank -> accountant- -> [pieceSquareValue]+ -> Type.Count.NPieces -- ^ The number of pieces (of any logical colour or rank) remaining on the board; used to gauge progress through the game.+ -> [Type.Mass.Base] -- CAVEAT: can't return '[Type.Mass.PieceSquareValue]' because it's bounded.
src-lib/BishBosh/Component/CastlingMove.hs view
@@ -43,9 +43,9 @@ import Control.Arrow((&&&)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.FixedMembership as Property.FixedMembership@@ -64,7 +64,7 @@ kingsMoveLength = 2 -- | Define all possible castling-moves for the specified /logical colour/.-defineCastlingMoves :: Attribute.LogicalColour.LogicalColour -> [CastlingMove]+defineCastlingMoves :: Colour.LogicalColour.LogicalColour -> [CastlingMove] defineCastlingMoves logicalColour = [ MkCastlingMove { getMoveType = Attribute.MoveType.longCastle,@@ -81,24 +81,24 @@ } ] where isBlack :: Bool- isBlack = Attribute.LogicalColour.isBlack logicalColour+ isBlack = Colour.LogicalColour.isBlack logicalColour kingsMove translation = uncurry ($) . (Component.Move.mkMove &&& Cartesian.Coordinates.translateX translation) $ Cartesian.Coordinates.kingsStartingCoordinates logicalColour -- | Defines by /logical colour/, the constant list of all possible castling-moves.-castlingMovesByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [CastlingMove]-castlingMovesByLogicalColour = Attribute.LogicalColour.listArrayByLogicalColour $ map defineCastlingMoves Property.FixedMembership.members+castlingMovesByLogicalColour :: Colour.LogicalColour.ArrayByLogicalColour [CastlingMove]+castlingMovesByLogicalColour = Colour.LogicalColour.listArrayByLogicalColour $ map defineCastlingMoves Property.FixedMembership.members {- | * Accessor. * CAVEAT: the moves are returned in unspecified order. -}-getCastlingMoves :: Attribute.LogicalColour.LogicalColour -> [CastlingMove]+getCastlingMoves :: Colour.LogicalColour.LogicalColour -> [CastlingMove] getCastlingMoves = (castlingMovesByLogicalColour !) -- | Break-down the two castling-moves for the specified /logical colour/ into a long & a short castling-move.-getLongAndShortMoves :: Attribute.LogicalColour.LogicalColour -> (CastlingMove, CastlingMove)+getLongAndShortMoves :: Colour.LogicalColour.LogicalColour -> (CastlingMove, CastlingMove) getLongAndShortMoves logicalColour | [longCastlingMove, shortCastlingMove] <- getCastlingMoves logicalColour = (longCastlingMove, shortCastlingMove) | otherwise = Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.Component.CastlingMove.getLongAndShortMoves:\tunexpected list-length."
src-lib/BishBosh/Component/Move.hs view
@@ -46,13 +46,14 @@ isPawnDoubleAdvance ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Cartesian.Vector as Cartesian.Vector-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Orientated as Property.Orientated-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Type.Count as Type.Count+import Control.Arrow((&&&))+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -77,8 +78,8 @@ } deriving Eq instance Ord Move where- move@MkMove { getSource = source } `compare` move'@MkMove { getSource = source' } = case source `compare` source' of- EQ -> Data.Ord.comparing getDestination move move'+ l'@MkMove { getSource = l } `compare` r'@MkMove { getSource = r } = case l `compare` r of+ EQ -> Data.Ord.comparing getDestination l' r' ordering -> ordering instance Control.DeepSeq.NFData Move where@@ -106,8 +107,17 @@ } instance Property.Orientated.Orientated Move where+ isVertical MkMove {+ getSource = source,+ getDestination = destination+ } = Cartesian.Coordinates.getX source == Cartesian.Coordinates.getX destination++ isHorizontal MkMove {+ getSource = source,+ getDestination = destination+ } = Cartesian.Coordinates.getY source == Cartesian.Coordinates.getY destination+ isDiagonal = Property.Orientated.isDiagonal . measureDistance- isParallel = Property.Orientated.isParallel . measureDistance instance Property.Reflectable.ReflectableOnX Move where reflectOnX MkMove {@@ -159,10 +169,12 @@ but passing only guarantees that it is, if it was a @Pawn@ which moved & that the /move/ is valid. -} isPawnDoubleAdvance- :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side whose move is referenced.- -> Move+ :: Move+ -> Colour.LogicalColour.LogicalColour -- ^ Defines the side whose move is referenced. -> Bool-isPawnDoubleAdvance logicalColour move@MkMove { getSource = source } = Cartesian.Coordinates.isPawnsFirstRank logicalColour source && Cartesian.Vector.matchesPawnDoubleAdvance logicalColour (- measureDistance move+isPawnDoubleAdvance move@MkMove { getSource = source } = uncurry (&&) . (+ Cartesian.Coordinates.isPawnsFirstRank source &&& Cartesian.Vector.matchesPawnDoubleAdvance (+ measureDistance move+ ) )
src-lib/BishBosh/Component/Piece.hs view
@@ -72,24 +72,25 @@ isKnight, -- isBishop, -- isRook,--- isQueen,+ isQueen, isKing, isPawnPromotion ) where import Control.Arrow((&&&), (***)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Direction.Direction as Direction.Direction import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception@@ -116,7 +117,7 @@ -- | A Chess-piece has a /logical colour/ & a /rank/. data Piece = MkPiece {- getLogicalColour :: Attribute.LogicalColour.LogicalColour,+ getLogicalColour :: Colour.LogicalColour.LogicalColour, getRank :: Attribute.Rank.Rank } deriving (Bounded, Eq, Ord) @@ -149,8 +150,8 @@ c : remainder -> ( MkPiece ( if Data.Char.isUpper c- then Attribute.LogicalColour.White- else Attribute.LogicalColour.Black+ then Colour.LogicalColour.White+ else Colour.LogicalColour.Black ) *** const remainder ) `map` reads [c] _ -> [] -- No parse.@@ -195,31 +196,31 @@ members = range -- | Constructor.-mkPiece :: Attribute.LogicalColour.LogicalColour -> Attribute.Rank.Rank -> Piece+mkPiece :: Colour.LogicalColour.LogicalColour -> Attribute.Rank.Rank -> Piece mkPiece = MkPiece -- | Constructor.-mkPawn :: Attribute.LogicalColour.LogicalColour -> Piece+mkPawn :: Colour.LogicalColour.LogicalColour -> Piece mkPawn = (`MkPiece` Attribute.Rank.Pawn) -- | Constructor.-mkRook :: Attribute.LogicalColour.LogicalColour -> Piece+mkRook :: Colour.LogicalColour.LogicalColour -> Piece mkRook = (`MkPiece` Attribute.Rank.Rook) -- | Constructor.-mkKnight :: Attribute.LogicalColour.LogicalColour -> Piece+mkKnight :: Colour.LogicalColour.LogicalColour -> Piece mkKnight = (`MkPiece` Attribute.Rank.Knight) -- | Constructor.-mkBishop:: Attribute.LogicalColour.LogicalColour -> Piece+mkBishop:: Colour.LogicalColour.LogicalColour -> Piece mkBishop = (`MkPiece` Attribute.Rank.Bishop) -- | Constructor.-mkQueen :: Attribute.LogicalColour.LogicalColour -> Piece+mkQueen :: Colour.LogicalColour.LogicalColour -> Piece mkQueen = (`MkPiece` Attribute.Rank.Queen) -- | Constructor.-mkKing :: Attribute.LogicalColour.LogicalColour -> Piece+mkKing :: Colour.LogicalColour.LogicalColour -> Piece mkKing = (`MkPiece` Attribute.Rank.King) -- | Changes the specified /piece/ to the specified /rank/ leaving its /logical colour/ unchanged.@@ -230,15 +231,15 @@ | otherwise = piece { getRank = newRank } -- | The structure of a container of arbitrary data, indexed by /logicalColour/ & some /rank/s.-type ByRankByLogicalColour element = Attribute.LogicalColour.ArrayByLogicalColour (Map.Map Attribute.Rank.Rank element)+type ByRankByLogicalColour element = Colour.LogicalColour.ArrayByLogicalColour (Map.Map Attribute.Rank.Rank element) -- | Constructor of a certain shape of container, but with arbitrary contents. mkByRankByLogicalColour :: #ifdef USE_PARALLEL Control.DeepSeq.NFData element => #endif- [Attribute.Rank.Rank] -> (Attribute.LogicalColour.LogicalColour -> Attribute.Rank.Rank -> element) -> ByRankByLogicalColour element-mkByRankByLogicalColour ranks mkElement = Attribute.LogicalColour.listArrayByLogicalColour+ [Attribute.Rank.Rank] -> (Colour.LogicalColour.LogicalColour -> Attribute.Rank.Rank -> element) -> ByRankByLogicalColour element+mkByRankByLogicalColour ranks mkElement = Colour.LogicalColour.listArrayByLogicalColour #ifdef USE_PARALLEL . Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq) #endif@@ -265,14 +266,14 @@ -- | Calls 'attackVectorsByRankByLogicalColour' to find the destinations which the specified /piece/ can attack from the specified position. findAttackDestinations'- :: Cartesian.Coordinates.Coordinates -- ^ The source from which the attack originates.- -> Piece+ :: Piece+ -> Cartesian.Coordinates.Coordinates -- ^ The source from which the attack originates. -> [Cartesian.Coordinates.Coordinates] -- ^ The destinations which can be attacked.-findAttackDestinations' source MkPiece {+findAttackDestinations' MkPiece { getLogicalColour = logicalColour, getRank = rank-} = Data.Maybe.mapMaybe (- Cartesian.Vector.maybeTranslate source+} source = Data.Maybe.mapMaybe (+ `Cartesian.Vector.maybeTranslate` source ) ( attackVectorsByRankByLogicalColour ! logicalColour Map.! rank )@@ -286,40 +287,40 @@ -} attackDestinationsByCoordinatesByRankByLogicalColour :: AttackDestinationsByCoordinatesByRankByLogicalColour attackDestinationsByCoordinatesByRankByLogicalColour = mkByRankByLogicalColour Attribute.Rank.fixedAttackRange $ \logicalColour rank -> Cartesian.Coordinates.listArrayByCoordinates $ map (- `findAttackDestinations'` mkPiece logicalColour rank+ findAttackDestinations' $! mkPiece logicalColour rank ) Property.FixedMembership.members -- | Find the destinations which the specified /piece/ can attack from the specified position. findAttackDestinations- :: Cartesian.Coordinates.Coordinates -- ^ The source from which the attack originates.- -> Piece+ :: Piece+ -> Cartesian.Coordinates.Coordinates -- ^ The source from which the attack originates. -> [Cartesian.Coordinates.Coordinates] -- ^ The destinations which can be attacked.-findAttackDestinations coordinates MkPiece {+findAttackDestinations MkPiece { getLogicalColour = logicalColour, getRank = rank-} = attackDestinationsByCoordinatesByRankByLogicalColour ! logicalColour Map.! rank ! coordinates+} coordinates = attackDestinationsByCoordinatesByRankByLogicalColour ! logicalColour Map.! rank ! coordinates -- The constant /direction/s of the straight lines along which each type of /piece/ can attack. {- |- * Find the constant /direction/s of the straight lines along which each type of /piece/ can attack.+ * The constant /direction/s of the straight lines along which each type of /piece/ can attack. * CAVEAT: not defined for a @Knight@. -}-attackDirectionsByRankByLogicalColour :: ByRankByLogicalColour [Attribute.Direction.Direction]+attackDirectionsByRankByLogicalColour :: ByRankByLogicalColour [Direction.Direction.Direction] attackDirectionsByRankByLogicalColour = mkByRankByLogicalColour Attribute.Rank.earthBound $ \logicalColour -> \case- Attribute.Rank.Pawn -> Attribute.Direction.attackDirectionsForPawn logicalColour- Attribute.Rank.Bishop -> Attribute.Direction.diagonals- Attribute.Rank.Rook -> Attribute.Direction.parallels- _ {-royalty-} -> Property.FixedMembership.members+ Attribute.Rank.Pawn -> Direction.Direction.attackDirectionsForPawn logicalColour+ Attribute.Rank.Bishop -> Direction.Direction.diagonals+ Attribute.Rank.Rook -> Direction.Direction.parallels+ _ {-royalty-} -> Property.FixedMembership.members {-directions-} {- | * Get the constant /direction/s of the straight lines along which the specified /piece/ can attack. * CAVEAT: not defined for a @Knight@. -}-getAttackDirections :: Piece -> [Attribute.Direction.Direction]+getAttackDirections :: Piece -> [Direction.Direction.Direction] getAttackDirections MkPiece { getLogicalColour = logicalColour, getRank = rank@@ -341,15 +342,13 @@ -> Bool canAttackAlong source destination piece = ( case getRank piece of- Attribute.Rank.Pawn -> Cartesian.Vector.isPawnAttack $ getLogicalColour piece+ Attribute.Rank.Pawn -> (`Cartesian.Vector.isPawnAttack` getLogicalColour piece) Attribute.Rank.Knight -> Cartesian.Vector.isKnightsMove- Attribute.Rank.Bishop -> Cartesian.Vector.isDiagonal- Attribute.Rank.Rook -> Cartesian.Vector.isParallel- Attribute.Rank.Queen -> Cartesian.Vector.isStraight+ Attribute.Rank.Bishop -> Property.Orientated.isDiagonal+ Attribute.Rank.Rook -> Property.Orientated.isParallel+ Attribute.Rank.Queen -> Property.Orientated.isStraight Attribute.Rank.King -> Cartesian.Vector.isKingsMove- ) (- Cartesian.Vector.measureDistance source destination- )+ ) $! Cartesian.Vector.measureDistance source destination {- | * Whether the specified /piece/ can move between the specified /coordinates/.@@ -357,47 +356,52 @@ * N.B.: can't detect any blocking pieces. -} canMoveBetween- :: Cartesian.Coordinates.Coordinates -- ^ Source.+ :: Piece+ -> Cartesian.Coordinates.Coordinates -- ^ Source. -> Cartesian.Coordinates.Coordinates -- ^ Destination.- -> Piece -> Bool-canMoveBetween source destination piece = (+canMoveBetween piece source destination = ( case getRank piece of- Attribute.Rank.Pawn -> \distance -> let+ Attribute.Rank.Pawn -> let logicalColour = getLogicalColour piece- in Cartesian.Vector.isPawnAttack logicalColour distance || Cartesian.Vector.getXDistance distance == 0 && (- let- y' = (- if Attribute.LogicalColour.isBlack logicalColour- then negate- else id- ) $ Cartesian.Vector.getYDistance distance- in y' == 1 || Cartesian.Coordinates.isPawnsFirstRank logicalColour source && y' == 2+ in uncurry (||) . (+ (`Cartesian.Vector.isPawnAttack` logicalColour) &&& (+ uncurry (&&) . (+ (== 0) . Cartesian.Vector.getXDistance &&& (+ \case+ 1 -> True+ 2 -> Cartesian.Coordinates.isPawnsFirstRank source logicalColour+ _ -> False+ ) . (+ if Colour.LogicalColour.isBlack logicalColour+ then negate+ else id+ ) . Cartesian.Vector.getYDistance+ )+ ) ) Attribute.Rank.Knight -> Cartesian.Vector.isKnightsMove- Attribute.Rank.Bishop -> Cartesian.Vector.isDiagonal- Attribute.Rank.Rook -> Cartesian.Vector.isParallel- Attribute.Rank.Queen -> Cartesian.Vector.isStraight+ Attribute.Rank.Bishop -> Property.Orientated.isDiagonal+ Attribute.Rank.Rook -> Property.Orientated.isParallel+ Attribute.Rank.Queen -> Property.Orientated.isStraight Attribute.Rank.King -> Cartesian.Vector.isKingsMove- ) (- Cartesian.Vector.measureDistance source destination- )+ ) $! Cartesian.Vector.measureDistance source destination -- | Whether a move qualifies for @Pawn@-promotion. isPawnPromotion- :: Cartesian.Coordinates.Coordinates -- ^ Destination.- -> Piece+ :: Piece+ -> Cartesian.Coordinates.Coordinates -- ^ Destination. -> Bool-isPawnPromotion destination MkPiece {+isPawnPromotion MkPiece { getLogicalColour = logicalColour, getRank = Attribute.Rank.Pawn-} = Cartesian.Ordinate.lastRank logicalColour == Cartesian.Coordinates.getY destination+} destination = Cartesian.Ordinate.lastRank logicalColour == Cartesian.Coordinates.getY destination isPawnPromotion _ _ = False -- | Whether the specified /piece/ is @Black@. {-# INLINE isBlack #-} isBlack :: Piece -> Bool-isBlack MkPiece { getLogicalColour = Attribute.LogicalColour.Black } = True+isBlack MkPiece { getLogicalColour = Colour.LogicalColour.Black } = True isBlack _ = False -- | Whether the specified /piece/s have the same /logical colour/.
src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -45,76 +46,97 @@ import Control.Arrow((&&&), (|||)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.DeepSeq import qualified Data.Array.IArray import qualified Data.Foldable import qualified Data.List +#if defined(USE_UNBOXED_ARRAYS) && !(defined(USE_NEWTYPE_WRAPPERS) || defined(USE_PRECISION))+#define UNBOX+import qualified Data.Array.Unboxed+#endif+ -- | The piece-square value may vary as the game progresses.-type PieceSquareValueByNPieces pieceSquareValue = Data.Array.IArray.Array Type.Count.NPieces pieceSquareValue+type PieceSquareValueByNPieces =+#ifdef UNBOX+ Data.Array.Unboxed.UArray+#else+ Data.Array.IArray.Array+#endif+ Type.Count.NPieces Type.Mass.PieceSquareValue -- | The bounds of the number of pieces on the board, at the end-game & opening-game respectively. nPiecesBounds :: (Type.Count.NPieces, Type.Count.NPieces) nPiecesBounds = ( 3 {-minimum sufficient material-},- fromIntegral Attribute.LogicalColour.nDistinctLogicalColours * Component.Piece.nPiecesPerSide+ fromIntegral Colour.LogicalColour.nDistinctLogicalColours * Component.Piece.nPiecesPerSide ) -- | Self-documentation.-type EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue = Either (- Cartesian.Coordinates.ArrayByCoordinates pieceSquareValue -- Uninterpolated.+type EitherPieceSquareValueByNPiecesByCoordinates = Either (+#ifdef UNBOX+ Cartesian.Coordinates.UArrayByCoordinates+#else+ Cartesian.Coordinates.ArrayByCoordinates+#endif+ Type.Mass.PieceSquareValue -- Uninterpolated. ) (- Cartesian.Coordinates.ArrayByCoordinates (PieceSquareValueByNPieces pieceSquareValue) -- Interpolated.+ Cartesian.Coordinates.ArrayByCoordinates PieceSquareValueByNPieces -- Interpolated. ) -- | The value for each type of /piece/ of occupying each coordinate, at each stage in the lifetime of the game.-newtype PieceSquareByCoordinatesByRank pieceSquareValue = MkPieceSquareByCoordinatesByRank {- deconstruct :: Attribute.Rank.ArrayByRank (EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue)+newtype PieceSquareByCoordinatesByRank = MkPieceSquareByCoordinatesByRank {+ deconstruct :: Attribute.Rank.ArrayByRank EitherPieceSquareValueByNPiecesByCoordinates } deriving (Eq, Show) -instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (PieceSquareByCoordinatesByRank pieceSquareValue) where- rnf MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = Control.DeepSeq.rnf byRank+instance Control.DeepSeq.NFData PieceSquareByCoordinatesByRank where+ rnf+#ifdef UNBOX+ _ = ()+#else+ MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = Control.DeepSeq.rnf byRank+#endif -- | Constructor. mkPieceSquareByCoordinatesByRank- :: (Attribute.Rank.Rank -> EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue) -- ^ Convert a /rank/ into either (a /pieceSquareValue/ or a /pieceSquareValue/ which linearly varies with the number of /piece/s remaining) by /coordinates/.- -> PieceSquareByCoordinatesByRank pieceSquareValue+ :: (Attribute.Rank.Rank -> EitherPieceSquareValueByNPiecesByCoordinates) -- ^ Convert a /rank/ into either (a /pieceSquareValue/ or a /pieceSquareValue/ which linearly varies with the number of /piece/s remaining) by /coordinates/.+ -> PieceSquareByCoordinatesByRank mkPieceSquareByCoordinatesByRank = MkPieceSquareByCoordinatesByRank . Attribute.Rank.listArrayByRank . (`map` Property.FixedMembership.members) -- | Find the piece-square value, at a stage in the game's lifetime defined by the total number of pieces remaining, for the specified /rank/ & /coordinates/. findPieceSquareValue- :: PieceSquareByCoordinatesByRank pieceSquareValue- -> Type.Count.NPieces -- ^ The progress through the game.- -> Attribute.LogicalColour.LogicalColour -- ^ The /piece/'s /logical colour/.- -> Attribute.Rank.Rank -- ^ The /piece/'s /rank/.- -> Cartesian.Coordinates.Coordinates -- ^ The /piece/'s location.- -> pieceSquareValue+ :: PieceSquareByCoordinatesByRank+ -> Type.Count.NPieces -- ^ The progress through the game.+ -> Colour.LogicalColour.LogicalColour -- ^ The /piece/'s /logical colour/.+ -> Attribute.Rank.Rank -- ^ The /piece/'s /rank/.+ -> Cartesian.Coordinates.Coordinates -- ^ The /piece/'s location.+ -> Type.Mass.PieceSquareValue findPieceSquareValue MkPieceSquareByCoordinatesByRank { deconstruct = byRank } nPieces logicalColour rank = ( (!) ||| ( \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !) ) $ byRank ! rank- ) . if Attribute.LogicalColour.isBlack logicalColour+ ) . if Colour.LogicalColour.isBlack logicalColour then Property.Reflectable.reflectOnX else id -- | Given the bounds over which two piece-square values vary as the game progresses from opening to end, return linearly interpolated values for all stages. interpolatePieceSquareValues- :: Fractional pieceSquareValue- => pieceSquareValue -- ^ Opening-game.- -> pieceSquareValue -- ^ End-game.- -> PieceSquareValueByNPieces pieceSquareValue+ :: Type.Mass.PieceSquareValue -- ^ Opening-game.+ -> Type.Mass.PieceSquareValue -- ^ End-game.+ -> PieceSquareValueByNPieces interpolatePieceSquareValues openingGame endGame = Data.Array.IArray.listArray nPiecesBounds . map (- uncurry (+) . (- (* openingGame) &&& (* endGame) . (1 -)+ fromRational . uncurry (+) . (+ (* toRational openingGame) &&& (* toRational endGame) . (1 -) ) . ( / fromIntegral ( uncurry subtract nPiecesBounds -- N.B.: this can't reasonably be zero.@@ -130,12 +152,12 @@ -- | Format the data for input to __GNUPlot__. formatForGNUPlot- :: (pieceSquareValue -> ShowS) -- ^ Format a /pieceSquareValue/.- -> ShowS -- ^ The column-delimiter.- -> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue) -- ^ Select one /pieceSquareValue/ from interpolated values.- -> PieceSquareByCoordinatesByRank pieceSquareValue+ :: PieceSquareByCoordinatesByRank+ -> (Type.Mass.PieceSquareValue -> ShowS) -- ^ Format a /pieceSquareValue/.+ -> ShowS -- ^ The column-delimiter.+ -> (PieceSquareValueByNPieces -> Type.Mass.PieceSquareValue) -- ^ Select one /PieceSquareValue/ from interpolated values. -> ShowS-formatForGNUPlot pieceSquareValueFormatter columnDelimiter selector MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = (+formatForGNUPlot MkPieceSquareByCoordinatesByRank { deconstruct = byRank } pieceSquareValueFormatter columnDelimiter selector = ( showsRow ( showChar gnuPlotComment . showChar 'x' : showChar 'y' : map shows Attribute.Rank.range -- Header comment. ) .@@ -152,7 +174,7 @@ ) id . zip ( Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates] ) . Data.List.transpose . map (- Data.Foldable.toList ||| map selector {-select one pieceSquareValue from interpolated values-} . Data.Foldable.toList {-ByCoordinates-}+ Data.Array.IArray.elems ||| map selector {-select one PieceSquareValue from interpolated values-} . Data.Foldable.toList {-ByCoordinates-} ) $ Data.Foldable.toList {-ByRank-} byRank where terminateRow = showChar '\n' showsRow = Text.ShowList.showsDelimitedList columnDelimiter id terminateRow
src-lib/BishBosh/Component/QualifiedMove.hs view
@@ -24,6 +24,8 @@ module BishBosh.Component.QualifiedMove( -- * Types+-- * Type-synonyms+ QualifiedMoveSequence, -- ** Data-types QualifiedMove( -- MkQualifiedMove,@@ -68,4 +70,7 @@ -- | Constructor. mkQualifiedMove :: Component.Move.Move -> Attribute.MoveType.MoveType -> QualifiedMove mkQualifiedMove = MkQualifiedMove++-- | A sequence of QualifiedMoves applied to a game.+type QualifiedMoveSequence = [QualifiedMove]
src-lib/BishBosh/Component/Turn.hs view
@@ -42,9 +42,9 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Property.Reflectable as Property.Reflectable@@ -116,13 +116,13 @@ -- | Whether the /turn/ represents a @Pawn@'s initial two-square advance. isPawnDoubleAdvance- :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side whose /turn/ is referenced.- -> Turn+ :: Turn+ -> Colour.LogicalColour.LogicalColour -- ^ Defines the side whose /turn/ is referenced. -> Bool-isPawnDoubleAdvance logicalColour MkTurn {+isPawnDoubleAdvance MkTurn { getRank = Attribute.Rank.Pawn, getQualifiedMove = qualifiedMove-} = Component.Move.isPawnDoubleAdvance logicalColour (Component.QualifiedMove.getMove qualifiedMove) && Component.QualifiedMove.getMoveType qualifiedMove == Data.Default.def+} logicalColour = Component.Move.isPawnDoubleAdvance (Component.QualifiedMove.getMove qualifiedMove) logicalColour && Component.QualifiedMove.getMoveType qualifiedMove == Data.Default.def isPawnDoubleAdvance _ _ = False -- | Forwards the request to 'Attribute.Rank.compareByLVA'.
src-lib/BishBosh/Component/Zobrist.hs view
@@ -51,12 +51,12 @@ import Control.Arrow((***)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Array.IArray import qualified Data.Bits@@ -66,15 +66,15 @@ import qualified ToolShed.System.Random -- | Used as an index into 'getRandomByCoordinatesByRankByLogicalColour'.-type Index = (Attribute.LogicalColour.LogicalColour, Attribute.Rank.Rank, Cartesian.Coordinates.Coordinates)+type Index = (Colour.LogicalColour.LogicalColour, Attribute.Rank.Rank, Cartesian.Coordinates.Coordinates) -- | The random numbers used to generate a hash, which almost uniquely represent a /position/. data Zobrist positionHash = MkZobrist {- getRandomForBlacksMove :: positionHash, -- ^ Defines a random number to apply when the next move is @Black@'s.- getRandomByCoordinatesByRankByLogicalColour :: Data.Array.IArray.Array {-Boxed-} Index positionHash, -- ^ Defines random numbers to represent all combinations of each piece at each coordinate; though @Pawn@s can't exist on the terminal ranks. N.B.: regrettably the array can't be unboxed, because 'Data.Array.Unboxed.UArray' isn't 'Foldable'; cf. 'Data.Array.IArray.Array'.+ getRandomForBlacksMove :: positionHash, -- ^ Defines a random number to apply when the next move is @Black@'s.+ getRandomByCoordinatesByRankByLogicalColour :: Data.Array.IArray.Array {-Boxed-} Index positionHash, -- ^ Defines random numbers to represent all combinations of each piece at each coordinate; though @Pawn@s can't exist on the terminal ranks. N.B.: regrettably the array can't be unboxed, because 'Data.Array.Unboxed.UArray' isn't 'Foldable'; cf. 'Data.Array.IArray.Array'. - getRandomByCastleableRooksXByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [(Type.Length.X, positionHash)], -- ^ Defines random numbers to represent all combinations of castleable @Rook@s.- getRandomByEnPassantAbscissa :: Data.Array.IArray.Array Type.Length.X positionHash -- ^ Defines random numbers to represent any file on which capture en-passant might be available.+ getRandomByCastleableRooksXByLogicalColour :: Colour.LogicalColour.ArrayByLogicalColour [(Type.Length.X, positionHash)], -- ^ Defines random numbers to represent all combinations of castleable @Rook@s.+ getRandomByEnPassantAbscissa :: Data.Array.IArray.Array Type.Length.X positionHash -- ^ Defines random numbers to represent any file on which capture en-passant might be available. } deriving Show instance Foldable Zobrist where@@ -133,7 +133,7 @@ ) . System.Random.split ) *** ( (- Attribute.LogicalColour.listArrayByLogicalColour . map (+ Colour.LogicalColour.listArrayByLogicalColour . map ( zip [Cartesian.Abscissa.xMin, Cartesian.Abscissa.xMax] . System.Random.randoms ) . ToolShed.System.Random.randomGens *** Cartesian.Abscissa.listArrayByAbscissa . System.Random.randoms ) . System.Random.split@@ -147,18 +147,18 @@ } -- | Dereferences 'getRandomByCoordinatesByRankByLogicalColour' using the specified index.-dereferenceRandomByCoordinatesByRankByLogicalColour :: Index -> Zobrist positionHash -> positionHash-dereferenceRandomByCoordinatesByRankByLogicalColour index MkZobrist { getRandomByCoordinatesByRankByLogicalColour = randomByCoordinatesByRankByLogicalColour } = randomByCoordinatesByRankByLogicalColour ! index+dereferenceRandomByCoordinatesByRankByLogicalColour :: Zobrist positionHash -> Index -> positionHash+dereferenceRandomByCoordinatesByRankByLogicalColour MkZobrist { getRandomByCoordinatesByRankByLogicalColour = randomByCoordinatesByRankByLogicalColour } = (randomByCoordinatesByRankByLogicalColour !) -- | Dereferences 'getRandomByCastleableRooksXByLogicalColour' using the specified abscissa. dereferenceRandomByCastleableRooksXByLogicalColour- :: Attribute.LogicalColour.LogicalColour+ :: Zobrist positionHash+ -> Colour.LogicalColour.LogicalColour -> Type.Length.X- -> Zobrist positionHash -> Maybe positionHash -- ^ The existence of a result depends on whether there remain any Rooks which can castle.-dereferenceRandomByCastleableRooksXByLogicalColour logicalColour x MkZobrist { getRandomByCastleableRooksXByLogicalColour = randomByCastleableRooksXByLogicalColour } = lookup x $ randomByCastleableRooksXByLogicalColour ! logicalColour+dereferenceRandomByCastleableRooksXByLogicalColour MkZobrist { getRandomByCastleableRooksXByLogicalColour = randomByCastleableRooksXByLogicalColour } logicalColour x = lookup x $ randomByCastleableRooksXByLogicalColour ! logicalColour -- | Dereferences 'getRandomByEnPassantAbscissa' using the specified abscissa.-dereferenceRandomByEnPassantAbscissa :: Type.Length.X -> Zobrist positionHash -> positionHash-dereferenceRandomByEnPassantAbscissa x MkZobrist { getRandomByEnPassantAbscissa = randomByEnPassantAbscissa } = randomByEnPassantAbscissa ! x+dereferenceRandomByEnPassantAbscissa :: Zobrist positionHash -> Type.Length.X -> positionHash+dereferenceRandomByEnPassantAbscissa MkZobrist { getRandomByEnPassantAbscissa = randomByEnPassantAbscissa } = (randomByEnPassantAbscissa !)
src-lib/BishBosh/ContextualNotation/PGN.hs view
@@ -72,7 +72,7 @@ ) where import Control.Arrow((&&&), (***))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.ContextualNotation.PGNComment as ContextualNotation.PGNComment import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Data.Exception as Data.Exception@@ -475,7 +475,7 @@ expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game in do moveNumber <- (- if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game+ if Colour.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game then fmap (Data.Maybe.fromMaybe expectedMoveNumber) . Control.Applicative.optional else id ) moveNumberParser@@ -514,7 +514,7 @@ expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game in do moveNumber <- (- if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game+ if Colour.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game then fmap (Data.Maybe.fromMaybe expectedMoveNumber) . Control.Applicative.optional else id ) moveNumberParser
src-lib/BishBosh/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -39,6 +39,7 @@ PositionHashQualifiedMoveTree(), -- * Functions -- onymiseQualifiedMove,+-- colourFlipper, -- findNextOnymousQualifiedMovesForGame, findNextOnymousQualifiedMovesForPosition, -- findNextJoiningOnymousQualifiedMovesFromPosition,@@ -53,8 +54,8 @@ ) where import Control.Arrow((&&&), (***))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn@@ -77,6 +78,7 @@ import qualified Data.List.Extra import qualified Data.Maybe import qualified Data.Tree+import qualified Data.Tuple import qualified System.Random import qualified ToolShed.System.Random @@ -101,7 +103,7 @@ getHasAnyVictories :: Bool -- ^ Whether a victory has been recorded for any game in the tree; which won't be the case if it was constructed from a PGN-database containing standard-openings. } --- | Augment the specified /qualified-move forest/ with a /Zobrist-hash/ of the /position/ & include the default initial game at the apex.+-- | Constructor: augment the specified /qualified-move forest/ with a /Zobrist-hash/ of the /position/ & include the default initial game at the apex. fromQualifiedMoveForest :: Data.Bits.Bits positionHash => Bool -- ^ IncrementalEvaluation.@@ -122,7 +124,7 @@ ) tree } where initialGame = Data.Default.def- initialPositionHash = StateProperty.Hashable.hash initialGame zobrist+ initialPositionHash = StateProperty.Hashable.hash zobrist initialGame tree = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel initialPositionHash Nothing, Data.Tree.subForest = map (@@ -143,7 +145,7 @@ Data.Tree.rootLabel = label@(qualifiedMove, _), Data.Tree.subForest = qualifiedMoveForest' } = Data.Tree.Node {- Data.Tree.rootLabel = MkNodeLabel (StateProperty.Hashable.hash game' zobrist) $ Just label, -- Hash the game after applying the move.+ Data.Tree.rootLabel = MkNodeLabel (StateProperty.Hashable.hash zobrist game') $ Just label, -- Hash the game after applying the move. Data.Tree.subForest = map (slave game') qualifiedMoveForest' -- Recurse. } where game' = Model.Game.applyQualifiedMove qualifiedMove game@@ -161,8 +163,8 @@ * CAVEAT: a negative result doesn't imply that convergence is possible, since other factors may prevent it. -}-cantConverge :: Model.Game.Game -> PositionHashQualifiedMoveTree positionHash -> Bool-cantConverge game MkPositionHashQualifiedMoveTree { getMinimumPieces = minimumPieces } = State.Board.getNPieces (Model.Game.getBoard game) < minimumPieces+cantConverge :: PositionHashQualifiedMoveTree positionHash -> Model.Game.Game -> Bool+cantConverge MkPositionHashQualifiedMoveTree { getMinimumPieces = minimumPieces } = (< minimumPieces) . State.Board.getNPieces . Model.Game.getBoard -- | A /qualified move/ annotated by the name & ultimate /result/, of each /game/ from which it could have originated. type OnymousQualifiedMove = (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.OnymousResult])@@ -178,13 +180,14 @@ ) . Data.Tree.flatten -- | The type of a function used to locate a match in the tree.-type FindMatch positionHash = Model.Game.Game -> PositionHashQualifiedMoveTree positionHash -> [OnymousQualifiedMove]+type FindMatch positionHash = PositionHashQualifiedMoveTree positionHash -> Model.Game.Game -> [OnymousQualifiedMove] -- | For any exactly matching /game/ in the tree, return the subsequent /qualifiedMove/s. findNextOnymousQualifiedMovesForGame :: FindMatch positionHash-findNextOnymousQualifiedMovesForGame requiredGame = slave (+findNextOnymousQualifiedMovesForGame MkPositionHashQualifiedMoveTree { getTree = tree } requiredGame = slave ( Model.Game.listTurnsChronologically requiredGame- ) . Data.Tree.subForest {-remove the apex which lacks a founding move-} . getTree where+ ) $ Data.Tree.subForest {-remove the apex which lacks a founding move-} tree where+ slave :: [Component.Turn.Turn] -> [Tree positionHash] -> [OnymousQualifiedMove] slave (turn : remainingTurns) = Data.Maybe.maybe [] {-match-failure-} ( slave remainingTurns . Data.Tree.subForest -- Recurse. ) . Data.List.find (@@ -204,43 +207,41 @@ * CAVEAT: a null list can result from either match-failure, or a match with the final /move/ of a /game/. -} findNextOnymousQualifiedMovesForPosition :: Data.Bits.Bits positionHash => FindMatch positionHash-{-# SPECIALISE findNextOnymousQualifiedMovesForPosition :: FindMatch Type.Crypto.PositionHash #-}-findNextOnymousQualifiedMovesForPosition requiredGame positionHashQualifiedMoveTree- | cantConverge requiredGame positionHashQualifiedMoveTree = [] -- The game we're required to match has fewer pieces than any defined in the tree.- | otherwise = slave nPiecesDiffByLogicalColour $ getTree positionHashQualifiedMoveTree+findNextOnymousQualifiedMovesForPosition positionHashQualifiedMoveTree requiredGame+ | cantConverge positionHashQualifiedMoveTree requiredGame = [] -- The game we're required to match has fewer pieces than any defined in the tree.+ | otherwise = slave (+ (+ uncurry (***) . (id &&& id) $ (Component.Piece.nPiecesPerSide -) -- Find the number of pieces at the apex of the tree, in excess of the requiredGame, to be taken before a match can be found.+ ) . StateProperty.Censor.countPiecesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . Model.Game.getBoard $ requiredGame+ ) $ getTree positionHashQualifiedMoveTree where- nPiecesDiffByLogicalColour :: (Type.Count.NPieces, Type.Count.NPieces)- (requiredPositionHash, nPiecesDiffByLogicalColour) = (`StateProperty.Hashable.hash` getZobrist positionHashQualifiedMoveTree) &&& (- uncurry (***) . (id &&& id) $ (Component.Piece.nPiecesPerSide -) -- Find the excess pieces on either side, to be taken before a match can be found.- ) . StateProperty.Censor.countPiecesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . Model.Game.getBoard $ requiredGame-- slave (nPiecesDiffOpponent, nPiecesDiffMover) Data.Tree.Node {+ slave nPiecesDiff Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getPositionHash = positionHash }, Data.Tree.subForest = forest } = (- case nPiecesDiffMover `compare` 0 of -- N.B. equivalent to 'signum' to slightly better performance.- GT -> id -- This node can't match, but there may be a match further down the tree.+ case snd {-mover-} nPiecesDiff `compare` 0 of -- N.B. equivalent to 'signum' to slightly better performance.+ GT -> id -- This node can't match, but there may be a match further down the tree. EQ- | positionHash == requiredPositionHash -> (map onymiseQualifiedMove forest ++) -- The position matches, so one can select any move from the forest.- | otherwise -> id -- This node doesn't match, but there may be a match further down the tree.- _ -> const [] -- Terminate the recursion, since from here down the tree, the mover has insufficient pieces to match the required game.+ | positionHash == StateProperty.Hashable.hash (+ getZobrist positionHashQualifiedMoveTree+ ) requiredGame -> (map onymiseQualifiedMove forest ++) -- The position matches, so one can select any move from the forest.+ | otherwise -> id -- This node doesn't match, but there may be a match further down the tree.+ _ -> const [] -- Terminate the recursion, since from here down the tree, the mover has insufficient pieces to match the required game. ) $ concatMap ( \node@Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getMaybeQualifiedMoveWithOnymousResult = Just (qualifiedMove, _) } } -> slave (- nPiecesDiffMover,- (+ Data.Tuple.swap $ ( if Attribute.MoveType.isCapture $! Component.QualifiedMove.getMoveType qualifiedMove- then pred+ then Control.Arrow.first pred -- Decrement opponent's piece-count. else id- ) nPiecesDiffOpponent- ) {-swap pair-} node -- Recurse.+ ) nPiecesDiff+ ) node -- Recurse. ) forest -- | Finds any single /move/s which can join the current /position/ with a member of the forest. findNextJoiningOnymousQualifiedMovesFromPosition :: Data.Bits.Bits positionHash => FindMatch positionHash-{-# SPECIALISE findNextJoiningOnymousQualifiedMovesFromPosition :: FindMatch Type.Crypto.PositionHash #-}-findNextJoiningOnymousQualifiedMovesFromPosition game positionHashQualifiedMoveTree+findNextJoiningOnymousQualifiedMovesFromPosition positionHashQualifiedMoveTree game | Model.Game.isTerminated game = [] | otherwise = [ Control.Arrow.second (concatMap snd {-[OnymousResult]-}) movePair | -- Discard the opponent's matching move, but cite the names of archived games it reached.@@ -251,7 +252,7 @@ ) . #endif map (- id &&& (`findNextOnymousQualifiedMovesForPosition` positionHashQualifiedMoveTree) . (`Model.Game.applyQualifiedMove` game) -- Apply this player's move.+ id &&& findNextOnymousQualifiedMovesForPosition positionHashQualifiedMoveTree . (`Model.Game.applyQualifiedMove` game) -- Apply this player's move. ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game ] -- List-comprehension. @@ -270,6 +271,14 @@ -- | Whether from all matching positions extracted from the tree, to prefer moves which result in a greater probability of victory, for the player who has the next move. type PreferVictories = Bool +-- | Transform an arbitrary match-function to operate on the colour-flipped game.+colourFlipper :: FindMatch positionHash -> FindMatch positionHash+colourFlipper findMatch positionHashQualifiedMoveTree = map (+ Property.Reflectable.reflectOnX {-reflect matching moves back into the original domain-} *** map (+ Control.Arrow.first $ showString "Colour-flipped:\t"+ )+ ) . findMatch positionHashQualifiedMoveTree . Property.Reflectable.reflectOnX+ {- | * Calls 'findNextOnymousQualifiedMovesForGame' to find an exact match for the current /game/ in the tree. @@ -287,32 +296,23 @@ :: Data.Bits.Bits positionHash => MatchSwitches -> FindMatch positionHash-{-# SPECIALISE findNextOnymousQualifiedMoves :: MatchSwitches -> FindMatch Type.Crypto.PositionHash #-}-findNextOnymousQualifiedMoves (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition) game positionHashQualifiedMoveTree- | cantConverge game positionHashQualifiedMoveTree = [] -- The specified game is smaller than any defined in the tree.+findNextOnymousQualifiedMoves (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition) positionHashQualifiedMoveTree game+ | cantConverge positionHashQualifiedMoveTree game = [] -- The specified game is smaller than any defined in the tree. | otherwise = Data.Maybe.fromMaybe [] . Data.List.find ( not . null -- Accept the results from the first match-function which returns any. ) $ ( if tryToMatchMoves- then (findNextOnymousQualifiedMovesForGame game positionHashQualifiedMoveTree :)+ then (findNextOnymousQualifiedMovesForGame positionHashQualifiedMoveTree game :) else id ) [- colourFlipper findMatch game positionHashQualifiedMoveTree |+ transformation findMatch positionHashQualifiedMoveTree game | findMatch <- findNextOnymousQualifiedMovesForPosition : [findNextJoiningOnymousQualifiedMovesFromPosition | tryToMatchViaJoiningMove] {-list-comprehension-},- colourFlipper <- id : [- \findMatch' game' -> map (- Property.Reflectable.reflectOnX {-reflect matching moves back into the original domain-} *** map (- Control.Arrow.first $ showString "Colour-flipped:\t"- )- ) . findMatch' (- Property.Reflectable.reflectOnX game'- ) | tryToMatchColourFlippedPosition- ] -- Transform an arbitrary match-function to operate on either the original or the colour-flipped game.+ transformation <- id : [colourFlipper | tryToMatchColourFlippedPosition] -- Transform an arbitrary match-function to operate on either the original or the colour-flipped game. ] -- List-comprehension. -- | Shortlist matching moves extracted from the tree, prefering those after which the player who makes it, has the greatest recorded incidence of victory. shortListMostVictorious- :: Attribute.LogicalColour.LogicalColour -- ^ The player who is next to move.+ :: Colour.LogicalColour.LogicalColour -- ^ The player who is next to move. -> [OnymousQualifiedMove] -> [OnymousQualifiedMove] shortListMostVictorious nextLogicalColour = last {-highest scoring group-} . Data.List.Extra.groupSortOn (@@ -331,19 +331,10 @@ => randomGen -> PreferVictories -> MatchSwitches- -> Model.Game.Game -> PositionHashQualifiedMoveTree positionHash- -> Maybe (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.Name])-{-# SPECIALISE maybeRandomlySelectOnymousQualifiedMove- :: System.Random.RandomGen randomGen- => randomGen- -> PreferVictories- -> MatchSwitches -> Model.Game.Game- -> PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> Maybe (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.Name])- #-}-maybeRandomlySelectOnymousQualifiedMove randomGen preferVictories matchSwitches game positionHashQualifiedMoveTree = case findNextOnymousQualifiedMoves matchSwitches game positionHashQualifiedMoveTree of+maybeRandomlySelectOnymousQualifiedMove randomGen preferVictories matchSwitches positionHashQualifiedMoveTree game = case findNextOnymousQualifiedMoves matchSwitches positionHashQualifiedMoveTree game of [] -> Nothing onymousQualifiedMoves -> fmap ( Control.Arrow.second $ Data.List.nub . map fst {-Name-}
src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs view
@@ -151,8 +151,8 @@ mkCompositeIdentifier = unwords . map snd {-value-} . ContextualNotation.PGN.getIdentificationTagPairs merge- :: OnymousResult -- ^ The name of this move-sequence, & the result.- -> [Component.QualifiedMove.QualifiedMove] -- ^ A chronological sequence of /qualified move/s.+ :: OnymousResult -- ^ The name of this move-sequence, & the result.+ -> Component.QualifiedMove.QualifiedMoveSequence -- ^ A chronological sequence of /qualified move/s. -> [QualifiedMoveTree] -> [QualifiedMoveTree] merge onymousResult qualifiedMoves@(qualifiedMove : remainingQualifiedMoves) forest = case span (@@ -172,7 +172,7 @@ _ {-no match-} -> mkLinkedList onymousResult qualifiedMoves : forest merge _ [] forest = forest - mkLinkedList :: OnymousResult -> [Component.QualifiedMove.QualifiedMove] -> QualifiedMoveTree+ mkLinkedList :: OnymousResult -> Component.QualifiedMove.QualifiedMoveSequence -> QualifiedMoveTree mkLinkedList onymousResult ~(qualifiedMove : remainingQualifiedMoves) | null remainingQualifiedMoves = Data.Tree.Node { Data.Tree.rootLabel = (qualifiedMove, Just onymousResult),@@ -198,6 +198,7 @@ findMinimumPieces = slave ( 2 * Component.Piece.nPiecesPerSide -- CAVEAT: assuming a conventional starting position. ) . deconstruct where+ slave :: Type.Count.NPieces -> [QualifiedMoveTree] -> Type.Count.NPieces slave nPieces [] = nPieces slave nPieces forest = minimum $ map ( \Data.Tree.Node {@@ -211,6 +212,7 @@ -- | Count the number of /game/s & distinct /positions/. count :: QualifiedMoveForest -> (Type.Count.NGames, Type.Count.NPositions) count = slave . deconstruct where+ slave :: [QualifiedMoveTree] -> (Type.Count.NGames, Type.Count.NPositions) slave = Data.List.foldl' ( \(nGames, nPositions) Data.Tree.Node { Data.Tree.rootLabel = (_, maybeOnymousResult),@@ -238,6 +240,7 @@ } where initialGame = Data.Default.def + slave :: Model.Game.Game -> QualifiedMoveTree -> Model.GameTree.BareGameTree slave game Data.Tree.Node { Data.Tree.rootLabel = (qualifiedMove, _), Data.Tree.subForest = qualifiedMoveForest'
src-lib/BishBosh/ContextualNotation/StandardAlgebraic.hs view
@@ -157,7 +157,7 @@ -> Model.Game.Game -- ^ The /game/ prior to application of the specified /turn/. -> ShowS showsTurn explicitEnPassant turn game- | Just sourceRank <- fmap Component.Piece.getRank . State.MaybePieceByCoordinates.dereference source $ State.Board.getMaybePieceByCoordinates board = (+ | Just sourceRank <- Component.Piece.getRank <$> State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates board) source = ( if sourceRank == Attribute.Rank.Pawn then ( if isCapture@@ -175,9 +175,9 @@ then shortCastleToken else longCastleToken _ {-not a castling-} -> showsRank sourceRank . (- case Data.List.delete source {-search for alternatives-} $ State.Board.findAttacksBy (+ case Data.List.delete source {-search for alternatives-} $ State.Board.findAttacksBy board ( Component.Piece.mkPiece (Model.Game.getNextLogicalColour game) sourceRank- ) destination board of+ ) destination of [] -> id -- There're aren't any pieces of this rank which can perform this move. coordinates -> case any ( (== Cartesian.Coordinates.getX source) . Cartesian.Coordinates.getX@@ -206,7 +206,7 @@ isEnPassant, isCapture :: Bool isEnPassant = Attribute.MoveType.isEnPassant moveType- isCapture = State.MaybePieceByCoordinates.isOccupied destination (State.Board.getMaybePieceByCoordinates board) || isEnPassant+ isCapture = State.MaybePieceByCoordinates.isOccupied (State.Board.getMaybePieceByCoordinates board) destination || isEnPassant showsRank :: Attribute.Rank.Rank -> ShowS showsRank rank = showChar $ fromRank rank@@ -290,7 +290,7 @@ nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour board = Model.Game.getBoard game- getMaybePiece = (`State.MaybePieceByCoordinates.dereference` State.Board.getMaybePieceByCoordinates board)+ getMaybePiece = State.MaybePieceByCoordinates.dereference $ State.Board.getMaybePieceByCoordinates board getMaybeRank = fmap Component.Piece.getRank . getMaybePiece in do qualifiedMove <- Text.Poly.spaces >> Poly.oneOf' [@@ -303,7 +303,7 @@ piece :: Component.Piece.Piece piece = Component.Piece.mkPiece nextLogicalColour rank - findAttacksBy destination = State.Board.findAttacksBy piece destination board+ findAttacksBy destination = State.Board.findAttacksBy board piece destination if rank == Attribute.Rank.Pawn then let@@ -378,7 +378,7 @@ show &&& return {-to Parser-monad-} $ qualifiedMove | source <- sourceCandidates,-- Attempt to resolve the ambiguity by playing subsequent moves. let qualifiedMove = Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) $ mkNormalMoveType destination,- Model.Game.isValidQualifiedMove qualifiedMove game+ Model.Game.isValidQualifiedMove game qualifiedMove ] -- List-comprehension. in Poly.oneOf' [ (@@ -431,16 +431,18 @@ _ <- Control.Applicative.optional (Poly.satisfyMsg (`elem` [checkFlag, checkMateFlag]) "Check") >> Control.Applicative.optional moveSuffixAnnotationParser - fmap fromQualifiedMove $ if validateMoves- then Data.Maybe.maybe (return {-to Parser-monad-} qualifiedMove) (Poly.failBad . showString "failed: ") $ Model.Game.validateQualifiedMove qualifiedMove game- else return {-to Parser-monad-} qualifiedMove+ fromQualifiedMove `fmap` (+ if validateMoves+ then Data.Maybe.maybe (return {-to Parser-monad-} qualifiedMove) (Poly.failBad . showString "failed: ") . Model.Game.validateQualifiedMove game+ else return {-to Parser-monad-}+ ) qualifiedMove #else /* Parsec */ -> Parsec.Parser StandardAlgebraic parser explicitEnPassant validateMoves game = let nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour board = Model.Game.getBoard game- getMaybePiece = (`State.MaybePieceByCoordinates.dereference` State.Board.getMaybePieceByCoordinates board)+ getMaybePiece = State.MaybePieceByCoordinates.dereference $ State.Board.getMaybePieceByCoordinates board getMaybeRank = fmap Component.Piece.getRank . getMaybePiece in do qualifiedMove <- Parsec.spaces >> Parsec.choice [@@ -451,7 +453,7 @@ piece :: Component.Piece.Piece piece = Component.Piece.mkPiece nextLogicalColour rank - findAttacksBy destination = State.Board.findAttacksBy piece destination board+ findAttacksBy destination = State.Board.findAttacksBy board piece destination if rank == Attribute.Rank.Pawn then let@@ -506,7 +508,7 @@ Parsec.try $ return {-to ParsecT-monad-} qualifiedMove | source <- sourceCandidates,-- Attempt to resolve the ambiguity by playing subsequent moves. let qualifiedMove = Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) $ mkNormalMoveType destination,- Model.Game.isValidQualifiedMove qualifiedMove game+ Model.Game.isValidQualifiedMove game qualifiedMove ] -- List-comprehension. in Parsec.choice [ Parsec.try $ do -- N.B. this scenario occurs when there are identical pieces on both the same row & the same column, as the intended attacker; i.e. after a promotion.@@ -553,9 +555,11 @@ _ <- Parsec.optional (Parsec.oneOf [checkFlag, checkMateFlag] <?> "Check") >> Parsec.optional moveSuffixAnnotationParser - fromQualifiedMove <$> if validateMoves- then Data.Maybe.maybe (return {-to ParsecT-monad-} qualifiedMove) (fail . showString "Failed: ") $ Model.Game.validateQualifiedMove qualifiedMove game- else return {-to ParsecT-monad-} qualifiedMove+ fromQualifiedMove <$> (+ if validateMoves+ then Data.Maybe.maybe (return {-to ParsecT-monad-} qualifiedMove) (fail . showString "Failed: ") . Model.Game.validateQualifiedMove game+ else return {-to ParsecT-monad-}+ ) qualifiedMove #endif -- | Represent a /rank/ in SAN.
src-lib/BishBosh/Data/RoseTree.hs view
@@ -35,6 +35,7 @@ -- ** Mutators promote, reduce,+ prune, mapForest ) where @@ -77,7 +78,7 @@ \Data.Tree.Node { Data.Tree.rootLabel = rootLabel, Data.Tree.subForest = subForest- } -> (rootLabel :) `fmap` slave subForest remainingData {-recurse-}+ } -> (rootLabel :) <$> slave subForest remainingData {-recurse-} ) slave _ _ = Just [] @@ -97,7 +98,7 @@ \forest'' -> match { Data.Tree.subForest = forest'' } : mismatches ++ remainingNodes- ) `fmap` slave remainingData forest' -- Recurse.+ ) <$> slave remainingData forest' -- Recurse. _ -> Nothing -- Match-failure. slave _ forest = Just forest -- Data exhausted => Terminate normally. @@ -110,6 +111,18 @@ -- | The type of a function which changes the structure (but not the type) of the specified tree. type Transformation a = Data.Tree.Tree a -> Data.Tree.Tree a++-- | Remove branches after the specified depth.+prune :: Int -> Transformation a+prune depth tree@Data.Tree.Node { Data.Tree.subForest = forest }+ | depth < 0 = error "BishBosh.Data.RoseTree.prune:\tdepth can't be negative."+ | otherwise = tree {+ Data.Tree.subForest = if depth == 0+ then []+ else map (+ prune $ pred depth -- Recurse.+ ) forest+ } {- | * Apply an arbitrary mapping to all subForests; cf. 'fmap' which applies an arbitrary function to all 'Data.Tree.rootLabel's.
+ src-lib/BishBosh/Direction/Diagonal.hs view
@@ -0,0 +1,114 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Describes the directional components of a diagonal line.+-}++module BishBosh.Direction.Diagonal(+-- * Types+-- ** Data-types+ Diagonal()+) where++import Control.Arrow((***))+import qualified BishBosh.Direction.Horizontal as Direction.Horizontal+import qualified BishBosh.Direction.Vertical as Direction.Vertical+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified Control.DeepSeq+import qualified Data.List.Extra++-- | Directions at 45 degress to all edges of the board; those in which a Bishop can move.+data Diagonal = MkDiagonal {+ getVertical :: Direction.Vertical.Vertical, -- ^ The vertical component of the diagonal.+ getHorizontal :: Direction.Horizontal.Horizontal -- ^ The horizontal component of the diagonal.+} deriving (Eq, Ord)++instance Control.DeepSeq.NFData Diagonal where+ rnf MkDiagonal {+ getVertical = _,+ getHorizontal = _+ } = ()++instance Enum Diagonal where+ fromEnum MkDiagonal {+ getVertical = v,+ getHorizontal = h+ } = fromIntegral Direction.Vertical.nVerticals * fromEnum v + fromEnum h++ toEnum i = uncurry MkDiagonal . (toEnum *** toEnum) $! i `divMod` fromIntegral Direction.Vertical.nVerticals++instance Show Diagonal where+ showsPrec precedence MkDiagonal {+ getVertical = v,+ getHorizontal = h+ } = showsPrec precedence v . showsPrec precedence h++instance Read Diagonal where+ readsPrec precedence s = case readsPrec precedence $ Data.List.Extra.trimStart s of+ [(vertical, s')] -> case readsPrec precedence s' of+ [(horizontal, s'')] -> [+ (+ MkDiagonal {+ getVertical = vertical,+ getHorizontal = horizontal+ },+ s''+ ) -- Pair.+ ] -- Singleton.+ _ -> [] -- No parse.+ _ -> [] -- No parse.++instance Property.FixedMembership.FixedMembership Diagonal where+ members = map MkDiagonal Property.FixedMembership.members {-vertical-} <*> Property.FixedMembership.members {-horizontal-}++instance Property.Opposable.Opposable Diagonal where+ getOpposite MkDiagonal {+ getVertical = v,+ getHorizontal = h+ } = MkDiagonal {+ getVertical = Property.Opposable.getOpposite v,+ getHorizontal = Property.Opposable.getOpposite h+ }++instance Property.Orientated.Orientated Diagonal where+ isParallel = const False+ isDiagonal = const True+ isStraight = const True++instance Property.Reflectable.ReflectableOnX Diagonal where+ reflectOnX diagonal@MkDiagonal {+ getVertical = v+ } = diagonal {+ getVertical = Property.Reflectable.reflectOnX v+ }++instance Property.Reflectable.ReflectableOnY Diagonal where+ reflectOnY diagonal@MkDiagonal {+ getHorizontal = h+ } = diagonal {+ getHorizontal = Property.Reflectable.reflectOnY h+ }+
+ src-lib/BishBosh/Direction/Direction.hs view
@@ -0,0 +1,180 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Describes a /direction/.++ * The resolution of the measure is merely sufficient for Chess-moves.++ * The IO-format is based on 8 points of the compass.+-}++module BishBosh.Direction.Direction(+-- * Types+-- ** Type-synonyms+ ArrayByDirection,+-- ** Data-types+ Direction(),+-- * Constants+ parallels,+ s,+ n,+ w,+ e,+ diagonals,+ sw,+ se,+ nw,+ ne,+ opposites,+-- * Functions+ attackDirectionsForPawn,+ listArrayByDirection,+-- ** Predicates+ areAligned+) where++import Control.Arrow((&&&), (|||), (+++))+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Direction.Diagonal as Direction.Diagonal+import qualified BishBosh.Direction.Parallel as Direction.Parallel+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.Rotatable as Property.Rotatable+import qualified Control.DeepSeq+import qualified Data.Array.IArray+import qualified Data.List.Extra++-- | Define the /direction/ in which a piece moves relative to the board's edges.+newtype Direction = MkDirection (Either Direction.Parallel.Parallel Direction.Diagonal.Diagonal) deriving (Eq, Ord)++instance Control.DeepSeq.NFData Direction where+ rnf (MkDirection d) = Control.DeepSeq.rnf ||| Control.DeepSeq.rnf $ d++instance Show Direction where+ showsPrec precedence (MkDirection d) = showsPrec precedence ||| showsPrec precedence $ d++instance Read Direction where+ readsPrec precedence string = let+ s' = Data.List.Extra.trimStart string+ in case readsPrec precedence s' of+ [(diagonal, s'')] -> [(MkDirection $ Right diagonal, s'')]+ _ -> case readsPrec precedence s' of+ [(parallel, s'')] -> [(MkDirection $ Left parallel, s'')]+ _ -> [] -- No parse.++instance Property.Opposable.Opposable Direction where+ getOpposite (MkDirection d) = MkDirection $ (Property.Opposable.getOpposite +++ Property.Opposable.getOpposite) d++instance Property.Orientated.Orientated Direction where+ isVertical (MkDirection (Left p)) = Property.Orientated.isVertical p+ isVertical _ = False++ isHorizontal (MkDirection (Left p)) = Property.Orientated.isHorizontal p+ isHorizontal _ = False++ isParallel (MkDirection (Left _)) = True+ isParallel _ = False++ isDiagonal (MkDirection (Right _)) = True+ isDiagonal _ = False++ isStraight = const True++instance Property.Reflectable.ReflectableOnX Direction where+ reflectOnX (MkDirection d) = MkDirection $ (Property.Reflectable.reflectOnX +++ Property.Reflectable.reflectOnX) d++instance Property.Reflectable.ReflectableOnY Direction where+ reflectOnY (MkDirection d) = MkDirection $ (Property.Reflectable.reflectOnY +++ Property.Reflectable.reflectOnY) d++instance Property.Rotatable.Rotatable Direction where+ rotate90 direction+ | Property.Orientated.isParallel direction = rotateParallel+ | otherwise = rotateDiagonal+ where+ rotateParallel+ | Property.Orientated.isVertical direction = rotateVertical+ | otherwise = rotateHorizontal+ where+ rotateVertical+ | direction == s = e+ | otherwise {-n-} = w++ rotateHorizontal+ | direction == w = s+ | otherwise {-e-} = n+ rotateDiagonal+ | direction == sw = se+ | direction == se = ne+ | direction == nw = sw+ | otherwise {-ne-} = nw++ rotate180 = Property.Opposable.getOpposite++instance Property.FixedMembership.FixedMembership Direction where+ members = parallels ++ diagonals++instance Bounded Direction where+ minBound = head Property.FixedMembership.members+ maxBound = last Property.FixedMembership.members++instance Data.Array.IArray.Ix Direction where+ range _ = Property.FixedMembership.members+ inRange _ _ = True+ index _ (MkDirection d) = fromEnum ||| (+ fromIntegral Direction.Parallel.nParallels) . fromEnum $ d++-- | Constant directions.+parallels :: [Direction]+s, n, w, e :: Direction+parallels@[s, n, w, e] = map (MkDirection . Left) Property.FixedMembership.members {-parallels-}++-- | Constant directions.+diagonals :: [Direction]+sw, se, nw, ne :: Direction+diagonals@[sw, se, nw, ne] = map (MkDirection . Right) Property.FixedMembership.members++{- |+ * Returns a list of /direction/s, each paired with its anti-parallel.++ * CAVEAT: each /direction/ only appears once in the list, on an arbitrary side of a pair.+-}+opposites :: [(Direction, Direction)]+opposites = map (id &&& Property.Opposable.getOpposite) [n, ne, e, se]++-- | The /direction/s in which a @Pawn@ can attack.+attackDirectionsForPawn :: Colour.LogicalColour.LogicalColour -> [Direction]+attackDirectionsForPawn Colour.LogicalColour.Black = [sw, se]+attackDirectionsForPawn _ = [nw, ne]++-- | Whether the two /direction/s specified, are either parallel or anti-parallel.+areAligned :: Direction -> Direction -> Bool+areAligned l = uncurry (||) . ((== l) &&& (== l) . Property.Opposable.getOpposite)++-- | A boxed array indexed by /direction/, of arbitrary elements.+type ArrayByDirection = Data.Array.IArray.Array {-Boxed-} Direction++-- | Array-constructor.+listArrayByDirection :: Data.Array.IArray.IArray a e => [e] -> a Direction e+listArrayByDirection = Data.Array.IArray.listArray (minBound, maxBound)+
+ src-lib/BishBosh/Direction/Horizontal.hs view
@@ -0,0 +1,66 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Describes the direction of a rank of the board.+-}++module BishBosh.Direction.Horizontal(+-- * Types+-- ** Data-types+ Horizontal(),+-- * Constants+-- range,+ nHorizontals+) where++import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count++-- | The sum-type of orientations of all lines of constant rank.+data Horizontal = W | E deriving (Enum, Eq, Ord, Show)++instance Read Horizontal where+ readsPrec _ ('W' : s) = [(W, s)]+ readsPrec _ ('E' : s) = [(E, s)]+ readsPrec _ _ = [] -- No parse.++instance Property.FixedMembership.FixedMembership Horizontal where+ members = range++instance Property.Opposable.Opposable Horizontal where+ getOpposite W = E+ getOpposite E = W++instance Property.Reflectable.ReflectableOnY Horizontal where+ reflectOnY = Property.Opposable.getOpposite++-- | Constant range of values.+range :: [Horizontal]+range = [ toEnum 0 .. ]++-- | The number of verticals directions.+nHorizontals :: Type.Count.NDirections+nHorizontals = fromIntegral $ length range+
+ src-lib/BishBosh/Direction/Parallel.hs view
@@ -0,0 +1,104 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Describes the directional components of a line parallel to an edge of the board.+-}++module BishBosh.Direction.Parallel(+-- * Types+-- ** Data-types+ Parallel(),+-- * Constants+-- range,+ nParallels+) where++import Control.Arrow((|||), (+++))+import qualified BishBosh.Direction.Horizontal as Direction.Horizontal+import qualified BishBosh.Direction.Vertical as Direction.Vertical+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count+import qualified Control.DeepSeq+import qualified Data.List.Extra++-- | Directions parallel to two edges of the board; those in which a Rook can move.+newtype Parallel = MkParallel (Either Direction.Vertical.Vertical Direction.Horizontal.Horizontal) deriving (Eq, Ord)++instance Control.DeepSeq.NFData Parallel where+ rnf (MkParallel p) = Control.DeepSeq.rwhnf ||| Control.DeepSeq.rwhnf $ p++instance Enum Parallel where+ fromEnum (MkParallel p) = fromEnum ||| (+ fromIntegral Direction.Vertical.nVerticals) . fromEnum $ p++ toEnum i = MkParallel $! case i `divMod` fromIntegral Direction.Vertical.nVerticals of+ (0, remainder) -> Left $! toEnum remainder+ (~1, remainder) -> Right $! toEnum remainder++instance Show Parallel where+ showsPrec precedence (MkParallel p) = showsPrec precedence ||| showsPrec precedence $ p++instance Read Parallel where+ readsPrec precedence s = let+ s' = Data.List.Extra.trimStart s+ in case readsPrec precedence s' of+ [(vertical, s'')] -> [(MkParallel $ Left vertical, s'')]+ _ -> case readsPrec precedence s' of+ [(horizontal, s'')] -> [(MkParallel $ Right horizontal, s'')]+ _ -> [] -- No parse.++instance Property.FixedMembership.FixedMembership Parallel where+ members = range++instance Property.Opposable.Opposable Parallel where+ getOpposite (MkParallel p) = MkParallel $ (Property.Opposable.getOpposite +++ Property.Opposable.getOpposite) p++instance Property.Orientated.Orientated Parallel where+ isVertical (MkParallel (Left _)) = True+ isVertical _ = False++ isHorizontal (MkParallel (Right _)) = True+ isHorizontal _ = False++ isParallel = const True++ isDiagonal = const False++ isStraight = const True++instance Property.Reflectable.ReflectableOnX Parallel where+ reflectOnX (MkParallel p) = MkParallel $ (Property.Reflectable.reflectOnX +++ id) p++instance Property.Reflectable.ReflectableOnY Parallel where+ reflectOnY (MkParallel p) = MkParallel $ (id +++ Property.Reflectable.reflectOnY) p++-- | Constant range of values.+range :: [Parallel]+range = take (fromIntegral $ Direction.Vertical.nVerticals + Direction.Horizontal.nHorizontals) [ toEnum 0 .. ]++-- | The number of verticals directions.+nParallels :: Type.Count.NDirections+nParallels = fromIntegral $ length range+
+ src-lib/BishBosh/Direction/Vertical.hs view
@@ -0,0 +1,66 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Describes the direction of a file of the board.+-}++module BishBosh.Direction.Vertical(+-- * Types+-- ** Data-types+ Vertical(),+-- * Constants+-- verticals,+ nVerticals+) where++import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count++-- | The sum-type of orientations of all lines of constant file.+data Vertical = S | N deriving (Enum, Eq, Ord, Show)++instance Read Vertical where+ readsPrec _ ('S' : s) = [(S, s)]+ readsPrec _ ('N' : s) = [(N, s)]+ readsPrec _ _ = [] -- No parse.++instance Property.FixedMembership.FixedMembership Vertical where+ members = verticals++instance Property.Opposable.Opposable Vertical where+ getOpposite S = N+ getOpposite N = S++instance Property.Reflectable.ReflectableOnX Vertical where+ reflectOnX = Property.Opposable.getOpposite++-- | Constant range of values.+verticals :: [Vertical]+verticals = [ toEnum 0 .. ]++-- | The number of verticals directions.+nVerticals :: Type.Count.NDirections+nVerticals = fromIntegral $ length verticals+
src-lib/BishBosh/Evaluation/Fitness.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -34,8 +33,8 @@ -- maximumDestinations, maximumDefended, -- * Functions- measurePieceSquareValue,- measurePieceSquareValueIncrementally,+ measurePieceSquareValueDifference,+ measurePieceSquareValueDifferenceIncrementally, measureValueOfMaterial, -- measureValueOfMobility, measureValueOfCastlingPotential,@@ -49,11 +48,11 @@ import Control.Applicative((<|>)) import Control.Arrow((&&&)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank@@ -78,49 +77,34 @@ import qualified Data.Map.Strict as Map import qualified Data.Maybe -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif---- | Measures the piece-square value from the perspective of the last player to move.-measurePieceSquareValue :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Num pieceSquareValue- )- => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+-- | Measures the difference in piece-square value between players, from the perspective of the last player to move.+measurePieceSquareValueDifference+ :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank -> Model.Game.Game- -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValue :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Mass.PieceSquareValue -> Model.Game.Game -> Type.Mass.PieceSquareValue #-}-measurePieceSquareValue pieceSquareByCoordinatesByRank game = (- if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game+ -> Type.Mass.Base+measurePieceSquareValueDifference pieceSquareByCoordinatesByRank game = (+ if Colour.LogicalColour.isBlack $! Model.Game.getNextLogicalColour game then id- else negate -- Represent the piece-square value from Black's perspective.- ) $ whitesPieceSquareValue - blacksPieceSquareValue where+ else negate -- Represent the piece-square value difference from Black's perspective.+ ) $! whitesPieceSquareValue - blacksPieceSquareValue where [blacksPieceSquareValue, whitesPieceSquareValue] = Data.Array.IArray.elems . State.Board.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank $ Model.Game.getBoard game {- |- * Measures the piece-square value from the perspective of the last player to move.+ * Measures the difference in piece-square value between players, from the perspective of the last player to move. * The previous value is provided, to enable calculation by difference. - * N.B.: because of diminishing returns, the piece-square value for everything but quiet moves is calculated from scratch.+ * N.B.: because of diminishing returns, the piece-square value for everything but simple moves is calculated from scratch. -}-measurePieceSquareValueIncrementally :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Num pieceSquareValue- )- => pieceSquareValue -- ^ The value before the last move was applied, & therefore also from the perspective of the previous player.- -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+measurePieceSquareValueDifferenceIncrementally+ :: Type.Mass.Base -- ^ The difference between players in the piece-square value, before the last move was applied & therefore also from the perspective of the previous player.+ -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank -> Model.Game.Game- -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValueIncrementally :: Type.Mass.PieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Mass.PieceSquareValue -> Model.Game.Game -> Type.Mass.PieceSquareValue #-}-measurePieceSquareValueIncrementally previousPieceSquareValue pieceSquareByCoordinatesByRank game- | Attribute.MoveType.isSimple $ Component.QualifiedMove.getMoveType qualifiedMove = let- findPieceSquareValue = uncurry (+ -> Type.Mass.Base+measurePieceSquareValueDifferenceIncrementally previousPieceSquareValueDifference pieceSquareByCoordinatesByRank game+ | Attribute.MoveType.isSimple $! Component.QualifiedMove.getMoveType qualifiedMove = let+ findPieceSquareValue :: Cartesian.Coordinates.Coordinates -> Type.Mass.Base+ findPieceSquareValue = realToFrac . uncurry ( Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank ) ( State.Board.getNPieces {- N.B.: no capture occurred-} . Model.Game.getBoard &&& Property.Opposable.getOpposite . Model.Game.getNextLogicalColour $ game {-the last player to move-}@@ -129,8 +113,8 @@ ) in uncurry (-) ( findPieceSquareValue . Component.Move.getDestination &&& findPieceSquareValue . Component.Move.getSource $ Component.QualifiedMove.getMove qualifiedMove- ) - previousPieceSquareValue {-from the previous player's perspective-}- | otherwise = measurePieceSquareValue pieceSquareByCoordinatesByRank game -- N.B.: though non-simple (Castling, En-passant, promotion) can be calculated, the returns don't justify the effort.+ ) - previousPieceSquareValueDifference {-from the previous player's perspective-}+ | otherwise = measurePieceSquareValueDifference pieceSquareByCoordinatesByRank game -- N.B.: though non-simple (Castling, En-passant, promotion) can be calculated, the returns don't justify the effort. where Just turn = Model.Game.maybeLastTurn game qualifiedMove = Component.Turn.getQualifiedMove turn@@ -144,14 +128,14 @@ measureValueOfMaterial rankValues maximumTotalRankValue game = realToFrac . ( / maximumTotalRankValue -- Normalise. ) . (- if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game+ if Colour.LogicalColour.isBlack $! Model.Game.getNextLogicalColour game then id -- White just moved. else negate -- Black just moved. ) . Data.List.foldl' ( \acc (rank, nPiecesDifference) -> if nPiecesDifference == 0 then acc -- Avoid calling 'Input.RankValues.findRankValue'. else acc + realToFrac (- Input.RankValues.findRankValue rank rankValues+ Input.RankValues.findRankValue rankValues rank ) * fromIntegral nPiecesDifference ) 0 . Data.Array.IArray.assocs . State.Board.getNPiecesDifferenceByRank {-which arbitrarily counts White pieces as positive & Black as negative-} $ Model.Game.getBoard game @@ -178,20 +162,20 @@ measureValueOfMobility :: Model.Game.Game -> Metric.CriterionValue.CriterionValue measureValueOfMobility game = realToFrac . uncurry (-) . ( measureConstriction &&& measureConstriction . Property.Opposable.getOpposite {-recent mover-}- ) $ Model.Game.getNextLogicalColour game where- measureConstriction :: Attribute.LogicalColour.LogicalColour -> Type.Mass.CriterionValue- measureConstriction logicalColour = recip . fromIntegral {-NPlies-} . succ {-avoid divide-by-zero-} $ Model.Game.countPliesAvailableTo logicalColour game+ ) $! Model.Game.getNextLogicalColour game where+ measureConstriction :: Colour.LogicalColour.LogicalColour -> Type.Mass.CriterionValue+ measureConstriction logicalColour = recip . fromIntegral {-NPlies-} . succ {-avoid divide-by-zero-} $ Model.Game.countPliesAvailableTo game logicalColour -- | Measure the arithmetic difference between the potential to /Castle/, on either side. measureValueOfCastlingPotential :: Model.Game.Game -> Metric.CriterionValue.CriterionValue measureValueOfCastlingPotential game = realToFrac . uncurry (-) . ( castlingPotential . Property.Opposable.getOpposite {-recent mover-} &&& castlingPotential ) $ Model.Game.getNextLogicalColour game where- castlingPotential :: Attribute.LogicalColour.LogicalColour -> Type.Mass.CriterionValue+ castlingPotential :: Colour.LogicalColour.LogicalColour -> Type.Mass.CriterionValue castlingPotential = Data.Maybe.maybe 1 {-have Castled-} ( (/ 2) . fromIntegral . length- ) . (- `State.CastleableRooksByLogicalColour.locateForLogicalColour` Model.Game.getCastleableRooksByLogicalColour game+ ) . State.CastleableRooksByLogicalColour.locateForLogicalColour (+ Model.Game.getCastleableRooksByLogicalColour game ) {- |@@ -209,7 +193,7 @@ ) . fromIntegral {-NPieces-} . uncurry (-) . ( countDoubledPawns &&& countDoubledPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where- countDoubledPawns :: Attribute.LogicalColour.LogicalColour -> Type.Count.NPieces+ countDoubledPawns :: Colour.LogicalColour.LogicalColour -> Type.Count.NPieces countDoubledPawns logicalColour = uncurry (-) . ( Data.Foldable.foldl' (+) 0 &&& fromIntegral . Data.Foldable.length {-one Pawn can't be considered to be doubled, so substract one Pawn per column-} ) $ State.Board.getNPawnsByFileByLogicalColour (Model.Game.getBoard game) ! logicalColour@@ -227,7 +211,7 @@ ) . fromIntegral {-NPieces-} . uncurry (-) . ( countIsolatedPawns &&& countIsolatedPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where- countIsolatedPawns :: Attribute.LogicalColour.LogicalColour -> Type.Count.NPieces+ countIsolatedPawns :: Colour.LogicalColour.LogicalColour -> Type.Count.NPieces countIsolatedPawns logicalColour = Map.foldlWithKey' ( \acc x nPawns -> if (`Map.member` nPawnsByFile) `any` Cartesian.Abscissa.getAdjacents x then acc -- This file has at least one neighbouring Pawn which can (if at a suitable rank) be used to protect any of those in this file.@@ -242,7 +226,7 @@ ) . uncurry (-) . ( valuePassedPawns . Property.Opposable.getOpposite {-recent mover-} &&& valuePassedPawns ) $ Model.Game.getNextLogicalColour game where- valuePassedPawns :: Attribute.LogicalColour.LogicalColour -> Type.Mass.CriterionValue+ valuePassedPawns :: Colour.LogicalColour.LogicalColour -> Type.Mass.CriterionValue valuePassedPawns logicalColour = Data.List.foldl' ( \acc -> (acc +) . recip {-value increases exponentially as distance to promotion decreases-} . fromIntegral . abs . subtract ( Cartesian.Ordinate.lastRank logicalColour@@ -298,19 +282,12 @@ * Many possible criteria aren't measured because they're, either currently or imminently, represented by those that are, typically by 'measureValueOfMaterial'. -}-evaluateFitness :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Fractional pieceSquareValue,- Real pieceSquareValue- )- => Maybe pieceSquareValue -- ^ An optional value for the specified game.+evaluateFitness+ :: Maybe Type.Mass.Base -- ^ An optional piece-square value difference for the specified game. -> Model.Game.Game- -> Input.EvaluationOptions.Reader pieceSquareValue Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues-{-# SPECIALISE evaluateFitness :: Maybe Type.Mass.PieceSquareValue -> Model.Game.Game -> Input.EvaluationOptions.Reader Type.Mass.PieceSquareValue Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues #-}-evaluateFitness maybePieceSquareValue game- | Just gameTerminationReason <- Model.Game.getMaybeTerminationReason game = return {-to Reader-monad-} $ Metric.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues (+ -> Input.EvaluationOptions.Reader Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues+evaluateFitness maybePieceSquareValueDifference game+ | Just gameTerminationReason <- Model.Game.getMaybeTerminationReason game = return {-to Reader-monad-} $! Metric.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues ( if Rule.GameTerminationReason.isCheckMate gameTerminationReason then 1 -- The last player to move, has won. else 0 -- A draw.@@ -320,14 +297,14 @@ rankValuePair <- Control.Monad.Reader.asks $ Input.EvaluationOptions.getRankValues &&& Input.EvaluationOptions.getMaximumTotalRankValue maybePieceSquareByCoordinatesByRank <- Control.Monad.Reader.asks Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank - return {-to Reader-monad-} $ Input.CriteriaWeights.calculateWeightedMean criteriaWeights (+ return {-to Reader-monad-} $! Input.CriteriaWeights.calculateWeightedMean criteriaWeights ( uncurry measureValueOfMaterial rankValuePair game ) ( measureValueOfMobility game ) ( Data.Maybe.maybe 0 (- realToFrac . (/ fromIntegral Component.Piece.nPiecesPerSide)- ) $ maybePieceSquareValue <|> fmap (`measurePieceSquareValue` game) maybePieceSquareByCoordinatesByRank+ realToFrac . (/ fromIntegral Component.Piece.nPiecesPerSide) -- Normalise.+ ) $ maybePieceSquareValueDifference <|> fmap (`measurePieceSquareValueDifference` game) maybePieceSquareByCoordinatesByRank ) ( measureValueOfCastlingPotential game ) (
src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -51,8 +50,8 @@ reduce, traceRoute, resign,- traceMatchingMoves,- promoteMatchingMoves,+ traceMatchingMoveSequence,+ promoteMatchingMoveSequence, sortNonCaptureMoves, -- ** Accessors getRootQuantifiedGame',@@ -83,17 +82,12 @@ import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.Monad.Reader import qualified Data.Bits import qualified Data.Maybe import qualified Data.Tree -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | Define a node in the tree to contain the hash of a /game/ & an evaluation of the fitness of that /game/. data NodeLabel positionHash = MkNodeLabel { getPositionHash :: positionHash, -- ^ The hash of the /game/ contained in 'getQuantifiedGame'.@@ -129,7 +123,7 @@ } deriving Eq instance Property.Arboreal.Prunable (PositionHashQuantifiedGameTree positionHash) where- prune depth MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree $ Property.Arboreal.prune depth barePositionHashQuantifiedGameTree+ prune depth MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree $ Data.RoseTree.prune depth barePositionHashQuantifiedGameTree instance Notation.MoveNotation.ShowNotationFloat (PositionHashQuantifiedGameTree positionHash) where showsNotationFloat moveNotation showsDouble MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = showString $ (@@ -144,22 +138,16 @@ fromBarePositionHashQuantifiedGameTree = MkPositionHashQuantifiedGameTree -- | Constructor.-mkPositionHashQuantifiedGameTree :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Data.Bits.Bits positionHash,- Fractional pieceSquareValue,- Real pieceSquareValue- )- => Input.EvaluationOptions.EvaluationOptions pieceSquareValue+mkPositionHashQuantifiedGameTree+ :: Data.Bits.Bits positionHash+ => Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Component.Zobrist.Zobrist positionHash -> Model.GameTree.MoveFrequency -> Model.Game.Game -- ^ The current state of the /game/. -> PositionHashQuantifiedGameTree positionHash {-# SPECIALISE mkPositionHashQuantifiedGameTree- :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue+ :: Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Component.Zobrist.Zobrist Type.Crypto.PositionHash -> Model.GameTree.MoveFrequency@@ -169,11 +157,11 @@ mkPositionHashQuantifiedGameTree evaluationOptions searchOptions zobrist moveFrequency seedGame = MkPositionHashQuantifiedGameTree ( if Input.EvaluationOptions.getIncrementalEvaluation evaluationOptions then let- apexPositionHash = StateProperty.Hashable.hash seedGame zobrist+ apexPositionHash = StateProperty.Hashable.hash zobrist seedGame in Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel apexPositionHash $ Control.Monad.Reader.runReader ( Evaluation.QuantifiedGame.fromGame Nothing seedGame- ) evaluationOptions, -- Neither the previous positionHash nor the previous pieceSquareValue, are available to support incremental construction.+ ) evaluationOptions, -- Neither the previous positionHash nor the previous pieceSquareValueDifference, are available to support incremental construction. Data.Tree.subForest = map ( Data.Maybe.maybe ( let@@ -190,33 +178,31 @@ in slave ) ( \pieceSquareByCoordinatesByRank -> let- slave pieceSquareValue positionHash game Data.Tree.Node {+ slave pieceSquareValueDifference positionHash game Data.Tree.Node { Data.Tree.rootLabel = game', Data.Tree.subForest = gameForest' } = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel positionHash' $ Control.Monad.Reader.runReader (- Evaluation.QuantifiedGame.fromGame (Just pieceSquareValue') game'+ Evaluation.QuantifiedGame.fromGame (Just pieceSquareValueDifference') game' ) evaluationOptions,- Data.Tree.subForest = map (slave pieceSquareValue' positionHash' game') gameForest' -- Recurse.+ Data.Tree.subForest = map (slave pieceSquareValueDifference' positionHash' game') gameForest' -- Recurse. } where- pieceSquareValue' = Evaluation.Fitness.measurePieceSquareValueIncrementally pieceSquareValue pieceSquareByCoordinatesByRank game'- positionHash' = Model.Game.updateIncrementalPositionHash game positionHash game' zobrist- in slave $ Evaluation.Fitness.measurePieceSquareValue pieceSquareByCoordinatesByRank seedGame+ pieceSquareValueDifference' = Evaluation.Fitness.measurePieceSquareValueDifferenceIncrementally pieceSquareValueDifference pieceSquareByCoordinatesByRank game'+ positionHash' = Model.Game.updateIncrementalPositionHash game positionHash game' zobrist+ in slave $ Evaluation.Fitness.measurePieceSquareValueDifference pieceSquareByCoordinatesByRank seedGame ) ( Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions ) apexPositionHash seedGame ) $ Data.Tree.subForest bareGameTree }- else fmap (- uncurry MkNodeLabel . (- (`StateProperty.Hashable.hash` zobrist) &&& (`Control.Monad.Reader.runReader` evaluationOptions) . Evaluation.QuantifiedGame.fromGame Nothing- )- ) bareGameTree+ else uncurry MkNodeLabel . (+ StateProperty.Hashable.hash zobrist &&& (`Control.Monad.Reader.runReader` evaluationOptions) . Evaluation.QuantifiedGame.fromGame Nothing+ ) <$> bareGameTree ) where bareGameTree = Model.GameTree.deconstruct . Model.GameTree.sortGameTree ( Input.SearchOptions.getMaybeCaptureMoveSortAlgorithm searchOptions ) (- `Input.RankValues.findRankValue` Input.EvaluationOptions.getRankValues evaluationOptions+ Input.RankValues.findRankValue $ Input.EvaluationOptions.getRankValues evaluationOptions ) moveFrequency $ Model.GameTree.fromGame seedGame -- | Accessor.@@ -240,7 +226,7 @@ :: Data.RoseTree.IsMatch (NodeLabel positionHash) -> PositionHashQuantifiedGameTree positionHash -> Maybe (PositionHashQuantifiedGameTree positionHash)-reduce isMatch MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree `fmap` Data.RoseTree.reduce isMatch barePositionHashQuantifiedGameTree+reduce isMatch MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree <$> Data.RoseTree.reduce isMatch barePositionHashQuantifiedGameTree -- | Forward request. traceRoute@@ -251,11 +237,11 @@ traceRoute isMatch MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = Data.RoseTree.traceRoute isMatch barePositionHashQuantifiedGameTree -- | Follow the specified move-sequence down the /positionHashQuantifiedGameTree/.-traceMatchingMoves+traceMatchingMoveSequence :: PositionHashQuantifiedGameTree positionHash- -> [Component.QualifiedMove.QualifiedMove]+ -> Component.QualifiedMove.QualifiedMoveSequence -> Maybe [NodeLabel positionHash] -- ^ Returns 'Nothing', on failure to match a move.-traceMatchingMoves MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = Data.RoseTree.traceRoute equalsLastQualifiedMove barePositionHashQuantifiedGameTree+traceMatchingMoveSequence MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = Data.RoseTree.traceRoute equalsLastQualifiedMove barePositionHashQuantifiedGameTree -- | Amend the apex-game to reflect the resignation of the next player. resign :: PositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash@@ -277,11 +263,11 @@ * N.B.: this can be used to dynamically re-order the forest when a transposition is detected. -}-promoteMatchingMoves- :: [Component.QualifiedMove.QualifiedMove] -- ^ The list of qualifiedMoves, which should be promoted at successively deeper levels in the tree.+promoteMatchingMoveSequence+ :: Component.QualifiedMove.QualifiedMoveSequence -- ^ The list of qualifiedMoves, which should be promoted at successively deeper levels in the tree. -> Forest positionHash- -> Maybe (Forest positionHash) -- ^ Returns 'Nothing' on failure to match a move.-promoteMatchingMoves = Data.RoseTree.promote equalsLastQualifiedMove+ -> Maybe (Forest positionHash) -- ^ Returns 'Nothing' on failure to match a move.+promoteMatchingMoveSequence = Data.RoseTree.promote equalsLastQualifiedMove {- | * Sorts the forest, starting just after any initial capture-moves.
src-lib/BishBosh/Evaluation/QuantifiedGame.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -40,7 +39,6 @@ -- * Constants unboundedInterval, -- * Functions- compareFitness, -- ** Accessors getFitness, -- ** Constructors@@ -50,7 +48,10 @@ getLatestTurns, -- ** Mutators negateFitness,- negateInterval+ negateInterval,+-- ** Predicates+ (<=>),+ (===) ) where import Control.Arrow((&&&))@@ -71,10 +72,6 @@ import qualified Data.Maybe import qualified Data.Ord -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | The selected /game/ & the criteria against which it was quantified. data QuantifiedGame = MkQuantifiedGame { getGame :: Model.Game.Game, -- ^ The /game/ resulting from a sequence of /turn/s.@@ -98,18 +95,28 @@ getFitness :: QuantifiedGame -> Type.Mass.WeightedMean getFitness MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Metric.WeightedMeanAndCriterionValues.getWeightedMean weightedMeanAndCriterionValues +-- | Space-ship operator, like in Perl.+(<=>) :: QuantifiedGame -> QuantifiedGame -> Ordering+(<=>) = Data.Ord.comparing getFitness++infix 4 <=> -- Same as (>).++{- |+ * Whether the games have taken the same move-sequences, & as such have the same position.++ * CAVEAT: the games won't be identical if they started from different positions, but by some fluke managed to make the same sequence of moves.+-}+(===) :: QuantifiedGame -> QuantifiedGame -> Bool+lhs === rhs = uncurry (==) . (($ lhs) &&& ($ rhs)) $ Model.Game.getTurnsByLogicalColour . getGame++infix 4 === -- Same as (==).+ -- | Constructor.-fromGame :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Fractional pieceSquareValue,- Real pieceSquareValue- )- => Maybe pieceSquareValue -- ^ The value for the specified game.- -> Model.Game.Game -- ^ The current state of the /game/.- -> Input.EvaluationOptions.Reader pieceSquareValue QuantifiedGame-fromGame maybePieceSquareValue game = MkQuantifiedGame game `fmap` Evaluation.Fitness.evaluateFitness maybePieceSquareValue game+fromGame+ :: Maybe Type.Mass.Base -- ^ The piece-square value difference for the specified game.+ -> Model.Game.Game -- ^ The current state of the /game/.+ -> Input.EvaluationOptions.Reader QuantifiedGame+fromGame maybePieceSquareValueDifference game = MkQuantifiedGame game <$> Evaluation.Fitness.evaluateFitness maybePieceSquareValueDifference game -- | Retrieve the /turn/ used to generate the selected /game/. getLastTurn :: QuantifiedGame -> Component.Turn.Turn@@ -127,10 +134,6 @@ -- | Represent the /fitness/ of the /game/ resulting from a future /move/ by the opponent, from the perspective of the current player. negateFitness :: QuantifiedGame -> QuantifiedGame negateFitness quantifiedGame@MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = quantifiedGame { getWeightedMeanAndCriterionValues = Metric.WeightedMeanAndCriterionValues.negateWeightedMean weightedMeanAndCriterionValues }---- | Compares fitness.-compareFitness :: QuantifiedGame -> QuantifiedGame -> Ordering-compareFitness = Data.Ord.comparing getFitness {- | * The open interval in which to search for better solutions.
src-lib/BishBosh/Input/CommandLineOption.hs view
@@ -111,6 +111,7 @@ -> [String] -- ^ The command-line arguments to search. -> [String] -- ^ The matching argument-values. getArgs flags = slave where+ slave :: [String] -> [String] slave [] = [] slave (x : xs) | x `elem` flags = case xs of
src-lib/BishBosh/Input/EvaluationOptions.hs view
@@ -69,6 +69,7 @@ import qualified Control.DeepSeq import qualified Control.Exception import qualified Control.Monad.Reader+import qualified Data.Array.IArray import qualified Data.Default import qualified Data.Foldable import qualified Data.Maybe@@ -94,21 +95,19 @@ type IncrementalEvaluation = Bool -- | A pair of piece-square tables representing the opening & end-games respectively.-type PieceSquareTablePair pieceSquareValue = (Input.PieceSquareTable.PieceSquareTable pieceSquareValue, Input.PieceSquareTable.PieceSquareTable pieceSquareValue)+type PieceSquareTablePair = (Input.PieceSquareTable.PieceSquareTable, Input.PieceSquareTable.PieceSquareTable) -- | Defines the options related to the automatic selection of /move/s.-data EvaluationOptions pieceSquareValue = MkEvaluationOptions {- getRankValues :: Input.RankValues.RankValues, -- ^ The static value associated with each /piece/'s /rank/.- getMaximumTotalRankValue :: Type.Mass.RankValue, -- ^ Used to normalise the total value of pieces. Derived from 'getRankValues'.- getCriteriaWeights :: Input.CriteriaWeights.CriteriaWeights, -- ^ The weights applied to each of the heterogeneous criterion-values used to select a /move/.- getIncrementalEvaluation :: IncrementalEvaluation, -- ^ Whether to generate position-hashes & evaluate the piece-square value, from the previous value or from scratch.- getMaybePieceSquareTablePair :: Maybe (PieceSquareTablePair pieceSquareValue), -- ^ A optional pair of piece-square tables representing the opening & end-games respectively.- getMaybePieceSquareByCoordinatesByRank :: Maybe (- Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue- ) -- ^ The optional value for each rank of /piece/, when occupying each coordinate, at each phase of the game.+data EvaluationOptions = MkEvaluationOptions {+ getRankValues :: Input.RankValues.RankValues, -- ^ The static value associated with each /piece/'s /rank/.+ getMaximumTotalRankValue :: Type.Mass.RankValue, -- ^ Used to normalise the total value of pieces. Derived from 'getRankValues'.+ getCriteriaWeights :: Input.CriteriaWeights.CriteriaWeights, -- ^ The weights applied to each of the heterogeneous criterion-values used to select a /move/.+ getIncrementalEvaluation :: IncrementalEvaluation, -- ^ Whether to generate position-hashes & evaluate the piece-square value, from the previous value or from scratch.+ getMaybePieceSquareTablePair :: Maybe PieceSquareTablePair, -- ^ A optional pair of piece-square tables representing the opening & end-games respectively.+ getMaybePieceSquareByCoordinatesByRank :: Maybe Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank -- ^ The optional value for each rank of /piece/, when occupying each coordinate, at each phase of the game. } deriving (Eq, Show) -instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (EvaluationOptions pieceSquareValue) where+instance Control.DeepSeq.NFData EvaluationOptions where rnf MkEvaluationOptions { -- getRankValues = rankValues, getMaximumTotalRankValue = maximumTotalValue,@@ -118,7 +117,7 @@ getMaybePieceSquareByCoordinatesByRank = maybePieceSquareByCoordinatesByRank } = Control.DeepSeq.rnf (maximumTotalValue, criteriaWeights, incrementalEvaluation, maybePieceSquareByCoordinatesByRank) -instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (EvaluationOptions pieceSquareValue) where+instance Property.ShowFloat.ShowFloat EvaluationOptions where showsFloat fromDouble MkEvaluationOptions { getRankValues = rankValues, -- getMaximumTotalRankValue = maximumTotalValue,@@ -146,7 +145,7 @@ ] ) maybePieceSquareTablePair -instance Data.Default.Default (EvaluationOptions pieceSquareValue) where+instance Data.Default.Default EvaluationOptions where def = MkEvaluationOptions { getRankValues = rankValues, getMaximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues,@@ -157,12 +156,7 @@ } where rankValues = Data.Default.def -instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Real pieceSquareValue,- Show pieceSquareValue- ) => HXT.XmlPickler (EvaluationOptions pieceSquareValue) where+instance HXT.XmlPickler EvaluationOptions where xpickle = HXT.xpDefault def . HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d) -> mkEvaluationOptions a b c d, -- Construct. \MkEvaluationOptions {@@ -184,27 +178,26 @@ def = Data.Default.def -- | Convert a /PieceSquareTablePair/ to a single linearly interpolated array.-fromPieceSquareTablePair :: Fractional pieceSquareValue => PieceSquareTablePair pieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+fromPieceSquareTablePair :: PieceSquareTablePair -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank fromPieceSquareTablePair pieceSquareTablePair = Component.PieceSquareByCoordinatesByRank.mkPieceSquareByCoordinatesByRank $ \rank -> (- \(openingGamePieceSquareValuesByCoordinates, maybeEndGamePieceSquareValuesByCoordinates) -> Data.Maybe.maybe (- Left openingGamePieceSquareValuesByCoordinates+ \(openingGamePieceSquareValueByCoordinates, maybeEndGamePieceSquareValueByCoordinates) -> Data.Maybe.maybe (+ Left openingGamePieceSquareValueByCoordinates ) ( Right . Cartesian.Coordinates.listArrayByCoordinates . zipWith Component.PieceSquareByCoordinatesByRank.interpolatePieceSquareValues (- Data.Foldable.toList openingGamePieceSquareValuesByCoordinates- ) . Data.Foldable.toList- ) maybeEndGamePieceSquareValuesByCoordinates+ Data.Array.IArray.elems openingGamePieceSquareValueByCoordinates+ ) . Data.Array.IArray.elems+ ) maybeEndGamePieceSquareValueByCoordinates ) $ ( Data.Maybe.fromJust {-values for the openingGame must be specified-} . Input.PieceSquareTable.dereference rank *** Input.PieceSquareTable.dereference rank ) pieceSquareTablePair -- | Smart constructor. mkEvaluationOptions- :: Fractional pieceSquareValue- => Input.RankValues.RankValues -- ^ The static value associated with each /piece/'s /rank/.- -> Input.CriteriaWeights.CriteriaWeights -- ^ The weights applied to the values of the criteria used to select a /move/.+ :: Input.RankValues.RankValues -- ^ The static value associated with each /piece/'s /rank/.+ -> Input.CriteriaWeights.CriteriaWeights -- ^ The weights applied to the values of the criteria used to select a /move/. -> IncrementalEvaluation- -> Maybe (PieceSquareTablePair pieceSquareValue) -- ^ The value to each type of piece, of each square, during normal play & the end-game.- -> EvaluationOptions pieceSquareValue+ -> Maybe PieceSquareTablePair -- ^ The value to each type of piece, of each square, during normal play & the end-game.+ -> EvaluationOptions mkEvaluationOptions rankValues criteriaWeights incrementalEvaluation maybePieceSquareTablePair | Just (pieceSquareTable, _) <- maybePieceSquareTablePair , let undefinedRanks = Input.PieceSquareTable.findUndefinedRanks pieceSquareTable@@ -220,10 +213,10 @@ getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, getMaybePieceSquareTablePair = maybePieceSquareTablePair,- getMaybePieceSquareByCoordinatesByRank = fromPieceSquareTablePair `fmap` maybePieceSquareTablePair -- Infer.+ getMaybePieceSquareByCoordinatesByRank = fromPieceSquareTablePair <$> maybePieceSquareTablePair -- Infer. } where maximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues -- | Self-documentation.-type Reader pieceSquareValue = Control.Monad.Reader.Reader (EvaluationOptions pieceSquareValue)+type Reader = Control.Monad.Reader.Reader EvaluationOptions
src-lib/BishBosh/Input/NativeUIOptions.hs view
@@ -46,7 +46,7 @@ import BishBosh.Data.Bool() import Control.Arrow((***))-import qualified BishBosh.Attribute.ColourScheme as Attribute.ColourScheme+import qualified BishBosh.Colour.ColourScheme as Colour.ColourScheme import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Length as Type.Length@@ -84,7 +84,7 @@ -- | Constructor. data NativeUIOptions = MkNativeUIOptions { getBoardMagnification :: ScreenCoordinates, -- ^ The factor by which the dimensions of the board are stretched when displayed.- getColourScheme :: Attribute.ColourScheme.ColourScheme,+ getColourScheme :: Colour.ColourScheme.ColourScheme, getDepictFigurine :: DepictFigurine -- ^ Whether to a depict pieces using Unicode figurines. } deriving Eq @@ -109,7 +109,7 @@ boardMagnificationTag, showsPrec precision boardMagnification ), (- Attribute.ColourScheme.tag,+ Colour.ColourScheme.tag, showsPrec precision colourScheme ), ( depictFigurineTag,@@ -150,7 +150,7 @@ -- | Smart constructor. mkNativeUIOptions :: ScreenCoordinates -- ^ The factor by which the dimensions of the board are stretched when displayed.- -> Attribute.ColourScheme.ColourScheme+ -> Colour.ColourScheme.ColourScheme -> DepictFigurine -> NativeUIOptions mkNativeUIOptions boardMagnification colourScheme depictFigurine
src-lib/BishBosh/Input/Options.hs view
@@ -93,15 +93,15 @@ type RandomSeed = Int -- | Defines the application's options.-data Options pieceSquareValue = MkOptions {- getMaybeMaximumPlies :: Maybe Type.Count.NPlies, -- ^ The maximum number of plies before the game is terminated; required for profiling the application.- getMaybeRandomSeed :: Maybe RandomSeed, -- ^ Optionally seed the pseudo-random number-generator to produce a repeatable sequence.- getEvaluationOptions :: Input.EvaluationOptions.EvaluationOptions pieceSquareValue, -- ^ The single set of options by which all automated /move/s are evaluated.- getSearchOptions :: Input.SearchOptions.SearchOptions, -- ^ The options by which to automatically select /move/s.- getIOOptions :: Input.IOOptions.IOOptions -- ^ The /ioOptions/ by which to receive commands & present results.+data Options = MkOptions {+ getMaybeMaximumPlies :: Maybe Type.Count.NPlies, -- ^ The maximum number of plies before the game is terminated; required for profiling the application.+ getMaybeRandomSeed :: Maybe RandomSeed, -- ^ Optionally seed the pseudo-random number-generator to produce a repeatable sequence.+ getEvaluationOptions :: Input.EvaluationOptions.EvaluationOptions, -- ^ The single set of options by which all automated /move/s are evaluated.+ getSearchOptions :: Input.SearchOptions.SearchOptions, -- ^ The options by which to automatically select /move/s.+ getIOOptions :: Input.IOOptions.IOOptions -- ^ The /ioOptions/ by which to receive commands & present results. } deriving (Eq, Show) -instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (Options pieceSquareValue) where+instance Control.DeepSeq.NFData Options where rnf MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -110,7 +110,7 @@ getIOOptions = ioOptions } = Control.DeepSeq.rnf (maybeMaximumPlies, maybeRandomSeed, evaluationOptions, searchOptions, ioOptions) -instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (Options pieceSquareValue) where+instance Property.ShowFloat.ShowFloat Options where showsFloat fromDouble MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -134,7 +134,7 @@ ) ] -instance Data.Default.Default (Options pieceSquareValue) where+instance Data.Default.Default Options where def = MkOptions { getMaybeMaximumPlies = Nothing, getMaybeRandomSeed = Nothing,@@ -143,12 +143,7 @@ getIOOptions = Data.Default.def } -instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Real pieceSquareValue,- Show pieceSquareValue- ) => HXT.XmlPickler (Options pieceSquareValue) where+instance HXT.XmlPickler Options where xpickle = HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d, e) -> mkOptions a b c d e, -- Construct. \MkOptions {@@ -174,10 +169,10 @@ mkOptions :: Maybe Type.Count.NPlies -- ^ The maximum number of plies before the game is terminated; required for profiling the application. -> Maybe RandomSeed -- ^ Optionally seed the pseudo-random number-generator to produce a repeatable sequence.- -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue+ -> Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Input.IOOptions.IOOptions- -> Options pieceSquareValue+ -> Options mkOptions maybeMaximumPlies maybeRandomSeed evaluationOptions searchOptions ioOptions | Just maximumPlies <- maybeMaximumPlies , maximumPlies <= 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.Options.mkOptions:\t" . showString maximumPliesTag . Text.ShowList.showsAssociation $ shows maximumPlies " must exceed zero."@@ -193,22 +188,22 @@ } -- | The type of a function used to transform 'Options'.-type Transformation pieceSquareValue = Options pieceSquareValue -> Options pieceSquareValue+type Transformation = Options -> Options -- | Mutator.-setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation pieceSquareValue+setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation setMaybeOutputConfigFilePath maybeOutputConfigFilePath options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybeOutputConfigFilePath maybeOutputConfigFilePath ioOptions } -- | Mutator.-setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue+setMaybeRandomSeed :: Maybe RandomSeed -> Transformation setMaybeRandomSeed maybeRandomSeed options = options { getMaybeRandomSeed = maybeRandomSeed } -- | Mutator.-setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation pieceSquareValue+setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation setMaybePersistence maybePersistence options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = ioOptions { Input.IOOptions.getMaybePersistence = maybePersistence@@ -216,25 +211,25 @@ } -- | Mutator.-setVerbosity :: Input.Verbosity.Verbosity -> Transformation pieceSquareValue+setVerbosity :: Input.Verbosity.Verbosity -> Transformation setVerbosity verbosity options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setVerbosity verbosity ioOptions } -- | Mutator.-setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue+setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions ioOptions } -- | Mutator.-setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation pieceSquareValue+setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation setMaybePrintMoveTree maybePrintMoveTree options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybePrintMoveTree maybePrintMoveTree ioOptions } -- | Mutator.-swapSearchDepth :: Transformation pieceSquareValue+swapSearchDepth :: Transformation swapSearchDepth options@MkOptions { getSearchOptions = searchOptions } = options { getSearchOptions = Input.SearchOptions.swapSearchDepth searchOptions }
src-lib/BishBosh/Input/PieceSquareTable.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -40,6 +41,7 @@ -- ** Type-synonyms -- Normalise, -- ReflectOnY,+-- PieceSquareValueByCoordinates, IOFormat, Assocs, -- ** Data-types@@ -61,7 +63,7 @@ -- ** Constructors mkPieceSquareTable, -- ** Predicates- inClosedUnitInterval+-- inClosedUnitInterval ) where import BishBosh.Data.Bool() -- HXT.XmlPickler.@@ -77,10 +79,11 @@ import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Text.Case as Text.Case import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.Exception+import qualified Data.Array.IArray import qualified Data.Default-import qualified Data.Foldable import qualified Data.Map.Strict as Map import qualified Data.Set import qualified Text.XML.HXT.Arrow.Pickle as HXT@@ -103,20 +106,27 @@ -- | Type-synonym. type ReflectOnY = Bool +-- | Self-documentation.+type PieceSquareValueByCoordinates =+#if defined(USE_UNBOXED_ARRAYS) && !(defined(USE_NEWTYPE_WRAPPERS) || defined(USE_PRECISION))+ Cartesian.Coordinates.UArrayByCoordinates+#else+ Cartesian.Coordinates.ArrayByCoordinates+#endif+ Type.Mass.PieceSquareValue+ -- | Defines the value for each type of piece, of occupying each square.-data PieceSquareTable pieceSquareValue = MkPieceSquareTable {- getNormalise :: Normalise, -- ^ Whether to map the specified values into the closed unit-interval. CAVEAT: incompatible with RelaxNG, the specification for which already constrains values to the unit-interval.- getReflectOnY :: ReflectOnY, -- ^ Whether values for the RHS of the board should be inferred by reflection about the y-axis.- getPieceSquareValueByCoordinatesByRank :: Map.Map Attribute.Rank.Rank (- Cartesian.Coordinates.ArrayByCoordinates pieceSquareValue- ) -- ^ N.B.: on the assumption that the values for Black pieces are the reflection of those for White, merely the /rank/ of each /piece/ need be defined.+data PieceSquareTable = MkPieceSquareTable {+ getNormalise :: Normalise, -- ^ Whether to map the specified values into the closed unit-interval. CAVEAT: incompatible with RelaxNG, the specification for which already constrains values to the unit-interval.+ getReflectOnY :: ReflectOnY, -- ^ Whether values for the RHS of the board should be inferred by reflection about the y-axis.+ getPieceSquareValueByCoordinatesByRank :: Map.Map Attribute.Rank.Rank PieceSquareValueByCoordinates -- ^ N.B.: on the assumption that the values for Black pieces are the reflection of those for White, merely the /rank/ of each /piece/ need be defined. } deriving (Eq, Show) -instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (PieceSquareTable pieceSquareValue) where+instance Property.ShowFloat.ShowFloat PieceSquareTable where showsFloat fromDouble MkPieceSquareTable { getNormalise = normalise, getReflectOnY = reflectOnY,- getPieceSquareValueByCoordinatesByRank = byRank+ getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Text.ShowList.showsAssociationList Text.ShowList.showsSeparator $ ( normaliseTag, shows normalise@@ -130,12 +140,12 @@ if reflectOnY then unmirror else id- ) . Data.Foldable.toList+ ) . Data.Array.IArray.elems ) (- Map.toList byRank+ Map.toList pieceSquareValueByCoordinatesByRank ) -instance Data.Default.Default (PieceSquareTable pieceSquareValue) where+instance Data.Default.Default PieceSquareTable where def = MkPieceSquareTable { getNormalise = False, getReflectOnY = True,@@ -145,28 +155,23 @@ -- | The format of the values when read or written. type IOFormat = Double -instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Real pieceSquareValue,- Show pieceSquareValue- ) => HXT.XmlPickler (PieceSquareTable pieceSquareValue) where+instance HXT.XmlPickler PieceSquareTable where xpickle = HXT.xpWrap ( \(a, b, c) -> mkPieceSquareTable a b c, -- Construct. \MkPieceSquareTable { getNormalise = normalise, getReflectOnY = reflectOnY,- getPieceSquareValueByCoordinatesByRank = byRank+ getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } -> ( normalise, reflectOnY, Map.toList $ Map.map (- (+ map realToFrac . ( if reflectOnY then unmirror else id- ) . Data.Foldable.toList- ) byRank+ ) . Data.Array.IArray.elems+ ) pieceSquareValueByCoordinatesByRank ) -- Deconstruct to tuple. ) . HXT.xpTriple ( getNormalise Data.Default.def `HXT.xpDefault` HXT.xpAttr normaliseTag HXT.xpickle {-Bool-}@@ -177,11 +182,13 @@ showString "by" $ Text.Case.toUpperInitial Attribute.Rank.tag ) $ HXT.xpickle {-rank-} `HXT.xpPair` HXT.xpWrap ( \s -> [- realToFrac (pieceSquareValue :: IOFormat) |+ (realToFrac :: IOFormat -> Type.Mass.Base) pieceSquareValue | word <- words s, (pieceSquareValue, "") <- reads word ], -- List-comprehension.- unwords . map (show . (\pieceSquareValue -> realToFrac pieceSquareValue :: IOFormat))+ unwords . map (+ show . (realToFrac :: Type.Mass.Base -> IOFormat)+ ) -- Deconstruct. ) ( HXT.xpTextAttr . showString "by" $ Text.Case.toUpperInitial Cartesian.Coordinates.tag )@@ -191,26 +198,20 @@ type Assocs rank pieceSquareValue = [(rank, [pieceSquareValue])] -- | Map the range of values onto the Closed Unit Interval.-normaliseToUnitInterval- :: (Fractional pieceSquareValue, Ord pieceSquareValue)- => Assocs rank pieceSquareValue- -> Assocs rank pieceSquareValue+normaliseToUnitInterval :: (Fractional pieceSquareValueIn, Real pieceSquareValueIn, Fractional pieceSquareValueOut) => Assocs rank pieceSquareValueIn -> Assocs rank pieceSquareValueOut normaliseToUnitInterval [] = [] normaliseToUnitInterval assocs | range == 0 = Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Input.PieceSquareTable.normaliseToUnitInterval:\tthe specified piece-square values are identical." | otherwise = map (- Control.Arrow.second $ map ((/ range) . subtract minimum')+ Control.Arrow.second $ map (realToFrac . (/ range) . subtract minimum') ) assocs where bounds@(minimum', _) = minimum &&& maximum $ concatMap snd assocs -- Analyse the range of values. range = uncurry subtract bounds -- | Check that the range of values is in the Closed Unit Interval.-inClosedUnitInterval- :: (Num pieceSquareValue, Ord pieceSquareValue)- => Assocs rank pieceSquareValue- -> Bool-inClosedUnitInterval = all $ all Data.Num.inClosedUnitInterval . snd {-[pieceSquareValue]-}+inClosedUnitInterval :: (Num pieceSquareValue, Ord pieceSquareValue) => Assocs rank pieceSquareValue -> Bool+inClosedUnitInterval = all $ all Data.Num.inClosedUnitInterval . snd {-[PieceSquareValue]-} -- | Generates a mirror-symmetric RHS, to build a complete description. mirror :: Show pieceSquareValue => [pieceSquareValue] -> [pieceSquareValue]@@ -225,18 +226,14 @@ unmirror pieceSquareValues = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.PieceSquareTable.unmirror:\tthe number of piece-square values must be a multiple of " . shows (Cartesian.Abscissa.xLength `div` 2) . showString "; " $ shows pieceSquareValues "." -- | Smart constructor.-mkPieceSquareTable :: (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Show pieceSquareValue- )- => Normalise -- ^ Whether to normalise the specified values into the closed unit interval.+mkPieceSquareTable+ :: Normalise -- ^ Whether to normalise the specified values into the closed unit interval. -> ReflectOnY -- ^ Whether values for the RHS of the board are inferred by reflection about the y-axis.- -> Assocs Attribute.Rank.Rank pieceSquareValue- -> PieceSquareTable pieceSquareValue+ -> Assocs Attribute.Rank.Rank Type.Mass.Base+ -> PieceSquareTable mkPieceSquareTable normalise reflectOnY assocs | any (- (/= nValuesRequired) . fromIntegral . length . snd {-pieceSquareValues-}+ (/= nValuesRequired) . fromIntegral . length . snd {-PieceSquareValues-} ) assocs = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.PieceSquareTable.mkPieceSquareTable:\texactly " . shows nValuesRequired . showString " values must be defined for each type of piece; " $ shows assocs "." | not $ null duplicateRanks = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Input.PieceSquareTable.mkPieceSquareTable:\tranks must be distinct; " $ shows duplicateRanks "." | not $ normalise || inClosedUnitInterval assocs = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.PieceSquareTable.mkPieceSquareTable:\tall values must be within the closed unit-interval [0,1]; " $ shows assocs "."@@ -252,7 +249,7 @@ ) $ ( if normalise then normaliseToUnitInterval- else id+ else map (Control.Arrow.second $ map realToFrac) ) assocs } where@@ -265,13 +262,10 @@ ) Cartesian.Coordinates.nSquares -- | Identify any /rank/ lacking a definition.-findUndefinedRanks :: PieceSquareTable pieceSquareValue -> Data.Set.Set Attribute.Rank.Rank+findUndefinedRanks :: PieceSquareTable -> Data.Set.Set Attribute.Rank.Rank findUndefinedRanks MkPieceSquareTable { getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Data.Set.fromAscList Property.FixedMembership.members `Data.Set.difference` Map.keysSet pieceSquareValueByCoordinatesByRank -- | Lookup the values for all /coordinates/, corresponding to the specified /rank/.-dereference- :: Attribute.Rank.Rank- -> PieceSquareTable pieceSquareValue- -> Maybe (Cartesian.Coordinates.ArrayByCoordinates pieceSquareValue)+dereference :: Attribute.Rank.Rank -> PieceSquareTable -> Maybe PieceSquareValueByCoordinates dereference rank MkPieceSquareTable { getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Map.lookup rank pieceSquareValueByCoordinatesByRank
src-lib/BishBosh/Input/RankValues.hs view
@@ -116,8 +116,8 @@ byRank = Attribute.Rank.arrayByRank assocs -- | Query.-findRankValue :: Attribute.Rank.Rank -> RankValues -> Metric.RankValue.RankValue-findRankValue rank (MkRankValues byRank) = byRank ! rank+findRankValue :: RankValues -> Attribute.Rank.Rank -> Metric.RankValue.RankValue+findRankValue (MkRankValues byRank) = (byRank !) {- | * The maximum total rank-value one side can have.
src-lib/BishBosh/Input/SearchOptions.hs view
@@ -81,7 +81,7 @@ import BishBosh.Data.Bool() -- For 'HXT.xpickle'. import Control.Arrow((***)) import qualified BishBosh.Attribute.CaptureMoveSortAlgorithm as Attribute.CaptureMoveSortAlgorithm-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Data.Foldable import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions@@ -137,7 +137,7 @@ -- | Used to qualify XML. searchDepthByLogicalColourTag :: String-searchDepthByLogicalColourTag = showString searchDepthTag . showString "By" $ Text.Case.toUpperInitial Attribute.LogicalColour.tag+searchDepthByLogicalColourTag = showString searchDepthTag . showString "By" $ Text.Case.toUpperInitial Colour.LogicalColour.tag -- | The constant minimum permissible search-depth. minimumSearchDepth :: Type.Count.NPlies@@ -170,7 +170,7 @@ type MaybeUseTranspositions = Maybe (Type.Count.NMoves, Type.Count.NPlies) -- | The depth to search for each /logical colour/.-type SearchDepthByLogicalColour = Map.Map Attribute.LogicalColour.LogicalColour Type.Count.NPlies+type SearchDepthByLogicalColour = Map.Map Colour.LogicalColour.LogicalColour Type.Count.NPlies -- | Defines options related to searching for a move. data SearchOptions = MkSearchOptions {@@ -308,11 +308,11 @@ duplicateLogicalColours = BishBosh.Data.Foldable.findDuplicates $ map fst {-logicalColour-} l in if null duplicateLogicalColours then l- else Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Input.SearchOptions.xpickle:\t" . showString Attribute.LogicalColour.tag . showString "s must be distinct; " $ shows duplicateLogicalColours "."+ else Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Input.SearchOptions.xpickle:\t" . showString Colour.LogicalColour.tag . showString "s must be distinct; " $ shows duplicateLogicalColours "." ), -- Construct from a List. Map.toList -- Deconstruct to an association-list. ) . HXT.xpList {-potentially null-} . HXT.xpElem (- showString "by" $ Text.Case.toUpperInitial Attribute.LogicalColour.tag+ showString "by" $ Text.Case.toUpperInitial Colour.LogicalColour.tag ) $ HXT.xpickle {-LogicalColour-} `HXT.xpPair` HXT.xpAttr searchDepthTag HXT.xpickle {-NPlies-} ) where def = Data.Default.def@@ -330,14 +330,14 @@ -> SearchDepthByLogicalColour -> SearchOptions mkSearchOptions sortOnStandardOpeningMoveFrequency maybeCaptureMoveSortAlgorithm maybeMinimumHammingDistance maybeRetireKillerMovesAfter trapRepeatedPositions usePondering maybeUseTranspositions standardOpeningOptions searchDepthByLogicalColour- | Just minimumHammingDistance <- maybeMinimumHammingDistance+ | Just minimumHammingDistance <- maybeMinimumHammingDistance , minimumHammingDistance < 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString minimumHammingDistanceTag . Text.ShowList.showsAssociation $ shows minimumHammingDistance " must exceed zero."- | Just retireKillerMovesAfter <- maybeRetireKillerMovesAfter+ | Just retireKillerMovesAfter <- maybeRetireKillerMovesAfter , retireKillerMovesAfter < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString retireKillerMovesAfterTag . Text.ShowList.showsAssociation $ shows retireKillerMovesAfter " can't be negative." | let nAutomatedPlayers = Data.Foldable.length searchDepthByLogicalColour , usePondering && nAutomatedPlayers /= 1 = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\tpondering is pointless unless there's an automated player who can use the unused CPU-time during a manual player's move, but there're " $ shows nAutomatedPlayers " automated players."- | Just (retireTranspositionsAfter, _) <- maybeUseTranspositions+ | Just (retireTranspositionsAfter, _) <- maybeUseTranspositions , retireTranspositionsAfter < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString retireTranspositionsAfterTag . Text.ShowList.showsAssociation $ shows retireTranspositionsAfter " can't be negative." | Just (_, minimumTranspositionSearchDepth) <- maybeUseTranspositions , minimumTranspositionSearchDepth < 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString minimumTranspositionSearchDepthTag . Text.ShowList.showsAssociation $ shows minimumTranspositionSearchDepth " must exceed zero."@@ -398,7 +398,7 @@ } -- | Extract those /logical colour/s for which a search-depth has been defined, which implies that the corresponding player is automated.-identifyAutomatedPlayers :: SearchOptions -> [Attribute.LogicalColour.LogicalColour]+identifyAutomatedPlayers :: SearchOptions -> [Colour.LogicalColour.LogicalColour] identifyAutomatedPlayers MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour } = Map.keys searchDepthByLogicalColour
src-lib/BishBosh/Input/UIOptions.hs view
@@ -213,12 +213,12 @@ -- | Mutator. updateCECPFeature :: Input.CECPFeatures.Feature -> Transformation updateCECPFeature feature uiOptions@MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = uiOptions {- getEitherNativeUIOrCECPOptions = Input.CECPOptions.updateFeature feature `fmap` eitherNativeUIOrCECPOptions+ getEitherNativeUIOrCECPOptions = Input.CECPOptions.updateFeature feature <$> eitherNativeUIOrCECPOptions } -- | Mutator. deleteCECPFeature :: Input.CECPFeatures.Feature -> Transformation deleteCECPFeature feature uiOptions@MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = uiOptions {- getEitherNativeUIOrCECPOptions = Input.CECPOptions.deleteFeature feature `fmap` eitherNativeUIOrCECPOptions+ getEitherNativeUIOrCECPOptions = Input.CECPOptions.deleteFeature feature <$> eitherNativeUIOrCECPOptions }
src-lib/BishBosh/Metric/CriterionValue.hs view
@@ -53,15 +53,15 @@ showsPrec precedence (MkCriterionValue criterionValue) = showsPrec precedence criterionValue instance Num CriterionValue where- MkCriterionValue l + MkCriterionValue r = mkCriterionValue $ l + r- MkCriterionValue l * MkCriterionValue r = MkCriterionValue $ l * r- abs (MkCriterionValue criterionValue) = MkCriterionValue $ abs criterionValue- signum (MkCriterionValue criterionValue) = MkCriterionValue $ signum criterionValue+ MkCriterionValue l + MkCriterionValue r = mkCriterionValue $! l + r+ MkCriterionValue l * MkCriterionValue r = MkCriterionValue $! l * r+ abs (MkCriterionValue criterionValue) = MkCriterionValue $! abs criterionValue+ signum (MkCriterionValue criterionValue) = MkCriterionValue $! signum criterionValue fromInteger = mkCriterionValue . fromInteger- negate (MkCriterionValue criterionValue) = MkCriterionValue $ negate criterionValue+ negate (MkCriterionValue criterionValue) = MkCriterionValue $! negate criterionValue instance Fractional CriterionValue where- MkCriterionValue l / MkCriterionValue r = mkCriterionValue $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ MkCriterionValue l / MkCriterionValue r = mkCriterionValue $! l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid. fromRational = mkCriterionValue . fromRational instance Real CriterionValue where
src-lib/BishBosh/Metric/CriterionWeight.hs view
@@ -61,15 +61,15 @@ showsPrec precedence (MkCriterionWeight criterionWeight) = showsPrec precedence criterionWeight instance Num CriterionWeight where- MkCriterionWeight l + MkCriterionWeight r = mkCriterionWeight $ l + r- MkCriterionWeight l * MkCriterionWeight r = MkCriterionWeight $ l * r- abs (MkCriterionWeight criterionWeight) = MkCriterionWeight $ abs criterionWeight -- N.B.: if the operand is valid, then this is equivalent to 'id'.- signum (MkCriterionWeight criterionWeight) = MkCriterionWeight $ signum criterionWeight+ MkCriterionWeight l + MkCriterionWeight r = mkCriterionWeight $! l + r+ MkCriterionWeight l * MkCriterionWeight r = MkCriterionWeight $! l * r+ abs (MkCriterionWeight criterionWeight) = MkCriterionWeight $! abs criterionWeight -- N.B.: if the operand is valid, then this is equivalent to 'id'.+ signum (MkCriterionWeight criterionWeight) = MkCriterionWeight $! signum criterionWeight fromInteger = mkCriterionWeight . fromInteger- negate (MkCriterionWeight criterionWeight) = mkCriterionWeight $ negate criterionWeight -- CAVEAT: only valid for '0'.+ negate (MkCriterionWeight criterionWeight) = mkCriterionWeight $! negate criterionWeight -- CAVEAT: only valid for '0'. instance Fractional CriterionWeight where- MkCriterionWeight l / MkCriterionWeight r = mkCriterionWeight $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ MkCriterionWeight l / MkCriterionWeight r = mkCriterionWeight $! l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid. fromRational = mkCriterionWeight . fromRational instance Real CriterionWeight where
src-lib/BishBosh/Metric/RankValue.hs view
@@ -66,18 +66,18 @@ readsPrec precision = map (Control.Arrow.first mkRankValue) . readsPrec precision . Data.List.Extra.trimStart instance Property.ShowFloat.ShowFloat RankValue where- showsFloat fromDouble MkRankValue { deconstruct = rankValue } = fromDouble $ realToFrac rankValue+ showsFloat fromDouble MkRankValue { deconstruct = rankValue } = fromDouble $! realToFrac rankValue instance Num RankValue where- MkRankValue { deconstruct = l } + MkRankValue { deconstruct = r } = mkRankValue $ l + r- MkRankValue { deconstruct = l } * MkRankValue { deconstruct = r } = MkRankValue $ l * r- abs MkRankValue { deconstruct = rankValue } = MkRankValue $ abs rankValue -- N.B.: if the operand is valid, then this is equivalent to 'id'.- signum MkRankValue { deconstruct = rankValue } = MkRankValue $ signum rankValue+ MkRankValue { deconstruct = l } + MkRankValue { deconstruct = r } = mkRankValue $! l + r+ MkRankValue { deconstruct = l } * MkRankValue { deconstruct = r } = MkRankValue $! l * r+ abs MkRankValue { deconstruct = rankValue } = MkRankValue $! abs rankValue -- N.B.: if the operand is valid, then this is equivalent to 'id'.+ signum MkRankValue { deconstruct = rankValue } = MkRankValue $! signum rankValue fromInteger = mkRankValue . fromInteger- negate MkRankValue { deconstruct = rankValue } = mkRankValue $ negate rankValue -- CAVEAT: only valid for '0'.+ negate MkRankValue { deconstruct = rankValue } = mkRankValue $! negate rankValue -- CAVEAT: only valid for '0'. instance Fractional RankValue where- MkRankValue { deconstruct = l } / MkRankValue { deconstruct = r } = mkRankValue $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ MkRankValue { deconstruct = l } / MkRankValue { deconstruct = r } = mkRankValue $! l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid. fromRational = mkRankValue . fromRational instance Real RankValue where@@ -87,7 +87,7 @@ rnf MkRankValue { deconstruct = rankValue } = Control.DeepSeq.rnf rankValue instance HXT.XmlPickler RankValue where- xpickle = HXT.xpWrap (mkRankValue, deconstruct) $ HXT.xpAttr tag HXT.xpickle+ xpickle = HXT.xpWrap (mkRankValue, deconstruct) $! HXT.xpAttr tag HXT.xpickle -- | Smart constructor. mkRankValue :: Type.Mass.RankValue -> RankValue
src-lib/BishBosh/Metric/WeightedMeanAndCriterionValues.hs view
@@ -76,7 +76,7 @@ getWeightedMean = weightedMean, getCriterionValues = criterionValues } = Text.ShowList.showsAssociationList' [- (weightedMeanTag, fromDouble $ realToFrac weightedMean),+ (weightedMeanTag, fromDouble $! realToFrac weightedMean), (criterionValuesTag, Text.ShowList.showsFormattedList' (fromDouble . realToFrac) criterionValues) ]
src-lib/BishBosh/Model/Game.hs view
@@ -88,12 +88,12 @@ ) where import Control.Arrow((&&&), (***), (|||))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.CastlingMove as Component.CastlingMove import qualified BishBosh.Component.EitherQualifiedMove as Component.EitherQualifiedMove import qualified BishBosh.Component.Move as Component.Move@@ -172,7 +172,7 @@ sortAvailableQualifiedMoves = Map.map . Data.List.sortBy $ Data.Ord.comparing fst {-destination-} -- | The /move/s available to both players.-type AvailableQualifiedMovesByLogicalColour = Map.Map Attribute.LogicalColour.LogicalColour AvailableQualifiedMoves+type AvailableQualifiedMovesByLogicalColour = Map.Map Colour.LogicalColour.LogicalColour AvailableQualifiedMoves {- | * The first three fields represent the state of the /game/.@@ -182,11 +182,11 @@ * For efficiency the list of available /move/s is stored. -} data Game = MkGame {- getNextLogicalColour :: Attribute.LogicalColour.LogicalColour, -- ^ N.B.: can be derived from 'getTurnsByLogicalColour', unless 'Property.Reflectable.reflectOnX' has been called.+ getNextLogicalColour :: Colour.LogicalColour.LogicalColour, -- ^ N.B.: can be derived from 'getTurnsByLogicalColour', unless 'Property.Reflectable.reflectOnX' has been called. getCastleableRooksByLogicalColour :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour, -- ^ Those @Rook@s which can still participate in castling. getBoard :: State.Board.Board, -- ^ The current state of the /board/. getTurnsByLogicalColour :: State.CastleableRooksByLogicalColour.TurnsByLogicalColour, -- ^ Successive /move/s & any /piece/ taken, recorded by player.- getMaybeChecked :: Maybe Attribute.LogicalColour.LogicalColour, -- ^ The player (if any), whose currently /checked/; which will typically be 'getNextLogicalColour', but 'listQualifiedMovesAvailableTo' can be called for either player.+ getMaybeChecked :: Maybe Colour.LogicalColour.LogicalColour, -- ^ The player (if any), whose currently /checked/; which will typically be 'getNextLogicalColour', but 'listQualifiedMovesAvailableTo' can be called for either player. getInstancesByPosition :: InstancesByPosition, -- ^ The number of instances of various positions since the last unrepeatable move. getAvailableQualifiedMovesByLogicalColour :: AvailableQualifiedMovesByLogicalColour, -- ^ The /move/s available to each player. Since this is merely required for efficiency, it needn't have an entry for both players; & typically doesn't when checked, since radical pruning would otherwise be required. CAVEAT: doesn't account for game-termination. getMaybeTerminationReason :: Maybe Rule.GameTerminationReason.GameTerminationReason -- ^ The reason (where appropriate) why the game was terminated.@@ -283,11 +283,11 @@ instance Data.Default.Default Game where def = (- mkGame Attribute.LogicalColour.White Data.Default.def {-castleableRooksByLogicalColour-} Data.Default.def {-board-} Data.Default.def {-turnsByLogicalColour-}+ mkGame Colour.LogicalColour.White Data.Default.def {-castleableRooksByLogicalColour-} Data.Default.def {-board-} Data.Default.def {-turnsByLogicalColour-} ) { getMaybeChecked = Nothing, getAvailableQualifiedMovesByLogicalColour = Map.fromAscList $ map (- id &&& (`mkAvailableQualifiedMovesFor` Data.Default.def {-game-})+ id &&& mkAvailableQualifiedMovesFor Data.Default.def {-game-} ) Property.FixedMembership.members } @@ -335,7 +335,7 @@ Property.ExtendedPositionDescription.showsEPD nextLogicalColour, -- 2. Active colour. Property.ExtendedPositionDescription.showsEPD castleableRooksByLogicalColour, -- 3. Castling availability. Data.Maybe.maybe Property.ExtendedPositionDescription.showsNullField (- \turn -> if Component.Turn.isPawnDoubleAdvance (Property.Opposable.getOpposite nextLogicalColour) turn+ \turn -> if Component.Turn.isPawnDoubleAdvance turn $ Property.Opposable.getOpposite nextLogicalColour then Notation.MoveNotation.showsNotation Data.Default.def {-Smith is the same as the required Algebraic notation in this limited role-} . Cartesian.Coordinates.advance nextLogicalColour . Component.Move.getDestination . Component.QualifiedMove.getMove $ Component.Turn.getQualifiedMove turn else Property.ExtendedPositionDescription.showsNullField ) $ maybeLastTurn game -- 4. En-passant target square. CAVEAT: in contrast to X-EPD, this is required even when there's no opposing Pawn in a suitable position to take en-passant.@@ -357,7 +357,7 @@ } = Text.ShowList.showsDelimitedList Property.ExtendedPositionDescription.showsSeparator id id [ Property.ExtendedPositionDescription.showsEPD game, shows $ State.InstancesByPosition.countConsecutiveRepeatablePlies instancesByPosition, -- 5. Half move clock.- shows . succ {-the full-move counter starts at '1', before any move has occurred-} . length $ State.TurnsByLogicalColour.dereference Attribute.LogicalColour.Black turnsByLogicalColour -- 6. Full move counter.+ shows . succ {-the full-move counter starts at '1', before any move has occurred-} . length $ State.TurnsByLogicalColour.dereference turnsByLogicalColour Colour.LogicalColour.Black -- 6. Full move counter. ] instance Property.Empty.Empty Game where@@ -396,34 +396,32 @@ } instance StateProperty.Hashable.Hashable Game where- listRandoms game@MkGame {+ listRandoms zobrist game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board- } zobrist = (- if Attribute.LogicalColour.isBlack nextLogicalColour+ } = (+ if Colour.LogicalColour.isBlack nextLogicalColour then (Component.Zobrist.getRandomForBlacksMove zobrist :) else id- ) . Data.Maybe.maybe id (- (++) . (`StateProperty.Hashable.listRandoms` zobrist)- ) (+ ) $ StateProperty.Hashable.listRandoms zobrist ( maybeLastTurn game >>= State.EnPassantAbscissa.mkMaybeEnPassantAbscissa nextLogicalColour ( State.Board.getMaybePieceByCoordinates board- )- ) $ StateProperty.Hashable.listRandoms castleableRooksByLogicalColour zobrist ++ StateProperty.Hashable.listRandoms board zobrist+ ),+ castleableRooksByLogicalColour,+ board+ ) -- Triple. -- | Smart constructor. mkGame- :: Attribute.LogicalColour.LogicalColour -- ^ The player who is required to move next.+ :: Colour.LogicalColour.LogicalColour -- ^ The player who is required to move next. -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> State.Board.Board -> State.CastleableRooksByLogicalColour.TurnsByLogicalColour -> Game mkGame nextLogicalColour castleableRooksByLogicalColour board turnsByLogicalColour | not . StateProperty.Censor.hasBothKings $ State.Board.getCoordinatesByRankByLogicalColour board = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Model.Game.mkGame:\tboth Kings must exist; " $ shows board "."- | State.Board.isKingChecked (- Property.Opposable.getOpposite nextLogicalColour- ) board = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Model.Game.mkGame:\tthe player who last moved, is still checked; " $ shows board "."+ | State.Board.isKingChecked board $ Property.Opposable.getOpposite nextLogicalColour = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Model.Game.mkGame:\tthe player who last moved, is still checked; " $ shows board "." | otherwise = game where game = MkGame {@@ -431,10 +429,10 @@ getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board, getTurnsByLogicalColour = turnsByLogicalColour,- getMaybeChecked = Data.List.find (`State.Board.isKingChecked` board) Property.FixedMembership.members,+ getMaybeChecked = Data.List.find (State.Board.isKingChecked board) Property.FixedMembership.members, getInstancesByPosition = State.InstancesByPosition.mkSingleton $ mkPosition game, getAvailableQualifiedMovesByLogicalColour = Map.fromAscList [- (logicalColour, mkAvailableQualifiedMovesFor logicalColour game) |+ (logicalColour, mkAvailableQualifiedMovesFor game logicalColour) | logicalColour <- Property.FixedMembership.members, getMaybeChecked game /= Just logicalColour -- Define the available qualified moves for unchecked players only. ], -- List-comprehension.@@ -451,7 +449,7 @@ * There're zero previous turns. -} fromBoard :: State.Board.Board -> Game-fromBoard board = mkGame Attribute.LogicalColour.White (+fromBoard board = mkGame Colour.LogicalColour.White ( State.CastleableRooksByLogicalColour.fromBoard board ) board Property.Empty.empty {-TurnsByLogicalColour-} @@ -461,8 +459,8 @@ getNextLogicalColour = nextLogicalColour, getTurnsByLogicalColour = turnsByLogicalColour } = uncurry ToolShed.Data.List.interleave $ (- State.TurnsByLogicalColour.dereference (Property.Opposable.getOpposite nextLogicalColour) &&& State.TurnsByLogicalColour.dereference nextLogicalColour- ) turnsByLogicalColour+ State.TurnsByLogicalColour.dereference turnsByLogicalColour . Property.Opposable.getOpposite &&& State.TurnsByLogicalColour.dereference turnsByLogicalColour+ ) nextLogicalColour -- | Gets the sequence of /turn/s in the order they occured. listTurnsChronologically :: Game -> [Component.Turn.Turn]@@ -473,9 +471,7 @@ maybeLastTurn MkGame { getNextLogicalColour = nextLogicalColour, getTurnsByLogicalColour = turnsByLogicalColour-} = Data.Maybe.listToMaybe $ State.TurnsByLogicalColour.dereference (- Property.Opposable.getOpposite nextLogicalColour- ) turnsByLogicalColour+} = Data.Maybe.listToMaybe . State.TurnsByLogicalColour.dereference turnsByLogicalColour $ Property.Opposable.getOpposite nextLogicalColour {- | * Returns the castling /move/s currently available to the @King@ of the specified /logical colour/.@@ -484,26 +480,28 @@ * CAVEAT: this is a performance-hotspot; refactor => re-profile. -}-findAvailableCastlingMoves :: Attribute.LogicalColour.LogicalColour -> Game -> [Component.QualifiedMove.QualifiedMove]-findAvailableCastlingMoves logicalColour MkGame {+findAvailableCastlingMoves :: Game -> Colour.LogicalColour.LogicalColour -> [Component.QualifiedMove.QualifiedMove]+findAvailableCastlingMoves MkGame { getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board, getMaybeChecked = maybeChecked-}+} logicalColour | Just checkedLogicalColour <- maybeChecked , checkedLogicalColour == logicalColour = [] -- One can't Castle out of check.- | Just rooksStartingXs <- State.CastleableRooksByLogicalColour.locateForLogicalColour logicalColour castleableRooksByLogicalColour = [+ | Just rooksStartingXs <- State.CastleableRooksByLogicalColour.locateForLogicalColour castleableRooksByLogicalColour logicalColour = [ Component.QualifiedMove.mkQualifiedMove castlingKingsMove $ Component.CastlingMove.getMoveType castlingMove | x <- rooksStartingXs, castlingMove <- Component.CastlingMove.getCastlingMoves logicalColour, let castlingRooksSource = Component.Move.getSource $ Component.CastlingMove.getRooksMove castlingMove, Cartesian.Coordinates.getX castlingRooksSource == x, State.MaybePieceByCoordinates.isClear (+ State.Board.getMaybePieceByCoordinates board+ ) ( Cartesian.Coordinates.kingsStartingCoordinates logicalColour- ) castlingRooksSource $ State.Board.getMaybePieceByCoordinates board,+ ) castlingRooksSource, let castlingKingsMove = Component.CastlingMove.getKingsMove castlingMove, all (- null . ($ board) . State.Board.findAttackersOf logicalColour+ null . State.Board.findAttackersOf board logicalColour ) $ Component.Move.interpolate castlingKingsMove -- The King mustn't be checked anywhere alongs its route. ] {-list-comprehension-} | otherwise = [] {-have already Castled-}@@ -515,7 +513,7 @@ -> [Maybe Attribute.Rank.Rank] {-# INLINE listMaybePromotionRanks #-} listMaybePromotionRanks destination piece- | Component.Piece.isPawnPromotion destination piece = map Just Attribute.Rank.promotionProspects+ | Component.Piece.isPawnPromotion piece destination = map Just Attribute.Rank.promotionProspects | otherwise = [Nothing] -- | The type of a function which transforms a /game/.@@ -541,10 +539,10 @@ } = Control.Exception.assert ( not $ isTerminated game -- CAVEAT: otherwise any resignation will be overwritten. ) game' where- ((move, moveType), sourceRank) = (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) . Component.Turn.getQualifiedMove &&& Component.Turn.getRank $ turn -- Deconstruct.+ ((move, moveType), sourceRank) = (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) . Component.Turn.getQualifiedMove &&& Component.Turn.getRank $! turn -- Deconstruct. (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move -- Deconstruct. - opponentsLogicalColour :: Attribute.LogicalColour.LogicalColour+ opponentsLogicalColour :: Colour.LogicalColour.LogicalColour opponentsLogicalColour = Property.Opposable.getOpposite nextLogicalColour inferredRooksMove = Data.Maybe.maybe (@@ -566,9 +564,10 @@ getCastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.takeTurn nextLogicalColour turn castleableRooksByLogicalColour, getBoard = board', getTurnsByLogicalColour = State.TurnsByLogicalColour.prepend nextLogicalColour turn turnsByLogicalColour,- getMaybeChecked = Data.List.find (`State.Board.isKingChecked` board') [opponentsLogicalColour],+ getMaybeChecked = Data.List.find (State.Board.isKingChecked board') [opponentsLogicalColour], getInstancesByPosition = State.InstancesByPosition.insertPosition (Component.Turn.getIsRepeatableMove turn) (mkPosition game') instancesByPosition, getAvailableQualifiedMovesByLogicalColour = let+ moveEndpoints :: [Cartesian.Coordinates.Coordinates] moveEndpoints = ( case moveType of Attribute.MoveType.Castle _ -> (++) [@@ -579,10 +578,12 @@ _ -> id ) [source, destination] + kingsByCoordinates :: [Component.Piece.LocatedPiece] kingsByCoordinates = map (- (`State.CoordinatesByRankByLogicalColour.getKingsCoordinates` State.Board.getCoordinatesByRankByLogicalColour board') &&& Component.Piece.mkKing+ State.CoordinatesByRankByLogicalColour.getKingsCoordinates (State.Board.getCoordinatesByRankByLogicalColour board') &&& Component.Piece.mkKing ) Property.FixedMembership.members + affected, affected' :: [Component.Piece.LocatedPiece] (affected, affected') = ( Data.List.nub . (:) ( destination,@@ -591,33 +592,30 @@ ) . Data.List.partition ( (== nextLogicalColour) . Component.Piece.getLogicalColour . snd {-piece-} ) . (- if Component.Turn.isPawnDoubleAdvance nextLogicalColour turn+ if Component.Turn.isPawnDoubleAdvance turn nextLogicalColour then (++) [ (pawnCoordinates, oppositePiece) | let oppositePiece = Component.Piece.mkPiece opponentsLogicalColour sourceRank, pawnCoordinates <- Cartesian.Coordinates.getAdjacents destination,- State.MaybePieceByCoordinates.dereference pawnCoordinates (State.Board.getMaybePieceByCoordinates board) == Just oppositePiece -- Find any opposing Pawn which can capture En-passant.+ State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates board) pawnCoordinates == Just oppositePiece -- Find any opposing Pawn which can capture En-passant. ] {-list-comprehension-} else id ) $ kingsByCoordinates {-moves available to either King may be constrained or liberated, even if misaligned with move-endpoints-} ++ [ (knightsCoordinates, Component.Piece.mkKnight knightsColour) | knightsColour <- Property.FixedMembership.members, -- The moves for one's own Knights may be have been blocked by a friendly piece occupying an end-point, whereas the moves for opposing Knights will have a new move-type.- moveEndpoint <- moveEndpoints,- knightsCoordinates <- StateProperty.Seeker.findProximateKnights knightsColour moveEndpoint board'+ knightsCoordinates <- concatMap (StateProperty.Seeker.findProximateKnights board' knightsColour) moveEndpoints ] {-list-comprehension-} ++ ( if sourceRank == Attribute.Rank.King- then [- (blockingCoordinates, blockingPiece) |- (kingsCoordinates, _) <- kingsByCoordinates,- direction <- Property.FixedMembership.members,- (blockingCoordinates, blockingPiece) <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.findBlockingPiece direction kingsCoordinates maybePieceByCoordinates'- ] -- List-comprehension. Re-evaluate the moves available to all pieces aligned with a King.+ then concatMap (+ flip (+ State.MaybePieceByCoordinates.findBlockingPieces maybePieceByCoordinates'+ ) Nothing {-omni-directional-} . fst {-coordinates-}+ ) kingsByCoordinates -- Re-evaluate the moves available to all pieces aligned with a King. else [ (blockingCoordinates, blockingPiece) | (kingsCoordinates, _) <- kingsByCoordinates,- moveEndpoint <- moveEndpoints,- direction <- Data.Maybe.maybeToList . Cartesian.Vector.toMaybeDirection $ Cartesian.Vector.measureDistance kingsCoordinates moveEndpoint, -- N.B. null when the King isn't aligned with any move-endpoint.- let findBlockingPieceFrom coordinates = State.MaybePieceByCoordinates.findBlockingPiece direction coordinates maybePieceByCoordinates',+ direction <- Data.Maybe.mapMaybe (Cartesian.Vector.toMaybeDirection . Cartesian.Vector.measureDistance kingsCoordinates) moveEndpoints, -- N.B. null when the King isn't aligned with any move-endpoint.+ let findBlockingPieceFrom = flip (State.MaybePieceByCoordinates.findBlockingPiece maybePieceByCoordinates') direction, (blockingCoordinates, blockingPiece) <- Data.Maybe.maybeToList $ ( \pair@(coordinates, _) -> if coordinates /= destination then Just pair@@ -627,28 +625,30 @@ ) =<< findBlockingPieceFrom kingsCoordinates ] -- List-comprehension. Re-evaluate the moves available to all pieces aligned with a King & a move-endpoint. ) ++ [- (coordinates, affectedPiece) |- moveEndpoint <- moveEndpoints,- direction <- Property.FixedMembership.members,- (coordinates, affectedPiece) <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.findBlockingPiece direction moveEndpoint maybePieceByCoordinates',- coordinates /= destination, -- Added above.- not . uncurry (||) $ (Component.Piece.isKnight &&& Component.Piece.isKing) affectedPiece, -- Added above.- Component.Piece.canMoveBetween coordinates moveEndpoint affectedPiece+ locatedAffectedPiece |+ moveEndpoint <- moveEndpoints,+ locatedAffectedPiece <- filter (+ not . uncurry (||) . (+ (== destination) *** uncurry (||) . (+ Component.Piece.isKnight &&& Component.Piece.isKing+ ) -- Added above.+ )+ ) $ State.MaybePieceByCoordinates.findBlockingPieces maybePieceByCoordinates' moveEndpoint Nothing {-omni-directional-},+ uncurry (flip Component.Piece.canMoveBetween) locatedAffectedPiece moveEndpoint ] -- List-comprehension. Re-evaluate the moves available to all pieces, which either could move to the source, or can now move to the destination, of the requested move. + insertMovesFrom :: AvailableQualifiedMoves -> [Component.Piece.LocatedPiece] -> AvailableQualifiedMoves insertMovesFrom = foldr $ \(source', piece') -> let logicalColour = Component.Piece.getLogicalColour piece'- isSafeDestination destination' = not $ State.Board.exposesKing logicalColour (Component.Move.mkMove source' destination') board'+ isSafeDestination destination' = not . State.Board.exposesKing board' logicalColour $ Component.Move.mkMove source' destination' in case [ (destination', Attribute.MoveType.EnPassant) |- Cartesian.Coordinates.isEnPassantRank logicalColour source',+ Cartesian.Coordinates.isEnPassantRank source' logicalColour, Component.Piece.isPawn piece',- destination' <- Component.Piece.findAttackDestinations source' piece',- State.MaybePieceByCoordinates.isVacant destination' maybePieceByCoordinates',+ destination' <- Component.Piece.findAttackDestinations piece' source',+ State.MaybePieceByCoordinates.isVacant maybePieceByCoordinates' destination', uncurry (&&) . (- (== Just (Property.Opposable.getOpposite piece')) . (- `State.MaybePieceByCoordinates.dereference` maybePieceByCoordinates'- ) &&& (== move) . Component.Move.mkMove (Cartesian.Coordinates.advance logicalColour destination')+ (== Just (Property.Opposable.getOpposite piece')) . State.MaybePieceByCoordinates.dereference maybePieceByCoordinates' &&& (== move) . Component.Move.mkMove (Cartesian.Coordinates.advance logicalColour destination') ) $ Cartesian.Coordinates.retreat logicalColour destination', -- Did an opposing Pawn just double-advance to the expected position ? isSafeDestination destination' ] {-list-comprehension-} ++ [@@ -656,7 +656,7 @@ destination', Attribute.MoveType.mkNormalMoveType maybeTakenRank maybePromotionRank ) |- (destination', maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor source' piece' maybePieceByCoordinates',+ (destination', maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates' source' piece', maybeTakenRank /= Just Attribute.Rank.King, -- This move can never be made; the option will either be immediately removed or check-mate declared. isSafeDestination destination', maybePromotionRank <- listMaybePromotionRanks destination' piece'@@ -664,7 +664,8 @@ [] -> Map.delete source' -- There're zero moves from here. qualifiedDestinations -> Map.insert source' qualifiedDestinations -- Overwrite any existing moves. - insertCastlingMoves logicalColour = case findAvailableCastlingMoves logicalColour game' of+ insertCastlingMoves :: Colour.LogicalColour.LogicalColour -> AvailableQualifiedMoves -> AvailableQualifiedMoves+ insertCastlingMoves logicalColour = case findAvailableCastlingMoves game' logicalColour of [] -> id validCastlingMoves -> uncurry ( Map.insertWith (++)@@ -676,30 +677,32 @@ in ( \availableQualifiedMovesByLogicalColour' -> ( case (Map.member opponentsLogicalColour availableQualifiedMovesByLogicalColour', Data.Maybe.isJust $ getMaybeChecked game') of- (True, True) -> Map.delete opponentsLogicalColour -- Many changes result from the King being checked.- (True, _) -> Map.adjust (- insertCastlingMoves opponentsLogicalColour . (- `insertMovesFrom` affected' -- Reconstruct any moves for affected pieces.- ) . (- if Attribute.MoveType.isEnPassant moveType- then Map.delete $ Cartesian.Coordinates.retreat nextLogicalColour destination- else id- ) . Map.delete destination -- Delete the moves originally available to any taken piece.- ) opponentsLogicalColour- (_, True) -> id -- We neither want an entry in the map, nor is there one.- _ -> Map.insert opponentsLogicalColour $ mkAvailableQualifiedMovesFor opponentsLogicalColour game' -- Reconstruct.+ (True, isChecked)+ | isChecked -> Map.delete opponentsLogicalColour -- Many changes result from the King being checked.+ | otherwise -> Map.adjust (+ insertCastlingMoves opponentsLogicalColour . (+ `insertMovesFrom` affected' -- Reconstruct any moves for affected pieces.+ ) . (+ if Attribute.MoveType.isEnPassant moveType+ then Map.delete $ Cartesian.Coordinates.retreat nextLogicalColour destination+ else id+ ) . Map.delete destination -- Delete the moves originally available to any taken piece.+ ) opponentsLogicalColour+ (_, isChecked)+ | isChecked -> id -- We neither want an entry in the map, nor is there one.+ | otherwise -> Map.insert opponentsLogicalColour $ mkAvailableQualifiedMovesFor game' opponentsLogicalColour -- Reconstruct. ) availableQualifiedMovesByLogicalColour' ) $ ( if Data.Maybe.maybe True {-not a member-} ( \availableQualifiedMoves -> sourceRank == Attribute.Rank.King || Data.Maybe.maybe False {-zero previous turns-} (- Component.Turn.isPawnDoubleAdvance opponentsLogicalColour+ `Component.Turn.isPawnDoubleAdvance` opponentsLogicalColour ) ( maybeLastTurn game -- I.E. one's opponent. ) {-only required for efficiency-} && Data.Foldable.any ( any $ Attribute.MoveType.isEnPassant . snd {-moveType-} ) availableQualifiedMoves ) $ Map.lookup nextLogicalColour availableQualifiedMovesByLogicalColour- then Map.insert nextLogicalColour $ mkAvailableQualifiedMovesFor nextLogicalColour game' -- Reconstruct.+ then Map.insert nextLogicalColour $ mkAvailableQualifiedMovesFor game' nextLogicalColour -- Reconstruct. else Map.adjust ( insertCastlingMoves nextLogicalColour . ( `insertMovesFrom` affected -- Reconstruct any moves for affected pieces.@@ -712,8 +715,8 @@ -- | Construct a /turn/ & relay the request to 'takeTurn'. applyQualifiedMove :: Component.QualifiedMove.QualifiedMove -> Transformation applyQualifiedMove qualifiedMove game@MkGame { getBoard = board }- | Just piece <- State.MaybePieceByCoordinates.dereference (Component.Move.getSource move) $ State.Board.getMaybePieceByCoordinates board- = takeTurn (Component.Turn.mkTurn qualifiedMove $ Component.Piece.getRank piece) game+ | Just piece <- State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates board) $! Component.Move.getSource move+ = takeTurn (Component.Turn.mkTurn qualifiedMove $! Component.Piece.getRank piece) game | otherwise = Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Model.Game.applyQualifiedMove:\tthere isn't a piece at the source of " . shows move . showString "; " $ shows game "." where move = Component.QualifiedMove.getMove qualifiedMove@@ -722,7 +725,7 @@ applyEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove -> Transformation applyEitherQualifiedMove eitherQualifiedMove game@MkGame { getBoard = board } = applyQualifiedMove ( Component.QualifiedMove.mkQualifiedMove move . (- ($ State.Board.getMaybePieceByCoordinates board) . State.MaybePieceByCoordinates.inferMoveType move ||| id+ State.MaybePieceByCoordinates.inferMoveType (State.Board.getMaybePieceByCoordinates board) move ||| id ) $ Component.EitherQualifiedMove.getPromotionRankOrMoveType eitherQualifiedMove ) game where move = Component.EitherQualifiedMove.getMove eitherQualifiedMove@@ -743,7 +746,7 @@ datum, showString "board" . Text.ShowList.showsAssociation . shows (getBoard game) . showString " (" $ shows errorMessage ")" ) -- Pair.- ) $ validateEitherQualifiedMove eitherQualifiedMove game+ ) $ validateEitherQualifiedMove game eitherQualifiedMove ) $ moveConstructor datum ) ) . Right@@ -754,18 +757,18 @@ * N.B.: it is considered valid to take a @King@, one just never has the opportunity, since the game terminates the move before. -} validateQualifiedMove- :: Component.QualifiedMove.QualifiedMove- -> Game -- ^ Prior to playing the /qualified move/.+ :: Game -- ^ Prior to playing the /qualified move/.+ -> Component.QualifiedMove.QualifiedMove -> Maybe String -- ^ Error-message.-validateQualifiedMove qualifiedMove game@MkGame {+validateQualifiedMove game@MkGame { getNextLogicalColour = nextLogicalColour, getBoard = board, getMaybeChecked = maybeChecked, getMaybeTerminationReason = maybeTerminationReason-} = Control.Exception.assert (+} qualifiedMove = Control.Exception.assert ( StateProperty.Censor.hasBothKings ( State.Board.getCoordinatesByRankByLogicalColour board- ) && maybeChecked == Data.List.find (`State.Board.isKingChecked` board) Property.FixedMembership.members+ ) && maybeChecked == Data.List.find (State.Board.isKingChecked board) Property.FixedMembership.members ) $ Data.Maybe.maybe ( Data.Maybe.maybe ( Just "there isn't a piece at the specified source-coordinates" -- N.B.: this is also caught by 'validateEitherQualifiedMove'.@@ -796,19 +799,19 @@ ( case Component.Piece.getRank sourcePiece of Attribute.Rank.Pawn- | destination `elem` Component.Piece.findAttackDestinations source sourcePiece -> Data.Maybe.maybe (+ | destination `elem` Component.Piece.findAttackDestinations sourcePiece source -> Data.Maybe.maybe ( let opponentsCoordinates = Cartesian.Coordinates.retreat sourceLogicalColour destination opponentsPawn = Property.Opposable.getOpposite sourcePiece in [ (- not $ Cartesian.Coordinates.isEnPassantRank sourceLogicalColour source,+ not $ Cartesian.Coordinates.isEnPassantRank source sourceLogicalColour, showString "one can't take a '" $ shows opponentsPawn "' en-passant, from this rank" ), (- State.MaybePieceByCoordinates.isOccupied destination maybePieceByCoordinates,+ State.MaybePieceByCoordinates.isOccupied maybePieceByCoordinates destination, showString "taking a '" $ shows opponentsPawn "' en-passant, requires a move to a vacant square" ), (- State.MaybePieceByCoordinates.dereference opponentsCoordinates maybePieceByCoordinates /= Just opponentsPawn,+ State.MaybePieceByCoordinates.dereference maybePieceByCoordinates opponentsCoordinates /= Just opponentsPawn, shows "en-passant" . showString " requires a '" $ shows opponentsPawn "' to be taken" ), ( Data.Maybe.maybe True {-zero previous turns-} (@@ -827,14 +830,14 @@ "it may only have a sideways component during attack" ) : ( case (- if Attribute.LogicalColour.isBlack sourceLogicalColour+ if Colour.LogicalColour.isBlack sourceLogicalColour then negate else id ) $ Cartesian.Vector.getYDistance distance of 1 -> id 2 -> (++) [ (- not $ Cartesian.Coordinates.isPawnsFirstRank sourceLogicalColour source,+ not $ Cartesian.Coordinates.isPawnsFirstRank source sourceLogicalColour, "it only has the option to advance two squares on its first move" ), ( isObstructed,@@ -899,10 +902,10 @@ ( \rooksSource -> [ (- not . State.CastleableRooksByLogicalColour.canCastleWith sourceLogicalColour rooksSource $ getCastleableRooksByLogicalColour game,+ not $ State.CastleableRooksByLogicalColour.canCastleWith (getCastleableRooksByLogicalColour game) sourceLogicalColour rooksSource, showString "it has either already castled or lost the right to castle with the implied '" $ shows (Component.Piece.mkRook sourceLogicalColour) "'" ), (- State.MaybePieceByCoordinates.isObstructed source rooksSource maybePieceByCoordinates,+ State.MaybePieceByCoordinates.isObstructed maybePieceByCoordinates source rooksSource, "it can't castle through an obstruction" ) ]@@ -918,7 +921,7 @@ "it can't castle out of check" ), ( not . all (- null . ($ board) . State.Board.findAttackersOf sourceLogicalColour+ null . State.Board.findAttackersOf board sourceLogicalColour ) $ Component.Move.interpolate move, -- The King mustn't pass through check when moving from source to destination (inclusive); a long castle still permits the square right of the Rook to be checked. "it can't castle through check" )@@ -930,57 +933,57 @@ else showString "your '" . shows (Component.Piece.mkKing sourceLogicalColour) . showChar '\'' ) $ if maybeChecked == Just sourceLogicalColour then (- State.Board.isKingChecked sourceLogicalColour $ State.Board.movePiece move (Just moveType) board, -- CAVEAT: don't perform an unvalidated move at the Game-level.+ State.Board.isKingChecked (State.Board.movePiece move (Just moveType) board) sourceLogicalColour, -- CAVEAT: don't perform an unvalidated move at the Game-level. " remains checked" ) -- Pair. else (- State.Board.exposesKing sourceLogicalColour move board,+ State.Board.exposesKing board sourceLogicalColour move, " would become exposed" ) -- Pair. ] -- Post-move tests on one's King. )- ) $ State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates+ ) $ State.MaybePieceByCoordinates.dereference maybePieceByCoordinates source ) ( Just . show -- The game has been terminated, so there aren't any valid moves. ) maybeTerminationReason where (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ qualifiedMove (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move -- Deconstruct. maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board- maybeDestinationPiece = State.MaybePieceByCoordinates.dereference destination maybePieceByCoordinates -- Query.+ maybeDestinationPiece = State.MaybePieceByCoordinates.dereference maybePieceByCoordinates destination -- Query. distance = Component.Move.measureDistance move isObstructed :: Bool- isObstructed = State.MaybePieceByCoordinates.isObstructed source destination maybePieceByCoordinates+ isObstructed = State.MaybePieceByCoordinates.isObstructed maybePieceByCoordinates source destination -- | Validates the /move-type/ then forwards the request to 'validateQualifiedMove'. validateEitherQualifiedMove- :: Component.EitherQualifiedMove.EitherQualifiedMove- -> Game -- ^ Prior to playing the /move/.+ :: Game -- ^ Prior to playing the /move/.+ -> Component.EitherQualifiedMove.EitherQualifiedMove -> Maybe String -- ^ Error-message.-validateEitherQualifiedMove eitherQualifiedMove game@MkGame { getBoard = board }- | State.MaybePieceByCoordinates.isVacant (+validateEitherQualifiedMove game@MkGame { getBoard = board } eitherQualifiedMove+ | State.MaybePieceByCoordinates.isVacant maybePieceByCoordinates ( Component.Move.getSource move- ) maybePieceByCoordinates = Just "there isn't a piece at the specified source-coordinates" -- Guard the call to 'State.MaybePieceByCoordinates.inferMoveType'.+ ) = Just "there isn't a piece at the specified source-coordinates" -- Guard the call to 'State.MaybePieceByCoordinates.inferMoveType'. | Right moveType <- promotionRankOrMoveType , moveType /= inferredMoveType = Just . showString "the implied " . showString Attribute.MoveType.tag . Text.ShowList.showsAssociation . shows moveType . showString " /= " $ show inferredMoveType- | otherwise = validateQualifiedMove (Component.QualifiedMove.mkQualifiedMove move inferredMoveType) game+ | otherwise = validateQualifiedMove game $ Component.QualifiedMove.mkQualifiedMove move inferredMoveType where (move, promotionRankOrMoveType) = Component.EitherQualifiedMove.getMove &&& Component.EitherQualifiedMove.getPromotionRankOrMoveType $ eitherQualifiedMove maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board inferredMoveType :: Attribute.MoveType.MoveType- inferredMoveType = State.MaybePieceByCoordinates.inferMoveType move (- id ||| Attribute.Rank.getMaybePromotionRank $ promotionRankOrMoveType -- Discard any move-type.- ) maybePieceByCoordinates+ inferredMoveType = State.MaybePieceByCoordinates.inferMoveType maybePieceByCoordinates move $ (+ id ||| Attribute.Rank.getMaybePromotionRank+ ) promotionRankOrMoveType -- Discard any move-type. -- | Whether the specified /QualifiedMove/ is valid.-isValidQualifiedMove :: Component.QualifiedMove.QualifiedMove -> Game -> Bool-isValidQualifiedMove qualifiedMove = Data.Maybe.isNothing . validateQualifiedMove qualifiedMove+isValidQualifiedMove :: Game -> Component.QualifiedMove.QualifiedMove -> Bool+isValidQualifiedMove game = Data.Maybe.isNothing . validateQualifiedMove game -- | Whether the specified /EitherQualifiedMove/ is valid.-isValidEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove -> Game -> Bool-isValidEitherQualifiedMove eitherQualifiedMove = Data.Maybe.isNothing . validateEitherQualifiedMove eitherQualifiedMove+isValidEitherQualifiedMove :: Game -> Component.EitherQualifiedMove.EitherQualifiedMove -> Bool+isValidEitherQualifiedMove game = Data.Maybe.isNothing . validateEitherQualifiedMove game {- | * Roll-back the specified /game/ until the start, returning each previous /game/ paired with the /ply/ which was then made.@@ -996,7 +999,7 @@ getInstancesByPosition = instancesByPosition } -> let previousColour = Property.Opposable.getOpposite nextLogicalColour- in case State.TurnsByLogicalColour.dereference previousColour turnsByLogicalColour of+ in case State.TurnsByLogicalColour.dereference turnsByLogicalColour previousColour of turn : previousTurns -> let (move, moveType) = (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) $ Component.Turn.getQualifiedMove turn -- Deconstruct. destination = Component.Move.getDestination move -- Deconstruct.@@ -1006,10 +1009,10 @@ getTurnsByLogicalColour = turnsByLogicalColour', getMaybeChecked = maybeChecked' } = game {- getNextLogicalColour = previousColour,- getCastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.fromTurnsByLogicalColour turnsByLogicalColour',- getMaybeChecked = Data.List.find (`State.Board.isKingChecked` board') [previousColour],- getBoard = (+ getNextLogicalColour = previousColour,+ getCastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.fromTurnsByLogicalColour turnsByLogicalColour',+ getMaybeChecked = Data.List.find (State.Board.isKingChecked board') [previousColour],+ getBoard = ( case moveType of Attribute.MoveType.Castle isShort -> State.Board.movePiece ( uncurry Component.Move.mkMove $ (@@ -1033,16 +1036,16 @@ ) ( Attribute.MoveType.getMaybeExplicitlyTakenRank moveType -- Reconstruct any piece taken (except en-passant), inferring the logical colour. ) $ State.Board.movePiece (Property.Opposable.getOpposite move) Nothing {-MoveType-} board, -- N.B.: operate directly on the board to avoid creating a new Turn in the Game-structure.- getTurnsByLogicalColour = State.TurnsByLogicalColour.update turnsByLogicalColour [(previousColour, previousTurns)],- getInstancesByPosition = if Component.Turn.getIsRepeatableMove turn+ getTurnsByLogicalColour = State.TurnsByLogicalColour.update [(previousColour, previousTurns)] turnsByLogicalColour,+ getInstancesByPosition = if Component.Turn.getIsRepeatableMove turn then State.InstancesByPosition.deletePosition (mkPosition game) instancesByPosition else mkInstancesByPosition game', -- Reconstruct the map prior to the unrepeatable move. getAvailableQualifiedMovesByLogicalColour = Map.fromAscList [- (logicalColour, mkAvailableQualifiedMovesFor logicalColour game') |+ id &&& mkAvailableQualifiedMovesFor game' $ logicalColour | logicalColour <- Property.FixedMembership.members, maybeChecked' /= Just logicalColour ], -- List-comprehension.- getMaybeTerminationReason = Nothing+ getMaybeTerminationReason = Nothing } in Just ((game', turn), game') _ -> Nothing@@ -1054,23 +1057,23 @@ * CAVEAT: to avoid an infinite loop, this doesn't check whether the game has already terminated. -} listQualifiedMovesAvailableTo- :: Attribute.LogicalColour.LogicalColour -- ^ Define the player for whom the moves are required.- -> Game+ :: Game+ -> Colour.LogicalColour.LogicalColour -- ^ Define the player for whom the moves are required. -> [Component.QualifiedMove.QualifiedMove]-listQualifiedMovesAvailableTo logicalColour game@MkGame {+listQualifiedMovesAvailableTo game@MkGame { getBoard = board, getMaybeChecked = maybeChecked-}+} logicalColour | maybeChecked == Just logicalColour = let- kingsCoordinates = State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour+ kingsCoordinates = State.CoordinatesByRankByLogicalColour.getKingsCoordinates coordinatesByRankByLogicalColour logicalColour in [ Component.QualifiedMove.mkQualifiedMove move moveType |- (destination, maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor kingsCoordinates (Component.Piece.mkKing logicalColour) maybePieceByCoordinates,+ (destination, maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates kingsCoordinates $ Component.Piece.mkKing logicalColour, let move = Component.Move.mkMove kingsCoordinates destination moveType = Attribute.MoveType.mkNormalMoveType maybeTakenRank Nothing {-promotion-rank-},- null . State.Board.findAttackersOf logicalColour destination $ State.Board.movePiece move (Just moveType) board -- Avoid moving the King into another check. CAVEAT: one can't merely use 'Board.exposesKing' since that assumes that one isn't already checked.- ] {-list-comprehension-} ++ case State.Board.findAttackersOf logicalColour kingsCoordinates board of+ null $ State.Board.findAttackersOf (State.Board.movePiece move (Just moveType) board) logicalColour destination -- Avoid moving the King into another check. CAVEAT: one can't merely use 'Board.exposesKing' since that assumes that one isn't already checked.+ ] {-list-comprehension-} ++ case State.Board.findAttackersOf board logicalColour kingsCoordinates of [(checkedFrom, checkedByRank)] -> Control.Exception.assert (checkedByRank /= Attribute.Rank.King) . filter isSafeQualifiedMove $ ( if checkedByRank == Attribute.Rank.Pawn then Data.Maybe.maybe [] {-CAVEAT: this can occur if the game has just been read from FEN-} (@@ -1082,9 +1085,9 @@ Component.QualifiedMove.mkQualifiedMove ( Component.Move.mkMove source $ Cartesian.Coordinates.advance logicalColour lastDestination -- Construct a move which takes the attacker. ) Attribute.MoveType.enPassant |- Component.Move.isPawnDoubleAdvance opponentsLogicalColour lastMove,+ Component.Move.isPawnDoubleAdvance lastMove opponentsLogicalColour, source <- Cartesian.Coordinates.getAdjacents lastDestination,- State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates == Just pawn+ State.MaybePieceByCoordinates.dereference maybePieceByCoordinates source == Just pawn ] -- List-comprehension. ) . Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove ) $ maybeLastTurn game -- The King is checked by a Pawn, which must also have been the last piece to move.@@ -1093,7 +1096,7 @@ Component.QualifiedMove.mkQualifiedMove ( Component.Move.mkMove source checkedFrom -- Construct a move which takes the attacker. ) $ Attribute.MoveType.mkNormalMoveType (Just checkedByRank) maybePromotionRank |- (source, attackersRank) <- State.Board.findAttackersOf opponentsLogicalColour checkedFrom board, -- See if the attacker can be taken (excluding en-passant).+ (source, attackersRank) <- State.Board.findAttackersOf board opponentsLogicalColour checkedFrom, -- See if the attacker can be taken (excluding en-passant). attackersRank /= Attribute.Rank.King, -- The King can take its attacker, but it's already addressed above. maybePromotionRank <- listMaybePromotionRanks checkedFrom {-destination-} $ Component.Piece.mkPiece logicalColour attackersRank ] {-list-comprehension-} ++ [@@ -1103,26 +1106,26 @@ checkedByRank /= Attribute.Rank.Knight, -- A Knight can't be blocked. rank <- Attribute.Rank.expendable, -- Find pieces that might be able to block the checking piece. let piece = Component.Piece.mkPiece logicalColour rank,- source <- State.CoordinatesByRankByLogicalColour.dereference logicalColour rank coordinatesByRankByLogicalColour, -- Find the source of a potential blocking move.- (destination, Nothing) <- State.MaybePieceByCoordinates.listDestinationsFor source piece maybePieceByCoordinates, -- The blocker must move to an empty square, otherwise the checker was already blocked.+ source <- State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour rank, -- Find the source of a potential blocking move.+ (destination, Nothing) <- State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates source piece, -- The blocker must move to an empty square, otherwise the checker was already blocked. Control.Exception.assert (checkedFrom /= kingsCoordinates) . elem destination . init {-drop King's location-} $ Cartesian.Coordinates.interpolate checkedFrom kingsCoordinates, maybePromotionRank <- listMaybePromotionRanks destination piece ] -- List-comprehension. attackers -> Control.Exception.assert ( length attackers == 2 -- Triple-check isn't possible. ) [] -- If checked by more than one piece, then the King must be moved; see options above.- | otherwise {-not checked-} = findAvailableCastlingMoves logicalColour game ++ filter isSafeQualifiedMove (+ | otherwise {-not checked-} = findAvailableCastlingMoves game logicalColour ++ filter isSafeQualifiedMove ( [ Component.QualifiedMove.mkQualifiedMove ( Component.Move.mkMove source destination ) Attribute.MoveType.enPassant | let pawn = Component.Piece.mkPawn logicalColour,- source <- State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn coordinatesByRankByLogicalColour,- Cartesian.Coordinates.isEnPassantRank logicalColour source,- destination <- Component.Piece.findAttackDestinations source pawn,- State.MaybePieceByCoordinates.isVacant destination maybePieceByCoordinates,+ source <- State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour Attribute.Rank.Pawn,+ Cartesian.Coordinates.isEnPassantRank source logicalColour,+ destination <- Component.Piece.findAttackDestinations pawn source,+ State.MaybePieceByCoordinates.isVacant maybePieceByCoordinates destination, let opponentsCoordinates = Cartesian.Coordinates.retreat logicalColour destination,- State.MaybePieceByCoordinates.dereference opponentsCoordinates maybePieceByCoordinates == Just (Property.Opposable.getOpposite pawn),+ State.MaybePieceByCoordinates.dereference maybePieceByCoordinates opponentsCoordinates == Just (Property.Opposable.getOpposite pawn), Data.Maybe.maybe False {-zero previous turns-} ( uncurry (&&) . ( (== opponentsCoordinates) . Component.Move.getDestination &&& (@@ -1134,8 +1137,8 @@ Component.QualifiedMove.mkQualifiedMove ( Component.Move.mkMove source destination ) $ Attribute.MoveType.mkNormalMoveType maybeTakenRank maybePromotionRank |- (source, piece) <- State.CoordinatesByRankByLogicalColour.findPiecesOfColour logicalColour coordinatesByRankByLogicalColour,- (destination, maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor source piece maybePieceByCoordinates,+ (source, piece) <- State.CoordinatesByRankByLogicalColour.findPiecesOfColour coordinatesByRankByLogicalColour logicalColour,+ (destination, maybeTakenRank) <- State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates source piece, maybeTakenRank /= Just Attribute.Rank.King, -- This move can never be made; the option will either be immediately removed or check-mate declared. maybePromotionRank <- listMaybePromotionRanks destination piece ] -- List-comprehension.@@ -1143,11 +1146,11 @@ where opponentsLogicalColour = Property.Opposable.getOpposite logicalColour (maybePieceByCoordinates, coordinatesByRankByLogicalColour) = State.Board.getMaybePieceByCoordinates &&& State.Board.getCoordinatesByRankByLogicalColour $ board- isSafeQualifiedMove qualifiedMove = not $ State.Board.exposesKing logicalColour (Component.QualifiedMove.getMove qualifiedMove) board+ isSafeQualifiedMove qualifiedMove = not . State.Board.exposesKing board logicalColour $ Component.QualifiedMove.getMove qualifiedMove -- | Construct 'AvailableQualifiedMoves' for the player of the specified /logical colour/.-mkAvailableQualifiedMovesFor :: Attribute.LogicalColour.LogicalColour -> Game -> AvailableQualifiedMoves-mkAvailableQualifiedMovesFor logicalColour = foldr {-maintains destination-order-} (+mkAvailableQualifiedMovesFor :: Game -> Colour.LogicalColour.LogicalColour -> AvailableQualifiedMoves+mkAvailableQualifiedMovesFor game = foldr {-maintains destination-order-} ( \qualifiedMove -> let move = Component.QualifiedMove.getMove qualifiedMove in Map.insertWith (++) (@@ -1158,7 +1161,7 @@ Component.QualifiedMove.getMoveType qualifiedMove ) -- Pair. ] {-singleton-}- ) Property.Empty.empty . listQualifiedMovesAvailableTo logicalColour+ ) Property.Empty.empty . listQualifiedMovesAvailableTo game {- | * Retrieve the recorded value, or generate the list of /move/s available to the player of the specified /logical colour/.@@ -1166,31 +1169,31 @@ * CAVEAT: doesn't account for game-termination. -} findQualifiedMovesAvailableTo- :: Attribute.LogicalColour.LogicalColour- -> Game+ :: Game+ -> Colour.LogicalColour.LogicalColour -> [Component.QualifiedMove.QualifiedMove]-findQualifiedMovesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour }+findQualifiedMovesAvailableTo game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour } logicalColour | Just availableQualifiedMoves <- Map.lookup logicalColour availableQualifiedMovesByLogicalColour = [ Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) moveType | (source, qualifiedDestinations) <- Map.toList availableQualifiedMoves, (destination, moveType) <- qualifiedDestinations ] -- List-comprehension.- | otherwise = listQualifiedMovesAvailableTo logicalColour game -- Generate the list of moves for this player.+ | otherwise = listQualifiedMovesAvailableTo game logicalColour -- Generate the list of moves for this player. -- | Count the number of plies available to the specified player.-countPliesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game -> Type.Count.NPlies-countPliesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour }+countPliesAvailableTo :: Game -> Colour.LogicalColour.LogicalColour -> Type.Count.NPlies+countPliesAvailableTo game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour } logicalColour | isTerminated game = 0 | Just availableQualifiedMoves <- Map.lookup logicalColour availableQualifiedMovesByLogicalColour -- N.B.: 'findQualifiedMovesAvailableToNextPlayer' unnecessarily constructs a list. = fromIntegral $ Data.Foldable.foldl' (\acc -> (+ acc) . length) 0 availableQualifiedMoves- | otherwise = fromIntegral . length $ listQualifiedMovesAvailableTo logicalColour game+ | otherwise = fromIntegral . length $ listQualifiedMovesAvailableTo game logicalColour -- | Retrieve the recorded value, or generate the list of /move/s available to the next player. findQualifiedMovesAvailableToNextPlayer :: Game -> [Component.QualifiedMove.QualifiedMove]-findQualifiedMovesAvailableToNextPlayer game@MkGame { getNextLogicalColour = nextLogicalColour } = findQualifiedMovesAvailableTo nextLogicalColour game+findQualifiedMovesAvailableToNextPlayer game@MkGame { getNextLogicalColour = nextLogicalColour } = findQualifiedMovesAvailableTo game nextLogicalColour -- | Let the specified player resign.-resignationBy :: Attribute.LogicalColour.LogicalColour -> Transformation+resignationBy :: Colour.LogicalColour.LogicalColour -> Transformation resignationBy logicalColour game | isTerminated game = game -- Already terminated. | otherwise = game {@@ -1225,7 +1228,7 @@ } | haveZeroMoves , Just logicalColour <- getMaybeChecked game = Just $ Rule.GameTerminationReason.mkCheckMate logicalColour- | otherwise = fmap Rule.GameTerminationReason.mkDraw maybeDrawReason+ | otherwise = Rule.GameTerminationReason.mkDraw <$> maybeDrawReason where haveZeroMoves :: Bool haveZeroMoves = null $ findQualifiedMovesAvailableToNextPlayer game@@ -1296,7 +1299,7 @@ (castleableRooksByLogicalColour, castleableRooksByLogicalColour') = ($ game) &&& ($ game') $ getCastleableRooksByLogicalColour in if isCastle || castleableRooksByLogicalColour /= castleableRooksByLogicalColour' then (- State.CastleableRooksByLogicalColour.listIncrementalRandoms castleableRooksByLogicalColour castleableRooksByLogicalColour' zobrist +++ State.CastleableRooksByLogicalColour.listIncrementalRandoms zobrist castleableRooksByLogicalColour castleableRooksByLogicalColour' ++ ) -- Section. else id ) $ [@@ -1308,9 +1311,9 @@ State.Board.getMaybePieceByCoordinates $ getBoard g ) -- CAVEAT: accounts for any change to the En-passant option, rather than the act of taking En-passant. ) [game, game'],- random <- StateProperty.Hashable.listRandoms enPassantAbscissa zobrist+ random <- StateProperty.Hashable.listRandoms zobrist enPassantAbscissa ] {-list-comprehension-} ++ Component.Zobrist.getRandomForBlacksMove zobrist : [- Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (lastLogicalColour, rankAccessor turn, coordinatesAccessor move) zobrist |+ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist (lastLogicalColour, rankAccessor turn, coordinatesAccessor move) | (rankAccessor, coordinatesAccessor) <- zip [Component.Turn.getRank, (`Data.Maybe.fromMaybe` Attribute.Rank.getMaybePromotionRank moveType) . Component.Turn.getRank] coordinatesAccessors ] {-list-comprehension-} where lastLogicalColour = getNextLogicalColour game@@ -1322,9 +1325,9 @@ coordinatesAccessors = [Component.Move.getSource, Component.Move.getDestination] randomsFromMoveType- | Just rank <- Attribute.MoveType.getMaybeExplicitlyTakenRank moveType = [Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (nextLogicalColour, rank, destination) zobrist] -- Singleton.+ | Just rank <- Attribute.MoveType.getMaybeExplicitlyTakenRank moveType = [Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist (nextLogicalColour, rank, destination)] -- Singleton. | isCastle = map (- \coordinatesAccessor -> Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (+ \coordinatesAccessor -> Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist ( lastLogicalColour, Attribute.Rank.Rook, Data.Maybe.maybe (@@ -1334,9 +1337,9 @@ ) . Data.List.find ( (== move) . Component.CastlingMove.getKingsMove ) $ Component.CastlingMove.getCastlingMoves lastLogicalColour- ) zobrist+ ) ) coordinatesAccessors- | Attribute.MoveType.isEnPassant moveType = [Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (nextLogicalColour, Attribute.Rank.Pawn, Cartesian.Coordinates.advance nextLogicalColour destination) zobrist] -- Singleton.+ | Attribute.MoveType.isEnPassant moveType = [Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist (nextLogicalColour, Attribute.Rank.Pawn, Cartesian.Coordinates.advance nextLogicalColour destination)] -- Singleton. | otherwise = [] where nextLogicalColour = getNextLogicalColour game'
src-lib/BishBosh/Model/GameTree.hs view
@@ -30,7 +30,7 @@ module BishBosh.Model.GameTree( -- * Types -- ** Type-synonyms--- BareGameTree,+ BareGameTree, MoveFrequency, -- Transformation, -- ** Data-types@@ -57,6 +57,7 @@ import qualified BishBosh.Attribute.CaptureMoveSortAlgorithm as Attribute.CaptureMoveSortAlgorithm import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn@@ -113,7 +114,7 @@ getMaybeImplicitlyTakenRank :: Model.Game.Game -> Maybe Attribute.Rank.Rank getMaybeImplicitlyTakenRank game' = Attribute.MoveType.getMaybeImplicitlyTakenRank . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove =<< Model.Game.maybeLastTurn game' --- slave :: BareGameTree -> Attribute.Rank.Rank -> Type.Mass.RankValue+ slave :: BareGameTree -> Attribute.Rank.Rank -> Type.Mass.RankValue slave node'@Data.Tree.Node { Data.Tree.subForest = forest' } = max 0 {-this player shouldn't progress the battle-} . subtract ( case filter ( (@@ -148,7 +149,7 @@ def = fromGame Data.Default.def instance Property.Arboreal.Prunable GameTree where- prune depth MkGameTree { deconstruct = bareGameTree } = MkGameTree $ Property.Arboreal.prune depth bareGameTree+ prune depth MkGameTree { deconstruct = bareGameTree } = MkGameTree $ Data.RoseTree.prune depth bareGameTree instance Notation.MoveNotation.ShowNotation GameTree where showsNotation moveNotation MkGameTree {@@ -185,11 +186,11 @@ * N.B.: some of the /game-state/s may have identical positions, reached by different sequences of /move/s. -} countGames :: Property.Arboreal.Depth -> Type.Count.NGames-countGames depth = Data.RoseTree.countTerminalNodes . deconstruct $ Property.Arboreal.prune depth (Data.Default.def :: GameTree)+countGames depth = Data.RoseTree.countTerminalNodes . Data.RoseTree.prune depth . deconstruct $ (Data.Default.def :: GameTree) -- | Counts the number of possible positions in chess, down to the specified depth. N.B.: some of these may be transpositions. countPositions :: Property.Arboreal.Depth -> Type.Count.NPositions-countPositions depth = fromIntegral . pred {-the apex is constructed without moving-} . Data.Foldable.length . deconstruct $ Property.Arboreal.prune depth (Data.Default.def :: GameTree)+countPositions depth = fromIntegral . pred {-the apex is constructed without moving-} . Data.Foldable.length . Data.RoseTree.prune depth . deconstruct $ (Data.Default.def :: GameTree) -- | Trace the route down the tree which matches the specified list of turns. traceRoute@@ -241,6 +242,7 @@ -} toMoveFrequency :: GameTree -> MoveFrequency toMoveFrequency MkGameTree { deconstruct = bareGameTree } = slave maxBound {-logicalColour-} Property.Empty.empty {-MoveFrequency-} bareGameTree where+ slave :: Colour.LogicalColour.LogicalColour -> MoveFrequency -> BareGameTree -> MoveFrequency slave _ moveFrequency Data.Tree.Node { Data.Tree.subForest = [] } = moveFrequency slave logicalColour moveFrequency Data.Tree.Node { Data.Tree.subForest = forest } = Data.List.foldl' ( slave {-recurse-} $ Property.Opposable.getOpposite logicalColour
src-lib/BishBosh/Model/MoveFrequency.hs view
@@ -43,15 +43,15 @@ import Control.Arrow((&&&)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Property.Empty as Property.Empty-import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.Empty as Property.Empty+import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra-import qualified Data.Map.Strict as Map+import qualified Data.Map.Strict as Map import qualified Data.Ord {- |@@ -59,7 +59,7 @@ * CAVEAT: the /move-type/ isn't recorded. -}-type InstancesByMoveByRankByLogicalColour move = Attribute.LogicalColour.ArrayByLogicalColour (+type InstancesByMoveByRankByLogicalColour move = Colour.LogicalColour.ArrayByLogicalColour ( Attribute.Rank.ArrayByRank ( Map.Map move Type.Count.NPlies )@@ -71,7 +71,7 @@ } deriving Eq instance Property.Empty.Empty (MoveFrequency move) where- empty = MkMoveFrequency . Attribute.LogicalColour.listArrayByLogicalColour . repeat . Attribute.Rank.listArrayByRank $ repeat Property.Empty.empty+ empty = MkMoveFrequency . Colour.LogicalColour.listArrayByLogicalColour . repeat . Attribute.Rank.listArrayByRank $ repeat Property.Empty.empty instance Property.Null.Null (MoveFrequency move) where isNull MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.Foldable.all (Data.Foldable.all Data.Foldable.null) instancesByMoveByRankByLogicalColour@@ -104,10 +104,10 @@ -} insertMoves :: Ord move- => Attribute.LogicalColour.LogicalColour -- ^ References the player who is required to make any one of the specified moves.- -> GetRankAndMove a move -- ^ How to extract the required /rank/ & /move/ from a datum.+ => Colour.LogicalColour.LogicalColour -- ^ References the player who is required to make any one of the specified moves.+ -> GetRankAndMove a move -- ^ How to extract the required /rank/ & /move/ from a datum. -> MoveFrequency move- -> [a] -- ^ The data from each of which, /rank/ & /move/ can be extracted.+ -> [a] -- ^ The data from each of which, /rank/ & /move/ can be extracted. -> MoveFrequency move insertMoves logicalColour getRankAndMove MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = MkMoveFrequency . ( instancesByMoveByRankByLogicalColour //@@ -139,10 +139,10 @@ -} sortByDescendingMoveFrequency :: Ord move- => Attribute.LogicalColour.LogicalColour -- ^ References the player who is required to make any one of the specified moves.- -> GetRankAndMove a move -- ^ How to extract the required /rank/ & /move/ from a datum.+ => Colour.LogicalColour.LogicalColour -- ^ References the player who is required to make any one of the specified moves.+ -> GetRankAndMove a move -- ^ How to extract the required /rank/ & /move/ from a datum. -> MoveFrequency move- -> [a] -- ^ The data from each of which, /rank/ & /move/ can be extracted.+ -> [a] -- ^ The data from each of which, /rank/ & /move/ can be extracted. -> [a] {-# INLINE sortByDescendingMoveFrequency #-} sortByDescendingMoveFrequency logicalColour getRankAndMove MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.List.sortOn $ negate {-most frequent first-} . (
src-lib/BishBosh/Model/PositionHashTree.hs view
@@ -71,7 +71,7 @@ => Component.Zobrist.Zobrist positionHash -> Model.GameTree.GameTree -> PositionHashTree positionHash-mkPositionHashTree zobrist = MkPositionHashTree . fmap (`StateProperty.Hashable.hash` zobrist) . Model.GameTree.deconstruct+mkPositionHashTree zobrist = MkPositionHashTree . fmap (StateProperty.Hashable.hash zobrist) . Model.GameTree.deconstruct -- | Count the number of distinct positions, irrespective of the sequence of moves taken to reach that terminal state. countDistinctPositions@@ -84,6 +84,7 @@ | depth < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Component.PositionHashTree.countDistinctPositions:\tdepth" . Text.ShowList.showsAssociation $ shows depth "must be positive" | otherwise = fromIntegral . Data.Set.size $ slave depth barePositionHashTree where+ slave :: Ord positionHash => Property.Arboreal.Depth -> BarePositionHashTree positionHash -> Data.Set.Set positionHash slave 0 Data.Tree.Node { Data.Tree.rootLabel = hash } = Data.Set.singleton hash -- Having reached the maximum depth, include this game's hash. slave _ Data.Tree.Node { Data.Tree.rootLabel = hash,
src-lib/BishBosh/Property/Arboreal.hs view
@@ -31,23 +31,10 @@ Depth ) where -import qualified Data.Tree- -- | A distance down the tree. type Depth = Int -- | An interface which tree-like data can support. class Prunable tree where prune :: Depth -> tree -> tree -- ^ Remove branches after the specified depth.--instance Prunable (Data.Tree.Tree a) where- prune depth tree@Data.Tree.Node { Data.Tree.subForest = forest }- | depth < 0 = error "BishBosh.Property.Arboreal.prune:\tdepth can't be negative."- | otherwise = tree {- Data.Tree.subForest = if depth == 0- then []- else map (- prune $ pred depth -- Recurse.- ) forest- }
src-lib/BishBosh/Property/Orientated.hs view
@@ -27,13 +27,33 @@ Orientated(..) ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) --- | An interface for vector-like data.+{- |+ * An interface for vector-like data.++ * CAVEAT: the default implementations are mutually dependent, & could result in infinite recursion.+-} class Orientated a where- isDiagonal :: a -> Bool -- ^ Whether it is diagonal wrt the edges of the board.+ isVertical :: a -> Bool -- ^ Whether the datum is aligned with a file of the board.+ isVertical = uncurry (&&) . (isParallel &&& not . isHorizontal) -- Default implementation.++ isHorizontal :: a -> Bool -- ^ Whether the datum is aligned with a rank of the board.+ isHorizontal = uncurry (&&) . (isParallel &&& not . isVertical) -- Default implementation.+ isParallel :: a -> Bool -- ^ Whether it is parallel to an edge of the board.+ isParallel = uncurry (||) . (isVertical &&& isHorizontal) -- Default implementation. + isDiagonal :: a -> Bool -- ^ Whether it is diagonal (45 degrees) wrt the edges of the board.+ isDiagonal = uncurry (&&) . (isStraight &&& not . isParallel) -- Default implementation.+ isStraight :: a -> Bool- isStraight = uncurry (||) . (isParallel &&& isDiagonal) -- Default implementation.+ isStraight = uncurry (||) . (isParallel &&& isDiagonal) -- Default implementation.++instance (Orientated l, Orientated r) => Orientated (Either l r) where+ isVertical = isVertical ||| isVertical+ isHorizontal = isHorizontal ||| isHorizontal+ isDiagonal = isDiagonal ||| isDiagonal+ isParallel = isParallel ||| isParallel+ isStraight = isStraight ||| isStraight
src-lib/BishBosh/Property/Rotatable.hs view
@@ -37,9 +37,11 @@ -- | An interface which data which can be transformed by rotation, may implement. class (Property.Reflectable.ReflectableOnX a, Property.Reflectable.ReflectableOnY a) => Rotatable a where rotate90 :: a -> a -- ^ Rotate anticlockwise by 90 degrees, so that @N@ becomes @W@.+ rotate90 = rotate270 . rotate180 rotate180 :: a -> a -- ^ Rotate by 180 degrees.- rotate180 = Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnY -- CAVEAT: perhaps not the most efficient implementation.+ rotate180 = Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnY -- CAVEAT: perhaps not the most efficient implementation. rotate270 :: a -> a -- ^ Rotate clockwise by 90 degrees, so that @N@ becomes @E@.+ rotate270 = rotate90 . rotate180
src-lib/BishBosh/Property/SelfValidating.hs view
@@ -32,6 +32,8 @@ isInvalid ) where +import Control.Arrow((***))+ {- | * This class serves data-types which must preserve compatibility beyond that which can be guarded by a smart-constructor. @@ -42,6 +44,9 @@ instance SelfValidating a => SelfValidating [a] where findInvalidity = concatMap findInvalidity++instance (SelfValidating a, SelfValidating b) => SelfValidating (a, b) where+ findInvalidity = uncurry (++) . (findInvalidity *** findInvalidity) -- | Predicate. isValid :: SelfValidating a => a -> Bool
src-lib/BishBosh/Rule/GameTerminationReason.hs view
@@ -46,7 +46,7 @@ isStaleMate ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Rule.DrawReason as Rule.DrawReason@@ -55,8 +55,8 @@ -- | The sum-type of ways in which a game can legally be terminated. data GameTerminationReason- = CheckMateOf Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /check-mated/ player.- | ResignationBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player who resigned.+ = CheckMateOf Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /check-mated/ player.+ | ResignationBy Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player who resigned. | Draw Rule.DrawReason.DrawReason deriving (Eq, Ord, Read, Show) @@ -81,11 +81,11 @@ Draw _ -> Nothing -- | Constructor.-mkCheckMate :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason+mkCheckMate :: Colour.LogicalColour.LogicalColour -> GameTerminationReason mkCheckMate = CheckMateOf -- | Constructor.-mkResignation :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason+mkResignation :: Colour.LogicalColour.LogicalColour -> GameTerminationReason mkResignation = ResignationBy -- | Constructor.@@ -93,7 +93,7 @@ mkDraw = Draw -- | Whether the game was won by the specified player.-isCheckMateBy :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason -> Bool+isCheckMateBy :: Colour.LogicalColour.LogicalColour -> GameTerminationReason -> Bool isCheckMateBy logicalColour (CheckMateOf logicalColour') = logicalColour /= logicalColour' isCheckMateBy _ _ = False
src-lib/BishBosh/Rule/Result.hs view
@@ -38,7 +38,7 @@ isDraw ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Opposable as Property.Opposable import qualified Control.DeepSeq@@ -46,7 +46,7 @@ -- | The sum-type of ways in which a game can legally be terminated. data Result- = VictoryBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the victor.+ = VictoryBy Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the victor. | Draw deriving Eq @@ -59,7 +59,7 @@ showsPrec _ = ( \(showsWhiteResult, showsBlackResult) -> showsWhiteResult . showChar '-' . showsBlackResult ) . \case- VictoryBy Attribute.LogicalColour.Black -> (lose, win)+ VictoryBy Colour.LogicalColour.Black -> (lose, win) VictoryBy _ -> (win, lose) _ -> (draw, draw) where@@ -69,8 +69,8 @@ instance Read Result where readsPrec _ s = case Data.List.Extra.trimStart s of- '0' : '-' : '1' : remainder -> [(VictoryBy Attribute.LogicalColour.Black, remainder)]- '1' : '-' : '0' : remainder -> [(VictoryBy Attribute.LogicalColour.White, remainder)]+ '0' : '-' : '1' : remainder -> [(VictoryBy Colour.LogicalColour.Black, remainder)]+ '1' : '-' : '0' : remainder -> [(VictoryBy Colour.LogicalColour.White, remainder)] '1' : '/' : '2' : '-' : '1' : '/' : '2' : remainder -> [(Draw, remainder)] _ -> [] -- No Parse. @@ -82,7 +82,7 @@ members = Draw : map VictoryBy Property.FixedMembership.members -- | Constructor.-mkResult :: Maybe Attribute.LogicalColour.LogicalColour -> Result+mkResult :: Maybe Colour.LogicalColour.LogicalColour -> Result mkResult (Just logicalColour) = VictoryBy logicalColour mkResult _ = Draw @@ -92,7 +92,7 @@ isDraw _ = False -- | Find any winner.-findMaybeVictor :: Result -> Maybe Attribute.LogicalColour.LogicalColour+findMaybeVictor :: Result -> Maybe Colour.LogicalColour.LogicalColour findMaybeVictor (VictoryBy logicalColour) = Just logicalColour findMaybeVictor _ = Nothing
src-lib/BishBosh/Search/AlphaBeta.hs view
@@ -44,7 +44,7 @@ -- addNPositionsToResult ) where -import BishBosh.Model.Game((=~))+import BishBosh.Evaluation.QuantifiedGame((<=>), (===)) import Control.Applicative((<|>)) import Control.Arrow((&&&)) import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -73,7 +73,7 @@ -- | The type returned by 'negaMax'. data Result positionHash = MkResult {- getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData positionHash, -- ^ Killer moves & transpositions.+ getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData positionHash, -- ^ Killer moves & Transpositions. getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame, getNPositionsEvaluated :: Type.Count.NPositions -- ^ The total number of nodes analysed, before making the selection. }@@ -117,7 +117,7 @@ -> Search.TranspositionValue.TranspositionValue Component.QualifiedMove.QualifiedMove -> Evaluation.QuantifiedGame.QuantifiedGame findTranspositionTerminalQuantifiedGame positionHashQuantifiedGameTree transpositionValue = Data.Maybe.maybe (- Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Search.AlphaBeta.findTranspositionTerminalQuantifiedGame:\tEvaluation.PositionHashQuantifiedGameTree.traceMatchingMoves failed; " . shows transpositionValue . showString ":\n" $ (+ Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Search.AlphaBeta.findTranspositionTerminalQuantifiedGame:\tEvaluation.PositionHashQuantifiedGameTree.traceMatchingMoveSequence failed; " . shows transpositionValue . showString ":\n" $ ( Notation.MoveNotation.showsNotationFloatToNDecimals Data.Default.def {-move-notation-} 3 {-decimal digits-} $ Property.Arboreal.prune (fromIntegral inferredSearchDepth) positionHashQuantifiedGameTree ) "" ) (@@ -126,7 +126,7 @@ then Evaluation.QuantifiedGame.negateFitness -- The opponent made the last move in the list, & therefore defined the fitness. else id ) . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame . last- ) . Evaluation.PositionHashQuantifiedGameTree.traceMatchingMoves positionHashQuantifiedGameTree $ Search.TranspositionValue.getQualifiedMoves transpositionValue where+ ) . Evaluation.PositionHashQuantifiedGameTree.traceMatchingMoveSequence positionHashQuantifiedGameTree $ Search.TranspositionValue.getQualifiedMoves transpositionValue where inferredSearchDepth = Search.TranspositionValue.inferSearchDepth transpositionValue -- | Record a qualifiedMove-sequence in the transposition-table.@@ -147,7 +147,7 @@ * /alpha/ is the minimum fitness of which the maximising player is assured. - * /beta/ is the maximum fitness of which the minimising player is assured.+ * /beta/ is the maximum fitness which the minimising player will tolerate. -} negaMax :: Ord positionHash@@ -162,13 +162,8 @@ let getNPlies = State.TurnsByLogicalColour.getNPlies . Model.Game.getTurnsByLogicalColour -- Abbreviate.-{-- descend- :: Evaluation.QuantifiedGame.OpenInterval- -> Type.Count.NPlies- -> Search.SearchState.SearchState positionHash- -> Result positionHash--}++ descend :: Ord positionHash => Evaluation.QuantifiedGame.OpenInterval -> Type.Count.NPlies -> Search.SearchState.SearchState positionHash -> Result positionHash descend (maybeAlphaQuantifiedGame, maybeBetaQuantifiedGame) searchDepth searchState | searchDepth == 0 || Model.Game.isTerminated game = MkResult { getDynamicMoveData = dynamicMoveData,@@ -178,9 +173,10 @@ | useTranspositions , Just transpositionValue <- Search.Transpositions.find positionHash $ Search.DynamicMoveData.getTranspositions dynamicMoveData -- Look for a previously encountered position with a matching positionHash. , let+-- selectMaxUsingTranspositions :: Result positionHash selectMaxUsingTranspositions = selectMaxWithSorter $ Data.Maybe.fromMaybe (- Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Search.AlphaBeta.negaMax.descend:\tEvaluation.PositionHashQuantifiedGameTree.promoteMatchingMoves failed; " $ shows transpositionValue "." -- N.B.: perhaps because of hash-collision.- ) . Evaluation.PositionHashQuantifiedGameTree.promoteMatchingMoves (+ Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Search.AlphaBeta.negaMax.descend:\tEvaluation.PositionHashQuantifiedGameTree.promoteMatchingMoveSequence failed; " $ shows transpositionValue "." -- N.B.: perhaps because of hash-collision.+ ) . Evaluation.PositionHashQuantifiedGameTree.promoteMatchingMoveSequence ( Search.TranspositionValue.getQualifiedMoves transpositionValue ) -- For efficiency, promote moves in the positionHashQuantifiedGameTree, using the knowledge in the transposition. = if Search.TranspositionValue.inferSearchDepth transpositionValue < searchDepth@@ -194,13 +190,13 @@ getNPositionsEvaluated = 0 } else Data.Maybe.maybe selectMaxUsingTranspositions (- \betaQuantifiedGame -> if Evaluation.QuantifiedGame.compareFitness transposedQuantifiedGame betaQuantifiedGame == LT+ \betaQuantifiedGame -> if uncurry (<) $ (($ transposedQuantifiedGame) &&& ($ betaQuantifiedGame)) Evaluation.QuantifiedGame.getFitness then selectMaxUsingTranspositions else MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = Control.Exception.assert (betaQuantifiedGame == getQuantifiedGame selectMaxUsingTranspositions) betaQuantifiedGame, getNPositionsEvaluated = 0- }+ } -- Beta-cutoff. ) maybeBetaQuantifiedGame | otherwise = selectMaxWithSorter id where@@ -211,6 +207,7 @@ game = Evaluation.QuantifiedGame.getGame quantifiedGame -- Prior to application of any move from the forest. (nPlies, nDistinctPositions) = getNPlies &&& State.InstancesByPosition.getNDistinctPositions . Model.Game.getInstancesByPosition $ game -- Count the distinct positions since the last irreversible move. +-- selectMaxWithSorter :: (Evaluation.PositionHashQuantifiedGameTree.Forest positionHash -> Evaluation.PositionHashQuantifiedGameTree.Forest positionHash) -> Result positionHash selectMaxWithSorter forestSorter = selectMax dynamicMoveData maybeAlphaQuantifiedGame . forestSorter . ( if recordKillerMoves then Evaluation.PositionHashQuantifiedGameTree.sortNonCaptureMoves (@@ -222,47 +219,35 @@ ) -- Dynamically advance the evaluation of killer-moves, to just after the statically sorted capture-moves. else id ) . Data.Tree.subForest $ Evaluation.PositionHashQuantifiedGameTree.deconstruct positionHashQuantifiedGameTree-{-- selectMax- :: Search.DynamicMoveData.DynamicMoveData positionHash- -> Maybe Evaluation.QuantifiedGame.QuantifiedGame- -> [Evaluation.PositionHashQuantifiedGameTree.BarePositionHashQuantifiedGameTree positionHash]- -> Result positionHash--}++-- selectMax :: Search.DynamicMoveData.DynamicMoveData positionHash -> Maybe Evaluation.QuantifiedGame.QuantifiedGame -> Evaluation.PositionHashQuantifiedGameTree.Forest positionHash -> Result positionHash selectMax dynamicMoveData' maybeAlphaQuantifiedGame' (node : remainingNodes) | trapRepeatedPositions- , nDistinctPositions >= fromIntegral State.InstancesByPosition.leastCyclicPlies -- CAVEAT: accounting for the typically (except when its the initial position) unrepeatable first distinct position.+ , nDistinctPositions >= fromIntegral State.InstancesByPosition.leastCyclicPlies -- CAVEAT: accounting for the typically (except the initial position) unrepeatable first distinct position. , State.InstancesByPosition.getNDistinctPositions ( Model.Game.getInstancesByPosition . Evaluation.QuantifiedGame.getGame $ Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame' node -- If the size hasn't increased, then the recently added position must have already been a member; (size == 1) during successive unrepeatable moves also, but that exception is caught above.- ) == nDistinctPositions = selectMax dynamicMoveData' (+ ) == nDistinctPositions = selectMax dynamicMoveData' ( maybeAlphaQuantifiedGame' <|> Just quantifiedGame'' -- CAVEAT: guard against exhausting all nodes without defining alpha.- ) remainingNodes -- Skip this node & recurse through the remaining moves at this depth.+ ) remainingNodes -- Skip this repetitive node & recurse through the remaining nodes at this depth. | Just betaQuantifiedGame <- maybeBetaQuantifiedGame -- Beta-cutoff can't occur until beta has been defined.- , let fitnessComparedWithBeta = Evaluation.QuantifiedGame.compareFitness quantifiedGame'' betaQuantifiedGame+ , let fitnessComparedWithBeta = quantifiedGame'' <=> betaQuantifiedGame , fitnessComparedWithBeta /= LT = result'' {- getDynamicMoveData = let- game'' = Evaluation.QuantifiedGame.getGame quantifiedGame''- in (+ getDynamicMoveData = ( if recordKillerMoves && not (- fitnessComparedWithBeta == EQ && game'' =~ Evaluation.QuantifiedGame.getGame betaQuantifiedGame -- CAVEAT: betaQuantifiedGame was copied in selectMaxWithSorters terminal case, from one of the open-interval's boundaries.+ fitnessComparedWithBeta == EQ && quantifiedGame'' === betaQuantifiedGame -- betaQuantifiedGame was copied in the terminal case of 'selectMax', from one of the open-interval's boundaries. ) -- Confirm that betaQuantifiedGame is beneath the current node.- then updateKillerMoves game''+ then updateKillerMoves $ Evaluation.QuantifiedGame.getGame quantifiedGame'' else id ) dynamicMoveData'', getQuantifiedGame = betaQuantifiedGame } -- Beta-cutoff; the solution-space is either zero or negative.- | otherwise = addNPositionsToResult (- getNPositionsEvaluated result''- ) $ let+ | otherwise = let isFitter = Data.Maybe.maybe True {-alpha is undefined => anything qualifies-} (- \alphaQuantifiedGame -> case quantifiedGame'' `Evaluation.QuantifiedGame.compareFitness` alphaQuantifiedGame of- LT -> False- GT -> True- EQ -> uncurry (<) . (- ($ quantifiedGame'') &&& ($ alphaQuantifiedGame)- ) $ getNPlies . Evaluation.QuantifiedGame.getGame -- Prefer a shorter move-sequence.+ \alphaQuantifiedGame -> uncurry (>) $ (($ quantifiedGame'') &&& ($ alphaQuantifiedGame)) Evaluation.QuantifiedGame.getFitness ) maybeAlphaQuantifiedGame'- in selectMax (+ in addNPositionsToResult (+ getNPositionsEvaluated result''+ ) $ selectMax ( ( if useTranspositions && isFitter then updateTranspositions False {-isOptimal-} nPlies positionHash {-the hash of the game before the first move in the sequence-} (@@ -272,7 +257,7 @@ ) dynamicMoveData'' ) ( if isFitter- then Just quantifiedGame'' -- Replace the alpha solution (i.e. the lower acceptable solution-bound).+ then Just quantifiedGame'' -- Increase the alpha solution (i.e. the lower acceptable solution-bound). else maybeAlphaQuantifiedGame' ) remainingNodes -- Recurse through the remaining moves at this depth. where
src-lib/BishBosh/Search/KillerMoves.hs view
@@ -37,15 +37,15 @@ import Control.Arrow((&&&)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Property.Empty as Property.Empty-import qualified BishBosh.Search.EphemeralData as Search.EphemeralData-import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.Empty as Property.Empty+import qualified BishBosh.Search.EphemeralData as Search.EphemeralData+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Array.IArray import qualified Data.Foldable-import qualified Data.IntMap.Strict as IntMap+import qualified Data.IntMap.Strict as IntMap import qualified Data.List-import qualified Data.Map as Map+import qualified Data.Map as Map import qualified Data.Maybe {- |@@ -54,7 +54,7 @@ a key containing the killer-move, & the logical colour of the player making the move. -}-type NInstancesByNPliesByKeyByLogicalColour killerMoveKey = Attribute.LogicalColour.ArrayByLogicalColour (+type NInstancesByNPliesByKeyByLogicalColour killerMoveKey = Colour.LogicalColour.ArrayByLogicalColour ( Map.Map killerMoveKey ( IntMap.IntMap Type.Count.NPlies {-NInstances-} -- CAVEAT: 'Int' is used to represent the number of plies into the game (in order to utilise 'IntMap') though it ought to be NPlies also. )@@ -66,7 +66,7 @@ } instance Property.Empty.Empty (KillerMoves killerMoveKey) where- empty = MkKillerMoves . Attribute.LogicalColour.listArrayByLogicalColour $ repeat Property.Empty.empty+ empty = MkKillerMoves . Colour.LogicalColour.listArrayByLogicalColour $ repeat Property.Empty.empty instance Search.EphemeralData.EphemeralData (KillerMoves killerMoveKey) where getSize MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = fromIntegral $ Data.Foldable.foldl' (@@ -100,14 +100,14 @@ ) . ( nInstancesByNPliesByKeyByLogicalColour ! ) $ if even nPlies- then Attribute.LogicalColour.Black- else Attribute.LogicalColour.White -- White makes the first move.+ then Colour.LogicalColour.Black+ else Colour.LogicalColour.White -- White makes the first move. ] -- Singleton. -- | Sorts an arbitrary list using the History-heuristic; <https://www.chessprogramming.org/History_Heuristic>. sortByHistoryHeuristic :: Ord killerMoveKey- => Attribute.LogicalColour.LogicalColour+ => Colour.LogicalColour.LogicalColour -> (a -> killerMoveKey) -- ^ Key-constructor. -> KillerMoves killerMoveKey -> [a]
src-lib/BishBosh/State/Board.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts #-}+{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -67,29 +67,31 @@ import Control.Arrow((&&&), (***), (|||)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Accountant as Component.Accountant import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Direction.Direction as Direction.Direction import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.StateProperty.View as StateProperty.View import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow@@ -101,17 +103,12 @@ import qualified Data.List import qualified Data.Map.Strict as Map import qualified Data.Maybe-import qualified ToolShed.Data.List -#ifdef USE_UNBOXED_ARRAYS-import qualified Data.Array.Unboxed-#endif- -- | The type of a function which transforms a /board/. type Transformation = Board -> Board -- | The number of defenders for each /piece/, belonging to each side.-type NDefendersByCoordinatesByLogicalColour = Attribute.LogicalColour.ArrayByLogicalColour (Map.Map Cartesian.Coordinates.Coordinates Type.Count.NPieces)+type NDefendersByCoordinatesByLogicalColour = Colour.LogicalColour.ArrayByLogicalColour (Map.Map Cartesian.Coordinates.Coordinates Type.Count.NPieces) {- | * The board is modelled as two alternative structures representing the same data, but indexed by either /coordinates/ or /piece/.@@ -180,22 +177,39 @@ reflectOnY MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ Property.Reflectable.reflectOnY maybePieceByCoordinates instance StateProperty.Hashable.Hashable Board where- listRandoms MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Hashable.listRandoms coordinatesByRankByLogicalColour+ listRandoms zobrist MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Hashable.listRandoms zobrist coordinatesByRankByLogicalColour -- Forward. instance StateProperty.Mutator.Mutator Board where- defineCoordinates maybePiece coordinates MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ StateProperty.Mutator.defineCoordinates maybePiece coordinates maybePieceByCoordinates+ defineCoordinates maybePiece coordinates MkBoard {+ getMaybePieceByCoordinates = maybePieceByCoordinates+ } = fromMaybePieceByCoordinates $ StateProperty.Mutator.defineCoordinates maybePiece coordinates maybePieceByCoordinates + movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkBoard {+ getMaybePieceByCoordinates = maybePieceByCoordinates+ } = fromMaybePieceByCoordinates $ StateProperty.Mutator.movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank maybePieceByCoordinates+ instance StateProperty.Seeker.Seeker Board where- findProximateKnights logicalColour coordinates MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Seeker.findProximateKnights logicalColour coordinates coordinatesByRankByLogicalColour -- Forward the request.- findPieces predicate MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Seeker.findPieces predicate coordinatesByRankByLogicalColour -- Forward the request.- countPawnsByFileByLogicalColour MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour -- Forward the request.+ findProximateKnights MkBoard {+ getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour+ } = StateProperty.Seeker.findProximateKnights coordinatesByRankByLogicalColour -- Forward the request. + findPieces predicate MkBoard {+ getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour+ } = StateProperty.Seeker.findPieces predicate coordinatesByRankByLogicalColour -- Forward the request.++ countPawnsByFileByLogicalColour MkBoard {+ getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour+ } = StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour -- Forward the request.++instance Property.SelfValidating.SelfValidating Board where+ findInvalidity = Property.SelfValidating.findInvalidity . (getMaybePieceByCoordinates &&& getCoordinatesByRankByLogicalColour)+ -- | Constructor. fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates -> Board fromMaybePieceByCoordinates maybePieceByCoordinates = board where board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates,- getCoordinatesByRankByLogicalColour = State.CoordinatesByRankByLogicalColour.fromMaybePieceByCoordinates maybePieceByCoordinates, -- Infer.+ getCoordinatesByRankByLogicalColour = StateProperty.View.translate maybePieceByCoordinates, -- Infer. getNDefendersByCoordinatesByLogicalColour = countDefendersByCoordinatesByLogicalColour board, -- Infer. getNPiecesDifferenceByRank = StateProperty.Censor.countPieceDifferenceByRank coordinatesByRankByLogicalColour, -- Infer. getNPawnsByFileByLogicalColour = StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour, -- Infer.@@ -221,60 +235,58 @@ getNPiecesDifferenceByRank = nPiecesDifferenceByRank, getNPieces = nPieces }- | Just sourcePiece <- State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates = let+ | Just sourcePiece <- State.MaybePieceByCoordinates.dereference maybePieceByCoordinates source = let oppositePiece = Property.Opposable.getOpposite sourcePiece- (logicalColour, opponentsLogicalColour) = ($ sourcePiece) &&& ($ oppositePiece) $ Component.Piece.getLogicalColour+ (logicalColour, opponentsLogicalColour) = ($! sourcePiece) &&& ($! oppositePiece) $ Component.Piece.getLogicalColour moveType :: Attribute.MoveType.MoveType moveType -- CAVEAT: one can't call 'State.MaybePieceByCoordinates.inferMoveType', since that performs some move-validation, & therefore exceeds the remit of this module. | Just explicitMoveType <- maybeMoveType = explicitMoveType- | State.MaybePieceByCoordinates.isEnPassantMove move maybePieceByCoordinates = Attribute.MoveType.enPassant -- N.B.: if this move is valid, then one's opponent must have just double-advanced an adjacent Pawn.+ | State.MaybePieceByCoordinates.isEnPassantMove maybePieceByCoordinates move = Attribute.MoveType.enPassant -- N.B.: if this move is valid, then one's opponent must have just double-advanced an adjacent Pawn. | otherwise = Attribute.MoveType.mkNormalMoveType (- Component.Piece.getRank <$> State.MaybePieceByCoordinates.dereference destination maybePieceByCoordinates- ) $ if Component.Piece.isPawnPromotion destination sourcePiece+ Component.Piece.getRank <$> State.MaybePieceByCoordinates.dereference maybePieceByCoordinates destination+ ) $ if Component.Piece.isPawnPromotion sourcePiece destination then Just Attribute.Rank.defaultPromotionRank else Nothing -- Derive the required values from moveType.- (maybePromotionRank, maybeExplicitlyTakenRank) = Attribute.Rank.getMaybePromotionRank &&& Attribute.MoveType.getMaybeExplicitlyTakenRank $ moveType -- Deconstruct.+ (maybePromotionRank, maybeExplicitlyTakenRank) = Attribute.Rank.getMaybePromotionRank &&& Attribute.MoveType.getMaybeExplicitlyTakenRank $! moveType -- Deconstruct. destinationPiece = Data.Maybe.maybe id Component.Piece.promote maybePromotionRank sourcePiece wasPawnTakenExplicitly = maybeExplicitlyTakenRank == Just Attribute.Rank.Pawn + eitherPassingPawnsDestinationOrMaybeTakenRank :: Either Cartesian.Coordinates.Coordinates (Maybe Attribute.Rank.Rank) eitherPassingPawnsDestinationOrMaybeTakenRank | Attribute.MoveType.isEnPassant moveType = Left $ Cartesian.Coordinates.retreat logicalColour destination | otherwise = Right maybeExplicitlyTakenRank + eitherPassingPawnsDestinationOrMaybeTakenPiece :: Either Cartesian.Coordinates.Coordinates (Maybe Component.Piece.Piece) eitherPassingPawnsDestinationOrMaybeTakenPiece = fmap (Component.Piece.mkPiece opponentsLogicalColour) <$> eitherPassingPawnsDestinationOrMaybeTakenRank + movePiece' :: StateProperty.Mutator.Mutator mutator => mutator -> mutator+ movePiece' = StateProperty.Mutator.movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank+ board'@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates' } = MkBoard {- getMaybePieceByCoordinates = State.MaybePieceByCoordinates.movePiece move destinationPiece (- Just ||| const Nothing $ eitherPassingPawnsDestinationOrMaybeTakenRank- ) maybePieceByCoordinates,- getCoordinatesByRankByLogicalColour = State.CoordinatesByRankByLogicalColour.movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank coordinatesByRankByLogicalColour,+ getMaybePieceByCoordinates = movePiece' maybePieceByCoordinates,+ getCoordinatesByRankByLogicalColour = movePiece' coordinatesByRankByLogicalColour, getNDefendersByCoordinatesByLogicalColour = (- \(nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates) -> Attribute.LogicalColour.listArrayByLogicalColour [nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates]+ \(nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates) -> Colour.LogicalColour.listArrayByLogicalColour [nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates] ) . foldr ( \(affectedCoordinates, affectedPiece) -> if Component.Piece.isKing affectedPiece then id -- N.B.: defence of the King is irrelevant, since one can't get to a position where it can be taken. else let logicalColour' = Component.Piece.getLogicalColour affectedPiece in (- if Attribute.LogicalColour.isBlack logicalColour'+ if Colour.LogicalColour.isBlack logicalColour' then Control.Arrow.first else Control.Arrow.second- ) . Map.insert affectedCoordinates {-overwrite-} . fromIntegral . length $ findAttackersOf (+ ) . Map.insert affectedCoordinates {-overwrite-} . fromIntegral . length $! findAttackersOf board' ( Property.Opposable.getOpposite logicalColour' -- Investigate an attack on the affected coordinates by the affected piece's own logical colour, i.e. defence.- ) affectedCoordinates board'+ ) affectedCoordinates ) (- (! Attribute.LogicalColour.Black) &&& (! Attribute.LogicalColour.White) $ nDefendersByCoordinatesByLogicalColour // (+ (! Colour.LogicalColour.Black) &&& (! Colour.LogicalColour.White) $ nDefendersByCoordinatesByLogicalColour // ( let nDefendersByCoordinates = nDefendersByCoordinatesByLogicalColour ! opponentsLogicalColour- in (- \passingPawnsDestination -> (:) (- opponentsLogicalColour,- Map.delete passingPawnsDestination nDefendersByCoordinates -- This Pawn has been taken.- )- ) ||| (+ in (:) . (,) opponentsLogicalColour . (`Map.delete` nDefendersByCoordinates) {-Pawn has been taken-} ||| ( \maybeExplicitlyTakenRank' -> if Data.Maybe.isJust maybeExplicitlyTakenRank' then (:) ( opponentsLogicalColour,@@ -283,50 +295,47 @@ else id ) $ eitherPassingPawnsDestinationOrMaybeTakenRank ) [- (- logicalColour,- Map.delete source $ nDefendersByCoordinatesByLogicalColour ! logicalColour -- This piece has been moved.- ) -- Pair.+ id &&& Map.delete source . (nDefendersByCoordinatesByLogicalColour !) $ logicalColour -- This piece has been moved. ] -- Singleton. ) . Data.List.nubBy (- ToolShed.Data.List.equalityBy fst {-coordinates-}+ \l r -> fst l == fst r -- Compare coordinates. ) $ [ (affectedCoordinates, affectedPiece) | (knightsCoordinates, knight) <- (source, sourcePiece) : (,) destination `map` (destinationPiece : (const [] ||| Data.Maybe.maybeToList) eitherPassingPawnsDestinationOrMaybeTakenPiece), Component.Piece.isKnight knight,- Just affectedCoordinates <- Cartesian.Vector.maybeTranslate knightsCoordinates `map` Cartesian.Vector.attackVectorsForKnight,- affectedPiece <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.dereference affectedCoordinates maybePieceByCoordinates',+ affectedCoordinates <- Data.Maybe.mapMaybe (`Cartesian.Vector.maybeTranslate` knightsCoordinates) Cartesian.Vector.attackVectorsForKnight,+ affectedPiece <- Data.Maybe.maybeToList $! State.MaybePieceByCoordinates.dereference maybePieceByCoordinates' affectedCoordinates, Component.Piece.isFriend knight affectedPiece ] {-list-comprehension-} ++ [ (blockingCoordinates, blockingPiece) | passingPawnsDestination <- return {-to List-monad-} ||| const [] $ eitherPassingPawnsDestinationOrMaybeTakenRank,- (direction, antiParallelDirection) <- Attribute.Direction.opposites,- (blockingCoordinates, blockingPiece) <- case ($ direction) &&& ($ antiParallelDirection) $ ($ maybePieceByCoordinates') . (`State.MaybePieceByCoordinates.findBlockingPiece` passingPawnsDestination) of- (Just cp, Just cp') -> [- cp |- let isDefendedBy from = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp),- isDefendedBy passingPawnsDestination oppositePiece || uncurry isDefendedBy cp'+ (direction, antiParallelDirection) <- Direction.Direction.opposites,+ (blockingCoordinates, blockingPiece) <- case State.MaybePieceByCoordinates.findBlockingPieces maybePieceByCoordinates' passingPawnsDestination $ Just [direction, antiParallelDirection] of+ [cp, cp'] -> [+ cp | uncurry (||) . (+ ($ (passingPawnsDestination, oppositePiece)) &&& ($ cp')+ ) $ \(from, piece) -> uncurry (&&) $ uncurry (&&&) (+ Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp+ ) piece ] {-list-comprehension-} ++ [- cp' |- let isDefendedBy from = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp'),- isDefendedBy passingPawnsDestination oppositePiece || uncurry isDefendedBy cp- ] -- List-comprehension.- (Just cp, _) -> [- cp |- uncurry (&&) $ uncurry (&&&) (Component.Piece.canAttackAlong passingPawnsDestination *** Component.Piece.isFriend $ cp) oppositePiece- ] -- List-comprehension.- (_, Just cp') -> [- cp' |- uncurry (&&) $ uncurry (&&&) (Component.Piece.canAttackAlong passingPawnsDestination *** Component.Piece.isFriend $ cp') oppositePiece+ cp' | uncurry (||) . (+ ($ (passingPawnsDestination, oppositePiece)) &&& ($ cp)+ ) $ \(from, piece) -> uncurry (&&) $ uncurry (&&&) (+ Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp'+ ) piece ] -- List-comprehension.- _ -> []+ locatedPieces -> filter (+ \locatedPiece -> uncurry (&&) $ uncurry (&&&) (+ Component.Piece.canAttackAlong passingPawnsDestination *** Component.Piece.isFriend $ locatedPiece+ ) oppositePiece+ ) locatedPieces ] {-list-comprehension-} ++ (destination, destinationPiece) : [ (blockingCoordinates, blockingPiece) | let maybeExplicitlyTakenPiece = const Nothing ||| id $ eitherPassingPawnsDestinationOrMaybeTakenPiece,- (direction, antiParallelDirection) <- Attribute.Direction.opposites,+ (direction, antiParallelDirection) <- Direction.Direction.opposites, (coordinates, piece) <- [(source, sourcePiece), (destination, destinationPiece)],- (blockingCoordinates, blockingPiece) <- case ($ direction) &&& ($ antiParallelDirection) $ ($ maybePieceByCoordinates') . (`State.MaybePieceByCoordinates.findBlockingPiece` coordinates) of- (Just cp, Just cp') -> [+ (blockingCoordinates, blockingPiece) <- case State.MaybePieceByCoordinates.findBlockingPieces maybePieceByCoordinates' coordinates $ Just [direction, antiParallelDirection] of+ [cp, cp'] -> [ cp | let isDefendedBy from = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp), isDefendedBy coordinates piece || coordinates == destination && Data.Maybe.maybe False (isDefendedBy destination) maybeExplicitlyTakenPiece || uncurry isDefendedBy cp'@@ -335,20 +344,14 @@ let isDefendedBy from = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong from *** Component.Piece.isFriend $ cp'), isDefendedBy coordinates piece || coordinates == destination && Data.Maybe.maybe False (isDefendedBy destination) maybeExplicitlyTakenPiece || uncurry isDefendedBy cp ] -- List-comprehension.- (Just cp, _) -> [- cp |- let isDefendedBy = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong coordinates *** Component.Piece.isFriend $ cp),- isDefendedBy piece || coordinates == destination && Data.Maybe.maybe False isDefendedBy maybeExplicitlyTakenPiece- ] -- List-comprehension.- (_, Just cp') -> [- cp' |- let isDefendedBy = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong coordinates *** Component.Piece.isFriend $ cp'),- isDefendedBy piece || coordinates == destination && Data.Maybe.maybe False isDefendedBy maybeExplicitlyTakenPiece- ] -- List-comprehension.- _ -> []+ locatedPieces -> filter (+ \locatedPiece -> let+ isDefendedBy = uncurry (&&) . uncurry (&&&) (Component.Piece.canAttackAlong coordinates *** Component.Piece.isFriend $ locatedPiece)+ in isDefendedBy piece || coordinates == destination && Data.Maybe.maybe False isDefendedBy maybeExplicitlyTakenPiece+ ) locatedPieces ], -- List-comprehension. Define any pieces whose defence may be affected by the move. getNPiecesDifferenceByRank = Data.Array.IArray.accum (- if Attribute.LogicalColour.isBlack logicalColour+ if Colour.LogicalColour.isBlack logicalColour then (-) -- Since White pieces are arbitrarily counted as positive, negate the adjustment if the current player is Black. else (+) ) nPiecesDifferenceByRank $ if Attribute.MoveType.isEnPassant moveType@@ -379,39 +382,23 @@ in board' | otherwise = Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.State.Board.movePiece:\tno piece exists at " . shows source . showString "; " $ shows board "." where- (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move -- Deconstruct.+ (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $! move -- Deconstruct. -- | Calculate the total value of the /coordinates/ occupied by the /piece/s of either side, at a stage in the game's life-span defined by the total number of pieces remaining.-sumPieceSquareValueByLogicalColour :: (-#ifdef USE_UNBOXED_ARRAYS- Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size).-#endif- Num pieceSquareValue- )- => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue- -> Board- ->-#ifdef USE_UNBOXED_ARRAYS- Attribute.LogicalColour.UArrayByLogicalColour-#else- Attribute.LogicalColour.ArrayByLogicalColour-#endif- pieceSquareValue-{-# SPECIALISE sumPieceSquareValueByLogicalColour- :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Mass.PieceSquareValue+sumPieceSquareValueByLogicalColour+ :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank -> Board ->-#ifdef USE_UNBOXED_ARRAYS- Attribute.LogicalColour.UArrayByLogicalColour+#if defined(USE_UNBOXED_ARRAYS) && !defined(USE_PRECISION)+ Colour.LogicalColour.UArrayByLogicalColour #else- Attribute.LogicalColour.ArrayByLogicalColour+ Colour.LogicalColour.ArrayByLogicalColour #endif- Type.Mass.PieceSquareValue- #-}+ Type.Mass.Base -- ^ Sum of PieceSquareValues. sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour, getNPieces = nPieces-} = Attribute.LogicalColour.listArrayByLogicalColour $ Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces coordinatesByRankByLogicalColour+} = Colour.LogicalColour.listArrayByLogicalColour $ Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank coordinatesByRankByLogicalColour nPieces {- | * Lists the source-/coordinates/ from which the referenced destination can be attacked.@@ -425,16 +412,14 @@ * CAVEAT: can't detect an en-passant attack, since this depends both on whether the previous move was a double advance & that the defender is a @Pawn@. -} findAttackersOf- :: Attribute.LogicalColour.LogicalColour -- ^ The defender's /logical colour/.+ :: Board+ -> Colour.LogicalColour.LogicalColour -- ^ The defender's /logical colour/. -> Cartesian.Coordinates.Coordinates -- ^ The defender's location.- -> Board -> [(Cartesian.Coordinates.Coordinates, Attribute.Rank.Rank)] -- ^ The locations from which the specified square can be attacked by the opposite /logical colour/.-findAttackersOf destinationLogicalColour destination board@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = [+findAttackersOf board@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } destinationLogicalColour destination = [ (coordinates, Attribute.Rank.Knight) |- coordinates <- StateProperty.Seeker.findProximateKnights (Property.Opposable.getOpposite destinationLogicalColour) destination board- ] {-list-comprehension-} ++ Data.Maybe.mapMaybe (- \directionFromDestination -> State.MaybePieceByCoordinates.findAttackerInDirection destinationLogicalColour directionFromDestination destination maybePieceByCoordinates- ) Property.FixedMembership.members+ coordinates <- StateProperty.Seeker.findProximateKnights board (Property.Opposable.getOpposite destinationLogicalColour) destination+ ] {-list-comprehension-} ++ State.MaybePieceByCoordinates.findAttackerInDirections maybePieceByCoordinates destinationLogicalColour destination Nothing {-omni-directional-} {- | * Lists the source-/coordinates/ from which the referenced destination can be attacked by the specified type of /piece/.@@ -444,15 +429,15 @@ * CAVEAT: can't detect an en-passant attack, since this depends both on whether the previous move was a double advance & that the defender is a @Pawn@. -} findAttacksBy- :: Component.Piece.Piece -- ^ The type of attacker.+ :: Board+ -> Component.Piece.Piece -- ^ The type of attacker. -> Cartesian.Coordinates.Coordinates -- ^ The defender's location.- -> Board -> [Cartesian.Coordinates.Coordinates] -- ^ The sources from which the specified attacker could strike.-findAttacksBy piece destination board- | rank == Attribute.Rank.Knight = StateProperty.Seeker.findProximateKnights logicalColour destination board+findAttacksBy board piece destination+ | rank == Attribute.Rank.Knight = StateProperty.Seeker.findProximateKnights board logicalColour destination | otherwise = filter (- \source -> source /= destination && Component.Piece.canAttackAlong source destination piece && State.MaybePieceByCoordinates.isClear source destination (getMaybePieceByCoordinates board)- ) . State.CoordinatesByRankByLogicalColour.dereference logicalColour rank $ getCoordinatesByRankByLogicalColour board+ \source -> source /= destination && Component.Piece.canAttackAlong source destination piece && State.MaybePieceByCoordinates.isClear (getMaybePieceByCoordinates board) source destination+ ) $ State.CoordinatesByRankByLogicalColour.dereference (getCoordinatesByRankByLogicalColour board) logicalColour rank where (logicalColour, rank) = Component.Piece.getLogicalColour &&& Component.Piece.getRank $ piece @@ -464,10 +449,12 @@ * CAVEAT: assumes there's exactly one @King@ of the specified /logical colour/. -} isKingChecked- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ in question.- -> Board+ :: Board+ -> Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ in question. -> Bool-isKingChecked logicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = not . null $ findAttackersOf logicalColour (State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour) board+isKingChecked board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = not . null . uncurry ($!) . (+ findAttackersOf board &&& State.CoordinatesByRankByLogicalColour.getKingsCoordinates coordinatesByRankByLogicalColour+ ) {- | * Whether one's own @King@ has become exposed in the proposed /board/.@@ -477,42 +464,42 @@ * CAVEAT: this function is a performance-hotspot. -} exposesKing- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player proposing to move.- -> Component.Move.Move -- ^ The /move/.- -> Board -- ^ The original /board/, i.e. prior to the /move/.+ :: Board -- ^ The original /board/, i.e. prior to the /move/.+ -> Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player proposing to move.+ -> Component.Move.Move -- ^ The /move/. -> Bool-exposesKing logicalColour move board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour }- | source == kingsCoordinates = not . null $ findAttackersOf logicalColour (Component.Move.getDestination move) board -- CAVEAT: expensive, since all directions from the King may have to be explored.- | Just directionFromKing <- Cartesian.Vector.toMaybeDirection $ Cartesian.Vector.measureDistance kingsCoordinates source -- Confirm that one's own King is on a straight line with the start of the move.+exposesKing board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } logicalColour move+ | source == kingsCoordinates = not . null . findAttackersOf board logicalColour $! Component.Move.getDestination move -- CAVEAT: expensive, since all directions from the King may have to be explored.+ | Just directionFromKing <- Cartesian.Vector.toMaybeDirection $! Cartesian.Vector.measureDistance kingsCoordinates source -- Check whether one's own King is on a straight line with the start of the move. , let maybePieceByCoordinates = getMaybePieceByCoordinates board- , State.MaybePieceByCoordinates.isClear kingsCoordinates source maybePieceByCoordinates -- Confirm that the straight line from one's own King to the start of the move, is clear.+ , State.MaybePieceByCoordinates.isClear maybePieceByCoordinates kingsCoordinates source -- Check whether the straight line from one's own King to the start of the move, is clear. , Data.Maybe.maybe True {-Knight's move-} (- not . Attribute.Direction.areAligned directionFromKing -- The blocking piece has revealed any attacker.- ) . Cartesian.Vector.toMaybeDirection $ Component.Move.measureDistance move- , Just (_, attackersRank) <- State.MaybePieceByCoordinates.findAttackerInDirection logicalColour directionFromKing source maybePieceByCoordinates -- Confirm the existence of an obscured attacker.- = attackersRank `notElem` Attribute.Rank.plodders -- Confirm sufficient range to bridge the vacated space.- | otherwise = False+ not . Direction.Direction.areAligned directionFromKing -- The blocking piece has revealed any attacker.+ ) . Cartesian.Vector.toMaybeDirection $! Component.Move.measureDistance move+ , Just (_, attackersRank) <- State.MaybePieceByCoordinates.findAttackerInDirection maybePieceByCoordinates logicalColour source directionFromKing -- Confirm the existence of an obscured attacker.+ = attackersRank `notElem` Attribute.Rank.plodders -- Check the attacker's strike-range is sufficient to bridge the vacated space.+ | otherwise = False where source = Component.Move.getSource move- kingsCoordinates = State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour+ kingsCoordinates = State.CoordinatesByRankByLogicalColour.getKingsCoordinates coordinatesByRankByLogicalColour logicalColour -- | Count the number of defenders of each /piece/ on the /board/. countDefendersByCoordinatesByLogicalColour :: Board -> NDefendersByCoordinatesByLogicalColour-countDefendersByCoordinatesByLogicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = Attribute.LogicalColour.listArrayByLogicalColour [+countDefendersByCoordinatesByLogicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = Colour.LogicalColour.listArrayByLogicalColour [ Map.fromList [ ( coordinates,- fromIntegral . length $ findAttackersOf (+ fromIntegral . length $ findAttackersOf board ( Property.Opposable.getOpposite logicalColour -- Investigate an attack on these coordinates by one's own logical colour.- ) coordinates board+ ) coordinates ) | rank <- Attribute.Rank.expendable, -- CAVEAT: there's no point defending one's own King.- coordinates <- State.CoordinatesByRankByLogicalColour.dereference logicalColour rank coordinatesByRankByLogicalColour+ coordinates <- State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour rank ] {-list-comprehension-} | logicalColour <- Property.FixedMembership.members ] -- List-comprehension. -- | Collapses 'NDefendersByCoordinatesByLogicalColour' into the total number of defenders on either side.-summariseNDefendersByLogicalColour :: Board -> Attribute.LogicalColour.ArrayByLogicalColour Type.Count.NPieces+summariseNDefendersByLogicalColour :: Board -> Colour.LogicalColour.ArrayByLogicalColour Type.Count.NPieces summariseNDefendersByLogicalColour MkBoard { getNDefendersByCoordinatesByLogicalColour = nDefendersByCoordinatesByLogicalColour } = Data.Array.IArray.amap ( Data.Foldable.foldl' (+) 0 -- CAVEAT: 'Data.Foldable.sum' is too slow. ) nDefendersByCoordinatesByLogicalColour
src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs view
@@ -54,12 +54,12 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -93,18 +93,18 @@ * N.B.: both the outer list (indexed by logical colour) & the inner list of abscissae, are kept ordered, otherwise the derived instance of 'Eq' would be unpredictable. -}-type AbscissaeByLogicalColour = [(Attribute.LogicalColour.LogicalColour, [Type.Length.X])]+type AbscissaeByLogicalColour = [(Colour.LogicalColour.LogicalColour, [Type.Length.X])] -- | Ensure a predictable order, to facilitate '(==)'. sortByLogicalColour :: AbscissaeByLogicalColour -> AbscissaeByLogicalColour sortByLogicalColour = Data.List.sortBy $ Data.Ord.comparing fst {-logicalColour-} -- | Update to account for the specified player castling.-castle :: Attribute.LogicalColour.LogicalColour -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour+castle :: Colour.LogicalColour.LogicalColour -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour castle logicalColour = filter $ (/= logicalColour) . fst {-logicalColour-} -- N.B.: if 'Data.List.deleteBy' took a simple predicate, it would have been ideal. -- | Update to account for the specified player losing the right to castle.-relinquishCastlingRights :: Attribute.LogicalColour.LogicalColour -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour+relinquishCastlingRights :: Colour.LogicalColour.LogicalColour -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour relinquishCastlingRights logicalColour = map $ \pair@(logicalColour', _) -> ( if logicalColour' == logicalColour then Control.Arrow.second $ const []@@ -113,7 +113,7 @@ -- | Remove the right to castle, from the referenced @Rook@. removeX- :: Attribute.LogicalColour.LogicalColour+ :: Colour.LogicalColour.LogicalColour -> Type.Length.X -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour@@ -125,11 +125,11 @@ -- | Predicate. canCastleWith'- :: Attribute.LogicalColour.LogicalColour+ :: AbscissaeByLogicalColour+ -> Colour.LogicalColour.LogicalColour -> Type.Length.X -- ^ @Rook@'s abscissa.- -> AbscissaeByLogicalColour -> Bool-canCastleWith' logicalColour x = Data.Maybe.maybe False {-has castled-} (elem x) . lookup logicalColour+canCastleWith' abscissaeByLogicalColour logicalColour x = Data.Maybe.maybe False {-has castled-} (elem x) $ lookup logicalColour abscissaeByLogicalColour -- | For the players of each /logical colour/, identifies the abscissae of those @Rook@s which can still participate in castling (when other constraints are removed). newtype CastleableRooksByLogicalColour = MkCastleableRooksByLogicalColour {@@ -197,9 +197,9 @@ (.) . Property.ExtendedPositionDescription.showsEPD ) id [ pieceConstructor logicalColour |- logicalColour <- [Attribute.LogicalColour.White, Attribute.LogicalColour.Black], -- N.B.: the order is standardised.+ logicalColour <- [Colour.LogicalColour.White, Colour.LogicalColour.Black], -- N.B.: the order is standardised. (rooksX, pieceConstructor) <- [(Cartesian.Abscissa.xMax, Component.Piece.mkKing), (Cartesian.Abscissa.xMin, Component.Piece.mkQueen)], -- N.B.: the order is defined as King-side (short) before Queen-side (long), which is also alphabetical.- canCastleWith' logicalColour rooksX assocs+ canCastleWith' assocs logicalColour rooksX ] -- List-comprehension. instance Property.ForsythEdwards.ReadsFEN CastleableRooksByLogicalColour@@ -208,8 +208,8 @@ -- | Get the list of random numbers required to represent the current castling potential. instance StateProperty.Hashable.Hashable CastleableRooksByLogicalColour where- listRandoms MkCastleableRooksByLogicalColour { getAssocs = assocs } zobrist = Data.Maybe.catMaybes [- Component.Zobrist.dereferenceRandomByCastleableRooksXByLogicalColour logicalColour x zobrist |+ listRandoms zobrist MkCastleableRooksByLogicalColour { getAssocs = assocs } = Data.Maybe.catMaybes [+ Component.Zobrist.dereferenceRandomByCastleableRooksXByLogicalColour zobrist logicalColour x | logicalColour <- Property.FixedMembership.members, x <- Data.Maybe.fromMaybe [] $ lookup logicalColour assocs ] -- List-comprehension.@@ -234,8 +234,8 @@ fromBoard :: State.Board.Board -> CastleableRooksByLogicalColour fromBoard board | any (- \logicalColour -> hasCastled logicalColour castleableRooksByLogicalColour && all (- `elem` State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn coordinatesByRankByLogicalColour+ \logicalColour -> hasCastled castleableRooksByLogicalColour logicalColour && all (+ `elem` State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour Attribute.Rank.Pawn ) [ Cartesian.Coordinates.mkCoordinates x ( Cartesian.Ordinate.pawnsFirstRank logicalColour@@ -252,8 +252,8 @@ logicalColour, [ Cartesian.Coordinates.getX rooksCoordinates |- State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour == Cartesian.Coordinates.kingsStartingCoordinates logicalColour,- rooksCoordinates <- State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Rook coordinatesByRankByLogicalColour,+ uncurry (==) $ (State.CoordinatesByRankByLogicalColour.getKingsCoordinates coordinatesByRankByLogicalColour &&& Cartesian.Coordinates.kingsStartingCoordinates) logicalColour,+ rooksCoordinates <- State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour Attribute.Rank.Rook, rooksCoordinates `elem` Cartesian.Coordinates.rooksStartingCoordinates logicalColour ] -- List-comprehension. ) -- Pair.@@ -266,7 +266,7 @@ fromTurnsByLogicalColour :: TurnsByLogicalColour -> CastleableRooksByLogicalColour fromTurnsByLogicalColour turnsByLogicalColour = MkCastleableRooksByLogicalColour $ foldr ( \logicalColour -> let- turns = State.TurnsByLogicalColour.dereference logicalColour turnsByLogicalColour+ turns = State.TurnsByLogicalColour.dereference turnsByLogicalColour logicalColour in if any (Attribute.MoveType.isCastle . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove) turns then id -- Have Castled. else (:) (@@ -275,7 +275,7 @@ Cartesian.Coordinates.getX coordinates | not $ haveMovedFrom (Cartesian.Coordinates.kingsStartingCoordinates logicalColour) turns, coordinates <- Cartesian.Coordinates.rooksStartingCoordinates logicalColour,- not $ haveMovedFrom coordinates turns || haveMovedTo coordinates (State.TurnsByLogicalColour.dereference (Property.Opposable.getOpposite logicalColour) turnsByLogicalColour)+ not $ haveMovedFrom coordinates turns || haveMovedTo coordinates (State.TurnsByLogicalColour.dereference turnsByLogicalColour $ Property.Opposable.getOpposite logicalColour) ] -- List-comprehension. ) -- Pair. ) [] Property.FixedMembership.members where@@ -284,33 +284,33 @@ haveMovedTo coordinates = any $ (== coordinates) . Component.Move.getDestination . Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove -- | Predicate.-hasCastled :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Bool-hasCastled logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = all ((/= logicalColour) . fst) assocs+hasCastled :: CastleableRooksByLogicalColour -> Colour.LogicalColour.LogicalColour -> Bool+hasCastled MkCastleableRooksByLogicalColour { getAssocs = assocs } logicalColour = all ((/= logicalColour) . fst) assocs -- | Predicate.-canCastle :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Bool-canCastle logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = Data.Maybe.maybe False {-has castled-} (not . null) $ lookup logicalColour assocs+canCastle :: CastleableRooksByLogicalColour -> Colour.LogicalColour.LogicalColour -> Bool+canCastle MkCastleableRooksByLogicalColour { getAssocs = assocs } = Data.Maybe.maybe False {-has castled-} (not . null) . (`lookup` assocs) -- | Infer the @Rook@'s ordinate from the /piece/'s /logical colour/.-inferRooksOrdinate :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y+inferRooksOrdinate :: Colour.LogicalColour.LogicalColour -> Type.Length.Y inferRooksOrdinate logicalColour- | Attribute.LogicalColour.isBlack logicalColour = Cartesian.Ordinate.yMax+ | Colour.LogicalColour.isBlack logicalColour = Cartesian.Ordinate.yMax | otherwise = Cartesian.Ordinate.yMin -- | Predicate. canCastleWith- :: Attribute.LogicalColour.LogicalColour+ :: CastleableRooksByLogicalColour+ -> Colour.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -- ^ @Rook@'s coordinates.- -> CastleableRooksByLogicalColour -> Bool-canCastleWith logicalColour rookSource MkCastleableRooksByLogicalColour { getAssocs = assocs } = Data.Maybe.maybe False {-has castled-} (+canCastleWith MkCastleableRooksByLogicalColour { getAssocs = assocs } logicalColour rookSource = Data.Maybe.maybe False {-has castled-} ( any $ (== rookSource) . (`Cartesian.Coordinates.mkCoordinates` inferRooksOrdinate logicalColour) ) $ lookup logicalColour assocs -- | Find the abscissae of all @Rook@s of the specified /logical colour/, which can still participate in castling.-locateForLogicalColour :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Maybe [Type.Length.X]+locateForLogicalColour :: CastleableRooksByLogicalColour -> Colour.LogicalColour.LogicalColour -> Maybe [Type.Length.X] {-# INLINE locateForLogicalColour #-}-locateForLogicalColour logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = lookup logicalColour assocs+locateForLogicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = (`lookup` assocs) -- | Self-documentation. type Transformation = CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour@@ -329,7 +329,7 @@ -- | Update with the latest /turn/. takeTurn- :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side who took the specified turn.+ :: Colour.LogicalColour.LogicalColour -- ^ Defines the side who took the specified turn. -> Component.Turn.Turn -> Transformation takeTurn logicalColour turn MkCastleableRooksByLogicalColour { getAssocs = assocs } = MkCastleableRooksByLogicalColour $ (@@ -381,7 +381,7 @@ -> CastleableRooksByLogicalColour -> Bool cantConverge castleableRooksByLogicalColour castleableRooksByLogicalColour' = any (- \logicalColour -> case ($ castleableRooksByLogicalColour) &&& ($ castleableRooksByLogicalColour') $ locateForLogicalColour logicalColour of+ \logicalColour -> case ($ castleableRooksByLogicalColour) &&& ($ castleableRooksByLogicalColour') $ (`locateForLogicalColour` logicalColour) of (Just [], Nothing) -> True (Nothing, Just []) -> True _ -> False@@ -389,13 +389,9 @@ -- | Generate the additional random-numbers required to correct the hash resulting from a change to the castleable @Rook@s. listIncrementalRandoms- :: CastleableRooksByLogicalColour -- ^ The old value.+ :: Component.Zobrist.Zobrist random+ -> CastleableRooksByLogicalColour -- ^ The old value. -> CastleableRooksByLogicalColour -- ^ The new value.- -> Component.Zobrist.Zobrist random -> [random]-listIncrementalRandoms castleableRooksByLogicalColour castleableRooksByLogicalColour' zobrist = [- random |- hashable <- [castleableRooksByLogicalColour, castleableRooksByLogicalColour'],- random <- StateProperty.Hashable.listRandoms hashable zobrist- ] -- List-comprehension.+listIncrementalRandoms zobrist castleableRooksByLogicalColour castleableRooksByLogicalColour' = StateProperty.Hashable.listRandoms zobrist [castleableRooksByLogicalColour, castleableRooksByLogicalColour']
src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs view
@@ -30,6 +30,7 @@ -- * Types -- ** Type-synonyms -- CoordinatesByRank,+ BareCoordinatesByRankByLogicalColour, CoordinatesByLogicalColour, -- Transformation, -- ** Data-types@@ -38,6 +39,7 @@ deconstruct ), -- * Functions+-- advanceDirection, findPassedPawnCoordinatesByLogicalColour, findPiecesOfColour, assocs,@@ -45,22 +47,20 @@ -- ** Accessors getKingsCoordinates, dereference,--- ** Constructor- fromMaybePieceByCoordinates, -- ** Mutators--- deleteCoordinates,- movePiece,+-- deleteCoordinatesFromRank,+-- mapCoordinates,+-- purgeCoordinates, sortCoordinates ) where import Control.Arrow((&&&), (|||)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Accountant as Component.Accountant import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece@@ -69,36 +69,41 @@ import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable+import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.StateProperty.View as StateProperty.View import qualified Control.Arrow import qualified Control.DeepSeq-import qualified Control.Exception import qualified Data.Array.IArray import qualified Data.Foldable import qualified Data.List+import qualified Data.List.Extra import qualified Data.Map.Strict as Map import qualified Data.Maybe -- | The /coordinate/s of all the pieces of one /rank/. type CoordinatesByRank = Attribute.Rank.ArrayByRank [Cartesian.Coordinates.Coordinates] +-- | The /coordinate/s of all the pieces of one /rank/, for both logical colours.+type BareCoordinatesByRankByLogicalColour = Colour.LogicalColour.ArrayByLogicalColour CoordinatesByRank+ {- | * This structure allows one to determine the set of /coordinates/ where a type of /piece/ is located. * CAVEAT: the list of /coordinates/ is unordered, so test for equality using @ deconstruct . sortCoordinates @. -} newtype CoordinatesByRankByLogicalColour = MkCoordinatesByRankByLogicalColour {- deconstruct :: Attribute.LogicalColour.ArrayByLogicalColour CoordinatesByRank+ deconstruct :: BareCoordinatesByRankByLogicalColour } instance Control.DeepSeq.NFData CoordinatesByRankByLogicalColour where rnf MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Control.DeepSeq.rnf byLogicalColour instance StateProperty.Censor.Censor CoordinatesByRankByLogicalColour where- countPiecesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = ($ Attribute.LogicalColour.Black) &&& ($ Attribute.LogicalColour.White) $ Data.List.foldl' (\acc -> (+ acc) . fromIntegral . length) 0 . (byLogicalColour !)+ countPiecesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = ($ Colour.LogicalColour.Black) &&& ($ Colour.LogicalColour.White) $ Data.List.foldl' (\acc -> (+ acc) . fromIntegral . length) 0 . (byLogicalColour !) countPieces MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.foldl' ( Data.List.foldl' $ \acc -> (+ acc) . fromIntegral . length@@ -107,7 +112,7 @@ countPieceDifferenceByRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Attribute.Rank.listArrayByRank . uncurry ( zipWith (-) ) . (- ($ Attribute.LogicalColour.White) &&& ($ Attribute.LogicalColour.Black)+ ($ Colour.LogicalColour.White) &&& ($ Colour.LogicalColour.Black) ) $ map (fromIntegral . length) . Data.Foldable.toList . (byLogicalColour !) hasInsufficientMaterial MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.all (@@ -127,23 +132,67 @@ bishops = blackBishops ++ whiteBishops - hasBothKings MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = not $ Data.Foldable.any (null . (! Attribute.Rank.King)) byLogicalColour -- CAVEAT: true for more than one King per side also.+ hasBothKings MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.all ((== 1) . length . (! Attribute.Rank.King)) byLogicalColour -- CAVEAT: false for more than one King per side also. instance StateProperty.Hashable.Hashable CoordinatesByRankByLogicalColour where- listRandoms MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } zobrist = [- Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (logicalColour, rank, coordinates) zobrist |+ listRandoms zobrist MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = [+ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist (logicalColour, rank, coordinates) | (logicalColour, byRank) <- Data.Array.IArray.assocs byLogicalColour, (rank, coordinatesList) <- Data.Array.IArray.assocs byRank, coordinates <- coordinatesList ] -- List-comprehension. +instance StateProperty.Mutator.Mutator CoordinatesByRankByLogicalColour where+ defineCoordinates maybePiece coordinates = MkCoordinatesByRankByLogicalColour . (+ \byLogicalColour -> Data.Maybe.maybe byLogicalColour (+ \piece -> let+ logicalColour = Component.Piece.getLogicalColour piece+ byRank = byLogicalColour ! logicalColour+ in byLogicalColour // [+ (+ logicalColour,+ byRank // [+ id &&& (coordinates :) . (byRank !) $ Component.Piece.getRank piece -- Prepend.+ ] -- Singleton.+ ) -- Pair.+ ] -- Singleton.+ ) maybePiece+ ) . deconstruct . purgeCoordinates coordinates++ movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkCoordinatesByRankByLogicalColour {+ deconstruct = byLogicalColour+ } = MkCoordinatesByRankByLogicalColour $ byLogicalColour // (+ (:) . (`deleteOpponentsCoordinates` Attribute.Rank.Pawn) ||| Data.Maybe.maybe id {-quiet move-} (+ (:) . deleteOpponentsCoordinates destination+ ) $ eitherPassingPawnsDestinationOrMaybeTakenRank+ ) [+ let+ byRank = byLogicalColour ! logicalColour+ in (+ logicalColour,+ byRank // Data.Maybe.maybe (+ return {-to List-monad-} . Control.Arrow.second (destination :) -- Add the destination to the mover.+ ) (+ \promotionRank -> (:) (+ promotionRank,+ destination : byRank ! promotionRank -- Add the destination to the mover's promoted rank.+ ) . return {-to List-monad-}+ ) maybePromotionRank (+ id &&& Data.List.delete (Component.Move.getSource move) . (byRank !) $ Component.Piece.getRank sourcePiece+ )+ ) -- Pair.+ ] where+ destination = Component.Move.getDestination move+ logicalColour = Component.Piece.getLogicalColour sourcePiece+ deleteOpponentsCoordinates coordinates rank = id &&& deleteCoordinatesFromRank coordinates rank . (byLogicalColour !) $ Property.Opposable.getOpposite logicalColour+ {- | * Find any @Knight@s of the specified /logical colour/, in attack-range around the specified /coordinates/. * CAVEAT: nothing is said about whether any /piece/ at the specified /coordinates/ belongs to the opponent, as one might expect. -} instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour {-CAVEAT: MultiParamTypeClasses-} where- findProximateKnights logicalColour destination MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = filter (+ findProximateKnights MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } logicalColour destination = filter ( \source -> source /= destination {-guard against attempting to constructing a null vector-} && Cartesian.Vector.isKnightsMove ( Cartesian.Vector.measureDistance source destination )@@ -164,36 +213,46 @@ ) Property.Empty.empty . (! Attribute.Rank.Pawn) ) byLogicalColour +instance StateProperty.View.View CoordinatesByRankByLogicalColour where+ fromAssocs = MkCoordinatesByRankByLogicalColour . Data.Array.IArray.accumArray (+ flip const -- Replace the default.+ ) (+ Attribute.Rank.listArrayByRank $ repeat [] -- Default.+ ) (minBound, maxBound) . map (+ Control.Arrow.second $ Data.Array.IArray.accumArray (++) [] {-default-} (minBound, maxBound) . Data.List.Extra.groupSort {-by Rank-} -- Construct the ArrayByRank.+ ) . Data.List.Extra.groupSort {-by LogicalColour-} . map (+ \(coordinates, piece) -> (Component.Piece.getLogicalColour piece, (Component.Piece.getRank piece, coordinates)) -- Reorder the components.+ )+ instance Component.Accountant.Accountant CoordinatesByRankByLogicalColour where- sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = map (+ sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } nPieces = map ( \(logicalColour, byRank) -> Data.List.foldl' ( \acc (rank, coordinatesList) -> Data.List.foldl' (- \acc' -> (+ acc') . Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank nPieces logicalColour rank+ \acc' -> (+ acc') . realToFrac . Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank nPieces logicalColour rank ) acc coordinatesList ) 0 $ Data.Array.IArray.assocs byRank ) $ Data.Array.IArray.assocs byLogicalColour --- | Constructor.-fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates -> CoordinatesByRankByLogicalColour-fromMaybePieceByCoordinates maybePieceByCoordinates = MkCoordinatesByRankByLogicalColour . (- \(b, w) -> Attribute.LogicalColour.listArrayByLogicalColour $ map (- Data.Array.IArray.accumArray (++) [] (minBound, maxBound) . map (Control.Arrow.first Component.Piece.getRank)- ) [b, w]- ) $ Data.List.partition (- Component.Piece.isBlack . fst {-piece-}- ) [- (piece, [coordinates]) |- (coordinates, piece) <- StateProperty.Seeker.findAllPieces maybePieceByCoordinates- ] -- List-comprehension.+instance Property.SelfValidating.SelfValidating CoordinatesByRankByLogicalColour where+ findInvalidity selfValidator = concatMap ($ selfValidator) [+ StateProperty.Censor.findInvalidity,+ StateProperty.Seeker.findInvalidity,+ Property.SelfValidating.findErrors [+ (+ not . all ((== 1) . length) . Data.List.group . Data.List.sort . listCoordinates,+ "there can't be any duplicate coordinates regardless of logical colour or ranks."+ )+ ]+ ] -- | Dereference the array. dereference- :: Attribute.LogicalColour.LogicalColour+ :: CoordinatesByRankByLogicalColour+ -> Colour.LogicalColour.LogicalColour -> Attribute.Rank.Rank- -> CoordinatesByRankByLogicalColour -> [Cartesian.Coordinates.Coordinates] {-# INLINE dereference #-}-dereference logicalColour rank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = byLogicalColour ! logicalColour ! rank+dereference MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } logicalColour rank = byLogicalColour ! logicalColour ! rank -- | Build an association-list. assocs :: CoordinatesByRankByLogicalColour -> [(Component.Piece.Piece, [Cartesian.Coordinates.Coordinates])]@@ -214,35 +273,40 @@ -- | Get the /coordinates/ of the @King@ of the specified /logical colour/. getKingsCoordinates- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ to find.- -> CoordinatesByRankByLogicalColour+ :: CoordinatesByRankByLogicalColour+ -> Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ to find. -> Cartesian.Coordinates.Coordinates {-# INLINE getKingsCoordinates #-}-getKingsCoordinates logicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Control.Exception.assert (not $ null coordinates) $ head coordinates {-there should be exactly one-} where- coordinates = byLogicalColour ! logicalColour ! Attribute.Rank.King+getKingsCoordinates MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } logicalColour = coordinates where+ [coordinates] = byLogicalColour ! logicalColour ! Attribute.Rank.King -- CAVEAT: there should be exactly one. -- | Locate all /piece/s of the specified /logical colour/. findPiecesOfColour- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/s to find.- -> CoordinatesByRankByLogicalColour+ :: CoordinatesByRankByLogicalColour+ -> Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/s to find. -> [Component.Piece.LocatedPiece]-findPiecesOfColour logicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = [+findPiecesOfColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } logicalColour = [ (coordinates, Component.Piece.mkPiece logicalColour rank) | (rank, coordinatesList) <- Data.Array.IArray.assocs $ byLogicalColour ! logicalColour, coordinates <- coordinatesList ] -- List-comprehension. +-- | The /y/-direction in which a @Pawn@ of the specified /logical colour/ advances.+advanceDirection :: Colour.LogicalColour.LogicalColour -> Ordering+advanceDirection Colour.LogicalColour.Black = LT -- Black moves down.+advanceDirection _ = GT+ -- | A list of /coordinates/ for each /logical colour/.-type CoordinatesByLogicalColour = Attribute.LogicalColour.ArrayByLogicalColour [Cartesian.Coordinates.Coordinates]+type CoordinatesByLogicalColour = Colour.LogicalColour.ArrayByLogicalColour [Cartesian.Coordinates.Coordinates] -- | For each /logical colour/, find the /coordinates/ of any passed @Pawn@s (<https://en.wikipedia.org/wiki/Passed_pawn>). findPassedPawnCoordinatesByLogicalColour :: CoordinatesByRankByLogicalColour -> CoordinatesByLogicalColour-findPassedPawnCoordinatesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Attribute.LogicalColour.listArrayByLogicalColour $ map (+findPassedPawnCoordinatesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Colour.LogicalColour.listArrayByLogicalColour $ map ( \logicalColour -> let opponentsLogicalColour = Property.Opposable.getOpposite logicalColour opposingPawnYByX = Data.List.foldl' ( \m coordinates -> uncurry (- Map.insertWith $ if Attribute.LogicalColour.isBlack opponentsLogicalColour+ Map.insertWith $ if Colour.LogicalColour.isBlack opponentsLogicalColour then max else min ) {-only compare with the least advanced opposing Pawn in each file-} (@@ -253,7 +317,7 @@ \coordinates -> all ( Data.Maybe.maybe True {-absence of opposition doesn't impede advance-} ( (- /= Attribute.Direction.advanceDirection logicalColour -- Either equal or backwards is OK.+ /= advanceDirection logicalColour -- Either equal or backwards is OK. ) . ( {-opponent-} `compare` Cartesian.Coordinates.getY coordinates ) -- As a Pawn advances, it becomes "Passed" when the y-distance to the least advanced adjacent opposing Pawn, is either equal or backwards.@@ -265,50 +329,26 @@ ) Property.FixedMembership.members where findPawns = (! Attribute.Rank.Pawn) . (byLogicalColour !) --- | Self-documentation.-type Transformation = CoordinatesByRankByLogicalColour -> CoordinatesByRankByLogicalColour- -- | Remove the specified /coordinates/ from those recorded for the specified /rank/.-deleteCoordinates+deleteCoordinatesFromRank :: Cartesian.Coordinates.Coordinates -> Attribute.Rank.Rank -> CoordinatesByRank -> CoordinatesByRank-deleteCoordinates coordinates rank byRank = byRank // [(rank, Data.List.delete coordinates $ byRank ! rank)]+deleteCoordinatesFromRank coordinates rank byRank = byRank // [id &&& Data.List.delete coordinates . (byRank !) $ rank] --- | Adjust the array to reflect a new /move/.-movePiece- :: Component.Move.Move- -> Component.Piece.Piece -- ^ The piece which moved.- -> Maybe Attribute.Rank.Rank -- ^ The (possibly promoted) rank to place at the destination.- -> Either Cartesian.Coordinates.Coordinates (Maybe Attribute.Rank.Rank) -- ^ Either the destination of any passed @Pawn@, or the /rank/ of any /piece/ taken.- -> Transformation-movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ byLogicalColour // (- (:) . (`deleteOpponentsCoordinates` Attribute.Rank.Pawn) ||| Data.Maybe.maybe id {-quiet move-} (- (:) . deleteOpponentsCoordinates destination- ) $ eitherPassingPawnsDestinationOrMaybeTakenRank- ) [- let- byRank = byLogicalColour ! logicalColour- in (- logicalColour,- byRank // Data.Maybe.maybe (- return {-to List-monad-} . Control.Arrow.second (destination :) -- Add the destination to the mover.- ) (- \promotionRank -> (:) (- promotionRank,- destination : byRank ! promotionRank -- Add the destination to the mover's promoted rank.- ) . return {-to List-monad-}- ) maybePromotionRank (- id &&& Data.List.delete (Component.Move.getSource move) . (byRank !) $ Component.Piece.getRank sourcePiece- )- ) -- Pair.- ] where- destination = Component.Move.getDestination move- logicalColour = Component.Piece.getLogicalColour sourcePiece- deleteOpponentsCoordinates coordinates rank = id &&& deleteCoordinates coordinates rank . (byLogicalColour !) $ Property.Opposable.getOpposite logicalColour+-- | Self-documentation.+type Transformation = CoordinatesByRankByLogicalColour -> CoordinatesByRankByLogicalColour +-- | Map the coordinate-lists.+mapCoordinates :: ([Cartesian.Coordinates.Coordinates] -> [Cartesian.Coordinates.Coordinates]) -> Transformation+mapCoordinates f MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ Data.Array.IArray.amap (Data.Array.IArray.amap f) byLogicalColour++-- | Purge the specified /coordinates/ regardless of the /rank/ or /logical colour/ of any incumbent piece.+purgeCoordinates :: Cartesian.Coordinates.Coordinates -> Transformation+purgeCoordinates coordinates = mapCoordinates $ Data.List.delete coordinates+ -- | Independently sort each list of /coordinates/. sortCoordinates :: Transformation-sortCoordinates MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ Data.Array.IArray.amap (Data.Array.IArray.amap Data.List.sort) byLogicalColour+sortCoordinates = mapCoordinates Data.List.sort
src-lib/BishBosh/State/EnPassantAbscissa.hs view
@@ -31,9 +31,9 @@ mkMaybeEnPassantAbscissa ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -56,28 +56,31 @@ rnf MkEnPassantAbscissa { getAbscissa = x } = Control.DeepSeq.rnf x instance StateProperty.Hashable.Hashable EnPassantAbscissa where- listRandoms MkEnPassantAbscissa { getAbscissa = x } = return {-to List-monad-} . Component.Zobrist.dereferenceRandomByEnPassantAbscissa x+ listRandoms zobrist MkEnPassantAbscissa { getAbscissa = x } = return {-to List-monad-} $! Component.Zobrist.dereferenceRandomByEnPassantAbscissa zobrist x -- | Constructor. mkMaybeEnPassantAbscissa- :: Attribute.LogicalColour.LogicalColour -- ^ The player who moves next, & who may have an En-passant capture-option.+ :: Colour.LogicalColour.LogicalColour -- ^ The player who moves next, & who may have an En-passant capture-option. -> State.MaybePieceByCoordinates.MaybePieceByCoordinates- -> Component.Turn.Turn -- ^ The last /turn/ taken.+ -> Component.Turn.Turn -- ^ The last /turn/ taken. -> Maybe EnPassantAbscissa mkMaybeEnPassantAbscissa nextLogicalColour maybePieceByCoordinates lastTurn- | Component.Turn.isPawnDoubleAdvance (Property.Opposable.getOpposite nextLogicalColour) lastTurn- , let lastMoveDestination = Component.Move.getDestination . Component.QualifiedMove.getMove $ Component.Turn.getQualifiedMove lastTurn+ | Component.Turn.isPawnDoubleAdvance lastTurn $! Property.Opposable.getOpposite nextLogicalColour+ , let lastMoveDestination = Component.Move.getDestination . Component.QualifiedMove.getMove $! Component.Turn.getQualifiedMove lastTurn , not $ null [- passedPawn |- adjacentCoordinates <- Cartesian.Coordinates.getAdjacents lastMoveDestination,- Component.Piece.mkKing nextLogicalColour {- Will I expose my King ? -} `notElem` [- blockingPiece |- threatDirection <- Property.FixedMembership.members, -- Consider all directions.- (_, attackerRank) <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.findAttackerInDirection nextLogicalColour threatDirection adjacentCoordinates maybePieceByCoordinates, -- Find discovered attacks.- attackerRank `notElem` Attribute.Rank.fixedAttackRange, -- Any viable attack through the vacated square must be long-range.- (_, blockingPiece) <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.findBlockingPiece (Property.Opposable.getOpposite threatDirection) adjacentCoordinates maybePieceByCoordinates -- Find any discovered attack.- ], -- Confirm that the En-passant capture doesn't expose my King.- passedPawn <- filter (== Component.Piece.mkPawn nextLogicalColour) . Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.dereference adjacentCoordinates maybePieceByCoordinates- ] = Just . MkEnPassantAbscissa $ Cartesian.Coordinates.getX lastMoveDestination- | otherwise = Nothing+ adjacentPawnCoordinates |+ adjacentPawnCoordinates <- filter (+ (== Just (Component.Piece.mkPawn nextLogicalColour)) . State.MaybePieceByCoordinates.dereference maybePieceByCoordinates -- Confirm the existence of an enemy Pawn.+ ) $ Cartesian.Coordinates.getAdjacents lastMoveDestination, -- Find locations from which a Pawn may mount an attack en-passant.+ all (+ \(direction, rank) -> rank `elem` Attribute.Rank.plodders || (+ /= Just (Component.Piece.mkKing nextLogicalColour) -- Confirm that my King doesn't become checked.+ ) (+ fmap snd {-piece-} . State.MaybePieceByCoordinates.findBlockingPiece maybePieceByCoordinates adjacentPawnCoordinates $ Property.Opposable.getOpposite direction -- Check whether there's a piece in the opposite direction through the vacated square.+ )+ ) $ Data.Maybe.mapMaybe (+ \direction -> (,) direction . snd {-rank-} <$> State.MaybePieceByCoordinates.findAttackerInDirection maybePieceByCoordinates nextLogicalColour adjacentPawnCoordinates direction -- Identify attacks passing through the square vacated by the attacking Pawn; the square occupied by the double advanced Pawn, wasn't an issue before it advanced, so it isn't if taken.+ ) Property.FixedMembership.members -- Consider all directions.+ ] {-list-comprehension-} = Just . MkEnPassantAbscissa $ Cartesian.Coordinates.getX lastMoveDestination+ | otherwise = Nothing
src-lib/BishBosh/State/MaybePieceByCoordinates.hs view
@@ -31,14 +31,14 @@ module BishBosh.State.MaybePieceByCoordinates( -- * Types--- ** Type-synonyms--- Transformation, -- ** Data-types MaybePieceByCoordinates(), -- * Functions inferMoveType, findBlockingPiece,+ findBlockingPieces, findAttackerInDirection,+ findAttackerInDirections, listDestinationsFor, -- listToRaster, -- shows2D,@@ -46,8 +46,6 @@ -- ** Accessors dereference, -- getPieces,--- ** Mutators- movePiece, -- ** Predicates isVacant, isOccupied,@@ -57,20 +55,19 @@ ) where import Control.Applicative((<|>))-import Control.Arrow((&&&), (***))+import Control.Arrow((&&&), (***), (|||)) import Control.Category((>>>)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.ANSIColourCode as Attribute.ANSIColourCode-import qualified BishBosh.Attribute.ColourScheme as Attribute.ColourScheme-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Attribute.LogicalColourOfSquare as Attribute.LogicalColourOfSquare import qualified BishBosh.Attribute.MoveType as Attribute.MoveType-import qualified BishBosh.Attribute.PhysicalColour as Attribute.PhysicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Colour.ANSIColourCode as Colour.ANSIColourCode+import qualified BishBosh.Colour.ColourScheme as Colour.ColourScheme+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Colour.LogicalColourOfSquare as Colour.LogicalColourOfSquare+import qualified BishBosh.Colour.PhysicalColour as Colour.PhysicalColour import qualified BishBosh.Component.Accountant as Component.Accountant import qualified BishBosh.Component.CastlingMove as Component.CastlingMove import qualified BishBosh.Component.Move as Component.Move@@ -78,6 +75,7 @@ import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Direction.Direction as Direction.Direction import qualified BishBosh.Notation.Figurine as Notation.Figurine import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription@@ -86,10 +84,12 @@ import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.Orientated as Property.Orientated import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.StateProperty.View as StateProperty.View import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow@@ -110,13 +110,14 @@ * N.B.: this could be implemented using 'Data.Vector.Vector', which being indexed by 'Int' is no longer polymorphic & permits many unsafe operations; but the result is no faster. -} newtype MaybePieceByCoordinates = MkMaybePieceByCoordinates {- deconstruct :: Cartesian.Coordinates.ArrayByCoordinates (- Maybe Component.Piece.Piece -- Each square optionally contains a piece.- )+ deconstruct :: Cartesian.Coordinates.ArrayByCoordinates (Maybe Component.Piece.Piece) -- ^ Each square optionally contains a piece. } deriving (Eq, Ord) --- | Used to separate the /ranks/ of the /board/ as represented by the IO-format <https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation>.--- | Chops a list into a 2-D list.+{- |+ * Used to separate the /ranks/ of the /board/ as represented by the IO-format <https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation>.++ * Chops a list into a 2-D list.+-} listToRaster :: [a] -> [[a]] listToRaster = Data.List.Extra.chunksOf $ fromIntegral Cartesian.Abscissa.xLength {-CAVEAT: this also depends on the raster-order-} @@ -167,17 +168,17 @@ instance Property.ForsythEdwards.ShowsFEN MaybePieceByCoordinates instance Data.Default.Default MaybePieceByCoordinates where- def = Property.ForsythEdwards.readFEN . Data.List.intercalate [Property.ExtendedPositionDescription.rankSeparator] $ map ($ Attribute.LogicalColour.Black) [+ def = Property.ForsythEdwards.readFEN . Data.List.intercalate [Property.ExtendedPositionDescription.rankSeparator] $ map ($ Colour.LogicalColour.Black) [ showNobility, showPawnRow- ] ++ replicate 4 "8" ++ map ($ Attribute.LogicalColour.White) [+ ] ++ replicate 4 "8" ++ map ($ Colour.LogicalColour.White) [ showPawnRow, showNobility ] where showPieces :: [Component.Piece.Piece] -> String showPieces = concatMap Property.ForsythEdwards.showFEN - showPawnRow, showNobility :: Attribute.LogicalColour.LogicalColour -> String+ showPawnRow, showNobility :: Colour.LogicalColour.LogicalColour -> String showPawnRow logicalColour = showPieces . replicate (fromIntegral Cartesian.Abscissa.xLength) $ Component.Piece.mkPawn logicalColour showNobility logicalColour = showPieces $ map (Component.Piece.mkPiece logicalColour) Attribute.Rank.nobility @@ -197,13 +198,9 @@ instance StateProperty.Censor.Censor MaybePieceByCoordinates where countPiecesByLogicalColour = Data.List.foldl' (- \acc piece -> let- acc'@(nBlack, nWhite) = (- if Component.Piece.isBlack piece- then Control.Arrow.first- else Control.Arrow.second- ) succ acc- in nBlack `seq` nWhite `seq` acc'+ \(nBlack, nWhite) piece -> if Component.Piece.isBlack piece+ then let nBlack' = succ nBlack in nBlack' `seq` (nBlack', nWhite)+ else let nWhite' = succ nWhite in nWhite' `seq` (nBlack, nWhite') ) (0, 0) . getPieces countPieces = fromIntegral . length . getPieces@@ -244,16 +241,32 @@ _ -> False instance StateProperty.Hashable.Hashable MaybePieceByCoordinates where- listRandoms MkMaybePieceByCoordinates { deconstruct = byCoordinates } zobrist = [- Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (Component.Piece.getLogicalColour piece, Component.Piece.getRank piece, coordinates) zobrist |+ listRandoms zobrist MkMaybePieceByCoordinates { deconstruct = byCoordinates } = [+ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour zobrist $ uncurry (,,) (Component.Piece.getLogicalColour &&& Component.Piece.getRank $ piece) coordinates | (coordinates, Just piece) <- Data.Array.IArray.assocs byCoordinates ] -- List-comprehension. instance StateProperty.Mutator.Mutator MaybePieceByCoordinates where- defineCoordinates maybePiece coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Control.Exception.assert (+ defineCoordinates maybePiece coordinates MkMaybePieceByCoordinates {+ deconstruct = byCoordinates+ } = Control.Exception.assert ( Data.Maybe.isJust maybePiece || Data.Maybe.isJust (byCoordinates ! coordinates) ) . MkMaybePieceByCoordinates $ byCoordinates // [(coordinates, maybePiece)] + movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkMaybePieceByCoordinates {+ deconstruct = byCoordinates+ } = MkMaybePieceByCoordinates $ byCoordinates // (+ (:) . flip (,) Nothing {-take en-passant-} ||| const id $ eitherPassingPawnsDestinationOrMaybeTakenRank+ ) [+ (+ Component.Move.getSource move,+ Nothing -- Remove the piece from the source.+ ), (+ Component.Move.getDestination move,+ Just $ Data.Maybe.maybe id Component.Piece.promote maybePromotionRank sourcePiece -- Place the piece at the destination, removing any opposing incumbent as a side-effect.+ )+ ]+ {- | * Find any @Knight@s of the specified /logical colour/, in attack-range around the specified /coordinates/. @@ -262,9 +275,9 @@ * CAVEAT: less efficient than 'State.CoordinatesByRankByLogicalColour.findProximateKnights'. -} instance StateProperty.Seeker.Seeker MaybePieceByCoordinates where- findProximateKnights logicalColour destination MkMaybePieceByCoordinates { deconstruct = byCoordinates } = filter (+ findProximateKnights MkMaybePieceByCoordinates { deconstruct = byCoordinates } logicalColour destination = filter ( (== Just knight) . (byCoordinates !)- ) $ Component.Piece.findAttackDestinations destination knight where+ ) $ Component.Piece.findAttackDestinations knight destination where knight = Component.Piece.mkKnight logicalColour findPieces predicate MkMaybePieceByCoordinates { deconstruct = byCoordinates } = [@@ -273,41 +286,44 @@ predicate piece ] -- List-comprehension. +instance StateProperty.View.View MaybePieceByCoordinates where+ fromAssocs = MkMaybePieceByCoordinates . Data.Array.IArray.accumArray (flip const) Nothing {-default-} (minBound, maxBound) . map (Control.Arrow.second Just)+ instance Component.Accountant.Accountant MaybePieceByCoordinates where- sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces = (+ sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank maybePieceByCoordinates nPieces = ( \(b, w) -> [b, w] ) . Data.List.foldl' ( \(b, w) (coordinates, piece) -> let logicalColour = Component.Piece.getLogicalColour piece- pieceSquareValue = Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank nPieces logicalColour (Component.Piece.getRank piece) coordinates- in if Attribute.LogicalColour.isBlack logicalColour+ pieceSquareValue = realToFrac $! Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank nPieces logicalColour (Component.Piece.getRank piece) coordinates+ in if Colour.LogicalColour.isBlack logicalColour then let b' = b + pieceSquareValue in b' `seq` (b', w) else let w' = w + pieceSquareValue in w' `seq` (b, w')- ) (0, 0) . StateProperty.Seeker.findAllPieces+ ) (0, 0) $ StateProperty.Seeker.findAllPieces maybePieceByCoordinates +instance Property.SelfValidating.SelfValidating MaybePieceByCoordinates where+ findInvalidity = uncurry (++) . (StateProperty.Censor.findInvalidity &&& StateProperty.Seeker.findInvalidity)+ -- | Dereference the array.-dereference- :: Cartesian.Coordinates.Coordinates- -> MaybePieceByCoordinates- -> Maybe Component.Piece.Piece+dereference :: MaybePieceByCoordinates -> Cartesian.Coordinates.Coordinates -> Maybe Component.Piece.Piece {-# INLINE dereference #-}-dereference coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = byCoordinates ! coordinates+dereference MkMaybePieceByCoordinates { deconstruct = byCoordinates } = (byCoordinates !) -- | Infer the type of the specified /move/. inferMoveType- :: Component.Move.Move+ :: MaybePieceByCoordinates+ -> Component.Move.Move -> Maybe Attribute.Rank.Rank -- ^ The /rank/ to which a @Pawn@ should be promoted; defaulting to @Queen@.- -> MaybePieceByCoordinates -> Attribute.MoveType.MoveType-inferMoveType move maybePromotionRank maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates }+inferMoveType maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } move maybePromotionRank | Just sourcePiece <- byCoordinates ! Component.Move.getSource move = Data.Maybe.maybe (- if isEnPassantMove move maybePieceByCoordinates+ if isEnPassantMove maybePieceByCoordinates move then Attribute.MoveType.enPassant -- N.B.: if this move is valid, then one's opponent must have just double advanced an adjacent Pawn. else let destination = Component.Move.getDestination move in Attribute.MoveType.mkNormalMoveType (- fmap Component.Piece.getRank $ byCoordinates ! destination -- Record the rank of any piece which was taken; the logical colour is inferred to be the opposite of 'sourcePiece'.- ) $ if Component.Piece.isPawnPromotion destination sourcePiece+ Component.Piece.getRank <$> byCoordinates ! destination -- Record the rank of any piece which was taken; the logical colour is inferred to be the opposite of 'sourcePiece'.+ ) $ if Component.Piece.isPawnPromotion sourcePiece destination then maybePromotionRank <|> Just Attribute.Rank.defaultPromotionRank else Nothing ) Component.CastlingMove.getMoveType $ if Component.Piece.isKing sourcePiece@@ -331,17 +347,18 @@ * CAVEAT: doesn't typically check whether anything (let alone the specified /piece/) exists at the specified source-/coordinates/. -} listDestinationsFor- :: Cartesian.Coordinates.Coordinates -- ^ The source for which destinations are required.+ :: MaybePieceByCoordinates+ -> Cartesian.Coordinates.Coordinates -- ^ The source for which destinations are required. -> Component.Piece.Piece -- ^ The /piece/ at the specified source.- -> MaybePieceByCoordinates -> [(Cartesian.Coordinates.Coordinates, Maybe Attribute.Rank.Rank)] -- ^ The destination & the rank of any piece taken.-listDestinationsFor source piece maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Control.Exception.assert (+listDestinationsFor maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } source piece = Control.Exception.assert ( byCoordinates ! source == Just piece ) $ if Component.Piece.getRank piece `elem` Attribute.Rank.fixedAttackRange then {-P,N,K-} let+ findAttackDestinations :: (Maybe Component.Piece.Piece -> Bool) -> [(Cartesian.Coordinates.Coordinates, Maybe Attribute.Rank.Rank)] findAttackDestinations predicate = [- (destination, fmap Component.Piece.getRank maybeDestinationPiece) |- destination <- Component.Piece.findAttackDestinations source piece,+ (destination, Component.Piece.getRank <$> maybeDestinationPiece) |+ destination <- Component.Piece.findAttackDestinations piece source, let maybeDestinationPiece = byCoordinates ! destination, predicate maybeDestinationPiece ] -- List-comprehension.@@ -353,57 +370,56 @@ advance = Cartesian.Coordinates.advance logicalColour advancedLocation = advance source- in if isVacant advancedLocation maybePieceByCoordinates+ in if isVacant maybePieceByCoordinates advancedLocation then map ( flip (,) Nothing -- N.B.: a Pawn can only take diagonally. ) $ advancedLocation : [ doubleAdvancedLocation |- Cartesian.Coordinates.isPawnsFirstRank logicalColour source,+ Cartesian.Coordinates.isPawnsFirstRank source logicalColour, let doubleAdvancedLocation = advance advancedLocation,- isVacant doubleAdvancedLocation maybePieceByCoordinates+ isVacant maybePieceByCoordinates doubleAdvancedLocation ] -- List-comprehension. else [] -- The path immediately ahead is blocked. else {-N,K-} findAttackDestinations . Data.Maybe.maybe True {-unoccupied-} $ (/= logicalColour) . Component.Piece.getLogicalColour else {-R,B,Q-} let+ takeUntil :: [Cartesian.Coordinates.Coordinates] -> [(Cartesian.Coordinates.Coordinates, Maybe Attribute.Rank.Rank)] takeUntil (destination : remainder)- | Just blockingPiece <- byCoordinates ! destination = [+ | Just blockingPiece <- byCoordinates ! destination = [ ( destination, Just $ Component.Piece.getRank blockingPiece ) | Component.Piece.getLogicalColour blockingPiece /= logicalColour ] -- List-comprehension.- | otherwise = (destination, Nothing) : takeUntil remainder -- Recurse.- takeUntil _ = []- in [- pairs |- direction <- Component.Piece.getAttackDirections piece,- pairs <- takeUntil $ Cartesian.Coordinates.extrapolate direction source- ] -- List-comprehension.+ | otherwise = (destination, Nothing) : takeUntil remainder -- Recurse.+ takeUntil _ = []+ in Cartesian.Coordinates.applyAlongDirectionsFrom takeUntil source $ if Component.Piece.isQueen piece+ then Nothing -- i.e. all directions.+ else Just $ Component.Piece.getAttackDirections piece where logicalColour = Component.Piece.getLogicalColour piece -- | Show the /board/ in two dimensions, with /x/ & /y/ indexes. shows2D- :: Type.Length.Column -- ^ The column-magnification.- -> Attribute.ColourScheme.ColourScheme+ :: MaybePieceByCoordinates+ -> Type.Length.Column -- ^ The column-magnification.+ -> Colour.ColourScheme.ColourScheme -> Bool -- ^ Whether to depict pieces as Unicode figurines. -> (Type.Length.X, Type.Length.Y) -- ^ The origin from which axes are labelled.- -> MaybePieceByCoordinates- -> ShowS -- ^ Output suitable for display on a terminal.-shows2D boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) MkMaybePieceByCoordinates { deconstruct = byCoordinates } = (+ -> ShowS -- ^ Output suitable for display on a terminal.+shows2D MkMaybePieceByCoordinates { deconstruct = byCoordinates } boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) = ( foldr ( \(y, pairs) showsRow -> showsRow . showString axisGraphicsRendition . showChar y . foldr ( \(coordinates, c) acc' -> showString (- Attribute.ANSIColourCode.selectGraphicsRendition False {-isBold-} . Attribute.ANSIColourCode.mkBgColourCode $ (- if Attribute.LogicalColourOfSquare.isBlack $ Cartesian.Coordinates.getLogicalColourOfSquare coordinates- then Attribute.ColourScheme.getDarkSquareColour- else Attribute.ColourScheme.getLightSquareColour+ Colour.ANSIColourCode.selectGraphicsRendition False {-isBold-} . Colour.ANSIColourCode.mkBgColourCode $ (+ if Colour.LogicalColourOfSquare.isBlack $ Cartesian.Coordinates.getLogicalColourOfSquare coordinates+ then Colour.ColourScheme.getDarkSquareColour+ else Colour.ColourScheme.getLightSquareColour ) colourScheme ) . showString (- Attribute.ANSIColourCode.selectGraphicsRendition True {-isBold-} . Attribute.ANSIColourCode.mkFgColourCode $ (+ Colour.ANSIColourCode.selectGraphicsRendition True {-isBold-} . Colour.ANSIColourCode.mkFgColourCode $ ( if Data.Char.isLower c {-Black-}- then Attribute.ColourScheme.getDarkPieceColour- else Attribute.ColourScheme.getLightPieceColour+ then Colour.ColourScheme.getDarkPieceColour+ else Colour.ColourScheme.getLightPieceColour ) colourScheme ) . let showPadding = showString (fromIntegral (pred boardColumnMagnification) `replicate` ' ')@@ -425,73 +441,102 @@ fromIntegral Cartesian.Abscissa.xLength ) . enumFrom . Data.Char.chr $ fromIntegral xOrigin ) where- axisGraphicsRendition :: Attribute.ANSIColourCode.GraphicsRendition- axisGraphicsRendition = Attribute.ANSIColourCode.selectGraphicsRendition True {-isBold-} $ Attribute.ANSIColourCode.mkFgColourCode Attribute.PhysicalColour.green+ axisGraphicsRendition :: Colour.ANSIColourCode.GraphicsRendition+ axisGraphicsRendition = Colour.ANSIColourCode.selectGraphicsRendition True {-isBold-} $ Colour.ANSIColourCode.mkFgColourCode Colour.PhysicalColour.green showsReset :: ShowS- showsReset = showString $ Attribute.ANSIColourCode.selectGraphicsRendition False Data.Default.def+ showsReset = showString $ Colour.ANSIColourCode.selectGraphicsRendition False Data.Default.def -- | Show the board using a two-dimensional representation. show2D- :: Type.Length.Column -- ^ The column-magnification.- -> Attribute.ColourScheme.ColourScheme+ :: MaybePieceByCoordinates+ -> Type.Length.Column -- ^ The column-magnification.+ -> Colour.ColourScheme.ColourScheme -> Bool -- ^ Whether to depict figurines. -> (Type.Length.X, Type.Length.Y) -- ^ The origin from which axes are labelled.- -> MaybePieceByCoordinates- -> String -- ^ The output suitable for display on a terminal.-show2D boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) maybePieceByCoordinates = shows2D boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) maybePieceByCoordinates ""+ -> String -- ^ The output suitable for display on a terminal.+show2D maybePieceByCoordinates boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) = shows2D maybePieceByCoordinates boardColumnMagnification colourScheme depictFigurine (xOrigin, yOrigin) "" -- | Extract the pieces from the board, discarding their coordinates. getPieces :: MaybePieceByCoordinates -> [Component.Piece.Piece] getPieces MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.catMaybes $ Data.Foldable.toList byCoordinates {- |- * Find the first /piece/ of either /logical colour/, encountered along a straight line in the specified /direction/, from just after the specified /coordinates/.+ * Find the first /piece/ of either /logical colour/, encountered in the specified /direction/, from just after the specified /coordinates/. * CAVEAT: this is a performance-hotspot. -} findBlockingPiece- :: Attribute.Direction.Direction -- ^ The direction in which to search.+ :: MaybePieceByCoordinates -> Cartesian.Coordinates.Coordinates -- ^ The starting point.- -> MaybePieceByCoordinates- -> Maybe Component.Piece.LocatedPiece-findBlockingPiece direction source MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.listToMaybe [- (coordinates, piece) |- (coordinates, Just piece) <- map (id &&& (byCoordinates !)) $ Cartesian.Coordinates.extrapolate direction source- ] -- List-comprehension.+ -> Direction.Direction.Direction -- ^ The direction in which to search.+ -> Maybe Component.Piece.LocatedPiece -- ^ Any blocking piece.+findBlockingPiece MkMaybePieceByCoordinates { deconstruct = byCoordinates } source = slave . Cartesian.Coordinates.extrapolate source where+ slave :: [Cartesian.Coordinates.Coordinates] -> Maybe Component.Piece.LocatedPiece+ slave (coordinates : remainder)+ | Just blockingPiece <- byCoordinates ! coordinates = Just (coordinates, blockingPiece) -- Terminate with success.+ | otherwise = slave remainder -- Recurse.+ slave _ = Nothing -- Terminate with failure. {- |- * Find the /coordinates/ of any attacker who can strike the specified /coordinates/, in a straight line along the specified /direction/ (as seen by the target).+ * Find the first /piece/ of either /logical colour/, encountered in each of the specified /direction/s, from just after the specified /coordinates/. + * N.B.: one could call 'findBlockingPiece' for each /direction/, but this function exploits optimisations available when all /direction/s are required.+-}+findBlockingPieces+ :: MaybePieceByCoordinates+ -> Cartesian.Coordinates.Coordinates -- ^ The starting point.+ -> Maybe [Direction.Direction.Direction] -- ^ The directions in which to search; 'Nothing' implies omni-directional.+ -> [Component.Piece.LocatedPiece] -- ^ Blocking pieces in non-specific directions.+findBlockingPieces MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Cartesian.Coordinates.applyAlongDirectionsFrom slave where+ slave :: [Cartesian.Coordinates.Coordinates] -> [Component.Piece.LocatedPiece]+ slave (coordinates : remainder)+ | Just blockingPiece <- byCoordinates ! coordinates = [(coordinates, blockingPiece)] -- Terminate with success.+ | otherwise = slave remainder -- Recurse.+ slave _ = [] -- Terminate with failure.++{- |+ * Find the /coordinates/ of any attacker who can strike the specified /coordinates/, from the specified /direction/ (as seen by the target).+ * N.B.: there no requirement for there to actually be a /piece/ to attack at the specified target. -} findAttackerInDirection- :: Attribute.LogicalColour.LogicalColour -- ^ The defender's /logical colour/.- -> Attribute.Direction.Direction -- ^ The /direction/ from the /coordinates/ of concern; the opposite /direction/ from which an attacker might strike.+ :: MaybePieceByCoordinates+ -> Colour.LogicalColour.LogicalColour -- ^ The defender's /logical colour/. -> Cartesian.Coordinates.Coordinates -- ^ The defender's square.- -> MaybePieceByCoordinates+ -> Direction.Direction.Direction -- ^ The /direction/ from the /coordinates/ of concern; the opposite /direction/ from which an attacker might strike. -> Maybe (Cartesian.Coordinates.Coordinates, Attribute.Rank.Rank) -- ^ Any opposing /piece/ which can attack the specified square from the specified /direction/.-findAttackerInDirection destinationLogicalColour direction destination = (=<<) (+findAttackerInDirection maybePieceByCoordinates destinationLogicalColour destination direction = findBlockingPiece maybePieceByCoordinates destination direction >>= \(source, sourcePiece) -> if Component.Piece.getLogicalColour sourcePiece /= destinationLogicalColour && Component.Piece.canAttackAlong source destination sourcePiece+ then Just (source, Component.Piece.getRank sourcePiece)+ else Nothing++{- |+ * Find the /coordinates/ of any attacker who can strike the specified /coordinates/, from the specified /direction/s (as seen by the target).++ * N.B.: one could call 'findAttackerInDirection' for each /direction/, but this function exploits optimisations available when all /direction/s are required.+-}+findAttackerInDirections+ :: MaybePieceByCoordinates+ -> Colour.LogicalColour.LogicalColour -- ^ The defender's /logical colour/.+ -> Cartesian.Coordinates.Coordinates -- ^ The defender's square.+ -> Maybe [Direction.Direction.Direction] -- ^ The /direction/s from the /coordinates/ of concern; the opposite /direction/ from which an attacker might strike; 'Nothing' implies omni-directional.+ -> [(Cartesian.Coordinates.Coordinates, Attribute.Rank.Rank)] -- ^ Any opposing /piece/s which can attack the specified square from the specified /direction/s.+findAttackerInDirections maybePieceByCoordinates destinationLogicalColour destination = Data.Maybe.mapMaybe ( \(source, sourcePiece) -> if Component.Piece.getLogicalColour sourcePiece /= destinationLogicalColour && Component.Piece.canAttackAlong source destination sourcePiece then Just (source, Component.Piece.getRank sourcePiece) else Nothing- ) . findBlockingPiece direction destination+ ) . findBlockingPieces maybePieceByCoordinates destination -- | Whether the specified /coordinates/ are unoccupied.-isVacant- :: Cartesian.Coordinates.Coordinates- -> MaybePieceByCoordinates- -> Bool+isVacant :: MaybePieceByCoordinates -> Cartesian.Coordinates.Coordinates -> Bool {-# INLINE isVacant #-}-isVacant coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.isNothing $ byCoordinates ! coordinates+isVacant MkMaybePieceByCoordinates { deconstruct = byCoordinates } coordinates+ | Nothing <- byCoordinates ! coordinates = True+ | otherwise = False -- | Whether the specified /coordinates/ are occupied.-isOccupied- :: Cartesian.Coordinates.Coordinates- -> MaybePieceByCoordinates- -> Bool-{-# INLINE isOccupied #-}-isOccupied coordinates = not . isVacant coordinates+isOccupied :: MaybePieceByCoordinates -> Cartesian.Coordinates.Coordinates -> Bool+isOccupied maybePieceByCoordinates = not . isVacant maybePieceByCoordinates {- | * Whether the open interval (source, destination) is unobstructed.@@ -501,22 +546,21 @@ * N.B.: the specified end-points are uninspected. -} isClear- :: Cartesian.Coordinates.Coordinates -- ^ Source.+ :: MaybePieceByCoordinates+ -> Cartesian.Coordinates.Coordinates -- ^ Source. -> Cartesian.Coordinates.Coordinates -- ^ Destination.- -> MaybePieceByCoordinates -> Bool-{-# INLINABLE isClear #-} -- N.B.: required to ensure specialisation of 'Cartesian.Coordinates.interpolate'.-isClear source destination maybePieceByCoordinates = Control.Exception.assert (+isClear maybePieceByCoordinates source destination = Control.Exception.assert ( source /= destination && Property.Orientated.isStraight (Component.Move.mkMove source destination)- ) . all (`isVacant` maybePieceByCoordinates) . init {-discard the destination-} $ Cartesian.Coordinates.interpolate source destination+ ) . all (isVacant maybePieceByCoordinates) . init {-discard the destination-} $ Cartesian.Coordinates.interpolate source destination -- | Whether there's a blockage between a /piece/ presumed to exist at the specified source, & a /piece/ presumed to exist @ the specified destination. isObstructed- :: Cartesian.Coordinates.Coordinates -- ^ Source.+ :: MaybePieceByCoordinates+ -> Cartesian.Coordinates.Coordinates -- ^ Source. -> Cartesian.Coordinates.Coordinates -- ^ Destination.- -> MaybePieceByCoordinates -> Bool-isObstructed source destination = not . isClear source destination+isObstructed maybePieceByCoordinates source = not . isClear maybePieceByCoordinates source {- | * Whether the specified /move/ matches the rules for /en-passant/.@@ -524,40 +568,12 @@ * CAVEAT: assumes that the /move/ is valid; otherwise one would also need to confirm that the opponent's @Pawn@ had just double-advanced into the appropriate position. -}-isEnPassantMove- :: Component.Move.Move- -> MaybePieceByCoordinates- -> Bool-isEnPassantMove move maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates }+isEnPassantMove :: MaybePieceByCoordinates -> Component.Move.Move -> Bool+isEnPassantMove maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } move | Just piece <- byCoordinates ! source , let logicalColour = Component.Piece.getLogicalColour piece- = Cartesian.Coordinates.isEnPassantRank logicalColour source && Component.Piece.isPawn piece && destination `elem` Component.Piece.findAttackDestinations source piece && isVacant destination maybePieceByCoordinates -- The move is either En-passant or invalid.+ = Cartesian.Coordinates.isEnPassantRank source logicalColour && Component.Piece.isPawn piece && destination `elem` Component.Piece.findAttackDestinations piece source && isVacant maybePieceByCoordinates destination -- The move is either En-passant or invalid. | otherwise = False -- No piece. where (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move---- | Self-documentation.-type Transformation = MaybePieceByCoordinates -> MaybePieceByCoordinates--{- |- * Adjust the array to reflect a move.-- * CAVEAT: regrettably this allocates an entire array.--}-movePiece- :: Component.Move.Move- -> Component.Piece.Piece -- ^ The (possibly promoted) piece to place at the destination.- -> Maybe Cartesian.Coordinates.Coordinates -- ^ Destination of any En-passant @Pawn@.- -> Transformation-movePiece move destinationPiece maybeEnPassantDestination MkMaybePieceByCoordinates { deconstruct = byCoordinates } = MkMaybePieceByCoordinates $ byCoordinates // Data.Maybe.maybe id (- (:) . flip (,) Nothing -- Take the Pawn en-passant.- ) maybeEnPassantDestination [- (- Component.Move.getSource move,- Nothing -- Remove the piece from the source.- ), (- Component.Move.getDestination move,- Just destinationPiece -- Place the piece at the destination, removing any opposing incumbent as a side-effect.- )- ]
src-lib/BishBosh/State/Position.hs view
@@ -43,7 +43,7 @@ mkPosition ) where -import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Property.Opposable as Property.Opposable@@ -53,11 +53,10 @@ import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified Control.DeepSeq-import qualified Data.Maybe -- | The state of the game, without regard to how it arrived there. data Position = MkPosition {- getNextLogicalColour :: Attribute.LogicalColour.LogicalColour, -- ^ The next player to move.+ getNextLogicalColour :: Colour.LogicalColour.LogicalColour, -- ^ The next player to move. getMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates, getCastleableRooksByLogicalColour :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour, getMaybeEnPassantAbscissa :: Maybe State.EnPassantAbscissa.EnPassantAbscissa@@ -102,25 +101,23 @@ } instance StateProperty.Hashable.Hashable Position where- listRandoms MkPosition {+ listRandoms zobrist MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getMaybeEnPassantAbscissa = maybeEnPassantAbscissa- } zobrist = (- if Attribute.LogicalColour.isBlack nextLogicalColour+ } = (+ if Colour.LogicalColour.isBlack nextLogicalColour then (Component.Zobrist.getRandomForBlacksMove zobrist :) else id- ) . Data.Maybe.maybe id (- (++) . (`StateProperty.Hashable.listRandoms` zobrist)- ) maybeEnPassantAbscissa $ StateProperty.Hashable.listRandoms castleableRooksByLogicalColour zobrist ++ StateProperty.Hashable.listRandoms maybePieceByCoordinates zobrist+ ) $ StateProperty.Hashable.listRandoms zobrist (maybeEnPassantAbscissa, castleableRooksByLogicalColour, maybePieceByCoordinates) -- | Constructor. mkPosition- :: Attribute.LogicalColour.LogicalColour -- ^ The logical colour of the next player to move.+ :: Colour.LogicalColour.LogicalColour -- ^ The logical colour of the next player to move. -> State.MaybePieceByCoordinates.MaybePieceByCoordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour- -> Maybe Component.Turn.Turn -- ^ The last /turn/ made.+ -> Maybe Component.Turn.Turn -- ^ The last /turn/ made. -> Position mkPosition nextLogicalColour maybePieceByCoordinates castleableRooksByLogicalColour maybeLastTurn = MkPosition { getNextLogicalColour = nextLogicalColour,
src-lib/BishBosh/State/TurnsByLogicalColour.hs view
@@ -45,13 +45,13 @@ import Control.Arrow((&&&), (***)) import Data.Array.IArray((!), (//))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.Empty as Property.Empty-import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Property.Empty as Property.Empty+import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -62,7 +62,7 @@ -- | The type used to hold a record of each player's /turn/s. data TurnsByLogicalColour turn = MkTurnsByLogicalColour {- getTurnsByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [turn],+ getTurnsByLogicalColour :: Colour.LogicalColour.ArrayByLogicalColour [turn], getNPlies :: Type.Count.NPlies -- ^ The total number of plies applied to the game for both players; this could alternatively be derived using 'countPlies'. } @@ -80,7 +80,7 @@ instance Data.Default.Default (TurnsByLogicalColour turn) where def = MkTurnsByLogicalColour {- getTurnsByLogicalColour = Attribute.LogicalColour.listArrayByLogicalColour $ repeat [],+ getTurnsByLogicalColour = Colour.LogicalColour.listArrayByLogicalColour $ repeat [], getNPlies = 0 } @@ -93,24 +93,24 @@ instance Property.Reflectable.ReflectableOnX turn => Property.Reflectable.ReflectableOnX (TurnsByLogicalColour turn) where reflectOnX turnsByLogicalColour@MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = turnsByLogicalColour {- getTurnsByLogicalColour = Attribute.LogicalColour.arrayByLogicalColour . map (+ getTurnsByLogicalColour = Colour.LogicalColour.arrayByLogicalColour . map ( Property.Opposable.getOpposite {-logical colour-} *** Property.Reflectable.reflectOnX {-[turn]-} ) $ Data.Array.IArray.assocs byLogicalColour } -- | Smart constructor.-fromAssocs :: Show turn => [(Attribute.LogicalColour.LogicalColour, [turn])] -> TurnsByLogicalColour turn+fromAssocs :: Show turn => [(Colour.LogicalColour.LogicalColour, [turn])] -> TurnsByLogicalColour turn fromAssocs assocs | fromIntegral ( length assocs- ) /= Attribute.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tboth logical colours must be defined; " $ shows assocs "."- | Data.List.Extra.anySame $ map fst {-logicalColour-} assocs = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tduplicates specified; " $ shows assocs "."+ ) /= Colour.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tboth logical colours must be defined; " $ shows assocs "."+ | Data.List.Extra.anySame $ map fst {-logicalColour-} assocs = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tduplicates specified; " $ shows assocs "." | (> 1) . abs {-allow for Property.Reflectable.reflectOnX-} . uncurry (-) $ (- length . (! Attribute.LogicalColour.White) &&& length . (! Attribute.LogicalColour.Black)- ) byLogicalColour = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tany difference in the number of turns taken by each player, can't exceed one " $ shows assocs "."- | otherwise = turnsByLogicalColour+ length . (! Colour.LogicalColour.White) &&& length . (! Colour.LogicalColour.Black)+ ) byLogicalColour = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tany difference in the number of turns taken by each player, can't exceed one " $ shows assocs "."+ | otherwise = turnsByLogicalColour where- byLogicalColour = Attribute.LogicalColour.arrayByLogicalColour assocs+ byLogicalColour = Colour.LogicalColour.arrayByLogicalColour assocs turnsByLogicalColour = MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour, getNPlies = countPlies turnsByLogicalColour -- Infer.@@ -121,10 +121,10 @@ * CAVEAT: the result can't be guaranteed if 'Property.Reflectable.reflectOnX' has been called. -}-inferNextLogicalColour :: TurnsByLogicalColour turn -> Attribute.LogicalColour.LogicalColour+inferNextLogicalColour :: TurnsByLogicalColour turn -> Colour.LogicalColour.LogicalColour inferNextLogicalColour MkTurnsByLogicalColour { getNPlies = nPlies }- | even nPlies = Attribute.LogicalColour.White- | otherwise = Attribute.LogicalColour.Black+ | even nPlies = Colour.LogicalColour.White+ | otherwise = Colour.LogicalColour.Black {- | * Count the total number of plies, regardless of the player.@@ -135,26 +135,26 @@ countPlies MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = fromIntegral $ Data.Foldable.foldl' (\acc -> (+ acc) . length) 0 byLogicalColour -- | Dereference.-dereference :: Attribute.LogicalColour.LogicalColour -> TurnsByLogicalColour turn -> [turn]-dereference logicalColour MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = byLogicalColour ! logicalColour+dereference :: TurnsByLogicalColour turn -> Colour.LogicalColour.LogicalColour -> [turn]+dereference MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } logicalColour = byLogicalColour ! logicalColour +-- | Self-documentation.+type Transformation turn = TurnsByLogicalColour turn -> TurnsByLogicalColour turn+ {- | * Update the specified logical colours. * CAVEAT: obliterates any incumbent data for the specified logical colours. -}-update :: TurnsByLogicalColour turn -> [(Attribute.LogicalColour.LogicalColour, [turn])] -> TurnsByLogicalColour turn-update MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } assocs = turnsByLogicalColour where+update :: [(Colour.LogicalColour.LogicalColour, [turn])] -> Transformation turn+update assocs MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = turnsByLogicalColour where turnsByLogicalColour = MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour // assocs, getNPlies = countPlies turnsByLogicalColour -- Infer. } --- | Self-documentation.-type Transformation turn = TurnsByLogicalColour turn -> TurnsByLogicalColour turn- -- | Prepend the specified /turn/.-prepend :: Attribute.LogicalColour.LogicalColour -> turn -> Transformation turn+prepend :: Colour.LogicalColour.LogicalColour -> turn -> Transformation turn prepend logicalColour turn MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour, getNPlies = nPlies
src-lib/BishBosh/StateProperty/Censor.hs view
@@ -27,11 +27,16 @@ -- ** Type-synonyms NPiecesByRank, -- * Type-classes- Censor(..)+ Censor(..),+-- * Functions+ findInvalidity ) where -import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Type.Count as Type.Count+import Control.Arrow((&&&), (***))+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Type.Count as Type.Count -- | The difference in the number of /piece/s of each /rank/ held by either side. type NPiecesByRank = Attribute.Rank.ArrayByRank Type.Count.NPieces@@ -48,4 +53,18 @@ hasInsufficientMaterial :: censor -> Bool -- ^ Whether insufficient material remains on the board, to force check-mate; <https://en.wikipedia.org/wiki/Draw_(chess)>. hasBothKings :: censor -> Bool -- ^ Whether there's exactly one @King@ of each /logical colour/.++-- | Self-validate.+findInvalidity :: Censor censor => censor -> [String]+findInvalidity = Property.SelfValidating.findErrors [+ (+ not . hasBothKings,+ "there must be exactly one King of each logical colour."+ ), (+ uncurry (||) . uncurry (***) (+ id &&& id $ (> Component.Piece.nPiecesPerSide)+ ) . countPiecesByLogicalColour,+ "there are too many pieces of at least one logical colour."+ )+ ]
src-lib/BishBosh/StateProperty/Hashable.hs view
@@ -28,7 +28,7 @@ module BishBosh.StateProperty.Hashable( -- * Type-classes- Hashable(..),+ Hashable(listRandoms), -- * Constants -- combiningOp, -- * Functions@@ -36,14 +36,28 @@ combine ) where +import Control.Arrow((***)) import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified Data.Bits import qualified Data.List+import qualified Data.Maybe -- | An interface to which hashable data can conform. class Hashable hashable where- listRandoms :: hashable -> Component.Zobrist.Zobrist positionHash -> [positionHash]+ listRandoms :: Component.Zobrist.Zobrist positionHash -> hashable -> [positionHash] +instance (Hashable l, Hashable r) => Hashable (l, r) where+ listRandoms zobrist = uncurry (++) . (listRandoms zobrist *** listRandoms zobrist)++instance (Hashable f, Hashable s, Hashable t) => Hashable (f, s, t) where+ listRandoms zobrist (f, s, t) = listRandoms zobrist f ++ listRandoms zobrist s ++ listRandoms zobrist t++instance Hashable a => Hashable [a] where+ listRandoms zobrist = concatMap $ listRandoms zobrist++instance Hashable a => Hashable (Maybe a) where+ listRandoms zobrist = Data.Maybe.maybe [] $ listRandoms zobrist+ -- | The operator used when combining random numbers to compose a hash. combiningOp :: Data.Bits.Bits positionHash => positionHash -> positionHash -> positionHash combiningOp = Data.Bits.xor@@ -53,10 +67,10 @@ Data.Bits.Bits positionHash, Hashable hashable )- => hashable- -> Component.Zobrist.Zobrist positionHash+ => Component.Zobrist.Zobrist positionHash+ -> hashable -> positionHash-hash hashable = Data.List.foldl1' combiningOp . listRandoms hashable+hash zobrist = Data.List.foldl1' combiningOp . listRandoms zobrist -- | Include a list of random numbers in the hash. combine :: Data.Bits.Bits positionHash => positionHash -> [positionHash] -> positionHash
src-lib/BishBosh/StateProperty/Mutator.hs view
@@ -34,26 +34,40 @@ removePiece ) where +import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Property.Empty as Property.Empty {- |- * Defines the specified /coordinates/, by either placing or removing a /piece/.-- * CAVEAT: this function should only be used to construct custom scenarios, since /piece/s don't normally spring into existence.-- * CAVEAT: doesn't validate the request, so @King@s can be placed /in check/ & @Pawn@s can be placed behind their starting rank or unpromoted on their last /rank/.+ * An interface which may be implemented by data which can mutate the board. - * CAVEAT: this function isn't called during normal play.+ * CAVEAT: doesn't validate requests, so @King@s can be placed /in check/ & @Pawn@s can be placed behind their starting rank or unpromoted on their last /rank/. -} class Mutator mutator where+ {- |+ * Defines the specified /coordinates/, by either placing or removing a /piece/.++ * CAVEAT: this function should only be used to construct custom scenarios, since /piece/s don't normally spring into existence.++ * CAVEAT: this function isn't called during normal play.+ -} defineCoordinates :: Maybe Component.Piece.Piece -- ^ The optional /piece/ to place (or remove if @Nothing@ is specified). -> Cartesian.Coordinates.Coordinates -- ^ The /coordinates/ to define. -> mutator -> mutator + -- | Move the specified piece, accounting for promotions & casualties.+ movePiece+ :: Component.Move.Move -- ^ The source & destination /coordinates/.+ -> Component.Piece.Piece -- ^ The /piece/ which moved.+ -> Maybe Attribute.Rank.Rank -- ^ The (possibly promoted) /rank/ to place at the destination.+ -> Either Cartesian.Coordinates.Coordinates (Maybe Attribute.Rank.Rank) -- ^ Either the /coordinates/ of any @Pawn@ which was just captured en-passant, or the /rank/ of any /piece/ taken.+ -> mutator+ -> mutator+ {- | * Place a /piece/ at the specified /coordinates/. @@ -93,5 +107,4 @@ -> mutator -> mutator removePiece = defineCoordinates Nothing-
src-lib/BishBosh/StateProperty/Seeker.hs view
@@ -33,19 +33,25 @@ -- * Functions accumulatePawnsByFile, findAllPieces,- summariseNPawnsByLogicalColour+ summariseNPawnsByLogicalColour,+ findInvalidity ) where -import Control.Arrow((***))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import Control.Arrow((&&&), (***))+import Data.Array.IArray((!))+import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Property.Empty as Property.Empty+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Data.Array.IArray import qualified Data.Foldable+import qualified Data.List import qualified Data.Map.Strict as Map -- | The number of /piece/s in each file, for each /logical colour/.@@ -57,15 +63,15 @@ accumulatePawnsByFile = flip (Map.insertWith $ const succ) 1 -- | The number of /piece/s in each file, for each /logical colour/.-type NPiecesByFileByLogicalColour = Attribute.LogicalColour.ArrayByLogicalColour NPiecesByFile+type NPiecesByFileByLogicalColour = Colour.LogicalColour.ArrayByLogicalColour NPiecesByFile -- | An interface which may be implemented by data which can search the board. class Seeker seeker where -- | Locate any @Knight@s capable of taking a /piece/ at the specified /coordinates/. findProximateKnights- :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @Knight@ for which to search.- -> Cartesian.Coordinates.Coordinates -- ^ The destination to which the @Knight@ is required to be capable of jumping.- -> seeker+ :: seeker+ -> Colour.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @Knight@ for which to search.+ -> Cartesian.Coordinates.Coordinates -- ^ The destination to which the @Knight@ is required to be capable of jumping. -> [Cartesian.Coordinates.Coordinates] -- | Locate any /piece/s satisfying the specified predicate.@@ -81,14 +87,14 @@ -} countPawnsByFileByLogicalColour :: seeker -> NPiecesByFileByLogicalColour countPawnsByFileByLogicalColour = (- \(mB, mW) -> Attribute.LogicalColour.listArrayByLogicalColour [mB, mW]+ \(mB, mW) -> Colour.LogicalColour.listArrayByLogicalColour [mB, mW] ) . foldr ( ( \(x, isBlack) -> ( if isBlack then Control.Arrow.first else Control.Arrow.second -- Select the appropriate map. ) $ accumulatePawnsByFile x ) . (- Cartesian.Coordinates.getX *** Attribute.LogicalColour.isBlack . Component.Piece.getLogicalColour+ Cartesian.Coordinates.getX *** Colour.LogicalColour.isBlack . Component.Piece.getLogicalColour ) ) Property.Empty.empty . findPieces Component.Piece.isPawn @@ -97,8 +103,28 @@ findAllPieces = findPieces $ const True -- | Resolves 'NPiecesByFileByLogicalColour' into the total number of /Pawn/s on either side.-summariseNPawnsByLogicalColour :: Seeker seeker => seeker -> Attribute.LogicalColour.ArrayByLogicalColour Type.Count.NPieces+summariseNPawnsByLogicalColour :: Seeker seeker => seeker -> Colour.LogicalColour.ArrayByLogicalColour Type.Count.NPieces summariseNPawnsByLogicalColour = Data.Array.IArray.amap ( Data.Foldable.foldl' (+) 0 ) . countPawnsByFileByLogicalColour++-- | Self-validate.+findInvalidity :: Seeker seeker => seeker -> [String]+findInvalidity = Property.SelfValidating.findErrors [+ (+ uncurry (||) . uncurry (***) (+ id &&& id $ (> Attribute.Rank.initialAllocationByRankPerSide ! Attribute.Rank.Pawn) . fromIntegral . length+ ) . Data.List.partition (+ Colour.LogicalColour.isBlack . Component.Piece.getLogicalColour+ ) . map snd {-piece-} . findPieces Component.Piece.isPawn,+ "there are too many Pawns of at least one logical colour."+ ), (+ any (+ uncurry (||) . uncurry (&&&) (+ (==) *** (==) $ Cartesian.Ordinate.yBounds+ ) . Cartesian.Coordinates.getY . fst {-coordinates-}+ ) . findPieces Component.Piece.isPawn,+ "no Pawn can exist on either of the terminal ranks."+ )+ ]
+ src-lib/BishBosh/StateProperty/View.hs view
@@ -0,0 +1,48 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Permits construction & destruction of views of the board.+-}++module BishBosh.StateProperty.View(+-- * Type-classes+ View(..),+-- * Functions+ toAssocs,+ translate+) where++import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker++-- | An interface which may be implemented by data which represent a view of the board.+class View view where+ -- | Constructor.+ fromAssocs :: [Component.Piece.LocatedPiece] -> view++-- | Deconstructor.+toAssocs :: StateProperty.Seeker.Seeker seeker => seeker -> [Component.Piece.LocatedPiece]+toAssocs = StateProperty.Seeker.findAllPieces++-- | Convert between implementations.+translate :: (StateProperty.Seeker.Seeker seeker, View view) => seeker -> view+translate = fromAssocs . toAssocs+
src-lib/BishBosh/Text/ShowColouredPrefix.hs view
@@ -29,25 +29,25 @@ showsPrefixError ) where -import qualified BishBosh.Attribute.ANSIColourCode as Attribute.ANSIColourCode-import qualified BishBosh.Attribute.PhysicalColour as Attribute.PhysicalColour-import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix+import qualified BishBosh.Colour.ANSIColourCode as Colour.ANSIColourCode+import qualified BishBosh.Colour.PhysicalColour as Colour.PhysicalColour+import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix -- | Show the prefix used to denote an information-message. showsPrefixInfo :: ShowS-showsPrefixInfo = Attribute.ANSIColourCode.bracket (- Attribute.ANSIColourCode.selectGraphicsRendition False $ Attribute.ANSIColourCode.mkFgColourCode Attribute.PhysicalColour.green+showsPrefixInfo = Colour.ANSIColourCode.bracket (+ Colour.ANSIColourCode.selectGraphicsRendition False $ Colour.ANSIColourCode.mkFgColourCode Colour.PhysicalColour.green ) $ Text.ShowPrefix.showsPrefixInfo "" -- | Show the prefix used to denote a warning-message. showsPrefixWarning :: ShowS-showsPrefixWarning = Attribute.ANSIColourCode.bracket (- Attribute.ANSIColourCode.selectGraphicsRendition True $ Attribute.ANSIColourCode.mkFgColourCode Attribute.PhysicalColour.yellow+showsPrefixWarning = Colour.ANSIColourCode.bracket (+ Colour.ANSIColourCode.selectGraphicsRendition True $ Colour.ANSIColourCode.mkFgColourCode Colour.PhysicalColour.yellow ) $ Text.ShowPrefix.showsPrefixWarning "" -- | Show the prefix used to denote an error-message. showsPrefixError :: ShowS-showsPrefixError = Attribute.ANSIColourCode.bracket (- Attribute.ANSIColourCode.selectGraphicsRendition True $ Attribute.ANSIColourCode.mkFgColourCode Attribute.PhysicalColour.red+showsPrefixError = Colour.ANSIColourCode.bracket (+ Colour.ANSIColourCode.selectGraphicsRendition True $ Colour.ANSIColourCode.mkFgColourCode Colour.PhysicalColour.red ) $ Text.ShowPrefix.showsPrefixError ""
src-lib/BishBosh/Time/GameClock.hs view
@@ -34,10 +34,10 @@ ) where import Control.Arrow((***))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Property.Switchable as Property.Switchable import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Time.StopWatch as Time.StopWatch@@ -49,12 +49,12 @@ -- | Models a game-clock, in which each player owns a personal stop-watch, exactly one of which is running at any one time. newtype GameClock = MkGameClock {- deconstruct :: Attribute.LogicalColour.ArrayByLogicalColour Time.StopWatch.StopWatch -- ^ Contains one stop-watch for each of two players.+ deconstruct :: Colour.LogicalColour.ArrayByLogicalColour Time.StopWatch.StopWatch -- ^ Contains one stop-watch for each of two players. } instance Property.Switchable.Switchable GameClock where on = fmap (- MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour . (+ MkGameClock . Colour.LogicalColour.listArrayByLogicalColour . ( Data.Default.def : -- A stopped watch for Black. ) . return {-to List-monad-} ) Property.Switchable.on -- A running watch for White.@@ -62,11 +62,11 @@ toggle gameClock | errorMessages@(_ : _) <- Property.SelfValidating.findInvalidity gameClock = Control.Exception.throwIO . Data.Exception.mkInsufficientData . showString "Duel.Process.Intermediary.initialise:\tinvalid gameClock; " $ show errorMessages | otherwise = fmap (- MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour+ MkGameClock . Colour.LogicalColour.listArrayByLogicalColour ) . mapM Property.Switchable.toggle . Data.Foldable.toList $ deconstruct gameClock switchOff = fmap (- MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour+ MkGameClock . Colour.LogicalColour.listArrayByLogicalColour ) . mapM Property.Switchable.switchOff . Data.Foldable.toList . deconstruct -- CAVEAT: this invalidates the clock, since a subsequent call to 'toggle' would activate both stop-watches. isOn = Data.Foldable.any Property.Switchable.isOn . deconstruct -- CAVEAT: includes the dysfunctional state in which both sides are running.
src-lib/BishBosh/Type/Crypto.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE CPP #-} {-- Copyright (C) 2018 Dr. Alistair Ward+ Copyright (C) 2021 Dr. Alistair Ward This file is part of BishBosh. @@ -22,7 +22,7 @@ [@DESCRIPTION@] - * Defines suitable concrete types with which to specialise miscellaneous type-parameters.+ * Defines suitable types for various quantities. * CAVEAT: use of narrow numeric types, results in marginally slower performance without any reduction in space-requirements. -}@@ -30,7 +30,7 @@ module BishBosh.Type.Crypto( -- * Types -- ** Type-synonyms- PositionHash,+ PositionHash ) where import qualified Data.Word
src-lib/BishBosh/Type/Mass.hs view
@@ -31,21 +31,32 @@ module BishBosh.Type.Mass( -- * Types -- ** Type-synonyms+ Base, CriterionWeight, CriterionValue, WeightedMean, RankValue,- PieceSquareValue+ PieceSquareValue(),+-- * Functions+-- ** Constructors+-- mkPieceSquareValue ) where +#ifdef USE_NEWTYPE_WRAPPERS+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Num as Data.Num+import qualified Control.DeepSeq+import qualified Control.Exception+#endif+ #ifdef USE_PRECISION import BishBosh.Data.Ratio() #else import qualified Text.XML.HXT.Arrow.Pickle as HXT #endif --- | The preferred type by which to weight criteria.-type CriterionWeight =+-- | The underling type.+type Base = #ifdef USE_PRECISION Rational #else /* Floating-point */@@ -62,19 +73,49 @@ # endif #endif --- | The preferred type by which to value criteria.+-- | The type by which to weight criteria.+type CriterionWeight = Base++-- | The type by which to value criteria. type CriterionValue = CriterionWeight --- | The preferred type by which to represent fitness.+-- | The type by which to represent fitness. type WeightedMean = CriterionValue --- | The preferred type by which to represent the value of a /rank/.-type RankValue = CriterionValue+-- | The type by which to represent the value of a /rank/.+type RankValue = Base -{- |- * The preferred type by which to represent a /piece-square/ value.+-- | The type by which to represent a /piece-square/ value.+#ifdef USE_NEWTYPE_WRAPPERS+newtype PieceSquareValue = MkPieceSquareValue Base deriving (Eq, Ord) - * CAVEAT: performance of 'BishBosh.Evaluation.Fitness.interpolatePieceSquareValues' suffers from use of 'Rational'.--}-type PieceSquareValue = CriterionValue+instance Show PieceSquareValue where+ showsPrec precision (MkPieceSquareValue pieceSquareValue) = showsPrec precision pieceSquareValue++instance Num PieceSquareValue where+ MkPieceSquareValue l + MkPieceSquareValue r = mkPieceSquareValue $! l + r+ MkPieceSquareValue l * MkPieceSquareValue r = MkPieceSquareValue $! l * r+ abs (MkPieceSquareValue pieceSquareValue) = MkPieceSquareValue $! abs pieceSquareValue -- N.B.: if the operand is valid, then this is equivalent to 'id'.+ signum (MkPieceSquareValue pieceSquareValue) = MkPieceSquareValue $! signum pieceSquareValue+ fromInteger = mkPieceSquareValue . fromInteger+ negate (MkPieceSquareValue pieceSquareValue) = mkPieceSquareValue $! negate pieceSquareValue -- CAVEAT: only valid for '0'.++instance Fractional PieceSquareValue where+ MkPieceSquareValue l / MkPieceSquareValue r = mkPieceSquareValue $! l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ fromRational = mkPieceSquareValue . fromRational++instance Real PieceSquareValue where+ toRational (MkPieceSquareValue pieceSquareValue) = toRational pieceSquareValue++instance Control.DeepSeq.NFData PieceSquareValue where+ rnf (MkPieceSquareValue pieceSquareValue) = Control.DeepSeq.rnf pieceSquareValue++-- | Smart constructor.+mkPieceSquareValue :: Base -> PieceSquareValue+mkPieceSquareValue pieceSquareValue+ | Data.Num.inClosedUnitInterval pieceSquareValue = MkPieceSquareValue pieceSquareValue+ | otherwise = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Type.Mass.mkPieceSquareValue:\t" $ shows pieceSquareValue " must be within the closed unit-interval [0,1]."+#else+type PieceSquareValue = Base+#endif
− src-test/BishBosh/Test/HUnit/Attribute/Direction.hs
@@ -1,46 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Static tests.--}--module BishBosh.Test.HUnit.Attribute.Direction(--- * Constants- testCases-) where--import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified Data.List-import qualified Test.HUnit-import Test.HUnit((~?))---- | Check the sanity of the implementation, by validating a list of static test-cases.-testCases :: Test.HUnit.Test-testCases = Test.HUnit.test [- null (- Attribute.Direction.diagonals `Data.List.intersect` Attribute.Direction.parallels- ) ~? "BishBosh.Attribute.Direction.[diagonal, parallels] intersect.",- all (- (== 2) . length . Attribute.Direction.attackDirectionsForPawn- ) Property.FixedMembership.members ~? "'BishBosh.Attribute.Direction.attackDirectionsForPawn' failed."- ]-
− src-test/BishBosh/Test/HUnit/Attribute/LogicalColour.hs
@@ -1,41 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Static tests.--}--module BishBosh.Test.HUnit.Attribute.LogicalColour(--- * Constants- testCases-) where--import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified Data.List-import qualified Test.HUnit-import Test.HUnit((~?))---- | Check the sanity of the implementation, by validating a list of static test-cases.-testCases :: Test.HUnit.Test-testCases = Test.HUnit.test [- Property.FixedMembership.members == Data.List.sort Attribute.LogicalColour.range ~? "BishBosh.Attribute.LogicalColour.range is misordered."- ]-
src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs view
@@ -27,9 +27,9 @@ testCases ) where -import qualified BishBosh.Attribute.LogicalColourOfSquare as Attribute.LogicalColourOfSquare-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColourOfSquare as Colour.LogicalColourOfSquare+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified Data.Array.IArray import qualified Data.List import qualified Test.HUnit@@ -38,12 +38,12 @@ -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [- all (Attribute.LogicalColourOfSquare.isBlack . Cartesian.Coordinates.getLogicalColourOfSquare) (- Cartesian.Coordinates.extrapolate maxBound {-direction-} (minBound :: Cartesian.Coordinates.Coordinates)+ all (Colour.LogicalColourOfSquare.isBlack . Cartesian.Coordinates.getLogicalColourOfSquare) (+ Cartesian.Coordinates.extrapolate (minBound :: Cartesian.Coordinates.Coordinates) maxBound {-direction-} ) ~? "'BishBosh.Cartesian.Coordinates.getLogicalColourOfSquare' failed to find black squares on the main diagonal.", "'BishBosh.Cartesian.Coordinates.getLogicalColourOfSquare' failed to count equal numbers of black & white squares." ~: ( \(black, white) -> length black ~?= length white- ) . Data.List.partition Attribute.LogicalColourOfSquare.isBlack $ map Cartesian.Coordinates.getLogicalColourOfSquare (+ ) . Data.List.partition Colour.LogicalColourOfSquare.isBlack $ map Cartesian.Coordinates.getLogicalColourOfSquare ( Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates] ), "'BishBosh.Cartesian.Coordinates' failed to visit all squares." ~: length (
+ src-test/BishBosh/Test/HUnit/Colour/LogicalColour.hs view
@@ -0,0 +1,41 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Static tests.+-}++module BishBosh.Test.HUnit.Colour.LogicalColour(+-- * Constants+ testCases+) where++import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified Data.List+import qualified Test.HUnit+import Test.HUnit((~?))++-- | Check the sanity of the implementation, by validating a list of static test-cases.+testCases :: Test.HUnit.Test+testCases = Test.HUnit.test [+ Property.FixedMembership.members == Data.List.sort Colour.LogicalColour.range ~? "BishBosh.Colour.LogicalColour.range is misordered."+ ]+
src-test/BishBosh/Test/HUnit/Component/Move.hs view
@@ -27,10 +27,10 @@ testCases ) where -import qualified BishBosh.Attribute.Direction as Attribute.Direction import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Direction.Direction as Direction.Direction import qualified BishBosh.Notation.Smith as Notation.Smith import qualified Test.HUnit import Test.HUnit((~?))@@ -42,32 +42,32 @@ \(direction, s) -> let move :: Component.Move.Move move = Component.QualifiedMove.getMove . Notation.Smith.getQualifiedMove $ read s- in Cartesian.Coordinates.extrapolate direction (Component.Move.getSource move) == Component.Move.interpolate move+ in Cartesian.Coordinates.extrapolate (Component.Move.getSource move) direction == Component.Move.interpolate move ) [ (- Attribute.Direction.ne, "a1h8"+ Direction.Direction.ne, "a1h8" ), (- Attribute.Direction.n, "a1a8"+ Direction.Direction.n, "a1a8" ), (- Attribute.Direction.e, "a1h1"+ Direction.Direction.e, "a1h1" ), (- Attribute.Direction.se, "a8h1"+ Direction.Direction.se, "a8h1" ), (- Attribute.Direction.s, "a8a1"+ Direction.Direction.s, "a8a1" ), (- Attribute.Direction.e, "a8h8"+ Direction.Direction.e, "a8h8" ), (- Attribute.Direction.sw, "h8a1"+ Direction.Direction.sw, "h8a1" ), (- Attribute.Direction.s, "h8h1"+ Direction.Direction.s, "h8h1" ), (- Attribute.Direction.w, "h8a8"+ Direction.Direction.w, "h8a8" ), (- Attribute.Direction.nw, "h1a8"+ Direction.Direction.nw, "h1a8" ), (- Attribute.Direction.n, "h1h8"+ Direction.Direction.n, "h1h8" ), (- Attribute.Direction.w, "h1a1"+ Direction.Direction.w, "h1a1" ) ] ~? "'BishBosh.Cartesian.Coordinates.extrapolate' is incompatible with 'BishBosh.Component.Move.interpolate'." ]
src-test/BishBosh/Test/HUnit/Component/Piece.hs view
@@ -28,10 +28,10 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -46,16 +46,16 @@ testCases = Test.HUnit.test [ Property.FixedMembership.members == Data.List.sort Component.Piece.range ~? "BishBosh.Component.Piece.range is misordered.", all (- == Data.List.sort (Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black)+ == Data.List.sort (Component.Piece.getAttackDirections $ Component.Piece.mkKing Colour.LogicalColour.Black) ) [- Data.List.sort $ Component.Piece.getAttackDirections $ Component.Piece.mkQueen Attribute.LogicalColour.Black,- Data.List.sort . uncurry (++) $ (Component.Piece.getAttackDirections . Component.Piece.mkBishop &&& Component.Piece.getAttackDirections . Component.Piece.mkRook) Attribute.LogicalColour.Black+ Data.List.sort $ Component.Piece.getAttackDirections $ Component.Piece.mkQueen Colour.LogicalColour.Black,+ Data.List.sort . uncurry (++) $ (Component.Piece.getAttackDirections . Component.Piece.mkBishop &&& Component.Piece.getAttackDirections . Component.Piece.mkRook) Colour.LogicalColour.Black ] ~? "'BishBosh.Component.Piece.getAttackDirections' failed to show Queen's moves to be union of Bishop & Rook.", "'BishBosh.Cartesian.Vector.attackVectorsForKing'." ~: (- length Cartesian.Vector.attackVectorsForKing ~?= length (Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black)+ length Cartesian.Vector.attackVectorsForKing ~?= length (Component.Piece.getAttackDirections $ Component.Piece.mkKing Colour.LogicalColour.Black) ), "'BishBosh.Component.Piece.getAttackDirections' failed for King." ~: Data.List.sort (- Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black {-arbitrarily-}+ Component.Piece.getAttackDirections $ Component.Piece.mkKing Colour.LogicalColour.Black {-arbitrarily-} ) ~?= Property.FixedMembership.members, all ( \((s, logicalColour), rank) -> let@@ -66,13 +66,13 @@ concat [ [ (- "a2b3", Attribute.LogicalColour.White+ "a2b3", Colour.LogicalColour.White ), (- "b3a4", Attribute.LogicalColour.White+ "b3a4", Colour.LogicalColour.White ), (- "a7b6", Attribute.LogicalColour.Black+ "a7b6", Colour.LogicalColour.Black ), (- "b6a5", Attribute.LogicalColour.Black+ "b6a5", Colour.LogicalColour.Black ) ] `zip` repeat Attribute.Rank.Pawn, (@@ -120,13 +120,13 @@ ) $ concat [ [ (- "a2a3", Attribute.LogicalColour.White+ "a2a3", Colour.LogicalColour.White ), (- "a2a4", Attribute.LogicalColour.White+ "a2a4", Colour.LogicalColour.White ), (- "a7a6", Attribute.LogicalColour.Black+ "a7a6", Colour.LogicalColour.Black ), (- "a7a5", Attribute.LogicalColour.Black+ "a7a5", Colour.LogicalColour.Black ) ] `zip` repeat Attribute.Rank.Pawn, (
src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -65,14 +65,14 @@ Component.QualifiedMove.getMove . fst {-qualifiedMove-} ) ( ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves matchSwitches (- mkGame moveStrings- ) . ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest False {-incrementalEvaluation-} (- Data.Default.def :: Component.Zobrist.Zobrist Type.Crypto.PositionHash- ) $ ContextualNotation.QualifiedMoveForest.fromPGNDatabase [- ContextualNotation.PGN.mkPGN' [] [- (ContextualNotation.PGN.dateTag, "2018.01.01")- ] game- ]+ ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest False {-incrementalEvaluation-} (+ Data.Default.def :: Component.Zobrist.Zobrist Type.Crypto.PositionHash+ ) $ ContextualNotation.QualifiedMoveForest.fromPGNDatabase [+ ContextualNotation.PGN.mkPGN' [] [+ (ContextualNotation.PGN.dateTag, "2018.01.01")+ ] game+ ]+ ) $ mkGame moveStrings ) ~?= [expectedMove] -- | Check the sanity of the implementation, by validating a list of static test-cases.
src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs view
@@ -29,7 +29,7 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.EitherQualifiedMove as Component.EitherQualifiedMove import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -90,7 +90,7 @@ ContextualNotation.StandardAlgebraic.fromQualifiedMove $ Component.QualifiedMove.mkQualifiedMove move moveType ) ( Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic.testCases:\tinvalid " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows move . showString "; " . show- ) $ Model.Game.validateEitherQualifiedMove eitherQualifiedMove game+ ) $ Model.Game.validateEitherQualifiedMove game eitherQualifiedMove _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic.testCases:\tfailed to read " $ shows s "." ) ["g1h3", "e2e3", "e2e4"] ++ map ( \(fen, nextLogicalColour, s, maybeMoveSuffixAnnotation) -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def s of@@ -105,58 +105,58 @@ ContextualNotation.StandardAlgebraic.fromQualifiedMove $ Component.QualifiedMove.mkQualifiedMove move moveType ) ( Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic.testCases:\tinvalid " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows move . showString "; " . show- ) $ Model.Game.validateEitherQualifiedMove eitherQualifiedMove game+ ) $ Model.Game.validateEitherQualifiedMove game eitherQualifiedMove _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic.testCases:\tfailed to read FEN" . Text.ShowList.showsAssociation $ show fen _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic.testCases:\tfailed to read " $ shows s "." ) [ ( "r3k2r/8/8/8/8/8/PPPPPPPP/RNBQK2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "e1g1c", -- O-O. Just "!" ), ( "rnbqk2r/pppppppp/8/8/8/8/8/R3K2R",- Attribute.LogicalColour.Black,+ Colour.LogicalColour.Black, "e8g8c", -- O-O. Just " ?" ), ( "r3k2r/8/8/8/8/8/PPPPPPPP/R3KBNR",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "e1c1C", -- O-O-O. Just "!!" ), ( "r3kbnr/pppppppp/8/8/8/8/8/R3K2R",- Attribute.LogicalColour.Black,+ Colour.LogicalColour.Black, "e8c8C", -- O-O-O. Just " !?" ), ( "r3kbnr/8/2R5/1RnR4/2R5/8/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "b5c5n", -- Rbxc5. Just "?!" ), ( "r3kbnr/8/2R5/1RnR4/2R5/8/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "c4c5n", -- R4xc5. Just "\t??" ), ( "r3kbnr/3N1N2/2N3N1/4b3/2N3N1/3N1N2/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "d3e5b", -- Nd3xe5. Nothing ), ( "r3kbnr/8/8/8/3r4/2P1P3/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "c3d4r", -- cxd4. Nothing ), ( "r3kbnr/1P6/8/8/8/8/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "b7b8N", -- b8=N. Nothing ), ( "r3kbnr/1P6/8/8/8/8/8/R3K2R",- Attribute.LogicalColour.White,+ Colour.LogicalColour.White, "b7a8rQ", -- bxa8=Q+. Nothing )
+ src-test/BishBosh/Test/HUnit/Direction/Direction.hs view
@@ -0,0 +1,46 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Static tests.+-}++module BishBosh.Test.HUnit.Direction.Direction(+-- * Constants+ testCases+) where++import qualified BishBosh.Direction.Direction as Direction.Direction+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified Data.List+import qualified Test.HUnit+import Test.HUnit((~?))++-- | Check the sanity of the implementation, by validating a list of static test-cases.+testCases :: Test.HUnit.Test+testCases = Test.HUnit.test [+ null (+ Direction.Direction.diagonals `Data.List.intersect` Direction.Direction.parallels+ ) ~? "BishBosh.Direction.Direction.[diagonal, parallels] intersect.",+ all (+ (== 2) . length . Direction.Direction.attackDirectionsForPawn+ ) Property.FixedMembership.members ~? "'BishBosh.Direction.Direction.attackDirectionsForPawn' failed."+ ]+
src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs view
@@ -28,19 +28,19 @@ ) where import Control.Arrow((&&&), (|||))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Component.Move as Component.Move-import qualified BishBosh.Component.Piece as Component.Piece-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness-import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation-import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator-import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker-import qualified BishBosh.Test.HUnit.Model.Game as Test.HUnit.Model.Game-import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator+import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.Test.HUnit.Model.Game as Test.HUnit.Model.Game+import qualified BishBosh.Text.ShowList as Text.ShowList import qualified Control.Exception import qualified Data.Default import qualified Test.HUnit@@ -65,7 +65,7 @@ ) Data.Default.def {-moveType-} ) ( Data.Default.def :: State.Board.Board- ) $ Cartesian.Coordinates.rooksStartingCoordinates Attribute.LogicalColour.White+ ) $ Cartesian.Coordinates.rooksStartingCoordinates Colour.LogicalColour.White ) ~?= 1, "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after moving White Queen's Rook." ~: case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a1a3" {-move Queen's Rook (illegally)-} of [(eitherQualifiedMove, "")] -> Evaluation.Fitness.measureValueOfCastlingPotential (
src-test/BishBosh/Test/HUnit/Input/Options.hs view
@@ -31,7 +31,6 @@ import Control.Category((>>>)) import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.Options as Input.Options-import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Data.List import qualified Data.Maybe@@ -80,9 +79,7 @@ (== Just (head optionsList)) ( (HXT.unpickleDoc HXT.xpickle . HXT.pickleDoc HXT.xpickle) =<< Data.Maybe.listToMaybe (- optionsList :: [- Input.Options.Options Type.Mass.PieceSquareValue- ]+ optionsList :: [Input.Options.Options] ) ) @? "Input.Options.pickler failed." ) . Data.Maybe.listToMaybe
src-test/BishBosh/Test/HUnit/Model/Game.hs view
@@ -32,10 +32,10 @@ import BishBosh.Model.Game((/~)) import Control.Arrow((&&&), (***), (|||)) import Data.Map((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Data.Exception as Data.Exception@@ -58,9 +58,7 @@ \s -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def {-Smith-} s of [(eitherQualifiedMove, "")] -> Right eitherQualifiedMove _ -> Left . shows s . showString " /~ " $ Notation.MoveNotation.showsMoveSyntax Data.Default.def ""- ) (- Data.Default.def :: Model.Game.Game- )+ ) Data.Default.def -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test@@ -86,7 +84,7 @@ $ (Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "r3k2r/8/8/8/8/8/8/R3K2R" :: Model.Game.Game) ) . ( \s -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def s of- [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove+ [(eitherQualifiedMove, "")] -> (`Model.Game.isValidEitherQualifiedMove` eitherQualifiedMove) _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t" . shows s . showString " /~ " $ Notation.MoveNotation.showsMoveSyntax Data.Default.def "" ) ) [@@ -94,7 +92,7 @@ "e1c1C" ] ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed when castling.", "'BishBosh.Model.Game.findQualifiedMovesAvailableToNextPlayer' failed" ~: Model.Game.findQualifiedMovesAvailableToNextPlayer (- Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "8/3K4/4q3/3bb3/8/8/8/4k3" :: Model.Game.Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "8/3K4/4q3/3bb3/8/8/8/4k3" ) ~?= [ Component.QualifiedMove.mkQualifiedMove ( Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 6)) `Component.Move.mkMove` Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 7))@@ -102,12 +100,10 @@ ], not ( Model.Game.isValidQualifiedMove (- Component.QualifiedMove.mkQualifiedMove (- Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** succ) `Component.Move.mkMove` Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 2))- ) $ Attribute.MoveType.mkNormalMoveType (Just Attribute.Rank.Pawn) Nothing- ) (- Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "4k3/8/8/8/1b6/3p4/3R4/4K3" :: Model.Game.Game- )+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "4k3/8/8/8/1b6/3p4/3R4/4K3"+ ) . Component.QualifiedMove.mkQualifiedMove (+ Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** succ) `Component.Move.mkMove` Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 2))+ ) $ Attribute.MoveType.mkNormalMoveType (Just Attribute.Rank.Pawn) Nothing ) ~? "'BishBosh.Model.Game.isValidQualifiedMove' failed", let pawnsCoordinates :: Cartesian.Coordinates.Coordinates@@ -141,7 +137,7 @@ \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "." ) ||| ( \game -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a5b6E" of- [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove game ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by White."+ [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove game eitherQualifiedMove ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by White." _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t /~ " $ Notation.MoveNotation.showsMoveSyntax Data.Default.def "" ) $ applyMoves [ "a2a4", -- White: Queen's Rook's Pawn.@@ -153,7 +149,7 @@ \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "." ) ||| ( \game -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a4b3E" of- [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove game ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by Black."+ [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove game eitherQualifiedMove ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by Black." _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed to parse move." ) $ applyMoves [ "b1c3", -- White: Queen's Knight.@@ -164,12 +160,12 @@ ], Data.Maybe.maybe False Rule.GameTerminationReason.isStaleMate ( Model.Game.getMaybeTerminationReason (- Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "rnbqk2r/pppppp2/8/8/8/7p/6np/6bK" :: Model.Game.Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "rnbqk2r/pppppp2/8/8/8/7p/6np/6bK" ) ) ~? "'BishBosh.Model.Game.getMaybeTerminationReason' failed to detect \"Stale-mate\".", all ( \s -> Data.Maybe.maybe False Rule.GameTerminationReason.isDrawByInsufficientMaterial $ Model.Game.getMaybeTerminationReason (- Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Model.Game.Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s ) ) [ "2k5/8/1KB5/3B4/8/8/8/8",@@ -178,7 +174,7 @@ ] ~? "'BishBosh.Model.Game.getMaybeTerminationReason' failed to detect \"Draw by Insufficient Material\".", all ( \s -> Data.Maybe.maybe True (not . Rule.GameTerminationReason.isDrawByInsufficientMaterial) $ Model.Game.getMaybeTerminationReason (- Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Model.Game.Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s ) ) [ "k7/8/K7/8/8/8/8/1Q6",@@ -195,7 +191,7 @@ \(moveString, s) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t" . showString moveString . showString "; " $ showString s "." ) ( uncurry (==) . (- Model.Game.sortAvailableQualifiedMoves . (! Attribute.LogicalColour.White) . Model.Game.getAvailableQualifiedMovesByLogicalColour &&& Model.Game.sortAvailableQualifiedMoves . Model.Game.mkAvailableQualifiedMovesFor Attribute.LogicalColour.White+ Model.Game.sortAvailableQualifiedMoves . (! Colour.LogicalColour.White) . Model.Game.getAvailableQualifiedMovesByLogicalColour &&& Model.Game.sortAvailableQualifiedMoves . (`Model.Game.mkAvailableQualifiedMovesFor` Colour.LogicalColour.White) ) ) . applyMoves $ words "g2g4 f7f6 g1h3 g7g5 h1g1 c7c6 d2d3 h7h5 c1d2 h5g4p d3d4 b8a6 f2f4 g4f3E" ) ~? "'BishBosh.Model.Game.getAvailableQualifiedMovesByLogicalColour' failed after En-passant.",@@ -258,9 +254,9 @@ let longCastle = "e1c1C" in case Notation.MoveNotation.readsQualifiedMove Data.Default.def longCastle of- [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove (- Property.ForsythEdwards.readFEN "r2qkbnr/ppp1pppp/2np4/5b2/3P4/NQP5/PP1BPPPP/R3KBNR w KQkq - 5 6" :: Model.Game.Game- ) ~? "long Castle through legal check failed."+ [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove (+ Property.ForsythEdwards.readFEN "r2qkbnr/ppp1pppp/2np4/5b2/3P4/NQP5/PP1BPPPP/R3KBNR w KQkq - 5 6"+ ) eitherQualifiedMove ~? "long Castle through legal check failed." _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed to parse " $ shows longCastle ".", let epds :: [String]@@ -289,7 +285,7 @@ let terminalMoves = map (Notation.Smith.getQualifiedMove . read) ["d6d8", "e7c7", "d6b6"] in all (- `elem` Model.Game.findQualifiedMovesAvailableTo minBound (Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "K7/4q1p1/3r4/8/8/5k2/8/8 b - - 13 49" :: Model.Game.Game)+ `elem` Model.Game.findQualifiedMovesAvailableTo (Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "K7/4q1p1/3r4/8/8/5k2/8/8 b - - 13 49" :: Model.Game.Game) minBound ) terminalMoves ~? "BishBosh.Test.HUnit.Model.Game.testCases:\tterminal move unavailable." ]
src-test/BishBosh/Test/HUnit/Model/GameTree.hs view
@@ -58,19 +58,19 @@ "'BishBosh.Model.GameTree.sortGameTree/MVVLVA' failed" ~: map ( \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn) ) (- sortAvailableMoves (Just Attribute.CaptureMoveSortAlgorithm.MVVLVA) testString- ) ~?= ["c4d5p","e4d5p","c3d5p","d1d5p","a1b1","c1b2","c1a3","c1d2","c1e3","c1f4","c1g5","c1h6","d1d2","d1d3","d1d4","d1e2","e1d2","e1e2","e1f1","g1e2","g1h3","a2a3","a2a4","g2g3","g2g4","h2h3","h2h4","b3b4","c3b1","c3b5","c3a4","c3e2","f3e2","f3g4","f3h5","c4c5","e4e5"],+ take 4 $ sortAvailableMoves (Just Attribute.CaptureMoveSortAlgorithm.MVVLVA) testString+ ) ~?= ["c4d5p","e4d5p","c3d5p","d1d5p"], "'BishBosh.Model.GameTree.sortGameTree/SEE' failed" ~: map ( \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn) ) (- sortAvailableMoves (Just Attribute.CaptureMoveSortAlgorithm.SEE) testString- ) ~?= ["c4d5p","e4d5p","a1b1","c1b2","c1a3","c1d2","c1e3","c1f4","c1g5","c1h6","d1d2","d1d3","d1d4","d1d5p","d1e2","e1d2","e1e2","e1f1","g1e2","g1h3","a2a3","a2a4","g2g3","g2g4","h2h3","h2h4","b3b4","c3b1","c3b5","c3a4","c3e2","c3d5p","f3e2","f3g4","f3h5","c4c5","e4e5"]+ take 3 $ sortAvailableMoves (Just Attribute.CaptureMoveSortAlgorithm.SEE) testString+ ) ~?= ["c4d5p","e4d5p","a1b1"] ] where sortAvailableMoves :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> String -> [Component.Turn.Turn] sortAvailableMoves maybeSortAlgorithm = Data.Maybe.mapMaybe ( Model.Game.maybeLastTurn . Data.Tree.rootLabel ) . Data.Tree.subForest . Model.GameTree.deconstruct . Model.GameTree.sortGameTree maybeSortAlgorithm (- `Input.RankValues.findRankValue` Input.RankValues.fromAssocs (+ Input.RankValues.findRankValue $ Input.RankValues.fromAssocs ( zip Property.FixedMembership.members $ map ( fromRational . (/ 10) -- Map into the closed unit-interval. ) [
src-test/BishBosh/Test/HUnit/Search/Search.hs view
@@ -43,7 +43,6 @@ import qualified BishBosh.Search.Search as Search.Search import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Control.Monad.Reader import qualified Data.Default@@ -52,7 +51,7 @@ import Test.HUnit((~?)) -- | Constant.-evaluationOptions :: Fractional pieceSquareValue => Input.EvaluationOptions.EvaluationOptions pieceSquareValue+evaluationOptions :: Input.EvaluationOptions.EvaluationOptions evaluationOptions = Input.EvaluationOptions.mkEvaluationOptions Data.Default.def {-rankValues-} Data.Default.def { Input.CriteriaWeights.getWeightOfMobility = fromRational $ 24 / 1000, Input.CriteriaWeights.getWeightOfCastlingPotential = fromRational $ 5 / 1000@@ -74,7 +73,7 @@ turnString = Notation.MoveNotation.showNotation Data.Default.def {-Smith-} $ case Search.Search.getQuantifiedGames $ Control.Monad.Reader.runReader ( Search.Search.search searchDepth $ Search.SearchState.initialise ( Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree (- evaluationOptions :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue+ evaluationOptions :: Input.EvaluationOptions.EvaluationOptions ) searchOptions Data.Default.def {-Zobrist-} Property.Empty.empty {-MoveFrequency-} game :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree Type.Crypto.PositionHash ) ) searchOptions of
src-test/BishBosh/Test/HUnit/State/Board.hs view
@@ -58,17 +58,17 @@ testCases = Test.HUnit.test [ "'BishBosh.Cartesian.Coordinates' failed to locate the expected pieces on a default board." ~: ( map length . ToolShed.Data.Foldable.gather $ map (- `State.MaybePieceByCoordinates.dereference` Data.Default.def+ State.MaybePieceByCoordinates.dereference Data.Default.def ) (Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates]) ) ~?= [32, 8, 2, 2, 2, 1, 1, 8, 2, 2, 2, 1, 1], let kingsColour = minBound destination = Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 3))- directionToCoordinates = last . (`Cartesian.Coordinates.extrapolate` destination)+ directionToCoordinates = last . Cartesian.Coordinates.extrapolate destination mkPiece = Component.Piece.mkPiece $ Property.Opposable.getOpposite kingsColour- maybeShift = Cartesian.Vector.maybeTranslate destination+ maybeShift = (`Cartesian.Vector.maybeTranslate` destination) in all (- State.Board.isKingChecked kingsColour . placePieces . (:) (Component.Piece.mkKing kingsColour, destination) . return {-to List-monad-}+ (`State.Board.isKingChecked` kingsColour) . placePieces . (:) (Component.Piece.mkKing kingsColour, destination) . return {-to List-monad-} ) ( concat [ Data.Maybe.mapMaybe (@@ -179,113 +179,113 @@ let whitePawnsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing maxBound (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates- ) $ placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkPawn maxBound,- whitePawnsCoordinates- ), (- Component.Piece.mkPawn minBound,- Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2)- )- ]+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkPawn maxBound,+ whitePawnsCoordinates+ ), (+ Component.Piece.mkPawn minBound,+ Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2)+ )+ ]+ ) maxBound . Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates ) ~? "'BishBosh.State.Board.exposesKing false positive attack by black Pawn, after moving White Pawn.", let whitePawnsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing maxBound (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates- ) $ placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkPawn maxBound,- whitePawnsCoordinates- ), (- Component.Piece.mkKing minBound,- Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2)- )- ]+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkPawn maxBound,+ whitePawnsCoordinates+ ), (+ Component.Piece.mkKing minBound,+ Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2)+ )+ ]+ ) maxBound . Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates ) ~? "'BishBosh.State.Board.exposesKing false positive attack by black King, after moving White Pawn.", let whiteBishopsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing maxBound (- Component.Move.mkMove whiteBishopsCoordinates $ Cartesian.Coordinates.translate (succ *** succ) whiteBishopsCoordinates -- Move towards Black Queen.- ) $ placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkBishop maxBound,- whiteBishopsCoordinates- ), (- Component.Piece.mkQueen minBound,- maxBound- )- ]+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkBishop maxBound,+ whiteBishopsCoordinates+ ), (+ Component.Piece.mkQueen minBound,+ maxBound+ )+ ]+ ) maxBound . Component.Move.mkMove whiteBishopsCoordinates $ Cartesian.Coordinates.translate (succ *** succ) whiteBishopsCoordinates -- Move towards Black Queen. ) ~? "'BishBosh.State.Board.exposesKing false positive attack by black Queen, after moving White Bishop.", let whitePawnsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ- in State.Board.exposesKing maxBound (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates -- Expose attack from Black Queen.- ) (- placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkPawn maxBound,- whitePawnsCoordinates- ), (- Component.Piece.mkQueen minBound,- maxBound- )- ]+ in (+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkPawn maxBound,+ whitePawnsCoordinates+ ), (+ Component.Piece.mkQueen minBound,+ maxBound+ )+ ]+ ) maxBound . Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates -- Expose attack from Black Queen. ) ~? "'BishBosh.State.Board.exposesKing failed after advancing White Pawn.", let whiteKnightsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ- in State.Board.exposesKing maxBound (- Component.Move.mkMove whiteKnightsCoordinates . Cartesian.Coordinates.mkRelativeCoordinates $ (+ 3) *** (+ 2) -- Expose attack from Black Queen.- ) (- placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkKnight maxBound,- whiteKnightsCoordinates- ), (- Component.Piece.mkQueen minBound,- maxBound- )- ]+ in (+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkKnight maxBound,+ whiteKnightsCoordinates+ ), (+ Component.Piece.mkQueen minBound,+ maxBound+ )+ ]+ ) maxBound . Component.Move.mkMove whiteKnightsCoordinates . Cartesian.Coordinates.mkRelativeCoordinates $ (+ 3) *** (+ 2) -- Expose attack from Black Queen. ) ~? "'BishBosh.State.Board.exposesKing failed after moving White Knight.", let whiteRooksCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2) in not (- State.Board.exposesKing maxBound (- Component.Move.mkMove whiteRooksCoordinates $ Cartesian.Coordinates.advance maxBound whiteRooksCoordinates -- Shift blocking-role to Pawn.- ) $ placePieces [- (- Component.Piece.mkKing maxBound,- minBound- ), (- Component.Piece.mkPawn maxBound,- Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ- ), (- Component.Piece.mkRook maxBound,- whiteRooksCoordinates- ), (- Component.Piece.mkQueen minBound,- maxBound- )- ]+ State.Board.exposesKing (+ placePieces [+ (+ Component.Piece.mkKing maxBound,+ minBound+ ), (+ Component.Piece.mkPawn maxBound,+ Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ+ ), (+ Component.Piece.mkRook maxBound,+ whiteRooksCoordinates+ ), (+ Component.Piece.mkQueen minBound,+ maxBound+ )+ ]+ ) maxBound . Component.Move.mkMove whiteRooksCoordinates $ Cartesian.Coordinates.advance maxBound whiteRooksCoordinates -- Shift blocking-role to Pawn. ) ~? "'BishBosh.State.Board.exposesKing failed after moving White Rook.", Data.Foldable.all ( Data.Foldable.all (== 1)
− src-test/BishBosh/Test/QuickCheck/Attribute/Direction.hs
@@ -1,87 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.--}--module BishBosh.Test.QuickCheck.Attribute.Direction(--- * Constants- results-) where--import Control.Arrow((&&&))-import qualified BishBosh.Attribute.Direction as Attribute.Direction-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Orientated as Property.Orientated-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified Test.QuickCheck-import qualified ToolShed.Test.ReversibleIO--instance Test.QuickCheck.Arbitrary Attribute.Direction.Direction where- arbitrary = Test.QuickCheck.elements Property.FixedMembership.members---- | The constant test-results for this data-type.-results :: IO [Test.QuickCheck.Result]-results = sequence [- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_readPrependedWhiteSpace" . ToolShed.Test.ReversibleIO.readPrependedWhiteSpace- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: String -> Test.QuickCheck.Property- f garbage = Test.QuickCheck.label "Direction.prop_read" $ case (reads garbage :: [(Attribute.Direction.Direction, String)]) of- [_] -> True- _ -> True -- Unless the read-implementation throws an exception.- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: Attribute.Direction.Direction -> String -> Test.QuickCheck.Property- f direction = Test.QuickCheck.label "Direction.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` "ewEW") direction- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_reflectOnY" . uncurry (==) . (id &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnY)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_getOpposite/Reflectable" . uncurry (==) . (Property.Opposable.getOpposite &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnX)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_areAligned" . uncurry Attribute.Direction.areAligned . (id &&& Property.Opposable.getOpposite)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,- let- f :: Attribute.Direction.Direction -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Direction.prop_isParallel" . uncurry (/=) . (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f- ]---
− src-test/BishBosh/Test/QuickCheck/Attribute/LogicalColour.hs
@@ -1,56 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.--}--module BishBosh.Test.QuickCheck.Attribute.LogicalColour(--- * Constants- results-) where--import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Test.QuickCheck--instance Test.QuickCheck.Arbitrary Attribute.LogicalColour.LogicalColour where- arbitrary = Test.QuickCheck.elements Property.FixedMembership.members---- | The constant test-results for this data-type.-results :: IO [Test.QuickCheck.Result]-results = sequence [- let- f :: Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property- f = Test.QuickCheck.label "LogicalColour.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4 } f,- let- f :: Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property- f logicalColour = Test.QuickCheck.label "LogicalColour.prop_fen" $ case Property.ForsythEdwards.readsFEN $ Property.ForsythEdwards.showFEN logicalColour of- [(logicalColour', "")] -> logicalColour' == logicalColour- _ -> False- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4 } f- ]--
src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs view
@@ -28,16 +28,16 @@ results ) where -import BishBosh.Test.QuickCheck.Attribute.Direction()+import BishBosh.Test.QuickCheck.Direction.Direction() import Control.Arrow((&&&))-import qualified BishBosh.Attribute.Direction as Attribute.Direction import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Direction.Direction as Direction.Direction import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.Orientated as Property.Orientated import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.Property.Rotatable as Property.Rotatable-import qualified Data.Array.IArray import qualified Data.List import qualified Data.List.Extra import qualified Test.QuickCheck@@ -77,7 +77,7 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property- f coordinates = Test.QuickCheck.label "Coordinates.prop_fromIx" $ Cartesian.Coordinates.fromIx (Data.Array.IArray.index (minBound, maxBound) coordinates) == coordinates+ f coordinates = Test.QuickCheck.label "Coordinates.prop_enum" $ toEnum (fromEnum coordinates) == coordinates in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property@@ -89,10 +89,6 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Coordinates.prop_rotate180" . uncurry (==) . (Property.Rotatable.rotate180 &&& Property.Rotatable.rotate180)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,- let- f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f coordinates = Test.QuickCheck.label "Coordinates.prop_rotateIdentity" $ all ((== coordinates) . ($ coordinates)) [ Property.Rotatable.rotate90 . Property.Rotatable.rotate90 . Property.Rotatable.rotate90 . Property.Rotatable.rotate90, Property.Rotatable.rotate180 . Property.Rotatable.rotate180,@@ -108,7 +104,15 @@ ] in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Attribute.Direction.Direction -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Coordinates.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Coordinates.prop_getOpposite/Reflectable" . uncurry (==) . (Property.Opposable.getOpposite &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnX)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f direction source = Test.QuickCheck.label "Coordinates.prop_extrapolate" . ( \extrapolation -> let destination@@ -117,7 +121,7 @@ in source == destination || source : extrapolation == reverse ( destination : Cartesian.Coordinates.interpolate destination source )- ) $ Cartesian.Coordinates.extrapolate direction source+ ) $ Cartesian.Coordinates.extrapolate source direction in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property@@ -132,6 +136,12 @@ null &&& (== 1) . length . Data.List.nub . map Cartesian.Coordinates.getLogicalColourOfSquare ) )- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Coordinates.prop_applyAlongDirectionsFrom" . uncurry (==) . (+ flip (Cartesian.Coordinates.applyAlongDirectionsFrom id) Nothing &&& flip (Cartesian.Coordinates.applyAlongDirectionsFrom id) (Just Property.FixedMembership.members)+ )+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f ]
src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs view
@@ -31,13 +31,14 @@ import BishBosh.Test.QuickCheck.Cartesian.Coordinates() import Control.Arrow((&&&), (***))-import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate-import qualified BishBosh.Cartesian.Vector as Cartesian.Vector-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Orientated as Property.Orientated-import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Type.Length as Type.Length+import qualified Data.Maybe import qualified Test.QuickCheck import Test.QuickCheck((==>)) @@ -60,26 +61,34 @@ f = Test.QuickCheck.label "Vector.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property+ f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property f = Test.QuickCheck.label "Vector.prop_orthogonal" . not . uncurry (&&) . (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property- f vector = not (Property.Orientated.isStraight vector) ==> Test.QuickCheck.label "Vector.prop_straight" . not . uncurry (||) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) vector+ f vector = not (Property.Orientated.isStraight vector) ==> Test.QuickCheck.label "Vector.prop_(not isStraight => not (isDiagonal || isParallel))" . not . uncurry (||) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) vector in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let+ f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property+ f vector = Property.Orientated.isStraight vector ==> Test.QuickCheck.label "Vector.prop_(isStraight => isDiagonal /= isParallel)" . uncurry (/=) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) vector+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property+ f vector = Property.Orientated.isParallel vector ==> Test.QuickCheck.label "Vector.prop_(isParallel => isHorizontal /= isVertical)" . uncurry (/=) $ (Property.Orientated.isHorizontal &&& Property.Orientated.isVertical) vector+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let f :: (Type.Length.X, Type.Length.Y) -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f (distanceX, distanceY) coordinates = Test.QuickCheck.label "Vector.prop_maybeTranslate" $ Cartesian.Coordinates.maybeTranslate (deltaX *** deltaY) coordinates == ( Cartesian.Coordinates.maybeTranslateX deltaX coordinates >>= Cartesian.Coordinates.maybeTranslateY deltaY ) where- deltaX :: Type.Length.X -> Type.Length.X+ deltaX :: Type.Length.X -> Type.Length.X deltaX = ( + ( (distanceX `mod` Cartesian.Abscissa.xLength) - (Cartesian.Abscissa.xLength `div` 2) ) ) -- Section. - deltaY :: Type.Length.Y -> Type.Length.Y+ deltaY :: Type.Length.Y -> Type.Length.Y deltaY = ( + ( (distanceY `mod` Cartesian.Ordinate.yLength) - (Cartesian.Ordinate.yLength `div` 2)@@ -88,14 +97,20 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property- f source destination = Test.QuickCheck.label "Vector.prop_measureDistance => translate" $ Cartesian.Vector.translate source (- Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.Vector- ) == destination+ f source destination = Test.QuickCheck.label "Vector.prop_measureDistance => translate" $ Cartesian.Vector.translate (+ Cartesian.Vector.measureDistance source destination+ ) source == destination in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f source destination = Test.QuickCheck.label "Vector.prop_translate" $ Cartesian.Vector.measureDistance source destination == Property.Opposable.getOpposite (- Cartesian.Vector.measureDistance destination source :: Cartesian.Vector.Vector+ Cartesian.Vector.measureDistance destination source+ )+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let+ f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Vector.prop_toMaybeDirection" . uncurry (==) . (+ Data.Maybe.isJust . Cartesian.Vector.toMaybeDirection &&& Property.Orientated.isStraight ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
+ src-test/BishBosh/Test/QuickCheck/Colour/LogicalColour.hs view
@@ -0,0 +1,56 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.Colour.LogicalColour(+-- * Constants+ results+) where++import Control.Arrow((&&&))+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Colour.LogicalColour.LogicalColour where+ arbitrary = Test.QuickCheck.elements Property.FixedMembership.members++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Colour.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "LogicalColour.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4 } f,+ let+ f :: Colour.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f logicalColour = Test.QuickCheck.label "LogicalColour.prop_fen" $ case Property.ForsythEdwards.readsFEN $ Property.ForsythEdwards.showFEN logicalColour of+ [(logicalColour', "")] -> logicalColour' == logicalColour+ _ -> False+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4 } f+ ]++
src-test/BishBosh/Test/QuickCheck/Component/Move.hs view
@@ -60,16 +60,24 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Component.Move.Move -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Move.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let+ f :: Component.Move.Move -> Test.QuickCheck.Property f = Test.QuickCheck.label "Move.prop_orthogonal" . not . uncurry (&&) . (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Component.Move.Move -> Test.QuickCheck.Property- f move = not (Property.Orientated.isStraight move) ==> Test.QuickCheck.label "Move.prop_straight" . not . uncurry (||) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) move+ f move = not (Property.Orientated.isStraight move) ==> Test.QuickCheck.label "Move.prop_(not isStraight => not (isDiagonal || isParallel))" . not . uncurry (||) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) move in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Component.Move.Move -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Move.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ f move = Property.Orientated.isStraight move ==> Test.QuickCheck.label "Move.prop_(isStraight => isDiagonal /= isParallel)" . uncurry (/=) $ (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel) move+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Component.Move.Move -> Test.QuickCheck.Property+ f move = Property.Orientated.isParallel move ==> Test.QuickCheck.label "Move.prop_(isParallel => isHorizontal /= isVertical)" . uncurry (/=) $ (Property.Orientated.isHorizontal &&& Property.Orientated.isVertical) move+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f, let f :: Component.Move.Move -> Test.QuickCheck.Property f move = Test.QuickCheck.label "Move.prop_measureDistance" $ Component.Move.measureDistance (Property.Opposable.getOpposite move) == Property.Opposable.getOpposite (Component.Move.measureDistance move)
src-test/BishBosh/Test/QuickCheck/Component/QualifiedMove.hs view
@@ -37,7 +37,7 @@ import qualified ToolShed.Test.ReversibleIO instance Test.QuickCheck.Arbitrary Component.QualifiedMove.QualifiedMove where- arbitrary = uncurry Component.QualifiedMove.mkQualifiedMove `fmap` Test.QuickCheck.arbitrary -- CAVEAT: the move & moveType are unlikely to be compatible.+ arbitrary = uncurry Component.QualifiedMove.mkQualifiedMove <$> Test.QuickCheck.arbitrary -- CAVEAT: the move & moveType are unlikely to be compatible. -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/BishBosh/Test/QuickCheck/Component/Turn.hs view
@@ -29,8 +29,8 @@ results ) where -import BishBosh.Test.QuickCheck.Attribute.LogicalColour() import BishBosh.Test.QuickCheck.Attribute.MoveType()+import BishBosh.Test.QuickCheck.Colour.LogicalColour() import BishBosh.Test.QuickCheck.Component.Move() import BishBosh.Test.QuickCheck.Component.Piece() import BishBosh.Test.QuickCheck.Input.RankValues()@@ -94,7 +94,7 @@ f :: Input.RankValues.RankValues -> [Component.Turn.Turn] -> Test.QuickCheck.Property f rankValues' = Test.QuickCheck.label "Turn.prop_compareByMVVLVA/quiet" . uncurry (==) . ( dropWhile Component.Turn.isCapture . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues')+ Component.Turn.compareByMVVLVA $ Input.RankValues.findRankValue rankValues' ) &&& filter ( not . Component.Turn.isCapture )@@ -104,12 +104,12 @@ f :: [Component.Turn.Turn] -> Test.QuickCheck.Property f = Test.QuickCheck.label "Turn.prop_compareByMVVLVA/MVV" . ( \ranks -> Data.List.sortOn (- negate . toRational . (`Input.RankValues.findRankValue` rankValues) -- Most valuable victim should be first.+ negate . toRational . Input.RankValues.findRankValue rankValues -- Most valuable victim should be first. ) ranks == ranks ) . map head . Data.List.group . Data.Maybe.mapMaybe ( Attribute.MoveType.getMaybeImplicitlyTakenRank . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove ) . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues)+ Component.Turn.compareByMVVLVA $ Input.RankValues.findRankValue rankValues ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let@@ -118,14 +118,14 @@ ( \ranks -> uncurry (++) ( Control.Arrow.first (- Data.List.sortOn (`Input.RankValues.findRankValue` rankValues) -- Least valuable aggressor should be first.+ Data.List.sortOn $ Input.RankValues.findRankValue rankValues -- Least valuable aggressor should be first. ) $ Data.List.partition (/= Attribute.Rank.King) ranks ) == ranks ) . map head . Data.List.group . map Component.Turn.getRank {-aggressor's rank-} ) . Data.List.groupBy ( ToolShed.Data.List.equalityBy $ Attribute.MoveType.getMaybeImplicitlyTakenRank . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove ) . takeWhile Component.Turn.isCapture . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues)+ Component.Turn.compareByMVVLVA $ Input.RankValues.findRankValue rankValues ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f ]
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -66,7 +66,9 @@ ( == Component.QualifiedMove.getMove (Component.Turn.getQualifiedMove lastTurn) ) . Component.QualifiedMove.getMove . fst {-qualifiedMove-}- ) . ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches previousGame $ ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest incrementalEvaluation zobrist qualifiedMoveForest+ ) $ ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches (+ ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest incrementalEvaluation zobrist qualifiedMoveForest+ ) previousGame ) . head . Model.Game.rollBack ) . tail {-drop the default game-} . Data.Tree.flatten . Model.GameTree.deconstruct $ ContextualNotation.QualifiedMoveForest.toGameTree qualifiedMoveForest in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f
+ src-test/BishBosh/Test/QuickCheck/Direction/Direction.hs view
@@ -0,0 +1,116 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.Direction.Direction(+-- * Constants+ results+) where++import Control.Arrow((&&&))+import qualified BishBosh.Direction.Direction as Direction.Direction+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Orientated as Property.Orientated+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.Rotatable as Property.Rotatable+import qualified Data.List.Extra+import qualified Test.QuickCheck+import qualified ToolShed.Test.ReversibleIO+import Test.QuickCheck((==>))++instance Test.QuickCheck.Arbitrary Direction.Direction.Direction where+ arbitrary = Test.QuickCheck.elements Property.FixedMembership.members++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_readPrependedWhiteSpace" . ToolShed.Test.ReversibleIO.readPrependedWhiteSpace+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: String -> Test.QuickCheck.Property+ f garbage = Test.QuickCheck.label "Direction.prop_read" $ case (reads garbage :: [(Direction.Direction.Direction, String)]) of+ [_] -> True+ _ -> True -- Unless the read-implementation throws an exception.+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Direction.Direction.Direction -> String -> Test.QuickCheck.Property+ f direction = Test.QuickCheck.label "Direction.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` "EW") direction+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_orthogonal" . not . uncurry (&&) . (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f direction = Property.Orientated.isDiagonal direction ==> Test.QuickCheck.label "Direction.prop_(isDiagonal => not (isHorizontal || isVertical))" . not . uncurry (||) $ (Property.Orientated.isHorizontal &&& Property.Orientated.isVertical) direction+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_(isDiagonal /= isParallel)" . uncurry (/=) . (Property.Orientated.isDiagonal &&& Property.Orientated.isParallel)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f direction = Property.Orientated.isParallel direction ==> Test.QuickCheck.label "Direction.prop_(isParallel => isHorizontal /= isVertical)" . uncurry (/=) $ (Property.Orientated.isHorizontal &&& Property.Orientated.isVertical) direction+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_reflectOnY" . uncurry (==) . (id &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnY)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f direction = Test.QuickCheck.label "Direction.prop_rotateIdentity" $ all ((== direction) . ($ direction)) [+ Property.Rotatable.rotate90 . Property.Rotatable.rotate90 . Property.Rotatable.rotate90 . Property.Rotatable.rotate90,+ Property.Rotatable.rotate180 . Property.Rotatable.rotate180,+ Property.Rotatable.rotate270 . Property.Rotatable.rotate270 . Property.Rotatable.rotate270 . Property.Rotatable.rotate270+ ]+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f direction = Test.QuickCheck.label "Direction.prop_rotate180/identity" . Data.List.Extra.allSame $ map ($ direction) [+ Property.Rotatable.rotate180,+ Property.Rotatable.rotate90 . Property.Rotatable.rotate90,+ Property.Rotatable.rotate270 . Property.Rotatable.rotate270+ ]+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_getOpposite/Reflectable" . uncurry (==) . (Property.Opposable.getOpposite &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnX)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f,+ let+ f :: Direction.Direction.Direction -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Direction.prop_areAligned" . uncurry Direction.Direction.areAligned . (id &&& Property.Opposable.getOpposite)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f+ ]+
src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -27,16 +27,17 @@ results ) where +import BishBosh.Test.QuickCheck.Input.EvaluationOptions() import BishBosh.Test.QuickCheck.Input.SearchOptions() import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame+import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.State.Position as State.Position import qualified BishBosh.Test.QuickCheck.Component.Zobrist as Test.QuickCheck.Component.Zobrist-import qualified BishBosh.Test.QuickCheck.Input.EvaluationOptions as Test.QuickCheck.Input.EvaluationOptions import qualified BishBosh.Type.Crypto as Type.Crypto import qualified BishBosh.Type.Mass as Type.Mass import qualified Data.List.Extra@@ -50,7 +51,7 @@ results = sequence [ let f- :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions+ :: Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game@@ -68,7 +69,7 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let f- :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions+ :: Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game
src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward@@ -24,9 +25,6 @@ -} module BishBosh.Test.QuickCheck.Input.EvaluationOptions(--- * Types--- ** Type-synonyms- EvaluationOptions, -- * Constants results ) where@@ -36,14 +34,12 @@ import BishBosh.Test.QuickCheck.Input.RankValues() import BishBosh.Test.QuickCheck.State.Board() import Control.Arrow((&&&))-import qualified BishBosh.Component.Accountant as Component.Accountant import qualified BishBosh.Input.CriteriaWeights as Input.CriteriaWeights import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Input.PieceSquareTable as Input.PieceSquareTable import qualified BishBosh.Input.RankValues as Input.RankValues import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.Type.Mass as Type.Mass import qualified Data.Array.IArray import qualified Data.List import qualified Data.Map.Strict as Map@@ -51,15 +47,12 @@ import qualified Test.QuickCheck import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type EvaluationOptions = Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue+#ifdef USE_PRECISION+import qualified BishBosh.Component.Accountant as Component.Accountant+import qualified BishBosh.Type.Mass as Type.Mass+#endif -instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.EvaluationOptions.EvaluationOptions pieceSquareValue) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary EvaluationOptions #-}+instance Test.QuickCheck.Arbitrary Input.EvaluationOptions.EvaluationOptions where arbitrary = do rankValues <- Test.QuickCheck.arbitrary criteriaWeights <- Test.QuickCheck.suchThat Test.QuickCheck.arbitrary $ \c -> Input.RankValues.calculateMaximumTotalValue rankValues /= 0 || Input.CriteriaWeights.getWeightOfMaterial c == 0@@ -79,22 +72,25 @@ -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [+#ifdef USE_PRECISION let- f :: EvaluationOptions -> State.Board.Board -> Test.QuickCheck.Property- f evaluationOptions board = Data.Maybe.isJust maybePieceSquareByCoordinatesByRank ==> Test.QuickCheck.label "EvaluationOptions.prop_sumPieceSquareValueByLogicalColour/reflectOnX" . uncurry (==) $ (- Data.Array.IArray.elems . sumPieceSquareValueByLogicalColour &&& reverse . Data.Array.IArray.elems . sumPieceSquareValueByLogicalColour . Property.Reflectable.reflectOnX+ f :: Input.EvaluationOptions.EvaluationOptions -> State.Board.Board -> Test.QuickCheck.Property+ f evaluationOptions board = Data.Maybe.isJust maybePieceSquareByCoordinatesByRank ==> Test.QuickCheck.label "EvaluationOptions.prop_sumPieceSquareValueByLogicalColour" . uncurry (==) $ (+ sumPieceSquareValueByLogicalColour' . State.Board.getCoordinatesByRankByLogicalColour &&& sumPieceSquareValueByLogicalColour' . State.Board.getMaybePieceByCoordinates ) board where maybePieceSquareByCoordinatesByRank = Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions- sumPieceSquareValueByLogicalColour = State.Board.sumPieceSquareValueByLogicalColour $ Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f,++ sumPieceSquareValueByLogicalColour' :: Component.Accountant.Accountant accountant => accountant -> [Type.Mass.Base]+ sumPieceSquareValueByLogicalColour' = flip (Component.Accountant.sumPieceSquareValueByLogicalColour $ Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank) $ State.Board.getNPieces board+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+#endif let- f :: Input.EvaluationOptions.EvaluationOptions Rational {-precision is required-} -> State.Board.Board -> Test.QuickCheck.Property- f evaluationOptions board = Data.Maybe.isJust maybePieceSquareByCoordinatesByRank ==> Test.QuickCheck.label "EvaluationOptions.prop_sumPieceSquareValueByLogicalColour" . uncurry (==) $ (- Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces . State.Board.getCoordinatesByRankByLogicalColour &&& Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces . State.Board.getMaybePieceByCoordinates+ f :: Input.EvaluationOptions.EvaluationOptions -> State.Board.Board -> Test.QuickCheck.Property+ f evaluationOptions board = Data.Maybe.isJust maybePieceSquareByCoordinatesByRank ==> Test.QuickCheck.label "EvaluationOptions.prop_sumPieceSquareValueByLogicalColour/reflectOnX" . uncurry (==) $ (+ Data.Array.IArray.elems . sumPieceSquareValueByLogicalColour &&& reverse . Data.Array.IArray.elems . sumPieceSquareValueByLogicalColour . Property.Reflectable.reflectOnX ) board where maybePieceSquareByCoordinatesByRank = Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions- pieceSquareByCoordinatesByRank = Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank- nPieces = State.Board.getNPieces board- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f+ sumPieceSquareValueByLogicalColour = State.Board.sumPieceSquareValueByLogicalColour $ Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f ]
src-test/BishBosh/Test/QuickCheck/Input/Options.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Input.Options(--- * Types--- ** Type-synonyms--- Options, -- * Constants results ) where@@ -37,23 +34,14 @@ import qualified BishBosh.Input.IOOptions as Input.IOOptions import qualified BishBosh.Input.Options as Input.Options import qualified BishBosh.Input.SearchOptions as Input.SearchOptions-import qualified BishBosh.Type.Mass as Type.Mass import qualified Test.QuickCheck --- | Defines a concrete type for testing.-type Options = Input.Options.Options Type.Mass.PieceSquareValue--instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.Options.Options pieceSquareValue) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Options #-}+instance Test.QuickCheck.Arbitrary Input.Options.Options where arbitrary = do (maybeMaximumPlies, maybeRandomSeed, evaluationOptions, searchOptions, ioOptions) <- Test.QuickCheck.arbitrary return {-to Gen-monad-} $ Input.Options.mkOptions (- fmap (fromInteger . succ . abs) maybeMaximumPlies+ fromInteger . succ . abs <$> maybeMaximumPlies ) maybeRandomSeed evaluationOptions ( if null $ Input.IOOptions.getPGNOptionsList ioOptions then searchOptions {@@ -66,7 +54,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Options -> Test.QuickCheck.Property+ f :: Input.Options.Options -> Test.QuickCheck.Property f options = Test.QuickCheck.label "Options.prop_swapSearchDepth" $ Input.Options.swapSearchDepth (Input.Options.swapSearchDepth options) == options in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f ]
src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs view
@@ -24,32 +24,19 @@ -} module BishBosh.Test.QuickCheck.Input.PieceSquareTable(--- * Types--- ** Type-synonyms--- PieceSquareTable, -- * Constants results ) where import BishBosh.Test.QuickCheck.Attribute.Rank()-import qualified BishBosh.Attribute.Rank as Attribute.Rank+import BishBosh.Test.QuickCheck.Type.Mass() import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Input.PieceSquareTable as Input.PieceSquareTable import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Type.Mass as Type.Mass-import qualified Data.List import qualified Test.QuickCheck-import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type PieceSquareTable = Input.PieceSquareTable.PieceSquareTable Type.Mass.PieceSquareValue--instance (- Fractional pieceSquareValue,- Ord pieceSquareValue,- Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.PieceSquareTable.PieceSquareTable pieceSquareValue) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary PieceSquareTable #-}+instance Test.QuickCheck.Arbitrary Input.PieceSquareTable.PieceSquareTable where arbitrary = do reflectOnY <- Test.QuickCheck.arbitrary @@ -71,11 +58,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Input.PieceSquareTable.Assocs Attribute.Rank.Rank Type.Mass.PieceSquareValue -> Test.QuickCheck.Property- f assocs = length (Data.List.nub $ concatMap snd assocs) > 1 ==> Test.QuickCheck.label "PieceSquareTable.prop_closedUnitInterval" . Input.PieceSquareTable.inClosedUnitInterval $ Input.PieceSquareTable.normaliseToUnitInterval assocs- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: (Int, Int, Int, Int) -> Test.QuickCheck.Property+ f :: (Type.Mass.PieceSquareValue, Type.Mass.PieceSquareValue, Type.Mass.PieceSquareValue, Type.Mass.PieceSquareValue) -> Test.QuickCheck.Property f (a, b, c, d) = Test.QuickCheck.label "PieceSquareTable.prop_mirror" . (== l) . Input.PieceSquareTable.unmirror $ Input.PieceSquareTable.mirror l where l = [a, b, c, d] in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f
src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs view
@@ -26,7 +26,7 @@ module BishBosh.Test.QuickCheck.Input.SearchOptions() where import BishBosh.Test.QuickCheck.Attribute.CaptureMoveSortAlgorithm()-import BishBosh.Test.QuickCheck.Attribute.LogicalColour()+import BishBosh.Test.QuickCheck.Colour.LogicalColour() import BishBosh.Test.QuickCheck.Input.StandardOpeningOptions() import Control.Arrow((***)) import qualified BishBosh.Input.SearchOptions as Input.SearchOptions
src-test/BishBosh/Test/QuickCheck/Model/Game.hs view
@@ -29,35 +29,36 @@ results ) where +import BishBosh.Test.QuickCheck.Input.EvaluationOptions() import Control.Arrow((&&&))-import qualified BishBosh.Attribute.MoveType as Attribute.MoveType-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Component.Move as Component.Move-import qualified BishBosh.Component.Piece as Component.Piece-import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove-import qualified BishBosh.Component.Turn as Component.Turn-import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness-import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions-import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards-import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Rule.DrawReason as Rule.DrawReason-import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour-import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour-import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates-import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker-import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Test.QuickCheck.Input.EvaluationOptions as Test.QuickCheck.Input.EvaluationOptions-import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Component.Turn as Component.Turn+import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness+import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards+import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Rule.DrawReason as Rule.DrawReason+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour+import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour+import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates+import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Array.IArray import qualified Data.Default import qualified Data.Foldable import qualified Data.List-import qualified Data.Map as Map+import qualified Data.Map as Map import qualified Data.Maybe import qualified Data.Ord import qualified System.Random@@ -76,9 +77,7 @@ ) . Data.Maybe.fromJust . ToolShed.System.Random.select randomGen $ Model.Game.findQualifiedMovesAvailableToNextPlayer game play game _ = game -- Terminate recursion. in Test.QuickCheck.arbitrary >>= (- \randomGens -> (- play Data.Default.def . (`take` ToolShed.System.Random.randomGens (System.Random.mkStdGen randomGens))- ) `fmap` Test.QuickCheck.choose (1 :: Int, 64)+ \randomGens -> play Data.Default.def . (`take` ToolShed.System.Random.randomGens (System.Random.mkStdGen randomGens)) <$> Test.QuickCheck.choose (1 :: Int, 64) ) -- | The constant test-results for this data-type.@@ -131,7 +130,7 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Model.Game.Game -> Test.QuickCheck.Property- f game = not (Model.Game.isTerminated game) ==> Test.QuickCheck.label "Game.prop_isValidQualifiedMove" . all (`Model.Game.isValidQualifiedMove` game) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game+ f game = not (Model.Game.isTerminated game) ==> Test.QuickCheck.label "Game.prop_isValidQualifiedMove" . all (Model.Game.isValidQualifiedMove game) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4096 } f, let f :: Model.Game.Game -> Test.QuickCheck.Property@@ -145,11 +144,11 @@ destination <- Property.FixedMembership.members, source /= destination, let move = Component.Move.mkMove source destination,- maybePromotionRank <- if Data.Maybe.maybe False (Component.Piece.isPawnPromotion destination) $ State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates+ maybePromotionRank <- if Data.Maybe.maybe False (`Component.Piece.isPawnPromotion` destination) $ State.MaybePieceByCoordinates.dereference maybePieceByCoordinates source then map Just Attribute.Rank.promotionProspects else [Nothing],- let qualifiedMove = Component.QualifiedMove.mkQualifiedMove move $ State.MaybePieceByCoordinates.inferMoveType move maybePromotionRank maybePieceByCoordinates,- Model.Game.isValidQualifiedMove qualifiedMove game+ let qualifiedMove = Component.QualifiedMove.mkQualifiedMove move $ State.MaybePieceByCoordinates.inferMoveType maybePieceByCoordinates move maybePromotionRank,+ Model.Game.isValidQualifiedMove game qualifiedMove ] {-list-comprehension-} where sort = Data.List.sortBy $ Data.Ord.comparing Component.QualifiedMove.getMove board = Model.Game.getBoard game@@ -160,7 +159,7 @@ f game = Test.QuickCheck.label "Game.prop_inferMoveType" . all ( \qualifiedMove -> let moveType = Component.QualifiedMove.getMoveType qualifiedMove- inferredMoveType = State.MaybePieceByCoordinates.inferMoveType (Component.QualifiedMove.getMove qualifiedMove) Nothing {-promotion-rank-} . State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard game+ inferredMoveType = State.MaybePieceByCoordinates.inferMoveType (State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard game) (Component.QualifiedMove.getMove qualifiedMove) Nothing {-promotion-rank-} in if Attribute.MoveType.isPromotion moveType then Attribute.MoveType.isPromotion inferredMoveType && Attribute.MoveType.getMaybeExplicitlyTakenRank moveType == Attribute.MoveType.getMaybeExplicitlyTakenRank inferredMoveType else moveType == inferredMoveType@@ -176,12 +175,6 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Model.Game.Game -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Game.prop_mkCoordinatesByRankByLogicalColour" . uncurry (==) . (- State.CoordinatesByRankByLogicalColour.deconstruct . State.CoordinatesByRankByLogicalColour.sortCoordinates . State.Board.getCoordinatesByRankByLogicalColour &&& State.CoordinatesByRankByLogicalColour.deconstruct . State.CoordinatesByRankByLogicalColour.sortCoordinates . State.CoordinatesByRankByLogicalColour.fromMaybePieceByCoordinates . State.Board.getMaybePieceByCoordinates- ) . Model.Game.getBoard- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_getCoordinatesByRankByLogicalColour/unique" . all ( (== 1) . length ) . ToolShed.Data.Foldable.gather . State.CoordinatesByRankByLogicalColour.listCoordinates . State.Board.getCoordinatesByRankByLogicalColour . Model.Game.getBoard@@ -189,17 +182,17 @@ let f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(getAvailableQualifiedMovesByLogicalColour == mkAvailableQualifiedMovesFor)" . Data.Maybe.maybe True (- == Model.Game.mkAvailableQualifiedMovesFor nextLogicalColour game+ == Model.Game.mkAvailableQualifiedMovesFor game nextLogicalColour ) . Map.lookup nextLogicalColour $ Model.Game.getAvailableQualifiedMovesByLogicalColour game where nextLogicalColour = Model.Game.getNextLogicalColour game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4096 } f, let f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(findQualifiedMovesAvailableTo => countPliesAvailableTo)" $ all (- \logicalColour -> Model.Game.countPliesAvailableTo logicalColour game == (+ \logicalColour -> Model.Game.countPliesAvailableTo game logicalColour == ( if Model.Game.isTerminated game then 0- else fromIntegral . length $ Model.Game.findQualifiedMovesAvailableTo logicalColour game+ else fromIntegral . length $ Model.Game.findQualifiedMovesAvailableTo game logicalColour ) ) Property.FixedMembership.members in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,@@ -219,7 +212,7 @@ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(getCoordinatesByRankByLogicalColour => getNPawnsByFileByLogicalColour)" . all ( \(logicalColour, nPawnsByFile) -> Data.Foldable.sum nPawnsByFile == fromIntegral (- length . State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn $ State.Board.getCoordinatesByRankByLogicalColour board+ length $ State.CoordinatesByRankByLogicalColour.dereference (State.Board.getCoordinatesByRankByLogicalColour board) logicalColour Attribute.Rank.Pawn ) ) . Data.Array.IArray.assocs $ State.Board.getNPawnsByFileByLogicalColour board where board = Model.Game.getBoard game@@ -233,7 +226,7 @@ let f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_(getMaybeChecked == isKingChecked)" . uncurry (==) . (- Data.Maybe.isJust . Model.Game.getMaybeChecked &&& uncurry State.Board.isKingChecked . (Model.Game.getNextLogicalColour &&& Model.Game.getBoard)+ Data.Maybe.isJust . Model.Game.getMaybeChecked &&& uncurry State.Board.isKingChecked . (Model.Game.getBoard &&& Model.Game.getNextLogicalColour) ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f, let@@ -249,7 +242,7 @@ let f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_reflectOnX/isValidQualifiedMove" . all (- \(game, turn) -> Model.Game.isValidQualifiedMove (Component.Turn.getQualifiedMove turn) game+ \(game, turn) -> Model.Game.isValidQualifiedMove game $ Component.Turn.getQualifiedMove turn ) . Model.Game.rollBack . Property.Reflectable.reflectOnX in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let@@ -271,14 +264,14 @@ let f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(findAttackersOf => listDestinationsFor)" $ all (- \(destination, destinationLogicalColour, destinationRank, source, sourceRank) -> (destination, Just destinationRank) `elem` State.MaybePieceByCoordinates.listDestinationsFor source (+ \(destination, destinationLogicalColour, destinationRank, source, sourceRank) -> (destination, Just destinationRank) `elem` State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates source ( Component.Piece.mkPiece (Property.Opposable.getOpposite destinationLogicalColour) sourceRank- ) maybePieceByCoordinates+ ) ) [ (destination, destinationLogicalColour, destinationRank, source, sourceRank) | (destination, piece) <- StateProperty.Seeker.findAllPieces maybePieceByCoordinates, let (destinationLogicalColour, destinationRank) = Component.Piece.getLogicalColour &&& Component.Piece.getRank $ piece, -- Deconstruct.- (source, sourceRank) <- State.Board.findAttackersOf destinationLogicalColour destination board+ (source, sourceRank) <- State.Board.findAttackersOf board destinationLogicalColour destination ] {-list-comprehension-} where board = Model.Game.getBoard game maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board@@ -286,19 +279,19 @@ let f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(listDestinationsFor => findAttackersOf)" $ all (- \(source, piece, destination) -> (source, Component.Piece.getRank piece) `elem` State.Board.findAttackersOf (+ \(source, piece, destination) -> (source, Component.Piece.getRank piece) `elem` State.Board.findAttackersOf board ( Property.Opposable.getOpposite $ Component.Piece.getLogicalColour piece- ) destination board+ ) destination ) [ (source, piece, destination) | (source, piece) <- StateProperty.Seeker.findAllPieces maybePieceByCoordinates,- (destination, Just _) <- State.MaybePieceByCoordinates.listDestinationsFor source piece maybePieceByCoordinates -- Identify attacks.+ (destination, Just _) <- State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates source piece -- Identify attacks. ] {-list-comprehension-} where board = Model.Game.getBoard game maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions -> Model.Game.Game -> Test.QuickCheck.Property+ f :: Input.EvaluationOptions.EvaluationOptions -> Model.Game.Game -> Test.QuickCheck.Property f evaluationOptions game = Data.Maybe.isJust ( Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions ) && not (@@ -317,12 +310,15 @@ ) . abs . uncurry (-) -- Tolerance for floating-point errors. #endif $ (- Evaluation.Fitness.measurePieceSquareValue pieceSquareByCoordinatesByRank &&& Evaluation.Fitness.measurePieceSquareValueIncrementally (- Evaluation.Fitness.measurePieceSquareValue pieceSquareByCoordinatesByRank oldGame- ) pieceSquareByCoordinatesByRank+ measurePieceSquareValueDifference' &&& Evaluation.Fitness.measurePieceSquareValueDifferenceIncrementally (measurePieceSquareValueDifference' oldGame) pieceSquareByCoordinatesByRank ) game where- pieceSquareByCoordinatesByRank = Data.Maybe.fromJust $ Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions- (oldGame, _) : _ = Model.Game.rollBack game- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 2048 } f+ pieceSquareByCoordinatesByRank = Data.Maybe.fromJust $ Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions+ measurePieceSquareValueDifference' = Evaluation.Fitness.measurePieceSquareValueDifference pieceSquareByCoordinatesByRank+ (oldGame, _) : _ = Model.Game.rollBack game+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 2048 } f,+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Game.prop_isValid" . Property.SelfValidating.isValid . Model.Game.getBoard+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs view
@@ -40,7 +40,7 @@ arbitrary = do depth <- Test.QuickCheck.elements [1 .. 3] - fmap (Property.Arboreal.prune depth . Model.GameTree.fromGame) Test.QuickCheck.arbitrary+ Property.Arboreal.prune depth . Model.GameTree.fromGame <$> Test.QuickCheck.arbitrary -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs view
@@ -43,7 +43,7 @@ arbitrary = do move <- Test.QuickCheck.arbitrary - Notation.ICCFNumeric.mkICCFNumeric move `fmap` if abs (+ Notation.ICCFNumeric.mkICCFNumeric move <$> if abs ( Cartesian.Vector.getXDistance (Component.Move.measureDistance move) ) <= 1 && ( Cartesian.Coordinates.getY . Component.Move.getSource &&& Cartesian.Coordinates.getY . Component.Move.getDestination $ move
src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs view
@@ -72,8 +72,7 @@ where turn = Data.Maybe.fromJust $ Model.Game.maybeLastTurn game (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ Component.Turn.getQualifiedMove turn- (Just rank) = fmap Component.Piece.getRank . State.MaybePieceByCoordinates.dereference (Component.Move.getDestination move) . State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard game-+ (Just rank) = fmap Component.Piece.getRank . State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates $ Model.Game.getBoard game) $ Component.Move.getDestination move in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f ]
src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs view
@@ -44,7 +44,7 @@ arbitrary = do move <- Test.QuickCheck.arbitrary - Notation.PureCoordinate.mkPureCoordinate move `fmap` if abs (+ Notation.PureCoordinate.mkPureCoordinate move <$> if abs ( Cartesian.Vector.getXDistance (Component.Move.measureDistance move) ) <= 1 && ( Cartesian.Coordinates.getY . Component.Move.getSource &&& Cartesian.Coordinates.getY . Component.Move.getDestination $ move
src-test/BishBosh/Test/QuickCheck/Rule/Result.hs view
@@ -28,7 +28,7 @@ results ) where -import BishBosh.Test.QuickCheck.Attribute.LogicalColour()+import BishBosh.Test.QuickCheck.Colour.LogicalColour() import Control.Arrow((&&&)) import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Rule.Result as Rule.Result@@ -36,7 +36,7 @@ import qualified ToolShed.Test.ReversibleIO instance Test.QuickCheck.Arbitrary Rule.Result.Result where- arbitrary = Rule.Result.mkResult `fmap` Test.QuickCheck.oneof [fmap Just Test.QuickCheck.arbitrary, return {-to Gen-monad-} Nothing]+ arbitrary = Rule.Result.mkResult <$> Test.QuickCheck.oneof [fmap Just Test.QuickCheck.arbitrary, return {-to Gen-monad-} Nothing] -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/BishBosh/Test/QuickCheck/Search/Search.hs view
@@ -68,10 +68,11 @@ Input.SearchOptions.getUsePondering = Input.SearchOptions.getUsePondering defaultSearchOptions, Input.SearchOptions.getStandardOpeningOptions = Input.SearchOptions.getStandardOpeningOptions defaultSearchOptions, Input.SearchOptions.getSearchDepthByLogicalColour = Input.SearchOptions.getSearchDepthByLogicalColour defaultSearchOptions- } - getQuantifiedGames = Search.Search.getQuantifiedGames . Control.Monad.Reader.runReader (Search.Search.search (Input.SearchOptions.minimumSearchDepth + fromIntegral (searchDepth `mod` 3)) searchState)+ getQuantifiedGames = Search.Search.getQuantifiedGames . Control.Monad.Reader.runReader (+ Search.Search.search (Input.SearchOptions.minimumSearchDepth + fromIntegral (searchDepth `mod` 3)) searchState+ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f ]
src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward@@ -35,11 +34,9 @@ import BishBosh.Test.QuickCheck.Input.SearchOptions() import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree-import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Mass as Type.Mass import qualified Data.Bits import qualified System.Random import qualified Test.QuickCheck@@ -47,7 +44,7 @@ -- | A suitable concrete type for testing. type SearchState = Search.SearchState.SearchState Type.Crypto.PositionHash -instance forall positionHash. (+instance ( Data.Bits.FiniteBits positionHash, Num positionHash, Show positionHash,@@ -55,11 +52,7 @@ ) => Test.QuickCheck.Arbitrary (Search.SearchState.SearchState positionHash) where {-# SPECIALISE instance Test.QuickCheck.Arbitrary SearchState #-} arbitrary = do- evaluationOptions <- Test.QuickCheck.arbitrary- Search.SearchState.initialise <$> (- Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree (- evaluationOptions :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue- ) <$> Test.QuickCheck.arbitrary {-SearchOptions-} <*> Test.QuickCheck.arbitrary {-Zobrist-} <*> return {-to Gen-monad-} Property.Empty.empty {-MoveFrequency-} <*> Test.QuickCheck.arbitrary {-Game-}+ Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree <$> Test.QuickCheck.arbitrary {-EvaluationOptions-} <*> Test.QuickCheck.arbitrary {-SearchOptions-} <*> Test.QuickCheck.arbitrary {-Zobrist-} <*> return {-to Gen-monad-} Property.Empty.empty {-MoveFrequency-} <*> Test.QuickCheck.arbitrary {-Game-} )
src-test/BishBosh/Test/QuickCheck/State/Board.hs view
@@ -28,14 +28,14 @@ results ) where -import BishBosh.Test.QuickCheck.Attribute.LogicalColour() import BishBosh.Test.QuickCheck.Cartesian.Coordinates()+import BishBosh.Test.QuickCheck.Colour.LogicalColour() import Control.Arrow((&&&)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Property.Empty as Property.Empty@@ -60,10 +60,10 @@ instance Test.QuickCheck.Arbitrary State.Board.Board where arbitrary = let- isKingChecked :: Attribute.LogicalColour.LogicalColour -> State.Board.Board -> Bool+ isKingChecked :: Colour.LogicalColour.LogicalColour -> State.Board.Board -> Bool isKingChecked logicalColour board = not . all (- null . ($ board) . State.Board.findAttackersOf logicalColour- ) . State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.King $ State.Board.getCoordinatesByRankByLogicalColour board+ null . State.Board.findAttackersOf board logicalColour+ ) $ State.CoordinatesByRankByLogicalColour.dereference (State.Board.getCoordinatesByRankByLogicalColour board) logicalColour Attribute.Rank.King in Control.Monad.foldM ( \board piece -> Test.QuickCheck.suchThat ( fmap (@@ -71,7 +71,7 @@ ) . Test.QuickCheck.suchThat Test.QuickCheck.arbitrary {-destination-} $ uncurry (&&) . ( Data.Maybe.maybe True {-unoccupied-} ( not . Component.Piece.isKing -- Avoid taking a King.- ) . (`State.MaybePieceByCoordinates.dereference` State.Board.getMaybePieceByCoordinates board) &&& not . (`Component.Piece.isPawnPromotion` piece) -- Avoid impossible scenarios.+ ) . State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates board) &&& not . Component.Piece.isPawnPromotion piece -- Avoid impossible scenarios. ) -- Predicate. ) $ not . uncurry (||) . ( isKingChecked minBound &&& isKingChecked maxBound@@ -104,17 +104,21 @@ _ -> False in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f, let- f :: Cartesian.Coordinates.Coordinates -> Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Colour.LogicalColour.LogicalColour -> Test.QuickCheck.Property f source logicalColour = Test.QuickCheck.label "Board.prop_bishopsMove/logicalColour" . all ( (== Cartesian.Coordinates.getLogicalColourOfSquare source) . Cartesian.Coordinates.getLogicalColourOfSquare . fst {-coordinates-}- ) . State.MaybePieceByCoordinates.listDestinationsFor source piece . State.Board.getMaybePieceByCoordinates $ StateProperty.Mutator.placeFirstPiece piece source where+ ) $ State.MaybePieceByCoordinates.listDestinationsFor (+ State.Board.getMaybePieceByCoordinates $ StateProperty.Mutator.placeFirstPiece piece source+ ) source piece where piece = Component.Piece.mkBishop logicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Cartesian.Coordinates.Coordinates -> Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Colour.LogicalColour.LogicalColour -> Test.QuickCheck.Property f source logicalColour = Test.QuickCheck.label "Board.prop_knightsMove/logicalColour" . all ( (/= Cartesian.Coordinates.getLogicalColourOfSquare source) . Cartesian.Coordinates.getLogicalColourOfSquare . fst {-coordinates-}- ) . State.MaybePieceByCoordinates.listDestinationsFor source piece . State.Board.getMaybePieceByCoordinates $ StateProperty.Mutator.placeFirstPiece piece source where+ ) $ State.MaybePieceByCoordinates.listDestinationsFor (+ State.Board.getMaybePieceByCoordinates $ StateProperty.Mutator.placeFirstPiece piece source+ ) source piece where piece = Component.Piece.mkKnight logicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let@@ -122,7 +126,7 @@ f board = Test.QuickCheck.label "Board.prop_listDestinationsFor/unique" $ all ( \(coordinates, piece) -> uncurry (==) . ( length &&& length . Data.List.nub- ) $ State.MaybePieceByCoordinates.listDestinationsFor coordinates piece maybePieceByCoordinates+ ) $ State.MaybePieceByCoordinates.listDestinationsFor maybePieceByCoordinates coordinates piece ) $ StateProperty.Seeker.findAllPieces maybePieceByCoordinates where maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,@@ -135,13 +139,13 @@ \destination -> foldr ( \rank m -> foldr ( \source -> Map.insertWith Data.Set.union source $ Data.Set.singleton rank- ) m $ State.Board.findAttacksBy (+ ) m $ State.Board.findAttacksBy board ( Component.Piece.mkPiece (Property.Opposable.getOpposite logicalColour) rank- ) destination board+ ) destination ) Property.Empty.empty Property.FixedMembership.members == foldr ( \(source, rank) -> Map.insertWith Data.Set.union source $ Data.Set.singleton rank ) Property.Empty.empty (- State.Board.findAttackersOf logicalColour destination board+ State.Board.findAttackersOf board logicalColour destination ) ) coordinates ) . State.CoordinatesByRankByLogicalColour.assocs $ State.Board.getCoordinatesByRankByLogicalColour board@@ -150,18 +154,30 @@ f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_(findBlockingPiece => isObstructed)" $ all ( \(source, _) -> let- isClear = ($ maybePieceByCoordinates) . State.MaybePieceByCoordinates.isClear source+ isClear = State.MaybePieceByCoordinates.isClear maybePieceByCoordinates source in all ( \direction -> Data.Maybe.maybe (- Data.Maybe.maybe True isClear . Data.Maybe.listToMaybe . reverse $ Cartesian.Coordinates.extrapolate direction source+ Data.Maybe.maybe True isClear . Data.Maybe.listToMaybe . reverse $ Cartesian.Coordinates.extrapolate source direction ) ( isClear . fst {-destination-}- ) $ State.MaybePieceByCoordinates.findBlockingPiece direction source maybePieceByCoordinates+ ) $ State.MaybePieceByCoordinates.findBlockingPiece maybePieceByCoordinates source direction ) Property.FixedMembership.members ) $ StateProperty.Seeker.findAllPieces maybePieceByCoordinates where maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let+ f :: State.Board.Board -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f board coordinates = Test.QuickCheck.label "Board.prop_findBlockingPieces" . (+ \maybePieceByCoordinates -> State.MaybePieceByCoordinates.findBlockingPieces maybePieceByCoordinates coordinates Nothing == Data.Maybe.mapMaybe (State.MaybePieceByCoordinates.findBlockingPiece maybePieceByCoordinates coordinates) Property.FixedMembership.members+ ) $ State.Board.getMaybePieceByCoordinates board+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let+ f :: State.Board.Board -> Colour.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f board logicalColour coordinates = Test.QuickCheck.label "Board.prop_findAttackerInDirections" . (+ \maybePieceByCoordinates -> State.MaybePieceByCoordinates.findAttackerInDirections maybePieceByCoordinates logicalColour coordinates Nothing == Data.Maybe.mapMaybe (State.MaybePieceByCoordinates.findAttackerInDirection maybePieceByCoordinates logicalColour coordinates) Property.FixedMembership.members+ ) $ State.Board.getMaybePieceByCoordinates board+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,+ let f :: State.Board.Board -> Test.QuickCheck.Property f = Test.QuickCheck.label "Board.prop_findPieces" . uncurry (==) . ( Data.List.sort . StateProperty.Seeker.findAllPieces . State.Board.getCoordinatesByRankByLogicalColour &&& Data.List.sort . StateProperty.Seeker.findAllPieces . State.Board.getMaybePieceByCoordinates@@ -183,7 +199,7 @@ Data.Foldable.sum . ( StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour ! ) &&& fromIntegral . length . (- \logicalColour -> State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn coordinatesByRankByLogicalColour+ \logicalColour -> State.CoordinatesByRankByLogicalColour.dereference coordinatesByRankByLogicalColour logicalColour Attribute.Rank.Pawn ) ) ) Property.FixedMembership.members@@ -192,14 +208,14 @@ let f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_(exposesKing => isKingChecked)" $ all (- \(logicalColour, move) -> State.Board.isKingChecked logicalColour $ State.Board.movePiece move Nothing board+ \(logicalColour, move) -> State.Board.isKingChecked (State.Board.movePiece move Nothing board) logicalColour ) [ (logicalColour, move) | (source, piece) <- StateProperty.Seeker.findAllPieces $ State.Board.getMaybePieceByCoordinates board, let logicalColour = Component.Piece.getLogicalColour piece,- (destination, _) <- State.MaybePieceByCoordinates.listDestinationsFor source piece $ State.Board.getMaybePieceByCoordinates board,+ (destination, _) <- State.MaybePieceByCoordinates.listDestinationsFor (State.Board.getMaybePieceByCoordinates board) source piece, let move = Component.Move.mkMove source destination,- State.Board.exposesKing logicalColour move board+ State.Board.exposesKing board logicalColour move ] -- List-comprehension. in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let@@ -207,11 +223,9 @@ f board = Test.QuickCheck.label "Board.prop_findProximateKnights" . all ( \(coordinates, piece) -> let logicalColour = Property.Opposable.getOpposite $ Component.Piece.getLogicalColour piece- in Data.List.sort (- StateProperty.Seeker.findProximateKnights logicalColour coordinates maybePieceByCoordinates- ) == Data.List.sort (- StateProperty.Seeker.findProximateKnights logicalColour coordinates coordinatesByRankByLogicalColour- )+ in uncurry (==) $ (+ Data.List.sort . StateProperty.Seeker.findProximateKnights maybePieceByCoordinates logicalColour &&& Data.List.sort . StateProperty.Seeker.findProximateKnights coordinatesByRankByLogicalColour logicalColour+ ) coordinates ) $ StateProperty.Seeker.findAllPieces maybePieceByCoordinates where (maybePieceByCoordinates, coordinatesByRankByLogicalColour) = State.Board.getMaybePieceByCoordinates &&& State.Board.getCoordinatesByRankByLogicalColour $ board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f
src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs view
@@ -28,12 +28,12 @@ results ) where -import BishBosh.Test.QuickCheck.Attribute.LogicalColour() import BishBosh.Test.QuickCheck.Cartesian.Coordinates()+import BishBosh.Test.QuickCheck.Colour.LogicalColour() import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Colour.LogicalColour as Colour.LogicalColour import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.Reflectable as Property.Reflectable@@ -84,29 +84,29 @@ f :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f castleableRooksByLogicalColour = Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_(canCastle /= hasCastled)" . not $ any ( uncurry (&&) . (- (`State.CastleableRooksByLogicalColour.canCastle` castleableRooksByLogicalColour) &&& (`State.CastleableRooksByLogicalColour.hasCastled` castleableRooksByLogicalColour)+ State.CastleableRooksByLogicalColour.canCastle castleableRooksByLogicalColour &&& State.CastleableRooksByLogicalColour.hasCastled castleableRooksByLogicalColour ) ) Property.FixedMembership.members in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Attribute.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f :: Colour.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f logicalColour coordinates castleableRooksByLogicalColour = coordinates `notElem` [ minBound, Cartesian.Coordinates.bottomRight, Cartesian.Coordinates.topLeft, maxBound- ] ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_canCastleWith" . not $ State.CastleableRooksByLogicalColour.canCastleWith logicalColour coordinates castleableRooksByLogicalColour+ ] ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_canCastleWith" . not $ State.CastleableRooksByLogicalColour.canCastleWith castleableRooksByLogicalColour logicalColour coordinates in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64} f, let- f :: Attribute.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property- f logicalColour coordinates castleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.canCastleWith logicalColour coordinates castleableRooksByLogicalColour ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_(canCastleWith => canCastle)" $ State.CastleableRooksByLogicalColour.canCastle logicalColour castleableRooksByLogicalColour+ f :: Colour.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f logicalColour coordinates castleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.canCastleWith castleableRooksByLogicalColour logicalColour coordinates ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_(canCastleWith => canCastle)" $ State.CastleableRooksByLogicalColour.canCastle castleableRooksByLogicalColour logicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64, Test.QuickCheck.maxDiscardRatio = 128 } f, let- f :: Attribute.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property- f logicalColour coordinates castleableRooksByLogicalColour = not (State.CastleableRooksByLogicalColour.canCastle logicalColour castleableRooksByLogicalColour) ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_(not . canCastle => not . canCastleWith)" . not $ State.CastleableRooksByLogicalColour.canCastleWith logicalColour coordinates castleableRooksByLogicalColour+ f :: Colour.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f logicalColour coordinates castleableRooksByLogicalColour = not (State.CastleableRooksByLogicalColour.canCastle castleableRooksByLogicalColour logicalColour) ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_(not . canCastle => not . canCastleWith)" . not $ State.CastleableRooksByLogicalColour.canCastleWith castleableRooksByLogicalColour logicalColour coordinates in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/StateProperty/Hashable.hs view
@@ -41,24 +41,20 @@ let f :: Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game -> Test.QuickCheck.Property f zobrist game = Test.QuickCheck.label "Hashable.prop_hash(Game)/unique" . areUnique . map (- (`StateProperty.Hashable.hash` zobrist) . (`Model.Game.applyQualifiedMove` game)+ StateProperty.Hashable.hash zobrist . (`Model.Game.applyQualifiedMove` game) ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game -> Test.QuickCheck.Property f zobrist game = Test.QuickCheck.label "Hashable.prop_hash(Position)/unique" . areUnique . map (- (`StateProperty.Hashable.hash` zobrist) . Model.Game.mkPosition . (`Model.Game.applyQualifiedMove` game)+ StateProperty.Hashable.hash zobrist . Model.Game.mkPosition . (`Model.Game.applyQualifiedMove` game) ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game -> Test.QuickCheck.Property f zobrist game = Test.QuickCheck.label "Hashable.prop_(hash(Game) == hash(Position))" . all ( uncurry (==) . (- (- `StateProperty.Hashable.hash` zobrist- ) &&& (- `StateProperty.Hashable.hash` zobrist- ) . Model.Game.mkPosition+ StateProperty.Hashable.hash zobrist &&& StateProperty.Hashable.hash zobrist . Model.Game.mkPosition ) . (`Model.Game.applyQualifiedMove` game) ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,@@ -66,8 +62,8 @@ f :: Test.QuickCheck.Component.Zobrist.Zobrist -> Model.Game.Game -> Test.QuickCheck.Property f zobrist game = Test.QuickCheck.label "Hashable.prop_incrementalEvaluation" . all ( (- \game' -> StateProperty.Hashable.hash game' zobrist == Model.Game.updateIncrementalPositionHash game (- StateProperty.Hashable.hash game zobrist+ \game' -> StateProperty.Hashable.hash zobrist game' == Model.Game.updateIncrementalPositionHash game (+ StateProperty.Hashable.hash zobrist game ) game' zobrist ) . (`Model.Game.applyQualifiedMove` game) ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game
+ src-test/BishBosh/Test/QuickCheck/StateProperty/Mutator.hs view
@@ -0,0 +1,90 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.StateProperty.Mutator(+-- * Constants+ results,+-- * Functions+-- normalise+) where++import BishBosh.Test.QuickCheck.Component.Piece()+import BishBosh.Test.QuickCheck.Model.Game()+import Control.Arrow((&&&))+import Test.QuickCheck ((==>))+import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Component.Turn as Component.Turn+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour+import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates+import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator+import qualified BishBosh.StateProperty.View as StateProperty.View+import qualified Data.Default+import qualified Data.Maybe+import qualified Test.QuickCheck++-- | Facilitate comparison.+normalise :: State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour -> State.CoordinatesByRankByLogicalColour.BareCoordinatesByRankByLogicalColour+normalise = State.CoordinatesByRankByLogicalColour.deconstruct . State.CoordinatesByRankByLogicalColour.sortCoordinates++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Maybe Component.Piece.Piece -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f maybePiece coordinates = let+ defineCoordinates :: StateProperty.Mutator.Mutator mutator => mutator -> mutator+ defineCoordinates = StateProperty.Mutator.defineCoordinates maybePiece coordinates+ in Test.QuickCheck.label "Mutator.prop_defineCoordinates" . uncurry (==) $ (normalise . StateProperty.View.translate . defineCoordinates . State.Board.getMaybePieceByCoordinates &&& normalise . defineCoordinates . State.Board.getCoordinatesByRankByLogicalColour) Data.Default.def+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f,+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f game = not (+ uncurry (||) $ (Model.Game.isTerminated &&& Property.Null.isNull) game+ ) ==> Test.QuickCheck.label "Mutator.prop_movePiece" . all (+ \qualifiedMove -> let+ (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ qualifiedMove+ board = Model.Game.getBoard game++ movePiece :: StateProperty.Mutator.Mutator mutator => mutator -> mutator+ movePiece = StateProperty.Mutator.movePiece move (+ Data.Maybe.fromJust . State.MaybePieceByCoordinates.dereference (State.Board.getMaybePieceByCoordinates board) $ Component.Move.getSource move+ ) (+ Attribute.MoveType.getMaybePromotedRank moveType+ ) $ if Attribute.MoveType.isEnPassant moveType+ then Left . Component.Move.getDestination . Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove . Data.Maybe.fromJust $ Model.Game.maybeLastTurn game+ else Right $ Attribute.MoveType.getMaybeExplicitlyTakenRank moveType+ in uncurry (==) $ (+ normalise . StateProperty.View.translate . movePiece . State.Board.getMaybePieceByCoordinates &&& normalise . movePiece . State.Board.getCoordinatesByRankByLogicalColour+ ) board+ ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f+ ]+
+ src-test/BishBosh/Test/QuickCheck/StateProperty/View.hs view
@@ -0,0 +1,65 @@+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.StateProperty.View(+-- * Constants+ results+) where++import BishBosh.Test.QuickCheck.Model.Game()+import Control.Arrow((&&&))+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour+import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+import qualified BishBosh.StateProperty.View as StateProperty.View+import qualified Data.List+import qualified Test.QuickCheck++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "View.prop_toAssocs(CoordinatesByRankByLogicalColour == getMaybePieceByCoordinates)" . uncurry (==) . (+ normalise . State.Board.getCoordinatesByRankByLogicalColour &&& normalise . State.Board.getMaybePieceByCoordinates+ ) . Model.Game.getBoard where+ normalise :: StateProperty.Seeker.Seeker seeker => seeker -> [Component.Piece.LocatedPiece]+ normalise = Data.List.sortOn fst {-coordinates-} . StateProperty.View.toAssocs+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "View.prop_translate(MaybePieceByCoordinates)" . uncurry (==) . (+ id &&& StateProperty.View.translate {-to self-}+ ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "View.prop_translate(CoordinatesByRankByLogicalColour)" . uncurry (==) . (+ State.CoordinatesByRankByLogicalColour.deconstruct &&& State.CoordinatesByRankByLogicalColour.deconstruct . StateProperty.View.translate {-to self-}+ ) . State.CoordinatesByRankByLogicalColour.sortCoordinates . State.Board.getCoordinatesByRankByLogicalColour . Model.Game.getBoard+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ ]+
+ src-test/BishBosh/Test/QuickCheck/Type/Mass.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2021 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'+-}++module BishBosh.Test.QuickCheck.Type.Mass() where++#ifdef USE_NEWTYPE_WRAPPERS+import qualified BishBosh.Type.Mass as Type.Mass+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Type.Mass.PieceSquareValue where+ arbitrary = let+ resolution :: Int+ resolution = 100+ in fromRational . (/ fromIntegral resolution) . fromIntegral <$> Test.QuickCheck.elements [0 .. pred resolution]+#endif+
src-test/BishBosh/Test/QuickCheck/UI/Command.hs view
@@ -43,9 +43,9 @@ UI.Command.Save, UI.Command.Swap ], -- Nullary commands- UI.Command.Print `fmap` Test.QuickCheck.arbitrary,+ UI.Command.Print <$> Test.QuickCheck.arbitrary, fmap UI.Command.RollBack . Test.QuickCheck.elements $ Nothing : map Just [1 .. 10],- UI.Command.Set `fmap` Test.QuickCheck.arbitrary+ UI.Command.Set <$> Test.QuickCheck.arbitrary ] -- | The constant test-results for this data-type.
src-test/HUnit.hs view
@@ -24,18 +24,18 @@ module Main(main) where -import qualified BishBosh.Test.HUnit.Attribute.Direction as Test.HUnit.Attribute.Direction-import qualified BishBosh.Test.HUnit.Attribute.LogicalColour as Test.HUnit.Attribute.LogicalColour import qualified BishBosh.Test.HUnit.Attribute.Rank as Test.HUnit.Attribute.Rank import qualified BishBosh.Test.HUnit.Cartesian.Coordinates as Test.HUnit.Cartesian.Coordinates import qualified BishBosh.Test.HUnit.Cartesian.Vector as Test.HUnit.Cartesian.Vector-import qualified BishBosh.Test.HUnit.Component.Move as Test.HUnit.Component.Move+import qualified BishBosh.Test.HUnit.Colour.LogicalColour as Test.HUnit.Colour.LogicalColour import qualified BishBosh.Test.HUnit.Component.CastlingMove as Test.HUnit.Component.CastlingMove+import qualified BishBosh.Test.HUnit.Component.Move as Test.HUnit.Component.Move import qualified BishBosh.Test.HUnit.Component.Piece as Test.HUnit.Component.Piece import qualified BishBosh.Test.HUnit.Component.Zobrist as Test.HUnit.Component.Zobrist import qualified BishBosh.Test.HUnit.ContextualNotation.PGN as Test.HUnit.ContextualNotation.PGN import qualified BishBosh.Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree as Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree import qualified BishBosh.Test.HUnit.ContextualNotation.StandardAlgebraic as Test.HUnit.ContextualNotation.StandardAlgebraic+import qualified BishBosh.Test.HUnit.Direction.Direction as Test.HUnit.Direction.Direction import qualified BishBosh.Test.HUnit.Evaluation.Fitness as Test.HUnit.Evaluation.Fitness import qualified BishBosh.Test.HUnit.Input.Options as Test.HUnit.Input.Options import qualified BishBosh.Test.HUnit.Model.Game as Test.HUnit.Model.Game@@ -52,8 +52,8 @@ main :: IO () main = mapM_ Test.HUnit.runTestTT [ Test.HUnit.Text.AutoComplete.testCases,- Test.HUnit.Attribute.Direction.testCases,- Test.HUnit.Attribute.LogicalColour.testCases,+ Test.HUnit.Colour.LogicalColour.testCases,+ Test.HUnit.Direction.Direction.testCases, Test.HUnit.Attribute.Rank.testCases, Test.HUnit.Cartesian.Coordinates.testCases, Test.HUnit.Cartesian.Vector.testCases,
src-test/QuickCheck.hs view
@@ -24,12 +24,11 @@ module Main(main) where -import qualified BishBosh.Test.QuickCheck.Attribute.Direction as Test.QuickCheck.Attribute.Direction-import qualified BishBosh.Test.QuickCheck.Attribute.LogicalColour as Test.QuickCheck.Attribute.LogicalColour import qualified BishBosh.Test.QuickCheck.Attribute.MoveType as Test.QuickCheck.Attribute.MoveType import qualified BishBosh.Test.QuickCheck.Attribute.Rank as Test.QuickCheck.Attribute.Rank import qualified BishBosh.Test.QuickCheck.Cartesian.Coordinates as Test.QuickCheck.Cartesian.Coordinates import qualified BishBosh.Test.QuickCheck.Cartesian.Vector as Test.QuickCheck.Cartesian.Vector+import qualified BishBosh.Test.QuickCheck.Colour.LogicalColour as Test.QuickCheck.Colour.LogicalColour import qualified BishBosh.Test.QuickCheck.Component.Move as Test.QuickCheck.Component.Move import qualified BishBosh.Test.QuickCheck.Component.Piece as Test.QuickCheck.Component.Piece import qualified BishBosh.Test.QuickCheck.Component.QualifiedMove as Test.QuickCheck.Component.QualifiedMove@@ -41,6 +40,7 @@ import qualified BishBosh.Test.QuickCheck.ContextualNotation.StandardAlgebraic as Test.QuickCheck.ContextualNotation.StandardAlgebraic import qualified BishBosh.Test.QuickCheck.Data.Foldable as Test.QuickCheck.Data.Foldable import qualified BishBosh.Test.QuickCheck.Data.Integral as Test.QuickCheck.Data.Integral+import qualified BishBosh.Test.QuickCheck.Direction.Direction as Test.QuickCheck.Direction.Direction import qualified BishBosh.Test.QuickCheck.Evaluation.PositionHashQuantifiedGameTree as Test.QuickCheck.Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Test.QuickCheck.Input.CriteriaWeights as Test.QuickCheck.Input.CriteriaWeights import qualified BishBosh.Test.QuickCheck.Input.EvaluationOptions as Test.QuickCheck.Input.EvaluationOptions@@ -65,7 +65,9 @@ import qualified BishBosh.Test.QuickCheck.State.Position as Test.QuickCheck.State.Position import qualified BishBosh.Test.QuickCheck.StateProperty.Censor as Test.QuickCheck.StateProperty.Censor import qualified BishBosh.Test.QuickCheck.StateProperty.Hashable as Test.QuickCheck.StateProperty.Hashable+import qualified BishBosh.Test.QuickCheck.StateProperty.Mutator as Test.QuickCheck.StateProperty.Mutator import qualified BishBosh.Test.QuickCheck.StateProperty.Seeker as Test.QuickCheck.StateProperty.Seeker+import qualified BishBosh.Test.QuickCheck.StateProperty.View as Test.QuickCheck.StateProperty.View import qualified BishBosh.Test.QuickCheck.State.TurnsByLogicalColour as Test.QuickCheck.State.TurnsByLogicalColour import qualified BishBosh.Test.QuickCheck.Text.Encoding as Test.QuickCheck.Text.Encoding import qualified BishBosh.Test.QuickCheck.UI.Command as Test.QuickCheck.UI.Command@@ -83,10 +85,10 @@ Test.QuickCheck.Data.Foldable.results, Test.QuickCheck.Data.Integral.results, Test.QuickCheck.Text.Encoding.results,- Test.QuickCheck.Attribute.LogicalColour.results,- Test.QuickCheck.Attribute.Direction.results,+ Test.QuickCheck.Colour.LogicalColour.results, Test.QuickCheck.Attribute.Rank.results, Test.QuickCheck.Attribute.MoveType.results,+ Test.QuickCheck.Direction.Direction.results, Test.QuickCheck.Input.EvaluationOptions.results, Test.QuickCheck.Input.Options.results, Test.QuickCheck.Input.PieceSquareTable.results,@@ -111,6 +113,8 @@ Test.QuickCheck.StateProperty.Censor.results, Test.QuickCheck.StateProperty.Hashable.results, Test.QuickCheck.StateProperty.Seeker.results,+ Test.QuickCheck.StateProperty.View.results,+ Test.QuickCheck.StateProperty.Mutator.results, Test.QuickCheck.Model.Game.results, Test.QuickCheck.Model.GameTree.results, Test.QuickCheck.Model.MoveFrequency.results,