bishbosh 0.1.1.0 → 0.1.2.0
raw patch · 164 files changed
+4161/−5205 lines, 164 filesdep ~QuickCheckdep ~arraydep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: QuickCheck, array, base, containers, data-default, deepseq, extra, factory, hxt, hxt-relaxng, mtl, parsec, polyparse, toolshed, unix
API changes (from Hackage documentation)
- BishBosh.Attribute.PhysicalColour: Black :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Blue :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Cyan :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Green :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Magenta :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Red :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: White :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: Yellow :: PhysicalColour
- BishBosh.Attribute.PhysicalColour: bracket :: String -> String -> ShowS
- BishBosh.Attribute.PhysicalColour: mkBgColourCode :: PhysicalColour -> ANSIColourCode
- BishBosh.Attribute.PhysicalColour: mkFgColourCode :: PhysicalColour -> ANSIColourCode
- BishBosh.Attribute.PhysicalColour: selectGraphicsRendition :: Bool -> ANSIColourCode -> String
- BishBosh.Cartesian.Abscissa: type ArrayByAbscissa x = Array x
- BishBosh.Cartesian.Abscissa: xOrigin :: Int
- BishBosh.Cartesian.Coordinates: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Ord (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Property.FixedMembership.FixedMembership (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Property.Rotatable.Rotatable (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => GHC.Enum.Bounded (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Ix.Ix (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Read.Read x, GHC.Read.Read y) => GHC.Read.Read (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance GHC.Enum.Enum x => BishBosh.Property.Reflectable.ReflectableOnY (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Coordinates: instance GHC.Enum.Enum y => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Cartesian.Ordinate: yOrigin :: Int
- BishBosh.Cartesian.Vector: instance (GHC.Classes.Eq distance, GHC.Num.Num distance) => BishBosh.Property.Orientated.Orientated (BishBosh.Cartesian.Vector.Vector distance)
- BishBosh.Cartesian.Vector: instance Control.DeepSeq.NFData distance => Control.DeepSeq.NFData (BishBosh.Cartesian.Vector.Vector distance)
- BishBosh.Cartesian.Vector: instance GHC.Classes.Eq distance => GHC.Classes.Eq (BishBosh.Cartesian.Vector.Vector distance)
- BishBosh.Cartesian.Vector: instance GHC.Num.Num distance => BishBosh.Property.Opposable.Opposable (BishBosh.Cartesian.Vector.Vector distance)
- BishBosh.Cartesian.Vector: instance GHC.Show.Show distance => GHC.Show.Show (BishBosh.Cartesian.Vector.Vector distance)
- BishBosh.Cartesian.Vector: mkVector :: (Num distance, Ord distance) => distance -> distance -> Vector distance
- BishBosh.Cartesian.Vector: type VectorInt = Vector Distance
- BishBosh.Component.Move: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance (GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Ord (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Property.Orientated.Orientated (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Read.Read x, GHC.Read.Read y) => GHC.Read.Read (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance BishBosh.Property.Opposable.Opposable (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance GHC.Enum.Enum x => BishBosh.Property.Reflectable.ReflectableOnY (BishBosh.Component.Move.Move x y)
- BishBosh.Component.Move: instance GHC.Enum.Enum y => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.Component.Move.Move x y)
- BishBosh.Component.PieceSquareByCoordinatesByRank: findPieceSquareValues :: (Enum x, Enum y, Ord x, Ord y) => NPieces -> LogicalColour -> Rank -> [Coordinates x y] -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> [pieceSquareValue]
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance (Control.DeepSeq.NFData pieceSquareValue, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue)
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq pieceSquareValue) => GHC.Classes.Eq (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue)
- BishBosh.Component.PieceSquareByCoordinatesByRank: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue) => GHC.Show.Show (BishBosh.Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue)
- BishBosh.Component.PieceSquareByCoordinatesByRank: type FindPieceSquareValue x y pieceSquareValue = LogicalColour " The /piece/'s /logical colour/." -> Rank " The /piece/'s /rank/." -> Coordinates x y " The /piece/'s location." -> pieceSquareValue
- BishBosh.Component.PieceSquareByCoordinatesByRank: type FindPieceSquareValues x y pieceSquareValue = LogicalColour " The /piece/'s /logical colour/." -> Rank " The /piece/'s /rank/." -> [Coordinates x y] " The locations of interest for the /piece/." -> [pieceSquareValue]
- BishBosh.Component.QualifiedMove: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Component.QualifiedMove: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Component.QualifiedMove: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Read.Read x, GHC.Read.Read y) => GHC.Read.Read (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Component.QualifiedMove: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Component.QualifiedMove: instance GHC.Enum.Enum y => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Component.Turn: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Component.Turn.Turn x y)
- BishBosh.Component.Turn: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Component.Turn.Turn x y)
- BishBosh.Component.Turn: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Read.Read x, GHC.Read.Read y) => GHC.Read.Read (BishBosh.Component.Turn.Turn x y)
- BishBosh.Component.Turn: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Component.Turn.Turn x y)
- BishBosh.Component.Turn: instance GHC.Enum.Enum y => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.Component.Turn.Turn x y)
- BishBosh.Component.Zobrist: class Hashable1D hashable x
- BishBosh.Component.Zobrist: class Hashable2D hashable x y
- BishBosh.Component.Zobrist: combine :: Bits positionHash => positionHash -> [positionHash] -> positionHash
- BishBosh.Component.Zobrist: hash2D :: (Bits positionHash, Hashable2D hashable x y) => hashable x y -> Zobrist x y positionHash -> positionHash
- BishBosh.Component.Zobrist: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord y, GHC.Show.Show positionHash, GHC.Show.Show x, GHC.Show.Show y, GHC.Ix.Ix x) => GHC.Show.Show (BishBosh.Component.Zobrist.Zobrist x y positionHash)
- BishBosh.Component.Zobrist: instance (GHC.Ix.Ix x, Data.Bits.FiniteBits positionHash, GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord y, System.Random.Random positionHash) => Data.Default.Class.Default (BishBosh.Component.Zobrist.Zobrist x y positionHash)
- BishBosh.Component.Zobrist: instance Data.Foldable.Foldable (BishBosh.Component.Zobrist.Zobrist x y)
- BishBosh.Component.Zobrist: listRandoms1D :: Hashable1D hashable x => hashable x -> Zobrist x y positionHash -> [positionHash]
- BishBosh.Component.Zobrist: listRandoms2D :: Hashable2D hashable x y => hashable x y -> Zobrist x y positionHash -> [positionHash]
- BishBosh.ContextualNotation.PGN: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.ContextualNotation.PGN.PGN x y)
- BishBosh.ContextualNotation.PGN: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.ContextualNotation.PGN.PGN x y)
- BishBosh.ContextualNotation.PGN: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.ContextualNotation.PGN.PGN x y)
- BishBosh.ContextualNotation.PGN: setGame :: Game x y -> PGN x y -> PGN x y
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type OnymousQualifiedMove x y = (QualifiedMove x y, [OnymousResult])
- BishBosh.ContextualNotation.QualifiedMoveForest: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y)
- BishBosh.ContextualNotation.QualifiedMoveForest: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotation (BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y)
- BishBosh.ContextualNotation.QualifiedMoveForest: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y)
- BishBosh.ContextualNotation.QualifiedMoveForest: instance BishBosh.Property.Empty.Empty (BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y)
- BishBosh.ContextualNotation.QualifiedMoveForest: instance BishBosh.Property.Null.Null (BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y)
- BishBosh.ContextualNotation.StandardAlgebraic: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.ContextualNotation.StandardAlgebraic.StandardAlgebraic x y)
- BishBosh.ContextualNotation.StandardAlgebraic: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.ContextualNotation.StandardAlgebraic.StandardAlgebraic x y)
- BishBosh.Data.Enum: translate :: (Enum a, Enum b) => (Int -> Int) -> a -> b
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq positionHash) => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq positionHash) => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show positionHash, GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Arboreal.Prunable (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Null.Null (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash)
- BishBosh.Evaluation.QuantifiedGame: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y)
- BishBosh.Evaluation.QuantifiedGame: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y)
- BishBosh.Evaluation.QuantifiedGame: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y)
- BishBosh.Evaluation.QuantifiedGame: instance BishBosh.Property.Null.Null (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y)
- BishBosh.Evaluation.QuantifiedGame: instance Control.DeepSeq.NFData (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y)
- BishBosh.Input.EvaluationOptions: instance (Control.DeepSeq.NFData pieceSquareValue, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq pieceSquareValue) => GHC.Classes.Eq (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue) => GHC.Show.Show (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.EvaluationOptions: instance Data.Default.Class.Default (BishBosh.Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.Options: instance (Control.DeepSeq.NFData pieceSquareValue, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.Options: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq pieceSquareValue) => GHC.Classes.Eq (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.Options: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.Options: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue) => GHC.Show.Show (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.Options: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.Options: instance Data.Default.Class.Default (BishBosh.Input.Options.Options pieceSquareValue x y)
- BishBosh.Input.PieceSquareTable: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq pieceSquareValue) => GHC.Classes.Eq (BishBosh.Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue) => GHC.Show.Show (BishBosh.Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Fractional pieceSquareValue, GHC.Classes.Ord pieceSquareValue, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)
- BishBosh.Input.PieceSquareTable: instance Data.Default.Class.Default (BishBosh.Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)
- BishBosh.Input.StandardOpeningOptions: type MatchSwitches = (TryToMatchMoves, TryToMatchViaJoiningMove, TryToMatchColourFlippedPosition)
- BishBosh.Model.Game: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ExtendedPositionDescription.ShowsEPD (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ForsythEdwards.ShowsFEN (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Read.Read x, GHC.Read.Read y, GHC.Show.Show x, GHC.Show.Show y) => GHC.Read.Read (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => BishBosh.Property.Empty.Empty (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => BishBosh.Property.ExtendedPositionDescription.ReadsEPD (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => BishBosh.Property.ForsythEdwards.ReadsFEN (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => Data.Default.Class.Default (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Model.Game.Game x y)
- BishBosh.Model.Game: instance (GHC.Ix.Ix x, GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord y) => BishBosh.Component.Zobrist.Hashable2D BishBosh.Model.Game.Game x y
- BishBosh.Model.Game: instance BishBosh.Property.Null.Null (BishBosh.Model.Game.Game x y)
- BishBosh.Model.GameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotation (BishBosh.Model.GameTree.GameTree x y)
- BishBosh.Model.GameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => Data.Default.Class.Default (BishBosh.Model.GameTree.GameTree x y)
- BishBosh.Model.GameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Model.GameTree.GameTree x y)
- BishBosh.Model.GameTree: instance BishBosh.Property.Arboreal.Prunable (BishBosh.Model.GameTree.GameTree x y)
- BishBosh.Notation.ICCFNumeric: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Notation.ICCFNumeric.ICCFNumeric x y)
- BishBosh.Notation.ICCFNumeric: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => GHC.Show.Show (BishBosh.Notation.ICCFNumeric.ICCFNumeric x y)
- BishBosh.Notation.ICCFNumeric: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Read.Read (BishBosh.Notation.ICCFNumeric.ICCFNumeric x y)
- BishBosh.Notation.ICCFNumeric: instance BishBosh.Attribute.Rank.Promotable (BishBosh.Notation.ICCFNumeric.ICCFNumeric x y)
- BishBosh.Notation.ICCFNumeric: origin :: (Int, Int)
- BishBosh.Notation.ICCFNumeric: showsCoordinates :: (Enum x, Enum y) => Coordinates x y -> ShowS
- BishBosh.Notation.MoveNotation: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotation (BishBosh.Cartesian.Coordinates.Coordinates x y)
- BishBosh.Notation.MoveNotation: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotation (BishBosh.Component.QualifiedMove.QualifiedMove x y)
- BishBosh.Notation.MoveNotation: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotation (BishBosh.Component.Turn.Turn x y)
- BishBosh.Notation.PureCoordinate: encode :: (Enum x, Enum y) => Coordinates x y -> (ShowS, ShowS)
- BishBosh.Notation.PureCoordinate: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Notation.PureCoordinate.PureCoordinate x y)
- BishBosh.Notation.PureCoordinate: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => GHC.Show.Show (BishBosh.Notation.PureCoordinate.PureCoordinate x y)
- BishBosh.Notation.PureCoordinate: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Read.Read (BishBosh.Notation.PureCoordinate.PureCoordinate x y)
- BishBosh.Notation.PureCoordinate: instance BishBosh.Attribute.Rank.Promotable (BishBosh.Notation.PureCoordinate.PureCoordinate x y)
- BishBosh.Notation.PureCoordinate: origin :: (Int, Int)
- BishBosh.Notation.PureCoordinate: readsCoordinates :: (Enum x, Enum y, Ord x, Ord y) => ReadS (Coordinates x y)
- BishBosh.Notation.PureCoordinate: showsCoordinates :: (Enum x, Enum y) => Coordinates x y -> ShowS
- BishBosh.Notation.Smith: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Notation.Smith.Smith x y)
- BishBosh.Notation.Smith: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => GHC.Show.Show (BishBosh.Notation.Smith.Smith x y)
- BishBosh.Notation.Smith: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Read.Read (BishBosh.Notation.Smith.Smith x y)
- BishBosh.Notation.Smith: instance BishBosh.Attribute.Rank.Promotable (BishBosh.Notation.Smith.Smith x y)
- BishBosh.Notation.Smith: origin :: (Int, Int)
- BishBosh.Notation.Smith: showsCoordinates :: (Enum x, Enum y) => Coordinates x y -> ShowS
- BishBosh.Search.DynamicMoveData: instance (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (BishBosh.Search.DynamicMoveData.KillerMoveKey x y)
- BishBosh.Search.DynamicMoveData: instance (GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Ord (BishBosh.Search.DynamicMoveData.KillerMoveKey x y)
- BishBosh.Search.DynamicMoveData: instance (GHC.Show.Show x, GHC.Show.Show y) => GHC.Show.Show (BishBosh.Search.DynamicMoveData.KillerMoveKey x y)
- BishBosh.Search.DynamicMoveData: instance BishBosh.Property.Empty.Empty (BishBosh.Search.DynamicMoveData.DynamicMoveData x y positionHash)
- BishBosh.Search.DynamicMoveData: instance BishBosh.Search.EphemeralData.MaybeEphemeralData (BishBosh.Search.DynamicMoveData.DynamicMoveData x y positionHash)
- BishBosh.Search.Search: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Search.Search.Result x y positionHash)
- BishBosh.Search.Search: instance Control.DeepSeq.NFData (BishBosh.Search.Search.Result x y positionHash)
- BishBosh.Search.SearchState: instance BishBosh.Search.EphemeralData.MaybeEphemeralData (BishBosh.Search.SearchState.SearchState x y positionHash)
- BishBosh.Search.SearchState: instance GHC.Show.Show (BishBosh.Search.SearchState.SearchState x y positionHash)
- BishBosh.State.Board: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Component.Zobrist.Hashable2D BishBosh.State.Board.Board x y
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Empty.Empty (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ExtendedPositionDescription.ReadsEPD (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ExtendedPositionDescription.ShowsEPD (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ForsythEdwards.ReadsFEN (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ForsythEdwards.ShowsFEN (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Reflectable.ReflectableOnY (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Mutator.Mutator BishBosh.State.Board.Board x y
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Seeker.Seeker BishBosh.State.Board.Board x y
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => Data.Default.Class.Default (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Read.Read (BishBosh.State.Board.Board x y)
- BishBosh.State.Board: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Show.Show (BishBosh.State.Board.Board x y)
- BishBosh.State.CastleableRooksByLogicalColour: instance (GHC.Enum.Enum x, GHC.Classes.Eq x) => BishBosh.Property.ExtendedPositionDescription.ShowsEPD (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance (GHC.Enum.Enum x, GHC.Classes.Eq x) => BishBosh.Property.ForsythEdwards.ShowsFEN (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance (GHC.Enum.Enum x, GHC.Classes.Ord x, GHC.Read.Read x, GHC.Show.Show x) => GHC.Read.Read (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance (GHC.Enum.Enum x, GHC.Classes.Ord x, GHC.Show.Show x) => BishBosh.Property.ExtendedPositionDescription.ReadsEPD (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance (GHC.Enum.Enum x, GHC.Classes.Ord x, GHC.Show.Show x) => BishBosh.Property.ForsythEdwards.ReadsFEN (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance Control.DeepSeq.NFData x => Control.DeepSeq.NFData (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Classes.Eq x => BishBosh.Component.Zobrist.Hashable1D BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x
- BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Classes.Eq x => GHC.Classes.Eq (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Classes.Ord x => GHC.Classes.Ord (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Enum.Enum x => Data.Default.Class.Default (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Show.Show x => GHC.Show.Show (BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x)
- BishBosh.State.CoordinatesByRankByLogicalColour: countPawnsByFileByLogicalColour :: Ord x => CoordinatesByRankByLogicalColour x y -> NPiecesByFileByLogicalColour x
- BishBosh.State.CoordinatesByRankByLogicalColour: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour x y)
- BishBosh.State.CoordinatesByRankByLogicalColour: instance (GHC.Enum.Enum x, GHC.Enum.Enum y) => BishBosh.StateProperty.Censor.Censor (BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour x y)
- BishBosh.State.CoordinatesByRankByLogicalColour: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Component.Zobrist.Hashable2D BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour x y
- BishBosh.State.CoordinatesByRankByLogicalColour: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Seeker.Seeker BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour x y
- BishBosh.State.CoordinatesByRankByLogicalColour: sumPieceSquareValueByLogicalColour :: Num pieceSquareValue => FindPieceSquareValues x y pieceSquareValue -> CoordinatesByRankByLogicalColour x y -> [pieceSquareValue]
- BishBosh.State.CoordinatesByRankByLogicalColour: type NPiecesByFileByLogicalColour x = ArrayByLogicalColour (Map x NPieces)
- BishBosh.State.EnPassantAbscissa: instance Control.DeepSeq.NFData x => Control.DeepSeq.NFData (BishBosh.State.EnPassantAbscissa.EnPassantAbscissa x)
- BishBosh.State.EnPassantAbscissa: instance GHC.Classes.Eq x => GHC.Classes.Eq (BishBosh.State.EnPassantAbscissa.EnPassantAbscissa x)
- BishBosh.State.EnPassantAbscissa: instance GHC.Classes.Ord x => GHC.Classes.Ord (BishBosh.State.EnPassantAbscissa.EnPassantAbscissa x)
- BishBosh.State.EnPassantAbscissa: instance GHC.Ix.Ix x => BishBosh.Component.Zobrist.Hashable1D BishBosh.State.EnPassantAbscissa.EnPassantAbscissa x
- BishBosh.State.MaybePieceByCoordinates: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Component.Zobrist.Hashable2D BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Empty.Empty (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ExtendedPositionDescription.ReadsEPD (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ExtendedPositionDescription.ShowsEPD (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ForsythEdwards.ReadsFEN (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.ForsythEdwards.ShowsFEN (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Reflectable.ReflectableOnY (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Censor.Censor (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Mutator.Mutator BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.StateProperty.Seeker.Seeker BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => Data.Default.Class.Default (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Ord (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Read.Read (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Show.Show (BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates x y)
- BishBosh.State.MaybePieceByCoordinates: sumPieceSquareValueByLogicalColour :: (Enum x, Enum y, Num pieceSquareValue, Ord x, Ord y) => FindPieceSquareValue x y pieceSquareValue -> MaybePieceByCoordinates x y -> [pieceSquareValue]
- BishBosh.State.Position: instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.State.Position.Position x y)
- BishBosh.State.Position: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => BishBosh.Property.Reflectable.ReflectableOnX (BishBosh.State.Position.Position x y)
- BishBosh.State.Position: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Eq (BishBosh.State.Position.Position x y)
- BishBosh.State.Position: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y) => GHC.Classes.Ord (BishBosh.State.Position.Position x y)
- BishBosh.State.Position: instance (GHC.Ix.Ix x, GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord y) => BishBosh.Component.Zobrist.Hashable2D BishBosh.State.Position.Position x y
- BishBosh.Type.Length: type Distance = Base
- BishBosh.UI.Command: commandPrefix :: Char
- BishBosh.UI.Command: instance Control.DeepSeq.NFData (BishBosh.UI.Command.Command x y)
- BishBosh.UI.Command: instance GHC.Classes.Eq (BishBosh.UI.Command.Command x y)
- BishBosh.UI.Command: instance GHC.Show.Show (BishBosh.UI.Command.Command x y)
- BishBosh.UI.Command: restartTag :: String
- BishBosh.UI.SetObject: newtype SetObject
+ 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.MoveType: isSimple :: MoveType -> Bool
+ BishBosh.Attribute.PhysicalColour: instance BishBosh.Property.Opposable.Opposable BishBosh.Attribute.PhysicalColour.PhysicalColour
+ BishBosh.Attribute.Rank: initialAllocationByRankPerSide :: ArrayByRank NPieces
+ BishBosh.Cartesian.Abscissa: bishopsFiles :: [X]
+ BishBosh.Cartesian.Abscissa: kingsFile :: X
+ BishBosh.Cartesian.Coordinates: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance BishBosh.Property.Rotatable.Rotatable BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance Control.DeepSeq.NFData BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Classes.Eq BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Classes.Ord BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Enum.Bounded BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Ix.Ix BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Read.Read BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Coordinates: instance GHC.Show.Show BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Cartesian.Vector: instance BishBosh.Property.Opposable.Opposable BishBosh.Cartesian.Vector.Vector
+ BishBosh.Cartesian.Vector: instance BishBosh.Property.Orientated.Orientated BishBosh.Cartesian.Vector.Vector
+ BishBosh.Cartesian.Vector: instance Control.DeepSeq.NFData BishBosh.Cartesian.Vector.Vector
+ BishBosh.Cartesian.Vector: instance GHC.Classes.Eq BishBosh.Cartesian.Vector.Vector
+ BishBosh.Cartesian.Vector: instance GHC.Show.Show BishBosh.Cartesian.Vector.Vector
+ BishBosh.Component.Accountant: class Accountant accountant
+ BishBosh.Component.Accountant: sumPieceSquareValueByLogicalColour :: (Accountant accountant, Num pieceSquareValue) => PieceSquareByCoordinatesByRank pieceSquareValue -> NPieces -> accountant -> [pieceSquareValue]
+ BishBosh.Component.Move: instance BishBosh.Property.Opposable.Opposable BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance BishBosh.Property.Orientated.Orientated BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance Control.DeepSeq.NFData BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance GHC.Classes.Eq BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance GHC.Classes.Ord BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance GHC.Read.Read BishBosh.Component.Move.Move
+ BishBosh.Component.Move: instance GHC.Show.Show BishBosh.Component.Move.Move
+ BishBosh.Component.Piece: epdCharacterSet :: EPD
+ BishBosh.Component.Piece: listArrayByPiece :: IArray a e => [e] -> a Piece e
+ BishBosh.Component.Piece: type ArrayByPiece = Array Piece
+ 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.Component.QualifiedMove: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Component.QualifiedMove: instance Control.DeepSeq.NFData BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Component.QualifiedMove: instance GHC.Classes.Eq BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Component.QualifiedMove: instance GHC.Read.Read BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Component.QualifiedMove: instance GHC.Show.Show BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Component.Turn: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Component.Turn.Turn
+ BishBosh.Component.Turn: instance Control.DeepSeq.NFData BishBosh.Component.Turn.Turn
+ BishBosh.Component.Turn: instance GHC.Classes.Eq BishBosh.Component.Turn.Turn
+ BishBosh.Component.Turn: instance GHC.Read.Read BishBosh.Component.Turn.Turn
+ BishBosh.Component.Turn: instance GHC.Show.Show BishBosh.Component.Turn.Turn
+ BishBosh.Component.Zobrist: instance (Data.Bits.FiniteBits positionHash, System.Random.Random positionHash) => Data.Default.Class.Default (BishBosh.Component.Zobrist.Zobrist positionHash)
+ BishBosh.Component.Zobrist: instance Data.Foldable.Foldable BishBosh.Component.Zobrist.Zobrist
+ BishBosh.Component.Zobrist: instance GHC.Show.Show positionHash => GHC.Show.Show (BishBosh.Component.Zobrist.Zobrist positionHash)
+ BishBosh.ContextualNotation.PGN: instance Control.DeepSeq.NFData BishBosh.ContextualNotation.PGN.PGN
+ BishBosh.ContextualNotation.PGN: instance GHC.Classes.Eq BishBosh.ContextualNotation.PGN.PGN
+ BishBosh.ContextualNotation.PGN: instance GHC.Show.Show BishBosh.ContextualNotation.PGN.PGN
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type MatchSwitches = (TryToMatchMoves, TryToMatchViaJoiningMove, TryToMatchColourFlippedPosition)
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type PreferVictories = Bool
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type TryToMatchColourFlippedPosition = Bool
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type TryToMatchMoves = Bool
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: type TryToMatchViaJoiningMove = Bool
+ BishBosh.ContextualNotation.QualifiedMoveForest: instance BishBosh.Notation.MoveNotation.ShowNotation BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest
+ BishBosh.ContextualNotation.QualifiedMoveForest: instance BishBosh.Property.Empty.Empty BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest
+ BishBosh.ContextualNotation.QualifiedMoveForest: instance BishBosh.Property.Null.Null BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest
+ BishBosh.ContextualNotation.QualifiedMoveForest: instance GHC.Classes.Eq BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest
+ BishBosh.ContextualNotation.QualifiedMoveForest: instance GHC.Show.Show BishBosh.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest
+ BishBosh.ContextualNotation.StandardAlgebraic: instance GHC.Classes.Eq BishBosh.ContextualNotation.StandardAlgebraic.StandardAlgebraic
+ BishBosh.ContextualNotation.StandardAlgebraic: instance GHC.Show.Show BishBosh.ContextualNotation.StandardAlgebraic.StandardAlgebraic
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Arboreal.Prunable (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Null.Null (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance GHC.Classes.Eq positionHash => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance GHC.Classes.Eq positionHash => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance GHC.Show.Show positionHash => GHC.Show.Show (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel positionHash)
+ BishBosh.Evaluation.QuantifiedGame: instance BishBosh.Notation.MoveNotation.ShowNotationFloat BishBosh.Evaluation.QuantifiedGame.QuantifiedGame
+ BishBosh.Evaluation.QuantifiedGame: instance BishBosh.Property.Null.Null BishBosh.Evaluation.QuantifiedGame.QuantifiedGame
+ BishBosh.Evaluation.QuantifiedGame: instance Control.DeepSeq.NFData BishBosh.Evaluation.QuantifiedGame.QuantifiedGame
+ BishBosh.Evaluation.QuantifiedGame: instance GHC.Classes.Eq BishBosh.Evaluation.QuantifiedGame.QuantifiedGame
+ BishBosh.Evaluation.QuantifiedGame: instance GHC.Show.Show BishBosh.Evaluation.QuantifiedGame.QuantifiedGame
+ 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.IOOptions: persist :: Show game => IOOptions -> Bool -> game -> IO ()
+ 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: 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.Input.PieceSquareTable: type IOFormat = Double
+ BishBosh.Input.SearchOptions: sortOnStandardOpeningMoveFrequencyTag :: String
+ BishBosh.Model.Game: instance BishBosh.Property.Empty.Empty BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.Null.Null BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance Control.DeepSeq.NFData BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance Data.Default.Class.Default BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance GHC.Classes.Eq BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance GHC.Read.Read BishBosh.Model.Game.Game
+ BishBosh.Model.Game: instance GHC.Show.Show BishBosh.Model.Game.Game
+ BishBosh.Model.GameTree: instance BishBosh.Notation.MoveNotation.ShowNotation BishBosh.Model.GameTree.GameTree
+ BishBosh.Model.GameTree: instance BishBosh.Property.Arboreal.Prunable BishBosh.Model.GameTree.GameTree
+ BishBosh.Model.GameTree: instance Data.Default.Class.Default BishBosh.Model.GameTree.GameTree
+ BishBosh.Model.GameTree: instance GHC.Show.Show BishBosh.Model.GameTree.GameTree
+ BishBosh.Model.MoveFrequency: countDistinctEntries :: MoveFrequency move -> NPlies
+ BishBosh.Notation.Figurine: fromFigurine :: Figurine -> Maybe Piece
+ BishBosh.Notation.Figurine: toFigurine :: Piece -> Figurine
+ BishBosh.Notation.ICCFNumeric: instance BishBosh.Attribute.Rank.Promotable BishBosh.Notation.ICCFNumeric.ICCFNumeric
+ BishBosh.Notation.ICCFNumeric: instance GHC.Classes.Eq BishBosh.Notation.ICCFNumeric.ICCFNumeric
+ BishBosh.Notation.ICCFNumeric: instance GHC.Read.Read BishBosh.Notation.ICCFNumeric.ICCFNumeric
+ BishBosh.Notation.ICCFNumeric: instance GHC.Show.Show BishBosh.Notation.ICCFNumeric.ICCFNumeric
+ BishBosh.Notation.ICCFNumeric: notation :: Notation
+ BishBosh.Notation.MoveNotation: getNotation :: MoveNotation -> Notation
+ BishBosh.Notation.MoveNotation: instance BishBosh.Notation.MoveNotation.ShowNotation BishBosh.Cartesian.Coordinates.Coordinates
+ BishBosh.Notation.MoveNotation: instance BishBosh.Notation.MoveNotation.ShowNotation BishBosh.Component.QualifiedMove.QualifiedMove
+ BishBosh.Notation.MoveNotation: instance BishBosh.Notation.MoveNotation.ShowNotation BishBosh.Component.Turn.Turn
+ BishBosh.Notation.Notation: data Notation
+ BishBosh.Notation.Notation: encode :: Notation -> Coordinates -> (ShowS, ShowS)
+ BishBosh.Notation.Notation: inXRange :: Notation -> Char -> Bool
+ BishBosh.Notation.Notation: inYRange :: Notation -> Char -> Bool
+ BishBosh.Notation.Notation: mkMaybeCoordinates :: Notation -> CoordinatePairC -> Maybe Coordinates
+ BishBosh.Notation.Notation: mkNotation :: CoordinatePairC -> Notation
+ BishBosh.Notation.Notation: readsCoordinates :: Notation -> ReadS Coordinates
+ BishBosh.Notation.Notation: showsCoordinates :: Notation -> Coordinates -> ShowS
+ BishBosh.Notation.Notation: type CoordinatePairI = (X, Y)
+ BishBosh.Notation.PureCoordinate: instance BishBosh.Attribute.Rank.Promotable BishBosh.Notation.PureCoordinate.PureCoordinate
+ BishBosh.Notation.PureCoordinate: instance GHC.Classes.Eq BishBosh.Notation.PureCoordinate.PureCoordinate
+ BishBosh.Notation.PureCoordinate: instance GHC.Read.Read BishBosh.Notation.PureCoordinate.PureCoordinate
+ BishBosh.Notation.PureCoordinate: instance GHC.Show.Show BishBosh.Notation.PureCoordinate.PureCoordinate
+ BishBosh.Notation.PureCoordinate: notation :: Notation
+ BishBosh.Notation.Smith: instance BishBosh.Attribute.Rank.Promotable BishBosh.Notation.Smith.Smith
+ BishBosh.Notation.Smith: instance GHC.Classes.Eq BishBosh.Notation.Smith.Smith
+ BishBosh.Notation.Smith: instance GHC.Read.Read BishBosh.Notation.Smith.Smith
+ BishBosh.Notation.Smith: instance GHC.Show.Show BishBosh.Notation.Smith.Smith
+ BishBosh.Notation.Smith: notation :: Notation
+ BishBosh.Property.Empty: instance BishBosh.Property.Empty.Empty (Data.Set.Internal.Set i)
+ BishBosh.Property.ExtendedPositionDescription: rankSeparator :: Char
+ BishBosh.Property.ExtendedPositionDescription: tag :: String
+ BishBosh.Property.ExtendedPositionDescription: type EPD = String
+ BishBosh.Property.Opposable: instance BishBosh.Property.Opposable.Opposable GHC.Types.Ordering
+ BishBosh.Search.DynamicMoveData: instance BishBosh.Property.Empty.Empty (BishBosh.Search.DynamicMoveData.DynamicMoveData positionHash)
+ BishBosh.Search.DynamicMoveData: instance BishBosh.Search.EphemeralData.MaybeEphemeralData (BishBosh.Search.DynamicMoveData.DynamicMoveData positionHash)
+ BishBosh.Search.DynamicMoveData: instance GHC.Classes.Eq BishBosh.Search.DynamicMoveData.KillerMoveKey
+ BishBosh.Search.DynamicMoveData: instance GHC.Classes.Ord BishBosh.Search.DynamicMoveData.KillerMoveKey
+ BishBosh.Search.DynamicMoveData: instance GHC.Show.Show BishBosh.Search.DynamicMoveData.KillerMoveKey
+ BishBosh.Search.Search: instance BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Search.Search.Result positionHash)
+ BishBosh.Search.Search: instance Control.DeepSeq.NFData (BishBosh.Search.Search.Result positionHash)
+ BishBosh.Search.SearchState: instance BishBosh.Search.EphemeralData.MaybeEphemeralData (BishBosh.Search.SearchState.SearchState positionHash)
+ BishBosh.Search.SearchState: instance GHC.Show.Show (BishBosh.Search.SearchState.SearchState positionHash)
+ BishBosh.State.Board: instance BishBosh.Property.Empty.Empty BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.StateProperty.Mutator.Mutator BishBosh.State.Board.Board
+ BishBosh.State.Board: instance BishBosh.StateProperty.Seeker.Seeker BishBosh.State.Board.Board
+ BishBosh.State.Board: instance Control.DeepSeq.NFData BishBosh.State.Board.Board
+ BishBosh.State.Board: instance Data.Default.Class.Default BishBosh.State.Board.Board
+ BishBosh.State.Board: instance GHC.Classes.Eq BishBosh.State.Board.Board
+ BishBosh.State.Board: instance GHC.Read.Read BishBosh.State.Board.Board
+ BishBosh.State.Board: instance GHC.Show.Show BishBosh.State.Board.Board
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance Control.DeepSeq.NFData BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance Data.Default.Class.Default BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Classes.Eq BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Classes.Ord BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Read.Read BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CastleableRooksByLogicalColour: instance GHC.Show.Show BishBosh.State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.Component.Accountant.Accountant BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.StateProperty.Censor.Censor BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance BishBosh.StateProperty.Seeker.Seeker BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.CoordinatesByRankByLogicalColour: instance Control.DeepSeq.NFData BishBosh.State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour
+ BishBosh.State.EnPassantAbscissa: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.EnPassantAbscissa.EnPassantAbscissa
+ BishBosh.State.EnPassantAbscissa: instance Control.DeepSeq.NFData BishBosh.State.EnPassantAbscissa.EnPassantAbscissa
+ BishBosh.State.EnPassantAbscissa: instance GHC.Classes.Eq BishBosh.State.EnPassantAbscissa.EnPassantAbscissa
+ BishBosh.State.EnPassantAbscissa: instance GHC.Classes.Ord BishBosh.State.EnPassantAbscissa.EnPassantAbscissa
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Component.Accountant.Accountant BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.Empty.Empty BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.ExtendedPositionDescription.ReadsEPD BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.ExtendedPositionDescription.ShowsEPD BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.ForsythEdwards.ReadsFEN BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.ForsythEdwards.ShowsFEN BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.Property.Reflectable.ReflectableOnY BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.StateProperty.Censor.Censor BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.StateProperty.Mutator.Mutator BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance BishBosh.StateProperty.Seeker.Seeker BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance Control.DeepSeq.NFData BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance Data.Default.Class.Default BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance GHC.Classes.Eq BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance GHC.Classes.Ord BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance GHC.Read.Read BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.MaybePieceByCoordinates: instance GHC.Show.Show BishBosh.State.MaybePieceByCoordinates.MaybePieceByCoordinates
+ BishBosh.State.Position: instance BishBosh.Property.Reflectable.ReflectableOnX BishBosh.State.Position.Position
+ BishBosh.State.Position: instance BishBosh.StateProperty.Hashable.Hashable BishBosh.State.Position.Position
+ BishBosh.State.Position: instance Control.DeepSeq.NFData BishBosh.State.Position.Position
+ BishBosh.State.Position: instance GHC.Classes.Eq BishBosh.State.Position.Position
+ BishBosh.State.Position: instance GHC.Classes.Ord BishBosh.State.Position.Position
+ BishBosh.StateProperty.Hashable: class Hashable hashable
+ BishBosh.StateProperty.Hashable: combine :: Bits positionHash => positionHash -> [positionHash] -> positionHash
+ BishBosh.StateProperty.Hashable: hash :: (Bits positionHash, Hashable hashable) => hashable -> Zobrist positionHash -> positionHash
+ BishBosh.StateProperty.Hashable: listRandoms :: Hashable hashable => hashable -> Zobrist positionHash -> [positionHash]
+ BishBosh.StateProperty.Seeker: accumulatePawnsByFile :: X -> NPiecesByFile -> NPiecesByFile
+ BishBosh.StateProperty.Seeker: countPawnsByFileByLogicalColour :: Seeker seeker => seeker -> NPiecesByFileByLogicalColour
+ BishBosh.StateProperty.Seeker: summariseNPawnsByLogicalColour :: Seeker seeker => seeker -> ArrayByLogicalColour NPieces
+ BishBosh.StateProperty.Seeker: type NPiecesByFileByLogicalColour = ArrayByLogicalColour NPiecesByFile
+ BishBosh.Text.ShowColouredPrefix: showsPrefixError :: ShowS
+ BishBosh.Text.ShowColouredPrefix: showsPrefixInfo :: ShowS
+ BishBosh.Text.ShowColouredPrefix: showsPrefixWarning :: ShowS
+ BishBosh.Type.Count: type NCoordinates = Base
+ BishBosh.UI.Command: instance Control.DeepSeq.NFData BishBosh.UI.Command.Command
+ BishBosh.UI.Command: instance GHC.Classes.Eq BishBosh.UI.Command.Command
+ BishBosh.UI.Command: instance GHC.Show.Show BishBosh.UI.Command.Command
+ BishBosh.UI.Command: issueCommand :: Command -> ShowS
+ BishBosh.UI.SetObject: EPD :: Game -> SetObject
+ BishBosh.UI.SetObject: data SetObject
+ BishBosh.UI.SetObject: mkEPD :: Game -> SetObject
+ BishBosh.UI.SetObject: searchDepthTag :: String
- BishBosh.Cartesian.Abscissa: fromIx :: Enum x => Int -> x
+ BishBosh.Cartesian.Abscissa: fromIx :: Int -> X
- BishBosh.Cartesian.Abscissa: getAdjacents :: (Enum x, Eq x) => x -> [x]
+ BishBosh.Cartesian.Abscissa: getAdjacents :: X -> [X]
- BishBosh.Cartesian.Abscissa: inBounds :: (Enum x, Ord x) => x -> Bool
+ BishBosh.Cartesian.Abscissa: inBounds :: X -> Bool
- BishBosh.Cartesian.Abscissa: listArrayByAbscissa :: (IArray a e, Ix x, Enum x) => [e] -> a x e
+ BishBosh.Cartesian.Abscissa: listArrayByAbscissa :: IArray a e => [e] -> a X e
- BishBosh.Cartesian.Abscissa: maybeTranslate :: (Enum x, Ord x) => (x -> x) -> x -> Maybe x
+ BishBosh.Cartesian.Abscissa: maybeTranslate :: (X -> X) -> X -> Maybe X
- BishBosh.Cartesian.Abscissa: reflect :: Enum x => x -> x
+ BishBosh.Cartesian.Abscissa: reflect :: X -> X
- BishBosh.Cartesian.Abscissa: toIx :: Enum x => x -> Int
+ BishBosh.Cartesian.Abscissa: toIx :: X -> Int
- BishBosh.Cartesian.Abscissa: translate :: (Enum x, Ord x) => (x -> x) -> x -> x
+ BishBosh.Cartesian.Abscissa: translate :: (X -> X) -> X -> X
- BishBosh.Cartesian.Abscissa: xBounds :: Enum x => (x, x)
+ BishBosh.Cartesian.Abscissa: xBounds :: (X, X)
- BishBosh.Cartesian.Abscissa: xLength :: Distance
+ BishBosh.Cartesian.Abscissa: xLength :: X
- BishBosh.Cartesian.Abscissa: xMax :: Enum x => x
+ BishBosh.Cartesian.Abscissa: xMax :: X
- BishBosh.Cartesian.Abscissa: xMin :: Enum x => x
+ BishBosh.Cartesian.Abscissa: xMin :: X
- BishBosh.Cartesian.Abscissa: xRange :: Enum x => [x]
+ BishBosh.Cartesian.Abscissa: xRange :: [X]
- BishBosh.Cartesian.Coordinates: advance :: (Enum y, Ord y) => LogicalColour -> Transformation x y
+ BishBosh.Cartesian.Coordinates: advance :: LogicalColour -> Transformation
- BishBosh.Cartesian.Coordinates: areSquaresIsochromatic :: (Enum x, Enum y) => [Coordinates x y] -> Bool
+ BishBosh.Cartesian.Coordinates: areSquaresIsochromatic :: [Coordinates] -> Bool
- BishBosh.Cartesian.Coordinates: arrayByCoordinates :: (IArray a e, Enum x, Enum y, Ord x, Ord y) => [(Coordinates x y, e)] -> a (Coordinates x y) e
+ BishBosh.Cartesian.Coordinates: arrayByCoordinates :: IArray a e => [(Coordinates, e)] -> a Coordinates e
- BishBosh.Cartesian.Coordinates: bottomRight :: (Enum x, Enum y) => Coordinates x y
+ BishBosh.Cartesian.Coordinates: bottomRight :: Coordinates
- BishBosh.Cartesian.Coordinates: data Coordinates x y
+ BishBosh.Cartesian.Coordinates: data Coordinates
- BishBosh.Cartesian.Coordinates: extrapolate :: (Enum x, Enum y) => Direction -> Coordinates x y -> [Coordinates x y]
+ BishBosh.Cartesian.Coordinates: extrapolate :: Direction -> Coordinates -> [Coordinates]
- BishBosh.Cartesian.Coordinates: fromIx :: (Enum x, Enum y) => Int -> Coordinates x y
+ BishBosh.Cartesian.Coordinates: fromIx :: Int -> Coordinates
- BishBosh.Cartesian.Coordinates: getAdjacents :: (Enum x, Eq x) => Coordinates x y -> [Coordinates x y]
+ BishBosh.Cartesian.Coordinates: getAdjacents :: Coordinates -> [Coordinates]
- BishBosh.Cartesian.Coordinates: getLogicalColourOfSquare :: (Enum x, Enum y) => Coordinates x y -> LogicalColourOfSquare
+ BishBosh.Cartesian.Coordinates: getLogicalColourOfSquare :: Coordinates -> LogicalColourOfSquare
- BishBosh.Cartesian.Coordinates: interpolate :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> Coordinates x y -> [Coordinates x y]
+ BishBosh.Cartesian.Coordinates: interpolate :: Coordinates -> Coordinates -> [Coordinates]
- BishBosh.Cartesian.Coordinates: isEnPassantRank :: (Enum y, Eq y) => LogicalColour -> Coordinates x y -> Bool
+ BishBosh.Cartesian.Coordinates: isEnPassantRank :: LogicalColour -> Coordinates -> Bool
- BishBosh.Cartesian.Coordinates: isPawnsFirstRank :: (Enum y, Eq y) => LogicalColour -> Coordinates x y -> Bool
+ BishBosh.Cartesian.Coordinates: isPawnsFirstRank :: LogicalColour -> Coordinates -> Bool
- BishBosh.Cartesian.Coordinates: kingsStartingCoordinates :: (Enum x, Enum y) => LogicalColour -> Coordinates x y
+ BishBosh.Cartesian.Coordinates: kingsStartingCoordinates :: LogicalColour -> Coordinates
- BishBosh.Cartesian.Coordinates: listArrayByCoordinates :: (IArray a e, Enum x, Enum y, Ord x, Ord y) => [e] -> a (Coordinates x y) e
+ BishBosh.Cartesian.Coordinates: listArrayByCoordinates :: IArray a e => [e] -> a Coordinates e
- BishBosh.Cartesian.Coordinates: maybeRetreat :: (Enum y, Ord y) => LogicalColour -> Coordinates x y -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: maybeRetreat :: LogicalColour -> Coordinates -> Maybe Coordinates
- BishBosh.Cartesian.Coordinates: maybeTranslate :: (Enum x, Enum y, Ord x, Ord y) => ((x, y) -> (x, y)) -> Coordinates x y -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: maybeTranslate :: ((X, Y) -> (X, Y)) -> Coordinates -> Maybe Coordinates
- BishBosh.Cartesian.Coordinates: maybeTranslateX :: (Enum x, Ord x) => (x -> x) -> Coordinates x y -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: maybeTranslateX :: (X -> X) -> Coordinates -> Maybe Coordinates
- BishBosh.Cartesian.Coordinates: maybeTranslateY :: (Enum y, Ord y) => (y -> y) -> Coordinates x y -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: maybeTranslateY :: (Y -> Y) -> Coordinates -> Maybe Coordinates
- BishBosh.Cartesian.Coordinates: measureDistance :: (Enum x, Enum y, Num distance) => Coordinates x y -> Coordinates x y -> (distance, distance)
+ BishBosh.Cartesian.Coordinates: measureDistance :: Coordinates -> Coordinates -> (X, Y)
- BishBosh.Cartesian.Coordinates: mkCoordinates :: (Enum x, Enum y, Ord x, Ord y) => x -> y -> Coordinates x y
+ BishBosh.Cartesian.Coordinates: mkCoordinates :: X -> Y -> Coordinates
- BishBosh.Cartesian.Coordinates: mkMaybeCoordinates :: (Enum x, Enum y, Ord x, Ord y) => x -> y -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: mkMaybeCoordinates :: X -> Y -> Maybe Coordinates
- BishBosh.Cartesian.Coordinates: mkRelativeCoordinates :: (Enum x, Enum y, Ord x, Ord y) => ((x, y) -> (x, y)) -> Coordinates x y
+ BishBosh.Cartesian.Coordinates: mkRelativeCoordinates :: ((X, Y) -> (X, Y)) -> Coordinates
- BishBosh.Cartesian.Coordinates: nSquares :: Int
+ BishBosh.Cartesian.Coordinates: nSquares :: NCoordinates
- BishBosh.Cartesian.Coordinates: retreat :: (Enum y, Ord y) => LogicalColour -> Transformation x y
+ BishBosh.Cartesian.Coordinates: retreat :: LogicalColour -> Transformation
- BishBosh.Cartesian.Coordinates: rooksStartingCoordinates :: (Enum x, Enum y) => LogicalColour -> [Coordinates x y]
+ BishBosh.Cartesian.Coordinates: rooksStartingCoordinates :: LogicalColour -> [Coordinates]
- BishBosh.Cartesian.Coordinates: topLeft :: (Enum x, Enum y) => Coordinates x y
+ BishBosh.Cartesian.Coordinates: topLeft :: Coordinates
- BishBosh.Cartesian.Coordinates: translate :: (Enum x, Enum y, Ord x, Ord y) => ((x, y) -> (x, y)) -> Coordinates x y -> Coordinates x y
+ BishBosh.Cartesian.Coordinates: translate :: ((X, Y) -> (X, Y)) -> Coordinates -> Coordinates
- BishBosh.Cartesian.Coordinates: translateX :: (Enum x, Ord x) => (x -> x) -> Transformation x y
+ BishBosh.Cartesian.Coordinates: translateX :: (X -> X) -> Transformation
- BishBosh.Cartesian.Coordinates: translateY :: (Enum y, Ord y) => (y -> y) -> Transformation x y
+ BishBosh.Cartesian.Coordinates: translateY :: (Y -> Y) -> Transformation
- BishBosh.Cartesian.Coordinates: type ArrayByCoordinates x y = Array (Coordinates x y)
+ BishBosh.Cartesian.Coordinates: type ArrayByCoordinates = Array Coordinates
- BishBosh.Cartesian.Ordinate: enPassantRank :: Enum y => LogicalColour -> y
+ BishBosh.Cartesian.Ordinate: enPassantRank :: LogicalColour -> Y
- BishBosh.Cartesian.Ordinate: firstRank :: Enum y => LogicalColour -> y
+ BishBosh.Cartesian.Ordinate: firstRank :: LogicalColour -> Y
- BishBosh.Cartesian.Ordinate: fromIx :: Enum y => Int -> y
+ BishBosh.Cartesian.Ordinate: fromIx :: Int -> Y
- BishBosh.Cartesian.Ordinate: inBounds :: (Enum y, Ord y) => y -> Bool
+ BishBosh.Cartesian.Ordinate: inBounds :: Y -> Bool
- BishBosh.Cartesian.Ordinate: lastRank :: Enum y => LogicalColour -> y
+ BishBosh.Cartesian.Ordinate: lastRank :: LogicalColour -> Y
- BishBosh.Cartesian.Ordinate: maybeTranslate :: (Enum y, Ord y) => (y -> y) -> y -> Maybe y
+ BishBosh.Cartesian.Ordinate: maybeTranslate :: (Y -> Y) -> Y -> Maybe Y
- BishBosh.Cartesian.Ordinate: pawnsFirstRank :: Enum y => LogicalColour -> y
+ BishBosh.Cartesian.Ordinate: pawnsFirstRank :: LogicalColour -> Y
- BishBosh.Cartesian.Ordinate: reflect :: Enum y => y -> y
+ BishBosh.Cartesian.Ordinate: reflect :: Y -> Y
- BishBosh.Cartesian.Ordinate: toIx :: Enum y => y -> Int
+ BishBosh.Cartesian.Ordinate: toIx :: Y -> Int
- BishBosh.Cartesian.Ordinate: translate :: (Enum y, Ord y) => (y -> y) -> y -> y
+ BishBosh.Cartesian.Ordinate: translate :: (Y -> Y) -> Y -> Y
- BishBosh.Cartesian.Ordinate: yBounds :: Enum y => (y, y)
+ BishBosh.Cartesian.Ordinate: yBounds :: (Y, Y)
- BishBosh.Cartesian.Ordinate: yLength :: Distance
+ BishBosh.Cartesian.Ordinate: yLength :: Y
- BishBosh.Cartesian.Ordinate: yMax :: Enum y => y
+ BishBosh.Cartesian.Ordinate: yMax :: Y
- BishBosh.Cartesian.Ordinate: yMin :: Enum y => y
+ BishBosh.Cartesian.Ordinate: yMin :: Y
- BishBosh.Cartesian.Ordinate: yRange :: Enum y => [y]
+ BishBosh.Cartesian.Ordinate: yRange :: [Y]
- BishBosh.Cartesian.Vector: attackVectorsForKing :: (Eq distance, Num distance) => [Vector distance]
+ BishBosh.Cartesian.Vector: attackVectorsForKing :: [Vector]
- BishBosh.Cartesian.Vector: attackVectorsForKnight :: Num distance => [Vector distance]
+ BishBosh.Cartesian.Vector: attackVectorsForKnight :: [Vector]
- BishBosh.Cartesian.Vector: attackVectorsForPawn :: Num distance => LogicalColour -> [Vector distance]
+ BishBosh.Cartesian.Vector: attackVectorsForPawn :: LogicalColour -> [Vector]
- BishBosh.Cartesian.Vector: data Vector distance
+ BishBosh.Cartesian.Vector: data Vector
- BishBosh.Cartesian.Vector: isDiagonal :: (Eq distance, Num distance) => Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isDiagonal :: Vector -> Bool
- BishBosh.Cartesian.Vector: isKingsMove :: (Num distance, Ord distance) => Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isKingsMove :: Vector -> Bool
- BishBosh.Cartesian.Vector: isKnightsMove :: (Eq distance, Num distance) => Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isKnightsMove :: Vector -> Bool
- BishBosh.Cartesian.Vector: isParallel :: (Eq distance, Num distance) => Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isParallel :: Vector -> Bool
- BishBosh.Cartesian.Vector: isPawnAttack :: (Eq distance, Num distance) => LogicalColour -> Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isPawnAttack :: LogicalColour -> Vector -> Bool
- BishBosh.Cartesian.Vector: isStraight :: (Eq distance, Num distance) => Vector distance -> Bool
+ BishBosh.Cartesian.Vector: isStraight :: Vector -> Bool
- BishBosh.Cartesian.Vector: matchesPawnDoubleAdvance :: (Eq distance, Num distance) => LogicalColour -> Vector distance -> Bool
+ BishBosh.Cartesian.Vector: matchesPawnDoubleAdvance :: LogicalColour -> Vector -> Bool
- BishBosh.Cartesian.Vector: maybeTranslate :: (Enum x, Enum y, Integral distance, Ord x, Ord y) => Coordinates x y -> Vector distance -> Maybe (Coordinates x y)
+ BishBosh.Cartesian.Vector: maybeTranslate :: Coordinates -> Vector -> Maybe Coordinates
- BishBosh.Cartesian.Vector: measureDistance :: (Enum x, Enum y, Num distance, Ord distance) => Coordinates x y -> Coordinates x y -> Vector distance
+ BishBosh.Cartesian.Vector: measureDistance :: Coordinates -> Coordinates -> Vector
- BishBosh.Cartesian.Vector: toMaybeDirection :: (Num distance, Ord distance) => Vector distance -> Maybe Direction
+ BishBosh.Cartesian.Vector: toMaybeDirection :: Vector -> Maybe Direction
- BishBosh.Cartesian.Vector: translate :: (Enum x, Enum y, Integral distance, Ord x, Ord y) => Coordinates x y -> Vector distance -> Coordinates x y
+ BishBosh.Cartesian.Vector: translate :: Coordinates -> Vector -> Coordinates
- BishBosh.Component.CastlingMove: data CastlingMove x y
+ BishBosh.Component.CastlingMove: data CastlingMove
- BishBosh.Component.CastlingMove: getCastlingMoves :: (Enum x, Enum y, Eq y, Ord x) => LogicalColour -> [CastlingMove x y]
+ BishBosh.Component.CastlingMove: getCastlingMoves :: LogicalColour -> [CastlingMove]
- BishBosh.Component.CastlingMove: getLongAndShortMoves :: (Enum x, Enum y, Eq y, Ord x) => LogicalColour -> (CastlingMove x y, CastlingMove x y)
+ BishBosh.Component.CastlingMove: getLongAndShortMoves :: LogicalColour -> (CastlingMove, CastlingMove)
- BishBosh.Component.CastlingMove: kingsMoveLength :: Num x => x
+ BishBosh.Component.CastlingMove: kingsMoveLength :: X
- BishBosh.Component.EitherQualifiedMove: data EitherQualifiedMove x y
+ BishBosh.Component.EitherQualifiedMove: data EitherQualifiedMove
- BishBosh.Component.EitherQualifiedMove: mkFullyQualifiedMove :: Move x y -> MoveType -> EitherQualifiedMove x y
+ BishBosh.Component.EitherQualifiedMove: mkFullyQualifiedMove :: Move -> MoveType -> EitherQualifiedMove
- BishBosh.Component.EitherQualifiedMove: mkPartiallyQualifiedMove :: Move x y -> Maybe Rank -> EitherQualifiedMove x y
+ BishBosh.Component.EitherQualifiedMove: mkPartiallyQualifiedMove :: Move -> Maybe Rank -> EitherQualifiedMove
- BishBosh.Component.Move: data Move x y
+ BishBosh.Component.Move: data Move
- BishBosh.Component.Move: interpolate :: (Enum x, Enum y, Ord x, Ord y) => Move x y -> [Coordinates x y]
+ BishBosh.Component.Move: interpolate :: Move -> [Coordinates]
- BishBosh.Component.Move: isPawnDoubleAdvance :: (Enum x, Enum y, Eq y) => LogicalColour -> Move x y -> Bool
+ BishBosh.Component.Move: isPawnDoubleAdvance :: LogicalColour -> Move -> Bool
- BishBosh.Component.Move: measureDistance :: (Enum x, Enum y, Num distance, Ord distance) => Move x y -> Vector distance
+ BishBosh.Component.Move: measureDistance :: Move -> Vector
- BishBosh.Component.Move: mkMove :: (Eq x, Eq y) => Coordinates x y -> Coordinates x y -> Move x y
+ BishBosh.Component.Move: mkMove :: Coordinates -> Coordinates -> Move
- BishBosh.Component.Piece: canAttackAlong :: (Enum x, Enum y) => Coordinates x y -> Coordinates x y -> Piece -> Bool
+ BishBosh.Component.Piece: canAttackAlong :: Coordinates -> Coordinates -> Piece -> Bool
- BishBosh.Component.Piece: canMoveBetween :: (Enum x, Enum y, Eq y) => Coordinates x y -> Coordinates x y -> Piece -> Bool
+ BishBosh.Component.Piece: canMoveBetween :: Coordinates -> Coordinates -> Piece -> Bool
- BishBosh.Component.Piece: findAttackDestinations :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> Piece -> [Coordinates x y]
+ BishBosh.Component.Piece: findAttackDestinations :: Coordinates -> Piece -> [Coordinates]
- BishBosh.Component.Piece: isPawnPromotion :: (Enum y, Eq y) => Coordinates x y -> Piece -> Bool
+ BishBosh.Component.Piece: isPawnPromotion :: Coordinates -> Piece -> Bool
- BishBosh.Component.Piece: type LocatedPiece x y = (Coordinates x y, Piece)
+ BishBosh.Component.Piece: type LocatedPiece = (Coordinates, Piece)
- BishBosh.Component.PieceSquareByCoordinatesByRank: data PieceSquareByCoordinatesByRank x y pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: data PieceSquareByCoordinatesByRank pieceSquareValue
- BishBosh.Component.PieceSquareByCoordinatesByRank: findPieceSquareValue :: (Enum x, Enum y, Ord x, Ord y) => NPieces -> LogicalColour -> Rank -> Coordinates x y -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: findPieceSquareValue :: PieceSquareByCoordinatesByRank pieceSquareValue -> NPieces -> LogicalColour -> Rank -> Coordinates -> pieceSquareValue
- BishBosh.Component.PieceSquareByCoordinatesByRank: formatForGNUPlot :: (Enum x, Enum y, Ord x, Ord y) => (pieceSquareValue -> ShowS) -> ShowS -> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue) -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> ShowS
+ BishBosh.Component.PieceSquareByCoordinatesByRank: formatForGNUPlot :: (pieceSquareValue -> ShowS) -> ShowS -> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue) -> PieceSquareByCoordinatesByRank pieceSquareValue -> ShowS
- BishBosh.Component.PieceSquareByCoordinatesByRank: mkPieceSquareByCoordinatesByRank :: (Rank -> EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue) -> PieceSquareByCoordinatesByRank x y pieceSquareValue
+ BishBosh.Component.PieceSquareByCoordinatesByRank: mkPieceSquareByCoordinatesByRank :: (Rank -> EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue) -> PieceSquareByCoordinatesByRank pieceSquareValue
- BishBosh.Component.QualifiedMove: data QualifiedMove x y
+ BishBosh.Component.QualifiedMove: data QualifiedMove
- BishBosh.Component.QualifiedMove: mkQualifiedMove :: Move x y -> MoveType -> QualifiedMove x y
+ BishBosh.Component.QualifiedMove: mkQualifiedMove :: Move -> MoveType -> QualifiedMove
- BishBosh.Component.Turn: compareByLVA :: EvaluateRank -> Turn x y -> Turn x y -> Ordering
+ BishBosh.Component.Turn: compareByLVA :: EvaluateRank -> Turn -> Turn -> Ordering
- BishBosh.Component.Turn: compareByMVVLVA :: EvaluateRank -> Turn x y -> Turn x y -> Ordering
+ BishBosh.Component.Turn: compareByMVVLVA :: EvaluateRank -> Turn -> Turn -> Ordering
- BishBosh.Component.Turn: data Turn x y
+ BishBosh.Component.Turn: data Turn
- BishBosh.Component.Turn: isCapture :: Turn x y -> Bool
+ BishBosh.Component.Turn: isCapture :: Turn -> Bool
- BishBosh.Component.Turn: isPawnDoubleAdvance :: (Enum x, Enum y, Eq y) => LogicalColour -> Turn x y -> Bool
+ BishBosh.Component.Turn: isPawnDoubleAdvance :: LogicalColour -> Turn -> Bool
- BishBosh.Component.Turn: mkTurn :: QualifiedMove x y -> Rank -> Turn x y
+ BishBosh.Component.Turn: mkTurn :: QualifiedMove -> Rank -> Turn
- BishBosh.Component.Zobrist: data Zobrist x y positionHash
+ BishBosh.Component.Zobrist: data Zobrist positionHash
- BishBosh.Component.Zobrist: dereferenceRandomByCastleableRooksXByLogicalColour :: Eq x => LogicalColour -> x -> Zobrist x y positionHash -> Maybe positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByCastleableRooksXByLogicalColour :: LogicalColour -> X -> Zobrist positionHash -> Maybe positionHash
- BishBosh.Component.Zobrist: dereferenceRandomByCoordinatesByRankByLogicalColour :: (Enum x, Enum y, Ord x, Ord y) => Index x y -> Zobrist x y positionHash -> positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByCoordinatesByRankByLogicalColour :: Index -> Zobrist positionHash -> positionHash
- BishBosh.Component.Zobrist: dereferenceRandomByEnPassantAbscissa :: Ix x => x -> Zobrist x y positionHash -> positionHash
+ BishBosh.Component.Zobrist: dereferenceRandomByEnPassantAbscissa :: X -> Zobrist positionHash -> positionHash
- BishBosh.Component.Zobrist: mkZobrist :: (Ix x, FiniteBits positionHash, Enum x, Enum y, Ord y, RandomGen randomGen, Random positionHash) => Maybe Int -> randomGen -> Zobrist x y positionHash
+ BishBosh.Component.Zobrist: mkZobrist :: (FiniteBits positionHash, RandomGen randomGen, Random positionHash) => Maybe Int -> randomGen -> Zobrist positionHash
- BishBosh.ContextualNotation.PGN: data PGN x y
+ BishBosh.ContextualNotation.PGN: data PGN
- BishBosh.ContextualNotation.PGN: mkPGN :: Maybe Value -> Maybe Value -> Day -> Maybe Value -> Maybe Value -> Maybe Value -> [TagPair] -> Game x y -> PGN x y
+ BishBosh.ContextualNotation.PGN: mkPGN :: Maybe Value -> Maybe Value -> Day -> Maybe Value -> Maybe Value -> Maybe Value -> [TagPair] -> Game -> PGN
- BishBosh.ContextualNotation.PGN: mkPGN' :: [Tag] -> [TagPair] -> Game x y -> PGN x y
+ BishBosh.ContextualNotation.PGN: mkPGN' :: [Tag] -> [TagPair] -> Game -> PGN
- BishBosh.ContextualNotation.PGN: moveTextParser :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => IsStrictlySequential -> ValidateMoves -> TextParser (Game x y)
+ BishBosh.ContextualNotation.PGN: moveTextParser :: IsStrictlySequential -> ValidateMoves -> TextParser Game
- BishBosh.ContextualNotation.PGN: parser :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => IsStrictlySequential -> ValidateMoves -> [Tag] -> TextParser (PGN x y)
+ BishBosh.ContextualNotation.PGN: parser :: IsStrictlySequential -> ValidateMoves -> [Tag] -> TextParser PGN
- BishBosh.ContextualNotation.PGN: showsGame :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Game x y -> IO ShowS
+ BishBosh.ContextualNotation.PGN: showsGame :: Game -> IO ShowS
- BishBosh.ContextualNotation.PGN: showsMoveText :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Game x y -> ShowS
+ BishBosh.ContextualNotation.PGN: showsMoveText :: Game -> ShowS
- BishBosh.ContextualNotation.PGNDatabase: parseIO :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => FilePath -> Maybe Decompressor -> IsStrictlySequential -> ValidateMoves -> TextEncoding -> [Tag] -> PGNPredicate x y -> MaybeMaximumGames -> IO (Either String (PGNDatabase x y))
+ BishBosh.ContextualNotation.PGNDatabase: parseIO :: FilePath -> Maybe Decompressor -> IsStrictlySequential -> ValidateMoves -> TextEncoding -> [Tag] -> PGNPredicate -> MaybeMaximumGames -> IO (Either String PGNDatabase)
- BishBosh.ContextualNotation.PGNDatabase: type PGNDatabase x y = [PGN x y]
+ BishBosh.ContextualNotation.PGNDatabase: type PGNDatabase = [PGN]
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: data NodeLabel x y positionHash
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: data NodeLabel positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: data PositionHashQualifiedMoveTree x y positionHash
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: data PositionHashQualifiedMoveTree positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: findNextOnymousQualifiedMoves :: (NFData x, NFData y, Ix x, Bits positionHash, Enum x, Enum y, Ord y, Show x, Show y) => (Bool, Bool, Bool) -> FindMatch x y positionHash
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: findNextOnymousQualifiedMoves :: Bits positionHash => MatchSwitches -> FindMatch positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: findNextOnymousQualifiedMovesForPosition :: (Ix x, Bits positionHash, Enum x, Enum y, Ord y) => FindMatch x y positionHash
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: findNextOnymousQualifiedMovesForPosition :: Bits positionHash => FindMatch positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: fromQualifiedMoveForest :: (Ix x, Bits positionHash, Enum x, Enum y, Ord y, Show x, Show y) => Bool -> Zobrist x y positionHash -> QualifiedMoveForest x y -> PositionHashQualifiedMoveTree x y positionHash
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: fromQualifiedMoveForest :: Bits positionHash => Bool -> Zobrist positionHash -> QualifiedMoveForest -> PositionHashQualifiedMoveTree positionHash
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: isTerminal :: PositionHashQualifiedMoveTree x y positionHash -> Bool
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: isTerminal :: PositionHashQualifiedMoveTree positionHash -> Bool
- BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: maybeRandomlySelectOnymousQualifiedMove :: (NFData x, NFData y, Ix x, Bits positionHash, Enum x, Enum y, Ord y, Show x, Show y, RandomGen randomGen) => randomGen -> (Bool, Bool, Bool) -> Game x y -> PositionHashQualifiedMoveTree x y positionHash -> Maybe (QualifiedMove x y, [Name])
+ BishBosh.ContextualNotation.PositionHashQualifiedMoveTree: maybeRandomlySelectOnymousQualifiedMove :: (Bits positionHash, RandomGen randomGen) => randomGen -> PreferVictories -> MatchSwitches -> Game -> PositionHashQualifiedMoveTree positionHash -> Maybe (QualifiedMove, [Name])
- BishBosh.ContextualNotation.QualifiedMoveForest: count :: QualifiedMoveForest x y -> (NGames, NPositions)
+ BishBosh.ContextualNotation.QualifiedMoveForest: count :: QualifiedMoveForest -> (NGames, NPositions)
- BishBosh.ContextualNotation.QualifiedMoveForest: data QualifiedMoveForest x y
+ BishBosh.ContextualNotation.QualifiedMoveForest: data QualifiedMoveForest
- BishBosh.ContextualNotation.QualifiedMoveForest: findMinimumPieces :: QualifiedMoveForest x y -> NPieces
+ BishBosh.ContextualNotation.QualifiedMoveForest: findMinimumPieces :: QualifiedMoveForest -> NPieces
- BishBosh.ContextualNotation.QualifiedMoveForest: fromPGNDatabase :: (Eq x, Eq y) => PGNDatabase x y -> QualifiedMoveForest x y
+ BishBosh.ContextualNotation.QualifiedMoveForest: fromPGNDatabase :: PGNDatabase -> QualifiedMoveForest
- BishBosh.ContextualNotation.QualifiedMoveForest: mergePGNDatabase :: (Eq x, Eq y) => PGNDatabase x y -> QualifiedMoveForest x y -> QualifiedMoveForest x y
+ BishBosh.ContextualNotation.QualifiedMoveForest: mergePGNDatabase :: PGNDatabase -> QualifiedMoveForest -> QualifiedMoveForest
- BishBosh.ContextualNotation.QualifiedMoveForest: toGameTree :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => QualifiedMoveForest x y -> GameTree x y
+ BishBosh.ContextualNotation.QualifiedMoveForest: toGameTree :: QualifiedMoveForest -> GameTree
- BishBosh.ContextualNotation.StandardAlgebraic: data StandardAlgebraic x y
+ BishBosh.ContextualNotation.StandardAlgebraic: data StandardAlgebraic
- BishBosh.ContextualNotation.StandardAlgebraic: fromQualifiedMove :: QualifiedMove x y -> StandardAlgebraic x y
+ BishBosh.ContextualNotation.StandardAlgebraic: fromQualifiedMove :: QualifiedMove -> StandardAlgebraic
- BishBosh.ContextualNotation.StandardAlgebraic: movePiece :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => StandardAlgebraic x y -> Transformation x y
+ BishBosh.ContextualNotation.StandardAlgebraic: movePiece :: StandardAlgebraic -> Transformation
- BishBosh.ContextualNotation.StandardAlgebraic: parser :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => ExplicitEnPassant -> ValidateMoves -> Game x y -> TextParser (StandardAlgebraic x y)
+ BishBosh.ContextualNotation.StandardAlgebraic: parser :: ExplicitEnPassant -> ValidateMoves -> Game -> TextParser StandardAlgebraic
- BishBosh.ContextualNotation.StandardAlgebraic: showMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => ExplicitEnPassant -> QualifiedMove x y -> Game x y -> String
+ BishBosh.ContextualNotation.StandardAlgebraic: showMove :: ExplicitEnPassant -> QualifiedMove -> Game -> String
- BishBosh.ContextualNotation.StandardAlgebraic: showTurn :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => ExplicitEnPassant -> Turn x y -> Game x y -> String
+ BishBosh.ContextualNotation.StandardAlgebraic: showTurn :: ExplicitEnPassant -> Turn -> Game -> String
- BishBosh.ContextualNotation.StandardAlgebraic: showsMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => ExplicitEnPassant -> QualifiedMove x y -> Game x y -> ShowS
+ BishBosh.ContextualNotation.StandardAlgebraic: showsMove :: ExplicitEnPassant -> QualifiedMove -> Game -> ShowS
- BishBosh.ContextualNotation.StandardAlgebraic: showsTurn :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => ExplicitEnPassant -> Turn x y -> Game x y -> ShowS
+ BishBosh.ContextualNotation.StandardAlgebraic: showsTurn :: ExplicitEnPassant -> Turn -> Game -> ShowS
- BishBosh.Evaluation.Fitness: evaluateFitness :: (Enum x, Enum y, Fractional pieceSquareValue, Ord x, Ord y, Real pieceSquareValue, Show x, Show y) => Maybe pieceSquareValue -> Game x y -> Reader pieceSquareValue x y WeightedMeanAndCriterionValues
+ BishBosh.Evaluation.Fitness: evaluateFitness :: (Fractional pieceSquareValue, Real pieceSquareValue) => Maybe pieceSquareValue -> Game -> Reader pieceSquareValue WeightedMeanAndCriterionValues
- BishBosh.Evaluation.Fitness: measurePieceSquareValue :: (Enum x, Enum y, Num pieceSquareValue, Ord x, Ord y) => PieceSquareByCoordinatesByRank x y pieceSquareValue -> Game x y -> pieceSquareValue
+ BishBosh.Evaluation.Fitness: measurePieceSquareValue :: Num pieceSquareValue => PieceSquareByCoordinatesByRank pieceSquareValue -> Game -> pieceSquareValue
- BishBosh.Evaluation.Fitness: measurePieceSquareValueIncrementally :: (Enum x, Enum y, Num pieceSquareValue, Ord x, Ord y) => pieceSquareValue -> PieceSquareByCoordinatesByRank x y pieceSquareValue -> Game x y -> pieceSquareValue
+ BishBosh.Evaluation.Fitness: measurePieceSquareValueIncrementally :: Num pieceSquareValue => pieceSquareValue -> PieceSquareByCoordinatesByRank pieceSquareValue -> Game -> pieceSquareValue
- BishBosh.Evaluation.Fitness: measureValueOfCastlingPotential :: Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfCastlingPotential :: Game -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfDefence :: Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfDefence :: Game -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfDoubledPawns :: Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfDoubledPawns :: Game -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfIsolatedPawns :: (Enum x, Ord x) => Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfIsolatedPawns :: Game -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfMaterial :: RankValues -> RankValue -> Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfMaterial :: RankValues -> RankValue -> Game -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfPassedPawns :: forall x y. Enum y => Game x y -> CriterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfPassedPawns :: Game -> CriterionValue
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: MkPositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: MkPositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: [deconstruct] :: PositionHashQuantifiedGameTree x y positionHash -> BarePositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: [deconstruct] :: PositionHashQuantifiedGameTree positionHash -> BarePositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: data NodeLabel x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: data NodeLabel positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash -> positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootPositionHash :: PositionHashQuantifiedGameTree positionHash -> positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash -> QuantifiedGame x y
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame :: PositionHashQuantifiedGameTree positionHash -> QuantifiedGame
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash -> QuantifiedGame x y
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree positionHash -> QuantifiedGame
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: mkPositionHashQuantifiedGameTree :: (Ix x, Bits positionHash, Fractional pieceSquareValue, Integral x, Integral y, Real pieceSquareValue, Show x, Show y) => EvaluationOptions pieceSquareValue x y -> SearchOptions -> Zobrist x y positionHash -> MoveFrequency x y -> Game x y -> PositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: mkPositionHashQuantifiedGameTree :: (Bits positionHash, Fractional pieceSquareValue, Real pieceSquareValue) => EvaluationOptions pieceSquareValue -> SearchOptions -> Zobrist positionHash -> MoveFrequency -> Game -> PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: newtype PositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: newtype PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoves :: (Eq x, Eq y) => [QualifiedMove x y] -> Forest x y positionHash -> Maybe (Forest x y positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoves :: [QualifiedMove] -> Forest positionHash -> Maybe (Forest positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: reduce :: IsMatch (NodeLabel x y positionHash) -> PositionHashQuantifiedGameTree x y positionHash -> Maybe (PositionHashQuantifiedGameTree x y positionHash)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: reduce :: IsMatch (NodeLabel positionHash) -> PositionHashQuantifiedGameTree positionHash -> Maybe (PositionHashQuantifiedGameTree positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: resign :: PositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: resign :: PositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: sortNonCaptureMoves :: (Forest x y positionHash -> Forest x y positionHash) -> Forest x y positionHash -> Forest x y positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: sortNonCaptureMoves :: (Forest positionHash -> Forest positionHash) -> Forest positionHash -> Forest positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoves :: (Eq x, Eq y) => PositionHashQuantifiedGameTree x y positionHash -> [QualifiedMove x y] -> Maybe [NodeLabel x y positionHash]
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoves :: PositionHashQuantifiedGameTree positionHash -> [QualifiedMove] -> Maybe [NodeLabel positionHash]
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceRoute :: (Turn x y -> IsMatch (NodeLabel x y positionHash)) -> PositionHashQuantifiedGameTree x y positionHash -> [Turn x y] -> Maybe [NodeLabel x y positionHash]
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceRoute :: (Turn -> IsMatch (NodeLabel positionHash)) -> PositionHashQuantifiedGameTree positionHash -> [Turn] -> Maybe [NodeLabel positionHash]
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: type Forest x y positionHash = [BarePositionHashQuantifiedGameTree x y positionHash]
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: type Forest positionHash = [BarePositionHashQuantifiedGameTree positionHash]
- BishBosh.Evaluation.QuantifiedGame: compareFitness :: QuantifiedGame x y -> QuantifiedGame x y -> Ordering
+ BishBosh.Evaluation.QuantifiedGame: compareFitness :: QuantifiedGame -> QuantifiedGame -> Ordering
- BishBosh.Evaluation.QuantifiedGame: data QuantifiedGame x y
+ BishBosh.Evaluation.QuantifiedGame: data QuantifiedGame
- BishBosh.Evaluation.QuantifiedGame: fromGame :: (Enum x, Enum y, Fractional pieceSquareValue, Ord x, Ord y, Real pieceSquareValue, Show x, Show y) => Maybe pieceSquareValue -> Game x y -> Reader pieceSquareValue x y (QuantifiedGame x y)
+ BishBosh.Evaluation.QuantifiedGame: fromGame :: (Fractional pieceSquareValue, Real pieceSquareValue) => Maybe pieceSquareValue -> Game -> Reader pieceSquareValue QuantifiedGame
- BishBosh.Evaluation.QuantifiedGame: getFitness :: QuantifiedGame x y -> WeightedMean
+ BishBosh.Evaluation.QuantifiedGame: getFitness :: QuantifiedGame -> WeightedMean
- BishBosh.Evaluation.QuantifiedGame: getLastTurn :: QuantifiedGame x y -> Turn x y
+ BishBosh.Evaluation.QuantifiedGame: getLastTurn :: QuantifiedGame -> Turn
- BishBosh.Evaluation.QuantifiedGame: getLatestTurns :: NPlies -> QuantifiedGame x y -> [Turn x y]
+ BishBosh.Evaluation.QuantifiedGame: getLatestTurns :: NPlies -> QuantifiedGame -> [Turn]
- BishBosh.Evaluation.QuantifiedGame: negateFitness :: QuantifiedGame x y -> QuantifiedGame x y
+ BishBosh.Evaluation.QuantifiedGame: negateFitness :: QuantifiedGame -> QuantifiedGame
- BishBosh.Evaluation.QuantifiedGame: negateInterval :: OpenInterval x y -> OpenInterval x y
+ BishBosh.Evaluation.QuantifiedGame: negateInterval :: OpenInterval -> OpenInterval
- BishBosh.Evaluation.QuantifiedGame: type OpenInterval x y = (Maybe (QuantifiedGame x y), Maybe (QuantifiedGame x y))
+ BishBosh.Evaluation.QuantifiedGame: type OpenInterval = (Maybe QuantifiedGame, Maybe QuantifiedGame)
- BishBosh.Evaluation.QuantifiedGame: unboundedInterval :: OpenInterval x y
+ BishBosh.Evaluation.QuantifiedGame: unboundedInterval :: OpenInterval
- BishBosh.Input.EvaluationOptions: data EvaluationOptions pieceSquareValue x y
+ BishBosh.Input.EvaluationOptions: data EvaluationOptions pieceSquareValue
- BishBosh.Input.EvaluationOptions: mkEvaluationOptions :: (Enum x, Enum y, Fractional pieceSquareValue, Ord x, Ord y) => RankValues -> CriteriaWeights -> IncrementalEvaluation -> Maybe (PieceSquareTablePair x y pieceSquareValue) -> EvaluationOptions pieceSquareValue x y
+ BishBosh.Input.EvaluationOptions: mkEvaluationOptions :: Fractional pieceSquareValue => RankValues -> CriteriaWeights -> IncrementalEvaluation -> Maybe (PieceSquareTablePair pieceSquareValue) -> EvaluationOptions pieceSquareValue
- BishBosh.Input.EvaluationOptions: type Reader pieceSquareValue x y = Reader (EvaluationOptions pieceSquareValue x y)
+ BishBosh.Input.EvaluationOptions: type Reader pieceSquareValue = Reader (EvaluationOptions pieceSquareValue)
- BishBosh.Input.IOOptions: mkIOOptions :: Maybe FilePath -> Maybe NGames -> [PGNOptions] -> Maybe (FilePath, Bool) -> UIOptions -> IOOptions
+ BishBosh.Input.IOOptions: mkIOOptions :: Maybe FilePath -> Maybe NGames -> [PGNOptions] -> Maybe PersistenceSpecification -> UIOptions -> IOOptions
- BishBosh.Input.NativeUIOptions: mkNativeUIOptions :: ScreenCoordinates -> ColourScheme -> NativeUIOptions
+ BishBosh.Input.NativeUIOptions: mkNativeUIOptions :: ScreenCoordinates -> ColourScheme -> DepictFigurine -> NativeUIOptions
- BishBosh.Input.Options: data Options pieceSquareValue x y
+ BishBosh.Input.Options: data Options pieceSquareValue
- BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions pieceSquareValue x y -> SearchOptions -> IOOptions -> Options pieceSquareValue x y
+ BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions pieceSquareValue -> SearchOptions -> IOOptions -> Options pieceSquareValue
- BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue
- BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation pieceSquareValue
- BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation pieceSquareValue
- BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation pieceSquareValue
- BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue
- BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation pieceSquareValue x y
+ BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation pieceSquareValue
- BishBosh.Input.Options: swapSearchDepth :: Transformation pieceSquareValue x y
+ BishBosh.Input.Options: swapSearchDepth :: Transformation pieceSquareValue
- BishBosh.Input.PieceSquareTable: data PieceSquareTable x y pieceSquareValue
+ BishBosh.Input.PieceSquareTable: data PieceSquareTable pieceSquareValue
- BishBosh.Input.PieceSquareTable: dereference :: Rank -> PieceSquareTable x y pieceSquareValue -> Maybe (ArrayByCoordinates x y pieceSquareValue)
+ BishBosh.Input.PieceSquareTable: dereference :: Rank -> PieceSquareTable pieceSquareValue -> Maybe (ArrayByCoordinates pieceSquareValue)
- BishBosh.Input.PieceSquareTable: findUndefinedRanks :: PieceSquareTable x y pieceSquareValue -> Set Rank
+ BishBosh.Input.PieceSquareTable: findUndefinedRanks :: PieceSquareTable pieceSquareValue -> Set Rank
- BishBosh.Input.PieceSquareTable: mkPieceSquareTable :: (Enum x, Enum y, Fractional pieceSquareValue, Ord pieceSquareValue, Ord x, Ord y, Show pieceSquareValue) => Normalise -> ReflectOnY -> Assocs Rank pieceSquareValue -> PieceSquareTable x y pieceSquareValue
+ BishBosh.Input.PieceSquareTable: mkPieceSquareTable :: (Fractional pieceSquareValue, Ord pieceSquareValue, Show pieceSquareValue) => Normalise -> ReflectOnY -> Assocs Rank pieceSquareValue -> PieceSquareTable pieceSquareValue
- BishBosh.Input.StandardOpeningOptions: mkStandardOpeningOptions :: TryToMatchMoves -> TryToMatchViaJoiningMove -> TryToMatchColourFlippedPosition -> StandardOpeningOptions
+ BishBosh.Input.StandardOpeningOptions: mkStandardOpeningOptions :: TryToMatchMoves -> TryToMatchViaJoiningMove -> TryToMatchColourFlippedPosition -> PreferVictories -> StandardOpeningOptions
- BishBosh.Model.Game: (/~) :: (Enum x, Enum y, Ord x, Ord y) => Game x y -> Game x y -> Bool
+ BishBosh.Model.Game: (/~) :: Game -> Game -> Bool
- BishBosh.Model.Game: (=~) :: (Enum x, Enum y, Ord x, Ord y) => Game x y -> Game x y -> Bool
+ BishBosh.Model.Game: (=~) :: Game -> Game -> Bool
- BishBosh.Model.Game: applyEitherQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => EitherQualifiedMove x y -> Transformation x y
+ BishBosh.Model.Game: applyEitherQualifiedMove :: EitherQualifiedMove -> Transformation
- BishBosh.Model.Game: applyEitherQualifiedMoves :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => (a -> Either String (EitherQualifiedMove x y)) -> Game x y -> [a] -> Either (a, String) (Game x y)
+ BishBosh.Model.Game: applyEitherQualifiedMoves :: (a -> Either String EitherQualifiedMove) -> Game -> [a] -> Either (a, String) Game
- BishBosh.Model.Game: applyQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => QualifiedMove x y -> Transformation x y
+ BishBosh.Model.Game: applyQualifiedMove :: QualifiedMove -> Transformation
- BishBosh.Model.Game: cantConverge :: Game x y -> Game x y -> Bool
+ BishBosh.Model.Game: cantConverge :: Game -> Game -> Bool
- BishBosh.Model.Game: countPliesAvailableTo :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> Game x y -> NPlies
+ BishBosh.Model.Game: countPliesAvailableTo :: LogicalColour -> Game -> NPlies
- BishBosh.Model.Game: data Game x y
+ BishBosh.Model.Game: data Game
- BishBosh.Model.Game: findQualifiedMovesAvailableTo :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> Game x y -> [QualifiedMove x y]
+ BishBosh.Model.Game: findQualifiedMovesAvailableTo :: LogicalColour -> Game -> [QualifiedMove]
- BishBosh.Model.Game: findQualifiedMovesAvailableToNextPlayer :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Game x y -> [QualifiedMove x y]
+ BishBosh.Model.Game: findQualifiedMovesAvailableToNextPlayer :: Game -> [QualifiedMove]
- BishBosh.Model.Game: fromBoard :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Board x y -> Game x y
+ BishBosh.Model.Game: fromBoard :: Board -> Game
- BishBosh.Model.Game: isTerminated :: Game x y -> Bool
+ BishBosh.Model.Game: isTerminated :: Game -> Bool
- BishBosh.Model.Game: isValidEitherQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => EitherQualifiedMove x y -> Game x y -> Bool
+ BishBosh.Model.Game: isValidEitherQualifiedMove :: EitherQualifiedMove -> Game -> Bool
- BishBosh.Model.Game: isValidQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => QualifiedMove x y -> Game x y -> Bool
+ BishBosh.Model.Game: isValidQualifiedMove :: QualifiedMove -> Game -> Bool
- BishBosh.Model.Game: listTurns :: Game x y -> [Turn x y]
+ BishBosh.Model.Game: listTurns :: Game -> [Turn]
- BishBosh.Model.Game: listTurnsChronologically :: Game x y -> [Turn x y]
+ BishBosh.Model.Game: listTurnsChronologically :: Game -> [Turn]
- BishBosh.Model.Game: maybeLastTurn :: Game x y -> Maybe (Turn x y)
+ BishBosh.Model.Game: maybeLastTurn :: Game -> Maybe Turn
- BishBosh.Model.Game: mkAvailableQualifiedMovesFor :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> Game x y -> AvailableQualifiedMoves x y
+ BishBosh.Model.Game: mkAvailableQualifiedMovesFor :: LogicalColour -> Game -> AvailableQualifiedMoves
- BishBosh.Model.Game: mkGame :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> CastleableRooksByLogicalColour x -> Board x y -> TurnsByLogicalColour x y -> Game x y
+ BishBosh.Model.Game: mkGame :: LogicalColour -> CastleableRooksByLogicalColour -> Board -> TurnsByLogicalColour -> Game
- BishBosh.Model.Game: mkPosition :: (Enum x, Enum y, Ord x, Ord y) => Game x y -> Position x y
+ BishBosh.Model.Game: mkPosition :: Game -> Position
- BishBosh.Model.Game: resign :: Transformation x y
+ BishBosh.Model.Game: resign :: Transformation
- BishBosh.Model.Game: rollBack :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Game x y -> [(Game x y, Turn x y)]
+ BishBosh.Model.Game: rollBack :: Game -> [(Game, Turn)]
- BishBosh.Model.Game: sortAvailableQualifiedMoves :: (Ord x, Ord y) => AvailableQualifiedMoves x y -> AvailableQualifiedMoves x y
+ BishBosh.Model.Game: sortAvailableQualifiedMoves :: AvailableQualifiedMoves -> AvailableQualifiedMoves
- BishBosh.Model.Game: takeTurn :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Turn x y -> Transformation x y
+ BishBosh.Model.Game: takeTurn :: Turn -> Transformation
- BishBosh.Model.Game: type Transformation x y = Game x y -> Game x y
+ BishBosh.Model.Game: type Transformation = Game -> Game
- BishBosh.Model.Game: updateIncrementalPositionHash :: (Ix x, Bits positionHash, Enum x, Enum y, Ord y) => Game x y -> positionHash -> Game x y -> Zobrist x y positionHash -> positionHash
+ BishBosh.Model.Game: updateIncrementalPositionHash :: Bits positionHash => Game -> positionHash -> Game -> Zobrist positionHash -> positionHash
- BishBosh.Model.Game: updateTerminationReasonWith :: Result -> Transformation x y
+ BishBosh.Model.Game: updateTerminationReasonWith :: Result -> Transformation
- BishBosh.Model.Game: validateEitherQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => EitherQualifiedMove x y -> Game x y -> Maybe String
+ BishBosh.Model.Game: validateEitherQualifiedMove :: EitherQualifiedMove -> Game -> Maybe String
- BishBosh.Model.Game: validateQualifiedMove :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => QualifiedMove x y -> Game x y -> Maybe String
+ BishBosh.Model.Game: validateQualifiedMove :: QualifiedMove -> Game -> Maybe String
- BishBosh.Model.GameTree: data GameTree x y
+ BishBosh.Model.GameTree: data GameTree
- BishBosh.Model.GameTree: fromBareGameTree :: BareGameTree x y -> GameTree x y
+ BishBosh.Model.GameTree: fromBareGameTree :: BareGameTree -> GameTree
- BishBosh.Model.GameTree: fromGame :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Game x y -> GameTree x y
+ BishBosh.Model.GameTree: fromGame :: Game -> GameTree
- BishBosh.Model.GameTree: sortGameTree :: (Integral x, Integral y) => Maybe CaptureMoveSortAlgorithm -> EvaluateRank -> MoveFrequency x y -> Transformation x y
+ BishBosh.Model.GameTree: sortGameTree :: Maybe CaptureMoveSortAlgorithm -> EvaluateRank -> MoveFrequency -> Transformation
- BishBosh.Model.GameTree: toMoveFrequency :: (Ord x, Ord y) => GameTree x y -> MoveFrequency x y
+ BishBosh.Model.GameTree: toMoveFrequency :: GameTree -> MoveFrequency
- BishBosh.Model.GameTree: traceRoute :: (Eq x, Eq y) => GameTree x y -> [Turn x y] -> Maybe [Game x y]
+ BishBosh.Model.GameTree: traceRoute :: GameTree -> [Turn] -> Maybe [Game]
- BishBosh.Model.GameTree: type MoveFrequency x y = MoveFrequency (Move x y)
+ BishBosh.Model.GameTree: type MoveFrequency = MoveFrequency Move
- BishBosh.Model.PositionHashTree: mkPositionHashTree :: (Ix x, Bits positionHash, Enum x, Enum y, Ord y) => Zobrist x y positionHash -> GameTree x y -> PositionHashTree positionHash
+ BishBosh.Model.PositionHashTree: mkPositionHashTree :: Bits positionHash => Zobrist positionHash -> GameTree -> PositionHashTree positionHash
- BishBosh.Notation.ICCFNumeric: data ICCFNumeric x y
+ BishBosh.Notation.ICCFNumeric: data ICCFNumeric
- BishBosh.Notation.ICCFNumeric: mkICCFNumeric :: Move x y -> Maybe Rank -> ICCFNumeric x y
+ BishBosh.Notation.ICCFNumeric: mkICCFNumeric :: Move -> Maybe Rank -> ICCFNumeric
- BishBosh.Notation.ICCFNumeric: mkICCFNumeric' :: Promotable promotable => Move x y -> promotable -> ICCFNumeric x y
+ BishBosh.Notation.ICCFNumeric: mkICCFNumeric' :: Promotable promotable => Move -> promotable -> ICCFNumeric
- BishBosh.Notation.MoveNotation: getOrigin :: MoveNotation -> (Int, Int)
+ BishBosh.Notation.MoveNotation: getOrigin :: MoveNotation -> CoordinatePairI
- BishBosh.Notation.MoveNotation: readsQualifiedMove :: (Enum x, Enum y, Ord x, Ord y) => MoveNotation -> ReadS (EitherQualifiedMove x y)
+ BishBosh.Notation.MoveNotation: readsQualifiedMove :: MoveNotation -> ReadS EitherQualifiedMove
- BishBosh.Notation.PureCoordinate: abscissaParser :: Enum x => TextParser x
+ BishBosh.Notation.PureCoordinate: abscissaParser :: TextParser X
- BishBosh.Notation.PureCoordinate: coordinatesParser :: (Enum x, Enum y, Ord x, Ord y) => TextParser (Coordinates x y)
+ BishBosh.Notation.PureCoordinate: coordinatesParser :: TextParser Coordinates
- BishBosh.Notation.PureCoordinate: data PureCoordinate x y
+ BishBosh.Notation.PureCoordinate: data PureCoordinate
- BishBosh.Notation.PureCoordinate: mkPureCoordinate :: Move x y -> Maybe Rank -> PureCoordinate x y
+ BishBosh.Notation.PureCoordinate: mkPureCoordinate :: Move -> Maybe Rank -> PureCoordinate
- BishBosh.Notation.PureCoordinate: mkPureCoordinate' :: Promotable promotable => Move x y -> promotable -> PureCoordinate x y
+ BishBosh.Notation.PureCoordinate: mkPureCoordinate' :: Promotable promotable => Move -> promotable -> PureCoordinate
- BishBosh.Notation.PureCoordinate: ordinateParser :: Enum y => TextParser y
+ BishBosh.Notation.PureCoordinate: ordinateParser :: TextParser Y
- BishBosh.Notation.Smith: data Smith x y
+ BishBosh.Notation.Smith: data Smith
- BishBosh.Notation.Smith: fromQualifiedMove :: QualifiedMove x y -> Smith x y
+ BishBosh.Notation.Smith: fromQualifiedMove :: QualifiedMove -> Smith
- BishBosh.Property.ExtendedPositionDescription: readEPD :: ReadsEPD a => String -> a
+ BishBosh.Property.ExtendedPositionDescription: readEPD :: ReadsEPD a => EPD -> a
- BishBosh.Property.ExtendedPositionDescription: showEPD :: ShowsEPD a => a -> String
+ BishBosh.Property.ExtendedPositionDescription: showEPD :: ShowsEPD a => a -> EPD
- BishBosh.Property.ForsythEdwards: readFEN :: ReadsFEN a => String -> a
+ BishBosh.Property.ForsythEdwards: readFEN :: ReadsFEN a => FEN -> a
- BishBosh.Property.ForsythEdwards: showFEN :: ShowsFEN a => a -> String
+ BishBosh.Property.ForsythEdwards: showFEN :: ShowsFEN a => a -> FEN
- BishBosh.Search.AlphaBeta: extractSelectedTurns :: NPlies -> Result x y positionHash -> (DynamicMoveData x y positionHash, [Turn x y], NPositions)
+ BishBosh.Search.AlphaBeta: extractSelectedTurns :: NPlies -> Result positionHash -> (DynamicMoveData positionHash, [Turn], NPositions)
- BishBosh.Search.AlphaBeta: negaMax :: (Enum x, Enum y, Ord positionHash, Ord x, Ord y, Show x, Show y) => NPlies -> SearchState x y positionHash -> Reader (Result x y positionHash)
+ BishBosh.Search.AlphaBeta: negaMax :: Ord positionHash => NPlies -> SearchState positionHash -> Reader (Result positionHash)
- BishBosh.Search.DynamicMoveData: data DynamicMoveData x y positionHash
+ BishBosh.Search.DynamicMoveData: data DynamicMoveData positionHash
- BishBosh.Search.DynamicMoveData: data KillerMoveKey x y
+ BishBosh.Search.DynamicMoveData: data KillerMoveKey
- BishBosh.Search.DynamicMoveData: mkKillerMoveKeyFromTurn :: Turn x y -> KillerMoveKey x y
+ BishBosh.Search.DynamicMoveData: mkKillerMoveKeyFromTurn :: Turn -> KillerMoveKey
- BishBosh.Search.DynamicMoveData: type Transformation x y positionHash = DynamicMoveData x y positionHash -> DynamicMoveData x y positionHash
+ BishBosh.Search.DynamicMoveData: type Transformation positionHash = DynamicMoveData positionHash -> DynamicMoveData positionHash
- BishBosh.Search.DynamicMoveData: updateKillerMoves :: Transformation (KillerMoveKey x y) -> Transformation x y positionHash
+ BishBosh.Search.DynamicMoveData: updateKillerMoves :: Transformation KillerMoveKey -> Transformation positionHash
- BishBosh.Search.DynamicMoveData: updateTranspositions :: Transformation (QualifiedMove x y) positionHash -> Transformation x y positionHash
+ BishBosh.Search.DynamicMoveData: updateTranspositions :: Transformation QualifiedMove positionHash -> Transformation positionHash
- BishBosh.Search.Search: data Result x y positionHash
+ BishBosh.Search.Search: data Result positionHash
- BishBosh.Search.Search: search :: (Enum x, Enum y, Ord positionHash, Ord x, Ord y, Show x, Show y) => NPlies -> SearchState x y positionHash -> Reader (Result x y positionHash)
+ BishBosh.Search.Search: search :: Ord positionHash => NPlies -> SearchState positionHash -> Reader (Result positionHash)
- BishBosh.Search.SearchState: data SearchState x y positionHash
+ BishBosh.Search.SearchState: data SearchState positionHash
- BishBosh.Search.SearchState: initialise :: PositionHashQuantifiedGameTree x y positionHash -> SearchState x y positionHash
+ BishBosh.Search.SearchState: initialise :: PositionHashQuantifiedGameTree positionHash -> SearchState positionHash
- BishBosh.Search.SearchState: mkSearchState :: PositionHashQuantifiedGameTree x y positionHash -> DynamicMoveData x y positionHash -> SearchState x y positionHash
+ BishBosh.Search.SearchState: mkSearchState :: PositionHashQuantifiedGameTree positionHash -> DynamicMoveData positionHash -> SearchState positionHash
- BishBosh.State.Board: countDefendersByCoordinatesByLogicalColour :: (Enum x, Enum y, Ord x, Ord y) => Board x y -> NDefendersByCoordinatesByLogicalColour x y
+ BishBosh.State.Board: countDefendersByCoordinatesByLogicalColour :: Board -> NDefendersByCoordinatesByLogicalColour
- BishBosh.State.Board: data Board x y
+ BishBosh.State.Board: data Board
- BishBosh.State.Board: exposesKing :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Move x y -> Board x y -> Bool
+ BishBosh.State.Board: exposesKing :: LogicalColour -> Move -> Board -> Bool
- BishBosh.State.Board: findAttackersOf :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Coordinates x y -> Board x y -> [(Coordinates x y, Rank)]
+ BishBosh.State.Board: findAttackersOf :: LogicalColour -> Coordinates -> Board -> [(Coordinates, Rank)]
- BishBosh.State.Board: findAttacksBy :: (Enum x, Enum y, Ord x, Ord y) => Piece -> Coordinates x y -> Board x y -> [Coordinates x y]
+ BishBosh.State.Board: findAttacksBy :: Piece -> Coordinates -> Board -> [Coordinates]
- BishBosh.State.Board: isKingChecked :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Board x y -> Bool
+ BishBosh.State.Board: isKingChecked :: LogicalColour -> Board -> Bool
- BishBosh.State.Board: movePiece :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Move x y -> Maybe MoveType -> Transformation x y
+ BishBosh.State.Board: movePiece :: Move -> Maybe MoveType -> Transformation
- BishBosh.State.Board: sumPieceSquareValueByLogicalColour :: (Enum x, Enum y, Num pieceSquareValue, Ord x, Ord y) => PieceSquareByCoordinatesByRank x y pieceSquareValue -> Board x y -> ArrayByLogicalColour pieceSquareValue
+ BishBosh.State.Board: sumPieceSquareValueByLogicalColour :: Num pieceSquareValue => PieceSquareByCoordinatesByRank pieceSquareValue -> Board -> ArrayByLogicalColour pieceSquareValue
- BishBosh.State.Board: summariseNDefendersByLogicalColour :: Board x y -> ArrayByLogicalColour NPieces
+ BishBosh.State.Board: summariseNDefendersByLogicalColour :: Board -> ArrayByLogicalColour NPieces
- BishBosh.State.CastleableRooksByLogicalColour: canCastle :: LogicalColour -> CastleableRooksByLogicalColour x -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: canCastle :: LogicalColour -> CastleableRooksByLogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: canCastleWith :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Coordinates x y -> CastleableRooksByLogicalColour x -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: canCastleWith :: LogicalColour -> Coordinates -> CastleableRooksByLogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: cantConverge :: CastleableRooksByLogicalColour x -> CastleableRooksByLogicalColour x -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: cantConverge :: CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: data CastleableRooksByLogicalColour x
+ BishBosh.State.CastleableRooksByLogicalColour: data CastleableRooksByLogicalColour
- BishBosh.State.CastleableRooksByLogicalColour: fromAssocs :: (Enum x, Ord x, Show x) => AbscissaeByLogicalColour x -> CastleableRooksByLogicalColour x
+ BishBosh.State.CastleableRooksByLogicalColour: fromAssocs :: AbscissaeByLogicalColour -> CastleableRooksByLogicalColour
- BishBosh.State.CastleableRooksByLogicalColour: fromBoard :: (Enum x, Enum y, Ord x, Ord y, Show x) => Board x y -> CastleableRooksByLogicalColour x
+ BishBosh.State.CastleableRooksByLogicalColour: fromBoard :: Board -> CastleableRooksByLogicalColour
- BishBosh.State.CastleableRooksByLogicalColour: fromTurnsByLogicalColour :: (Enum x, Enum y, Eq x, Eq y) => TurnsByLogicalColour x y -> CastleableRooksByLogicalColour x
+ BishBosh.State.CastleableRooksByLogicalColour: fromTurnsByLogicalColour :: TurnsByLogicalColour -> CastleableRooksByLogicalColour
- BishBosh.State.CastleableRooksByLogicalColour: hasCastled :: LogicalColour -> CastleableRooksByLogicalColour x -> Bool
+ BishBosh.State.CastleableRooksByLogicalColour: hasCastled :: LogicalColour -> CastleableRooksByLogicalColour -> Bool
- BishBosh.State.CastleableRooksByLogicalColour: listIncrementalRandoms :: Ix x => CastleableRooksByLogicalColour x -> CastleableRooksByLogicalColour x -> Zobrist x y random -> [random]
+ BishBosh.State.CastleableRooksByLogicalColour: listIncrementalRandoms :: CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour -> Zobrist random -> [random]
- BishBosh.State.CastleableRooksByLogicalColour: locateForLogicalColour :: LogicalColour -> CastleableRooksByLogicalColour x -> Maybe [x]
+ BishBosh.State.CastleableRooksByLogicalColour: locateForLogicalColour :: LogicalColour -> CastleableRooksByLogicalColour -> Maybe [X]
- BishBosh.State.CastleableRooksByLogicalColour: takeTurn :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Turn x y -> Transformation x
+ BishBosh.State.CastleableRooksByLogicalColour: takeTurn :: LogicalColour -> Turn -> Transformation
- BishBosh.State.CastleableRooksByLogicalColour: type TurnsByLogicalColour x y = TurnsByLogicalColour (Turn x y)
+ BishBosh.State.CastleableRooksByLogicalColour: type TurnsByLogicalColour = TurnsByLogicalColour Turn
- BishBosh.State.CastleableRooksByLogicalColour: unify :: Transformation x
+ BishBosh.State.CastleableRooksByLogicalColour: unify :: Transformation
- BishBosh.State.CoordinatesByRankByLogicalColour: assocs :: CoordinatesByRankByLogicalColour x y -> [(Piece, [Coordinates x y])]
+ BishBosh.State.CoordinatesByRankByLogicalColour: assocs :: CoordinatesByRankByLogicalColour -> [(Piece, [Coordinates])]
- BishBosh.State.CoordinatesByRankByLogicalColour: data CoordinatesByRankByLogicalColour x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: data CoordinatesByRankByLogicalColour
- BishBosh.State.CoordinatesByRankByLogicalColour: dereference :: LogicalColour -> Rank -> CoordinatesByRankByLogicalColour x y -> [Coordinates x y]
+ BishBosh.State.CoordinatesByRankByLogicalColour: dereference :: LogicalColour -> Rank -> CoordinatesByRankByLogicalColour -> [Coordinates]
- BishBosh.State.CoordinatesByRankByLogicalColour: findPassedPawnCoordinatesByLogicalColour :: (Enum x, Ord x, Ord y) => CoordinatesByRankByLogicalColour x y -> CoordinatesByLogicalColour x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: findPassedPawnCoordinatesByLogicalColour :: CoordinatesByRankByLogicalColour -> CoordinatesByLogicalColour
- BishBosh.State.CoordinatesByRankByLogicalColour: findPiecesOfColour :: LogicalColour -> CoordinatesByRankByLogicalColour x y -> [LocatedPiece x y]
+ BishBosh.State.CoordinatesByRankByLogicalColour: findPiecesOfColour :: LogicalColour -> CoordinatesByRankByLogicalColour -> [LocatedPiece]
- BishBosh.State.CoordinatesByRankByLogicalColour: fromMaybePieceByCoordinates :: (Enum x, Enum y, Ord x, Ord y) => MaybePieceByCoordinates x y -> CoordinatesByRankByLogicalColour x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: fromMaybePieceByCoordinates :: MaybePieceByCoordinates -> CoordinatesByRankByLogicalColour
- BishBosh.State.CoordinatesByRankByLogicalColour: getKingsCoordinates :: LogicalColour -> CoordinatesByRankByLogicalColour x y -> Coordinates x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: getKingsCoordinates :: LogicalColour -> CoordinatesByRankByLogicalColour -> Coordinates
- BishBosh.State.CoordinatesByRankByLogicalColour: listCoordinates :: CoordinatesByRankByLogicalColour x y -> [Coordinates x y]
+ BishBosh.State.CoordinatesByRankByLogicalColour: listCoordinates :: CoordinatesByRankByLogicalColour -> [Coordinates]
- BishBosh.State.CoordinatesByRankByLogicalColour: movePiece :: (Eq x, Eq y) => Move x y -> Piece -> Maybe Rank -> Either (Coordinates x y) (Maybe Rank) -> Transformation x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: movePiece :: Move -> Piece -> Maybe Rank -> Either Coordinates (Maybe Rank) -> Transformation
- BishBosh.State.CoordinatesByRankByLogicalColour: sortCoordinates :: (Ord x, Ord y) => Transformation x y
+ BishBosh.State.CoordinatesByRankByLogicalColour: sortCoordinates :: Transformation
- BishBosh.State.CoordinatesByRankByLogicalColour: type CoordinatesByLogicalColour x y = ArrayByLogicalColour [Coordinates x y]
+ BishBosh.State.CoordinatesByRankByLogicalColour: type CoordinatesByLogicalColour = ArrayByLogicalColour [Coordinates]
- BishBosh.State.EnPassantAbscissa: data EnPassantAbscissa x
+ BishBosh.State.EnPassantAbscissa: data EnPassantAbscissa
- BishBosh.State.EnPassantAbscissa: mkMaybeEnPassantAbscissa :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> MaybePieceByCoordinates x y -> Turn x y -> Maybe (EnPassantAbscissa x)
+ BishBosh.State.EnPassantAbscissa: mkMaybeEnPassantAbscissa :: LogicalColour -> MaybePieceByCoordinates -> Turn -> Maybe EnPassantAbscissa
- BishBosh.State.InstancesByPosition: mkInstancesByPosition :: Map position NPositions -> InstancesByPosition position
+ BishBosh.State.InstancesByPosition: mkInstancesByPosition :: (Foldable foldable, Ord position) => (a -> position) -> foldable a -> InstancesByPosition position
- BishBosh.State.MaybePieceByCoordinates: data MaybePieceByCoordinates x y
+ BishBosh.State.MaybePieceByCoordinates: data MaybePieceByCoordinates
- BishBosh.State.MaybePieceByCoordinates: dereference :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> MaybePieceByCoordinates x y -> Maybe Piece
+ BishBosh.State.MaybePieceByCoordinates: dereference :: Coordinates -> MaybePieceByCoordinates -> Maybe Piece
- BishBosh.State.MaybePieceByCoordinates: findAttackerInDirection :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> Direction -> Coordinates x y -> MaybePieceByCoordinates x y -> Maybe (Coordinates x y, Rank)
+ BishBosh.State.MaybePieceByCoordinates: findAttackerInDirection :: LogicalColour -> Direction -> Coordinates -> MaybePieceByCoordinates -> Maybe (Coordinates, Rank)
- BishBosh.State.MaybePieceByCoordinates: findBlockingPiece :: (Enum x, Enum y, Ord x, Ord y) => Direction -> Coordinates x y -> MaybePieceByCoordinates x y -> Maybe (LocatedPiece x y)
+ BishBosh.State.MaybePieceByCoordinates: findBlockingPiece :: Direction -> Coordinates -> MaybePieceByCoordinates -> Maybe LocatedPiece
- BishBosh.State.MaybePieceByCoordinates: inferMoveType :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Move x y -> Maybe Rank -> MaybePieceByCoordinates x y -> MoveType
+ BishBosh.State.MaybePieceByCoordinates: inferMoveType :: Move -> Maybe Rank -> MaybePieceByCoordinates -> MoveType
- BishBosh.State.MaybePieceByCoordinates: isClear :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> Coordinates x y -> MaybePieceByCoordinates x y -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isClear :: Coordinates -> Coordinates -> MaybePieceByCoordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isEnPassantMove :: (Enum x, Enum y, Ord x, Ord y) => Move x y -> MaybePieceByCoordinates x y -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isEnPassantMove :: Move -> MaybePieceByCoordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isObstructed :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> Coordinates x y -> MaybePieceByCoordinates x y -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isObstructed :: Coordinates -> Coordinates -> MaybePieceByCoordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isOccupied :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> MaybePieceByCoordinates x y -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isOccupied :: Coordinates -> MaybePieceByCoordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: isVacant :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> MaybePieceByCoordinates x y -> Bool
+ BishBosh.State.MaybePieceByCoordinates: isVacant :: Coordinates -> MaybePieceByCoordinates -> Bool
- BishBosh.State.MaybePieceByCoordinates: listDestinationsFor :: (Enum x, Enum y, Ord x, Ord y) => Coordinates x y -> Piece -> MaybePieceByCoordinates x y -> [(Coordinates x y, Maybe Rank)]
+ BishBosh.State.MaybePieceByCoordinates: listDestinationsFor :: Coordinates -> Piece -> MaybePieceByCoordinates -> [(Coordinates, Maybe Rank)]
- BishBosh.State.MaybePieceByCoordinates: movePiece :: (Enum x, Enum y, Ord x, Ord y) => Move x y -> Piece -> Maybe (Coordinates x y) -> Transformation x y
+ BishBosh.State.MaybePieceByCoordinates: movePiece :: Move -> Piece -> Maybe Coordinates -> Transformation
- BishBosh.State.MaybePieceByCoordinates: show2D :: (Enum x, Enum y, Ord x, Ord y) => Column -> ColourScheme -> (Int, Int) -> MaybePieceByCoordinates x y -> String
+ BishBosh.State.MaybePieceByCoordinates: show2D :: Column -> ColourScheme -> Bool -> (X, Y) -> MaybePieceByCoordinates -> String
- BishBosh.State.Position: data Position x y
+ BishBosh.State.Position: data Position
- BishBosh.State.Position: mkPosition :: (Enum x, Enum y, Ord x, Ord y) => LogicalColour -> MaybePieceByCoordinates x y -> CastleableRooksByLogicalColour x -> Maybe (Turn x y) -> Position x y
+ BishBosh.State.Position: mkPosition :: LogicalColour -> MaybePieceByCoordinates -> CastleableRooksByLogicalColour -> Maybe Turn -> Position
- BishBosh.StateProperty.Mutator: class Mutator mutator x y
+ BishBosh.StateProperty.Mutator: class Mutator mutator
- BishBosh.StateProperty.Mutator: defineCoordinates :: Mutator mutator x y => Maybe Piece -> Coordinates x y -> mutator x y -> mutator x y
+ BishBosh.StateProperty.Mutator: defineCoordinates :: Mutator mutator => Maybe Piece -> Coordinates -> mutator -> mutator
- BishBosh.StateProperty.Mutator: placeAllPieces :: (Empty (mutator x y), Mutator mutator x y) => [(Piece, Coordinates x y)] -> mutator x y
+ BishBosh.StateProperty.Mutator: placeAllPieces :: (Empty mutator, Mutator mutator) => [(Piece, Coordinates)] -> mutator
- BishBosh.StateProperty.Mutator: placeFirstPiece :: (Empty (mutator x y), Mutator mutator x y) => Piece -> Coordinates x y -> mutator x y
+ BishBosh.StateProperty.Mutator: placeFirstPiece :: (Empty mutator, Mutator mutator) => Piece -> Coordinates -> mutator
- BishBosh.StateProperty.Mutator: placePiece :: Mutator mutator x y => Piece -> Coordinates x y -> mutator x y -> mutator x y
+ BishBosh.StateProperty.Mutator: placePiece :: Mutator mutator => Piece -> Coordinates -> mutator -> mutator
- BishBosh.StateProperty.Mutator: removePiece :: Mutator mutator x y => Coordinates x y -> mutator x y -> mutator x y
+ BishBosh.StateProperty.Mutator: removePiece :: Mutator mutator => Coordinates -> mutator -> mutator
- BishBosh.StateProperty.Seeker: class Seeker seeker x y
+ BishBosh.StateProperty.Seeker: class Seeker seeker
- BishBosh.StateProperty.Seeker: findAllPieces :: Seeker seeker x y => seeker x y -> [LocatedPiece x y]
+ BishBosh.StateProperty.Seeker: findAllPieces :: Seeker seeker => seeker -> [LocatedPiece]
- BishBosh.StateProperty.Seeker: findPieces :: Seeker seeker x y => (Piece -> Bool) -> seeker x y -> [LocatedPiece x y]
+ BishBosh.StateProperty.Seeker: findPieces :: Seeker seeker => (Piece -> Bool) -> seeker -> [LocatedPiece]
- BishBosh.StateProperty.Seeker: findProximateKnights :: Seeker seeker x y => LogicalColour -> Coordinates x y -> seeker x y -> [Coordinates x y]
+ BishBosh.StateProperty.Seeker: findProximateKnights :: Seeker seeker => LogicalColour -> Coordinates -> seeker -> [Coordinates]
- BishBosh.Type.Length: type Column = X
+ BishBosh.Type.Length: type Column = Base
- BishBosh.Type.Length: type Row = Y
+ BishBosh.Type.Length: type Row = Base
- BishBosh.UI.Command: Hint :: Command x y
+ BishBosh.UI.Command: Hint :: Command
- BishBosh.UI.Command: Print :: PrintObject -> Command x y
+ BishBosh.UI.Command: Print :: PrintObject -> Command
- BishBosh.UI.Command: Quit :: Command x y
+ BishBosh.UI.Command: Quit :: Command
- BishBosh.UI.Command: Report :: ReportObject -> Command x y
+ BishBosh.UI.Command: Report :: ReportObject -> Command
- BishBosh.UI.Command: Resign :: Command x y
+ BishBosh.UI.Command: Resign :: Command
- BishBosh.UI.Command: Restart :: Command x y
+ BishBosh.UI.Command: Restart :: Command
- BishBosh.UI.Command: RollBack :: Maybe NPlies -> Command x y
+ BishBosh.UI.Command: RollBack :: Maybe NPlies -> Command
- BishBosh.UI.Command: Save :: Command x y
+ BishBosh.UI.Command: Save :: Command
- BishBosh.UI.Command: Set :: SetObject -> Command x y
+ BishBosh.UI.Command: Set :: SetObject -> Command
- BishBosh.UI.Command: Swap :: Command x y
+ BishBosh.UI.Command: Swap :: Command
- BishBosh.UI.Command: data Command x y
+ BishBosh.UI.Command: data Command
- BishBosh.UI.Command: readsCommand :: String -> Either String (Command x y, String)
+ BishBosh.UI.Command: readsCommand :: String -> Either String (Command, String)
- BishBosh.UI.Command: showsCommand :: Command x y -> ShowS
+ BishBosh.UI.Command: showsCommand :: Command -> ShowS
Files
- README.markdown +2/−1
- bishbosh.cabal +132/−154
- bishbosh.spec +1/−1
- changelog.markdown +41/−11
- config/CECP/bishbosh_black.xml +2/−1
- config/Raw/bishbosh_black.xml +2/−1
- config/Raw/bishbosh_black_figurine.xml +45/−0
- config/Raw/bishbosh_both.xml +2/−1
- config/Raw/bishbosh_duel_black.xml +4/−3
- config/Raw/bishbosh_duel_white.xml +4/−3
- config/Raw/bishbosh_prof.xml +2/−1
- config/Raw/bishbosh_white.xml +2/−1
- config/bishbosh.dtd +4/−0
- config/bishbosh.rng +8/−0
- makefile +22/−17
- man/man1/bishbosh.1 +1/−1
- man/man1/duel.1 +8/−0
- man/man5/bishbosh.5 +4/−0
- src-exe/BishBosh/Play.hs +45/−38
- src-exe/BishBosh/State/PlayState.hs +43/−67
- src-exe/BishBosh/Text/ShowColouredPrefix.hs +0/−52
- src-exe/BishBosh/UI/CECP.hs +79/−108
- src-exe/BishBosh/UI/Raw.hs +91/−116
- src-exe/Duel/Process/Intermediary.hs +53/−26
- src-exe/Main.hs +10/−7
- src-lib/BishBosh/Attribute/ANSIColourCode.hs +76/−0
- src-lib/BishBosh/Attribute/ColourScheme.hs +4/−3
- src-lib/BishBosh/Attribute/Direction.hs +7/−13
- src-lib/BishBosh/Attribute/MoveType.hs +9/−0
- src-lib/BishBosh/Attribute/PhysicalColour.hs +12/−37
- src-lib/BishBosh/Attribute/Rank.hs +4/−4
- src-lib/BishBosh/Cartesian/Abscissa.hs +38/−40
- src-lib/BishBosh/Cartesian/Coordinates.hs +102/−256
- src-lib/BishBosh/Cartesian/Ordinate.hs +22/−52
- src-lib/BishBosh/Cartesian/Vector.hs +96/−122
- src-lib/BishBosh/Component/Accountant.hs +42/−0
- src-lib/BishBosh/Component/CastlingMove.hs +14/−47
- src-lib/BishBosh/Component/EitherQualifiedMove.hs +4/−4
- src-lib/BishBosh/Component/Move.hs +31/−49
- src-lib/BishBosh/Component/Piece.hs +57/−95
- src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs +23/−96
- src-lib/BishBosh/Component/QualifiedMove.hs +7/−14
- src-lib/BishBosh/Component/Turn.hs +17/−28
- src-lib/BishBosh/Component/Zobrist.hs +16/−71
- src-lib/BishBosh/ContextualNotation/PGN.hs +33/−97
- src-lib/BishBosh/ContextualNotation/PGNComment.hs +5/−3
- src-lib/BishBosh/ContextualNotation/PGNDatabase.hs +22/−44
- src-lib/BishBosh/ContextualNotation/PositionHashQualifiedMoveTree.hs +122/−126
- src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs +31/−38
- src-lib/BishBosh/ContextualNotation/StandardAlgebraic.hs +34/−82
- src-lib/BishBosh/Data/Enum.hs +0/−34
- src-lib/BishBosh/Data/Foldable.hs +4/−4
- src-lib/BishBosh/Evaluation/Fitness.hs +76/−105
- src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs +49/−57
- src-lib/BishBosh/Evaluation/QuantifiedGame.hs +19/−27
- src-lib/BishBosh/Input/CriteriaWeights.hs +0/−81
- src-lib/BishBosh/Input/EvaluationOptions.hs +23/−48
- src-lib/BishBosh/Input/IOOptions.hs +48/−19
- src-lib/BishBosh/Input/NativeUIOptions.hs +36/−12
- src-lib/BishBosh/Input/Options.hs +24/−35
- src-lib/BishBosh/Input/PieceSquareTable.hs +28/−39
- src-lib/BishBosh/Input/SearchOptions.hs +16/−15
- src-lib/BishBosh/Input/StandardOpeningOptions.hs +39/−37
- src-lib/BishBosh/Model/Game.hs +128/−391
- src-lib/BishBosh/Model/GameTree.hs +27/−48
- src-lib/BishBosh/Model/MoveFrequency.hs +15/−9
- src-lib/BishBosh/Model/PositionHashTree.hs +9/−14
- src-lib/BishBosh/Notation/Figurine.hs +61/−0
- src-lib/BishBosh/Notation/ICCFNumeric.hs +21/−50
- src-lib/BishBosh/Notation/MoveNotation.hs +17/−20
- src-lib/BishBosh/Notation/Notation.hs +157/−0
- src-lib/BishBosh/Notation/PureCoordinate.hs +43/−128
- src-lib/BishBosh/Notation/Smith.hs +38/−50
- src-lib/BishBosh/Property/Empty.hs +11/−7
- src-lib/BishBosh/Property/ExtendedPositionDescription.hs +20/−4
- src-lib/BishBosh/Property/ForsythEdwards.hs +10/−4
- src-lib/BishBosh/Property/Null.hs +1/−1
- src-lib/BishBosh/Property/Opposable.hs +6/−1
- src-lib/BishBosh/Search/AlphaBeta.hs +31/−62
- src-lib/BishBosh/Search/DynamicMoveData.hs +10/−10
- src-lib/BishBosh/Search/KillerMoves.hs +13/−13
- src-lib/BishBosh/Search/Search.hs +16/−31
- src-lib/BishBosh/Search/SearchState.hs +9/−9
- src-lib/BishBosh/Search/Transpositions.hs +7/−6
- src-lib/BishBosh/State/Board.hs +92/−229
- src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs +53/−95
- src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs +58/−92
- src-lib/BishBosh/State/EnPassantAbscissa.hs +12/−19
- src-lib/BishBosh/State/InstancesByPosition.hs +32/−20
- src-lib/BishBosh/State/MaybePieceByCoordinates.hs +120/−302
- src-lib/BishBosh/State/Position.hs +18/−40
- src-lib/BishBosh/StateProperty/Hashable.hs +64/−0
- src-lib/BishBosh/StateProperty/Mutator.hs +21/−21
- src-lib/BishBosh/StateProperty/Seeker.hs +58/−9
- src-lib/BishBosh/Text/Poly.hs +4/−2
- src-lib/BishBosh/Text/ShowColouredPrefix.hs +53/−0
- src-lib/BishBosh/Time/GameClock.hs +3/−3
- src-lib/BishBosh/Type/Count.hs +14/−3
- src-lib/BishBosh/Type/Length.hs +35/−18
- src-lib/BishBosh/Type/Mass.hs +11/−3
- src-lib/BishBosh/UI/Command.hs +32/−26
- src-lib/BishBosh/UI/ReportObject.hs +7/−10
- src-lib/BishBosh/UI/SetObject.hs +33/−13
- src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs +5/−12
- src-test/BishBosh/Test/HUnit/Cartesian/Vector.hs +4/−9
- src-test/BishBosh/Test/HUnit/Component/CastlingMove.hs +3/−4
- src-test/BishBosh/Test/HUnit/Component/Move.hs +1/−8
- src-test/BishBosh/Test/HUnit/Component/Piece.hs +12/−14
- src-test/BishBosh/Test/HUnit/Component/Zobrist.hs +4/−5
- src-test/BishBosh/Test/HUnit/ContextualNotation/PGN.hs +11/−14
- src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs +56/−43
- src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs +9/−6
- src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs +12/−13
- src-test/BishBosh/Test/HUnit/Input/Options.hs +1/−2
- src-test/BishBosh/Test/HUnit/Model/Game.hs +15/−23
- src-test/BishBosh/Test/HUnit/Model/GameTree.hs +3/−9
- src-test/BishBosh/Test/HUnit/Search/Search.hs +46/−39
- src-test/BishBosh/Test/HUnit/State/Board.hs +95/−84
- src-test/BishBosh/Test/HUnit/Time/GameClock.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Attribute/MoveType.hs +6/−0
- src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs +17/−69
- src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs +27/−23
- src-test/BishBosh/Test/QuickCheck/Component/Move.hs +11/−27
- src-test/BishBosh/Test/QuickCheck/Component/Piece.hs +5/−17
- src-test/BishBosh/Test/QuickCheck/Component/QualifiedMove.hs +5/−18
- src-test/BishBosh/Test/QuickCheck/Component/Turn.hs +8/−20
- src-test/BishBosh/Test/QuickCheck/Component/Zobrist.hs +7/−63
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGN.hs +18/−27
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGNComment.hs +8/−4
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs +4/−19
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/QualifiedMoveForest.hs +3/−18
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/StandardAlgebraic.hs +10/−6
- src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs +6/−29
- src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs +20/−31
- src-test/BishBosh/Test/QuickCheck/Input/NativeUIOptions.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Input/Options.hs +15/−12
- src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs +5/−11
- src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs +4/−4
- src-test/BishBosh/Test/QuickCheck/Input/StandardOpeningOptions.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Model/Game.hs +82/−83
- src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs +6/−13
- src-test/BishBosh/Test/QuickCheck/Model/MoveFrequency.hs +4/−4
- src-test/BishBosh/Test/QuickCheck/Notation/Figurine.hs +43/−0
- src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs +5/−18
- src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs +46/−1
- src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs +5/−18
- src-test/BishBosh/Test/QuickCheck/Notation/Smith.hs +4/−17
- src-test/BishBosh/Test/QuickCheck/Search/KillerMoves.hs +5/−15
- src-test/BishBosh/Test/QuickCheck/Search/Search.hs +7/−1
- src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs +8/−17
- src-test/BishBosh/Test/QuickCheck/State/Board.hs +40/−54
- src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs +11/−22
- src-test/BishBosh/Test/QuickCheck/State/InstancesByPosition.hs +3/−3
- src-test/BishBosh/Test/QuickCheck/State/Position.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/State/TurnsByLogicalColour.hs +7/−9
- src-test/BishBosh/Test/QuickCheck/StateProperty/Censor.hs +12/−12
- src-test/BishBosh/Test/QuickCheck/StateProperty/Hashable.hs +78/−0
- src-test/BishBosh/Test/QuickCheck/StateProperty/Seeker.hs +72/−0
- src-test/BishBosh/Test/QuickCheck/Type/Count.hs +36/−0
- src-test/BishBosh/Test/QuickCheck/Type/Length.hs +41/−0
- src-test/BishBosh/Test/QuickCheck/UI/Command.hs +2/−9
- src-test/BishBosh/Test/QuickCheck/UI/SetObject.hs +5/−3
- src-test/HUnit.hs +3/−9
- src-test/QuickCheck.hs +8/−2
README.markdown view
@@ -2,8 +2,9 @@ [](https://travis-ci.com/functionalley/BishBosh) [](https://hackage.haskell.org/package/bishbosh)+[](https://github.com/functionalley/BishBosh)+[](https://github.com/functionalley/BishBosh) [](https://www.gnu.org/licenses/gpl-3.0)-[](https://haskell.org) This is "**BishBosh**", a chess-game which can be rendered in a terminal (emulator) using raw ASCII, or used as an engine by [xboard](https://www.gnu.org/software/xboard/).
bishbosh.cabal view
@@ -16,7 +16,7 @@ -- along with BishBosh. If not, see <http://www.gnu.org/licenses/>. Name: bishbosh-Version: 0.1.1.0+Version: 0.1.2.0 Copyright: (C) 2018 Dr. Alistair Ward License: GPL-3.0-or-later License-file: LICENSE@@ -24,9 +24,9 @@ Stability: stable Synopsis: Plays chess. Build-type: Simple-Description: A chess-game which can be rendered in a terminal (emulator) in raw ASCII, or used as an engine by xboard.+Description: A chess-game which can be rendered in a terminal (emulator) in raw ASCII, or used as an engine by @xboard@. Category: Game-Tested-with: GHC == 8.0, GHC == 8.4, GHC == 8.8, GHC == 8.10+Tested-with: GHC == 8.0, GHC == 8.2, GHC == 8.4, GHC == 8.6, GHC == 8.8, GHC == 8.10 Homepage: https://functionalley.com/BishBosh/bishbosh.html Maintainer: mailto:bishbosh@functionalley.com Bug-reports: mailto:bishbosh@functionalley.com@@ -64,14 +64,6 @@ Default: False -- Automatically disabled when the required package isn't available.--- To access Parsec's more precise error-messages, manually disable using one of:--- runhaskell Setup configure -f -polyparse --verbose;--- stack build --flag 'bishbosh:-polyparse' --cabal-verbose;-flag polyparse- Description: Link with package "polyparse" when available, rather than "parsec".- Default: True---- Automatically disabled when the required package isn't available. -- To force validation of the XML-configuration against the packaged DTD, manually disable using one of: -- runhaskell Setup configure -f -hxtrelaxng --verbose; -- stack build --flag 'bishbosh:-hxtrelaxng' --cabal-verbose;@@ -80,6 +72,7 @@ Default: True -- Whether to use narrower numerical types than machine-defaults. CAVEAT: this option increases both the space allocated & the execution-time.+-- CAVEAT: incompatble with the flag 'precision'. flag narrownumbers Description: Use narrow numerical types. Manual: True@@ -91,6 +84,20 @@ Manual: True Default: False +-- Automatically disabled when the required package isn't available.+-- To access Parsec's more precise error-messages, manually disable using one of:+-- runhaskell Setup configure -f -polyparse --verbose;+-- stack build --flag 'bishbosh:-polyparse' --cabal-verbose;+flag polyparse+ 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'.+flag precision+ Description: Use precise numerical types. CAVEAT: this is incompatible with either 'unboxedarrays' or 'narrownumbers'.+ Manual: True+ Default: False+ -- Concurrency is used to implement Pondering, & parallelism is used when searching through archived games. flag threaded Description: Build for parallel runtime.@@ -98,6 +105,7 @@ Default: True -- Whether to use unboxed arrays where possible.+-- CAVEAT: incompatble with the flag 'precision'. flag unboxedarrays Description: Use unboxed arrays. Manual: True@@ -109,12 +117,60 @@ Description: Link with package "unix" when available. Default: True -Library+common commonStanza Default-language: Haskell2010- GHC-options: -O2 -Wall -fno-warn-tabs -fno-warn-unused-top-binds -Wno-all-missed-specialisations++ Build-depends:+ base == 4.*,+ containers ^>= 0.6.2,+ data-default ^>= 0.7.1,+ filepath++ GHC-options: -Wall -Wredundant-constraints -fno-warn-tabs++common exeStanza+ Hs-source-dirs: src-exe+ GHC-options: -O2+ Autogen-modules: Paths_bishbosh+ Other-modules: Paths_bishbosh+ Build-depends:+ bishbosh,+ hxt ^>= 9.3.1++ if impl(ghc >= 7.0) && flag(llvm)+ GHC-options: -fllvm++common profStanza+ if impl(ghc >= 7.4.1)+ GHC-prof-options: -fprof-auto -fprof-cafs++ if flag(threaded)+ GHC-prof-options: -fno-prof-count-entries+ else+ GHC-prof-options: -auto-all -caf-all++common testStanza+ Hs-source-dirs: src-test+ Build-depends:+ array ^>= 0.5.1.1,+ bishbosh,+ mtl ^>= 2.2.2,+ random,+ toolshed ^>= 0.18.0++ if flag(polyparse)+ Build-depends: polyparse ^>= 1.13+ CPP-Options: -DUSE_POLYPARSE='L'+ else+ Build-depends: parsec ^>= 3.1.14.0++Library+ Import: commonStanza, profStanza+ GHC-options: -O2 -fno-warn-unused-top-binds -Wno-all-missed-specialisations Hs-source-dirs: src-lib Exposed-modules:+ BishBosh.Attribute.ANSIColourCode BishBosh.Attribute.CaptureMoveSortAlgorithm BishBosh.Attribute.ColourScheme BishBosh.Attribute.Direction@@ -127,6 +183,7 @@ BishBosh.Cartesian.Coordinates BishBosh.Cartesian.Ordinate BishBosh.Cartesian.Vector+ BishBosh.Component.Accountant BishBosh.Component.CastlingMove BishBosh.Component.EitherQualifiedMove BishBosh.Component.Move@@ -143,7 +200,6 @@ BishBosh.ContextualNotation.StandardAlgebraic BishBosh.Data.Bool BishBosh.Data.Either- BishBosh.Data.Enum BishBosh.Data.Exception BishBosh.Data.Foldable BishBosh.Data.Integral@@ -178,8 +234,10 @@ BishBosh.Model.GameTree BishBosh.Model.MoveFrequency BishBosh.Model.PositionHashTree+ BishBosh.Notation.Figurine BishBosh.Notation.ICCFNumeric BishBosh.Notation.MoveNotation+ BishBosh.Notation.Notation BishBosh.Notation.PureCoordinate BishBosh.Notation.Smith BishBosh.Property.Arboreal@@ -214,12 +272,14 @@ BishBosh.State.MaybePieceByCoordinates BishBosh.State.Position BishBosh.StateProperty.Censor+ BishBosh.StateProperty.Hashable BishBosh.StateProperty.Mutator BishBosh.StateProperty.Seeker BishBosh.State.TurnsByLogicalColour BishBosh.Text.AutoComplete BishBosh.Text.Case BishBosh.Text.Encoding+ BishBosh.Text.ShowColouredPrefix BishBosh.Text.ShowList BishBosh.Text.ShowPrefix BishBosh.Time.GameClock@@ -234,168 +294,110 @@ BishBosh.UI.SetObject Build-depends:- array >= 0.5.1.1,- base >= 4.9 && < 5.0,- containers,- data-default,- deepseq >= 1.4.1,- extra,- factory >= 0.3.1,- filepath,- hxt,- mtl,- process >= 1.6.4,+ array ^>= 0.5.1.1,+ deepseq ^>= 1.4.1,+ extra ^>= 1.7.4,+ factory ^>= 0.3.1,+ hxt ^>= 9.3.1,+ mtl ^>= 2.2.2,+ process >= 1.6.4, random, time,- toolshed >= 0.18+ toolshed ^>= 0.18.0 - if impl(ghc >= 7.0)- if flag(llvm)- GHC-options: -fllvm+ if impl(ghc >= 7.0) && flag(llvm)+ GHC-options: -fllvm - if impl(ghc >= 7.4.1)- GHC-prof-options: -fprof-auto -fprof-cafs+ if flag(precision)+ CPP-Options: -DUSE_PRECISION+ else+ if flag(narrownumbers)+ CPP-Options: -DUSE_NARROW_NUMBERS - if flag(threaded)- GHC-prof-options: -fno-prof-count-entries+ if flag(unboxedarrays)+ CPP-Options: -DUSE_UNBOXED_ARRAYS - if impl(ghc >= 8.0)- GHC-options: -Wredundant-constraints- else- GHC-prof-options: -auto-all -caf-all+ if flag(newtypewrappers)+ CPP-Options: -DUSE_NEWTYPE_WRAPPERS if flag(polyparse)- Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=2+ Build-depends: polyparse ^>= 1.13+ CPP-Options: -DUSE_POLYPARSE='L' Exposed-modules: BishBosh.Text.Poly else- Build-depends: parsec-- if flag(narrownumbers)- CPP-Options: -DUSE_NARROW_NUMBERS-- if flag(newtypewrappers)- CPP-Options: -DUSE_NEWTYPE_WRAPPERS+ Build-depends: parsec ^>= 3.1.14.0 if flag(threaded) Build-depends: parallel >= 3.0 CPP-Options: -DUSE_PARALLEL - if flag(unboxedarrays)- CPP-Options: -DUSE_UNBOXED_ARRAYS- Executable bishbosh- Default-language: Haskell2010- GHC-options: -O2 -Wall -fno-warn-tabs- Hs-source-dirs: src-exe- Main-is: Main.hs- Autogen-modules: Paths_bishbosh+ Import: commonStanza, exeStanza, profStanza+ Main-is: Main.hs Other-modules: BishBosh.Concurrent.Pondering BishBosh.Play BishBosh.State.ApplicationTerminationReason BishBosh.State.PlayState- BishBosh.Text.ShowColouredPrefix BishBosh.UI.CECP BishBosh.UI.Raw- Paths_bishbosh if flag(unix) Other-modules: BishBosh.Concurrent.SignalHandlers Build-depends:- array >= 0.5.1.1,- base >= 4.9 && < 5.0,- bishbosh,- containers,- data-default,- deepseq >= 1.4.1,+ array ^>= 0.5.1.1,+ deepseq ^>= 1.4.1, directory,- extra,- factory >= 0.3.1,- filepath,- hxt,- mtl,+ extra ^>= 1.7.4,+ factory ^>= 0.3.1,+ mtl ^>= 2.2.2, random,- toolshed >= 0.18+ toolshed ^>= 0.18.0 if impl(ghc >= 7.0)- if flag(llvm)- GHC-options: -fllvm- if flag(threaded) GHC-options: -rtsopts "-with-rtsopts=-N -H100M" if impl(ghc >= 7.4.1)- GHC-prof-options: -fprof-auto -fprof-cafs -rtsopts -with-rtsopts=-H100M-- if flag(threaded)- GHC-prof-options: -fno-prof-count-entries-- if impl(ghc >= 8.0)- GHC-options: -Wredundant-constraints- else- GHC-prof-options: -auto-all -caf-all+ GHC-prof-options: -rtsopts -with-rtsopts=-H100M if flag(hxtrelaxng)- Build-depends: hxt-relaxng+ Build-depends: hxt-relaxng ^>= 9.1.5 CPP-Options: -DUSE_HXTRELAXNG - if flag(narrownumbers)- CPP-Options: -DUSE_NARROW_NUMBERS- if flag(threaded)- CPP-Options: -DUSE_PARALLEL GHC-options: -threaded - if flag(unboxedarrays)+ 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- Build-depends: unix+ Build-depends: unix ^>= 2.7.2+ CPP-Options: -DUSE_UNIX -- This application coordinates a duel between two independently configured instances of 'bishbosh'. Executable duel- Default-language: Haskell2010- GHC-options: -O2 -Wall -fno-warn-tabs- Hs-source-dirs: src-exe- Main-is: Duel.hs- Autogen-modules: Paths_bishbosh+ Import: commonStanza, exeStanza+ Main-is: Duel.hs Other-modules: Duel.Data.Options Duel.IO.Logger Duel.Process.Handles Duel.Process.Intermediary- Paths_bishbosh - Build-depends:- base >= 4.9 && < 5.0,- bishbosh,- containers,- data-default,- filepath,- hxt,- process >= 1.6.4+ Build-depends: process >= 1.6.4 CPP-Options: -DMOVE_NOTATION='S' - if impl(ghc >= 7.0)- if flag(llvm)- GHC-options: -fllvm-- if impl(ghc >= 8.0)- GHC-options: -Wredundant-constraints- -- Static unit-tests of the library. Test-Suite hunit-tests- Default-language: Haskell2010- GHC-options: -Wall -fno-warn-tabs- Hs-source-dirs: src-test+ Import: commonStanza, testStanza Main-is: HUnit.hs Type: exitcode-stdio-1.0 Autogen-modules: Paths_bishbosh@@ -426,34 +428,16 @@ Paths_bishbosh Build-depends:- array >= 0.5.1.1,- base >= 4.9 && < 5.0,- bishbosh,- containers,- data-default,- filepath, HUnit,- hxt,- mtl,- random,- toolshed >= 0.18-- if impl(ghc >= 8.0)- GHC-options: -Wredundant-constraints+ hxt ^>= 9.3.1 - if flag(polyparse)- Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=2- else- Build-depends: parsec+-- CPP-Options: -DUSE_BRATKO_KOPEC -- Random unit-tests of the library. Test-Suite quickcheck-tests- Default-language: Haskell2010- GHC-options: -Wall -fno-warn-tabs- Hs-source-dirs: src-test- Main-is: QuickCheck.hs- Type: exitcode-stdio-1.0+ Import: commonStanza, testStanza+ Main-is: QuickCheck.hs+ Type: exitcode-stdio-1.0 Other-modules: BishBosh.Test.QuickCheck.Attribute.CaptureMoveSortAlgorithm@@ -495,6 +479,7 @@ BishBosh.Test.QuickCheck.Model.Game BishBosh.Test.QuickCheck.Model.GameTree BishBosh.Test.QuickCheck.Model.MoveFrequency+ BishBosh.Test.QuickCheck.Notation.Figurine BishBosh.Test.QuickCheck.Notation.ICCFNumeric BishBosh.Test.QuickCheck.Notation.MoveNotation BishBosh.Test.QuickCheck.Notation.PureCoordinate@@ -510,38 +495,31 @@ BishBosh.Test.QuickCheck.State.InstancesByPosition BishBosh.Test.QuickCheck.State.Position BishBosh.Test.QuickCheck.StateProperty.Censor+ BishBosh.Test.QuickCheck.StateProperty.Hashable+ BishBosh.Test.QuickCheck.StateProperty.Seeker 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.UI.Command BishBosh.Test.QuickCheck.UI.PrintObject BishBosh.Test.QuickCheck.UI.ReportObject BishBosh.Test.QuickCheck.UI.SetObject Build-depends:- array >= 0.5.1.1,- base >= 4.9 && < 5.0,- bishbosh,- containers,- data-default,- deepseq >= 1.4.1,- extra,- filepath,- mtl,- QuickCheck >= 2.8.2,- random,- toolshed >= 0.18+ deepseq ^>= 1.4.1,+ extra ^>= 1.7.4,+ QuickCheck ^>= 2.13.2 - if impl(ghc >= 8.0)- GHC-options: -Wredundant-constraints+ if flag(newtypewrappers)+ CPP-Options: -DUSE_NEWTYPE_WRAPPERS - if flag(polyparse)- Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=2- else- Build-depends: parsec+ if flag(precision)+ CPP-Options: -DUSE_PRECISION+ elif flag(narrownumbers)+ CPP-Options: -DUSE_NARROW_NUMBERS if flag(threaded)- CPP-Options: -DUSE_PARALLEL GHC-options: -threaded
bishbosh.spec view
@@ -24,7 +24,7 @@ Summary: BishBosh is a chess-game. Name: bishbosh-Version: 0.1.1.0+Version: 0.1.2.0 Release: 1 License: GPLv3 # From '/usr/share/doc/packages/rpm/GROUPS'.
changelog.markdown view
@@ -90,17 +90,17 @@ ## 0.1.1.0 ### New Modules: ----------------------------------------------------------New Module | Purpose-------------------------------------------------| --------**BishBosh.Time.StopWatch** | Replaces module **BishBosh.Data.Time** to encapsulate interaction with module **Data.Time.Clock**.-**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.Crypto** | Self-documentation.-**BishBosh.Type.Length** | Replaced the polymorphic type-parameters **row** & **column** with newtypes 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.+New Module | Purpose+----------------------------------------| -------+**BishBosh.Time.StopWatch** | Replaces module **BishBosh.Data.Time** to encapsulate interaction with module **Data.Time.Clock**.+**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.Crypto** | Self-documentation.+**BishBosh.Type.Length** | Replaced the polymorphic type-parameters **row** & **column** with newtypes 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. ### 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**.@@ -115,4 +115,34 @@ * 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. * Avoided repeated calls from module **BishBosh.Evaluation.Fitness** to function **IBishBosh.nput.RankValues.calculateMaximumTotalValue** by adding the record-field **BishBosh.Input.EvaluationOptions.getMaximumTotalRankValue**.++## 0.1.2.0+* Features:+ + Added a Boolean configuration-option **BishBosh.Input.NativeUIOptions.getDepictFigurine** to specify whether the native UI should depict pieces using Unicode figurines rather than merely ASCII letters.+ + **duel** now accumulates the frequency-distribution of games played in order to detect duplicates & warn when there's insufficient randomness.+ + Added the runtime ability to set the position using *Extended Position Description*.+* Efficiency:+ + Reimplemented function **BishBosh.Cartesian.Abscissa.getAdjacents** to promote memoisation.+ + Made **BishBosh.Cartesian.Coordinates** & **BishBosh.Attribute.Direction** strict.+ + Changed to use **Double** rather than **Rational** to perform the calculations defined by **BishBosh.Evaluation.Fitness**, before conversion to **BishBosh.Metric.CriterionValue.CriterionValue**.+ + Added a Boolean switch **preferVictories** to **standardOpeningOptions** to govern whether from all matching positions extracted from the PGN-database, to prefer moves which result in a greater probability of victory, for the player who has the next move. Turning this off reduces the evaluation required of the PGN-parser; & there's no down-side if the PGN-database is known not to actually record any victories.+ + Improved **BishBosh.ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition**, by independently comparing the pieces of each player, between the target game & a node of the tree, allowing earlier termination of the search.+* Bug-fixes:+ + Avoided potential divide-by-zero @ **BishBosh.Input.CriteriaWeights.getWeightOfMaterial** / **BishBosh.Input.RankValues.calculateMaximumTotalValue** @.+ + Guarded against starting from a persisted, but terminated, game.+ + Added guards to function **BishBosh.Component.Piece.promote**.+ + 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:+ + 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),+ + permit unification of the similar type-classes **BishBosh.Component.Zobrist.Hashable[12]D**, & to avoid the requirement for the **MultiParameterTypeClasses** pragma.+* Structural:+ + Moved the type-class from module **BishBosh.Component.Zobrist** into a new module **BishBosh.StateProperty.Hashable**.+ + Replaced non-specific type @ (Int, Int) @ coordinates in **BishBosh.Notation.{ICCFNumeric, PureCoordinate, Smith}** with @ (**BishBosh.Type.Length.X**, **BishBosh.Type.Length.Y**) @, & moved common code into a new module **BishBosh.Notation.Notation**.+ + 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**.
config/CECP/bishbosh_black.xml view
@@ -26,8 +26,9 @@ &criteriaWeights; &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" usePondering="True">+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="True"> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="Black" searchDepth="5"/> </searchDepthByLogicalColour>
config/Raw/bishbosh_black.xml view
@@ -26,8 +26,9 @@ &criteriaWeights; &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" usePondering="True">+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="True"> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="Black" searchDepth="4"/> </searchDepthByLogicalColour>
+ config/Raw/bishbosh_black_figurine.xml view
@@ -0,0 +1,45 @@+<?xml version="1.0" encoding="UTF-8"?>+<!DOCTYPE options SYSTEM "../bishbosh.dtd"> <!-- CAVEAT: amend after relocating this file ! -->+<!--+ AUTHOR: Dr. Alistair Ward++ 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/>.+-->+<options>+ <evaluationOptions>+ &rankValues_Kaufman;+ &criteriaWeights;+ &pieceSquareTables_symmetric;+ </evaluationOptions>+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="True">+ &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings -->+ <searchDepthByLogicalColour>+ <byLogicalColour logicalColour="Black" searchDepth="4"/>+ </searchDepthByLogicalColour>+ </searchOptions>+ <ioOptions maximumPGNNames="8">+ &pgnOptions_SCID;+ <uiOptions>+ <nativeUIOptions depictFigurine="True">+ <colourScheme darkPieceColour="Black" darkSquareColour="Blue" lightPieceColour="White" lightSquareColour="Yellow"/>+ </nativeUIOptions>+ </uiOptions>+ </ioOptions>+</options>+
config/Raw/bishbosh_both.xml view
@@ -26,8 +26,9 @@ &criteriaWeights; &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3">+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True"> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="Black" searchDepth="4"/> <byLogicalColour logicalColour="White" searchDepth="4"/>
config/Raw/bishbosh_duel_black.xml view
@@ -31,16 +31,17 @@ <criteriaWeights material="1" mobility="0" pieceSquareValue="0.1" castlingPotential="0" defence="0" doubledPawns="0" isolatedPawns="0" passedPawns="0"/> <!-- N.B. only those criteria under test need be non-zero --> &pieceSquareTables_Rofchade; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" usePondering="False"> <!-- CAVEAT: pondering uses time more productively used by the other instance -->+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="False"> <!-- CAVEAT: pondering uses time more productively used by the other instance --> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- maximise randomness --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="Black" searchDepth="3"/> </searchDepthByLogicalColour> </searchOptions> <ioOptions>- &pgnOptions_SCID; <!-- CAVEAT: specification of a PGN-database is required for non-determininstic behaviour -->+ &pgnOptions_SCID; &pgnOptions_FICS; <!-- CAVEAT: specification of a PGN-database is required for non-deterministic behaviour --> <persistence filePath="/dev/null" automatic="False"/> <!-- CAVEAT: otherwise the game may already have started -->- <uiOptions moveNotation="Smith"> <!-- CAVEAT: coordinate with the opponent defined in 'bishbosh_duel_white.txt' & 'bishbosh.cabal' -->+ <uiOptions moveNotation="Smith"> <!-- CAVEAT: coordinate with the opponent defined in 'bishbosh_duel_white.txt' & the compilation-flag in 'bishbosh.cabal' --> <nativeUIOptions/> </uiOptions> </ioOptions>
config/Raw/bishbosh_duel_white.xml view
@@ -31,16 +31,17 @@ <criteriaWeights material="1" mobility="0" pieceSquareValue="0.1" castlingPotential="0" defence="0" doubledPawns="0" isolatedPawns="0" passedPawns="0"/> <!-- N.B. only those criteria under test need be non-zero --> &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" usePondering="False"> <!-- CAVEAT: pondering uses time more productively used by the other instance -->+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="False"> <!-- CAVEAT: pondering uses time more productively used by the other instance --> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- maximise randomness --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="White" searchDepth="3"/> </searchDepthByLogicalColour> </searchOptions> <ioOptions>- &pgnOptions_SCID; <!-- CAVEAT: specification of a PGN-database is required for non-determininstic behaviour -->+ &pgnOptions_SCID; &pgnOptions_FICS; <!-- CAVEAT: specification of a PGN-database is required for non-deterministic behaviour --> <persistence filePath="/dev/null" automatic="False"/> <!-- CAVEAT: otherwise the game may already have started -->- <uiOptions moveNotation="Smith"> <!-- CAVEAT: coordinate with the opponent defined in 'bishbosh_duel_black.txt' & 'bishbosh.cabal' -->+ <uiOptions moveNotation="Smith"> <!-- CAVEAT: coordinate with the opponent defined in 'bishbosh_duel_black.txt' & the compilation-flag in 'bishbosh.cabal' --> <nativeUIOptions/> </uiOptions> </ioOptions>
config/Raw/bishbosh_prof.xml view
@@ -26,8 +26,9 @@ <criteriaWeights material="1" mobility="0.01" pieceSquareValue="0.01" castlingPotential="0.01" defence="0.0001" doubledPawns="0.0001" isolatedPawns="0.0001" passedPawns="0.0001"/> &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions sortOnStandardOpeningMoveFrequency="True" captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3">+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True"> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="Black" searchDepth="4"/> <byLogicalColour logicalColour="White" searchDepth="4"/>
config/Raw/bishbosh_white.xml view
@@ -26,8 +26,9 @@ &criteriaWeights; &pieceSquareTables_symmetric; </evaluationOptions>- <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" usePondering="True">+ <searchOptions captureMoveSortAlgorithm="MVVLVA" retireKillerMovesAfter="3" sortOnStandardOpeningMoveFrequency="True" usePondering="True"> &transpositions;+ <standardOpeningOptions preferVictories="False"/> <!-- the SCID PGN-database only contains standard-openings --> <searchDepthByLogicalColour> <byLogicalColour logicalColour="White" searchDepth="4"/> </searchDepthByLogicalColour>
config/bishbosh.dtd view
@@ -80,6 +80,7 @@ tryToMatchMoves (False | True) #IMPLIED tryToMatchViaJoiningMove (False | True) #IMPLIED tryToMatchColourFlippedPosition (False | True) #IMPLIED+ preferVictories (False | True) #IMPLIED > <!ELEMENT searchDepthByLogicalColour (byLogicalColour)*> <!ELEMENT byLogicalColour EMPTY>@@ -127,6 +128,9 @@ verbosity (Silent | Normal | Verbose | Deafening) #IMPLIED > <!ELEMENT nativeUIOptions ((boardMagnification)?, (colourScheme)?)>+ <!ATTLIST nativeUIOptions+ depictFigurine (False | True) #IMPLIED+ > <!ELEMENT boardMagnification EMPTY> <!ATTLIST boardMagnification nRows CDATA #REQUIRED
config/bishbosh.rng view
@@ -104,6 +104,10 @@ <attribute name="tryToMatchColourFlippedPosition"> <ref name="Boolean"/> </attribute>+ </optional><optional>+ <attribute name="preferVictories">+ <ref name="Boolean"/>+ </attribute> </optional> </element> <!-- standardOpeningOptions --> </optional>@@ -220,6 +224,10 @@ <choice> <element name="nativeUIOptions"> <optional>+ <attribute name="depictFigurine">+ <ref name="Boolean"/>+ </attribute>+ </optional><optional> <element name="boardMagnification"> <attribute name="nRows"> <data type="positiveInteger"/>
makefile view
@@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with BishBosh. If not, see <http://www.gnu.org/licenses/>. -.PHONY: cabalCheck duel findOmissions graphmod haddock hlint prof randomTest sdist test xboard+.PHONY: cabalCheck duel findOmissions graphmod haddock hlint prof profN2 randomTest sdist test xboard PACKAGE_NAME = bishbosh SHELL = /bin/bash@@ -29,45 +29,50 @@ # Groom sourcecode. hlint: $(BIN_DIR)/hlint- @$@ -j --no-exit-code\+ @$@ -j --no-exit-code\+ --cpp-define 'USE_NEWTYPE_WRAPPERS'\ --cpp-define 'USE_PARALLEL'\- --cpp-define 'USE_POLYPARSE=1'\+ --cpp-define 'USE_POLYPARSE=L'\ --cpp-define 'USE_UNBOXED_ARRAYS'\- --cpp-define 'USE_NEWTYPE_WRAPPERS'\ --ignore 'Use tuple-section'\ src-lib/ +RTS -N -RTS- @$@ -j --no-exit-code\+ @$@ -j --no-exit-code\+ --cpp-define 'MOVE_NOTATION=S'\ --cpp-define 'USE_HXTRELAXNG'\- --cpp-define 'USE_PARALLEL'\ --cpp-define 'USE_UNBOXED_ARRAYS'\ --cpp-define 'USE_UNIX'\- --cpp-define 'MOVE_NOTATION=S'\ --ignore 'Reduce duplication'\ src-exe/ +RTS -N -RTS- @$@ -j --cpp-define 'USE_PARALLEL'\- --cpp-define 'USE_POLYPARSE=1'\- --cpp-define 'USE_SEARCH'\+ @$@ -j --cpp-define 'USE_NEWTYPE_WRAPPERS'\+ --cpp-define 'USE_POLYPARSE=L'\+ --cpp-define 'USE_BRATKO_KOPEC'\ --ignore 'Use tuple-section'\ src-test/ +RTS -N -RTS # Serially compile with various CPP-flags & run the test-suites. test:- @for FLAG in -polyparse newtypewrappers -hxtrelaxng narrownumbers unboxedarrays -threaded; do\+ @for FLAG in -polyparse newtypewrappers narrownumbers unboxedarrays -hxtrelaxng -threaded precision; do\ echo $${FLAG};\ stack '$@' --flag="$(PACKAGE_NAME):$${FLAG}" $(GHC_OPTIONS) || break;\ done # Compile with random CPP-flags & run the test-suites. randomTest:- @FLAGS=$$(shuf --echo -- hxtrelaxng -hxtrelaxng narrownumbers -narrownumbers newtypewrappers -newtypewrappers polyparse -polyparse threaded -threaded unboxedarrays -unboxedarrays | head --lines=3 | sed -e 's/\(.*\)/--flag=$(PACKAGE_NAME):\1/');\- echo $$FLAGS;\+ 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) -# Profile.+# Profile a single-threaded build, to access entry-counts. prof:- @stack install --library-profiling --executable-profiling $(GHC_OPTIONS)- @$(PACKAGE_NAME) -i 'config/Raw/$(PACKAGE_NAME)_$@.xml' +RTS -p -N2 -RTS+ @stack install --profile --flag='bishbosh:-threaded' $(GHC_OPTIONS);+ sleep 16; # 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);+ @$(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)@@ -94,5 +99,5 @@ # Find source-files missing from the distribution. findOmissions: sdist- @diff <(find src-* -type f -name '*.hs' | sed 's!^\./!!' | sort) <(tar -ztf dist*/sdist/$(PACKAGE_NAME)-*.tar.gz | grep '\.hs$$' | grep -v 'Setup.hs' | sed 's!^$(PACKAGE_NAME)-[0-9.]*/!!' | sort)+ @diff <(find src-* -type f -name '*.hs' | sed 's!^\./!!' | sort) <(tar -ztf `find dist* -mtime 0 -name '$(PACKAGE_NAME)-*.tar.gz' -print` | grep '\.hs$$' | grep -v 'Setup.hs' | sed 's!^$(PACKAGE_NAME)-[0-9.]*/!!' | sort)
man/man1/bishbosh.1 view
@@ -110,7 +110,7 @@ :restart Start a new game. :rollBack [Int] Roll-back the optionally specified number of plies (half moves), defaulting to "\fB2\fR" when there's one manual player & "\fB1\fR" when both players are manual. :save Save the current game-state in "\fB~/.bishbosh\fR"; this is automatic unless explicitly un-configured.-:set \fBsearchDepth\fR \fIInt\fR Mutate the value of "\fBsearchDepth\fR", (see "\fBsearchOptions\fR" in \fBsection-5\fR of the man-pages).+:set object Specify "\fBEPD\fR <String>" to define the position using \fBExtended Position Description\fR or "\fBsearchDepth\fR <Int>" to define the number of plies to search. :swap Swap sides. If the moves of one side were automated, then this will cause automation of the moves of the other side. .TE .SS Hardware-requirements.
man/man1/duel.1 view
@@ -11,6 +11,11 @@ while measuring the total time taken by either side & collating the game-results to permit comparison of the fitness of their respective configurations. .PP This process facilitates optimisation of the complex configuration of \fBbishbosh\fR.+.PP+CAVEAT: the population of games resulting from this statistical experiment must be diverse, but this application's logic is largely deterministic (& both players are configured to use it).+In order to introduce some randomness, PGN-databases must be configured in which the application may search for positions matching the current game.+When more than one match for the current position is found, one of them is \fIrandomly\fR selected at the source of the next move.+If the specified PGN-databases fail to provide such move-options, deterministic play will result. .SH OPTIONS .TP \fB--verbosity=\fR(\fBSilent\fR|\fBNormal\fR|\fBVerbose\fR|\fBDeafening\fR), defaulting to "\fBNormal\fR".@@ -88,6 +93,9 @@ .SH AUTHOR Written by Dr. Alistair Ward. .SH BUGS+.PP+In the absence of any configured \fBpgnOptions\fR, the game is completely deterministic & will reproduce the previous result endlessly.+Even when PGN-databases have been configured, they may introduce insufficient randomness to produce a large population of unique games on which to perform statistical analysis. .SS "REPORTING BUGS" Report bugs to "\fBbishbosh@functionalley.com\fR". .SH COPYRIGHT
man/man5/bishbosh.5 view
@@ -140,6 +140,7 @@ tryToMatchMoves Bool True whether to attempt to exactly match the moves already made, with a standard opening; i.e. without matching transpositions. tryToMatchViaJoiningMove Bool True whether to attempt to join the current position (irrespective of the means by which it was achieved) to a standard opening that's only one move away. tryToMatchColourFlippedPosition Bool True whether to attempt to match a colour-flipped (<\fBhttps://www.chessprogramming.org/Color_Flipping\fR>) version of the current position with a standard opening.+preferVictories Bool True whether from all matching positions extracted from the PGN-database, to prefer moves which result in a greater probability of victory, for the player who has the next move. .TE .IP \(bu \fBsearchDepth\fR \fIInt\fR, defaulting to "\fB4\fR" (minimum "\fB1\fR"): the number of plies (half moves) to search ahead, when selecting the next move.@@ -220,6 +221,9 @@ darkSquareColour (\fBBlack\fR|\fBRed\fR|\fBGreen\fR|\fBBlue\fR|\fBMagenta\fR|\fBCyan\fR) lightSquareColour (\fBRed\fR|\fBGreen\fR|\fBYellow\fR|\fBMagenta\fR|\fBCyan\fR|\fBWhite\fR) .TE+.IP \(bu+\fBdepictFigurine\fR: specifies whether to depict pieces as Unicode figurines, or merely ASCII letters.+This will require a terminal configured to render Unicode. .SH FILES .TS lb lb
src-exe/BishBosh/Play.hs view
@@ -47,7 +47,10 @@ import qualified BishBosh.Input.Options as Input.Options import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions+import qualified BishBosh.Input.Verbosity as Input.Verbosity+import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Model.GameTree as Model.GameTree+import qualified BishBosh.Model.MoveFrequency as Model.MoveFrequency import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Arboreal as Property.Arboreal import qualified BishBosh.Property.Empty as Property.Empty@@ -55,13 +58,12 @@ 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.Length as Type.Length 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 Data.Array.IArray+import qualified Control.Monad import qualified Data.Bits import qualified Data.Default import qualified Data.Maybe@@ -76,39 +78,32 @@ -- | Plays the game according to the specified configuration. play :: (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,- Data.Array.IArray.Ix x,+ 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).+ 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,- Integral x,- Integral y,- Ord positionHash,- Read x,- Read y,- Real pieceSquareValue,- Show pieceSquareValue,- Show x,- Show y,- System.Random.Random positionHash,- System.Random.RandomGen randomGen+ Data.Bits.FiniteBits positionHash,+ Fractional pieceSquareValue,+ Ord positionHash,+ Real pieceSquareValue,+ Show pieceSquareValue,+ System.Random.Random positionHash,+ System.Random.RandomGen randomGen )- => randomGen- -> Input.Options.Options pieceSquareValue x y- -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y -- ^ Standard openings.- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ => Input.Verbosity.Verbosity+ -> randomGen+ -> Input.Options.Options pieceSquareValue+ -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -- ^ Standard openings.+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash) {-# SPECIALISE play :: System.Random.RandomGen randomGen- => randomGen- -> Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y- -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest Type.Length.X Type.Length.Y- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ => Input.Verbosity.Verbosity+ -> randomGen+ -> Input.Options.Options Type.Mass.PieceSquareValue+ -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest+ -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash) #-}-play randomGen options qualifiedMoveForest = Data.Maybe.maybe (+play verbosity randomGen options qualifiedMoveForest = Data.Maybe.maybe ( return {-to IO-monad-} Data.Default.def {-game-} ) ( \(filePath, _) -> if any (System.FilePath.equalFilePath filePath) [@@ -118,9 +113,16 @@ then return {-to IO-monad-} Data.Default.def {-game-} else Control.Exception.catch ( do- s <- readFile filePath+ game <- read <$> readFile filePath - return {-to IO-monad-} $! read s -- Force evaluation, to trigger any exception thrown from within 'catch'.+ Data.Maybe.maybe (+ return {-to IO-monad-} $! game -- Force evaluation, to trigger any exception thrown from within 'catch'.+ ) (+ \terminationReason -> do+ Control.Monad.when (verbosity > minBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixWarning . showString "persisted game had terminated (" $ shows terminationReason "); restarting game."++ return {-to IO-monad-} Data.Default.def+ ) $ Model.Game.getMaybeTerminationReason game ) $ \e -> do System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixWarning . showString "'readFile' failed; " $ shows (e :: Control.Exception.SomeException) "." @@ -128,9 +130,18 @@ ) ( Input.IOOptions.getMaybePersistence ioOptions ) >>= (- (+ let+ sortOnStandardOpeningMoveFrequency = Input.SearchOptions.getSortOnStandardOpeningMoveFrequency searchOptions++ moveFrequency+ | sortOnStandardOpeningMoveFrequency = Model.GameTree.toMoveFrequency $ ContextualNotation.QualifiedMoveForest.toGameTree qualifiedMoveForest+ | otherwise = Property.Empty.empty+ in ( \playState -> Data.Maybe.maybe (- return {-to IO-monad-} playState+ do+ Control.Monad.when (sortOnStandardOpeningMoveFrequency && verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . shows (Model.MoveFrequency.countEntries moveFrequency) . showString " plies are recorded in the tree, of which " $ shows (Model.MoveFrequency.countDistinctEntries moveFrequency) " are distinct."++ return {-to IO-monad-} playState ) ( \depth -> do System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "Move-tree:\n" $ (@@ -141,11 +152,7 @@ return {-to IO-monad-} playState ) $ Input.UIOptions.getMaybePrintMoveTree uiOptions- ) . State.PlayState.initialise options zobrist (- if Input.SearchOptions.getSortOnStandardOpeningMoveFrequency searchOptions- then Model.GameTree.toMoveFrequency $ ContextualNotation.QualifiedMoveForest.toGameTree qualifiedMoveForest- else Property.Empty.empty {-MoveFrequency-}- )+ ) . State.PlayState.initialise options zobrist moveFrequency ) >>= ( const UI.Raw.takeTurns ||| const UI.CECP.takeTurns $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- Select a user-interface. ) (
src-exe/BishBosh/State/PlayState.hs view
@@ -73,10 +73,8 @@ import qualified BishBosh.State.ApplicationTerminationReason as State.ApplicationTerminationReason import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default import qualified Data.List@@ -89,40 +87,35 @@ #endif -- | The type threaded through the sequence of /game/s during play.-data PlayState pieceSquareValue positionHash x y = MkPlayState {+data PlayState pieceSquareValue positionHash = MkPlayState { getCriterionValues :: [[Metric.CriterionValue.CriterionValue]], -- ^ The /criterion-value/s accumulated during the game.- getZobrist :: Component.Zobrist.Zobrist x y positionHash, -- ^ The constant hash-codes used construct position-hashes.- getMoveFrequency :: Model.GameTree.MoveFrequency x y, -- ^ The constant frequency of moves extracted from file.- getSearchState :: Search.SearchState.SearchState x y positionHash,- getOptions :: Input.Options.Options pieceSquareValue x y, -- ^ The constant options by which the game is configured.+ 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. getMaybeApplicationTerminationReason :: Maybe State.ApplicationTerminationReason.ApplicationTerminationReason -- ^ Whether the game has terminated. } -- | Constructor. initialise :: (- Data.Array.IArray.Ix x, #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).+ 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,- Integral x,- Integral y,- Real pieceSquareValue,- Show x,- Show y+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Real pieceSquareValue )- => Input.Options.Options pieceSquareValue x y- -> Component.Zobrist.Zobrist x y positionHash- -> Model.GameTree.MoveFrequency x y- -> Model.Game.Game x y- -> PlayState pieceSquareValue positionHash x y+ => Input.Options.Options pieceSquareValue+ -> Component.Zobrist.Zobrist positionHash+ -> Model.GameTree.MoveFrequency+ -> Model.Game.Game+ -> PlayState pieceSquareValue positionHash {-# SPECIALISE initialise- :: Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y- -> Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash- -> Model.GameTree.MoveFrequency Type.Length.X Type.Length.Y- -> Model.Game.Game Type.Length.X Type.Length.Y- -> PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y+ :: Input.Options.Options Type.Mass.PieceSquareValue+ -> Component.Zobrist.Zobrist Type.Crypto.PositionHash+ -> Model.GameTree.MoveFrequency+ -> Model.Game.Game+ -> PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash #-} initialise options zobrist moveFrequency game = MkPlayState { getCriterionValues = [],@@ -136,32 +129,27 @@ } -- | Accessor.-getGame :: PlayState pieceSquareValue positionHash x y -> Model.Game.Game x y+getGame :: PlayState pieceSquareValue 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 x y = PlayState pieceSquareValue positionHash x y -> PlayState pieceSquareValue positionHash x y+type Transformation pieceSquareValue positionHash = PlayState pieceSquareValue positionHash -> PlayState pieceSquareValue positionHash -- | Mutator.-setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> Transformation pieceSquareValue positionHash x y+setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash -> Transformation pieceSquareValue 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 :: (- Data.Array.IArray.Ix x, #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).+ 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,- Integral x,- Integral y,- Real pieceSquareValue,- Show x,- Show y- ) => Model.Game.Game x y -> Transformation pieceSquareValue positionHash x y+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Real pieceSquareValue+ ) => Model.Game.Game -> Transformation pieceSquareValue positionHash reconstructPositionHashQuantifiedGameTree game playState@MkPlayState { getZobrist = zobrist, getMoveFrequency = moveFrequency,@@ -174,18 +162,13 @@ -- | Reset to the initial state. resetPositionHashQuantifiedGameTree :: (- Data.Array.IArray.Ix x, #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).+ 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,- Integral x,- Integral y,- Real pieceSquareValue,- Show x,- Show y- ) => Transformation pieceSquareValue positionHash x y+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Real pieceSquareValue+ ) => Transformation pieceSquareValue positionHash resetPositionHashQuantifiedGameTree playState = reconstructPositionHashQuantifiedGameTree Data.Default.def playState { getCriterionValues = [], getMaybeApplicationTerminationReason = Nothing@@ -194,15 +177,15 @@ -- | Mutator. updateWithAutomaticMove :: [Metric.CriterionValue.CriterionValue]- -> Search.SearchState.SearchState x y positionHash- -> Transformation pieceSquareValue positionHash x y+ -> Search.SearchState.SearchState positionHash+ -> Transformation pieceSquareValue positionHash updateWithAutomaticMove criterionValues searchState playState = playState { getCriterionValues = criterionValues : getCriterionValues playState, getSearchState = searchState } -- | Mutator.-updateWithManualMove :: (Eq x, Eq y) => Model.Game.Game x y -> Transformation pieceSquareValue positionHash x y+updateWithManualMove :: Model.Game.Game -> Transformation pieceSquareValue 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."@@ -222,7 +205,7 @@ Floating standardDeviation, Fractional mean )- => PlayState pieceSquareValue positionHash x y+ => PlayState pieceSquareValue positionHash -> [(mean, standardDeviation)] calculateCriterionValueStatistics MkPlayState { getCriterionValues = criterionValues } = map ( (@@ -233,22 +216,15 @@ ) $ Data.List.transpose criterionValues -- | Resignation by the player who currently holds the choice of move.-resign :: Transformation pieceSquareValue positionHash x y+resign :: Transformation pieceSquareValue positionHash resign playState@MkPlayState { getSearchState = searchState } = setPositionHashQuantifiedGameTree ( Evaluation.PositionHashQuantifiedGameTree.resign $ Search.SearchState.getPositionHashQuantifiedGameTree searchState ) playState -- | 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 :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => String -- ^ Move-string.- -> PlayState pieceSquareValue positionHash x y+suggestCorrections+ :: String -- ^ Move-string.+ -> PlayState pieceSquareValue positionHash -> [String] -- ^ Suggested corrections. suggestCorrections moveString playState@MkPlayState { getOptions = options } | Model.Game.isTerminated game = []@@ -260,12 +236,12 @@ -- | Whether the game in the first /play-state/ has more plies than that in the second. hasMorePlies- :: PlayState pieceSquareValue positionHash x y- -> PlayState pieceSquareValue positionHash x y+ :: PlayState pieceSquareValue positionHash+ -> PlayState pieceSquareValue 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 x y -> Bool+hasApplicationTerminationBeenRequested :: PlayState pieceSquareValue positionHash -> Bool hasApplicationTerminationBeenRequested MkPlayState { getMaybeApplicationTerminationReason = maybeApplicationTerminationReason } = Data.Maybe.isJust maybeApplicationTerminationReason
− src-exe/BishBosh/Text/ShowColouredPrefix.hs
@@ -1,52 +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@] Define standard prefixes for log-messages.--}--module BishBosh.Text.ShowColouredPrefix(--- * Constants- showsPrefixInfo,- showsPrefixWarning,- showsPrefixError- ) where--import qualified BishBosh.Attribute.PhysicalColour as Attribute.PhysicalColour-import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix---- | Show the prefix used to denote an information-message.-showsPrefixInfo :: ShowS-showsPrefixInfo = Attribute.PhysicalColour.bracket (- Attribute.PhysicalColour.selectGraphicsRendition False $ Attribute.PhysicalColour.mkFgColourCode Attribute.PhysicalColour.green- ) $ Text.ShowPrefix.showsPrefixInfo ""---- | Show the prefix used to denote a warning-message.-showsPrefixWarning :: ShowS-showsPrefixWarning = Attribute.PhysicalColour.bracket (- Attribute.PhysicalColour.selectGraphicsRendition True $ Attribute.PhysicalColour.mkFgColourCode Attribute.PhysicalColour.yellow- ) $ Text.ShowPrefix.showsPrefixWarning ""---- | Show the prefix used to denote an error-message.-showsPrefixError :: ShowS-showsPrefixError = Attribute.PhysicalColour.bracket (- Attribute.PhysicalColour.selectGraphicsRendition True $ Attribute.PhysicalColour.mkFgColourCode Attribute.PhysicalColour.red- ) $ Text.ShowPrefix.showsPrefixError ""-
src-exe/BishBosh/UI/CECP.hs view
@@ -85,7 +85,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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified BishBosh.UI.Command as UI.Command import qualified BishBosh.UI.PrintObject as UI.PrintObject@@ -96,12 +95,12 @@ import qualified Control.Exception import qualified Control.Monad import qualified Control.Monad.Reader-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default+import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra-import qualified Data.Map+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified System.IO import qualified System.Random@@ -170,7 +169,7 @@ showsThinking :: Property.ShowFloat.ShowFloat stoppedWatch => Type.Count.NPlies -- ^ Search-depth.- -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y+ -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue -> Type.Mass.WeightedMean -> stoppedWatch -> Type.Count.NPositions -- ^ Nodes searched.@@ -192,37 +191,30 @@ * 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 x y. (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,- Data.Array.IArray.Ix x,+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).+ 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,- Integral x,- Integral y,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- Show x,- Show y,- System.Random.RandomGen randomGen+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Ord positionHash,+ Real pieceSquareValue,+ Show pieceSquareValue,+ System.Random.RandomGen randomGen )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash) {-# SPECIALISE readMove :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash+ -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash) #-} readMove positionHashQualifiedMoveTree randomGen = slave where slave runningWatch playState = let@@ -230,7 +222,7 @@ (searchOptions, ioOptions) = Input.Options.getSearchOptions &&& Input.Options.getIOOptions $ options (searchDepthByLogicalColour, tryToMatchSwitches) = Input.SearchOptions.getSearchDepthByLogicalColour &&& Input.StandardOpeningOptions.getMatchSwitches . Input.SearchOptions.getStandardOpeningOptions $ searchOptions- fullyManual = Data.Map.null searchDepthByLogicalColour+ fullyManual = Data.Foldable.null searchDepthByLogicalColour uiOptions = Input.IOOptions.getUIOptions ioOptions @@ -243,7 +235,7 @@ \cecpOptions -> let displaySAN = Input.CECPOptions.getDisplaySAN cecpOptions - onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState pieceSquareValue positionHash) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -261,13 +253,15 @@ ) ( 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 x y)+ else Notation.MoveNotation.showNotation moveNotation $ Evaluation.QuantifiedGame.getLastTurn (quantifiedGame :: Evaluation.QuantifiedGame.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 then ContextualNotation.StandardAlgebraic.showMove explicitEnpassant qualifiedMove game else Notation.MoveNotation.showNotation moveNotation qualifiedMove- ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen tryToMatchSwitches game positionHashQualifiedMoveTree+ ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen (+ Input.StandardOpeningOptions.getPreferVictories . Input.SearchOptions.getStandardOpeningOptions $ searchOptions+ ) tryToMatchSwitches game positionHashQualifiedMoveTree 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@@ -293,9 +287,7 @@ 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-} . showString (- showString Component.Move.tag "s"- ) . Text.ShowList.showsAssociation . ($ ".") . Text.ShowList.showsFormattedList' (+ UI.ReportObject.Moves -> return {-to IO-monad-} . ($ "") . Text.ShowList.showsFormattedList' ( Notation.MoveNotation.showsNotation moveNotation ) . Model.Game.listTurnsChronologically UI.ReportObject.PGN -> fmap ($ ".") . ContextualNotation.PGN.showsGame@@ -316,16 +308,7 @@ else showString " & leaving " . shows modeNames ) "." - Data.Maybe.maybe (- return {-to IO-monad-} ()- ) (- \(filePath, _) -> Control.Exception.catch (- do- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` (Data.Default.def :: Model.Game.Game Type.Length.X Type.Length.Y))-- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "the game-state has been saved in " $ shows filePath "."- ) $ \e -> System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixError $ show (e :: Control.Exception.SomeException)- ) $ Input.IOOptions.getMaybePersistence ioOptions+ Input.IOOptions.persist ioOptions False (Data.Default.def :: Model.Game.Game) return {-to IO-monad-} $ State.PlayState.resetPositionHashQuantifiedGameTree playState { State.PlayState.getOptions = options {@@ -337,14 +320,14 @@ } } onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue 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 in Data.Maybe.maybe ( let nPlies :: Type.Count.NPlies- nPlies = fromIntegral . succ $ Data.Map.size searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies.+ nPlies = fromIntegral . succ $ Data.Foldable.length searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies. in do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "rolling-back " $ shows nPlies " plies." @@ -367,31 +350,32 @@ ) >>= System.IO.hPutStrLn System.IO.stderr eventLoop- onCommand (UI.Command.Set setObject)- | fullyManual = do- Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixWarning $ shows UI.Command.setTag " requires an automated opponent."+ onCommand (UI.Command.Set setObject) = Control.Exception.catchJust (+ \e -> if Data.Exception.isBadData e+ then Just $ show e+ else Nothing+ ) (+ do+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "setting " $ shows setObject "." - return {-to IO-monad-} playState- | otherwise = Control.Exception.catchJust (- \e -> if Data.Exception.isBadData e- then Just $ show e- else Nothing- ) (- do- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "setting " $ shows setObject "."+ case setObject of+ UI.SetObject.EPD game' -> slave runningWatch $ State.PlayState.reconstructPositionHashQuantifiedGameTree game' playState -- Recurse.+ UI.SetObject.SearchDepth searchDepth+ | fullyManual -> do+ Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixWarning $ shows UI.Command.setTag " requires an automated opponent." - slave runningWatch playState {- State.PlayState.getOptions = Control.DeepSeq.force $ case setObject of- UI.SetObject.SearchDepth searchDepth -> options {+ eventLoop+ | otherwise -> slave runningWatch playState {+ State.PlayState.getOptions = Control.DeepSeq.force $ options { Input.Options.getSearchOptions = Input.SearchOptions.setSearchDepth searchDepth $ Input.Options.getSearchOptions options }- }- ) (- \s -> do- Control.Monad.unless (verbosity == minBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowPrefix.showsPrefixError s+ } -- Recurse.+ ) (+ \s -> do+ Control.Monad.unless (verbosity == minBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowPrefix.showsPrefixError s - eventLoop- )+ eventLoop+ ) onCommand UI.Command.Swap | fullyManual = do Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixWarning . showString " there aren't any " $ shows Input.SearchOptions.searchDepthTag " to swap."@@ -402,7 +386,7 @@ return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash) eventLoop = getLine >>= \line -> do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "received \"" $ showString line "\"." @@ -532,7 +516,7 @@ eventLoop else let nextLogicalColour = Model.Game.getNextLogicalColour game- in if nextLogicalColour `Data.Map.member` searchDepthByLogicalColour+ in if nextLogicalColour `Map.member` searchDepthByLogicalColour then return {-to IO-monad-} playState { State.PlayState.getOptions = options' } else do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "swapping to play " $ shows nextLogicalColour ", i.e. next."@@ -557,7 +541,7 @@ \playState' -> let engineLogicalColour = minBound options' = State.PlayState.getOptions playState'- in if Data.Map.member engineLogicalColour . Input.SearchOptions.getSearchDepthByLogicalColour $ Input.Options.getSearchOptions options'+ in if Map.member engineLogicalColour . Input.SearchOptions.getSearchDepthByLogicalColour $ Input.Options.getSearchOptions options' then return {-to IO-monad-} playState' else do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "swapping to play " $ shows engineLogicalColour "."@@ -811,7 +795,7 @@ ] ++ map show [ Data.Maybe.fromMaybe ( Control.Exception.throw . Data.Exception.mkNullDatum . showString "BishBosh.UI.CECP.readMove.slave.eventLoop:\tundefined " $ shows Input.Options.tag "."- ) . Data.Maybe.listToMaybe $ Data.Map.elems searchDepthByLogicalColour,+ ) . Data.Maybe.listToMaybe $ Data.Foldable.toList searchDepthByLogicalColour, Input.SearchOptions.minimumSearchDepth, 7 -- Arbitrary maximum. ]@@ -989,7 +973,7 @@ maybePaused = Input.CECPOptions.getMaybePaused cecpOptions - moveCommand :: String -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ moveCommand :: String -> IO (State.PlayState.PlayState pieceSquareValue positionHash) moveCommand moveString = case Notation.MoveNotation.readsQualifiedMove moveNotation moveString of [(eitherQualifiedMove, "")] | Just errorMessage <- Model.Game.validateEitherQualifiedMove eitherQualifiedMove game -> do@@ -1039,35 +1023,28 @@ ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall pieceSquareValue positionHash randomGen x y. (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,- Data.Array.IArray.Ix x,+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).+ 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,- Integral x,- Integral y,- Ord positionHash,- Real pieceSquareValue,- Show pieceSquareValue,- Show x,- Show y,- System.Random.RandomGen randomGen+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Ord positionHash,+ Real pieceSquareValue,+ Show pieceSquareValue,+ System.Random.RandomGen randomGen )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash) {-# SPECIALISE takeTurns :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> randomGen- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash+ -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = do mVar <- Control.Concurrent.newEmptyMVar@@ -1086,11 +1063,11 @@ verbosity = Input.UIOptions.getVerbosity uiOptions slave- :: Maybe (Concurrent.Pondering.Pondering (Component.Move.Move x y))+ :: Maybe (Concurrent.Pondering.Pondering Component.Move.Move) -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue 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 (@@ -1157,7 +1134,7 @@ then Property.ShowFloat.showsFloatToN nDecimalDigits ( Control.Monad.Reader.runReader ( Evaluation.Fitness.evaluateFitness Nothing game'- ) evaluationOptions :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues+ ) evaluationOptions ) . Search.Search.showsSeparator -- Prepend the fitness of the original game prior to the result. else id ) . Notation.MoveNotation.showsNotationFloatToNDecimals moveNotation nDecimalDigits searchResult' . showString " in " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s."@@ -1232,24 +1209,18 @@ putStrLn . showString moveTag . showChar ' ' $ Notation.MoveNotation.showNotation moveNotation qualifiedMove -- Send the move to the GUI. return {-to IO-monad-} (State.PlayState.updateWithManualMove selectedGame playState', Nothing) -- N.B.: one could ponder, but would have to construct a game-tree, & the chance of a subsequent standard-opening move is high.- ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen' (- Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions+ ) $ uncurry (+ 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. ) ( if Input.UIOptions.isCECPManualMode uiOptions' then Nothing- else Model.Game.getNextLogicalColour game' `Data.Map.lookup` Input.SearchOptions.getSearchDepthByLogicalColour searchOptions'+ else Model.Game.getNextLogicalColour game' `Map.lookup` Input.SearchOptions.getSearchDepthByLogicalColour searchOptions' ) >>= ( \(playState'', maybePondering') -> do- Data.Maybe.maybe (- return {-to IO-monad-} ()- ) (- \(filePath, automatic) -> let- game'' = State.PlayState.getGame playState''- in Control.Monad.when automatic . Control.Exception.catch (- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` game'')- ) $ \e -> System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixError $ show (e :: Control.Exception.SomeException)- ) $ Input.IOOptions.getMaybePersistence ioOptions+ Input.IOOptions.persist ioOptions False $ State.PlayState.getGame playState'' if State.PlayState.hasApplicationTerminationBeenRequested playState'' then return {-to IO-monad-} playState''
src-exe/BishBosh/UI/Raw.hs view
@@ -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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified BishBosh.UI.Command as UI.Command import qualified BishBosh.UI.PrintObject as UI.PrintObject@@ -79,11 +78,11 @@ import qualified Control.Exception import qualified Control.Monad import qualified Control.Monad.Reader-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default+import qualified Data.Foldable import qualified Data.List.Extra-import qualified Data.Map+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified System.IO import qualified System.Random@@ -98,46 +97,37 @@ * 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 x y. (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,- Data.Array.IArray.Ix x,+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).+ 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,- Integral x,- Integral y,- Ord positionHash,- Read x,- Read y,- Real pieceSquareValue,- Show pieceSquareValue,- Show x,- Show y,- System.Random.RandomGen randomGen+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Ord positionHash,+ Real pieceSquareValue,+ Show pieceSquareValue,+ System.Random.RandomGen randomGen )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash) {-# SPECIALISE readMove :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> randomGen -> Time.StopWatch.StopWatch- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash+ -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue 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 searchDepthByLogicalColour = Input.SearchOptions.getSearchDepthByLogicalColour searchOptions- fullyManual = Data.Map.null searchDepthByLogicalColour+ fullyManual = Data.Foldable.null searchDepthByLogicalColour (uiOptions, maybeMaximumPGNNames) = Input.IOOptions.getUIOptions &&& Input.IOOptions.getMaybeMaximumPGNNames $ ioOptions @@ -146,14 +136,18 @@ verbosity = Input.UIOptions.getVerbosity uiOptions in ( \nativeUIOptions -> let- show2D :: Model.Game.Game x y -> String- show2D = uncurry State.MaybePieceByCoordinates.show2D (- snd {-columns-} . Input.NativeUIOptions.getBoardMagnification &&& Input.NativeUIOptions.getColourScheme $ nativeUIOptions+ show2D :: Model.Game.Game -> String+ show2D = State.MaybePieceByCoordinates.show2D (+ snd {-columns-} $ Input.NativeUIOptions.getBoardMagnification nativeUIOptions ) (+ Input.NativeUIOptions.getColourScheme nativeUIOptions+ ) (+ Input.NativeUIOptions.getDepictFigurine nativeUIOptions+ ) ( Notation.MoveNotation.getOrigin moveNotation ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard - onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ onCommand :: UI.Command.Command -> IO (State.PlayState.PlayState pieceSquareValue positionHash) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -175,8 +169,10 @@ _ -> Control.Exception.throwIO . Data.Exception.mkRequestFailure . showString "BishBosh.UI.Raw.readMove.onCommand:\tunexpectedly failed to find any moves; " $ shows game "." -- CAVEAT: the game should have terminated. ) ( \(qualifiedMove, names) -> putStrLn . Text.ShowColouredPrefix.showsPrefixInfo . showString "Try \"" . Notation.MoveNotation.showsNotation moveNotation qualifiedMove . showString "\" from:" $ ContextualNotation.QualifiedMoveForest.showsNames maybeMaximumPGNNames names ""- ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen (- Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions+ ) $ uncurry (+ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen+ ) (+ Input.StandardOpeningOptions.getPreferVictories &&& Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions ) game positionHashQualifiedMoveTree 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.@@ -202,9 +198,7 @@ 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 . showString (- showString Component.Move.tag "s"- ) . Text.ShowList.showsAssociation . ($ ".") . Text.ShowList.showsFormattedList' (+ UI.ReportObject.Moves -> putStrLn . ($ "") . Text.ShowList.showsFormattedList' ( Notation.MoveNotation.showsNotation moveNotation ) . Model.Game.listTurnsChronologically UI.ReportObject.PGN -> putStrLn . ($ ".") <=< ContextualNotation.PGN.showsGame@@ -218,20 +212,11 @@ onCommand UI.Command.Restart = do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowColouredPrefix.showsPrefixInfo "restarting game." - Data.Maybe.maybe (- return {-to IO-monad-} ()- ) (- \(filePath, _) -> Control.Exception.catch (- do- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` (Data.Default.def :: Model.Game.Game Type.Length.X Type.Length.Y))-- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "the initial game-state has been saved in " $ shows filePath "."- ) $ \e -> System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixError $ show (e :: Control.Exception.SomeException)- ) $ Input.IOOptions.getMaybePersistence ioOptions+ Input.IOOptions.persist ioOptions (verbosity == maxBound) (Data.Default.def :: Model.Game.Game) return {-to IO-monad-} $ State.PlayState.resetPositionHashQuantifiedGameTree playState onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash) rollBack nPlies | (game', _) : _ <- drop (fromIntegral $ pred nPlies) $ Model.Game.rollBack game = do Control.Monad.when (verbosity == maxBound) . putStrLn $ show2D game'@@ -241,7 +226,7 @@ in Data.Maybe.maybe ( let nPlies :: Type.Count.NPlies- nPlies = fromIntegral . succ $ Data.Map.size searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies.+ nPlies = fromIntegral . succ $ Data.Foldable.length searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies. in do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "rolling-back " $ shows nPlies " plies." @@ -264,31 +249,35 @@ ) >>= System.IO.hPutStrLn System.IO.stderr eventLoop- onCommand (UI.Command.Set setObject)- | fullyManual = do- System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixWarning $ shows UI.Command.setTag " requires an automated opponent."+ onCommand (UI.Command.Set setObject) = Control.Exception.catchJust (+ \e -> if Data.Exception.isBadData e+ then Just $ show e+ else Nothing+ ) (+ do+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "setting " $ shows setObject "." - return {-to IO-monad-} playState- | otherwise = Control.Exception.catchJust (- \e -> if Data.Exception.isBadData e- then Just $ show e- else Nothing- ) (- do- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "setting " $ shows setObject "."+ case setObject of+ UI.SetObject.EPD game' -> do+ Control.Monad.when (verbosity == maxBound) . putStrLn $ show2D game' - readMove positionHashQualifiedMoveTree randomGen runningWatch playState {- State.PlayState.getOptions = Control.DeepSeq.force $ case setObject of- UI.SetObject.SearchDepth searchDepth -> options {+ readMove positionHashQualifiedMoveTree randomGen runningWatch $ State.PlayState.reconstructPositionHashQuantifiedGameTree game' playState -- Recurse.+ UI.SetObject.SearchDepth searchDepth+ | fullyManual -> do+ System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixWarning $ shows setObject " requires an automated opponent."++ eventLoop+ | otherwise -> readMove positionHashQualifiedMoveTree randomGen runningWatch playState {+ State.PlayState.getOptions = Control.DeepSeq.force $ options { Input.Options.getSearchOptions = Input.SearchOptions.setSearchDepth searchDepth $ Input.Options.getSearchOptions options }- } -- Recurse.- ) (- \s -> do- Control.Monad.unless (verbosity == minBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowColouredPrefix.showsPrefixError s+ } -- Recurse.+ ) (+ \s -> do+ Control.Monad.unless (verbosity == minBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowColouredPrefix.showsPrefixError s - eventLoop- )+ eventLoop+ ) onCommand UI.Command.Swap | fullyManual = do Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixWarning . showString " there aren't any " $ shows Input.SearchOptions.searchDepthTag " to swap."@@ -299,7 +288,7 @@ return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash) eventLoop = getLine >>= \line -> case Data.List.Extra.trim line of "?" -> onCommand $ UI.Command.Print UI.PrintObject.Help ':' : s -> (@@ -370,37 +359,28 @@ ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall pieceSquareValue positionHash randomGen x y. (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,- Data.Array.IArray.Ix x,+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).+ 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,- Integral x,- Integral y,- Ord positionHash,- Read x,- Read y,- Real pieceSquareValue,- Show pieceSquareValue,- Show x,- Show y,- System.Random.RandomGen randomGen+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Ord positionHash,+ Real pieceSquareValue,+ Show pieceSquareValue,+ System.Random.RandomGen randomGen )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash -> randomGen- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash) {-# SPECIALISE takeTurns :: System.Random.RandomGen randomGen- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash -> randomGen- -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y- -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ -> State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash+ -> IO (State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = let options = State.PlayState.getOptions playState@@ -417,19 +397,23 @@ mVar <- Control.Concurrent.newEmptyMVar let- show2D :: Model.Game.Game x y -> String- show2D = uncurry State.MaybePieceByCoordinates.show2D (- snd {-columns-} . Input.NativeUIOptions.getBoardMagnification &&& Input.NativeUIOptions.getColourScheme $ nativeUIOptions+ show2D :: Model.Game.Game -> String+ show2D = State.MaybePieceByCoordinates.show2D (+ snd {-columns-} $ Input.NativeUIOptions.getBoardMagnification nativeUIOptions ) (+ Input.NativeUIOptions.getColourScheme nativeUIOptions+ ) (+ Input.NativeUIOptions.getDepictFigurine nativeUIOptions+ ) ( Notation.MoveNotation.getOrigin moveNotation ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard slave- :: Maybe (Concurrent.Pondering.Pondering (Component.Move.Move x y))+ :: Maybe (Concurrent.Pondering.Pondering Component.Move.Move) -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState pieceSquareValue positionHash x y- -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash+ -> IO (State.PlayState.PlayState pieceSquareValue 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 (@@ -495,7 +479,7 @@ then Property.ShowFloat.showsFloatToN nDecimalDigits ( Control.Monad.Reader.runReader ( Evaluation.Fitness.evaluateFitness Nothing game'- ) $ Input.Options.getEvaluationOptions options :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues+ ) $ Input.Options.getEvaluationOptions options ) . Search.Search.showsSeparator -- Prepend the fitness of the original game prior to the new result. else id ) $ if verbosity > Data.Default.def@@ -550,25 +534,16 @@ putStrLn $ show2D selectedGame return {-to IO-monad-} (State.PlayState.updateWithManualMove selectedGame playState', Nothing) -- N.B.: one could ponder, but would have to construct a game-tree, & the chance of a subsequent standard-opening move is high.- ) $ ContextualNotation.PositionHashQualifiedMoveTree.maybeRandomlySelectOnymousQualifiedMove randomGen' (- Input.StandardOpeningOptions.getMatchSwitches $ Input.SearchOptions.getStandardOpeningOptions searchOptions+ ) $ uncurry (+ 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. ) (- Model.Game.getNextLogicalColour game' `Data.Map.lookup` Input.SearchOptions.getSearchDepthByLogicalColour searchOptions' -- Determinate whether the next player is manual.+ Model.Game.getNextLogicalColour game' `Map.lookup` Input.SearchOptions.getSearchDepthByLogicalColour searchOptions' -- Determinate whether the next player is manual. ) >>= ( \(playState'', maybePondering') -> do- Data.Maybe.maybe (- return {-to IO-monad-} ()- ) (- \(filePath, automatic) -> let- game'' = State.PlayState.getGame playState''- in Control.Monad.when automatic . Control.Exception.catch (- do- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` game'')-- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "the game-state has been saved in " $ shows filePath "."- ) $ \e -> System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixError $ show (e :: Control.Exception.SomeException)- ) $ Input.IOOptions.getMaybePersistence ioOptions+ Input.IOOptions.persist ioOptions (verbosity == maxBound) $ State.PlayState.getGame playState'' if State.PlayState.hasApplicationTerminationBeenRequested playState'' then return {-to IO-monad-} playState''
src-exe/Duel/Process/Intermediary.hs view
@@ -26,7 +26,9 @@ module Duel.Process.Intermediary ( -- * Types -- ** Type-synonyms+-- MoveNotation, -- IOHandles,+-- MoveSequence, -- GameTerminationReasonsMap, -- * Functions -- runBishBosh,@@ -47,10 +49,12 @@ import qualified BishBosh.Input.CommandLineOption as Input.CommandLineOption import qualified BishBosh.Input.IOOptions as Input.IOOptions import qualified BishBosh.Input.Options as Input.Options+import qualified BishBosh.Input.PGNOptions as Input.PGNOptions import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions import qualified BishBosh.Input.Verbosity as Input.Verbosity import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.SelfValidating as Property.SelfValidating import qualified BishBosh.Property.Switchable as Property.Switchable@@ -58,13 +62,14 @@ 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.Length as Type.Length 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 import qualified Control.Monad import qualified Data.Default-import qualified Data.Map.Strict+import qualified Data.Foldable+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified Duel.Data.Options as Data.Options import qualified Duel.IO.Logger as IO.Logger@@ -85,7 +90,7 @@ import qualified BishBosh.Notation.Smith as Notation.Smith type MoveNotation = Notation.Smith.Smith # else-# error "MOVE_NOTATION ill-defined"+# error "MOVE_NOTATION invalid" # endif #else # error "MOVE_NOTATION undefined"@@ -116,7 +121,7 @@ -> Type.Count.NSeconds -- ^ Read-timout. -> Attribute.LogicalColour.LogicalColour -- ^ Whose turn it is. -> System.IO.Handle -- ^ Output handle from which data should be read.- -> IO (Either Rule.GameTerminationReason.GameTerminationReason (MoveNotation Type.Length.X Type.Length.Y))+ -> IO (Either Rule.GameTerminationReason.GameTerminationReason MoveNotation) readMove verbosity readTimeout logicalColour stdOut = do Control.Monad.when (verbosity == maxBound) . IO.Logger.printInfo . showString "Waiting " . ( if readTimeout < 0@@ -132,7 +137,7 @@ case reads line of [(gameTerminationReason, "")] -> do- Control.Monad.when (verbosity > minBound) . IO.Logger.printInfo $ shows gameTerminationReason " => game over."+ Control.Monad.when (verbosity /= minBound) . IO.Logger.printInfo $ shows gameTerminationReason " => game over." return {-to IO-monad-} $ Left gameTerminationReason -- Return the result. _ -> case reads line of@@ -161,6 +166,9 @@ -- | Contains /stdin/ & /stdout/ handles respectively. type IOHandles = (System.IO.Handle, System.IO.Handle) +-- | The chronological sequence of moves which occurred in a game.+type MoveSequence = String+ -- | Shuttle moves between the two child processes until the game terminates. play :: Property.Switchable.Switchable gameClock@@ -169,7 +177,7 @@ -> IOHandles -> IOHandles -> gameClock- -> IO (Rule.GameTerminationReason.GameTerminationReason, gameClock)+ -> IO (MoveSequence, Rule.GameTerminationReason.GameTerminationReason, gameClock) play verbosity readTimeout = slave maxBound where slave logicalColour producer@(_, stdOut) consumer@(stdIn', stdOut') gameClock = copyMove verbosity readTimeout logicalColour stdOut stdIn' >>= Data.Maybe.maybe ( do@@ -182,7 +190,11 @@ \gameTerminationReason' -> do Control.Monad.unless (gameTerminationReason == gameTerminationReason') . Control.Exception.throwIO . Data.Exception.mkIncompatibleData . showString "Duel.Process.Intermediary.play:\tsecond game terminated for a different reason; " $ shows gameTerminationReason' "." - return {-to IO-monad-} (gameTerminationReason, gameClock)+ System.IO.hPutStrLn stdIn' $ UI.Command.issueCommand (UI.Command.Report UI.ReportObject.Moves) "" -- Request the move-sequence, for comparison with the other games in this trial.++ moveSequence <- System.IO.hGetLine stdOut' -- CAVEAT: no attempt is made to parse the move-sequence.++ return {-to IO-monad-} (moveSequence, gameTerminationReason, gameClock) ) ||| ( \move -> Control.Exception.throwIO . Data.Exception.mkParseFailure . showString "Duel.Process.Intermediary.play:\tread from " . shows (Property.Opposable.getOpposite logicalColour) . showString ", unexpected move='" $ shows move "'." )@@ -195,12 +207,8 @@ Control.Monad.when isReady . Control.Monad.void $ System.IO.hGetLine handle -{- |- * Accumulates the frequency of each game-termination reason-- * N.B.: the recorded result is merely a string, though it could be read into a 'BishBosh.Rule.GameTerminationReason'.--}-type GameTerminationReasonsMap = Data.Map.Strict.Map Rule.GameTerminationReason.GameTerminationReason Type.Count.NGames+-- | Accumulates the frequency-distribution of game-termination reasons.+type GameTerminationReasonsMap = Map.Map Rule.GameTerminationReason.GameTerminationReason Type.Count.NGames {- | * Constructs a game-clock.@@ -214,6 +222,8 @@ * Plays repeatedly, measuring both the total time taken by each side & accumulating the final results of each game. * Prints the total time taken by either side, & returns the accumulated results of each game.++ * Reports games which are duplicated; transpositions are considered to be different. -} startGame :: Input.Verbosity.Verbosity@@ -224,16 +234,25 @@ -> GameTerminationReasonsMap -> Type.Count.NGames -> IO GameTerminationReasonsMap-startGame verbosity nDecimalDigits readTimeout producer consumer gameTerminationReasonsMap nGames = Property.Switchable.on >>= slave gameTerminationReasonsMap nGames where- slave :: GameTerminationReasonsMap -> Type.Count.NGames -> Time.GameClock.GameClock -> IO GameTerminationReasonsMap- slave gameTerminationReasonsMap' 0 gameClock = do+startGame verbosity nDecimalDigits readTimeout producer consumer gameTerminationReasonsMap nGames = Property.Switchable.on >>= slave Property.Empty.empty gameTerminationReasonsMap nGames where+ accumulateFrequencyDistribution :: (Enum i, Num i, Ord k) => k -> Map.Map k i -> Map.Map k i+ accumulateFrequencyDistribution = flip (Map.insertWith $ const succ) 1++ slave :: Map.Map MoveSequence Type.Count.NGames -> GameTerminationReasonsMap -> Type.Count.NGames -> Time.GameClock.GameClock -> IO GameTerminationReasonsMap+ slave moveSequenceMap gameTerminationReasonsMap' 0 gameClock = do Time.GameClock.showsElapsedTimes nDecimalDigits gameClock >>= IO.Logger.printInfo . showString "Elapsed time" . Text.ShowList.showsAssociation . ($ ".") + let duplicatedMovesMap = Map.filter (> 1) moveSequenceMap++ if Data.Foldable.null duplicatedMovesMap+ then Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "All games were composed from unique move-sequences."+ else Control.Monad.unless (verbosity == minBound) . IO.Logger.printWarning . showString "Duplicated move-sequences:\t" $ shows (Map.toList duplicatedMovesMap) "."+ return {-to IO-monad-} gameTerminationReasonsMap'- slave gameTerminationReasonsMap' nGames' gameClock = do+ slave moveSequenceMap gameTerminationReasonsMap' nGames' gameClock = do Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Starting game." - (gameTerminationReason, gameClock') <- play verbosity readTimeout producer consumer gameClock+ (moveSequence, gameTerminationReason, gameClock') <- play verbosity readTimeout producer consumer gameClock sequence_ $ [ \(_, stdOut) -> do@@ -243,12 +262,14 @@ \(stdIn, _) -> do Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Requesting restart." - System.IO.hPutStrLn stdIn $ UI.Command.commandPrefix : UI.Command.restartTag+ System.IO.hPutStrLn stdIn $ UI.Command.issueCommand UI.Command.Restart "" ] <*> [consumer, producer] slave (- Data.Map.Strict.insertWith (const succ) gameTerminationReason 1 gameTerminationReasonsMap'+ accumulateFrequencyDistribution moveSequence moveSequenceMap ) (+ accumulateFrequencyDistribution gameTerminationReason gameTerminationReasonsMap'+ ) ( pred nGames' -- Recurse. ) gameClock' @@ -301,7 +322,7 @@ in Control.Exception.catch ( do Control.Monad.when (Data.Options.getVerifyConfiguration options) $ do- [(logicalColoursFirst, moveNotationFirst), (logicalColoursSecond, moveNotationSecond)] <- mapM (+ [(logicalColoursFirst, moveNotationFirst, unspecifiedPGNOptionsFirst), (logicalColoursSecond, moveNotationSecond, unspecifiedPGNOptionsSecond)] <- mapM ( \configFilePath -> do [pair] <- HXT.runX $ HXT.setTraceLevel hxtTraceLevel >>> HXT.xunpickleDocument HXT.xpickle [@@ -309,9 +330,13 @@ HXT.withStrictInput HXT.no -- Only a fraction of the document is required. ] configFilePath >>> HXT.arr (- \inputOptions -> Input.SearchOptions.identifyAutomatedPlayers . Input.Options.getSearchOptions &&& Input.UIOptions.getMoveNotation . Input.IOOptions.getUIOptions . Input.Options.getIOOptions $ (- inputOptions :: Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y -- Arbitrary concrete type.- )+ \inputOptions -> (+ Input.SearchOptions.identifyAutomatedPlayers $ Input.Options.getSearchOptions (+ inputOptions :: Input.Options.Options Type.Mass.PieceSquareValue -- Arbitrary concrete type.+ ),+ Input.UIOptions.getMoveNotation . Input.IOOptions.getUIOptions $ Input.Options.getIOOptions inputOptions,+ null . Input.IOOptions.getPGNOptionsList $ Input.Options.getIOOptions inputOptions+ ) ) -- Lift function into an arrow. return {-to IO-monad-} pair@@ -321,13 +346,15 @@ Control.Monad.unless (moveNotationFirst == moveNotationSecond) . Control.Exception.throwIO . Data.Exception.mkIncompatibleData . showString "Duel.Process.Intermediary.initialise:\tconfiguration-files must define the same " . showString Notation.MoveNotation.tag . Text.ShowList.showsAssociation $ shows (moveNotationFirst, moveNotationSecond) "." + Control.Monad.when (unspecifiedPGNOptionsFirst && unspecifiedPGNOptionsSecond) . Control.Exception.throwIO . Data.Exception.mkNullDatum . showString "Duel.Process.Intermediary.initialise:\tto introduce randomness, at least one configuration-file must define '" . showString Input.PGNOptions.tag . showChar '.' $ showString Input.PGNOptions.databaseFilePathTag "'."+ bracketProcess verbosity inputConfigFilePaths $ \[handles, handles'] -> uncurry ( uncurry (startGame verbosity) $ (Data.Options.getNDecimalDigits &&& Data.Options.getReadTimeout) options ) ( ($ handles) &&& ($ handles') $ Process.Handles.getHandlePair- ) Data.Map.Strict.empty (+ ) Property.Empty.empty ( Data.Options.getNGames options- ) >>= IO.Logger.printInfo . show . Data.Map.Strict.toList+ ) >>= IO.Logger.printInfo . show . Map.toList ) $ \e -> do IO.Logger.printError . showString "caught " $ show (e :: Control.Exception.SomeException)
src-exe/Main.hs view
@@ -29,7 +29,6 @@ module Main(main) where ---import BishBosh.Data.Ratio() -- Required if either Type.Mass.CriterionWeight or Type.Mass.CriterionValue is Rational. import Control.Arrow((&&&), (***), (|||)) import Control.Category((>>>)) import Data.Array.IArray((!))@@ -43,6 +42,7 @@ import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Input.IOOptions as Input.IOOptions import qualified BishBosh.Input.Options as Input.Options+import qualified BishBosh.Input.PieceSquareTable as Input.PieceSquareTable import qualified BishBosh.Input.PGNOptions as Input.PGNOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions import qualified BishBosh.Input.Verbosity as Input.Verbosity@@ -59,7 +59,6 @@ import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Control.Monad@@ -95,7 +94,7 @@ #endif -- Define concrete types to resolve the underlying polymorphic functions.-type Options = Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y+type Options = Input.Options.Options Type.Mass.PieceSquareValue writeXMLToFile :: HXT.XmlPickler pickleable@@ -277,7 +276,11 @@ ) ["Opening", "End"] ) $ map ( \selector -> Component.PieceSquareByCoordinatesByRank.formatForGNUPlot (- Property.ShowFloat.showsFloatToN' . Input.UIOptions.getNDecimalDigits . Input.IOOptions.getUIOptions $ Input.Options.getIOOptions options -- PieceSquareValue formatter.+ 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'.+ ) ) ( showChar '\t' -- Column-delimiter. ) (@@ -381,12 +384,12 @@ System.IO.hSetBuffering System.IO.stdout System.IO.LineBuffering -- CAVEAT: required when the output is another process instead of a terminal. - playState <- uncurry (Play.play randomGen) . (,) options' =<< ( -- CAVEAT: artificially construct a pair, to reduce the strictness & thus allow the UI to be rendered while PGN-databases are evaluated in the background.+ playState <- uncurry (Play.play verbosity randomGen) . (,) options' =<< ( -- CAVEAT: artificially construct a pair, to reduce the strictness & thus allow the UI to be rendered while PGN-databases are evaluated in the background. \qualifiedMoveForest -> do Control.Monad.when (verbosity == maxBound && not (Property.Null.isNull qualifiedMoveForest)) $ mapM_ ( System.IO.hPutStrLn System.IO.stderr . showsInfoPrefix . ($ ".") ) [- showString "resulting tree contains (nGames, nMoves)" . Text.ShowList.showsAssociation . shows (ContextualNotation.QualifiedMoveForest.count qualifiedMoveForest), -- CAVEAT: application stalls during this call.+ showString "resulting tree contains (nGames, nPositions)" . Text.ShowList.showsAssociation . shows (ContextualNotation.QualifiedMoveForest.count qualifiedMoveForest), -- CAVEAT: application stalls during this call. showString "the minimum number of pieces remaining in any of the archived games" . Text.ShowList.showsAssociation . shows (ContextualNotation.QualifiedMoveForest.findMinimumPieces qualifiedMoveForest) ]@@ -446,7 +449,7 @@ ) Property.Empty.empty {-QualifiedMoveForest-} (Input.IOOptions.getPGNOptionsList ioOptions) let- maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y)+ maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Type.Mass.PieceSquareValue 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 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.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 view
@@ -19,7 +19,7 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Defines the physical colour used to represent each component of the display.+ [@DESCRIPTION@] Defines the physical colour used to represent each component of the board. -} module BishBosh.Attribute.ColourScheme (@@ -45,6 +45,7 @@ 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@@ -105,9 +106,9 @@ instance Data.Default.Default ColourScheme where def = MkColourScheme { getDarkPieceColour = Attribute.PhysicalColour.blue,- getLightPieceColour = Attribute.PhysicalColour.yellow,+ getLightPieceColour = Property.Opposable.getOpposite $ getDarkPieceColour Data.Default.def, getDarkSquareColour = Attribute.PhysicalColour.black,- getLightSquareColour = Attribute.PhysicalColour.white+ getLightSquareColour = Property.Opposable.getOpposite $ getDarkSquareColour Data.Default.def } instance HXT.XmlPickler ColourScheme where
src-lib/BishBosh/Attribute/Direction.hs view
@@ -55,7 +55,7 @@ -- range, opposites, -- * Functions--- reverseOrdering,+-- getOpposite, advanceDirection, attackDirectionsForPawn, listArrayByDirection,@@ -118,8 +118,8 @@ -- | 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.+ 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@@ -164,19 +164,13 @@ 'E' : _ -> [(e, tail s')] _ -> [] -- No parse. --- | Get the opposite.-reverseOrdering :: Ordering -> Ordering-reverseOrdering LT = GT-reverseOrdering GT = LT-reverseOrdering _ = EQ- instance Property.Opposable.Opposable Direction where getOpposite MkDirection { getXDirection = xDirection, getYDirection = yDirection } = MkDirection {- getXDirection = reverseOrdering xDirection,- getYDirection = reverseOrdering yDirection+ getXDirection = Property.Opposable.getOpposite xDirection,+ getYDirection = Property.Opposable.getOpposite yDirection } instance Property.Orientated.Orientated Direction where@@ -186,12 +180,12 @@ instance Property.Reflectable.ReflectableOnX Direction where reflectOnX direction@MkDirection { getYDirection = yDirection } = direction {- getYDirection = reverseOrdering yDirection+ getYDirection = Property.Opposable.getOpposite yDirection } instance Property.Reflectable.ReflectableOnY Direction where reflectOnY direction@MkDirection { getXDirection = xDirection } = direction {- getXDirection = reverseOrdering xDirection+ getXDirection = Property.Opposable.getOpposite xDirection } instance HXT.XmlPickler Direction where
src-lib/BishBosh/Attribute/MoveType.hs view
@@ -49,6 +49,7 @@ isCapture, isPromotion, isQuiet,+ isSimple, isAcyclic, -- ** Query getMaybeExplicitlyTakenRank,@@ -232,6 +233,14 @@ getMaybePromotionRank = Nothing } = True isQuiet moveType = isCastle moveType++-- | The simplest type of move.+isSimple :: MoveType -> Bool+isSimple Normal {+ getMaybeTakenRank = Nothing,+ getMaybePromotionRank = Nothing+} = True+isSimple _ = False -- Neither Castling nor En-passant qualifies. {- | * Whether the /move/ can't be a member of a repeated cycle.
src-lib/BishBosh/Attribute/PhysicalColour.hs view
@@ -29,11 +29,10 @@ module BishBosh.Attribute.PhysicalColour( -- * Types--- ** Type-synonyms--- ANSIColourCode, -- ** Data-types- PhysicalColour(..),+ PhysicalColour(), -- * Constants+-- range, black, red, green,@@ -41,22 +40,20 @@ blue, magenta, cyan,- white,--- range,--- * Functions--- toANSIColourCode,- mkFgColourCode,- mkBgColourCode,- selectGraphicsRendition,- bracket+ 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.+{- |+ * 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@@ -78,6 +75,9 @@ 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]@@ -116,29 +116,4 @@ -- | Constant. white :: PhysicalColour white = White---- | A colour-code, as used by terminal-emulators; <https://en.wikipedia.org/wiki/ANSI_escape_code>.-type ANSIColourCode = Int---- | Offset the specified colour-code, so that it applies to the foreground.-mkFgColourCode :: PhysicalColour -> ANSIColourCode-mkFgColourCode = (+ 30) . toANSIColourCode---- | Offset the specified colour-code, so that it applies to the background.-mkBgColourCode :: PhysicalColour -> ANSIColourCode-mkBgColourCode = (+ 40) . toANSIColourCode---- | Translate.-toANSIColourCode :: PhysicalColour -> ANSIColourCode-toANSIColourCode = fromEnum -- CAVEAT: the order of the data-constructors has been defined with this in mind.---- | Generate the escape-sequence required to change a terminal to the specified physical colour.-selectGraphicsRendition :: Bool -> ANSIColourCode -> String-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 default.-bracket :: String -> String -> ShowS-bracket graphicsRendition s = showString graphicsRendition . showString s . showString (- selectGraphicsRendition False 0- )
src-lib/BishBosh/Attribute/Rank.hs view
@@ -49,7 +49,7 @@ earthBound, expendable, nDistinctRanks,--- allocationPerSide,+ initialAllocationByRankPerSide, -- * Functions compareByLVA, findUndefinedRanks,@@ -202,9 +202,9 @@ nDistinctRanks :: Type.Count.NRanks nDistinctRanks = fromIntegral $ length range --- | The number of each rank allocated to each side.-allocationPerSide :: ArrayByRank Type.Count.NRanks-allocationPerSide = listArrayByRank [8, 2, 2, 2, 1, 1]+-- | The constant number of each rank per side, at the conventional opening position.+initialAllocationByRankPerSide :: ArrayByRank Type.Count.NPieces+initialAllocationByRankPerSide = listArrayByRank [8, 2, 2, 2, 1, 1] -- | A boxed array indexed by /rank/, of arbitrary values. type ArrayByRank = Data.Array.IArray.Array Rank
src-lib/BishBosh/Cartesian/Abscissa.hs view
@@ -29,15 +29,15 @@ -} module BishBosh.Cartesian.Abscissa(--- * Types- ArrayByAbscissa, -- * Constants- xOrigin, xLength, xMin, xMax, xBounds, xRange,+ bishopsFiles,+ kingsFile,+-- adjacents, -- * Functions toIx, fromIx,@@ -45,68 +45,66 @@ translate, maybeTranslate, getAdjacents,+-- getAdjacents', -- ** Constructors listArrayByAbscissa, -- ** Predicates inBounds ) where -import qualified BishBosh.Data.Enum as Data.Enum+import Data.Array.IArray((!)) import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Array.IArray --- | The position of the origin on the /x/-axis.-xOrigin :: Int-xOrigin = 0- -- | The constant length of the /x/-axis.-xLength :: Type.Length.Distance+xLength :: Type.Length.X xLength = 8 --- | The constant lower bound of abscissae.-xMin :: Enum x => x-xMin = toEnum xOrigin---- | The constant upper bound of abscissae.-xMax :: Enum x => x-xMax = toEnum $ xOrigin + fromIntegral (pred {-fence-post-} xLength)- -- | The constant bounds of abscissae.-xBounds :: Enum x => (x, x)-xBounds = (xMin, xMax)+xBounds :: (Type.Length.X, Type.Length.X)+xMin, xMax :: Type.Length.X+xBounds@(xMin, xMax) = (0, xMin + pred {-fence-post-} xLength) -- | The constant list of all abscissae.-xRange :: Enum x => [x]+xRange :: [Type.Length.X] xRange = uncurry enumFromTo xBounds +-- | The conventional starting /file/s for the @Bishops@ of either /logical colour/.+bishopsFiles :: [Type.Length.X]+bishopsFiles = map fromIx [2, 5]++-- | The conventional starting /file/ for the @King@ of either /logical colour/.+kingsFile :: Type.Length.X+kingsFile = fromIx 4+ -- | Convert to an array-index.-toIx :: Enum x => x -> Int+toIx :: Type.Length.X -> Int {-# INLINE toIx #-}-toIx = subtract xOrigin . fromEnum+toIx = fromIntegral . subtract xMin -- | Convert from an array-index.-fromIx :: Enum x => Int -> x+fromIx :: Int -> Type.Length.X {-# INLINE fromIx #-}-fromIx = toEnum . (+ xOrigin)+fromIx = (+ xMin) . fromIntegral -- | Reflects about the mid-point of the axis.-reflect :: Enum x => x -> x-reflect = Data.Enum.translate $ (- + (2 * xOrigin + fromIntegral (pred xLength))+reflect :: Type.Length.X -> Type.Length.X+reflect = (+ + (2 * xMin + pred xLength) ) . negate -- | Predicate.-inBounds :: (Enum x, Ord x) => x -> Bool+inBounds :: Type.Length.X -> Bool {-# INLINE inBounds #-} inBounds x = x >= xMin && x <= xMax -- | Translate the specified ordinate.-translate :: (Enum x, Ord x) => (x -> x) -> x -> x+translate :: (Type.Length.X -> Type.Length.X) -> Type.Length.X -> Type.Length.X translate transformation = (\x -> Control.Exception.assert (inBounds x) x) . transformation -- | Where legal, translate the specified abscissa.-maybeTranslate :: (Enum x, Ord x) => (x -> x) -> x -> Maybe x+maybeTranslate :: (Type.Length.X -> Type.Length.X) -> Type.Length.X -> Maybe Type.Length.X maybeTranslate transformation = ( \x -> if inBounds x then Just x@@ -114,21 +112,21 @@ ) . transformation -- | Get the abscissae immediately left & right.-getAdjacents :: (Enum x, Eq x) => x -> [x]-{-# INLINE getAdjacents #-}-getAdjacents x+getAdjacents' :: Type.Length.X -> [Type.Length.X]+getAdjacents' x | x == xMin = [succ xMin] | x == xMax = [pred xMax] | otherwise = [pred x, succ x] --- | A boxed array indexed by /coordinates/, of arbitrary elements.-type ArrayByAbscissa x = Data.Array.IArray.Array {-Boxed-} x+-- | The constant abscissae either side of each value.+adjacents :: Data.Array.IArray.Array Type.Length.X [Type.Length.X]+adjacents = listArrayByAbscissa $ map getAdjacents' xRange +-- | Get the abscissae immediately left & right.+getAdjacents :: Type.Length.X -> [Type.Length.X]+getAdjacents = (adjacents !)+ -- | Array-constructor.-listArrayByAbscissa :: (- Data.Array.IArray.IArray a e,- Data.Array.IArray.Ix x,- Enum x- ) => [e] -> a x e+listArrayByAbscissa :: Data.Array.IArray.IArray a e => [e] -> a Type.Length.X e listArrayByAbscissa = Data.Array.IArray.listArray xBounds
src-lib/BishBosh/Cartesian/Coordinates.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts #-}+{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -45,9 +45,7 @@ -- * Functions -- extrapolate', extrapolate,--- extrapolateInt, interpolate,--- interpolateInt, getLogicalColourOfSquare, kingsStartingCoordinates, rooksStartingCoordinates,@@ -79,7 +77,7 @@ areSquaresIsochromatic ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (***)) import Data.Array.IArray((!)) import qualified BishBosh.Attribute.Direction as Attribute.Direction import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour@@ -92,13 +90,15 @@ 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 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+import qualified Data.Map as Map import qualified Data.Maybe #ifdef USE_PARALLEL@@ -110,39 +110,28 @@ tag = "coordinates" -- | The /coordinates/ of a square on the board.-data Coordinates x y = MkCoordinates {- getX :: x, -- ^ Abscissa.- getY :: y -- ^ Ordinate.+data Coordinates = MkCoordinates {+ getX :: ! Type.Length.X, -- ^ Abscissa.+ getY :: ! Type.Length.Y -- ^ Ordinate. } deriving Eq -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Coordinates x y) where+instance Control.DeepSeq.NFData Coordinates where rnf MkCoordinates { getX = x, getY = y } = Control.DeepSeq.rnf (x, y) -instance (Show x, Show y) => Show (Coordinates x y) where+instance Show Coordinates where showsPrec precedence MkCoordinates { getX = x, getY = y } = showsPrec precedence (x, y) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Read x,- Read y- ) => Read (Coordinates x y) where+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 x, Ord y) => Ord (Coordinates x y) where- {-# SPECIALISE instance Ord (Coordinates Type.Length.X Type.Length.Y) #-}+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 (Enum x, Enum y) => Bounded (Coordinates x y) where+instance Bounded Coordinates where minBound = MkCoordinates { getX = Cartesian.Abscissa.xMin, getY = Cartesian.Ordinate.yMin@@ -152,48 +141,41 @@ getY = Cartesian.Ordinate.yMax } -- Top Right. -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Data.Array.IArray.Ix (Coordinates x y) where- {-# SPECIALISE instance Data.Array.IArray.Ix (Coordinates Type.Length.X Type.Length.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 -instance Enum y => Property.Reflectable.ReflectableOnX (Coordinates x y) where+instance Property.Reflectable.ReflectableOnX Coordinates where reflectOnX coordinates@MkCoordinates { getY = y } = coordinates { getY = Cartesian.Ordinate.reflect y } -instance Enum x => Property.Reflectable.ReflectableOnY (Coordinates x y) where+instance Property.Reflectable.ReflectableOnY Coordinates where reflectOnY coordinates@MkCoordinates { getX = x } = coordinates { getX = Cartesian.Abscissa.reflect x } -instance (Enum x, Enum y) => Property.Rotatable.Rotatable (Coordinates x y) where+instance Property.Rotatable.Rotatable Coordinates where rotate90 = rotate Attribute.Direction.w rotate180 = rotate Attribute.Direction.s rotate270 = rotate Attribute.Direction.e -- | Constant.-topLeft :: (Enum x, Enum y) => Coordinates x y+topLeft :: Coordinates topLeft = MkCoordinates { getX = Cartesian.Abscissa.xMin, getY = Cartesian.Ordinate.yMax } -- | Constant.-bottomRight :: (Enum x, Enum y) => Coordinates x y+bottomRight :: Coordinates bottomRight = MkCoordinates { getX = Cartesian.Abscissa.xMax, getY = Cartesian.Ordinate.yMin } -- | The constant number of squares on the board.-nSquares :: Int-nSquares = fromIntegral $ Cartesian.Abscissa.xLength * Cartesian.Ordinate.yLength+nSquares :: Type.Count.NCoordinates+nSquares = fromIntegral Cartesian.Abscissa.xLength * fromIntegral Cartesian.Ordinate.yLength -instance (Enum x, Enum y) => Property.FixedMembership.FixedMembership (Coordinates x y) where- {-# SPECIALISE instance Property.FixedMembership.FixedMembership (Coordinates Type.Length.X Type.Length.Y) #-}+instance Property.FixedMembership.FixedMembership Coordinates where members = [ MkCoordinates { getX = x,@@ -204,47 +186,30 @@ ] -- List-comprehension. -- | Predicate.-inBounds :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => x -- ^ Abscissa.- -> y -- ^ Ordinate.+inBounds+ :: Type.Length.X -- ^ Abscissa.+ -> Type.Length.Y -- ^ Ordinate. -> Bool-{-# INLINABLE inBounds #-} inBounds x y = Cartesian.Abscissa.inBounds x && Cartesian.Ordinate.inBounds y -- | Constructor.-mkCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => x -- ^ Abscissa.- -> y -- ^ Ordinate.- -> Coordinates x y+mkCoordinates+ :: Type.Length.X -- ^ Abscissa.+ -> Type.Length.Y -- ^ Ordinate.+ -> Coordinates mkCoordinates x y = Control.Exception.assert (inBounds x y) $ MkCoordinates x y -- | Safe constructor.-mkMaybeCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => x -- ^ Abscissa.- -> y -- ^ Ordinate.- -> Maybe (Coordinates x y)+mkMaybeCoordinates+ :: Type.Length.X -- ^ Abscissa.+ -> Type.Length.Y -- ^ Ordinate.+ -> Maybe Coordinates mkMaybeCoordinates x y | inBounds x y = Just MkCoordinates { getX = x, getY = y } | otherwise = Nothing -- | Convert to an array-index.-toIx :: (Enum x, Enum y) => Coordinates x y -> Int-{-# SPECIALISE toIx :: Coordinates Type.Length.X Type.Length.Y -> Int #-}+toIx :: Coordinates -> Int toIx MkCoordinates { getX = x, getY = y@@ -255,7 +220,7 @@ * CAVEAT: assumes that the array is indexed by the whole range of /coordinates/. -}-fromIx :: (Enum x, Enum y) => Int -> Coordinates x y+fromIx :: Int -> Coordinates fromIx = ( \(y, x) -> MkCoordinates { getX = Cartesian.Abscissa.fromIx x,@@ -268,28 +233,14 @@ * CAVEAT: the caller must ensure that the results are legal. -}-translate :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => ((x, y) -> (x, y)) -> Coordinates x y -> Coordinates x y+translate :: ((Type.Length.X, Type.Length.Y) -> (Type.Length.X, Type.Length.Y)) -> Coordinates -> Coordinates translate transformation MkCoordinates { getX = x, getY = y } = uncurry mkCoordinates $ transformation (x, y) -- | Where legal, translate the specified /coordinates/.-maybeTranslate :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => ((x, y) -> (x, y)) -- ^ Translation.- -> Coordinates x y- -> Maybe (Coordinates x y)-{-# INLINABLE maybeTranslate #-}+maybeTranslate :: ((Type.Length.X, Type.Length.Y) -> (Type.Length.X, Type.Length.Y)) -> Coordinates -> Maybe Coordinates maybeTranslate transformation MkCoordinates { getX = x, getY = y@@ -300,15 +251,14 @@ * CAVEAT: the caller must ensure that the results are legal. -}-translateX :: (Enum x, Ord x) => (x -> x) -> Transformation x y+translateX :: (Type.Length.X -> Type.Length.X) -> Transformation translateX transformation coordinates@MkCoordinates { getX = x } = coordinates { getX = Cartesian.Abscissa.translate transformation x } -- | Where legal, translate the /x/-component of the specified /coordinates/. maybeTranslateX- :: (Enum x, Ord x)- => (x -> x) -- ^ Translation.- -> Coordinates x y- -> Maybe (Coordinates x y)+ :: (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 {- |@@ -316,15 +266,14 @@ * CAVEAT: the caller must ensure that the results are legal. -}-translateY :: (Enum y, Ord y) => (y -> y) -> Transformation x y+translateY :: (Type.Length.Y -> Type.Length.Y) -> Transformation translateY transformation coordinates@MkCoordinates { getY = y } = coordinates { getY = Cartesian.Ordinate.translate transformation y } -- | Where legal, translate the /y/-component of the specified /coordinates/. maybeTranslateY- :: (Enum y, Ord y)- => (y -> y) -- ^ Translation.- -> Coordinates x y- -> Maybe (Coordinates x y)+ :: (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 {- |@@ -332,14 +281,7 @@ * CAVEAT: the caller must ensure that the results are legal. -}-mkRelativeCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => ((x, y) -> (x, y)) -- ^ Translation.- -> Coordinates x y+mkRelativeCoordinates :: ((Type.Length.X, Type.Length.Y) -> (Type.Length.X, Type.Length.Y)) -> Coordinates mkRelativeCoordinates = (`translate` minBound) {- |@@ -348,20 +290,17 @@ * CAVEAT: the caller must ensure that the results are legal. -} advance- :: (Enum y, Ord y)- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance.- -> Transformation x y-{-# INLINE advance #-}+ :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance.+ -> Transformation advance logicalColour = translateY $ if Attribute.LogicalColour.isBlack logicalColour then pred else succ -- | Where legal, move one step towards the opponent. maybeAdvance- :: (Enum y, Ord y)- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to advance.- -> Coordinates x y -- ^ The location from which to advanced.- -> Maybe (Coordinates x y)+ :: Attribute.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 then pred else succ@@ -372,29 +311,26 @@ * CAVEAT: the caller must ensure that the results are legal. -} retreat- :: (Enum y, Ord y)- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat.- -> Transformation x y+ :: Attribute.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- :: (Enum y, Ord y)- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/ which is to retreat.- -> Coordinates x y -- ^ The location from which to retreat.- -> Maybe (Coordinates x y)+ :: Attribute.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 -- | Get the /coordinates/ immediately left & right.-getAdjacents :: (Enum x, Eq x) => Coordinates x y -> [Coordinates x y]+getAdjacents :: Coordinates -> [Coordinates] getAdjacents coordinates@MkCoordinates { getX = x } = map (\x' -> coordinates { getX = x' }) $ Cartesian.Abscissa.getAdjacents x -- | Generates a line of /coordinates/, starting just after the specified source & proceeding in the specified /direction/ to the edge of the board. extrapolate'- :: (Enum x, Enum y)- => Attribute.Direction.Direction -- ^ The direction in which to proceed.- -> Coordinates x y -- ^ The point from which to start.- -> [Coordinates x y]+ :: Attribute.Direction.Direction -- ^ The direction in which to proceed.+ -> Coordinates -- ^ The point from which to start.+ -> [Coordinates] extrapolate' direction MkCoordinates { getX = x, getY = y@@ -417,30 +353,13 @@ In consequence, it is typically automatically avoided using a rewrite-rule to lookup an array of the results from all possible calls. -} extrapolate- :: (Enum x, Enum y)- => Attribute.Direction.Direction -- ^ The direction in which to proceed.- -> Coordinates x y -- ^ The point from which to start.- -> [Coordinates x y]-{-# NOINLINE extrapolate #-} -- Ensure the rewrite-rule triggers.-{-# RULES "extrapolate/Int" extrapolate = extrapolateInt #-} -- CAVEAT: the call-stack leading here must be specialised to ensure this rule triggers.-extrapolate = extrapolate'---- | A specialisation of 'extrapolate'.-extrapolateInt :: Attribute.Direction.Direction -> Coordinates Type.Length.X Type.Length.Y -> [Coordinates Type.Length.X Type.Length.Y]-extrapolateInt direction coordinates = extrapolationsByDirectionByCoordinates ! coordinates ! direction+ :: Attribute.Direction.Direction -- ^ The direction in which to proceed.+ -> Coordinates -- ^ The point from which to start.+ -> [Coordinates]+extrapolate direction coordinates = extrapolationsByDirectionByCoordinates ! coordinates ! direction -- | The constant lists of /coordinates/, extrapolated from every /coordinate/ in the /board/, in every /direction/.-extrapolationsByDirectionByCoordinates :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Enum x,- Enum y,- Ord x,- Ord y- ) => ArrayByCoordinates x y (Attribute.Direction.ArrayByDirection [Coordinates x y])-{-# SPECIALISE extrapolationsByDirectionByCoordinates :: ArrayByCoordinates Type.Length.X Type.Length.Y (Attribute.Direction.ArrayByDirection [Coordinates Type.Length.X Type.Length.Y]) #-} -- To promote memoisation.+extrapolationsByDirectionByCoordinates :: ArrayByCoordinates (Attribute.Direction.ArrayByDirection [Coordinates]) extrapolationsByDirectionByCoordinates = listArrayByCoordinates #ifdef USE_PARALLEL . Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq)@@ -450,23 +369,13 @@ ) Property.FixedMembership.members -- | The list of /coordinates/, between every permutation of source & valid destination on the /board/.-interpolationsByDestinationBySource :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Enum x,- Enum y,- Ord x,- Ord y- ) => ArrayByCoordinates x y (Data.Map.Map (Coordinates x y) [Coordinates x y])-{-# SPECIALISE interpolationsByDestinationBySource :: ArrayByCoordinates Type.Length.X Type.Length.Y (Data.Map.Map (Coordinates Type.Length.X Type.Length.Y) [Coordinates Type.Length.X Type.Length.Y]) #-} -- To promote memoisation.+interpolationsByDestinationBySource :: ArrayByCoordinates (Map.Map Coordinates [Coordinates]) interpolationsByDestinationBySource = Data.Array.IArray.amap (- Data.Map.fromList . map (+ Map.fromList . map ( last {-destination-} &&& id {-interpolation-} ) . concatMap ( tail {-remove null list-} . Data.List.inits -- Generate all possible interpolations from this extrapolation.- ) . Data.Array.IArray.elems+ ) . Data.Foldable.toList ) extrapolationsByDirectionByCoordinates -- Derive from extrapolations. {- |@@ -474,77 +383,41 @@ * CAVEAT: the destination-/coordinates/ must be a valid @Queen@'s /move/ from the source; so that all intermediate points lie on a square of the board. -}-interpolate :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Coordinates x y -- ^ Source.- -> Coordinates x y -- ^ Destination.- -> [Coordinates x y]-{-# NOINLINE interpolate #-} -- Ensure the rewrite-rule triggers.-{-# RULES "interpolate/Int" interpolate = interpolateInt #-} -- CAVEAT: the call-stack leading here must be specialised to ensure this rule triggers.-interpolate source@MkCoordinates {- getX = x,- getY = y-} destination@MkCoordinates {- getX = x',- getY = y'-}- | source == destination = [] -- CAVEAT: an invalid move.- | otherwise = Control.Exception.assert (- x == x' || y == y' || (- let- distanceX, distanceY :: Type.Length.Distance- (distanceX, distanceY) = measureDistance source destination- in abs distanceX == abs distanceY- ) -- Check that the move is straight.- ) $ zipWith MkCoordinates (x `spanInterval` x') (y `spanInterval` y')- where- spanInterval :: (Enum a, Ord a) => a -> a -> [a]- spanInterval fromAfter to = case to `compare` fromAfter of- GT -> [succ fromAfter .. to]- LT -> let startFromAfter = pred fromAfter in startFromAfter `seq` [startFromAfter, pred startFromAfter .. to]- EQ -> repeat fromAfter---- | A specialisation of 'interpolate'.-interpolateInt :: Coordinates Type.Length.X Type.Length.Y -> Coordinates Type.Length.X Type.Length.Y -> [Coordinates Type.Length.X Type.Length.Y]-interpolateInt coordinatesSource coordinatesDestination = interpolationsByDestinationBySource ! coordinatesSource Data.Map.! coordinatesDestination+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 x y = Coordinates x y -> Coordinates x y+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 :: (Enum x, Enum y) => Attribute.Direction.Direction -> Transformation x y+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 $ fromIntegral yDistance',- getY = Cartesian.Ordinate.fromIx $ fromIntegral xDistance+ getX = Cartesian.Abscissa.fromIx yDistance',+ getY = Cartesian.Ordinate.fromIx xDistance } -- +90 degrees, i.e. anti-clockwise. (EQ, LT) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx $ fromIntegral xDistance',- getY = Cartesian.Ordinate.fromIx $ fromIntegral yDistance'+ getX = Cartesian.Abscissa.fromIx xDistance',+ getY = Cartesian.Ordinate.fromIx yDistance' } -- 180 degrees. (GT, EQ) -> MkCoordinates {- getX = Cartesian.Abscissa.fromIx $ fromIntegral yDistance,- getY = Cartesian.Ordinate.fromIx $ fromIntegral xDistance'+ 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, xDistance', yDistance, yDistance' :: Type.Length.Distance- xDistance = fromIntegral $ Cartesian.Abscissa.toIx x- yDistance = fromIntegral $ Cartesian.Ordinate.toIx y- xDistance' = pred Cartesian.Abscissa.xLength - xDistance- yDistance' = pred Cartesian.Ordinate.yLength - yDistance+ 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/.@@ -553,88 +426,61 @@ * CAVEAT: beware the potential fence-post error. -}-measureDistance :: (- Enum x,- Enum y,- Num distance- )- => Coordinates x y -- ^ Source.- -> Coordinates x y -- ^ Destination.- -> (distance, distance) -- ^ (X-distance, Y-distance)-{-# INLINE measureDistance #-}+measureDistance+ :: Coordinates -- ^ Source.+ -> Coordinates -- ^ Destination.+ -> (Type.Length.X, Type.Length.Y) measureDistance MkCoordinates { getX = x, getY = y } MkCoordinates { getX = x', getY = y'-} = (fromIntegral $ fromEnum x' - fromEnum x, fromIntegral $ fromEnum y' - fromEnum y)+} = (x' - x, y' - y) -- | The /logical colour/ of the specified square.-getLogicalColourOfSquare :: (Enum x, Enum y) => Coordinates x y -> Attribute.LogicalColourOfSquare.LogicalColourOfSquare+getLogicalColourOfSquare :: Coordinates -> Attribute.LogicalColourOfSquare.LogicalColourOfSquare getLogicalColourOfSquare coordinates- | even $ uncurry (+) distance = Attribute.LogicalColourOfSquare.black- | otherwise = Attribute.LogicalColourOfSquare.white- where- distance :: (Type.Length.Distance, Type.Length.Distance)- distance = measureDistance minBound coordinates+ | uncurry (==) . (+ even *** even+ ) $ measureDistance minBound coordinates = Attribute.LogicalColourOfSquare.black+ | otherwise = Attribute.LogicalColourOfSquare.white -- | Whether the specified squares have the same /logical colour/.-areSquaresIsochromatic :: (Enum x, Enum y) => [Coordinates x y] -> Bool+areSquaresIsochromatic :: [Coordinates] -> Bool areSquaresIsochromatic = uncurry (||) . (all (== minBound) &&& all (== maxBound)) . map getLogicalColourOfSquare -- | The conventional starting /coordinates/ for the @King@ of the specified /logical colour/.-kingsStartingCoordinates :: (Enum x, Enum y) => Attribute.LogicalColour.LogicalColour -> Coordinates x y+kingsStartingCoordinates :: Attribute.LogicalColour.LogicalColour -> Coordinates kingsStartingCoordinates logicalColour = MkCoordinates {- getX = Cartesian.Abscissa.fromIx 4,+ getX = Cartesian.Abscissa.kingsFile, getY = Cartesian.Ordinate.firstRank logicalColour } -- | The conventional starting /coordinates/ for each @Rook@.-rooksStartingCoordinates :: (Enum x, Enum y) => Attribute.LogicalColour.LogicalColour -> [Coordinates x y]+rooksStartingCoordinates :: Attribute.LogicalColour.LogicalColour -> [Coordinates] rooksStartingCoordinates Attribute.LogicalColour.Black = [topLeft, maxBound] rooksStartingCoordinates _ = [minBound, bottomRight] -- | Whether the specified /coordinates/ are where a @Pawn@ of the specified /logical colour/ starts.-isPawnsFirstRank- :: (Enum y, Eq y)- => Attribute.LogicalColour.LogicalColour- -> Coordinates x y- -> Bool-{-# INLINE isPawnsFirstRank #-}+isPawnsFirstRank :: Attribute.LogicalColour.LogicalColour -> Coordinates -> Bool isPawnsFirstRank logicalColour MkCoordinates { getY = y } = y == Cartesian.Ordinate.pawnsFirstRank logicalColour -- | Whether a @Pawn@ is currently on the appropriate /rank/ to take an opponent's @Pawn@ /en-passant/.-isEnPassantRank- :: (Enum y, Eq y)- => Attribute.LogicalColour.LogicalColour- -> Coordinates x y- -> Bool+isEnPassantRank :: Attribute.LogicalColour.LogicalColour -> Coordinates -> Bool isEnPassantRank logicalColour MkCoordinates { getY = y } = y == Cartesian.Ordinate.enPassantRank logicalColour -- | A boxed array indexed by /coordinates/, of arbitrary elements.-type ArrayByCoordinates x y = Data.Array.IArray.Array (Coordinates x y)+type ArrayByCoordinates = Data.Array.IArray.Array Coordinates -- | An unboxed array indexed by /coordinates/, of fixed-size elements.-type UArrayByCoordinates x y = Data.Array.Unboxed.UArray (Coordinates x y)+type UArrayByCoordinates = Data.Array.Unboxed.UArray Coordinates -- | Array-constructor from an ordered list of elements.-listArrayByCoordinates :: (- Data.Array.IArray.IArray a e,- Enum x,- Enum y,- Ord x,- Ord y- ) => [e] -> a (Coordinates x y) e+listArrayByCoordinates :: Data.Array.IArray.IArray a e => [e] -> a Coordinates e listArrayByCoordinates = Data.Array.IArray.listArray (minBound, maxBound) -- | Array-constructor from an association-list.-arrayByCoordinates :: (- Data.Array.IArray.IArray a e,- Enum x,- Enum y,- Ord x,- Ord y- ) => [(Coordinates x y, e)] -> a (Coordinates x y) e+arrayByCoordinates :: Data.Array.IArray.IArray a e => [(Coordinates, e)] -> a Coordinates e arrayByCoordinates = Data.Array.IArray.array (minBound, maxBound)
src-lib/BishBosh/Cartesian/Ordinate.hs view
@@ -29,10 +29,7 @@ -} module BishBosh.Cartesian.Ordinate(--- * Types--- ArrayByOrdinate, -- * Constants- yOrigin, yLength, yMin, yMax,@@ -48,107 +45,80 @@ reflect, translate, maybeTranslate,--- ** Constructors--- listArrayByOrdinate, -- ** Predicates inBounds ) where import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa-import qualified BishBosh.Data.Enum as Data.Enum import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception-import qualified Data.Array.IArray --- | The position of the origin on the /y/-axis.-yOrigin :: Int-yOrigin = Cartesian.Abscissa.xOrigin -- N.B. it doesn't need to be the same.- -- | The constant length of the /y/-axis.-yLength :: Type.Length.Distance-yLength = Cartesian.Abscissa.xLength -- Because the board is square.---- | The constant lower bound of ordinates.-yMin :: Enum y => y-yMin = toEnum yOrigin---- | The constant upper bound of ordinates.-yMax :: Enum y => y-yMax = toEnum $ yOrigin + fromIntegral (pred {-fence-post-} yLength)+yLength :: Type.Length.Y+yLength = fromIntegral Cartesian.Abscissa.xLength -- I.E.: the board is square. -- | The constant bounds of ordinates.-yBounds :: Enum y => (y, y)-yBounds = (yMin, yMax)+yBounds :: (Type.Length.Y, Type.Length.Y)+yMin, yMax :: Type.Length.Y+yBounds@(yMin, yMax) = (0, yMin + pred {-fence-post-} yLength) -- | The constant list of all ordinates.-yRange :: Enum y => [y]+yRange :: [Type.Length.Y] yRange = uncurry enumFromTo yBounds -- | Convert to an array-index.-toIx :: Enum y => y -> Int+toIx :: Type.Length.Y -> Int {-# INLINE toIx #-}-toIx = subtract yOrigin . fromEnum+toIx = fromIntegral . subtract yMin -- | Convert from an array-index.-fromIx :: Enum y => Int -> y+fromIx :: Int -> Type.Length.Y {-# INLINE fromIx #-}-fromIx = toEnum . (+ yOrigin)+fromIx = (+ yMin) . fromIntegral -- | The /rank/ from which /piece/s conventionally start.-firstRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y+firstRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y firstRank Attribute.LogicalColour.Black = yMax firstRank _ = yMin -- | The final /rank/; i.e. the one on which a @Pawn@ is promoted.-lastRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y+lastRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y lastRank = firstRank . Property.Opposable.getOpposite -- | The /rank/ from which @Pawn@s conventionally start.-pawnsFirstRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y+pawnsFirstRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y {-# INLINE pawnsFirstRank #-} pawnsFirstRank Attribute.LogicalColour.Black = pred yMax pawnsFirstRank _ = succ yMin -- | The /rank/ from which a @Pawn@ may capture /en-passant/.-enPassantRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y+enPassantRank :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y {-# INLINE enPassantRank #-}-enPassantRank Attribute.LogicalColour.Black = toEnum $ yOrigin + 3-enPassantRank _ = toEnum $ yOrigin + 4+enPassantRank Attribute.LogicalColour.Black = fromIx 3+enPassantRank _ = fromIx 4 -- | Reflects about the mid-point of the axis.-reflect :: Enum y => y -> y-reflect = Data.Enum.translate $ (- + (2 * yOrigin + fromIntegral (pred yLength))+reflect :: Type.Length.Y -> Type.Length.Y+reflect = (+ + (2 * yMin + pred yLength) ) . negate -- | Predicate.-inBounds :: (Enum y, Ord y) => y -> Bool+inBounds :: Type.Length.Y -> Bool {-# INLINE inBounds #-} inBounds y = y >= yMin && y <= yMax -- | Translate the specified ordinate.-translate :: (Enum y, Ord y) => (y -> y) -> y -> y+translate :: (Type.Length.Y -> Type.Length.Y) -> Type.Length.Y -> Type.Length.Y translate transformation = (\y -> Control.Exception.assert (inBounds y) y) . transformation -- | Where legal, translate the specified ordinate.-maybeTranslate :: (Enum y, Ord y) => (y -> y) -> y -> Maybe y+maybeTranslate :: (Type.Length.Y -> Type.Length.Y) -> Type.Length.Y -> Maybe Type.Length.Y maybeTranslate transformation = ( \y -> if inBounds y then Just y else Nothing ) . transformation----- | A boxed array indexed by /coordinates/, of arbitrary elements.-type ArrayByOrdinate y = Data.Array.IArray.Array {-Boxed-} y---- | Array-constructor.-listArrayByOrdinate :: (- Data.Array.IArray.IArray a e,- Data.Array.IArray.Ix y,- Enum y- ) => [e] -> a y e-listArrayByOrdinate = Data.Array.IArray.listArray yBounds
src-lib/BishBosh/Cartesian/Vector.hs view
@@ -19,13 +19,10 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Describes a line's magnitude & direction, irrespective of its position.+ [@DESCRIPTION@] Describes a line's magnitude & direction, irrespective of its position; cf. 'Component.Move.Move'. -} module BishBosh.Cartesian.Vector(--- * Types--- ** Type-synonyms- VectorInt, -- ** Data-types Vector( -- MkVector,@@ -41,7 +38,6 @@ maybeTranslate, toMaybeDirection, -- ** Constructor- mkVector, measureDistance, -- ** Predicates -- hasDistance,@@ -54,129 +50,127 @@ matchesPawnDoubleAdvance ) where -import Control.Arrow((***))+import Control.Arrow((&&&), (***)) import qualified BishBosh.Attribute.Direction as Attribute.Direction 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.Cartesian.Ordinate as Cartesian.Ordinate-import qualified BishBosh.Data.Enum as Data.Enum 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 Control.DeepSeq-import qualified Control.Exception -- | The distance between two /coordinates/.-data Vector distance = MkVector {- getXDistance :: !distance,- getYDistance :: !distance+data Vector = MkVector {+ getXDistance :: ! Type.Length.X,+ getYDistance :: ! Type.Length.Y } deriving (Eq, Show) -instance Num distance => Property.Opposable.Opposable (Vector distance) where- getOpposite (MkVector xDistance yDistance) = MkVector (negate xDistance) (negate yDistance)+instance Control.DeepSeq.NFData Vector where+ rnf MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+ } = Control.DeepSeq.rnf (xDistance, yDistance) --- | Whether the vector has a non-zero length (or a well-defined direction).-hasDistance :: (Eq distance, Num distance) => distance -> distance -> Bool-hasDistance xDistance yDistance = xDistance /= 0 || yDistance /= 0+instance Property.Opposable.Opposable Vector where+ getOpposite MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+ } = MkVector (negate xDistance) (negate yDistance) --- | Smart constructor.-mkVector :: (Num distance, Ord distance) => distance -> distance -> Vector distance-{-# INLINE mkVector #-}-mkVector xDistance yDistance = Control.Exception.assert (- hasDistance xDistance yDistance && abs xDistance < fromIntegral Cartesian.Abscissa.xLength && abs yDistance < fromIntegral Cartesian.Ordinate.yLength- ) $ MkVector xDistance yDistance+instance Property.Orientated.Orientated Vector where+ isDiagonal = isDiagonal+ isParallel = isParallel +-- | 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+hasDistance _ _ = True+ -- | Construct a /vector/ by measuring the signed distance between source-/coordinates/ & destination.-measureDistance :: (- Enum x,- Enum y,- Num distance,- Ord distance- )- => Cartesian.Coordinates.Coordinates x y -- ^ Source.- -> Cartesian.Coordinates.Coordinates x y -- ^ Destination.- -> Vector distance-{-# INLINE measureDistance #-}-measureDistance source destination = uncurry mkVector $ Cartesian.Coordinates.measureDistance source destination+measureDistance+ :: Cartesian.Coordinates.Coordinates -- ^ Source.+ -> Cartesian.Coordinates.Coordinates -- ^ Destination.+ -> 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 :: (Eq distance, Num distance) => Vector distance -> Bool-{-# INLINE isDiagonal #-} -- N.B.: highly effective.-isDiagonal (MkVector xDistance yDistance) = abs xDistance == abs yDistance+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 :: (Eq distance, Num distance) => Vector distance -> Bool+isParallel :: Vector -> Bool {-# INLINE isParallel #-}-isParallel (MkVector xDistance yDistance) = xDistance == 0 || yDistance == 0+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 :: (Eq distance, Num distance) => Vector distance -> Bool-{-# INLINE isStraight #-}-isStraight vector = isParallel vector || isDiagonal vector---- | A suitable concrete type.-type VectorInt = Vector Type.Length.Distance--instance Control.DeepSeq.NFData distance => Control.DeepSeq.NFData (Vector distance) where- rnf MkVector { getXDistance = xDistance, getYDistance = yDistance } = Control.DeepSeq.rnf (xDistance, yDistance)--instance (Eq distance, Num distance) => Property.Orientated.Orientated (Vector distance) where- {-# SPECIALISE instance Property.Orientated.Orientated VectorInt #-}- isDiagonal = isDiagonal- isParallel = isParallel+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 :: Num distance => Attribute.LogicalColour.LogicalColour -> [Vector distance]+attackVectorsForPawn :: Attribute.LogicalColour.LogicalColour -> [Vector] attackVectorsForPawn logicalColour = [- MkVector x $ (- if Attribute.LogicalColour.isBlack logicalColour- then negate -- Black moves down.- else id -- White moves up.- ) 1 | x <- [negate 1, 1]+ MkVector {+ getXDistance = x,+ getYDistance = (+ if Attribute.LogicalColour.isBlack logicalColour+ then negate -- Black moves down.+ else id -- White moves up.+ ) 1+ } | x <- [negate 1, 1] ] -- List-comprehension. -- | The constant list of attack-vectors for a @Knight@.-attackVectorsForKnight :: Num distance => [Vector distance]+attackVectorsForKnight :: [Vector] attackVectorsForKnight = [- MkVector (fX xDistance) (fY $ 3 - xDistance) |- fX <- negateOrNot,- fY <- negateOrNot,+ MkVector {+ getXDistance = fX xDistance,+ getYDistance = fY $ 3 - fromIntegral xDistance+ } |+ fX <- [negate, id],+ fY <- [negate, id], xDistance <- [1, 2]- ] where- negateOrNot = [negate, id]+ ] -- | The constant list of attack-vectors for a @King@.-attackVectorsForKing :: (Eq distance, Num distance) => [Vector distance]+attackVectorsForKing :: [Vector] attackVectorsForKing = [ MkVector xDistance yDistance |- xDistance <- signumValues,- yDistance <- signumValues,+ xDistance <- [negate 1, 0, 1],+ yDistance <- [negate 1, 0, 1], hasDistance xDistance yDistance- ] where- signumValues = [negate 1, 0, 1]+ ] {- | * Whether the specified /vector/ might represent an attack (rather than an advance) by a @Pawn@. * 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 :: (Eq distance, Num distance) => Attribute.LogicalColour.LogicalColour -> Vector distance -> Bool+isPawnAttack :: Attribute.LogicalColour.LogicalColour -> Vector -> Bool {-# INLINE isPawnAttack #-}-isPawnAttack logicalColour (MkVector xDistance yDistance) = abs xDistance == 1 && yDistance == (- if Attribute.LogicalColour.isBlack logicalColour- then negate- else id- ) 1+isPawnAttack logicalColour MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+} = abs xDistance == 1 && yDistance == if Attribute.LogicalColour.isBlack logicalColour+ then negate 1+ else 1 -- | Whether the specified /vector/ represents a move a @Knight@ could make.-isKnightsMove :: (Eq distance, Num distance) => Vector distance -> Bool+isKnightsMove :: Vector -> Bool {-# INLINE isKnightsMove #-}-isKnightsMove (MkVector xDistance yDistance) = case abs xDistance of+isKnightsMove MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+} = case abs xDistance of 1 -> absYDistance == 2 2 -> absYDistance == 1 _ -> False@@ -184,65 +178,45 @@ absYDistance = abs yDistance -- | Whether the specified /vector/ represents a move a @King@ could make.-isKingsMove :: (Num distance, Ord distance) => Vector distance -> Bool-isKingsMove (MkVector 0 0) = False-isKingsMove (MkVector xDistance yDistance) = abs xDistance <= 1 && abs yDistance <= 1+isKingsMove :: Vector -> Bool+isKingsMove MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+} = abs xDistance <= 1 && abs yDistance <= 1 {- | * Whether the specified /vector/ matches a @Pawn@'s initial double-advance move. * 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- :: (Eq distance, Num distance)- => Attribute.LogicalColour.LogicalColour- -> Vector distance- -> Bool-matchesPawnDoubleAdvance logicalColour (MkVector xDistance yDistance) = xDistance == 0 && yDistance == (- if Attribute.LogicalColour.isBlack logicalColour- then negate- else id- ) 2+matchesPawnDoubleAdvance :: Attribute.LogicalColour.LogicalColour -> Vector -> Bool+matchesPawnDoubleAdvance logicalColour MkVector {+ getXDistance = 0,+ getYDistance = yDistance+} = yDistance == if Attribute.LogicalColour.isBlack logicalColour then negate 2 else 2+matchesPawnDoubleAdvance _ _ = False -- | Translate the specified /coordinates/ by the specified /vector/.-translate :: (- Enum x,- Enum y,- Integral distance,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y- -> Vector distance- -> Cartesian.Coordinates.Coordinates x y-translate coordinates (MkVector xDistance yDistance) = Cartesian.Coordinates.translate (- Data.Enum.translate (+ fromIntegral xDistance) *** Data.Enum.translate (+ fromIntegral yDistance)- ) coordinates+translate :: Cartesian.Coordinates.Coordinates -> Vector -> Cartesian.Coordinates.Coordinates+translate coordinates MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+} = Cartesian.Coordinates.translate ((+ xDistance) *** (+ yDistance)) coordinates -- | Where legal, translate the specified /coordinates/ by the specified /vector/.-maybeTranslate :: (- Enum x,- Enum y,- Integral distance,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y- -> Vector distance- -> Maybe (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE maybeTranslate :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Vector Type.Length.Distance -> Maybe (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) #-}-maybeTranslate coordinates (MkVector xDistance yDistance) = Cartesian.Coordinates.maybeTranslate (- Data.Enum.translate (+ fromIntegral xDistance) *** Data.Enum.translate (+ fromIntegral yDistance)- ) coordinates+maybeTranslate :: Cartesian.Coordinates.Coordinates -> Vector -> Maybe Cartesian.Coordinates.Coordinates+maybeTranslate coordinates MkVector {+ getXDistance = xDistance,+ getYDistance = yDistance+} = Cartesian.Coordinates.maybeTranslate ((+ xDistance) *** (+ yDistance)) coordinates {- | * 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 :: (Num distance, Ord distance) => Vector distance -> Maybe Attribute.Direction.Direction-{-# INLINE toMaybeDirection #-}+toMaybeDirection :: Vector -> Maybe Attribute.Direction.Direction toMaybeDirection vector@(MkVector xDistance yDistance)- | isStraight vector = Just $ Attribute.Direction.mkDirection (compare xDistance 0) (compare yDistance 0)+ | isStraight vector = Just $ Attribute.Direction.mkDirection (xDistance `compare` 0) (yDistance `compare` 0) | otherwise = Nothing
+ src-lib/BishBosh/Component/Accountant.hs view
@@ -0,0 +1,42 @@+{-+ 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@] Sum the relative values of /rank/ of piece, based on their location on the board, at a specific stage in the game.+-}++module BishBosh.Component.Accountant(+-- * Type-classes+ Accountant(..)+) where++import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank+import qualified BishBosh.Type.Count as Type.Count++-- | 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.+ -> accountant+ -> [pieceSquareValue]+
src-lib/BishBosh/Component/CastlingMove.hs view
@@ -38,8 +38,7 @@ -- defineCastlingMoves, getLongAndShortMoves, -- ** Accessors- getCastlingMoves,--- getCastlingMovesInt+ getCastlingMoves ) where import Control.Arrow((&&&))@@ -48,41 +47,35 @@ 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.Data.Enum as Data.Enum import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception -- | Defines a castling-move.-data CastlingMove x y = MkCastlingMove {+data CastlingMove = MkCastlingMove { getMoveType :: Attribute.MoveType.MoveType, -- ^ CAVEAT: should only be a castling-move type.- getKingsMove :: Component.Move.Move x y,- getRooksMove :: Component.Move.Move x y+ getKingsMove :: Component.Move.Move,+ getRooksMove :: Component.Move.Move } --- | The constant number of files over which the King always travels when castling.-kingsMoveLength :: Num x => x+-- | The constant number of files over which the @King@ always travels when castling.+kingsMoveLength :: Type.Length.X kingsMoveLength = 2 -- | Define all possible castling-moves for the specified /logical colour/.-defineCastlingMoves :: (- Enum x,- Enum y,- Eq y,- Ord x- ) => Attribute.LogicalColour.LogicalColour -> [CastlingMove x y]+defineCastlingMoves :: Attribute.LogicalColour.LogicalColour -> [CastlingMove] defineCastlingMoves logicalColour = [ MkCastlingMove { getMoveType = Attribute.MoveType.longCastle, getKingsMove = kingsMove $ subtract kingsMoveLength,- getRooksMove = uncurry Component.Move.mkMove . (id &&& translateX (+ 3)) $ if isBlack+ getRooksMove = uncurry Component.Move.mkMove . (id &&& Cartesian.Coordinates.translateX (+ 3)) $ if isBlack then Cartesian.Coordinates.topLeft else minBound }, MkCastlingMove { getMoveType = Attribute.MoveType.shortCastle, getKingsMove = kingsMove (+ kingsMoveLength),- getRooksMove = uncurry Component.Move.mkMove . (id &&& translateX (subtract 2)) $ if isBlack+ getRooksMove = uncurry Component.Move.mkMove . (id &&& Cartesian.Coordinates.translateX (subtract 2)) $ if isBlack then maxBound else Cartesian.Coordinates.bottomRight }@@ -90,19 +83,10 @@ isBlack :: Bool isBlack = Attribute.LogicalColour.isBlack logicalColour - kingsStartingCoordinates = Cartesian.Coordinates.kingsStartingCoordinates logicalColour- kingsMove translation = Component.Move.mkMove kingsStartingCoordinates $ translateX translation kingsStartingCoordinates-- translateX :: (Enum x, Ord x) => (Int -> Int) -> Cartesian.Coordinates.Coordinates x y -> Cartesian.Coordinates.Coordinates x y- translateX = Cartesian.Coordinates.translateX . Data.Enum.translate+ 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 :: (- Enum x,- Enum y,- Eq y,- Ord x- ) => Attribute.LogicalColour.ArrayByLogicalColour [CastlingMove x y]+castlingMovesByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [CastlingMove] castlingMovesByLogicalColour = Attribute.LogicalColour.listArrayByLogicalColour $ map defineCastlingMoves Property.FixedMembership.members {- |@@ -110,28 +94,11 @@ * CAVEAT: the moves are returned in unspecified order. -}-getCastlingMoves :: (- Enum x,- Enum y,- Eq y,- Ord x- ) => Attribute.LogicalColour.LogicalColour -> [CastlingMove x y]-{-# NOINLINE getCastlingMoves #-} -- Ensure the rewrite-rule triggers.-{-# RULES "getCastlingMoves/Int" getCastlingMoves = getCastlingMovesInt #-}-getCastlingMoves = defineCastlingMoves---- | A specialisation of 'getCastlingMoves'.-getCastlingMovesInt :: Attribute.LogicalColour.LogicalColour -> [CastlingMove Type.Length.X Type.Length.Y]-getCastlingMovesInt = (castlingMovesByLogicalColour !)+getCastlingMoves :: Attribute.LogicalColour.LogicalColour -> [CastlingMove]+getCastlingMoves = (castlingMovesByLogicalColour !) -- | Break-down the two castling-moves for the specified /logical colour/ into a long & a short castling-move.-getLongAndShortMoves :: (- Enum x,- Enum y,- Eq y,- Ord x- ) => Attribute.LogicalColour.LogicalColour -> (CastlingMove x y, CastlingMove x y)-{-# SPECIALISE getLongAndShortMoves :: Attribute.LogicalColour.LogicalColour -> (CastlingMove Type.Length.X Type.Length.Y, CastlingMove Type.Length.X Type.Length.Y) #-}+getLongAndShortMoves :: Attribute.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/EitherQualifiedMove.hs view
@@ -49,16 +49,16 @@ import qualified BishBosh.Component.Move as Component.Move -- | As returned by 'Notation.MoveNotation.readsQualifiedMove'.-data EitherQualifiedMove x y = MkEitherQualifiedMove {- getMove :: Component.Move.Move x y,+data EitherQualifiedMove = MkEitherQualifiedMove {+ getMove :: Component.Move.Move, getPromotionRankOrMoveType :: Either (Maybe Attribute.Rank.Rank) Attribute.MoveType.MoveType -- ^ Either the optional /rank/ to which a @Pawn@ should be promoted, or the complete /move-type/. } -- | Constructor for notations which don't encode sufficient information to reliably re-construct the /move-type/, but merely the /rank/ to which a @Pawn@ is to be promoted.-mkPartiallyQualifiedMove :: Component.Move.Move x y -> Maybe Attribute.Rank.Rank -> EitherQualifiedMove x y+mkPartiallyQualifiedMove :: Component.Move.Move -> Maybe Attribute.Rank.Rank -> EitherQualifiedMove mkPartiallyQualifiedMove move = MkEitherQualifiedMove move . Left -- | Constructor for notations which encode sufficient information to reliably re-construct the /move-type/.-mkFullyQualifiedMove :: Component.Move.Move x y -> Attribute.MoveType.MoveType -> EitherQualifiedMove x y+mkFullyQualifiedMove :: Component.Move.Move -> Attribute.MoveType.MoveType -> EitherQualifiedMove mkFullyQualifiedMove move = MkEitherQualifiedMove move . Right
src-lib/BishBosh/Component/Move.hs view
@@ -19,7 +19,11 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Defines one move (actually just a half move AKA "ply") of a /piece/.+ [@DESCRIPTION@]++ * Defines one move (actually just a half move AKA "ply") of a /piece/.++ * Similar to 'Cartesian.Vector.Vector', but the position is fixed. -} module BishBosh.Component.Move(@@ -49,7 +53,6 @@ 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 BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -68,50 +71,45 @@ * Most modern chess-notations (except Standard Algebraic) start with similar information, but also define ancillary information which is captured in /MoveType/. -}-data Move x y = MkMove {- getSource :: Cartesian.Coordinates.Coordinates x y,- getDestination :: Cartesian.Coordinates.Coordinates x y+data Move = MkMove {+ getSource :: Cartesian.Coordinates.Coordinates,+ getDestination :: Cartesian.Coordinates.Coordinates } deriving Eq -instance (Ord x, Ord y) => Ord (Move x y) where- {-# SPECIALISE instance Ord (Move Type.Length.X Type.Length.Y) #-}+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' ordering -> ordering -instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (Move x y) where+instance Control.DeepSeq.NFData Move where rnf MkMove { getSource = source, getDestination = destination } = Control.DeepSeq.rnf (source, destination) -instance (Show x, Show y) => Show (Move x y) where+instance Show Move where showsPrec precedence MkMove { getSource = source, getDestination = destination } = showsPrec precedence (source, destination) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Read x,- Read y- ) => Read (Move x y) where+instance Read Move where readsPrec precedence = map (Control.Arrow.first $ uncurry mkMove) . readsPrec precedence -instance Property.Opposable.Opposable (Move x y) where- getOpposite (MkMove source destination) = MkMove {+instance Property.Opposable.Opposable Move where+ getOpposite MkMove {+ getSource = source,+ getDestination = destination+ } = MkMove { getSource = destination, getDestination = source } -instance (Enum x, Enum y) => Property.Orientated.Orientated (Move x y) where- isDiagonal = (Property.Orientated.isDiagonal :: Cartesian.Vector.VectorInt -> Bool) . measureDistance- isParallel = (Property.Orientated.isParallel :: Cartesian.Vector.VectorInt -> Bool) . measureDistance+instance Property.Orientated.Orientated Move where+ isDiagonal = Property.Orientated.isDiagonal . measureDistance+ isParallel = Property.Orientated.isParallel . measureDistance -instance Enum y => Property.Reflectable.ReflectableOnX (Move x y) where+instance Property.Reflectable.ReflectableOnX Move where reflectOnX MkMove { getSource = source, getDestination = destination@@ -120,7 +118,7 @@ getDestination = Property.Reflectable.reflectOnX destination } -instance Enum x => Property.Reflectable.ReflectableOnY (Move x y) where+instance Property.Reflectable.ReflectableOnY Move where reflectOnY MkMove { getSource = source, getDestination = destination@@ -131,10 +129,9 @@ -- | Smart constructor. mkMove- :: (Eq x, Eq y)- => Cartesian.Coordinates.Coordinates x y- -> Cartesian.Coordinates.Coordinates x y- -> Move x y+ :: Cartesian.Coordinates.Coordinates+ -> Cartesian.Coordinates.Coordinates+ -> Move {-# INLINE mkMove #-} mkMove source destination = Control.Exception.assert (source /= destination) MkMove { getSource = source,@@ -142,26 +139,14 @@ } -- | Measures the signed distance between the ends of the move.-measureDistance :: (- Enum x,- Enum y,- Num distance,- Ord distance- ) => Move x y -> Cartesian.Vector.Vector distance-{-# SPECIALISE measureDistance :: Move Type.Length.X Type.Length.Y -> Cartesian.Vector.VectorInt #-}+measureDistance :: Move -> Cartesian.Vector.Vector measureDistance MkMove { getSource = source, getDestination = destination } = Cartesian.Vector.measureDistance source destination -- | Generates a line of /coordinates/ covering the half open interval @(source, destination]@.-interpolate :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Move x y -> [Cartesian.Coordinates.Coordinates x y]-{-# SPECIALISE interpolate :: Move Type.Length.X Type.Length.Y -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y] #-}+interpolate :: Move -> [Cartesian.Coordinates.Coordinates] interpolate move@MkMove { getSource = source, getDestination = destination@@ -174,13 +159,10 @@ but passing only guarantees that it is, if it was a @Pawn@ which moved & that the /move/ is valid. -} isPawnDoubleAdvance- :: (Enum x, Enum y, Eq y)- => Attribute.LogicalColour.LogicalColour -- Defines the side whose move is referenced.- -> Move x y+ :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side whose move is referenced.+ -> Move -> Bool-isPawnDoubleAdvance logicalColour move = Cartesian.Coordinates.isPawnsFirstRank logicalColour (- getSource move- ) && Cartesian.Vector.matchesPawnDoubleAdvance logicalColour (- measureDistance move :: Cartesian.Vector.VectorInt+isPawnDoubleAdvance logicalColour move@MkMove { getSource = source } = Cartesian.Coordinates.isPawnsFirstRank logicalColour source && Cartesian.Vector.matchesPawnDoubleAdvance logicalColour (+ measureDistance move )
src-lib/BishBosh/Component/Piece.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP, LambdaCase #-}-{-# OPTIONS_GHC -fno-warn-unused-binds #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -29,7 +28,7 @@ -- ** Type-synonyms -- ByRankByLogicalColour, -- AttackDestinationsByCoordinatesByRankByLogicalColour,--- ArrayByPiece,+ ArrayByPiece, LocatedPiece, -- ** Data-types Piece(@@ -39,15 +38,15 @@ ), -- * Constants -- tag,- nPiecesPerSide, range,+ nPiecesPerSide,+ epdCharacterSet, -- attackVectorsByRankByLogicalColour, -- attackDirectionsByRankByLogicalColour, -- attackDestinationsByCoordinatesByRankByLogicalColour, -- * Functions -- findAttackDestinations', findAttackDestinations,--- findAttackDestinationsInt, showPieces, -- ** Accessors getAttackDirections,@@ -62,7 +61,7 @@ mkPiece, mkQueen, mkRook,--- listArrayByPiece,+ listArrayByPiece, -- ** Predicates canAttackAlong, canMoveBetween,@@ -83,22 +82,22 @@ 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.Ordinate as Cartesian.Ordinate import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Data.Exception as Data.Exception 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 BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray import qualified Data.Char+import qualified Data.Foldable import qualified Data.List.Extra-import qualified Data.Map+import qualified Data.Map as Map import qualified Data.Maybe import qualified Text.XML.HXT.Arrow.Pickle as HXT import qualified Text.XML.HXT.Arrow.Pickle.Schema@@ -111,9 +110,9 @@ tag :: String tag = "piece" --- | The initial number of pieces per side in a standard opening position; some of which are duplicates.+-- | The constant number of pieces per side at the conventional opening position; some of which are duplicates. nPiecesPerSide :: Type.Count.NPieces-nPiecesPerSide = fromIntegral $ Cartesian.Abscissa.xLength * 2 {-rows-}+nPiecesPerSide = Data.Foldable.foldl' (+) 0 Attribute.Rank.initialAllocationByRankPerSide -- | A Chess-piece has a /logical colour/ & a /rank/. data Piece = MkPiece {@@ -141,6 +140,10 @@ instance Show Piece where showsPrec _ = Property.ForsythEdwards.showsFEN +-- | The constant set of permissible characters in an EPD.+epdCharacterSet :: Property.ExtendedPositionDescription.EPD+epdCharacterSet = concatMap Property.ExtendedPositionDescription.showEPD range+ instance Property.ExtendedPositionDescription.ReadsEPD Piece where readsEPD s = case Data.List.Extra.trimStart s of c : remainder -> (@@ -197,11 +200,11 @@ -- | Constructor. mkPawn :: Attribute.LogicalColour.LogicalColour -> Piece-mkPawn = (`MkPiece` Attribute.Rank.Pawn)+mkPawn = (`MkPiece` Attribute.Rank.Pawn) -- | Constructor. mkRook :: Attribute.LogicalColour.LogicalColour -> Piece-mkRook = (`MkPiece` Attribute.Rank.Rook)+mkRook = (`MkPiece` Attribute.Rank.Rook) -- | Constructor. mkKnight :: Attribute.LogicalColour.LogicalColour -> Piece@@ -213,22 +216,21 @@ -- | Constructor. mkQueen :: Attribute.LogicalColour.LogicalColour -> Piece-mkQueen = (`MkPiece` Attribute.Rank.Queen)+mkQueen = (`MkPiece` Attribute.Rank.Queen) -- | Constructor. mkKing :: Attribute.LogicalColour.LogicalColour -> Piece-mkKing = (`MkPiece` Attribute.Rank.King)--{- |- * Changes the specified /piece/ to the specified /rank/ leaving its /logical colour/ unchanged.+mkKing = (`MkPiece` Attribute.Rank.King) - * CAVEAT: only legal if the unspecifed original /rank/ was a @Pawn@, & becomes neither a @Pawn@ nor a @King@.--}+-- | Changes the specified /piece/ to the specified /rank/ leaving its /logical colour/ unchanged. promote :: Attribute.Rank.Rank -> Piece -> Piece-promote newRank piece = piece { getRank = newRank }+promote newRank piece+ | not $ isPawn piece = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Component.Piece.promote:\tcan't promote a " $ shows piece "."+ | newRank `notElem` Attribute.Rank.promotionProspects = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Component.Piece.promote:\tcan't promote to a " $ shows newRank "."+ | otherwise = piece { getRank = newRank } -- | The structure of a container of arbitrary data, indexed by /logicalColour/ & some /rank/s.-type ByRankByLogicalColour element = Attribute.LogicalColour.ArrayByLogicalColour (Data.Map.Map Attribute.Rank.Rank element)+type ByRankByLogicalColour element = Attribute.LogicalColour.ArrayByLogicalColour (Map.Map Attribute.Rank.Rank element) -- | Constructor of a certain shape of container, but with arbitrary contents. mkByRankByLogicalColour ::@@ -241,7 +243,7 @@ . Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq) #endif $ map (- \logicalColour -> Data.Map.fromList $ map (id &&& mkElement logicalColour) ranks+ \logicalColour -> Map.fromList $ map (id &&& mkElement logicalColour) ranks ) Property.FixedMembership.members {- |@@ -251,13 +253,7 @@ * CAVEAT: it doesn't identify @Pawn@-advances, since these aren't attacks. -}-attackVectorsByRankByLogicalColour :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData distance,-#endif- Num distance,- Ord distance- ) => ByRankByLogicalColour [Cartesian.Vector.Vector distance]+attackVectorsByRankByLogicalColour :: ByRankByLogicalColour [Cartesian.Vector.Vector] attackVectorsByRankByLogicalColour = mkByRankByLogicalColour Attribute.Rank.fixedAttackRange $ \logicalColour -> \case Attribute.Rank.Pawn -> Cartesian.Vector.attackVectorsForPawn logicalColour Attribute.Rank.Knight -> Cartesian.Vector.attackVectorsForKnight@@ -265,8 +261,22 @@ rank -> error . showString "BishBosh.Component.Piece.attackVectorsByRankByLogicalColour:\trank must attack over fixed range; " $ shows rank "." -- These ranks attack over any distance. -- | The destinations available to those pieces with attack-vectors; @Pawn@, @Knight@, @King@.-type AttackDestinationsByCoordinatesByRankByLogicalColour x y = ByRankByLogicalColour (Cartesian.Coordinates.ArrayByCoordinates x y [Cartesian.Coordinates.Coordinates x y])+type AttackDestinationsByCoordinatesByRankByLogicalColour = ByRankByLogicalColour (Cartesian.Coordinates.ArrayByCoordinates [Cartesian.Coordinates.Coordinates]) +-- | 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+ -> [Cartesian.Coordinates.Coordinates] -- ^ The destinations which can be attacked.+findAttackDestinations' source MkPiece {+ getLogicalColour = logicalColour,+ getRank = rank+} = Data.Maybe.mapMaybe (+ Cartesian.Vector.maybeTranslate source+ ) (+ attackVectorsByRankByLogicalColour ! logicalColour Map.! rank+ )+ {- | * The destinations available to those pieces with attack-vectors; @Pawn@, @Knight@, @King@. @@ -274,60 +284,20 @@ * CAVEAT: this function has no knowledge of the /board/, & therefore of the position of any other piece. -}-attackDestinationsByCoordinatesByRankByLogicalColour :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Enum x,- Enum y,- Ord x,- Ord y- ) => AttackDestinationsByCoordinatesByRankByLogicalColour x y-{-# SPECIALISE attackDestinationsByCoordinatesByRankByLogicalColour :: AttackDestinationsByCoordinatesByRankByLogicalColour Type.Length.X Type.Length.Y #-} -- To promote memoisation.+attackDestinationsByCoordinatesByRankByLogicalColour :: AttackDestinationsByCoordinatesByRankByLogicalColour attackDestinationsByCoordinatesByRankByLogicalColour = mkByRankByLogicalColour Attribute.Rank.fixedAttackRange $ \logicalColour rank -> Cartesian.Coordinates.listArrayByCoordinates $ map ( `findAttackDestinations'` mkPiece logicalColour rank ) Property.FixedMembership.members --- | Calls 'attackVectorsByRankByLogicalColour' to find the destinations which the specified /piece/ can attack from the specified position.-findAttackDestinations' :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y -- ^ The source from which the attack originates.- -> Piece- -> [Cartesian.Coordinates.Coordinates x y] -- ^ The destinations which can be attacked.-findAttackDestinations' source MkPiece {- getLogicalColour = logicalColour,- getRank = rank-} = Data.Maybe.mapMaybe (- Cartesian.Vector.maybeTranslate source- ) (- attackVectorsByRankByLogicalColour ! logicalColour Data.Map.! rank :: [Cartesian.Vector.VectorInt]- )- -- | Find the destinations which the specified /piece/ can attack from the specified position.-findAttackDestinations :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y -- ^ The source from which the attack originates.+findAttackDestinations+ :: Cartesian.Coordinates.Coordinates -- ^ The source from which the attack originates. -> Piece- -> [Cartesian.Coordinates.Coordinates x y] -- ^ The destinations which can be attacked.-{-# NOINLINE findAttackDestinations #-} -- Ensure the rewrite-rule triggers.-{-# RULES "findAttackDestinations/Int" findAttackDestinations = findAttackDestinationsInt #-} -- CAVEAT: the call-stack leading to this function must be specialised to ensure this triggers.-findAttackDestinations = findAttackDestinations'---- | A specialisation of 'findAttackDestinations', more efficiently implemented by calling 'attackDestinationsByCoordinatesByRankByLogicalColour'.-findAttackDestinationsInt :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Piece -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y]-findAttackDestinationsInt coordinates MkPiece {+ -> [Cartesian.Coordinates.Coordinates] -- ^ The destinations which can be attacked.+findAttackDestinations coordinates MkPiece { getLogicalColour = logicalColour, getRank = rank-} = attackDestinationsByCoordinatesByRankByLogicalColour ! logicalColour Data.Map.! rank ! coordinates+} = attackDestinationsByCoordinatesByRankByLogicalColour ! logicalColour Map.! rank ! coordinates -- The constant /direction/s of the straight lines along which each type of /piece/ can attack. @@ -353,7 +323,7 @@ getAttackDirections MkPiece { getLogicalColour = logicalColour, getRank = rank-} = attackDirectionsByRankByLogicalColour ! logicalColour Data.Map.! rank+} = attackDirectionsByRankByLogicalColour ! logicalColour Map.! rank {- | * Whether a /piece/ at the specified /coordinates/ could attack the target at the specified /coordinates/.@@ -365,12 +335,10 @@ * CAVEAT: it won't confirm the ability of a @Pawn@ to advance, since that doesn't constitute an attack. -} canAttackAlong- :: (Enum x, Enum y)- => Cartesian.Coordinates.Coordinates x y -- ^ Source (attacker's location).- -> Cartesian.Coordinates.Coordinates x y -- ^ Destination (victim's location).- -> Piece -- ^ Attacker.+ :: Cartesian.Coordinates.Coordinates -- ^ Source (attacker's location).+ -> Cartesian.Coordinates.Coordinates -- ^ Destination (victim's location).+ -> Piece -- ^ Attacker. -> Bool-{-# SPECIALISE canAttackAlong :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Piece -> Bool #-} canAttackAlong source destination piece = ( case getRank piece of Attribute.Rank.Pawn -> Cartesian.Vector.isPawnAttack $ getLogicalColour piece@@ -380,7 +348,7 @@ Attribute.Rank.Queen -> Cartesian.Vector.isStraight Attribute.Rank.King -> Cartesian.Vector.isKingsMove ) (- Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.VectorInt+ Cartesian.Vector.measureDistance source destination ) {- |@@ -388,16 +356,11 @@ * N.B.: can't detect any blocking pieces. -}-canMoveBetween :: (- Enum x,- Enum y,- Eq y- )- => Cartesian.Coordinates.Coordinates x y -- ^ Source.- -> Cartesian.Coordinates.Coordinates x y -- ^ Destination.+canMoveBetween+ :: Cartesian.Coordinates.Coordinates -- ^ Source.+ -> Cartesian.Coordinates.Coordinates -- ^ Destination. -> Piece -> Bool-{-# SPECIALISE canMoveBetween :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Piece -> Bool #-} canMoveBetween source destination piece = ( case getRank piece of Attribute.Rank.Pawn -> \distance -> let@@ -417,13 +380,12 @@ Attribute.Rank.Queen -> Cartesian.Vector.isStraight Attribute.Rank.King -> Cartesian.Vector.isKingsMove ) (- Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.VectorInt+ Cartesian.Vector.measureDistance source destination ) -- | Whether a move qualifies for @Pawn@-promotion. isPawnPromotion- :: (Enum y, Eq y)- => Cartesian.Coordinates.Coordinates x y -- ^ Destination.+ :: Cartesian.Coordinates.Coordinates -- ^ Destination. -> Piece -> Bool isPawnPromotion destination MkPiece {@@ -488,5 +450,5 @@ listArrayByPiece = Data.Array.IArray.listArray (minBound, maxBound) -- | A /piece/ at specific /coordinates/.-type LocatedPiece x y = (Cartesian.Coordinates.Coordinates x y, Piece)+type LocatedPiece = (Cartesian.Coordinates.Coordinates, Piece)
src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs view
@@ -27,8 +27,6 @@ -- ** Type-synonyms -- PieceSquareValueByNPieces, -- EitherPieceSquareValueByNPiecesByCoordinates,- FindPieceSquareValue,- FindPieceSquareValues, -- ** Data-types PieceSquareByCoordinatesByRank( -- MkPieceSquareByCoordinatesByRank,@@ -39,7 +37,6 @@ gnuPlotComment, -- * Functions findPieceSquareValue,- findPieceSquareValues, interpolatePieceSquareValues, formatForGNUPlot, -- ** Constructor@@ -57,10 +54,9 @@ 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.Length as Type.Length-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 -- | The piece-square value may vary as the game progresses.@@ -74,105 +70,41 @@ ) -- | Self-documentation.-type EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue = Either (- Cartesian.Coordinates.ArrayByCoordinates x y pieceSquareValue -- Uninterpolated.+type EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue = Either (+ Cartesian.Coordinates.ArrayByCoordinates pieceSquareValue -- Uninterpolated. ) (- Cartesian.Coordinates.ArrayByCoordinates x y (PieceSquareValueByNPieces pieceSquareValue) -- Interpolated.+ Cartesian.Coordinates.ArrayByCoordinates (PieceSquareValueByNPieces pieceSquareValue) -- Interpolated. ) -- | The value for each type of /piece/ of occupying each coordinate, at each stage in the lifetime of the game.-newtype PieceSquareByCoordinatesByRank x y pieceSquareValue = MkPieceSquareByCoordinatesByRank {- deconstruct :: Attribute.Rank.ArrayByRank (EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue)+newtype PieceSquareByCoordinatesByRank pieceSquareValue = MkPieceSquareByCoordinatesByRank {+ deconstruct :: Attribute.Rank.ArrayByRank (EitherPieceSquareValueByNPiecesByCoordinates pieceSquareValue) } deriving (Eq, Show) -instance (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (PieceSquareByCoordinatesByRank x y pieceSquareValue) where+instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (PieceSquareByCoordinatesByRank pieceSquareValue) where rnf MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = Control.DeepSeq.rnf byRank -- | Constructor. mkPieceSquareByCoordinatesByRank- :: (Attribute.Rank.Rank -> EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue) -- ^ Convert a /rank/ into either (a /pieceSquareValue/ or a /pieceSquareValue/ which linearly varies with the number of /piece/s remaining) by /coordinates/.- -> PieceSquareByCoordinatesByRank x y pieceSquareValue+ :: (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 mkPieceSquareByCoordinatesByRank = MkPieceSquareByCoordinatesByRank . Attribute.Rank.listArrayByRank . (`map` Property.FixedMembership.members) --- | The type of a function which can find the required piece-square value.-type FindPieceSquareValue x y pieceSquareValue- = Attribute.LogicalColour.LogicalColour -- ^ The /piece/'s /logical colour/.- -> Attribute.Rank.Rank -- ^ The /piece/'s /rank/.- -> Cartesian.Coordinates.Coordinates x y -- ^ The /piece/'s location.- -> pieceSquareValue- -- | 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 :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Type.Count.NPieces -- ^ The progress through the game.+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 x y -- ^ The /piece/'s location.- -> PieceSquareByCoordinatesByRank x y pieceSquareValue+ -> Cartesian.Coordinates.Coordinates -- ^ The /piece/'s location. -> pieceSquareValue-{-# SPECIALISE findPieceSquareValue- :: Type.Count.NPieces- -> Attribute.LogicalColour.LogicalColour- -> Attribute.Rank.Rank- -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y- -> PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue- -> Type.Mass.PieceSquareValue- #-}-findPieceSquareValue nPieces logicalColour rank coordinates MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = (- (!) ||| (- \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !)- ) $ byRank ! rank- ) $ (- if Attribute.LogicalColour.isBlack logicalColour- then Property.Reflectable.reflectOnX- else id- ) coordinates---- | The type of a function which can find the required piece-square values.-type FindPieceSquareValues x y pieceSquareValue- = Attribute.LogicalColour.LogicalColour -- ^ The /piece/'s /logical colour/.- -> Attribute.Rank.Rank -- ^ The /piece/'s /rank/.- -> [Cartesian.Coordinates.Coordinates x y] -- ^ The locations of interest for the /piece/.- -> [pieceSquareValue]---- | Find the piece-square values, at a stage in the game's lifetime defined by the total number of pieces remaining, for the specified /rank/ & list of /coordinates/.-findPieceSquareValues :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => 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 x y] -- ^ The locations of interest for the specified /piece/.- -> PieceSquareByCoordinatesByRank x y pieceSquareValue- -> [pieceSquareValue]-{-# SPECIALISE findPieceSquareValues- :: Type.Count.NPieces- -> Attribute.LogicalColour.LogicalColour- -> Attribute.Rank.Rank- -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y]- -> PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue- -> [Type.Mass.PieceSquareValue]- #-}-findPieceSquareValues nPieces logicalColour rank coordinatesList MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = (+findPieceSquareValue MkPieceSquareByCoordinatesByRank { deconstruct = byRank } nPieces logicalColour rank = ( (!) ||| ( \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !) ) $ byRank ! rank- ) `map` (- if Attribute.LogicalColour.isBlack logicalColour- then map Property.Reflectable.reflectOnX- else id- ) coordinatesList+ ) . if Attribute.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@@ -197,16 +129,11 @@ gnuPlotComment = '#' -- | Format the data for input to __GNUPlot__.-formatForGNUPlot :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => (pieceSquareValue -> ShowS) -- ^ Format a /pieceSquareValue/.+formatForGNUPlot+ :: (pieceSquareValue -> ShowS) -- ^ Format a /pieceSquareValue/. -> ShowS -- ^ The column-delimiter. -> (PieceSquareValueByNPieces pieceSquareValue -> pieceSquareValue) -- ^ Select one /pieceSquareValue/ from interpolated values.- -> PieceSquareByCoordinatesByRank x y pieceSquareValue+ -> PieceSquareByCoordinatesByRank pieceSquareValue -> ShowS formatForGNUPlot pieceSquareValueFormatter columnDelimiter selector MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = ( showsRow (@@ -223,10 +150,10 @@ else id ) . showS ) id . zip (- Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y]+ Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates] ) . Data.List.transpose . map (- Data.Array.IArray.elems ||| map selector {-select one pieceSquareValue from interpolated values-} . Data.Array.IArray.elems {-ByCoordinates-}- ) $ Data.Array.IArray.elems {-ByRank-} byRank where+ Data.Foldable.toList ||| 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
@@ -42,37 +42,30 @@ import qualified Control.DeepSeq -- | A move qualified by its /movetype/.-data QualifiedMove x y = MkQualifiedMove {- getMove :: Component.Move.Move x y,+data QualifiedMove = MkQualifiedMove {+ getMove :: Component.Move.Move, getMoveType :: Attribute.MoveType.MoveType } deriving Eq -instance (Show x, Show y) => Show (QualifiedMove x y) where+instance Show QualifiedMove where showsPrec precedence MkQualifiedMove { getMove = move, getMoveType = moveType } = showsPrec precedence (move, moveType) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Read x,- Read y- ) => Read (QualifiedMove x y) where+instance Read QualifiedMove where readsPrec precedence = map (Control.Arrow.first $ uncurry MkQualifiedMove) . readsPrec precedence -instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (QualifiedMove x y) where+instance Control.DeepSeq.NFData QualifiedMove where rnf MkQualifiedMove { getMove = move, getMoveType = moveType } = Control.DeepSeq.rnf (move, moveType) -instance Enum y => Property.Reflectable.ReflectableOnX (QualifiedMove x y) where+instance Property.Reflectable.ReflectableOnX QualifiedMove where reflectOnX qualifiedMove@MkQualifiedMove { getMove = move } = qualifiedMove { getMove = Property.Reflectable.reflectOnX move } -- | Constructor.-mkQualifiedMove :: Component.Move.Move x y -> Attribute.MoveType.MoveType -> QualifiedMove x y+mkQualifiedMove :: Component.Move.Move -> Attribute.MoveType.MoveType -> QualifiedMove mkQualifiedMove = MkQualifiedMove
src-lib/BishBosh/Component/Turn.hs view
@@ -58,13 +58,13 @@ * Additional data is recorded to facilitate both rollback & recording of the /move/ in various conventional notations. -}-data Turn x y = MkTurn {- getQualifiedMove :: Component.QualifiedMove.QualifiedMove x y,+data Turn = MkTurn {+ getQualifiedMove :: Component.QualifiedMove.QualifiedMove, getRank :: Attribute.Rank.Rank, -- ^ The /rank/ of /piece/ that was moved, prior to any promotion. getIsRepeatableMove :: Bool -- ^ Whether this move can ever recur; without rolling-back. } -instance (Eq x, Eq y) => Eq (Turn x y) where+instance Eq Turn where MkTurn { getQualifiedMove = qualifiedMove, getRank = rank@@ -73,14 +73,14 @@ getRank = rank' } = (qualifiedMove, rank) == (qualifiedMove', rank') -- 'getIsRepeatableMove' can be derived. -instance (Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (Turn x y) where+instance Control.DeepSeq.NFData Turn where rnf MkTurn { getQualifiedMove = qualifiedMove, getRank = rank, getIsRepeatableMove = isRepeatableMove } = Control.DeepSeq.rnf (qualifiedMove, rank, isRepeatableMove) -instance (Show x, Show y) => Show (Turn x y) where+instance Show Turn where showsPrec precedence MkTurn { getQualifiedMove = qualifiedMove, getRank = rank@@ -91,24 +91,17 @@ -- isRepeatableMove -- Derived. ) -- Represent as a tuple. -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Read x,- Read y- ) => Read (Turn x y) where+instance Read Turn where readsPrec precedence = map (Control.Arrow.first $ uncurry mkTurn) . readsPrec precedence -instance Enum y => Property.Reflectable.ReflectableOnX (Turn x y) where+instance Property.Reflectable.ReflectableOnX Turn where reflectOnX turn@MkTurn { getQualifiedMove = qualifiedMove } = turn { getQualifiedMove = Property.Reflectable.reflectOnX qualifiedMove } -- | Smart constructor. mkTurn- :: Component.QualifiedMove.QualifiedMove x y+ :: Component.QualifiedMove.QualifiedMove -> Attribute.Rank.Rank- -> Turn x y+ -> Turn mkTurn qualifiedMove rank = MkTurn { getQualifiedMove = qualifiedMove, getRank = rank,@@ -118,17 +111,13 @@ } -- | Convenience.-isCapture :: Turn x y -> Bool+isCapture :: Turn -> Bool isCapture MkTurn { getQualifiedMove = qualifiedMove } = Attribute.MoveType.isCapture $ Component.QualifiedMove.getMoveType qualifiedMove -- | Whether the /turn/ represents a @Pawn@'s initial two-square advance.-isPawnDoubleAdvance :: (- Enum x,- Enum y,- Eq y- )- => Attribute.LogicalColour.LogicalColour -- Defines the side whose /turn/ is referenced.- -> Turn x y+isPawnDoubleAdvance+ :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side whose /turn/ is referenced.+ -> Turn -> Bool isPawnDoubleAdvance logicalColour MkTurn { getRank = Attribute.Rank.Pawn,@@ -139,8 +128,8 @@ -- | Forwards the request to 'Attribute.Rank.compareByLVA'. compareByLVA :: Attribute.Rank.EvaluateRank- -> Turn x y- -> Turn x y+ -> Turn+ -> Turn -> Ordering compareByLVA evaluateRank MkTurn { getRank = rankL } MkTurn { getRank = rankR } = Attribute.Rank.compareByLVA evaluateRank rankL rankR @@ -155,8 +144,8 @@ -} compareByMVVLVA :: Attribute.Rank.EvaluateRank- -> Turn x y- -> Turn x y+ -> Turn+ -> Turn -> Ordering compareByMVVLVA evaluateRank turnL@MkTurn { getQualifiedMove = qualifiedMoveL
src-lib/BishBosh/Component/Zobrist.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -30,9 +29,6 @@ -} module BishBosh.Component.Zobrist(--- * Type-classes- Hashable1D(..),- Hashable2D(..), -- * Types -- ** Type-synonyms -- Index,@@ -44,15 +40,11 @@ -- getRandomByCastleableRooksXByLogicalColour, -- getRandomByEnPassantAbscissa ),--- * Constants--- combiningOp, -- * Functions -- measureHammingDistances, dereferenceRandomByCoordinatesByRankByLogicalColour, dereferenceRandomByCastleableRooksXByLogicalColour, dereferenceRandomByEnPassantAbscissa,- hash2D,- combine, -- ** Constructors mkZobrist ) where@@ -64,28 +56,28 @@ 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 Control.Exception import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default import qualified Data.Foldable-import qualified Data.List import qualified System.Random import qualified ToolShed.System.Random -- | Used as an index into 'getRandomByCoordinatesByRankByLogicalColour'.-type Index x y = (Attribute.LogicalColour.LogicalColour, Attribute.Rank.Rank, Cartesian.Coordinates.Coordinates x y)+type Index = (Attribute.LogicalColour.LogicalColour, Attribute.Rank.Rank, Cartesian.Coordinates.Coordinates) -- | The random numbers used to generate a hash, which almost uniquely represent a /position/.-data Zobrist x y positionHash = MkZobrist {- getRandomForBlacksMove :: positionHash, -- ^ Defines a random number to apply when the next move is @Black@'s.- getRandomByCoordinatesByRankByLogicalColour :: Data.Array.IArray.Array {-Boxed-} (Index x y) 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'.+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'. - getRandomByCastleableRooksXByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [(x, positionHash)], -- ^ Defines random numbers to represent all combinations of castleable @Rook@s.- getRandomByEnPassantAbscissa :: Cartesian.Abscissa.ArrayByAbscissa x positionHash -- ^ Defines random numbers to represent any file on which capture en-passant might be available.+ 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. } deriving Show -instance Foldable (Zobrist x y) where+instance Foldable Zobrist where foldr f i MkZobrist { getRandomForBlacksMove = randomForBlacksMove, getRandomByCoordinatesByRankByLogicalColour = randomByCoordinatesByRankByLogicalColour,@@ -102,13 +94,9 @@ ) randomByEnPassantAbscissa instance (- Data.Array.IArray.Ix x, Data.Bits.FiniteBits positionHash,- Enum x,- Enum y,- Ord y, System.Random.Random positionHash- ) => Data.Default.Default (Zobrist x y positionHash) where+ ) => Data.Default.Default (Zobrist positionHash) where def = mkZobrist Nothing $ System.Random.mkStdGen 0 {- |@@ -118,7 +106,7 @@ * CAVEAT: <https://en.wikipedia.org/wiki/Linear_independence> a better measure of the suitability of the selected random numbers -}-measureHammingDistances :: Data.Bits.Bits positionHash => Zobrist x y positionHash -> [Int]+measureHammingDistances :: Data.Bits.Bits positionHash => Zobrist positionHash -> [Int] measureHammingDistances = map (Data.Bits.popCount . uncurry Data.Bits.xor) . getCombinations . Data.Foldable.toList where getCombinations :: [a] -> [(a, a)] getCombinations (x : remainder) = map ((,) x) remainder ++ getCombinations remainder -- CAVEAT: O(n^2) time-complexity.@@ -126,17 +114,13 @@ -- | Smart constructor. mkZobrist :: (- Data.Array.IArray.Ix x, Data.Bits.FiniteBits positionHash,- Enum x,- Enum y,- Ord y, System.Random.RandomGen randomGen, System.Random.Random positionHash ) => Maybe Int -- ^ The optional minimum acceptable Hamming-distance between any two of the selected random numbers. -> randomGen- -> Zobrist x y positionHash+ -> Zobrist positionHash mkZobrist maybeMinimumHammingDistance randomGen | Just minimumHammingDistance <- maybeMinimumHammingDistance , let minimumHammingDistance' = minimum $ measureHammingDistances zobrist@@ -163,57 +147,18 @@ } -- | Dereferences 'getRandomByCoordinatesByRankByLogicalColour' using the specified index.-dereferenceRandomByCoordinatesByRankByLogicalColour :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Index x y- -> Zobrist x y positionHash- -> positionHash+dereferenceRandomByCoordinatesByRankByLogicalColour :: Index -> Zobrist positionHash -> positionHash dereferenceRandomByCoordinatesByRankByLogicalColour index MkZobrist { getRandomByCoordinatesByRankByLogicalColour = randomByCoordinatesByRankByLogicalColour } = randomByCoordinatesByRankByLogicalColour ! index -- | Dereferences 'getRandomByCastleableRooksXByLogicalColour' using the specified abscissa. dereferenceRandomByCastleableRooksXByLogicalColour- :: Eq x- => Attribute.LogicalColour.LogicalColour- -> x- -> Zobrist x y positionHash+ :: Attribute.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 -- | Dereferences 'getRandomByEnPassantAbscissa' using the specified abscissa.-dereferenceRandomByEnPassantAbscissa- :: Data.Array.IArray.Ix x- => x- -> Zobrist x y positionHash- -> positionHash+dereferenceRandomByEnPassantAbscissa :: Type.Length.X -> Zobrist positionHash -> positionHash dereferenceRandomByEnPassantAbscissa x MkZobrist { getRandomByEnPassantAbscissa = randomByEnPassantAbscissa } = randomByEnPassantAbscissa ! x---- | An interface to which 1-D hashable data can conform.-class Hashable1D hashable x {-CAVEAT: MultiParamTypeClasses-} where- listRandoms1D :: hashable x -> Zobrist x y positionHash -> [positionHash]---- | An interface to which 2-D hashable data can conform.-class Hashable2D hashable x y {-CAVEAT: MultiParamTypeClasses-} where- listRandoms2D :: hashable x y -> Zobrist x y positionHash -> [positionHash]---- | The operator used when combining random numbers to compose a hash.-combiningOp :: Data.Bits.Bits positionHash => positionHash -> positionHash -> positionHash-combiningOp = Data.Bits.xor---- | Resolve a hashable into a hash.-hash2D :: (- Data.Bits.Bits positionHash,- Hashable2D hashable x y- )- => hashable x y- -> Zobrist x y positionHash- -> positionHash-hash2D hashable = Data.List.foldl1' combiningOp . listRandoms2D hashable---- | Include a list of random numbers in the hash.-combine :: Data.Bits.Bits positionHash => positionHash -> [positionHash] -> positionHash-combine = Data.List.foldl' combiningOp
src-lib/BishBosh/ContextualNotation/PGN.hs view
@@ -68,9 +68,7 @@ parser, -- ** Constructors mkPGN,- mkPGN',--- ** Mutators- setGame+ mkPGN' ) where import Control.Arrow((&&&), (***))@@ -85,7 +83,6 @@ import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour 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 Control.Applicative import qualified Control.Arrow import qualified Control.DeepSeq@@ -93,7 +90,7 @@ import qualified Data.Char import qualified Data.Default import qualified Data.List-import qualified Data.Map+import qualified Data.Map as Map import qualified Data.Maybe import qualified Data.Time.Calendar import qualified Data.Time.Clock@@ -101,11 +98,13 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# else+# error "USE_POLYPARSE invalid"+# endif #else /* Parsec */ import qualified BishBosh.Data.Integral as Data.Integral import qualified Text.ParserCombinators.Parsec as Parsec@@ -196,7 +195,7 @@ * The first six fields are mandatory according to the PGN-specification, though none are used by this application. The seventh mandatory field /Result/ can be derived from 'getGame'. -}-data PGN x y = MkPGN {+data PGN = MkPGN { getMaybeEventName :: Maybe Value, getMaybeSiteName :: Maybe Value, getDay :: Data.Time.Calendar.Day,@@ -204,18 +203,10 @@ getMaybeWhitePlayerName :: Maybe Value, getMaybeBlackPlayerName :: Maybe Value, getIdentificationTagPairs :: [TagPair], -- ^ Arbitrary tagged values.- getGame :: Model.Game.Game x y -- ^ Defines the turn-sequence & the result.+ getGame :: Model.Game.Game -- ^ Defines the turn-sequence & the result. } deriving Eq -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Show (PGN x y) where- {-# SPECIALISE instance Show (PGN Type.Length.X Type.Length.Y) #-}+instance Show PGN where showsPrec _ MkPGN { getMaybeEventName = maybeEventName, getMaybeSiteName = maybeSiteName,@@ -254,10 +245,7 @@ representUnknownTagValue :: Maybe Value -> ShowS representUnknownTagValue = quote . Data.Maybe.maybe (showChar unknownTagValue) showString -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (PGN x y) where+instance Control.DeepSeq.NFData PGN where rnf MkPGN { getIdentificationTagPairs = identificationTagPairs, getGame = game@@ -272,8 +260,8 @@ -> Maybe Value -- ^ Name of White player. -> Maybe Value -- ^ Name of Black player. -> [TagPair] -- ^ Arbitrary tag-pairs.- -> Model.Game.Game x y- -> PGN x y+ -> Model.Game.Game+ -> PGN mkPGN maybeEventName maybeSiteName day maybeRoundName maybeWhitePlayerName maybeBlackPlayerName identificationTagPairs game | any ( (== [unknownTagValue]) . snd {-tag-value-}@@ -304,16 +292,12 @@ ] -- Those tags for which an unknown value is represented by 'unknownTagValue'. ] -- List-comprehension. --- | Mutator.-setGame :: Model.Game.Game x y -> PGN x y -> PGN x y-setGame game pgn = pgn { getGame = game }- -- | Smart constructor. mkPGN' :: [Tag] -- ^ Identify fields used to form a unique composite game-identifier. -> [TagPair] -- ^ The data from which to extract the required values.- -> Model.Game.Game x y- -> PGN x y+ -> Model.Game.Game+ -> PGN mkPGN' identificationTags tagPairs = mkPGN maybeEventName maybeSiteName ( let #ifdef USE_POLYPARSE@@ -325,11 +309,11 @@ in Data.Maybe.maybe ( Control.Exception.throw . Data.Exception.mkSearchFailure . showString "failed to find " $ show dateTag -- N.B.: this will only terminate the application when the date is evaluated. ) (-#if USE_POLYPARSE != 1+# if USE_POLYPARSE != 'L' either ( Control.Exception.throw . Data.Exception.mkParseFailure . showString "failed to parse " . shows dateTag . showString "; " . show ) id .-#endif+# endif fst . Poly.runParser dateParser #else /* Parsec */ dateParser :: Parsec.Parser Data.Time.Calendar.Day@@ -349,7 +333,7 @@ (`elem` identificationTags) . fst {-tag-} ) tagPairs where [maybeEventName, maybeSiteName, maybeDate, maybeRoundName, maybeWhitePlayerName, maybeBlackPlayerName] = map (- `Data.Map.lookup` Data.Map.fromList tagPairs+ `Map.lookup` Map.fromList tagPairs ) [ eventNameTag, siteNameTag,@@ -364,15 +348,7 @@ * This function is only responsible for the line defining the numbered sequence of /move/s represented in SAN. -}-showsMoveText :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> ShowS-{-# SPECIALISE showsMoveText :: Model.Game.Game Type.Length.X Type.Length.Y -> ShowS #-}+showsMoveText :: Model.Game.Game -> ShowS showsMoveText game = foldr (.) ( Data.Maybe.maybe ( showsBlockComment "Game unfinished" . showChar ' ' . showChar inProgressFlag@@ -408,15 +384,7 @@ showsBlockComment = shows . ContextualNotation.PGNComment.BlockComment -- | Shows PGN for the specified /game/, with defaults for other fields.-showsGame :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> IO ShowS-{-# SPECIALISE showsGame :: Model.Game.Game Type.Length.X Type.Length.Y -> IO ShowS #-}+showsGame :: Model.Game.Game -> IO ShowS showsGame game = do utcTime <- Data.Time.Clock.getCurrentTime @@ -495,28 +463,13 @@ #endif -- | Parses a /game/ from PGN move-text.-moveTextParser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )+moveTextParser #ifdef USE_POLYPARSE- => IsStrictlySequential+ :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves- -> Text.Poly.TextParser (Model.Game.Game x y)-{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Text.Poly.TextParser (Model.Game.Game Type.Length.X Type.Length.Y) #-}+ -> Text.Poly.TextParser Model.Game.Game moveTextParser isStrictlySequential validateMoves = let- elementSequenceParser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> Text.Poly.TextParser (Model.Game.Game x y)+ elementSequenceParser :: Model.Game.Game -> Text.Poly.TextParser Model.Game.Game elementSequenceParser game = let expectedMoveNumber :: Type.Count.NMoves expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game@@ -551,19 +504,11 @@ in do game <- fmap (Data.Maybe.fromMaybe Data.Default.def {-game-}) . Control.Applicative.optional $ elementSequenceParser Data.Default.def {-game-} #else /* Parsec */- => IsStrictlySequential+ :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves- -> Parsec.Parser (Model.Game.Game x y)-{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Parsec.Parser (Model.Game.Game Type.Length.X Type.Length.Y) #-}+ -> Parsec.Parser Model.Game.Game moveTextParser isStrictlySequential validateMoves = let- elementSequenceParser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> Parsec.Parser (Model.Game.Game x y)+ elementSequenceParser :: Model.Game.Game -> Parsec.Parser Model.Game.Game elementSequenceParser game = let expectedMoveNumber :: Type.Count.NMoves expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game@@ -603,25 +548,17 @@ * CAVEAT: this function doesn't /produce/ when using either "Parsec" or "Poly.Plain", since it returns 'Either' the appropriate constructor for which may be unknown until the last character is parsed. Equally for these parsers, all data must be strictly evaluated before any data can retrieved. -}-parser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => IsStrictlySequential+parser+ :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -- ^ Identify fields used to form a unique composite game-identifier. #ifdef USE_POLYPARSE- -> Text.Poly.TextParser (PGN x y)-{-# SPECIALISE parser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -> Text.Poly.TextParser (PGN Type.Length.X Type.Length.Y) #-}+ -> Text.Poly.TextParser PGN parser isStrictlySequential validateMoves identificationTags = do tagPairs <- Control.Applicative.many $ tagPairParser <* Control.Applicative.many ContextualNotation.PGNComment.parser- moveText <- moveTextParser' <* Control.Applicative.many ContextualNotation.PGNComment.parser+ game <- moveTextParser' <* Control.Applicative.many ContextualNotation.PGNComment.parser - return {-to Parser-monad-} $ mkPGN' identificationTags (removeUnknownTagValues tagPairs) moveText+ return {-to Parser-monad-} $ mkPGN' identificationTags (removeUnknownTagValues tagPairs) game where tagPairParser :: Text.Poly.TextParser TagPair@@ -643,8 +580,7 @@ return {-to Parser-monad-} (tagName, tagValue) ) #else /* Parsec */- -> Parsec.Parser (PGN x y)-{-# SPECIALISE parser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -> Parsec.Parser (PGN Type.Length.X Type.Length.Y) #-}+ -> Parsec.Parser PGN parser isStrictlySequential validateMoves identificationTags = mkPGN' identificationTags <$> ( removeUnknownTagValues <$> Control.Applicative.many ( tagPairParser <* Control.Applicative.many ContextualNotation.PGNComment.parser
src-lib/BishBosh/ContextualNotation/PGNComment.hs view
@@ -45,11 +45,13 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# else+# error "USE_POLYPARSE invalid"+# endif #else /* Parsec */ import qualified Control.Monad import qualified Text.ParserCombinators.Parsec as Parsec
src-lib/BishBosh/ContextualNotation/PGNDatabase.hs view
@@ -47,7 +47,6 @@ import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Control.Monad import qualified Data.Maybe@@ -58,11 +57,13 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-# else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Control.Arrow import qualified Text.ParserCombinators.Poly.Plain as Poly+# else+# error "USE_POLYPARSE invalid" # endif #else /* Parsec */ import qualified Control.Arrow@@ -71,61 +72,46 @@ #endif -- | Self-documentation.-type PGNDatabase x y = [ContextualNotation.PGN.PGN x y]+type PGNDatabase = [ContextualNotation.PGN.PGN] -- | Parse a PGN-database.-parser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ContextualNotation.PGN.IsStrictlySequential+parser+ :: ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] #ifdef USE_POLYPARSE- -> Text.Poly.TextParser (PGNDatabase x y)-{-# SPECIALISE parser :: ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] -> Text.Poly.TextParser (PGNDatabase Type.Length.X Type.Length.Y) #-}+ -> Text.Poly.TextParser PGNDatabase parser isStrictlySequential validateMoves identificationTags = Poly.manyFinally' parser' $ Text.Poly.spaces >> Poly.eof #else /* Parsec */- -> Parsec.Parser (PGNDatabase x y)-{-# SPECIALISE parser :: ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] -> Parsec.Parser (PGNDatabase Type.Length.X Type.Length.Y) #-}+ -> Parsec.Parser PGNDatabase parser isStrictlySequential validateMoves identificationTags = Parsec.manyTill parser' (Parsec.try $ Parsec.spaces >> Parsec.try Parsec.eof) <?> "PGN-database" #endif where parser' = ContextualNotation.PGN.parser isStrictlySequential validateMoves identificationTags -- | PGNPredicate used to filter the database.-type PGNPredicate x y = ContextualNotation.PGN.PGN x y -> Bool+type PGNPredicate = ContextualNotation.PGN.PGN -> Bool -- | The optional maximum number of games to read. type MaybeMaximumGames = Maybe Type.Count.NGames -- | Parses a PGN-database from the specified string.-parse :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => String -- ^ The name of the specified database.+parse+ :: String -- ^ The name of the specified database. -> ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag]- -> PGNPredicate x y -- ^ Used to filter entries from the database.+ -> PGNPredicate -- ^ Used to filter entries from the database. -> MaybeMaximumGames -- ^ Optional maximum number of games to read from the database (after they've been filtered). -> String -- ^ The database-contents.- -> Either String (PGNDatabase x y)-{-# SPECIALISE parse :: String -> ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] -> PGNPredicate Type.Length.X Type.Length.Y -> MaybeMaximumGames -> String -> Either String (PGNDatabase Type.Length.X Type.Length.Y) #-}+ -> Either String PGNDatabase #ifdef USE_POLYPARSE-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' parse _ isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = Right -- N.B.: the lazy parser throws an exception rather than returning 'Either', because otherwise it can't choose whether to construct with 'Left' or 'Right' until the input has been fully parsed.-# else /* Plain */+# elif USE_POLYPARSE == 'P' parse name isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = Control.Arrow.left (showString "regarding " . shows name . showString ", ")+# else+# error "USE_POLYPARSE invalid" # endif . fst {-discard unparsed data-} . Poly.runParser parser' #else /* Parsec */@@ -140,24 +126,16 @@ type Decompressor = String -- | Reads a PGN-database from the (optionally compressed) file-path & passes it to the parser.-parseIO :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => System.FilePath.FilePath -- ^ The PGN-file's location.+parseIO+ :: System.FilePath.FilePath -- ^ The PGN-file's location. -> Maybe Decompressor -- ^ An Optional executable by which to decompress the PGN-file. -> ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> System.IO.TextEncoding -- ^ The conversion-scheme between byte-sequences & Unicode characters. -> [ContextualNotation.PGN.Tag]- -> PGNPredicate x y -- ^ Used to filter entries from the database.+ -> PGNPredicate -- ^ Used to filter entries from the database. -> MaybeMaximumGames -- ^ Optional maximum number of games to read from the database (after they've been filtered).- -> IO (Either String (PGNDatabase x y))-{-# SPECIALISE parseIO :: System.FilePath.FilePath -> Maybe Decompressor -> ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> System.IO.TextEncoding -> [ContextualNotation.PGN.Tag] -> PGNPredicate Type.Length.X Type.Length.Y -> MaybeMaximumGames -> IO (Either String (PGNDatabase Type.Length.X Type.Length.Y)) #-}+ -> IO (Either String PGNDatabase) parseIO filePath maybeDecompressionCommand isStrictlySequential validateMoves textEncoding identificationTags pgnPredicate maybeMaximumGames = parse filePath isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames `fmap` Data.Maybe.maybe ( System.IO.withFile filePath System.IO.ReadMode $ \fileHandle -> do System.IO.hSetEncoding fileHandle textEncoding
src-lib/BishBosh/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -27,8 +27,13 @@ -- * Types -- ** Type-synonyms -- Tree,- OnymousQualifiedMove,+-- OnymousQualifiedMove, -- FindMatch,+ TryToMatchMoves,+ TryToMatchViaJoiningMove,+ TryToMatchColourFlippedPosition,+ PreferVictories,+ MatchSwitches, -- ** Data-types NodeLabel(), PositionHashQualifiedMoveTree(),@@ -38,6 +43,7 @@ findNextOnymousQualifiedMovesForPosition, -- findNextJoiningOnymousQualifiedMovesFromPosition, findNextOnymousQualifiedMoves,+-- shortListMostVictorious, maybeRandomlySelectOnymousQualifiedMove, -- ** Constructors fromQualifiedMoveForest,@@ -47,6 +53,7 @@ ) where import Control.Arrow((&&&), (***))+import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove@@ -57,64 +64,66 @@ import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.Rule.Result as Rule.Result import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.StateProperty.Censor as StateProperty.Censor+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Control.Exception-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default+import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra import qualified Data.Maybe import qualified Data.Tree-import qualified Factory.Math.Statistics import qualified System.Random import qualified ToolShed.System.Random #ifdef USE_PARALLEL-import qualified Control.DeepSeq import qualified Control.Parallel.Strategies #endif -- | Each label of the tree contains a /Zobrist-hash/ of the current position, augmented (except in the case of the apex-game) by the last /move/ that was played, & any conclusive result.-data NodeLabel x y positionHash = MkNodeLabel {+data NodeLabel positionHash = MkNodeLabel { getPositionHash :: positionHash,- getMaybeQualifiedMoveWithOnymousResult :: Maybe (Component.QualifiedMove.QualifiedMove x y, Maybe ContextualNotation.QualifiedMoveForest.OnymousResult)+ getMaybeQualifiedMoveWithOnymousResult :: Maybe (Component.QualifiedMove.QualifiedMove, Maybe ContextualNotation.QualifiedMoveForest.OnymousResult) } -- | The tree of /qualified move/s.-type Tree x y positionHash = Data.Tree.Tree (NodeLabel x y positionHash)+type Tree positionHash = Data.Tree.Tree (NodeLabel positionHash) -- | Constructor.-data PositionHashQualifiedMoveTree x y positionHash = MkPositionHashQualifiedMoveTree {- getZobrist :: Component.Zobrist.Zobrist x y positionHash, -- ^ Used to hash each position in the tree.- getTree :: Tree x y positionHash,- getMinimumPieces :: Type.Count.NPieces -- ^ The minimum number of /piece/s remaining after the last /move/ in any game defined in the tree.+data PositionHashQualifiedMoveTree positionHash = MkPositionHashQualifiedMoveTree {+ getZobrist :: Component.Zobrist.Zobrist positionHash, -- ^ Used to hash each position in the tree.+ getTree :: Tree positionHash,+ getMinimumPieces :: ! Type.Count.NPieces, -- ^ The minimum number of /piece/s remaining after the last /move/ in any game defined in the tree.+ 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.-fromQualifiedMoveForest :: (- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y,- Show x,- Show y- )+fromQualifiedMoveForest+ :: Data.Bits.Bits positionHash => Bool -- ^ IncrementalEvaluation.- -> Component.Zobrist.Zobrist x y positionHash- -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y- -> PositionHashQualifiedMoveTree x y positionHash-{-# SPECIALISE fromQualifiedMoveForest :: Bool -> Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest Type.Length.X Type.Length.Y -> PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-}+ -> Component.Zobrist.Zobrist positionHash+ -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest+ -> PositionHashQualifiedMoveTree positionHash+{-# SPECIALISE fromQualifiedMoveForest :: Bool -> Component.Zobrist.Zobrist Type.Crypto.PositionHash -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> PositionHashQualifiedMoveTree Type.Crypto.PositionHash #-} fromQualifiedMoveForest incrementalEvaluation zobrist qualifiedMoveForest = MkPositionHashQualifiedMoveTree { getZobrist = zobrist,- getTree = let- initialGame = Data.Default.def- initialPositionHash = Component.Zobrist.hash2D initialGame zobrist- in Data.Tree.Node {+ getTree = tree,+ getMinimumPieces = ContextualNotation.QualifiedMoveForest.findMinimumPieces qualifiedMoveForest,+ getHasAnyVictories = Data.Foldable.any (+ Data.Maybe.maybe False {-no QualifiedMove-} (+ Data.Maybe.maybe False {-no OnymousResult-} (+ not . Rule.Result.isDraw . snd {-Result-}+ ) . snd {-Maybe OnymousResult-}+ ) . getMaybeQualifiedMoveWithOnymousResult+ ) tree+} where+ initialGame = Data.Default.def+ initialPositionHash = StateProperty.Hashable.hash initialGame zobrist+ tree = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel initialPositionHash Nothing, Data.Tree.subForest = map ( if incrementalEvaluation@@ -134,18 +143,16 @@ Data.Tree.rootLabel = label@(qualifiedMove, _), Data.Tree.subForest = qualifiedMoveForest' } = Data.Tree.Node {- Data.Tree.rootLabel = MkNodeLabel (Component.Zobrist.hash2D game' zobrist) $ Just label, -- Hash the game after applying the move.+ Data.Tree.rootLabel = MkNodeLabel (StateProperty.Hashable.hash game' zobrist) $ Just label, -- Hash the game after applying the move. Data.Tree.subForest = map (slave game') qualifiedMoveForest' -- Recurse. } where game' = Model.Game.applyQualifiedMove qualifiedMove game in slave initialGame ) $ ContextualNotation.QualifiedMoveForest.deconstruct qualifiedMoveForest- },- getMinimumPieces = ContextualNotation.QualifiedMoveForest.findMinimumPieces qualifiedMoveForest-}+ } -- | Predicate.-isTerminal :: PositionHashQualifiedMoveTree x y positionHash -> Bool+isTerminal :: PositionHashQualifiedMoveTree positionHash -> Bool isTerminal MkPositionHashQualifiedMoveTree { getTree = Data.Tree.Node { Data.Tree.subForest = [] } } = True isTerminal _ = False @@ -154,14 +161,14 @@ * CAVEAT: a negative result doesn't imply that convergence is possible, since other factors may prevent it. -}-cantConverge :: Model.Game.Game x y -> PositionHashQualifiedMoveTree x y positionHash -> Bool+cantConverge :: Model.Game.Game -> PositionHashQualifiedMoveTree positionHash -> Bool cantConverge game MkPositionHashQualifiedMoveTree { getMinimumPieces = minimumPieces } = State.Board.getNPieces (Model.Game.getBoard game) < minimumPieces -- | A /qualified move/ annotated by the name & ultimate /result/, of each /game/ from which it could have originated.-type OnymousQualifiedMove x y = (Component.QualifiedMove.QualifiedMove x y, [ContextualNotation.QualifiedMoveForest.OnymousResult])+type OnymousQualifiedMove = (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.OnymousResult]) -- | Find the /onymous result/s for all /game/s originating from the specified tree.-onymiseQualifiedMove :: Tree x y positionHash -> OnymousQualifiedMove x y+onymiseQualifiedMove :: Tree positionHash -> OnymousQualifiedMove onymiseQualifiedMove = ( fst {-qualifiedMove-} . head &&& Data.Maybe.mapMaybe snd {-Maybe OnymousResult-} ) . (@@ -171,10 +178,10 @@ ) . Data.Tree.flatten -- | The type of a function used to locate a match in the tree.-type FindMatch x y positionHash = Model.Game.Game x y -> PositionHashQualifiedMoveTree x y positionHash -> [OnymousQualifiedMove x y]+type FindMatch positionHash = Model.Game.Game -> PositionHashQualifiedMoveTree positionHash -> [OnymousQualifiedMove] -- | For any exactly matching /game/ in the tree, return the subsequent /qualifiedMove/s.-findNextOnymousQualifiedMovesForGame :: (Eq x, Eq y) => FindMatch x y positionHash+findNextOnymousQualifiedMovesForGame :: FindMatch positionHash findNextOnymousQualifiedMovesForGame requiredGame = slave ( Model.Game.listTurnsChronologically requiredGame ) . Data.Tree.subForest {-remove the apex which lacks a founding move-} . getTree where@@ -192,59 +199,47 @@ * By matching the /position/ rather than the precise sequence of /move/s, transpositions <https://www.chessprogramming.org/Transposition> can also be identified. + * N.B.: a comparison between the number of pieces in the game we're required to match & the decreasing number of pieces down the tree, permits early termination of the search.+ * CAVEAT: a null list can result from either match-failure, or a match with the final /move/ of a /game/. -}-findNextOnymousQualifiedMovesForPosition :: (- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y- ) => FindMatch x y positionHash-{-# SPECIALISE findNextOnymousQualifiedMovesForPosition :: FindMatch Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-}-findNextOnymousQualifiedMovesForPosition requiredGame positionHashQualifiedMoveTree@MkPositionHashQualifiedMoveTree {- getZobrist = zobrist,- getTree = tree-}- | cantConverge requiredGame positionHashQualifiedMoveTree = [] -- The specified game has fewer pieces than any defined in the tree.- | otherwise = slave (2 * Component.Piece.nPiecesPerSide) tree+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 where- (requiredPositionHash, requiredNPieces) = (`Component.Zobrist.hash2D` zobrist) &&& State.Board.getNPieces . Model.Game.getBoard $ requiredGame+ 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 nPieces Data.Tree.Node {+ slave (nPiecesDiffOpponent, nPiecesDiffMover) Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getPositionHash = positionHash }, Data.Tree.subForest = forest } = (- if positionHash == requiredPositionHash- then (- map onymiseQualifiedMove forest ++ -- The position matches, so one can select any move from the forest.- ) -- Section.- else id+ 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.+ 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. ) $ concatMap ( \node@Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getMaybeQualifiedMoveWithOnymousResult = Just (qualifiedMove, _) }- } -> if Attribute.MoveType.isCapture $ Component.QualifiedMove.getMoveType qualifiedMove- then if nPieces == requiredNPieces- then [] -- Terminate the recursion; no further pieces can be lost if a match is to occur.- else slave (pred nPieces) node -- Recurse.- else slave nPieces node -- Recurse.+ } -> slave (+ nPiecesDiffMover,+ (+ if Attribute.MoveType.isCapture $! Component.QualifiedMove.getMoveType qualifiedMove+ then pred+ else id+ ) nPiecesDiffOpponent+ ) {-swap pair-} node -- Recurse. ) forest -- | Finds any single /move/s which can join the current /position/ with a member of the forest.-findNextJoiningOnymousQualifiedMovesFromPosition :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y,- Show x,- Show y- ) => FindMatch x y positionHash-{-# SPECIALISE findNextJoiningOnymousQualifiedMovesFromPosition :: FindMatch Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-}+findNextJoiningOnymousQualifiedMovesFromPosition :: Data.Bits.Bits positionHash => FindMatch positionHash+{-# SPECIALISE findNextJoiningOnymousQualifiedMovesFromPosition :: FindMatch Type.Crypto.PositionHash #-} findNextJoiningOnymousQualifiedMovesFromPosition game positionHashQualifiedMoveTree | Model.Game.isTerminated game = [] | otherwise = [@@ -260,6 +255,21 @@ ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game ] -- List-comprehension. +-- | Whether to attempt to exactly match moves with a standard opening; transpositions won't be matched.+type TryToMatchMoves = Bool++-- | Whether to attempt to join the current position to a standard opening that's only one ply away.+type TryToMatchViaJoiningMove = Bool++-- | Whether to attempt to match a colour-flipped version of the current position with a standard opening+type TryToMatchColourFlippedPosition = Bool++-- | The switches used to control attempts to find a match amongst standard openings.+type MatchSwitches = (TryToMatchMoves, TryToMatchViaJoiningMove, TryToMatchColourFlippedPosition)++-- | 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+ {- | * Calls 'findNextOnymousQualifiedMovesForGame' to find an exact match for the current /game/ in the tree. @@ -273,22 +283,11 @@ * CAVEAT: the order of these searches has been hard-coded. -}-findNextOnymousQualifiedMoves :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y,- Show x,- Show y- )- => (Bool, Bool, Bool) -- ^ MatchSwitches.- -> FindMatch x y positionHash-{-# SPECIALISE findNextOnymousQualifiedMoves :: (Bool, Bool, Bool) -> FindMatch Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-}+findNextOnymousQualifiedMoves+ :: 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. | otherwise = Data.Maybe.fromMaybe [] . Data.List.find (@@ -311,49 +310,46 @@ ] -- 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.+ -> [OnymousQualifiedMove]+ -> [OnymousQualifiedMove]+shortListMostVictorious nextLogicalColour = last {-highest scoring group-} . Data.List.Extra.groupSortOn (+ Data.List.foldl' (+ \acc -> ($ acc) . Data.Maybe.maybe id {-draw-} (+ \victorsLogicalColour -> if victorsLogicalColour == nextLogicalColour then succ else pred -- Score the result, according to which side we'd like to win.+ ) . Rule.Result.findMaybeVictor . snd {-result-}+ ) (0 :: Int) . snd {-[OnymousResult]-}+ )+ -- | Randomly select a /qualifiedMove/ from matching /position/s in the tree, & supply the names of those archived games from which it originated. maybeRandomlySelectOnymousQualifiedMove :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y,-#endif- Data.Array.IArray.Ix x, Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y,- Show x,- Show y, System.Random.RandomGen randomGen ) => randomGen- -> (Bool, Bool, Bool) -- ^ MatchSwitches.- -> Model.Game.Game x y- -> PositionHashQualifiedMoveTree x y positionHash- -> Maybe (Component.QualifiedMove.QualifiedMove x y, [ContextualNotation.QualifiedMoveForest.Name])+ -> PreferVictories+ -> MatchSwitches+ -> Model.Game.Game+ -> PositionHashQualifiedMoveTree positionHash+ -> Maybe (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.Name]) {-# SPECIALISE maybeRandomlySelectOnymousQualifiedMove :: System.Random.RandomGen randomGen => randomGen- -> (Bool, Bool, Bool)- -> Model.Game.Game Type.Length.X Type.Length.Y- -> PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash- -> Maybe (Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y, [ContextualNotation.QualifiedMoveForest.Name])+ -> PreferVictories+ -> MatchSwitches+ -> Model.Game.Game+ -> PositionHashQualifiedMoveTree Type.Crypto.PositionHash+ -> Maybe (Component.QualifiedMove.QualifiedMove, [ContextualNotation.QualifiedMoveForest.Name]) #-}-maybeRandomlySelectOnymousQualifiedMove randomGen matchSwitches game positionHashQualifiedMoveTree = case findNextOnymousQualifiedMoves matchSwitches game positionHashQualifiedMoveTree of+maybeRandomlySelectOnymousQualifiedMove randomGen preferVictories matchSwitches game positionHashQualifiedMoveTree = case findNextOnymousQualifiedMoves matchSwitches game positionHashQualifiedMoveTree of [] -> Nothing onymousQualifiedMoves -> fmap ( Control.Arrow.second $ Data.List.nub . map fst {-Name-}- ) . ToolShed.System.Random.select randomGen . last {-highest scoring group-} $ Data.List.Extra.groupSortOn (- (- Factory.Math.Statistics.getMean :: [Int] -> Rational- ) . map (- Data.Maybe.maybe 0 {-a draw-} (- \victorsLogicalColour -> (- if victorsLogicalColour == Model.Game.getNextLogicalColour game- then id- else negate- ) 1 {-victory-}- ) . Rule.Result.findMaybeVictor . snd {-result-} -- Score the result, according to which side we'd like to win.- ) . snd {-[OnymousResult]-}+ ) . ToolShed.System.Random.select randomGen $ (+ if preferVictories && getHasAnyVictories positionHashQualifiedMoveTree+ then shortListMostVictorious $ Model.Game.getNextLogicalColour game+ else id ) onymousQualifiedMoves
src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs view
@@ -51,6 +51,7 @@ import Control.Applicative((<|>)) import Control.Arrow((&&&), (***)) import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+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.ContextualNotation.PGN as ContextualNotation.PGN@@ -63,10 +64,8 @@ import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason import qualified BishBosh.Rule.Result as Rule.Result-import qualified BishBosh.State.Board as State.Board 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 Control.Arrow import qualified Data.Default import qualified Data.List@@ -88,7 +87,7 @@ * CAVEAT: since zero moves have been made in the default initial game, the move-tree for the whole game of chess has no apex, so a forest is a more natural structure; though sub-trees can exist. -}-type QualifiedMoveTree x y = Data.Tree.Tree (Component.QualifiedMove.QualifiedMove x y, Maybe OnymousResult)+type QualifiedMoveTree = Data.Tree.Tree (Component.QualifiedMove.QualifiedMove, Maybe OnymousResult) {- | * A representation of a PGN-database, where initial /move/s shared between /game/s are merged into the trunk of a tree from which they each branch.@@ -97,21 +96,21 @@ * Since there are many different initial moves, the structure is a flat-topped /forest/ rather than a single apex /tree/. -}-newtype QualifiedMoveForest x y = MkQualifiedMoveForest {- deconstruct :: [QualifiedMoveTree x y]+newtype QualifiedMoveForest = MkQualifiedMoveForest {+ deconstruct :: [QualifiedMoveTree] } deriving ( Eq, Show -- CAVEAT: required by QuickCheck, but shouldn't actually be called. ) -instance Property.Empty.Empty (QualifiedMoveForest x y) where+instance Property.Empty.Empty QualifiedMoveForest where empty = MkQualifiedMoveForest Property.Empty.empty -instance Property.Null.Null (QualifiedMoveForest x y) where+instance Property.Null.Null QualifiedMoveForest where isNull MkQualifiedMoveForest { deconstruct = [] } = True isNull _ = False -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotation (QualifiedMoveForest x y) where+instance Notation.MoveNotation.ShowNotation QualifiedMoveForest where showsNotation moveNotation MkQualifiedMoveForest { deconstruct = forest } = showString $ Data.RoseTree.drawForest ( \(qualifiedMove, maybeOnymousResult) -> Notation.MoveNotation.showsNotation moveNotation qualifiedMove $ Data.Maybe.maybe id ( \onymousResult -> showChar ' ' . shows onymousResult@@ -136,10 +135,9 @@ -- | Include the specified PGN-database into the /forest/, thus allowing more than one 'ContextualNotation.PGNDatabase.PGNDatabase' to be read. mergePGNDatabase- :: (Eq x, Eq y)- => ContextualNotation.PGNDatabase.PGNDatabase x y- -> QualifiedMoveForest x y- -> QualifiedMoveForest x y+ :: ContextualNotation.PGNDatabase.PGNDatabase+ -> QualifiedMoveForest+ -> QualifiedMoveForest mergePGNDatabase pgnDatabase MkQualifiedMoveForest { deconstruct = initialForest } = MkQualifiedMoveForest $ foldr ( \pgn -> merge ( mkCompositeIdentifier &&& Data.Maybe.maybe (@@ -149,15 +147,14 @@ map Component.Turn.getQualifiedMove . Model.Game.listTurnsChronologically $ ContextualNotation.PGN.getGame pgn -- Extract the list of qualified moves defining this game. ) ) initialForest pgnDatabase where- mkCompositeIdentifier :: ContextualNotation.PGN.PGN x y -> Name+ mkCompositeIdentifier :: ContextualNotation.PGN.PGN -> Name mkCompositeIdentifier = unwords . map snd {-value-} . ContextualNotation.PGN.getIdentificationTagPairs merge- :: (Eq x, Eq y)- => OnymousResult -- ^ The name of this move-sequence, & the result.- -> [Component.QualifiedMove.QualifiedMove x y] -- ^ A chronological sequence of /qualified move/s.- -> [QualifiedMoveTree x y]- -> [QualifiedMoveTree x y]+ :: OnymousResult -- ^ The name of this move-sequence, & the result.+ -> [Component.QualifiedMove.QualifiedMove] -- ^ A chronological sequence of /qualified move/s.+ -> [QualifiedMoveTree]+ -> [QualifiedMoveTree] merge onymousResult qualifiedMoves@(qualifiedMove : remainingQualifiedMoves) forest = case span ( \Data.Tree.Node { Data.Tree.rootLabel = (qualifiedMove', _) } -> Component.QualifiedMove.getMove qualifiedMove /= Component.QualifiedMove.getMove qualifiedMove' ) forest of@@ -175,7 +172,7 @@ _ {-no match-} -> mkLinkedList onymousResult qualifiedMoves : forest merge _ [] forest = forest - mkLinkedList :: OnymousResult -> [Component.QualifiedMove.QualifiedMove x y] -> QualifiedMoveTree x y+ mkLinkedList :: OnymousResult -> [Component.QualifiedMove.QualifiedMove] -> QualifiedMoveTree mkLinkedList onymousResult ~(qualifiedMove : remainingQualifiedMoves) | null remainingQualifiedMoves = Data.Tree.Node { Data.Tree.rootLabel = (qualifiedMove, Just onymousResult),@@ -187,28 +184,32 @@ } -- | Constructor.-fromPGNDatabase :: (Eq x, Eq y) => ContextualNotation.PGNDatabase.PGNDatabase x y -> QualifiedMoveForest x y+fromPGNDatabase :: ContextualNotation.PGNDatabase.PGNDatabase -> QualifiedMoveForest fromPGNDatabase = (`mergePGNDatabase` Property.Empty.empty {-QualifiedMoveForest-}) --- | Find the minimum number of /piece/s in any of the recorded /game/s.-findMinimumPieces :: QualifiedMoveForest x y -> Type.Count.NPieces+{- |+ * Find the minimum total number of /piece/s in any of the recorded /game/s, in order to determining whether a sample game is too small to converge on anything in the tree.++ * CAVEAT: no attempt is made to partition this total by logical colour, because there's no clear concept of the /minimum/ amongst the pairs discovered at each leaf-node.++ * N.B.: one call also measure other monotonically changing quantities (number of Pawns, number of Castleable Rooks, least advanced Pawn), but this is cheap.+-}+findMinimumPieces :: QualifiedMoveForest -> Type.Count.NPieces findMinimumPieces = slave (- State.Board.getNPieces (- Data.Default.def :: State.Board.Board Type.Length.X Type.Length.Y -- CAVEAT: this assumes the game to which the moves in the forest refer.- )+ 2 * Component.Piece.nPiecesPerSide -- CAVEAT: assuming a conventional starting position. ) . deconstruct where slave nPieces [] = nPieces slave nPieces forest = minimum $ map ( \Data.Tree.Node { Data.Tree.rootLabel = (qualifiedMove, _), Data.Tree.subForest = subForest- } -> slave (- Attribute.MoveType.nPiecesMutator (Component.QualifiedMove.getMoveType qualifiedMove) nPieces- ) subForest -- Recurse.+ } -> let+ nPieces' = Attribute.MoveType.nPiecesMutator (Component.QualifiedMove.getMoveType qualifiedMove) nPieces+ in nPieces' `seq` slave nPieces' subForest -- Recurse. ) forest -- | Count the number of /game/s & distinct /positions/.-count :: QualifiedMoveForest x y -> (Type.Count.NGames, Type.Count.NPositions)+count :: QualifiedMoveForest -> (Type.Count.NGames, Type.Count.NPositions) count = slave . deconstruct where slave = Data.List.foldl' ( \(nGames, nPositions) Data.Tree.Node {@@ -230,15 +231,7 @@ * N.B.: to construct a tree from the specified forest, the default initial /game/ is included at the apex. -}-toGameTree :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => QualifiedMoveForest x y -> Model.GameTree.GameTree x y-{-# SPECIALISE toGameTree :: QualifiedMoveForest Type.Length.X Type.Length.Y -> Model.GameTree.GameTree Type.Length.X Type.Length.Y #-}+toGameTree :: QualifiedMoveForest -> Model.GameTree.GameTree toGameTree MkQualifiedMoveForest { deconstruct = qualifiedMoveForest } = Model.GameTree.fromBareGameTree Data.Tree.Node { Data.Tree.rootLabel = initialGame, Data.Tree.subForest = map (slave initialGame) qualifiedMoveForest
src-lib/BishBosh/ContextualNotation/StandardAlgebraic.hs view
@@ -69,13 +69,13 @@ import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Notation.Notation as Notation.Notation import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason import qualified BishBosh.State.Board as State.Board import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Applicative import qualified Control.Exception import qualified Control.Monad@@ -85,11 +85,13 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# else+# error "USE_POLYPARSE invalid"+# endif #else /* Parsec */ import qualified Text.ParserCombinators.Parsec as Parsec import Text.ParserCombinators.Parsec((<?>), (<|>))@@ -137,31 +139,23 @@ moveSuffixAnnotations = "!?" -- | Defines a /move/, to enable i/o in /StandardAlgebraic/-notation.-newtype StandardAlgebraic x y = MkStandardAlgebraic {- getQualifiedMove :: Component.QualifiedMove.QualifiedMove x y+newtype StandardAlgebraic = MkStandardAlgebraic {+ getQualifiedMove :: Component.QualifiedMove.QualifiedMove } deriving (Eq, Show) -- | Constructor.-fromQualifiedMove :: Component.QualifiedMove.QualifiedMove x y -> StandardAlgebraic x y+fromQualifiedMove :: Component.QualifiedMove.QualifiedMove -> StandardAlgebraic fromQualifiedMove = MkStandardAlgebraic -- | Whether en-passant moves are tagged, or implicit. type ExplicitEnPassant = Bool -- | Represent the specified /turn/ in SAN.-showsTurn :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ExplicitEnPassant- -> Component.Turn.Turn x y- -> Model.Game.Game x y -- ^ The /game/ prior to application of the specified /turn/.+showsTurn+ :: ExplicitEnPassant+ -> Component.Turn.Turn+ -> Model.Game.Game -- ^ The /game/ prior to application of the specified /turn/. -> ShowS-{-# SPECIALISE showsTurn :: ExplicitEnPassant -> Component.Turn.Turn Type.Length.X Type.Length.Y -> Model.Game.Game Type.Length.X Type.Length.Y -> ShowS #-} showsTurn explicitEnPassant turn game | Just sourceRank <- fmap Component.Piece.getRank . State.MaybePieceByCoordinates.dereference source $ State.Board.getMaybePieceByCoordinates board = ( if sourceRank == Attribute.Rank.Pawn@@ -205,7 +199,7 @@ else checkFlag else id )- | otherwise = Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.ContextualNotation.StandardAlgebraic.showsTurn:\tno piece exists at " . Notation.PureCoordinate.showsCoordinates source . showString "; " $ Property.ForsythEdwards.showsFEN game "."+ | otherwise = Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.ContextualNotation.StandardAlgebraic.showsTurn:\tno piece exists at " . Notation.Notation.showsCoordinates Notation.PureCoordinate.notation source . showString "; " $ Property.ForsythEdwards.showsFEN game "." where ((source, destination), moveType) = (Component.Move.getSource &&& Component.Move.getDestination) . Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ Component.Turn.getQualifiedMove turn board = Model.Game.getBoard game@@ -218,42 +212,25 @@ showsRank rank = showChar $ fromRank rank showsCapture, showsX, showsY, showsDestination :: ShowS- showsCapture = showChar captureFlag- (showsX, showsY) = Notation.PureCoordinate.encode source- showsDestination = Notation.PureCoordinate.showsCoordinates destination+ showsCapture = showChar captureFlag+ ((showsX, showsY), showsDestination) = (`Notation.Notation.encode` source) &&& (`Notation.Notation.showsCoordinates` destination) $ Notation.PureCoordinate.notation game' = Model.Game.takeTurn turn game -- | Calls 'showsTurn'.-showTurn :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ExplicitEnPassant- -> Component.Turn.Turn x y- -> Model.Game.Game x y -- ^ The /game/ prior to application of the specified /turn/.+showTurn+ :: ExplicitEnPassant+ -> Component.Turn.Turn+ -> Model.Game.Game -- ^ The /game/ prior to application of the specified /turn/. -> String-{-# SPECIALISE showTurn :: ExplicitEnPassant -> Component.Turn.Turn Type.Length.X Type.Length.Y -> Model.Game.Game Type.Length.X Type.Length.Y -> String #-} showTurn explicitEnPassant turn game = showsTurn explicitEnPassant turn game "" -- | A convenience-function, which generates the /turn/ required to call 'showsTurn'.-showsMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ExplicitEnPassant- -> Component.QualifiedMove.QualifiedMove x y- -> Model.Game.Game x y+showsMove+ :: ExplicitEnPassant+ -> Component.QualifiedMove.QualifiedMove+ -> Model.Game.Game -> ShowS-{-# SPECIALISE showsMove :: ExplicitEnPassant -> Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Model.Game.Game Type.Length.X Type.Length.Y -> ShowS #-} showsMove explicitEnPassant qualifiedMove game = showsTurn explicitEnPassant ( Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.ContextualNotation.StandardAlgebraic.showsMove:\tModel.Game.maybeLastTurn failed."@@ -261,31 +238,15 @@ ) game -- | Calls 'showsMove'.-showMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ExplicitEnPassant- -> Component.QualifiedMove.QualifiedMove x y- -> Model.Game.Game x y+showMove+ :: ExplicitEnPassant+ -> Component.QualifiedMove.QualifiedMove+ -> Model.Game.Game -> String-{-# SPECIALISE showMove :: ExplicitEnPassant -> Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Model.Game.Game Type.Length.X Type.Length.Y -> String #-} showMove explicitEnPassant qualifiedMove game = showsMove explicitEnPassant qualifiedMove game "" -- | Applies the specified /move/ to the specified /game/.-movePiece :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => StandardAlgebraic x y -> Model.Game.Transformation x y-{-# SPECIALISE movePiece :: StandardAlgebraic Type.Length.X Type.Length.Y -> Model.Game.Transformation Type.Length.X Type.Length.Y #-}+movePiece :: StandardAlgebraic -> Model.Game.Transformation movePiece MkStandardAlgebraic { getQualifiedMove = qualifiedMove } = Model.Game.applyQualifiedMove qualifiedMove #ifdef USE_POLYPARSE@@ -319,20 +280,12 @@ #endif -- | Parses a /move/ from SAN, & optionally validates it against the specified /game/.-parser :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => ExplicitEnPassant+parser+ :: ExplicitEnPassant -> ValidateMoves- -> Model.Game.Game x y+ -> Model.Game.Game #ifdef USE_POLYPARSE- -> Text.Poly.TextParser (StandardAlgebraic x y)-{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game Type.Length.X Type.Length.Y -> Text.Poly.TextParser (StandardAlgebraic Type.Length.X Type.Length.Y) #-}+ -> Text.Poly.TextParser StandardAlgebraic parser explicitEnPassant validateMoves game = let nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour@@ -482,8 +435,7 @@ then Data.Maybe.maybe (return {-to Parser-monad-} qualifiedMove) (Poly.failBad . showString "failed: ") $ Model.Game.validateQualifiedMove qualifiedMove game else return {-to Parser-monad-} qualifiedMove #else /* Parsec */- -> Parsec.Parser (StandardAlgebraic x y)-{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game Type.Length.X Type.Length.Y -> Parsec.Parser (StandardAlgebraic Type.Length.X Type.Length.Y) #-}+ -> Parsec.Parser StandardAlgebraic parser explicitEnPassant validateMoves game = let nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour
− src-lib/BishBosh/Data/Enum.hs
@@ -1,34 +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 a translation between enumerable types.--}--module BishBosh.Data.Enum(--- * Functions- translate- ) where---- | Translate between enumerable types.-translate :: (Enum a, Enum b) => (Int -> Int) -> a -> b-{-# INLINE translate #-}-translate f = toEnum . f . fromEnum-
src-lib/BishBosh/Data/Foldable.hs view
@@ -27,11 +27,11 @@ ) where import qualified Data.Foldable-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map -- | Returns a unique instance of any item which has been specified more than once. findDuplicates :: (Foldable foldable, Ord a) => foldable a -> [a]-findDuplicates = Data.Map.Strict.keys . Data.Map.Strict.filter (> 1) . Data.Foldable.foldr (- flip (Data.Map.Strict.insertWith $ const succ) (1 :: Int) -- Count instances.- ) Data.Map.Strict.empty+findDuplicates = Map.keys . Map.filter (> 1) . Data.Foldable.foldr (+ flip (Map.insertWith $ const succ) (1 :: Int) -- Count instances.+ ) Map.empty
src-lib/BishBosh/Evaluation/Fitness.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts, ScopedTypeVariables #-}+{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -29,11 +29,11 @@ -} module BishBosh.Evaluation.Fitness(+-- * Types -- * Constants -- maximumDestinations, maximumDefended, -- * Functions--- mkPieceSquareCriterionValue, measurePieceSquareValue, measurePieceSquareValueIncrementally, measureValueOfMaterial,@@ -70,45 +70,35 @@ import qualified BishBosh.State.Board as State.Board import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Monad.Reader import qualified Data.Array.IArray+import qualified Data.Foldable import qualified Data.List-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map import qualified Data.Maybe #ifdef USE_UNBOXED_ARRAYS import qualified Data.Array.Unboxed #endif --- | Construct a criterion-value from a piece-square value.-mkPieceSquareCriterionValue :: Real pieceSquareValue => pieceSquareValue -> Metric.CriterionValue.CriterionValue-mkPieceSquareCriterionValue = fromRational . (- / fromIntegral Component.Piece.nPiecesPerSide- ) . toRational- -- | 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).+ 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- Enum x,- Enum y,- Num pieceSquareValue,- Ord x,- Ord y+ Num pieceSquareValue )- => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue- -> Model.Game.Game x y+ => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+ -> Model.Game.Game -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValue :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue -> Model.Game.Game Type.Length.X Type.Length.Y -> Type.Mass.PieceSquareValue #-}-measurePieceSquareValue pieceSquareByCoordinatesByRank game- | Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game = difference- | otherwise = negate difference -- Represent the piece-square value from Black's perspective.- where- [blacksPieceSquareValue, whitesPieceSquareValue] = Data.Array.IArray.elems . State.Board.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank $ Model.Game.getBoard game- difference = whitesPieceSquareValue - blacksPieceSquareValue+{-# 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+ then id+ else negate -- Represent the piece-square value 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.@@ -119,33 +109,28 @@ -} 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).+ 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- Enum x,- Enum y,- Num pieceSquareValue,- Ord x,- Ord y+ Num pieceSquareValue ) => pieceSquareValue -- ^ The value before the last move was applied, & therefore also from the perspective of the previous player.- -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue- -> Model.Game.Game x y+ -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+ -> Model.Game.Game -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValueIncrementally :: Type.Mass.PieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue -> Model.Game.Game Type.Length.X Type.Length.Y -> Type.Mass.PieceSquareValue #-}+{-# SPECIALISE measurePieceSquareValueIncrementally :: Type.Mass.PieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Mass.PieceSquareValue -> Model.Game.Game -> Type.Mass.PieceSquareValue #-} measurePieceSquareValueIncrementally previousPieceSquareValue pieceSquareByCoordinatesByRank game- | Attribute.MoveType.isQuiet $ Component.QualifiedMove.getMoveType qualifiedMove = let- findPieceSquareValues coordinatesList = Component.PieceSquareByCoordinatesByRank.findPieceSquareValues (- State.Board.getNPieces $ Model.Game.getBoard game -- N.B.: no capture occurred.+ | Attribute.MoveType.isSimple $ Component.QualifiedMove.getMoveType qualifiedMove = let+ findPieceSquareValue = uncurry (+ Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank ) (- Property.Opposable.getOpposite $ Model.Game.getNextLogicalColour game -- The last player to move.+ State.Board.getNPieces {- N.B.: no capture occurred-} . Model.Game.getBoard &&& Property.Opposable.getOpposite . Model.Game.getNextLogicalColour $ game {-the last player to move-} ) ( Component.Turn.getRank turn -- N.B.: no promotion occurred.- ) coordinatesList pieceSquareByCoordinatesByRank-- (destination, source) = Component.Move.getDestination &&& Component.Move.getSource $ Component.QualifiedMove.getMove qualifiedMove- [destinationPieceSquareValue, sourcePiecesquareValue] = findPieceSquareValues [destination, source]- in (destinationPieceSquareValue - sourcePiecesquareValue) - previousPieceSquareValue {-from the previous player's perspective-}- | otherwise = measurePieceSquareValue pieceSquareByCoordinatesByRank game -- N.B.: though Castling, En-passant, & promotion, can also be calculated, the returns don't justify the effort.+ )+ 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. where Just turn = Model.Game.maybeLastTurn game qualifiedMove = Component.Turn.getQualifiedMove turn@@ -154,11 +139,10 @@ measureValueOfMaterial :: Input.RankValues.RankValues -> Type.Mass.RankValue -- ^ Maximum total rank-value.- -> Model.Game.Game x y+ -> Model.Game.Game -> Metric.CriterionValue.CriterionValue--- {-# SPECIALISE measureValueOfMaterial :: Input.RankValues.RankValues -> Type.Mass.RankValue -> Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfMaterial rankValues maximumTotalRankValue game = fromRational . (- / toRational maximumTotalRankValue -- Normalise.+measureValueOfMaterial rankValues maximumTotalRankValue game = realToFrac . (+ / maximumTotalRankValue -- Normalise. ) . ( if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game then id -- White just moved.@@ -166,7 +150,7 @@ ) . Data.List.foldl' ( \acc (rank, nPiecesDifference) -> if nPiecesDifference == 0 then acc -- Avoid calling 'Input.RankValues.findRankValue'.- else acc + toRational (+ else acc + realToFrac ( Input.RankValues.findRankValue rank rankValues ) * fromIntegral nPiecesDifference ) 0 . Data.Array.IArray.assocs . State.Board.getNPiecesDifferenceByRank {-which arbitrarily counts White pieces as positive & Black as negative-} $ Model.Game.getBoard game@@ -191,26 +175,19 @@ This presents a paradox ! -}-measureValueOfMobility :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> Metric.CriterionValue.CriterionValue-{-# SPECIALISE measureValueOfMobility :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfMobility game = fromRational . uncurry (-) . (+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 -- | Measure the arithmetic difference between the potential to /Castle/, on either side.-measureValueOfCastlingPotential :: Model.Game.Game x y -> Metric.CriterionValue.CriterionValue--- {-# SPECIALISE measureValueOfCastlingPotential :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfCastlingPotential game = fromRational . uncurry (-) . (+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 = Data.Maybe.maybe 1 {-have Castled-} ( (/ 2) . fromIntegral . length ) . (@@ -224,15 +201,17 @@ * CAVEAT: this is a negative attribute, so the weighted normalised value shouldn't exceed the reduction due to 'measureValueOfMaterial' resulting from a @Pawn@-sacrifice. -}-measureValueOfDoubledPawns :: Model.Game.Game x y -> Metric.CriterionValue.CriterionValue--- {-# SPECIALISE measureValueOfDoubledPawns :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfDoubledPawns game = fromRational . (- / 6 -- Normalise to [-1 .. 1]; the optimal scenario is all files containing one Pawn; the worst scenario is two files each containing four Pawns, all but one per file of which are counted as doubled.+measureValueOfDoubledPawns :: Model.Game.Game -> Metric.CriterionValue.CriterionValue+measureValueOfDoubledPawns game = realToFrac . (+ / (+ 6 :: Type.Mass.CriterionValue -- Normalise to [-1 .. 1]; the optimal scenario is all files containing one Pawn; the worst scenario is two files each containing four Pawns, all but one per file of which are counted as doubled.+ ) ) . fromIntegral {-NPieces-} . uncurry (-) . ( countDoubledPawns &&& countDoubledPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where+ countDoubledPawns :: Attribute.LogicalColour.LogicalColour -> Type.Count.NPieces countDoubledPawns logicalColour = uncurry (-) . (- Data.Map.Strict.foldl' (+) 0 &&& fromIntegral . Data.Map.Strict.size {-one Pawn can't be considered to be doubled, so substract one Pawn per column-}+ 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 {- |@@ -240,37 +219,34 @@ * CAVEAT: this is a negative attribute, so the weighted normalised value shouldn't exceed the reduction due to 'measureValueOfMaterial' resulting from a @Pawn@-sacrifice. -}-measureValueOfIsolatedPawns :: (Enum x, Ord x) => Model.Game.Game x y -> Metric.CriterionValue.CriterionValue-{-# SPECIALISE measureValueOfIsolatedPawns :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfIsolatedPawns game = fromRational . (- / fromIntegral {-Int-} Cartesian.Abscissa.xLength -- Normalise to [-1 .. 1]; the optimal scenario is eight files each containing one Pawn & the worst scenario is all Pawns isolated (e.g. 4 alternate files of 2, 2 separate files or 4, ...).+measureValueOfIsolatedPawns :: Model.Game.Game -> Metric.CriterionValue.CriterionValue+measureValueOfIsolatedPawns game = realToFrac . (+ / (+ fromIntegral {-X-} Cartesian.Abscissa.xLength :: Type.Mass.CriterionValue -- Normalise to [-1 .. 1]; the optimal scenario is eight files each containing one Pawn & the worst scenario is all Pawns isolated (e.g. 4 alternate files of 2, 2 separate files or 4, ...).+ ) ) . fromIntegral {-NPieces-} . uncurry (-) . ( countIsolatedPawns &&& countIsolatedPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where countIsolatedPawns :: Attribute.LogicalColour.LogicalColour -> Type.Count.NPieces- countIsolatedPawns logicalColour = Data.Map.Strict.foldlWithKey' (- \acc x nPawns -> (- if (`Data.Map.Strict.member` nPawnsByFile) `any` Cartesian.Abscissa.getAdjacents x- then id -- 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.- else (+ nPawns) -- All the Pawns on this file are isolated & thus lack the protection that may be offered by adjacent Pawns.- ) acc+ 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.+ else acc + nPawns -- All the Pawns on this file are isolated & thus lack the protection that may be offered by adjacent Pawns. ) 0 nPawnsByFile where nPawnsByFile = State.Board.getNPawnsByFileByLogicalColour (Model.Game.getBoard game) ! logicalColour -- | Measure the arithmetic difference between the number of /passed/ @Pawn@s on either side; <https://www.chessprogramming.org/Passed_Pawn>.-measureValueOfPassedPawns :: forall x y. Enum y => Model.Game.Game x y -> Metric.CriterionValue.CriterionValue-{-# SPECIALISE measureValueOfPassedPawns :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfPassedPawns game = fromRational . (- / fromIntegral {-Int-} Cartesian.Abscissa.xLength -- Normalise to [-1 .. 1].+measureValueOfPassedPawns :: Model.Game.Game -> Metric.CriterionValue.CriterionValue+measureValueOfPassedPawns game = realToFrac . (+ / fromIntegral {-X-} Cartesian.Abscissa.xLength -- Normalise to [-1 .. 1]; the optimal scenario is all files containing exactly one Pawn, of one's own logical colour, on the 7th rank. ) . uncurry (-) . ( valuePassedPawns . Property.Opposable.getOpposite {-recent mover-} &&& valuePassedPawns ) $ Model.Game.getNextLogicalColour game where+ valuePassedPawns :: Attribute.LogicalColour.LogicalColour -> Type.Mass.CriterionValue valuePassedPawns logicalColour = Data.List.foldl' (- \acc -> (acc +) . recip {-value increases exponentially as distance to promotion decreases-} . fromIntegral {-Int-} . abs . subtract (- fromEnum (- Cartesian.Ordinate.lastRank logicalColour :: y -- N.B.: ScopedTypeVariables.- )- ) . fromEnum . Cartesian.Coordinates.getY -- Measure the distance to promotion.+ \acc -> (acc +) . recip {-value increases exponentially as distance to promotion decreases-} . fromIntegral . abs . subtract (+ Cartesian.Ordinate.lastRank logicalColour+ ) . Cartesian.Coordinates.getY -- Measure the distance to promotion. ) 0 $ State.Board.getPassedPawnCoordinatesByLogicalColour (Model.Game.getBoard game) ! logicalColour {- |@@ -301,10 +277,11 @@ * CAVEAT: this criterion competes with /mobility/, since each defended /piece/ blocks the path of the defender. -}-measureValueOfDefence :: Model.Game.Game x y -> Metric.CriterionValue.CriterionValue--- {-# SPECIALISE measureValueOfDefence :: Model.Game.Game Type.Length.X Type.Length.Y -> Metric.CriterionValue.CriterionValue #-}-measureValueOfDefence game = fromRational . (- / fromIntegral {-NPieces-} maximumDefended -- Normalise.+measureValueOfDefence :: Model.Game.Game -> Metric.CriterionValue.CriterionValue+measureValueOfDefence game = realToFrac . (+ / (+ fromIntegral {-NPieces-} maximumDefended :: Type.Mass.CriterionValue -- Normalise.+ ) ) . fromIntegral {-NPieces-} . uncurry (-) . ( (! Property.Opposable.getOpposite {-recent mover-} nextLogicalColour) &&& (! nextLogicalColour) ) . State.Board.summariseNDefendersByLogicalColour $ Model.Game.getBoard game where@@ -323,21 +300,15 @@ -} 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).+ 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- Enum x,- Enum y,- Fractional pieceSquareValue,- Ord x,- Ord y,- Real pieceSquareValue,- Show x,- Show y+ Fractional pieceSquareValue,+ Real pieceSquareValue ) => Maybe pieceSquareValue -- ^ An optional value for the specified game.- -> Model.Game.Game x y- -> Input.EvaluationOptions.Reader pieceSquareValue x y Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues-{-# SPECIALISE evaluateFitness :: Maybe Type.Mass.PieceSquareValue -> Model.Game.Game Type.Length.X Type.Length.Y -> Input.EvaluationOptions.Reader Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues #-}+ -> 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 ( if Rule.GameTerminationReason.isCheckMate gameTerminationReason@@ -354,9 +325,9 @@ ) ( measureValueOfMobility game ) (- Data.Maybe.maybe 0 mkPieceSquareCriterionValue $ maybePieceSquareValue <|> fmap (- `measurePieceSquareValue` game- ) maybePieceSquareByCoordinatesByRank+ Data.Maybe.maybe 0 (+ realToFrac . (/ fromIntegral Component.Piece.nPiecesPerSide)+ ) $ maybePieceSquareValue <|> fmap (`measurePieceSquareValue` game) maybePieceSquareByCoordinatesByRank ) ( measureValueOfCastlingPotential game ) (
src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -81,12 +81,11 @@ import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Arboreal as Property.Arboreal 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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.Monad.Reader-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Maybe import qualified Data.Tree@@ -96,43 +95,43 @@ #endif -- | Define a node in the tree to contain the hash of a /game/ & an evaluation of the fitness of that /game/.-data NodeLabel x y positionHash = MkNodeLabel {+data NodeLabel positionHash = MkNodeLabel { getPositionHash :: positionHash, -- ^ The hash of the /game/ contained in 'getQuantifiedGame'.- getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y+ getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame } deriving (Eq, Show) -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (NodeLabel x y positionHash) where+instance Notation.MoveNotation.ShowNotationFloat (NodeLabel positionHash) where showsNotationFloat moveNotation showsDouble MkNodeLabel { getQuantifiedGame = quantifiedGame } = Notation.MoveNotation.showsNotation moveNotation ( Evaluation.QuantifiedGame.getLastTurn quantifiedGame ) . showString "\t=> " . showsDouble ( realToFrac . Metric.WeightedMeanAndCriterionValues.getWeightedMean $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) -instance Property.Null.Null (NodeLabel x y positionHash) where+instance Property.Null.Null (NodeLabel positionHash) where isNull MkNodeLabel { getQuantifiedGame = quantifiedGame } = Property.Null.isNull quantifiedGame -- | Whether the last qualifiedMove of the /game/ in a node, matches a specified /QualifiedMove/.-equalsLastQualifiedMove :: (Eq x, Eq y) => Component.QualifiedMove.QualifiedMove x y -> Data.RoseTree.IsMatch (NodeLabel x y positionHash)+equalsLastQualifiedMove :: Component.QualifiedMove.QualifiedMove -> Data.RoseTree.IsMatch (NodeLabel positionHash) equalsLastQualifiedMove qualifiedMove MkNodeLabel { getQuantifiedGame = quantifiedGame } = (== qualifiedMove) . Component.Turn.getQualifiedMove $ Evaluation.QuantifiedGame.getLastTurn quantifiedGame -- | The tree resulting from each possible move-choice applied to a /game/, including a position-hash & an evaluation of the resulting fitness.-type BarePositionHashQuantifiedGameTree x y positionHash = Data.Tree.Tree (NodeLabel x y positionHash)+type BarePositionHashQuantifiedGameTree positionHash = Data.Tree.Tree (NodeLabel positionHash) -- | Accessor.-getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash -> Evaluation.QuantifiedGame.QuantifiedGame x y+getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree positionHash -> Evaluation.QuantifiedGame.QuantifiedGame getRootQuantifiedGame' Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getQuantifiedGame = quantifiedGame } } = quantifiedGame -- | Wrap the bare tree.-newtype PositionHashQuantifiedGameTree x y positionHash = MkPositionHashQuantifiedGameTree {- deconstruct :: BarePositionHashQuantifiedGameTree x y positionHash+newtype PositionHashQuantifiedGameTree positionHash = MkPositionHashQuantifiedGameTree {+ deconstruct :: BarePositionHashQuantifiedGameTree positionHash } deriving Eq -instance Property.Arboreal.Prunable (PositionHashQuantifiedGameTree x y positionHash) where+instance Property.Arboreal.Prunable (PositionHashQuantifiedGameTree positionHash) where prune depth MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree $ Property.Arboreal.prune depth barePositionHashQuantifiedGameTree -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (PositionHashQuantifiedGameTree x y positionHash) where+instance Notation.MoveNotation.ShowNotationFloat (PositionHashQuantifiedGameTree positionHash) where showsNotationFloat moveNotation showsDouble MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = showString $ ( if Property.Null.isNull . Data.Tree.rootLabel $ barePositionHashQuantifiedGameTree then Data.RoseTree.drawForest toString . Data.Tree.subForest@@ -141,41 +140,36 @@ toString nodeLabel = Notation.MoveNotation.showsNotationFloat moveNotation showsDouble nodeLabel "" -- | Constructor.-fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash+fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash fromBarePositionHashQuantifiedGameTree = MkPositionHashQuantifiedGameTree -- | Constructor. mkPositionHashQuantifiedGameTree :: (- Data.Array.IArray.Ix x, #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).+ 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,- Integral x,- Integral y,- Real pieceSquareValue,- Show x,- Show y+ Data.Bits.Bits positionHash,+ Fractional pieceSquareValue,+ Real pieceSquareValue )- => Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y+ => Input.EvaluationOptions.EvaluationOptions pieceSquareValue -> Input.SearchOptions.SearchOptions- -> Component.Zobrist.Zobrist x y positionHash- -> Model.GameTree.MoveFrequency x y- -> Model.Game.Game x y -- ^ The current state of the /game/.- -> PositionHashQuantifiedGameTree x y positionHash+ -> 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 Type.Length.X Type.Length.Y+ :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue -> Input.SearchOptions.SearchOptions- -> Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash- -> Model.GameTree.MoveFrequency Type.Length.X Type.Length.Y- -> Model.Game.Game Type.Length.X Type.Length.Y- -> PositionHashQuantifiedGameTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ -> Component.Zobrist.Zobrist Type.Crypto.PositionHash+ -> Model.GameTree.MoveFrequency+ -> Model.Game.Game+ -> PositionHashQuantifiedGameTree Type.Crypto.PositionHash #-} mkPositionHashQuantifiedGameTree evaluationOptions searchOptions zobrist moveFrequency seedGame = MkPositionHashQuantifiedGameTree ( if Input.EvaluationOptions.getIncrementalEvaluation evaluationOptions then let- apexPositionHash = Component.Zobrist.hash2D seedGame zobrist+ apexPositionHash = StateProperty.Hashable.hash seedGame zobrist in Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel apexPositionHash $ Control.Monad.Reader.runReader ( Evaluation.QuantifiedGame.fromGame Nothing seedGame@@ -215,7 +209,7 @@ } else fmap ( uncurry MkNodeLabel . (- (`Component.Zobrist.hash2D` zobrist) &&& (`Control.Monad.Reader.runReader` evaluationOptions) . Evaluation.QuantifiedGame.fromGame Nothing+ (`StateProperty.Hashable.hash` zobrist) &&& (`Control.Monad.Reader.runReader` evaluationOptions) . Evaluation.QuantifiedGame.fromGame Nothing ) ) bareGameTree ) where@@ -226,7 +220,7 @@ ) moveFrequency $ Model.GameTree.fromGame seedGame -- | Accessor.-getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash -> positionHash+getRootPositionHash :: PositionHashQuantifiedGameTree positionHash -> positionHash getRootPositionHash MkPositionHashQuantifiedGameTree { deconstruct = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getPositionHash = positionHash }@@ -234,7 +228,7 @@ } = positionHash -- | Accessor.-getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash -> Evaluation.QuantifiedGame.QuantifiedGame x y+getRootQuantifiedGame :: PositionHashQuantifiedGameTree positionHash -> Evaluation.QuantifiedGame.QuantifiedGame getRootQuantifiedGame MkPositionHashQuantifiedGameTree { deconstruct = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getQuantifiedGame = quantifiedGame }@@ -243,29 +237,28 @@ -- | Forward request. reduce- :: Data.RoseTree.IsMatch (NodeLabel x y positionHash)- -> PositionHashQuantifiedGameTree x y positionHash- -> Maybe (PositionHashQuantifiedGameTree x y positionHash)+ :: Data.RoseTree.IsMatch (NodeLabel positionHash)+ -> PositionHashQuantifiedGameTree positionHash+ -> Maybe (PositionHashQuantifiedGameTree positionHash) reduce isMatch MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree `fmap` Data.RoseTree.reduce isMatch barePositionHashQuantifiedGameTree -- | Forward request. traceRoute- :: (Component.Turn.Turn x y -> Data.RoseTree.IsMatch (NodeLabel x y positionHash))- -> PositionHashQuantifiedGameTree x y positionHash- -> [Component.Turn.Turn x y]- -> Maybe [NodeLabel x y positionHash]+ :: (Component.Turn.Turn -> Data.RoseTree.IsMatch (NodeLabel positionHash))+ -> PositionHashQuantifiedGameTree positionHash+ -> [Component.Turn.Turn]+ -> Maybe [NodeLabel positionHash] traceRoute isMatch MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = Data.RoseTree.traceRoute isMatch barePositionHashQuantifiedGameTree -- | Follow the specified move-sequence down the /positionHashQuantifiedGameTree/. traceMatchingMoves- :: (Eq x, Eq y)- => PositionHashQuantifiedGameTree x y positionHash- -> [Component.QualifiedMove.QualifiedMove x y]- -> Maybe [NodeLabel x y positionHash] -- ^ Returns 'Nothing', on failure to match a move.+ :: PositionHashQuantifiedGameTree positionHash+ -> [Component.QualifiedMove.QualifiedMove]+ -> Maybe [NodeLabel positionHash] -- ^ Returns 'Nothing', on failure to match a move. traceMatchingMoves MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = Data.RoseTree.traceRoute equalsLastQualifiedMove barePositionHashQuantifiedGameTree -- | Amend the apex-game to reflect the resignation of the next player.-resign :: PositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash+resign :: PositionHashQuantifiedGameTree positionHash -> PositionHashQuantifiedGameTree positionHash resign MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree@Data.Tree.Node { Data.Tree.rootLabel = nodeLabel@MkNodeLabel { getQuantifiedGame = quantifiedGame }@@ -277,7 +270,7 @@ } -- | Self-documentation.-type Forest x y positionHash = [BarePositionHashQuantifiedGameTree x y positionHash]+type Forest positionHash = [BarePositionHashQuantifiedGameTree positionHash] {- | * Promotes the first matching /move/ to the head of the forest, then descends & recursively promotes the next matching move in the sub-forest.@@ -285,10 +278,9 @@ * N.B.: this can be used to dynamically re-order the forest when a transposition is detected. -} promoteMatchingMoves- :: (Eq x, Eq y)- => [Component.QualifiedMove.QualifiedMove x y] -- ^ The list of qualifiedMoves, which should be promoted at successively deeper levels in the tree.- -> Forest x y positionHash- -> Maybe (Forest x y positionHash) -- ^ Returns 'Nothing' on failure to match a move.+ :: [Component.QualifiedMove.QualifiedMove] -- ^ 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 {- |@@ -297,9 +289,9 @@ * N.B.: this can be used to dynamically re-order the forest using the killer heuristic. -} sortNonCaptureMoves- :: (Forest x y positionHash -> Forest x y positionHash)- -> Forest x y positionHash- -> Forest x y positionHash+ :: (Forest positionHash -> Forest positionHash)+ -> Forest positionHash+ -> Forest positionHash sortNonCaptureMoves sortForest = uncurry (++) . Control.Arrow.second sortForest . span ( Component.Turn.isCapture . Evaluation.QuantifiedGame.getLastTurn . getRootQuantifiedGame' -- Shield any capture-moves, which were previously advanced by static sorting, from the sort. )
src-lib/BishBosh/Evaluation/QuantifiedGame.hs view
@@ -65,7 +65,6 @@ import qualified BishBosh.Property.Null as Property.Null 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.Type.Mass as Type.Mass import qualified Control.DeepSeq import qualified Control.Exception@@ -77,50 +76,43 @@ #endif -- | The selected /game/ & the criteria against which it was quantified.-data QuantifiedGame x y = MkQuantifiedGame {- getGame :: Model.Game.Game x y, -- ^ The /game/ resulting from a sequence of /turn/s.+data QuantifiedGame = MkQuantifiedGame {+ getGame :: Model.Game.Game, -- ^ The /game/ resulting from a sequence of /turn/s. getWeightedMeanAndCriterionValues :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues } deriving (Eq, Show) -instance Control.DeepSeq.NFData (QuantifiedGame x y) where+instance Control.DeepSeq.NFData QuantifiedGame where rnf MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Control.DeepSeq.rnf weightedMeanAndCriterionValues -- The other field is a prerequisite. -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (QuantifiedGame x y) where+instance Notation.MoveNotation.ShowNotationFloat QuantifiedGame where showsNotationFloat moveNotation showsDouble quantifiedGame = Text.ShowList.showsAssociationList Text.ShowList.showsSeparator $ map ($ quantifiedGame) [ (,) Component.Move.tag . Notation.MoveNotation.showsNotation moveNotation . getLastTurn, (,) Metric.WeightedMeanAndCriterionValues.weightedMeanTag . showsDouble . realToFrac . getFitness, (,) Metric.WeightedMeanAndCriterionValues.criterionValuesTag . Text.ShowList.showsFormattedList' (showsDouble . realToFrac) . Metric.WeightedMeanAndCriterionValues.getCriterionValues . getWeightedMeanAndCriterionValues ] -instance Property.Null.Null (QuantifiedGame x y) where+instance Property.Null.Null QuantifiedGame where isNull MkQuantifiedGame { getGame = game } = Property.Null.isNull game -- | Accessor.-getFitness :: QuantifiedGame x y -> Type.Mass.WeightedMean+getFitness :: QuantifiedGame -> Type.Mass.WeightedMean getFitness MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Metric.WeightedMeanAndCriterionValues.getWeightedMean weightedMeanAndCriterionValues -- | 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).+ 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- Enum x,- Enum y,- Fractional pieceSquareValue,- Ord x,- Ord y,- Real pieceSquareValue,- Show x,- Show y+ Fractional pieceSquareValue,+ Real pieceSquareValue ) => Maybe pieceSquareValue -- ^ The value for the specified game.- -> Model.Game.Game x y -- ^ The current state of the /game/.- -> Input.EvaluationOptions.Reader pieceSquareValue x y (QuantifiedGame x y)-{-# SPECIALISE fromGame :: Maybe Type.Mass.PieceSquareValue -> Model.Game.Game Type.Length.X Type.Length.Y -> Input.EvaluationOptions.Reader Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y (QuantifiedGame Type.Length.X Type.Length.Y) #-}+ -> 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 -- | Retrieve the /turn/ used to generate the selected /game/.-getLastTurn :: QuantifiedGame x y -> Component.Turn.Turn x y+getLastTurn :: QuantifiedGame -> Component.Turn.Turn getLastTurn MkQuantifiedGame { getGame = game } = Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.Evaluation.QuantifiedGame.getLastTurn:\tzero turns have been made." ) $ Model.Game.maybeLastTurn game@@ -128,16 +120,16 @@ -- | Drop the specified number of plies from the start of the chronological sequence, leaving the most recent. getLatestTurns :: Type.Count.NPlies -- ^ The number of plies to drop from the start of the chronological sequence.- -> QuantifiedGame x y- -> [Component.Turn.Turn x y]+ -> QuantifiedGame+ -> [Component.Turn.Turn] getLatestTurns nPlies MkQuantifiedGame { getGame = game } = fromIntegral nPlies `drop` Model.Game.listTurnsChronologically game -- | Represent the /fitness/ of the /game/ resulting from a future /move/ by the opponent, from the perspective of the current player.-negateFitness :: QuantifiedGame x y -> QuantifiedGame x y+negateFitness :: QuantifiedGame -> QuantifiedGame negateFitness quantifiedGame@MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = quantifiedGame { getWeightedMeanAndCriterionValues = Metric.WeightedMeanAndCriterionValues.negateWeightedMean weightedMeanAndCriterionValues } -- | Compares fitness.-compareFitness :: QuantifiedGame x y -> QuantifiedGame x y -> Ordering+compareFitness :: QuantifiedGame -> QuantifiedGame -> Ordering compareFitness = Data.Ord.comparing getFitness {- |@@ -145,13 +137,13 @@ * N.B.: 'Nothing' is interpreted as unbounded. -}-type OpenInterval x y = (Maybe (QuantifiedGame x y), Maybe (QuantifiedGame x y))+type OpenInterval = (Maybe QuantifiedGame, Maybe QuantifiedGame) -- | Constant.-unboundedInterval :: OpenInterval x y+unboundedInterval :: OpenInterval unboundedInterval = (Nothing, Nothing) -- | Reflect the interval about zero.-negateInterval :: OpenInterval x y -> OpenInterval x y+negateInterval :: OpenInterval -> OpenInterval negateInterval (maybeAlpha, maybeBeta) = ($ maybeBeta) &&& ($ maybeAlpha) $ fmap negateFitness
src-lib/BishBosh/Input/CriteriaWeights.hs view
@@ -48,11 +48,9 @@ -- weightOfDoubledPawnsTag, -- weightOfIsolatedPawnsTag, -- weightOfPassedPawnsTag,--- onymousOperators, -- * Functions calculateWeightedMean, normalise,--- perturbWeights, -- ** Constructor mkCriteriaWeights ) where@@ -63,12 +61,10 @@ import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Default-import qualified System.Random import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify the XML.@@ -320,81 +316,4 @@ weightOfPassedPawns ] ) -- Section.--{- |- * Independently perturbs each /criterion-weight/ by a random value, of configurable magnitude.-- * Under this transformation, /criterion-weight/s of @0@, will remain unchanged, thus irrelevant criteria remain irrelevant.--}-perturbWeights- :: System.Random.RandomGen randomGen- => randomGen- -> Type.Mass.CriterionWeight -- ^ Change-magnitude.- -> Transformation-perturbWeights _ 0 criteriaWeights = criteriaWeights-perturbWeights randomGen changeMagnitude MkCriteriaWeights {- getWeightOfMaterial = weightOfMaterial,- getWeightOfMobility = weightOfMobility,- getWeightOfPieceSquareValue = weightOfPieceSquareValue,- getWeightOfCastlingPotential = weightOfCastlingPotential,- getWeightOfDefence = weightOfDefence,- getWeightOfDoubledPawns = weightOfDoubledPawns,- getWeightOfIsolatedPawns = weightOfIsolatedPawns,- getWeightOfPassedPawns = weightOfPassedPawns-} = Control.Exception.assert (changeMagnitude > 0) $ normalise MkCriteriaWeights {- getWeightOfMaterial = reduceBy a weightOfMaterial,- getWeightOfMobility = reduceBy b weightOfMobility,- getWeightOfPieceSquareValue = reduceBy c weightOfPieceSquareValue,- getWeightOfCastlingPotential = reduceBy d weightOfCastlingPotential,- getWeightOfDefence = reduceBy e weightOfDefence,- getWeightOfDoubledPawns = reduceBy f weightOfDoubledPawns,- getWeightOfIsolatedPawns = reduceBy g weightOfIsolatedPawns,- getWeightOfPassedPawns = reduceBy h weightOfPassedPawns-} where- (a : b : c : d : e : f : g : h : _) = System.Random.randomRs (1, succ changeMagnitude) randomGen- reduceBy randomValue = (/ realToFrac randomValue) -- N.B. this always reduces the weight, leaving 'normalise' to correct this.---- | A constant list of named accessors & mutators.-onymousOperators :: [- (- String, -- Tag.- CriteriaWeights -> Metric.CriterionWeight.CriterionWeight, -- Accessor.- Metric.CriterionWeight.CriterionWeight -> Transformation -- Mutator.- ) -- Triple.- ]-onymousOperators = [- (- weightOfMaterialTag,- getWeightOfMaterial,- \w criteriaWeights -> criteriaWeights { getWeightOfMaterial = w }- ), (- weightOfMobilityTag,- getWeightOfMobility,- \w criteriaWeights -> criteriaWeights { getWeightOfMobility = w }- ), (- weightOfPieceSquareValueTag,- getWeightOfPieceSquareValue,- \w criteriaWeights -> criteriaWeights { getWeightOfPieceSquareValue = w }- ), (- weightOfCastlingPotentialTag,- getWeightOfCastlingPotential,- \w criteriaWeights -> criteriaWeights { getWeightOfCastlingPotential = w }- ), (- weightOfDefenceTag,- getWeightOfDefence,- \w criteriaWeights -> criteriaWeights { getWeightOfDefence = w }- ), (- weightOfDoubledPawnsTag,- getWeightOfDoubledPawns,- \w criteriaWeights -> criteriaWeights { getWeightOfDoubledPawns = w }- ), (- weightOfIsolatedPawnsTag,- getWeightOfIsolatedPawns,- \w criteriaWeights -> criteriaWeights { getWeightOfIsolatedPawns = w }- ), (- weightOfPassedPawnsTag,- getWeightOfPassedPawns,- \w criteriaWeights -> criteriaWeights { getWeightOfPassedPawns = w }- )- ]
src-lib/BishBosh/Input/EvaluationOptions.hs view
@@ -69,10 +69,9 @@ 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-import qualified Data.Set import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify XML.@@ -95,25 +94,21 @@ type IncrementalEvaluation = Bool -- | A pair of piece-square tables representing the opening & end-games respectively.-type PieceSquareTablePair x y pieceSquareValue = (Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue, Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue)+type PieceSquareTablePair pieceSquareValue = (Input.PieceSquareTable.PieceSquareTable pieceSquareValue, Input.PieceSquareTable.PieceSquareTable pieceSquareValue) -- | Defines the options related to the automatic selection of /move/s.-data EvaluationOptions pieceSquareValue x y = MkEvaluationOptions {+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 x y pieceSquareValue), -- ^ A optional pair of piece-square tables representing the opening & end-games respectively.+ getMaybePieceSquareTablePair :: Maybe (PieceSquareTablePair pieceSquareValue), -- ^ A optional pair of piece-square tables representing the opening & end-games respectively. getMaybePieceSquareByCoordinatesByRank :: Maybe (- Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue+ Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue ) -- ^ 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 x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (EvaluationOptions pieceSquareValue x y) where+instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (EvaluationOptions pieceSquareValue) where rnf MkEvaluationOptions { -- getRankValues = rankValues, getMaximumTotalRankValue = maximumTotalValue,@@ -123,14 +118,7 @@ getMaybePieceSquareByCoordinatesByRank = maybePieceSquareByCoordinatesByRank } = Control.DeepSeq.rnf (maximumTotalValue, criteriaWeights, incrementalEvaluation, maybePieceSquareByCoordinatesByRank) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Real pieceSquareValue,- Show pieceSquareValue- ) => Property.ShowFloat.ShowFloat (EvaluationOptions pieceSquareValue x y) where+instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (EvaluationOptions pieceSquareValue) where showsFloat fromDouble MkEvaluationOptions { getRankValues = rankValues, -- getMaximumTotalRankValue = maximumTotalValue,@@ -158,7 +146,7 @@ ] ) maybePieceSquareTablePair -instance Data.Default.Default (EvaluationOptions pieceSquareValue x y) where+instance Data.Default.Default (EvaluationOptions pieceSquareValue) where def = MkEvaluationOptions { getRankValues = rankValues, getMaximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues,@@ -170,15 +158,11 @@ rankValues = Data.Default.def instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Real pieceSquareValue, Show pieceSquareValue- ) => HXT.XmlPickler (EvaluationOptions pieceSquareValue x y) where+ ) => HXT.XmlPickler (EvaluationOptions pieceSquareValue) where xpickle = HXT.xpDefault def . HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d) -> mkEvaluationOptions a b c d, -- Construct. \MkEvaluationOptions {@@ -200,55 +184,46 @@ def = Data.Default.def -- | Convert a /PieceSquareTablePair/ to a single linearly interpolated array.-fromPieceSquareTablePair :: (- Enum x,- Enum y,- Fractional pieceSquareValue,- Ord x,- Ord y- ) => PieceSquareTablePair x y pieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue+fromPieceSquareTablePair :: Fractional pieceSquareValue => PieceSquareTablePair pieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue fromPieceSquareTablePair pieceSquareTablePair = Component.PieceSquareByCoordinatesByRank.mkPieceSquareByCoordinatesByRank $ \rank -> ( \(openingGamePieceSquareValuesByCoordinates, maybeEndGamePieceSquareValuesByCoordinates) -> Data.Maybe.maybe ( Left openingGamePieceSquareValuesByCoordinates ) ( Right . Cartesian.Coordinates.listArrayByCoordinates . zipWith Component.PieceSquareByCoordinatesByRank.interpolatePieceSquareValues (- Data.Array.IArray.elems openingGamePieceSquareValuesByCoordinates- ) . Data.Array.IArray.elems+ Data.Foldable.toList openingGamePieceSquareValuesByCoordinates+ ) . Data.Foldable.toList ) maybeEndGamePieceSquareValuesByCoordinates ) $ ( Data.Maybe.fromJust {-values for the openingGame must be specified-} . Input.PieceSquareTable.dereference rank *** Input.PieceSquareTable.dereference rank ) pieceSquareTablePair -- | Smart constructor.-mkEvaluationOptions :: (- Enum x,- Enum y,- Fractional pieceSquareValue,- Ord x,- Ord y- )+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/. -> IncrementalEvaluation- -> Maybe (PieceSquareTablePair x y pieceSquareValue) -- ^ The value to each type of piece, of each square, during normal play & the end-game.- -> EvaluationOptions pieceSquareValue x y+ -> Maybe (PieceSquareTablePair pieceSquareValue) -- ^ The value to each type of piece, of each square, during normal play & the end-game.+ -> EvaluationOptions pieceSquareValue mkEvaluationOptions rankValues criteriaWeights incrementalEvaluation maybePieceSquareTablePair | Just (pieceSquareTable, _) <- maybePieceSquareTablePair , let undefinedRanks = Input.PieceSquareTable.findUndefinedRanks pieceSquareTable- , not $ Data.Set.null undefinedRanks- = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.Input.EvaluationOptions.mkEvaluationOptions:\tranks" . Text.ShowList.showsAssociation $ shows (Data.Set.toList undefinedRanks) " are undefined."+ , not $ Data.Foldable.null undefinedRanks+ = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.Input.EvaluationOptions.mkEvaluationOptions:\tranks" . Text.ShowList.showsAssociation $ shows (Data.Foldable.toList undefinedRanks) " are undefined." | Input.CriteriaWeights.getWeightOfPieceSquareValue criteriaWeights /= minBound , Data.Maybe.isNothing maybePieceSquareTablePair = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.EvaluationOptions.mkEvaluationOptions:\tweight of " . shows Input.CriteriaWeights.weightOfPieceSquareValueTag . showString " is defined but " $ shows Input.PieceSquareTable.tag " isn't."+ | maximumTotalRankValue == 0 && Input.CriteriaWeights.getWeightOfMaterial criteriaWeights /= 0 = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.EvaluationOptions.mkEvaluationOptions:\tweight of " . shows Input.CriteriaWeights.weightOfMaterialTag . showString " is non-zero, but the maximum total rank-value is " $ shows rankValues "." | otherwise = MkEvaluationOptions { getRankValues = rankValues,- getMaximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues, -- Infer.+ getMaximumTotalRankValue = maximumTotalRankValue, getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, getMaybePieceSquareTablePair = maybePieceSquareTablePair, getMaybePieceSquareByCoordinatesByRank = fromPieceSquareTablePair `fmap` maybePieceSquareTablePair -- Infer.- }+ } where+ maximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues -- | Self-documentation.-type Reader pieceSquareValue x y = Control.Monad.Reader.Reader (EvaluationOptions pieceSquareValue x y)+type Reader pieceSquareValue = Control.Monad.Reader.Reader (EvaluationOptions pieceSquareValue)
src-lib/BishBosh/Input/IOOptions.hs view
@@ -25,6 +25,7 @@ module BishBosh.Input.IOOptions( -- * Types -- ** Type-synonyms+-- PersistenceSpecification, -- Transformation, -- ** Data-types IOOptions(@@ -43,6 +44,7 @@ -- filePathTag, -- automaticTag, -- * Functions+ persist, -- ** Constructor mkIOOptions, -- ** Mutators@@ -54,22 +56,26 @@ setVerbosity ) where -import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Data.Foldable as Data.Foldable-import qualified BishBosh.Input.CECPFeatures as Input.CECPFeatures-import qualified BishBosh.Input.PGNOptions as Input.PGNOptions-import qualified BishBosh.Input.UIOptions as Input.UIOptions-import qualified BishBosh.Input.Verbosity as Input.Verbosity-import qualified BishBosh.Property.Arboreal as Property.Arboreal-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Foldable as Data.Foldable+import qualified BishBosh.Input.CECPFeatures as Input.CECPFeatures+import qualified BishBosh.Input.PGNOptions as Input.PGNOptions+import qualified BishBosh.Input.UIOptions as Input.UIOptions+import qualified BishBosh.Input.Verbosity as Input.Verbosity+import qualified BishBosh.Property.Arboreal as Property.Arboreal+import qualified BishBosh.Text.ShowColouredPrefix as Text.ShowColouredPrefix+import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception+import qualified Control.Monad import qualified Data.Default import qualified Data.Maybe import qualified System.FilePath-import qualified Text.XML.HXT.Arrow.Pickle as HXT+import qualified System.IO+import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify XML. tag :: String@@ -95,13 +101,16 @@ automaticTag :: String automaticTag = "automatic" +-- | The path to a file, into which game-state can be persisted (obliterating any existing content), & whether to save this state automatically after each move.+type PersistenceSpecification = (System.FilePath.FilePath, Bool)+ -- | Defines options related to i/o. data IOOptions = MkIOOptions {- getMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath, -- ^ An optional path to a file, into which the unprocessed configuration, formatted as XML, should be written (obliterating any existing file-contents).- getMaybeMaximumPGNNames :: Maybe Type.Count.NGames, -- ^ The maximum number of names to display, of matching games from the PGN-database; @Nothing@ implies unlimited. CAVEAT: pedantically, it's a number of names not a number of games.- getPGNOptionsList :: [Input.PGNOptions.PGNOptions], -- ^ How to construct each PGN-database.- getMaybePersistence :: Maybe (System.FilePath.FilePath, Bool), -- ^ Optional path to a file, into which game-state can be persisted (obliterating any existing content), & whether to save this state automatically after each move.- getUIOptions :: Input.UIOptions.UIOptions -- ^ Options which define the user-interface.+ getMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath, -- ^ An optional path to a file, into which the unprocessed configuration, formatted as XML, should be written (obliterating any existing file-contents).+ getMaybeMaximumPGNNames :: Maybe Type.Count.NGames, -- ^ The maximum number of names to display, of matching games from the PGN-database; @Nothing@ implies unlimited. CAVEAT: pedantically, it's a number of names not a number of games.+ getPGNOptionsList :: [Input.PGNOptions.PGNOptions], -- ^ How to construct each PGN-database.+ getMaybePersistence :: Maybe PersistenceSpecification, -- ^ Optional path to a file, into which game-state can be persisted (obliterating any existing content), & whether to save this state automatically after each move.+ getUIOptions :: Input.UIOptions.UIOptions -- ^ Options which define the user-interface. } deriving Eq instance Control.DeepSeq.NFData IOOptions where@@ -179,10 +188,10 @@ -- | Smart constructor. mkIOOptions- :: Maybe System.FilePath.FilePath -- ^ An optional path to a file, into which the unprocessed configuration, formatted as XML, should be written (obliterating any existing file-contents).- -> Maybe Type.Count.NGames -- ^ The optional maximum number of names, of matching PGN-games, to display; @Nothing@ implies unlimited.- -> [Input.PGNOptions.PGNOptions] -- ^ How to find & process PGN-databases.- -> Maybe (System.FilePath.FilePath, Bool) -- ^ Optional path to a file, into which game-state can be persisted (obliterating any existing content), & whether to save this state automatically after each move.+ :: Maybe System.FilePath.FilePath -- ^ An optional path to a file, into which the unprocessed configuration, formatted as XML, should be written (obliterating any existing file-contents).+ -> Maybe Type.Count.NGames -- ^ The optional maximum number of names, of matching PGN-games, to display; @Nothing@ implies unlimited.+ -> [Input.PGNOptions.PGNOptions] -- ^ How to find & process PGN-databases.+ -> Maybe PersistenceSpecification -- ^ Optional path to a file, into which game-state can be persisted (obliterating any existing content), & whether to save this state automatically after each move. -> Input.UIOptions.UIOptions -> IOOptions mkIOOptions maybeOutputConfigFilePath maybeMaximumPGNNames pgnOptionsList maybePersistence uiOptions@@ -206,6 +215,26 @@ } where duplicateFilePaths = Data.Foldable.findDuplicates $ map (System.FilePath.normalise . Input.PGNOptions.getDatabaseFilePath) pgnOptionsList++-- | Persist the specified game to file.+persist+ :: Show game+ => IOOptions+ -> Bool -- ^ Verbose.+ -> game+ -> IO ()+persist MkIOOptions {+ getMaybePersistence = maybePersistence+} verbose game = Data.Maybe.maybe (+ return {-to IO-monad-} ()+ ) (+ \(filePath, automatic) -> Control.Monad.when automatic . Control.Exception.catch (+ do+ System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` game)++ Control.Monad.when verbose . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "the game-state has been saved in " $ shows filePath "."+ ) $ \e -> System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixError $ show (e :: Control.Exception.SomeException)+ ) maybePersistence -- | The type of a function used to transform 'IOOptions'. type Transformation = IOOptions -> IOOptions
src-lib/BishBosh/Input/NativeUIOptions.hs view
@@ -26,11 +26,13 @@ -- * Types -- ** Type-synonyms -- ScreenCoordinates,+-- DepictFigurine, -- ** Data-types NativeUIOptions( -- MkNativeUIOptions, getBoardMagnification,- getColourScheme+ getColourScheme,+ getDepictFigurine ), -- * Constants tag,@@ -42,6 +44,7 @@ mkNativeUIOptions ) where +import BishBosh.Data.Bool() import Control.Arrow((***)) import qualified BishBosh.Attribute.ColourScheme as Attribute.ColourScheme import qualified BishBosh.Data.Exception as Data.Exception@@ -61,6 +64,10 @@ boardMagnificationTag = "boardMagnification" -- | Used to qualify XML.+depictFigurineTag :: String+depictFigurineTag = "depictFigurine"++-- | Used to qualify XML. nRowsTag :: String nRowsTag = "nRows" @@ -71,25 +78,32 @@ -- | The coordinates used to index the screen. CAVEAT: the name is an anachronistic hang-over from a discarded implementation of a Curses display. type ScreenCoordinates = (Type.Length.Row, Type.Length.Column) +-- | Whether to a depict a piece using a Unicode figurine.+type DepictFigurine = Bool+ -- | Constructor. data NativeUIOptions = MkNativeUIOptions { getBoardMagnification :: ScreenCoordinates, -- ^ The factor by which the dimensions of the board are stretched when displayed.- getColourScheme :: Attribute.ColourScheme.ColourScheme+ getColourScheme :: Attribute.ColourScheme.ColourScheme,+ getDepictFigurine :: DepictFigurine -- ^ Whether to a depict pieces using Unicode figurines. } deriving Eq instance Control.DeepSeq.NFData NativeUIOptions where rnf MkNativeUIOptions { getBoardMagnification = boardMagnification,- getColourScheme = colourScheme+ getColourScheme = colourScheme,+ getDepictFigurine = depictFigurine } = Control.DeepSeq.rnf ( boardMagnification,- colourScheme+ colourScheme,+ depictFigurine ) instance Show NativeUIOptions where showsPrec precision MkNativeUIOptions { getBoardMagnification = boardMagnification,- getColourScheme = colourScheme+ getColourScheme = colourScheme,+ getDepictFigurine = depictFigurine } = Text.ShowList.showsAssociationList' [ ( boardMagnificationTag,@@ -97,31 +111,39 @@ ), ( Attribute.ColourScheme.tag, showsPrec precision colourScheme+ ), (+ depictFigurineTag,+ showsPrec precision depictFigurine ) ] instance Data.Default.Default NativeUIOptions where def = MkNativeUIOptions { getBoardMagnification = (1, 1),- getColourScheme = Data.Default.def+ getColourScheme = Data.Default.def,+ getDepictFigurine = False } instance HXT.XmlPickler NativeUIOptions where xpickle = HXT.xpElem tag . HXT.xpWrap (- uncurry mkNativeUIOptions, -- Construct.+ \(a, b, c) -> mkNativeUIOptions a b c, -- Construct. \MkNativeUIOptions { getBoardMagnification = boardMagnification,- getColourScheme = colourScheme+ getColourScheme = colourScheme,+ getDepictFigurine = depictFigurine } -> ( boardMagnification,- colourScheme+ colourScheme,+ depictFigurine )- ) $ HXT.xpPair (+ ) $ HXT.xpTriple ( getBoardMagnification def `HXT.xpDefault` HXT.xpElem boardMagnificationTag ( HXT.xpAttr nRowsTag HXT.xpickle `HXT.xpPair` HXT.xpAttr nColumnsTag HXT.xpickle ) ) ( getColourScheme def `HXT.xpDefault` HXT.xpickle+ ) (+ getDepictFigurine def `HXT.xpDefault` HXT.xpAttr depictFigurineTag HXT.xpickle ) where def = Data.Default.def @@ -129,8 +151,9 @@ mkNativeUIOptions :: ScreenCoordinates -- ^ The factor by which the dimensions of the board are stretched when displayed. -> Attribute.ColourScheme.ColourScheme+ -> DepictFigurine -> NativeUIOptions-mkNativeUIOptions boardMagnification colourScheme+mkNativeUIOptions boardMagnification colourScheme depictFigurine | uncurry (||) $ ( (< 1) *** (< 1) ) boardMagnification = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.NativeUIOptions.mkNativeUIOptions:\t" . showString boardMagnificationTag . Text.ShowList.showsAssociation $ shows boardMagnification " must both exceed zero."@@ -139,6 +162,7 @@ ) boardMagnification = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.NativeUIOptions.mkNativeUIOptions:\t" . showString boardMagnificationTag . Text.ShowList.showsAssociation $ shows boardMagnification " must both be odd." | otherwise = MkNativeUIOptions { getBoardMagnification = boardMagnification,- getColourScheme = colourScheme+ getColourScheme = colourScheme,+ getDepictFigurine = depictFigurine }
src-lib/BishBosh/Input/Options.hs view
@@ -62,6 +62,7 @@ import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Input.IOOptions as Input.IOOptions+import qualified BishBosh.Input.PGNOptions as Input.PGNOptions import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions import qualified BishBosh.Input.Verbosity as Input.Verbosity@@ -92,19 +93,15 @@ type RandomSeed = Int -- | Defines the application's options.-data Options pieceSquareValue x y = 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 x y, -- ^ 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 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. } deriving (Eq, Show) -instance (- Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Options pieceSquareValue x y) where+instance Control.DeepSeq.NFData pieceSquareValue => Control.DeepSeq.NFData (Options pieceSquareValue) where rnf MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -113,14 +110,7 @@ getIOOptions = ioOptions } = Control.DeepSeq.rnf (maybeMaximumPlies, maybeRandomSeed, evaluationOptions, searchOptions, ioOptions) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Real pieceSquareValue,- Show pieceSquareValue- ) => Property.ShowFloat.ShowFloat (Options pieceSquareValue x y) where+instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (Options pieceSquareValue) where showsFloat fromDouble MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -144,7 +134,7 @@ ) ] -instance Data.Default.Default (Options pieceSquareValue x y) where+instance Data.Default.Default (Options pieceSquareValue) where def = MkOptions { getMaybeMaximumPlies = Nothing, getMaybeRandomSeed = Nothing,@@ -154,15 +144,11 @@ } instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Real pieceSquareValue, Show pieceSquareValue- ) => HXT.XmlPickler (Options pieceSquareValue x y) where+ ) => HXT.XmlPickler (Options pieceSquareValue) where xpickle = HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d, e) -> mkOptions a b c d e, -- Construct. \MkOptions {@@ -188,13 +174,16 @@ 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 x y+ -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue -> Input.SearchOptions.SearchOptions -> Input.IOOptions.IOOptions- -> Options pieceSquareValue x y+ -> Options pieceSquareValue 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."+ | Input.SearchOptions.getSortOnStandardOpeningMoveFrequency searchOptions && null (+ Input.IOOptions.getPGNOptionsList ioOptions+ ) = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.Options.mkOptions:\tcan't implement '" . showString Input.SearchOptions.tag . showChar '.' . showString Input.SearchOptions.sortOnStandardOpeningMoveFrequencyTag . showString "' without any '" . showString Input.PGNOptions.tag . showChar '.' $ showString Input.PGNOptions.databaseFilePathTag "'" | otherwise = MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -204,22 +193,22 @@ } -- | The type of a function used to transform 'Options'.-type Transformation pieceSquareValue x y = Options pieceSquareValue x y -> Options pieceSquareValue x y+type Transformation pieceSquareValue = Options pieceSquareValue -> Options pieceSquareValue -- | Mutator.-setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation pieceSquareValue x y+setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation pieceSquareValue setMaybeOutputConfigFilePath maybeOutputConfigFilePath options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybeOutputConfigFilePath maybeOutputConfigFilePath ioOptions } -- | Mutator.-setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue x y+setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue setMaybeRandomSeed maybeRandomSeed options = options { getMaybeRandomSeed = maybeRandomSeed } -- | Mutator.-setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation pieceSquareValue x y+setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation pieceSquareValue setMaybePersistence maybePersistence options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = ioOptions { Input.IOOptions.getMaybePersistence = maybePersistence@@ -227,25 +216,25 @@ } -- | Mutator.-setVerbosity :: Input.Verbosity.Verbosity -> Transformation pieceSquareValue x y+setVerbosity :: Input.Verbosity.Verbosity -> Transformation pieceSquareValue setVerbosity verbosity options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setVerbosity verbosity ioOptions } -- | Mutator.-setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue x y+setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions ioOptions } -- | Mutator.-setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation pieceSquareValue x y+setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation pieceSquareValue setMaybePrintMoveTree maybePrintMoveTree options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybePrintMoveTree maybePrintMoveTree ioOptions } -- | Mutator.-swapSearchDepth :: Transformation pieceSquareValue x y+swapSearchDepth :: Transformation pieceSquareValue swapSearchDepth options@MkOptions { getSearchOptions = searchOptions } = options { getSearchOptions = Input.SearchOptions.swapSearchDepth searchOptions }
src-lib/BishBosh/Input/PieceSquareTable.hs view
@@ -40,6 +40,7 @@ -- ** Type-synonyms -- Normalise, -- ReflectOnY,+ IOFormat, Assocs, -- ** Data-types PieceSquareTable(@@ -71,16 +72,16 @@ import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Data.Foldable as Data.Foldable import qualified BishBosh.Data.Num as Data.Num+import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.FixedMembership as Property.FixedMembership 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.Map.Strict+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,22 +104,15 @@ type ReflectOnY = Bool -- | Defines the value for each type of piece, of occupying each square.-data PieceSquareTable x y pieceSquareValue = MkPieceSquareTable {+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 :: Data.Map.Strict.Map Attribute.Rank.Rank (- Cartesian.Coordinates.ArrayByCoordinates x y pieceSquareValue+ 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. } deriving (Eq, Show) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Real pieceSquareValue,- Show pieceSquareValue- ) => Property.ShowFloat.ShowFloat (PieceSquareTable x y pieceSquareValue) where+instance (Real pieceSquareValue, Show pieceSquareValue) => Property.ShowFloat.ShowFloat (PieceSquareTable pieceSquareValue) where showsFloat fromDouble MkPieceSquareTable { getNormalise = normalise, getReflectOnY = reflectOnY,@@ -136,28 +130,27 @@ if reflectOnY then unmirror else id- ) . Data.Array.IArray.elems+ ) . Data.Foldable.toList ) (- Data.Map.Strict.assocs byRank+ Map.toList byRank ) -instance Data.Default.Default (PieceSquareTable x y pieceSquareValue) where+instance Data.Default.Default (PieceSquareTable pieceSquareValue) where def = MkPieceSquareTable { getNormalise = False, getReflectOnY = True,- getPieceSquareValueByCoordinatesByRank = Data.Map.Strict.empty+ getPieceSquareValueByCoordinatesByRank = Property.Empty.empty } +-- | The format of the values when read or written.+type IOFormat = Double+ instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Real pieceSquareValue, Show pieceSquareValue- ) => HXT.XmlPickler (PieceSquareTable x y pieceSquareValue) where+ ) => HXT.XmlPickler (PieceSquareTable pieceSquareValue) where xpickle = HXT.xpWrap ( \(a, b, c) -> mkPieceSquareTable a b c, -- Construct. \MkPieceSquareTable {@@ -167,12 +160,12 @@ } -> ( normalise, reflectOnY,- Data.Map.Strict.assocs $ Data.Map.Strict.map (+ Map.toList $ Map.map ( ( if reflectOnY then unmirror else id- ) . Data.Array.IArray.elems+ ) . Data.Foldable.toList ) byRank ) -- Deconstruct to tuple. ) . HXT.xpTriple (@@ -184,11 +177,11 @@ showString "by" $ Text.Case.toUpperInitial Attribute.Rank.tag ) $ HXT.xpickle {-rank-} `HXT.xpPair` HXT.xpWrap ( \s -> [- realToFrac (pieceSquareValue :: Type.Mass.PieceSquareValue) |+ realToFrac (pieceSquareValue :: IOFormat) | word <- words s, (pieceSquareValue, "") <- reads word ], -- List-comprehension.- unwords . map (show . (\pieceSquareValue -> realToFrac pieceSquareValue :: Type.Mass.PieceSquareValue))+ unwords . map (show . (\pieceSquareValue -> realToFrac pieceSquareValue :: IOFormat)) ) ( HXT.xpTextAttr . showString "by" $ Text.Case.toUpperInitial Cartesian.Coordinates.tag )@@ -233,28 +226,24 @@ -- | Smart constructor. mkPieceSquareTable :: (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Show pieceSquareValue ) => 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 x y pieceSquareValue+ -> PieceSquareTable pieceSquareValue mkPieceSquareTable normalise reflectOnY assocs | any (- (/= nValuesRequired) . 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 "." | otherwise = MkPieceSquareTable { getNormalise = normalise, getReflectOnY = reflectOnY,- getPieceSquareValueByCoordinatesByRank = Data.Map.Strict.fromList . map (+ getPieceSquareValueByCoordinatesByRank = Map.fromList . map ( Control.Arrow.second Cartesian.Coordinates.listArrayByCoordinates ) . ( if reflectOnY@@ -276,13 +265,13 @@ ) Cartesian.Coordinates.nSquares -- | Identify any /rank/ lacking a definition.-findUndefinedRanks :: PieceSquareTable x y pieceSquareValue -> Data.Set.Set Attribute.Rank.Rank-findUndefinedRanks MkPieceSquareTable { getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Data.Set.fromAscList Property.FixedMembership.members `Data.Set.difference` Data.Map.Strict.keysSet pieceSquareValueByCoordinatesByRank+findUndefinedRanks :: PieceSquareTable pieceSquareValue -> 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 x y pieceSquareValue- -> Maybe (Cartesian.Coordinates.ArrayByCoordinates x y pieceSquareValue)-dereference rank MkPieceSquareTable { getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Data.Map.Strict.lookup rank pieceSquareValueByCoordinatesByRank+ -> PieceSquareTable pieceSquareValue+ -> Maybe (Cartesian.Coordinates.ArrayByCoordinates pieceSquareValue)+dereference rank MkPieceSquareTable { getPieceSquareValueByCoordinatesByRank = pieceSquareValueByCoordinatesByRank } = Map.lookup rank pieceSquareValueByCoordinatesByRank
src-lib/BishBosh/Input/SearchOptions.hs view
@@ -51,7 +51,7 @@ ), -- * Constants tag,--- sortOnStandardOpeningMoveFrequencyTag+ sortOnStandardOpeningMoveFrequencyTag, -- minimumHammingDistanceTag, -- retireKillerMovesAfterTag, -- trapRepeatedPositionsTag,@@ -85,6 +85,7 @@ import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Data.Foldable import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions+import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Text.Case as Text.Case import qualified BishBosh.Text.ShowList as Text.ShowList@@ -94,7 +95,7 @@ import qualified Control.Monad.Reader import qualified Data.Default import qualified Data.Foldable-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified Text.XML.HXT.Arrow.Pickle as HXT @@ -169,7 +170,7 @@ type MaybeUseTranspositions = Maybe (Type.Count.NMoves, Type.Count.NPlies) -- | The depth to search for each /logical colour/.-type SearchDepthByLogicalColour = Data.Map.Strict.Map Attribute.LogicalColour.LogicalColour Type.Count.NPlies+type SearchDepthByLogicalColour = Map.Map Attribute.LogicalColour.LogicalColour Type.Count.NPlies -- | Defines options related to searching for a move. data SearchOptions = MkSearchOptions {@@ -245,13 +246,13 @@ shows standardOpeningOptions ), ( searchDepthByLogicalColourTag,- Text.ShowList.showsAssociationList' . map (show *** shows) $ Data.Map.Strict.assocs searchDepthByLogicalColour+ Text.ShowList.showsAssociationList' . map (show *** shows) $ Map.toList searchDepthByLogicalColour ) ] instance Data.Default.Default SearchOptions where def = MkSearchOptions {- getSortOnStandardOpeningMoveFrequency = False,+ getSortOnStandardOpeningMoveFrequency = False, -- CAVEAT: this can only be True if a PGN database has been defined; which is currently unknown. getMaybeCaptureMoveSortAlgorithm = Nothing, getMaybeMinimumHammingDistance = Nothing, getMaybeRetireKillerMovesAfter = Nothing,@@ -259,7 +260,7 @@ getUsePondering = False, getMaybeUseTranspositions = Nothing, getStandardOpeningOptions = Data.Default.def,- getSearchDepthByLogicalColour = Data.Map.Strict.empty -- Manual.+ getSearchDepthByLogicalColour = Property.Empty.empty -- Manual play. } instance HXT.XmlPickler SearchOptions where@@ -302,14 +303,14 @@ HXT.xpOption . HXT.xpElem "transpositions" $ HXT.xpAttr retireTranspositionsAfterTag HXT.xpickle {-NMoves-} `HXT.xpPair` HXT.xpAttr minimumTranspositionSearchDepthTag HXT.xpickle {-NPlies-} ) HXT.xpickle {-standardOpeningOptions-} ( HXT.xpElem searchDepthByLogicalColourTag . HXT.xpWrap (- Data.Map.Strict.fromList . (+ Map.fromList . ( \l -> let 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 "." ), -- Construct from a List.- Data.Map.Strict.toList -- Deconstruct to a List.+ Map.toList -- Deconstruct to an association-list. ) . HXT.xpList {-potentially null-} . HXT.xpElem ( showString "by" $ Text.Case.toUpperInitial Attribute.LogicalColour.tag ) $ HXT.xpickle {-LogicalColour-} `HXT.xpPair` HXT.xpAttr searchDepthTag HXT.xpickle {-NPlies-}@@ -333,7 +334,7 @@ , 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 , 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.Map.Strict.size searchDepthByLogicalColour+ | 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@@ -341,10 +342,10 @@ | 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." | Just (_, minimumTranspositionSearchDepth) <- maybeUseTranspositions- , not $ Data.Map.Strict.null searchDepthByLogicalColour+ , not $ Data.Foldable.null searchDepthByLogicalColour , Data.Foldable.all ( minimumTranspositionSearchDepth >- ) searchDepthByLogicalColour = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString minimumTranspositionSearchDepthTag . Text.ShowList.showsAssociation $ shows minimumTranspositionSearchDepth . showString " exceeds " . showString searchDepthTag . Text.ShowList.showsAssociation $ shows (Data.Map.Strict.toList searchDepthByLogicalColour) "."+ ) searchDepthByLogicalColour = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" . showString minimumTranspositionSearchDepthTag . Text.ShowList.showsAssociation $ shows minimumTranspositionSearchDepth . showString " exceeds " . showString searchDepthTag . Text.ShowList.showsAssociation $ shows (Map.toList searchDepthByLogicalColour) "." | Data.Foldable.any ( < minimumSearchDepth ) searchDepthByLogicalColour = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.mkSearchOptions:\t" $ showString searchDepthTag " must be positive."@@ -362,7 +363,7 @@ -- | Get either player's search-depth, using a default value when none are defined. getSearchDepth :: SearchOptions -> Type.Count.NPlies-getSearchDepth MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour } = Data.Maybe.fromMaybe defaultSearchDepth . Data.Maybe.listToMaybe $ Data.Map.Strict.elems searchDepthByLogicalColour -- Manual players don't have a searchDepth, so use the opponent's settings.+getSearchDepth MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour } = Data.Maybe.fromMaybe defaultSearchDepth . Data.Maybe.listToMaybe $ Data.Foldable.toList searchDepthByLogicalColour -- Manual players don't have a searchDepth, so use the opponent's settings. -- | Self-documentation. type RecordKillerMoves = Bool@@ -386,21 +387,21 @@ setSearchDepth :: Type.Count.NPlies -> Transformation setSearchDepth searchDepth searchOptions@MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour } | searchDepth < minimumSearchDepth = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.SearchOptions.setSearchDepth:\t" . showString searchDepthTag . Text.ShowList.showsAssociation $ shows searchDepth " must be positive."- | otherwise = searchOptions { getSearchDepthByLogicalColour = Data.Map.Strict.map (const searchDepth) searchDepthByLogicalColour }+ | otherwise = searchOptions { getSearchDepthByLogicalColour = Map.map (const searchDepth) searchDepthByLogicalColour } -- | Swap the /logical colour/ associated with any /searchDepth/ currently assigned. swapSearchDepth :: Transformation swapSearchDepth searchOptions@MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour } = searchOptions {- getSearchDepthByLogicalColour = Data.Map.Strict.mapKeys Property.Opposable.getOpposite searchDepthByLogicalColour+ getSearchDepthByLogicalColour = Map.mapKeys Property.Opposable.getOpposite searchDepthByLogicalColour } -- | 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 MkSearchOptions { getSearchDepthByLogicalColour = searchDepthByLogicalColour-} = Data.Map.Strict.keys searchDepthByLogicalColour+} = Map.keys searchDepthByLogicalColour -- | Self-documentation. type Reader = Control.Monad.Reader.Reader SearchOptions
src-lib/BishBosh/Input/StandardOpeningOptions.hs view
@@ -24,23 +24,20 @@ module BishBosh.Input.StandardOpeningOptions( -- * Types--- ** Type-synonyms--- TryToMatchMoves,--- TryToMatchViaJoiningMove,--- TryToMatchColourFlippedPosition,- MatchSwitches, -- ** Data-types StandardOpeningOptions( -- MkStandardOpeningOptions, -- getTryToMatchMoves, -- getTryToMatchViaJoiningMove,--- getTryToMatchColourFlippedPosition+-- getTryToMatchColourFlippedPosition,+ getPreferVictories ), -- * Constants tag, -- tryToMatchMovesTag, -- tryToMatchViaJoiningMoveTag, -- tryToMatchColourFlippedPositionTag,+-- preferVictoriesTag, -- * Functions -- ** Constructor mkStandardOpeningOptions,@@ -48,11 +45,12 @@ getMatchSwitches ) where -import BishBosh.Data.Bool() -- For 'HXT.xpickle'.-import qualified BishBosh.Text.ShowList as Text.ShowList+import BishBosh.Data.Bool() -- For 'HXT.xpickle'.+import qualified BishBosh.Text.ShowList as Text.ShowList import qualified Control.DeepSeq import qualified Data.Default-import qualified Text.XML.HXT.Arrow.Pickle as HXT+import qualified BishBosh.ContextualNotation.PositionHashQualifiedMoveTree as ContextualNotation.PositionHashQualifiedMoveTree+import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify XML. tag :: String@@ -70,37 +68,32 @@ tryToMatchColourFlippedPositionTag :: String tryToMatchColourFlippedPositionTag = "tryToMatchColourFlippedPosition" --- | Whether to attempt to exactly match moves with a standard opening; transpositions won't be matched.-type TryToMatchMoves = Bool---- | Whether to attempt to join the current position to a standard opening that's only one ply away.-type TryToMatchViaJoiningMove = Bool---- | Whether to attempt to match a colour-flipped version of the current position with a standard opening-type TryToMatchColourFlippedPosition = Bool---- | The switches used to control attempts to find a match amongst standard openings.-type MatchSwitches = (TryToMatchMoves, TryToMatchViaJoiningMove, TryToMatchColourFlippedPosition)+-- | Used to qualify XML.+preferVictoriesTag :: String+preferVictoriesTag = "preferVictories" -- | Defines options related to searching for a move. data StandardOpeningOptions = MkStandardOpeningOptions {- getTryToMatchMoves :: TryToMatchMoves, -- ^ Whether to attempt to exactly match moves with a standard opening; transpositions won't be matched.- getTryToMatchViaJoiningMove :: TryToMatchViaJoiningMove, -- ^ Whether to attempt to join the current position to a standard opening that's only one ply away.- getTryToMatchColourFlippedPosition :: TryToMatchColourFlippedPosition -- ^ Whether to attempt to match a colour-flipped version of the current position with a standard opening.+ getTryToMatchMoves :: ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchMoves, -- ^ Whether to attempt to exactly match moves with a standard opening; transpositions won't be matched.+ getTryToMatchViaJoiningMove :: ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchViaJoiningMove, -- ^ Whether to attempt to join the current position to a standard opening that's only one ply away.+ getTryToMatchColourFlippedPosition :: ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchColourFlippedPosition, -- ^ Whether to attempt to match a colour-flipped version of the current position with a standard opening.+ getPreferVictories :: ContextualNotation.PositionHashQualifiedMoveTree.PreferVictories -- ^ Whether from all matching positions extracted from PGN-Databases, to prefer moves which result in a greater probability of victory, for the player who has the next move. } deriving Eq instance Control.DeepSeq.NFData StandardOpeningOptions where rnf MkStandardOpeningOptions { getTryToMatchMoves = tryToMatchMoves, getTryToMatchViaJoiningMove = tryToMatchViaJoiningMove,- getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition- } = Control.DeepSeq.rnf (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition)+ getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition,+ getPreferVictories = preferVictories+ } = Control.DeepSeq.rnf (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition, preferVictories) instance Show StandardOpeningOptions where showsPrec _ MkStandardOpeningOptions { getTryToMatchMoves = tryToMatchMoves, getTryToMatchViaJoiningMove = tryToMatchViaJoiningMove,- getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition+ getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition,+ getPreferVictories = preferVictories } = Text.ShowList.showsAssociationList' [ ( tryToMatchMovesTag,@@ -111,6 +104,9 @@ ), ( tryToMatchColourFlippedPositionTag, shows tryToMatchColourFlippedPosition+ ), (+ preferVictoriesTag,+ shows preferVictories ) ] @@ -118,40 +114,46 @@ def = MkStandardOpeningOptions { getTryToMatchMoves = True, getTryToMatchViaJoiningMove = True,- getTryToMatchColourFlippedPosition = True+ getTryToMatchColourFlippedPosition = True,+ getPreferVictories = True } instance HXT.XmlPickler StandardOpeningOptions where xpickle = HXT.xpDefault Data.Default.def . HXT.xpElem tag . HXT.xpWrap (- \(a, b, c) -> mkStandardOpeningOptions a b c, -- Construct.+ \(a, b, c, d) -> mkStandardOpeningOptions a b c d, -- Construct. \MkStandardOpeningOptions { getTryToMatchMoves = tryToMatchMoves, getTryToMatchViaJoiningMove = tryToMatchViaJoiningMove,- getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition- } -> (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition) -- Deconstruct.- ) $ HXT.xpTriple(+ getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition,+ getPreferVictories = preferVictories+ } -> (tryToMatchMoves, tryToMatchViaJoiningMove, tryToMatchColourFlippedPosition, preferVictories) -- Deconstruct.+ ) $ HXT.xp4Tuple ( getTryToMatchMoves def `HXT.xpDefault` HXT.xpAttr tryToMatchMovesTag HXT.xpickle ) ( getTryToMatchViaJoiningMove def `HXT.xpDefault` HXT.xpAttr tryToMatchViaJoiningMoveTag HXT.xpickle ) ( getTryToMatchColourFlippedPosition def `HXT.xpDefault` HXT.xpAttr tryToMatchColourFlippedPositionTag HXT.xpickle+ ) (+ getPreferVictories def `HXT.xpDefault` HXT.xpAttr preferVictoriesTag HXT.xpickle ) where def = Data.Default.def -- | Smart constructor. mkStandardOpeningOptions- :: TryToMatchMoves- -> TryToMatchViaJoiningMove- -> TryToMatchColourFlippedPosition+ :: ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchMoves+ -> ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchViaJoiningMove+ -> ContextualNotation.PositionHashQualifiedMoveTree.TryToMatchColourFlippedPosition+ -> ContextualNotation.PositionHashQualifiedMoveTree.PreferVictories -> StandardOpeningOptions-mkStandardOpeningOptions tryToMatchMoves tryToMatchViaJoiningMove tryToMatchColourFlippedPosition = MkStandardOpeningOptions {+mkStandardOpeningOptions tryToMatchMoves tryToMatchViaJoiningMove tryToMatchColourFlippedPosition preferVictories = MkStandardOpeningOptions { getTryToMatchMoves = tryToMatchMoves, getTryToMatchViaJoiningMove = tryToMatchViaJoiningMove,- getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition+ getTryToMatchColourFlippedPosition = tryToMatchColourFlippedPosition,+ getPreferVictories = preferVictories } -- | Accessor.-getMatchSwitches :: StandardOpeningOptions -> MatchSwitches+getMatchSwitches :: StandardOpeningOptions -> ContextualNotation.PositionHashQualifiedMoveTree.MatchSwitches getMatchSwitches MkStandardOpeningOptions { getTryToMatchMoves = tryToMatchMoves, getTryToMatchViaJoiningMove = tryToMatchViaJoiningMove,
src-lib/BishBosh/Model/Game.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -104,6 +103,7 @@ import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+import qualified BishBosh.Notation.Notation as Notation.Notation import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription@@ -124,24 +124,22 @@ import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates import qualified BishBosh.State.Position as State.Position 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.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-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.Bits import qualified Data.Default import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra-import qualified Data.Map-import qualified Data.Map.Strict+import qualified Data.Map as Map import qualified Data.Maybe import qualified Data.Ord import qualified ToolShed.Data.List@@ -157,24 +155,24 @@ Building 'Component.Zobrist.Zobrist' into 'Game' would break the instance of 'Eq'. Building a hash-constructor into 'Game' would break the instance of @ (Eq, Read, Show) @. -}-type InstancesByPosition x y = State.InstancesByPosition.InstancesByPosition (State.Position.Position x y)+type InstancesByPosition = State.InstancesByPosition.InstancesByPosition State.Position.Position -- | The /move/s available to one player, indexed by the source-/coordinates/ of the /move/.-type AvailableQualifiedMoves x y = (- Data.Map.Map (Cartesian.Coordinates.Coordinates x y) -- Source.+type AvailableQualifiedMoves = (+ Map.Map Cartesian.Coordinates.Coordinates -- Source. ) [ (- Cartesian.Coordinates.Coordinates x y, -- Destination.+ Cartesian.Coordinates.Coordinates, -- Destination. Attribute.MoveType.MoveType ) ] -- | Sort the lists of destinations to faciliate testing for equality.-sortAvailableQualifiedMoves :: (Ord x, Ord y) => AvailableQualifiedMoves x y -> AvailableQualifiedMoves x y-sortAvailableQualifiedMoves = Data.Map.map . Data.List.sortBy $ Data.Ord.comparing fst {-destination-}+sortAvailableQualifiedMoves :: AvailableQualifiedMoves -> AvailableQualifiedMoves+sortAvailableQualifiedMoves = Map.map . Data.List.sortBy $ Data.Ord.comparing fst {-destination-} -- | The /move/s available to both players.-type AvailableQualifiedMovesByLogicalColour x y = Data.Map.Map Attribute.LogicalColour.LogicalColour (AvailableQualifiedMoves x y)+type AvailableQualifiedMovesByLogicalColour = Map.Map Attribute.LogicalColour.LogicalColour AvailableQualifiedMoves {- | * The first three fields represent the state of the /game/.@@ -183,23 +181,18 @@ * For efficiency the list of available /move/s is stored. -}-data Game x y = MkGame {- getNextLogicalColour :: Attribute.LogicalColour.LogicalColour, -- ^ N.B.: can be derived from 'getTurnsByLogicalColour', unless 'Property.Reflectable.reflectOnX' has been called.- getCastleableRooksByLogicalColour :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x, -- ^ Those @Rook@s which can still participate in castling.- getBoard :: State.Board.Board x y, -- ^ The current state of the /board/.- getTurnsByLogicalColour :: State.CastleableRooksByLogicalColour.TurnsByLogicalColour x y, -- ^ 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.- getInstancesByPosition :: InstancesByPosition x y, -- ^ The number of instances of various positions since the last unrepeatable move.- getAvailableQualifiedMovesByLogicalColour :: AvailableQualifiedMovesByLogicalColour x y, -- ^ 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.+data Game = MkGame {+ getNextLogicalColour :: Attribute.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.+ 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. } -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Eq (Game x y) where+instance Eq Game where MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -225,7 +218,7 @@ turnsByLogicalColour, maybeChecked, instancesByPosition,- Data.Map.map sortAvailableQualifiedMoves availableQualifiedMovesByLogicalColour,+ Map.map sortAvailableQualifiedMoves availableQualifiedMovesByLogicalColour, maybeTerminationReason ) == ( nextLogicalColour',@@ -234,14 +227,11 @@ turnsByLogicalColour', maybeChecked', instancesByPosition',- Data.Map.map sortAvailableQualifiedMoves availableQualifiedMovesByLogicalColour',+ Map.map sortAvailableQualifiedMoves availableQualifiedMovesByLogicalColour', maybeTerminationReason' ) -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Game x y) where+instance Control.DeepSeq.NFData Game where rnf MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -262,14 +252,7 @@ maybeTerminationReason ) -- Represent as a tuple. -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Show (Game x y) where+instance Show Game where showsPrec precedence MkGame { getBoard = board, getTurnsByLogicalColour = turnsByLogicalColour,@@ -280,17 +263,7 @@ maybeTerminationReason ) -- Represent as a tuple those fields which can't be inferred. -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Read x,- Read y,- Show x,- Show y- ) => Read (Game x y) where- {-# SPECIALISE instance Read (Game Type.Length.X Type.Length.Y) #-}+instance Read Game where readsPrec precedence = map ( Control.Arrow.first $ \( board,@@ -308,33 +281,17 @@ in game ) . readsPrec precedence -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Data.Default.Default (Game x y) where- {-# SPECIALISE instance Data.Default.Default (Game Type.Length.X Type.Length.Y) #-}+instance Data.Default.Default Game where def = ( mkGame Attribute.LogicalColour.White Data.Default.def {-castleableRooksByLogicalColour-} Data.Default.def {-board-} Data.Default.def {-turnsByLogicalColour-} ) { getMaybeChecked = Nothing,- getAvailableQualifiedMovesByLogicalColour = Data.Map.fromAscList $ map (+ getAvailableQualifiedMovesByLogicalColour = Map.fromAscList $ map ( id &&& (`mkAvailableQualifiedMovesFor` Data.Default.def {-game-}) ) Property.FixedMembership.members } -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Property.ExtendedPositionDescription.ReadsEPD (Game x y) where- {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Game Type.Length.X Type.Length.Y) #-}+instance Property.ExtendedPositionDescription.ReadsEPD Game where readsEPD s = [ ( mkGame nextLogicalColour castleableRooksByLogicalColour board turnsByLogicalColour,@@ -365,15 +322,10 @@ ] -- Singleton. ) -- Pair. ]- ) `map` Notation.PureCoordinate.readsCoordinates s3' -- En-passant destination.+ ) `map` Notation.Notation.readsCoordinates Notation.PureCoordinate.notation s3' -- En-passant destination. ] -- List-comprehension. -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ExtendedPositionDescription.ShowsEPD (Game x y) where+instance Property.ExtendedPositionDescription.ShowsEPD Game where showsEPD game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -390,15 +342,7 @@ ] -- CAVEAT: some information is lost during 'showsFEN', which can't subsequently be recovered by 'readsFEN'.-instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Property.ForsythEdwards.ReadsFEN (Game x y) where- {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Game Type.Length.X Type.Length.Y) #-}+instance Property.ForsythEdwards.ReadsFEN Game where readsFEN s = [ (game, s3) | (game, s1) <- Property.ExtendedPositionDescription.readsEPD s,@@ -406,12 +350,7 @@ (_fullMoveCounter, s3) <- reads s2 :: [(Int, String)] ] -- List-comprehension. -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ForsythEdwards.ShowsFEN (Game x y) where+instance Property.ForsythEdwards.ShowsFEN Game where showsFEN game@MkGame { getTurnsByLogicalColour = turnsByLogicalColour, getInstancesByPosition = instancesByPosition@@ -421,18 +360,10 @@ 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. ] -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Property.Empty.Empty (Game x y) where- {-# SPECIALISE instance Property.Empty.Empty (Game Type.Length.X Type.Length.Y) #-}+instance Property.Empty.Empty Game where empty = Data.Default.def -- i.e. zero turns have been taken, rather than zero pieces remain (which is illegal). -instance Property.Null.Null (Game x y) where+instance Property.Null.Null Game where isNull MkGame { getTurnsByLogicalColour = turnsByLogicalColour } = Property.Null.isNull turnsByLogicalColour {- |@@ -441,15 +372,7 @@ * N.B.: 'Property.Reflectable.ReflectableOnY' isn't implemented, since /reflectOnY/ produces a mirror-image /board/ in which the royal /piece/s start in a non-standard position & castling occurs the wrong way. -}-instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Property.Reflectable.ReflectableOnX (Game x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Game Type.Length.X Type.Length.Y) #-}+instance Property.Reflectable.ReflectableOnX Game where reflectOnX MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -472,9 +395,8 @@ getMaybeTerminationReason = fmap Property.Opposable.getOpposite maybeTerminationReason } -instance (Data.Array.IArray.Ix x, Enum x, Enum y, Ord y) => Component.Zobrist.Hashable2D Game x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- {-# SPECIALISE instance Component.Zobrist.Hashable2D Game Type.Length.X Type.Length.Y #-}- listRandoms2D game@MkGame {+instance StateProperty.Hashable.Hashable Game where+ listRandoms game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board@@ -483,28 +405,20 @@ then (Component.Zobrist.getRandomForBlacksMove zobrist :) else id ) . Data.Maybe.maybe id (- (++) . (`Component.Zobrist.listRandoms1D` zobrist)+ (++) . (`StateProperty.Hashable.listRandoms` zobrist) ) ( maybeLastTurn game >>= State.EnPassantAbscissa.mkMaybeEnPassantAbscissa nextLogicalColour ( State.Board.getMaybePieceByCoordinates board )- ) $ Component.Zobrist.listRandoms1D castleableRooksByLogicalColour zobrist ++ Component.Zobrist.listRandoms2D board zobrist+ ) $ StateProperty.Hashable.listRandoms castleableRooksByLogicalColour zobrist ++ StateProperty.Hashable.listRandoms board zobrist -- | Smart constructor.-mkGame :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Attribute.LogicalColour.LogicalColour -- ^ The player who is required to move next.- -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x- -> State.Board.Board x y- -> State.CastleableRooksByLogicalColour.TurnsByLogicalColour x y- -> Game x y-{-# SPECIALISE mkGame :: Attribute.LogicalColour.LogicalColour -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour Type.Length.X -> State.Board.Board Type.Length.X Type.Length.Y -> State.CastleableRooksByLogicalColour.TurnsByLogicalColour Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y #-}+mkGame+ :: Attribute.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 (@@ -519,7 +433,7 @@ getTurnsByLogicalColour = turnsByLogicalColour, getMaybeChecked = Data.List.find (`State.Board.isKingChecked` board) Property.FixedMembership.members, getInstancesByPosition = State.InstancesByPosition.mkSingleton $ mkPosition game,- getAvailableQualifiedMovesByLogicalColour = Data.Map.fromAscList [+ getAvailableQualifiedMovesByLogicalColour = Map.fromAscList [ (logicalColour, mkAvailableQualifiedMovesFor logicalColour game) | logicalColour <- Property.FixedMembership.members, getMaybeChecked game /= Just logicalColour -- Define the available qualified moves for unchecked players only.@@ -536,21 +450,13 @@ * There're zero previous turns. -}-fromBoard :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => State.Board.Board x y -> Game x y-{-# SPECIALISE fromBoard :: State.Board.Board Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y #-}+fromBoard :: State.Board.Board -> Game fromBoard board = mkGame Attribute.LogicalColour.White ( State.CastleableRooksByLogicalColour.fromBoard board ) board Property.Empty.empty {-TurnsByLogicalColour-} -- | Gets the sequence of /turn/s, with the latest at the head & the opening one last.-listTurns :: Game x y -> [Component.Turn.Turn x y]+listTurns :: Game -> [Component.Turn.Turn] listTurns MkGame { getNextLogicalColour = nextLogicalColour, getTurnsByLogicalColour = turnsByLogicalColour@@ -559,11 +465,11 @@ ) turnsByLogicalColour -- | Gets the sequence of /turn/s in the order they occured.-listTurnsChronologically :: Game x y -> [Component.Turn.Turn x y]+listTurnsChronologically :: Game -> [Component.Turn.Turn] listTurnsChronologically = reverse . listTurns -- | The last /turn/, if there was one.-maybeLastTurn :: Game x y -> Maybe (Component.Turn.Turn x y)+maybeLastTurn :: Game -> Maybe Component.Turn.Turn maybeLastTurn MkGame { getNextLogicalColour = nextLogicalColour, getTurnsByLogicalColour = turnsByLogicalColour@@ -578,13 +484,7 @@ * CAVEAT: this is a performance-hotspot; refactor => re-profile. -}-findAvailableCastlingMoves :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Attribute.LogicalColour.LogicalColour -> Game x y -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findAvailableCastlingMoves :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-}+findAvailableCastlingMoves :: Attribute.LogicalColour.LogicalColour -> Game -> [Component.QualifiedMove.QualifiedMove] findAvailableCastlingMoves logicalColour MkGame { getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board,@@ -610,8 +510,7 @@ -- | List any /rank/s to which the specified /piece/ can be promoted on moving to the specified /destination/. listMaybePromotionRanks- :: (Enum y, Eq y)- => Cartesian.Coordinates.Coordinates x y -- ^ Destination.+ :: Cartesian.Coordinates.Coordinates -- ^ Destination. -> Component.Piece.Piece -> [Maybe Attribute.Rank.Rank] {-# INLINE listMaybePromotionRanks #-}@@ -620,7 +519,7 @@ | otherwise = [Nothing] -- | The type of a function which transforms a /game/.-type Transformation x y = Game x y -> Game x y+type Transformation = Game -> Game {- | * Moves the referenced /piece/ between the specified /coordinates/.@@ -631,15 +530,7 @@ * CAVEAT: doesn't account for any previous game-termination when updating 'getAvailableQualifiedMovesByLogicalColour'. -}-takeTurn :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Component.Turn.Turn x y -> Transformation x y-{-# SPECIALISE takeTurn :: Component.Turn.Turn Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-}+takeTurn :: Component.Turn.Turn -> Transformation takeTurn turn game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -725,16 +616,12 @@ (blockingCoordinates, blockingPiece) | (kingsCoordinates, _) <- kingsByCoordinates, moveEndpoint <- moveEndpoints,- direction <- Data.Maybe.maybeToList $ Cartesian.Vector.toMaybeDirection (- Cartesian.Vector.measureDistance kingsCoordinates moveEndpoint :: Cartesian.Vector.VectorInt- ), -- N.B. null when the King isn't aligned with any move-endpoint.+ 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', (blockingCoordinates, blockingPiece) <- Data.Maybe.maybeToList $ ( \pair@(coordinates, _) -> if coordinates /= destination then Just pair- else {-blocker is destination-} if Cartesian.Vector.toMaybeDirection (- Cartesian.Vector.measureDistance kingsCoordinates source :: Cartesian.Vector.VectorInt- ) == Just direction+ else {-blocker is destination-} if Cartesian.Vector.toMaybeDirection (Cartesian.Vector.measureDistance kingsCoordinates source) == Just direction then Nothing else findBlockingPieceFrom coordinates -- Look through the destination to the previous blocker; which might be the source. ) =<< findBlockingPieceFrom kingsCoordinates@@ -774,13 +661,13 @@ isSafeDestination destination', maybePromotionRank <- listMaybePromotionRanks destination' piece' ] {-list-comprehension-} of- [] -> Data.Map.delete source' -- There're zero moves from here.- qualifiedDestinations -> Data.Map.insert source' qualifiedDestinations -- Overwrite any existing moves.+ [] -> 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 [] -> id validCastlingMoves -> uncurry (- Data.Map.insertWith (++)+ Map.insertWith (++) ) $ ( Component.Move.getSource {-the King-} . Component.QualifiedMove.getMove . head &&& map ( Component.Move.getDestination . Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType@@ -788,19 +675,19 @@ ) validCastlingMoves in ( \availableQualifiedMovesByLogicalColour' -> (- case (Data.Map.member opponentsLogicalColour availableQualifiedMovesByLogicalColour', Data.Maybe.isJust $ getMaybeChecked game') of- (True, True) -> Data.Map.delete opponentsLogicalColour -- Many changes result from the King being checked.- (True, _) -> Data.Map.adjust (+ 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 Data.Map.delete $ Cartesian.Coordinates.retreat nextLogicalColour destination+ then Map.delete $ Cartesian.Coordinates.retreat nextLogicalColour destination else id- ) . Data.Map.delete destination -- Delete the moves originally available to any taken piece.+ ) . 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.- _ -> Data.Map.insert opponentsLogicalColour $ mkAvailableQualifiedMovesFor opponentsLogicalColour game' -- Reconstruct.+ _ -> Map.insert opponentsLogicalColour $ mkAvailableQualifiedMovesFor opponentsLogicalColour game' -- Reconstruct. ) availableQualifiedMovesByLogicalColour' ) $ ( if Data.Maybe.maybe True {-not a member-} (@@ -811,27 +698,19 @@ ) {-only required for efficiency-} && Data.Foldable.any ( any $ Attribute.MoveType.isEnPassant . snd {-moveType-} ) availableQualifiedMoves- ) $ Data.Map.lookup nextLogicalColour availableQualifiedMovesByLogicalColour- then Data.Map.insert nextLogicalColour $ mkAvailableQualifiedMovesFor nextLogicalColour game' -- Reconstruct.- else Data.Map.adjust (+ ) $ Map.lookup nextLogicalColour availableQualifiedMovesByLogicalColour+ then Map.insert nextLogicalColour $ mkAvailableQualifiedMovesFor nextLogicalColour game' -- Reconstruct.+ else Map.adjust ( insertCastlingMoves nextLogicalColour . ( `insertMovesFrom` affected -- Reconstruct any moves for affected pieces.- ) . Data.Map.delete source -- Delete the moves originally available to the moved piece.+ ) . Map.delete source -- Delete the moves originally available to the moved piece. ) nextLogicalColour ) availableQualifiedMovesByLogicalColour, getMaybeTerminationReason = inferMaybeTerminationReason game' -- CAVEAT: this will overwrite any previous resignation. } -- | Construct a /turn/ & relay the request to 'takeTurn'.-applyQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Component.QualifiedMove.QualifiedMove x y -> Transformation x y-{-# SPECIALISE applyQualifiedMove :: Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-}+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@@ -840,15 +719,7 @@ move = Component.QualifiedMove.getMove qualifiedMove -- | Construct a /qualifiedMove/ & relay the request to "applyQualifiedMove".-applyEitherQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Component.EitherQualifiedMove.EitherQualifiedMove x y -> Transformation x y-{-# SPECIALISE applyEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-}+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@@ -857,20 +728,12 @@ move = Component.EitherQualifiedMove.getMove eitherQualifiedMove -- | Constructs /eitherQualifiedMove/s from the data provided, validating & applying each in the specified order.-applyEitherQualifiedMoves :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => (a -> Either String (Component.EitherQualifiedMove.EitherQualifiedMove x y)) -- ^ A constructor which can return an error-message.- -> Game x y -- ^ The /game/ to which the /move/s should be sequentially applied.+applyEitherQualifiedMoves+ :: (a -> Either String Component.EitherQualifiedMove.EitherQualifiedMove) -- ^ A constructor which can return an error-message.+ -> Game -- ^ The /game/ to which the /move/s should be sequentially applied. -> [a] -- ^ An ordered sequence of data from which /move/s are constructed.- -> Either (a, String) (Game x y) -- ^ Either a rogue datum & the corresponding error-message, or the resulting /game/.-{-# SPECIALISE applyEitherQualifiedMoves :: (a -> Either String (Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y)) -> Game Type.Length.X Type.Length.Y -> [a] -> Either (a, String) (Game Type.Length.X Type.Length.Y) #-}-applyEitherQualifiedMoves moveConstructor = Data.List.foldl' (+ -> Either (a, String) Game -- ^ Either a rogue datum & the corresponding error-message, or the resulting /game/.+applyEitherQualifiedMoves moveConstructor = Data.Foldable.foldl' ( \eitherGame datum -> eitherGame >>= ( \game -> Left . (,) datum {-Constructor failed-} ||| ( \eitherQualifiedMove -> Data.Maybe.maybe (@@ -890,18 +753,10 @@ * N.B.: it is considered valid to take a @King@, one just never has the opportunity, since the game terminates the move before. -}-validateQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Component.QualifiedMove.QualifiedMove x y- -> Game x y -- ^ Prior to playing the /qualified move/.+validateQualifiedMove+ :: Component.QualifiedMove.QualifiedMove+ -> Game -- ^ Prior to playing the /qualified move/. -> Maybe String -- ^ Error-message.-{-# SPECIALISE validateQualifiedMove :: Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Maybe String #-} validateQualifiedMove qualifiedMove game@MkGame { getNextLogicalColour = nextLogicalColour, getBoard = board,@@ -1092,26 +947,16 @@ (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move -- Deconstruct. maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board maybeDestinationPiece = State.MaybePieceByCoordinates.dereference destination maybePieceByCoordinates -- Query.-- distance :: Cartesian.Vector.VectorInt- distance = Component.Move.measureDistance move+ distance = Component.Move.measureDistance move isObstructed :: Bool isObstructed = State.MaybePieceByCoordinates.isObstructed source destination maybePieceByCoordinates -- | Validates the /move-type/ then forwards the request to 'validateQualifiedMove'.-validateEitherQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Component.EitherQualifiedMove.EitherQualifiedMove x y- -> Game x y -- ^ Prior to playing the /move/.+validateEitherQualifiedMove+ :: Component.EitherQualifiedMove.EitherQualifiedMove+ -> Game -- ^ Prior to playing the /move/. -> Maybe String -- ^ Error-message.-{-# SPECIALISE validateEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Maybe String #-} validateEitherQualifiedMove eitherQualifiedMove game@MkGame { getBoard = board } | State.MaybePieceByCoordinates.isVacant ( Component.Move.getSource move@@ -1130,27 +975,11 @@ ) maybePieceByCoordinates -- | Whether the specified /QualifiedMove/ is valid.-isValidQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Component.QualifiedMove.QualifiedMove x y -> Game x y -> Bool-{-# SPECIALISE isValidQualifiedMove :: Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-}+isValidQualifiedMove :: Component.QualifiedMove.QualifiedMove -> Game -> Bool isValidQualifiedMove qualifiedMove = Data.Maybe.isNothing . validateQualifiedMove qualifiedMove -- | Whether the specified /EitherQualifiedMove/ is valid.-isValidEitherQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Component.EitherQualifiedMove.EitherQualifiedMove x y -> Game x y -> Bool-{-# SPECIALISE isValidEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-}+isValidEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove -> Game -> Bool isValidEitherQualifiedMove eitherQualifiedMove = Data.Maybe.isNothing . validateEitherQualifiedMove eitherQualifiedMove {- |@@ -1158,15 +987,7 @@ * The list-head contains the most recent /ply/, while the tail contains the first. -}-rollBack :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Game x y -> [(Game x y, Component.Turn.Turn x y)]-{-# SPECIALISE rollBack :: Game Type.Length.X Type.Length.Y -> [(Game Type.Length.X Type.Length.Y, Component.Turn.Turn Type.Length.X Type.Length.Y)] #-}+rollBack :: Game -> [(Game, Component.Turn.Turn)] rollBack = Data.List.unfoldr ( \game@MkGame { getNextLogicalColour = nextLogicalColour,@@ -1216,7 +1037,7 @@ 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 = Data.Map.fromAscList [+ getAvailableQualifiedMovesByLogicalColour = Map.fromAscList [ (logicalColour, mkAvailableQualifiedMovesFor logicalColour game') | logicalColour <- Property.FixedMembership.members, maybeChecked' /= Just logicalColour@@ -1232,18 +1053,10 @@ * CAVEAT: to avoid an infinite loop, this doesn't check whether the game has already terminated. -}-listQualifiedMovesAvailableTo :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Attribute.LogicalColour.LogicalColour -- ^ Define the player for whom the moves are required.- -> Game x y- -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE listQualifiedMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-}+listQualifiedMovesAvailableTo+ :: Attribute.LogicalColour.LogicalColour -- ^ Define the player for whom the moves are required.+ -> Game+ -> [Component.QualifiedMove.QualifiedMove] listQualifiedMovesAvailableTo logicalColour game@MkGame { getBoard = board, getMaybeChecked = maybeChecked@@ -1333,19 +1146,11 @@ isSafeQualifiedMove qualifiedMove = not $ State.Board.exposesKing logicalColour (Component.QualifiedMove.getMove qualifiedMove) board -- | Construct 'AvailableQualifiedMoves' for the player of the specified /logical colour/.-mkAvailableQualifiedMovesFor :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Attribute.LogicalColour.LogicalColour -> Game x y -> AvailableQualifiedMoves x y-{-# SPECIALISE mkAvailableQualifiedMovesFor :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> AvailableQualifiedMoves Type.Length.X Type.Length.Y #-}+mkAvailableQualifiedMovesFor :: Attribute.LogicalColour.LogicalColour -> Game -> AvailableQualifiedMoves mkAvailableQualifiedMovesFor logicalColour = foldr {-maintains destination-order-} ( \qualifiedMove -> let move = Component.QualifiedMove.getMove qualifiedMove- in Data.Map.insertWith (++) (+ in Map.insertWith (++) ( Component.Move.getSource move -- Key. ) [ (@@ -1353,65 +1158,39 @@ Component.QualifiedMove.getMoveType qualifiedMove ) -- Pair. ] {-singleton-}- ) Data.Map.empty . listQualifiedMovesAvailableTo logicalColour+ ) Property.Empty.empty . listQualifiedMovesAvailableTo logicalColour {- | * Retrieve the recorded value, or generate the list of /move/s available to the player of the specified /logical colour/. * CAVEAT: doesn't account for game-termination. -}-findQualifiedMovesAvailableTo :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Attribute.LogicalColour.LogicalColour- -> Game x y- -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findQualifiedMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-}+findQualifiedMovesAvailableTo+ :: Attribute.LogicalColour.LogicalColour+ -> Game+ -> [Component.QualifiedMove.QualifiedMove] findQualifiedMovesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour }- | Just availableQualifiedMoves <- Data.Map.lookup logicalColour availableQualifiedMovesByLogicalColour = [+ | Just availableQualifiedMoves <- Map.lookup logicalColour availableQualifiedMovesByLogicalColour = [ Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) moveType |- (source, qualifiedDestinations) <- Data.Map.assocs availableQualifiedMoves,+ (source, qualifiedDestinations) <- Map.toList availableQualifiedMoves, (destination, moveType) <- qualifiedDestinations ] -- List-comprehension. | otherwise = listQualifiedMovesAvailableTo logicalColour game -- Generate the list of moves for this player. -- | Count the number of plies available to the specified player.-countPliesAvailableTo :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Attribute.LogicalColour.LogicalColour -> Game x y -> Type.Count.NPlies-{-# SPECIALISE countPliesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> Type.Count.NPlies #-}+countPliesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game -> Type.Count.NPlies countPliesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour } | isTerminated game = 0- | Just availableQualifiedMoves <- Data.Map.lookup logicalColour availableQualifiedMovesByLogicalColour -- N.B.: 'findQualifiedMovesAvailableToNextPlayer' unnecessarily constructs a list.--- = length $ Data.Foldable.concat availableQualifiedMoves -- CAVEAT: terrible performance.--- = Data.Map.foldl' (flip $ (+) . length) 0 availableQualifiedMoves -- CAVEAT: poor performance.- = fromIntegral $ Data.Map.Strict.foldl' (\acc -> (+ acc) . length) 0 availableQualifiedMoves- | otherwise = fromIntegral . length $ listQualifiedMovesAvailableTo logicalColour game+ | 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 -- | Retrieve the recorded value, or generate the list of /move/s available to the next player.-findQualifiedMovesAvailableToNextPlayer :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Game x y -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findQualifiedMovesAvailableToNextPlayer :: Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-}+findQualifiedMovesAvailableToNextPlayer :: Game -> [Component.QualifiedMove.QualifiedMove] findQualifiedMovesAvailableToNextPlayer game@MkGame { getNextLogicalColour = nextLogicalColour } = findQualifiedMovesAvailableTo nextLogicalColour game -- | Let the specified player resign.-resignationBy :: Attribute.LogicalColour.LogicalColour -> Transformation x y+resignationBy :: Attribute.LogicalColour.LogicalColour -> Transformation resignationBy logicalColour game | isTerminated game = game -- Already terminated. | otherwise = game {@@ -1419,11 +1198,11 @@ } -- | Resignation by the player who currently holds the choice of /move/.-resign :: Transformation x y+resign :: Transformation resign game@MkGame { getNextLogicalColour = nextLogicalColour } = resignationBy nextLogicalColour game -- | Agree to a draw.-agreeToADraw :: Transformation x y+agreeToADraw :: Transformation agreeToADraw game | isTerminated game = game -- Already terminated. | otherwise = game {@@ -1431,7 +1210,7 @@ } -- | Whether the game has been terminated.-isTerminated :: Game x y -> Bool+isTerminated :: Game -> Bool isTerminated MkGame { getMaybeTerminationReason = maybeTerminationReason } = Data.Maybe.isJust maybeTerminationReason {- |@@ -1439,15 +1218,7 @@ * N.B.: resignation isn't included, because it leaves no evidence on the board. -}-inferMaybeTerminationReason :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Game x y -> Maybe Rule.GameTerminationReason.GameTerminationReason-{-# SPECIALISE inferMaybeTerminationReason :: Game Type.Length.X Type.Length.Y -> Maybe Rule.GameTerminationReason.GameTerminationReason #-}+inferMaybeTerminationReason :: Game -> Maybe Rule.GameTerminationReason.GameTerminationReason inferMaybeTerminationReason game@MkGame { getBoard = board, getInstancesByPosition = instancesByPosition@@ -1468,13 +1239,13 @@ | otherwise = Nothing -- | Provided that the game hasn't already terminated, update the termination-reason according to whether the specified result implies either a /draw by agreement/ or a /resignation/.-updateTerminationReasonWith :: Rule.Result.Result -> Transformation x y+updateTerminationReasonWith :: Rule.Result.Result -> Transformation updateTerminationReasonWith result game | Just victorsLogicalColour <- Rule.Result.findMaybeVictor result = resignationBy (Property.Opposable.getOpposite victorsLogicalColour) game | otherwise = agreeToADraw game -- | Forwards request to "State.CastleableRooksByLogicalColour".-cantConverge :: Game x y -> Game x y -> Bool+cantConverge :: Game -> Game -> Bool cantConverge MkGame { getCastleableRooksByLogicalColour = castleableRooksByLogicalColour } MkGame {@@ -1482,13 +1253,7 @@ } = State.CastleableRooksByLogicalColour.cantConverge castleableRooksByLogicalColour castleableRooksByLogicalColour' -- | Constructor.-mkPosition :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Game x y -> State.Position.Position x y-{-# SPECIALISE mkPosition :: Game Type.Length.X Type.Length.Y -> State.Position.Position Type.Length.X Type.Length.Y #-}+mkPosition :: Game -> State.Position.Position mkPosition game@MkGame { getNextLogicalColour = nextLogicalColour, getBoard = board,@@ -1496,22 +1261,10 @@ } = State.Position.mkPosition nextLogicalColour (State.Board.getMaybePieceByCoordinates board) castleableRooksByLogicalColour $ maybeLastTurn game -- | Constructor. Count the instances of each repeatable /position/.-mkInstancesByPosition :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Game x y -> InstancesByPosition x y-{-# SPECIALISE mkInstancesByPosition :: Game Type.Length.X Type.Length.Y -> InstancesByPosition Type.Length.X Type.Length.Y #-}-mkInstancesByPosition = State.InstancesByPosition.mkInstancesByPosition . uncurry (- foldr $ flip (Data.Map.Strict.insertWith $ const succ) 1 . mkPosition . fst {-game-}- ) . (- (`Data.Map.Strict.singleton` 1) . mkPosition &&& takeWhile (- Component.Turn.getIsRepeatableMove . snd {-turn-}- ) . rollBack- )+mkInstancesByPosition :: Game -> InstancesByPosition+mkInstancesByPosition game = State.InstancesByPosition.mkInstancesByPosition mkPosition . (game :) . map fst {-game-} . takeWhile (+ Component.Turn.getIsRepeatableMove . snd {-turn-}+ ) $ rollBack game {- | * Whether the specified /game/'s /position/s have converged, & despite perhaps having reached this /position/ from different /move/-sequences, now have equal opportunities.@@ -1522,39 +1275,23 @@ * CAVEAT: though convenient, this function shouldn't be called for repeated tests against a constant /position/, resulting in unnecessary repeated construction of that /position/. -}-(=~) :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Game x y -> Game x y -> Bool-{-# SPECIALISE (=~) :: Game Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-}+(=~) :: Game -> Game -> Bool game =~ game' = mkPosition game == mkPosition game' -- | Whether the state of the specified /game/s is different.-(/~) :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Game x y -> Game x y -> Bool+(/~) :: Game -> Game -> Bool game /~ game' = not $ game =~ game' -- | Update the /position-hash/ of the /game/ prior to application of the last /move/.-updateIncrementalPositionHash :: (- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y- )- => Game x y -- ^ The /game/ before application of the last move.- -> positionHash -- ^ The value before application of the last move.- -> Game x y -- ^ The current game.- -> Component.Zobrist.Zobrist x y positionHash+updateIncrementalPositionHash+ :: Data.Bits.Bits positionHash+ => Game -- ^ The /game/ before application of the last move.+ -> positionHash -- ^ The value before application of the last move.+ -> Game -- ^ The current game.+ -> Component.Zobrist.Zobrist positionHash -> positionHash-{-# SPECIALISE updateIncrementalPositionHash :: Game Type.Length.X Type.Length.Y -> Type.Crypto.PositionHash -> Game Type.Length.X Type.Length.Y -> Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> Type.Crypto.PositionHash #-}-updateIncrementalPositionHash game positionHash game' zobrist = Component.Zobrist.combine positionHash . (++) randomsFromMoveType . (+{-# SPECIALISE updateIncrementalPositionHash :: Game -> Type.Crypto.PositionHash -> Game -> Component.Zobrist.Zobrist Type.Crypto.PositionHash -> Type.Crypto.PositionHash #-}+updateIncrementalPositionHash game positionHash game' zobrist = StateProperty.Hashable.combine positionHash . (++) randomsFromMoveType . ( let (castleableRooksByLogicalColour, castleableRooksByLogicalColour') = ($ game) &&& ($ game') $ getCastleableRooksByLogicalColour in if isCastle || castleableRooksByLogicalColour /= castleableRooksByLogicalColour'@@ -1571,7 +1308,7 @@ 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 <- Component.Zobrist.listRandoms1D enPassantAbscissa zobrist+ random <- StateProperty.Hashable.listRandoms enPassantAbscissa zobrist ] {-list-comprehension-} ++ Component.Zobrist.getRandomForBlacksMove zobrist : [ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (lastLogicalColour, rankAccessor turn, coordinatesAccessor move) zobrist | (rankAccessor, coordinatesAccessor) <- zip [Component.Turn.getRank, (`Data.Maybe.fromMaybe` Attribute.Rank.getMaybePromotionRank moveType) . Component.Turn.getRank] coordinatesAccessors
src-lib/BishBosh/Model/GameTree.hs view
@@ -70,7 +70,6 @@ import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Data.Default@@ -80,13 +79,13 @@ import qualified Data.Tree -- | Each node defines the state of the game.-type BareGameTree x y = Data.Tree.Tree (Model.Game.Game x y)+type BareGameTree = Data.Tree.Tree Model.Game.Game -- | Forwards request to 'Component.Turn.compareByMVVLVA'. compareByMVVLVA :: Attribute.Rank.EvaluateRank- -> BareGameTree x y- -> BareGameTree x y+ -> BareGameTree+ -> BareGameTree -> Ordering compareByMVVLVA evaluateRank Data.Tree.Node { Data.Tree.rootLabel = gameL } Data.Tree.Node { Data.Tree.rootLabel = gameR } = uncurry ( Component.Turn.compareByMVVLVA evaluateRank@@ -95,7 +94,7 @@ ) $ Data.Maybe.fromJust . Model.Game.maybeLastTurn -- | Get the last move responsible for the current position.-getLastMove :: BareGameTree x y -> Component.Move.Move x y+getLastMove :: BareGameTree -> Component.Move.Move {-# INLINE getLastMove #-} getLastMove Data.Tree.Node { Data.Tree.rootLabel = game } = Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove . Data.Maybe.fromJust $ Model.Game.maybeLastTurn game @@ -107,15 +106,14 @@ * CAVEAT: assumes that the battle continues until either player concludes it's disadvantageous to continue, or fire-power has been exhausted. -} staticExchangeEvaluation- :: (Eq x, Eq y)- => Attribute.Rank.EvaluateRank- -> BareGameTree x y+ :: Attribute.Rank.EvaluateRank+ -> BareGameTree -> Type.Mass.RankValue staticExchangeEvaluation evaluateRank node@Data.Tree.Node { Data.Tree.rootLabel = game } = Data.Maybe.maybe 0 {-nothing taken-} (slave node) $ getMaybeImplicitlyTakenRank game where -- Find the rank of any victim.- getMaybeImplicitlyTakenRank :: Model.Game.Game x y -> Maybe Attribute.Rank.Rank+ 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 x y -> 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 ( (@@ -137,30 +135,22 @@ ) . realToFrac . evaluateRank {-of victim-} -- | Accessor.-getRankAndMove :: Model.MoveFrequency.GetRankAndMove (BareGameTree x y) (Component.Move.Move x y)+getRankAndMove :: Model.MoveFrequency.GetRankAndMove BareGameTree Component.Move.Move {-# INLINE getRankAndMove #-} getRankAndMove Data.Tree.Node { Data.Tree.rootLabel = game } = (Component.Turn.getRank &&& Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove) . Data.Maybe.fromJust $ Model.Game.maybeLastTurn game -- | Wrap a 'BareGameTree'.-newtype GameTree x y = MkGameTree {- deconstruct :: BareGameTree x y+newtype GameTree = MkGameTree {+ deconstruct :: BareGameTree } deriving Show {-CAVEAT: required by QuickCheck, but shouldn't actually be called-} -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Data.Default.Default (GameTree x y) where- {-# SPECIALISE instance Data.Default.Default (GameTree Type.Length.X Type.Length.Y) #-}+instance Data.Default.Default GameTree where def = fromGame Data.Default.def -instance Property.Arboreal.Prunable (GameTree x y) where+instance Property.Arboreal.Prunable GameTree where prune depth MkGameTree { deconstruct = bareGameTree } = MkGameTree $ Property.Arboreal.prune depth bareGameTree -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotation (GameTree x y) where+instance Notation.MoveNotation.ShowNotation GameTree where showsNotation moveNotation MkGameTree { deconstruct = bareGameTree@Data.Tree.Node { Data.Tree.rootLabel = game,@@ -173,19 +163,11 @@ toString = Notation.MoveNotation.showNotation moveNotation . Data.Maybe.fromJust . Model.Game.maybeLastTurn -- | Constructor.-fromBareGameTree :: BareGameTree x y -> GameTree x y+fromBareGameTree :: BareGameTree -> GameTree fromBareGameTree = MkGameTree -- | Constructs a game-tree with the specified game at its root.-fromGame :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> GameTree x y-{-# SPECIALISE fromGame :: Model.Game.Game Type.Length.X Type.Length.Y -> GameTree Type.Length.X Type.Length.Y #-}+fromGame :: Model.Game.Game -> GameTree fromGame = MkGameTree . Data.Tree.unfoldTree ( \game -> ( game,@@ -203,25 +185,24 @@ * 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 Type.Length.X Type.Length.Y)+countGames depth = Data.RoseTree.countTerminalNodes . deconstruct $ Property.Arboreal.prune depth (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 Type.Length.X Type.Length.Y)+countPositions depth = fromIntegral . pred {-the apex is constructed without moving-} . Data.Foldable.length . deconstruct $ Property.Arboreal.prune depth (Data.Default.def :: GameTree) -- | Trace the route down the tree which matches the specified list of turns. traceRoute- :: (Eq x, Eq y)- => GameTree x y- -> [Component.Turn.Turn x y] -- ^ The data against which, nodes from the tree should be matched.- -> Maybe [Model.Game.Game x y] -- ^ Returns 'Nothing' on match-failure.+ :: GameTree+ -> [Component.Turn.Turn] -- ^ The data against which, nodes from the tree should be matched.+ -> Maybe [Model.Game.Game] -- ^ Returns 'Nothing' on match-failure. traceRoute MkGameTree { deconstruct = bareGameTree } = Data.RoseTree.traceRoute (\turn -> (== Just turn) . Model.Game.maybeLastTurn) bareGameTree -- | Focus the underlying type.-type MoveFrequency x y = Model.MoveFrequency.MoveFrequency (Component.Move.Move x y)+type MoveFrequency = Model.MoveFrequency.MoveFrequency Component.Move.Move -- | Self-documentation.-type Transformation x y = GameTree x y -> GameTree x y+type Transformation = GameTree -> GameTree {- | * Independently sorts the forest of moves at each node of the tree, without regard to runtime-data.@@ -231,12 +212,10 @@ * The above sort-algorithms are stable & can therefore be applied independently. -} sortGameTree- :: (Integral x, Integral y)- => Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm+ :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> Attribute.Rank.EvaluateRank- -> MoveFrequency x y- -> Transformation x y-{-# SPECIALISE sortGameTree :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> Attribute.Rank.EvaluateRank -> MoveFrequency Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-}+ -> MoveFrequency+ -> Transformation sortGameTree maybeCaptureMoveSortAlgorithm evaluateRank standardOpeningMoveFrequency MkGameTree { deconstruct = bareGameTree } = MkGameTree $ Data.RoseTree.mapForest ( \game -> Data.Maybe.maybe id ( \case@@ -260,7 +239,7 @@ Had the move-frequency been derived from a list of games, a different distribution would result, but then early moves would appear popular rather than just the consequence of limited choice. -}-toMoveFrequency :: (Ord x, Ord y) => GameTree x y -> MoveFrequency x y+toMoveFrequency :: GameTree -> MoveFrequency toMoveFrequency MkGameTree { deconstruct = bareGameTree } = slave maxBound {-logicalColour-} Property.Empty.empty {-MoveFrequency-} bareGameTree where slave _ moveFrequency Data.Tree.Node { Data.Tree.subForest = [] } = moveFrequency slave logicalColour moveFrequency Data.Tree.Node { Data.Tree.subForest = forest } = Data.List.foldl' (
src-lib/BishBosh/Model/MoveFrequency.hs view
@@ -22,7 +22,7 @@ [@DESCRIPTION@] - * The instances of various moves, categorised by /logical colour/ & /rank/, are recorded from a large resource of games.+ * The instances of various moves, categorised by /logical colour/ & /rank/, are recorded from recorded games. * The frequency-distribution can then be used to sort the moves in the current game, to prioritise evaluation of likely candidates. -}@@ -36,7 +36,7 @@ MoveFrequency(), -- * Functions countEntries,--- countDistinctEntries,+ countDistinctEntries, insertMoves, sortByDescendingMoveFrequency ) where@@ -51,7 +51,7 @@ import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map import qualified Data.Ord {- |@@ -61,7 +61,7 @@ -} type InstancesByMoveByRankByLogicalColour move = Attribute.LogicalColour.ArrayByLogicalColour ( Attribute.Rank.ArrayByRank (- Data.Map.Strict.Map move Type.Count.NPlies+ Map.Map move Type.Count.NPlies ) ) @@ -74,7 +74,7 @@ empty = MkMoveFrequency . Attribute.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.Map.Strict.null) instancesByMoveByRankByLogicalColour+ isNull MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.Foldable.all (Data.Foldable.all Data.Foldable.null) instancesByMoveByRankByLogicalColour -- | Count the total number of entries. countEntries :: MoveFrequency move -> Type.Count.NPlies@@ -82,10 +82,16 @@ Data.Foldable.foldl' $ \acc -> (acc +) . Data.Foldable.sum ) 0 instancesByMoveByRankByLogicalColour --- | Count the total number of distinct entries.+{- |+ * Count the total number of distinct entries.++ * N.B.: in this context, a distinct move is one which wasn't made in any other branch of the tree.+ E.g.: many recorded games will start with the same move, which becomes just one node in the game-tree from which this structure is derived, & so will only have a count of one in this structure.+ If this same move is also made subsequently (i.e. after a different opening), then it exists on a different branch of the tree, & increases the move's count to 2 but doesn't increase the number of distinct moves.+-} countDistinctEntries :: MoveFrequency move -> Type.Count.NPlies countDistinctEntries MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = fromIntegral $ Data.Foldable.foldl' (- Data.Foldable.foldl' $ \acc -> (acc +) . Data.Map.Strict.size+ Data.Foldable.foldl' $ \acc -> (acc +) . Data.Foldable.length ) 0 instancesByMoveByRankByLogicalColour -- | The type of a function which can extract the /rank/ & /move/ from a datum.@@ -124,7 +130,7 @@ ] -- List-comprehension. where instancesByMoveByRank = instancesByMoveByRankByLogicalColour ! logicalColour- incrementMoveCount = flip (Data.Map.Strict.insertWith (+)) 1+ incrementMoveCount = flip (Map.insertWith (+)) 1 {- | * Sorts an arbitrary list on the recorded frequency of the /rank/ & /move/ accessible from each list-item.@@ -140,6 +146,6 @@ -> [a] {-# INLINE sortByDescendingMoveFrequency #-} sortByDescendingMoveFrequency logicalColour getRankAndMove MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.List.sortOn $ negate {-most frequent first-} . (- \(rank, move) -> Data.Map.Strict.findWithDefault 0 move $ instancesByMoveByRankByLogicalColour ! logicalColour ! rank+ \(rank, move) -> Map.findWithDefault 0 move $ instancesByMoveByRankByLogicalColour ! logicalColour ! rank ) . getRankAndMove
src-lib/BishBosh/Model/PositionHashTree.hs view
@@ -38,12 +38,12 @@ import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Model.GameTree as Model.GameTree import qualified BishBosh.Property.Arboreal as Property.Arboreal+import qualified BishBosh.Property.Empty as Property.Empty+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.Default import qualified Data.List@@ -63,20 +63,15 @@ Data.Bits.FiniteBits positionHash, System.Random.Random positionHash ) => Data.Default.Default (PositionHashTree positionHash) where- def = mkPositionHashTree Data.Default.def (Data.Default.def :: Model.GameTree.GameTree Type.Length.X Type.Length.Y)+ def = mkPositionHashTree Data.Default.def (Data.Default.def :: Model.GameTree.GameTree) -- | Hash the specified 'game-tree/.-mkPositionHashTree :: (- Data.Array.IArray.Ix x,- Data.Bits.Bits positionHash,- Enum x,- Enum y,- Ord y- )- => Component.Zobrist.Zobrist x y positionHash- -> Model.GameTree.GameTree x y+mkPositionHashTree+ :: Data.Bits.Bits positionHash+ => Component.Zobrist.Zobrist positionHash+ -> Model.GameTree.GameTree -> PositionHashTree positionHash-mkPositionHashTree zobrist = MkPositionHashTree . fmap (`Component.Zobrist.hash2D` 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@@ -96,5 +91,5 @@ } = Data.Set.singleton hash -- Being unable to descend further, include the terminal game's hash. slave depth' Data.Tree.Node { Data.Tree.subForest = forest } = Data.List.foldl' ( \s -> Data.Set.union s . slave (pred depth') {-recurse-}- ) Data.Set.empty forest+ ) Property.Empty.empty forest
+ src-lib/BishBosh/Notation/Figurine.hs view
@@ -0,0 +1,61 @@+{-+ 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 translation between /piece/s & Unicode figurines; <https://en.wikipedia.org/wiki/Chess_symbols_in_Unicode>.+-}++module BishBosh.Notation.Figurine(+-- * Types+-- ** Type-synonyms+-- Figurine,+-- * Constants+-- figurinesByPiece,+-- piecesByFigurine,+-- * Functions+ toFigurine,+ fromFigurine+) where++import Data.Array.IArray((!))+import qualified BishBosh.Component.Piece as Component.Piece+import qualified Data.Array.IArray+import qualified Data.Map.Strict as Map+import qualified Data.Tuple++-- | A Unicode character depicting a piece.+type Figurine = Char++-- | The constant Unicode by which to depict each piece.+figurinesByPiece :: Component.Piece.ArrayByPiece Figurine+figurinesByPiece = Component.Piece.listArrayByPiece "\x265F\x265C\x265E\x265D\x265B\x265A\x2659\x2656\x2658\x2657\x2655\x2654"++-- | Returns the Unicode-character for the specified piece.+toFigurine :: Component.Piece.Piece -> Figurine+toFigurine = (figurinesByPiece !)++-- | The constant piece corresponding to each Unicode figurine.+piecesByFigurine :: Map.Map Figurine Component.Piece.Piece+piecesByFigurine = Map.fromList . map Data.Tuple.swap $ Data.Array.IArray.assocs figurinesByPiece++-- | Returns any piece which corresponds to the specified Unicode character.+fromFigurine :: Figurine -> Maybe Component.Piece.Piece+fromFigurine = (`Map.lookup` piecesByFigurine)+
src-lib/BishBosh/Notation/ICCFNumeric.hs view
@@ -31,40 +31,29 @@ -- getMaybePromotionRank ), -- * Constants- origin,--- xOriginOffset,--- yOriginOffset,+ notation, regexSyntax, toRank, -- * Functions--- encode,- showsCoordinates, -- ** Constructors mkICCFNumeric, mkICCFNumeric' ) where -import Control.Arrow((&&&), (***))+import Control.Arrow((&&&)) 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.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Notation.Notation as Notation.Notation import qualified Control.Arrow import qualified Control.Exception-import qualified Data.Char import qualified Data.List.Extra import qualified Data.Maybe import qualified Data.Tuple --- | The origin.-origin :: (Int, Int)-origin = Data.Char.ord &&& Data.Char.ord $ '1'---- | The offset of the application's internal coordinate-system from this conventional one.-xOriginOffset, yOriginOffset :: Int-(xOriginOffset, yOriginOffset) = (Cartesian.Abscissa.xOrigin -) *** (Cartesian.Ordinate.yOrigin -) $ origin+-- | Define the parameters of the notation, using the minimum permissible values for /x/ & /y/ coordinates.+notation :: Notation.Notation.Notation+notation = Notation.Notation.mkNotation $ (id &&& id) '1' -- | Defines using a regex, the required syntax. regexSyntax :: String@@ -80,16 +69,16 @@ ] -- | Defines a /move/, to enable i/o in /ICCF Numeric/-notation.-data ICCFNumeric x y = MkICCFNumeric {- getMove :: Component.Move.Move x y,+data ICCFNumeric = MkICCFNumeric {+ getMove :: Component.Move.Move, getMaybePromotionRank :: Maybe Attribute.Rank.Rank } deriving Eq -- | Smart constructor. mkICCFNumeric- :: Component.Move.Move x y+ :: Component.Move.Move -> Maybe Attribute.Rank.Rank -- ^ The optional promotion-rank.- -> ICCFNumeric x y+ -> ICCFNumeric mkICCFNumeric move maybePromotionRank | Just rank <- maybePromotionRank , rank `notElem` Attribute.Rank.promotionProspects = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Notation.ICCFNumeric.mkICCFNumeric:\tcan't promote to a " $ shows rank "."@@ -101,46 +90,27 @@ -- | Smart constructor. mkICCFNumeric' :: Attribute.Rank.Promotable promotable- => Component.Move.Move x y+ => Component.Move.Move -> promotable -- ^ The datum from which to extract the optional promotion-rank.- -> ICCFNumeric x y+ -> ICCFNumeric mkICCFNumeric' move = mkICCFNumeric move . Attribute.Rank.getMaybePromotionRank --- | Encodes the ordinate & abscissa.-encode :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> (ShowS, ShowS)-encode = showChar . Data.Char.chr . subtract xOriginOffset . fromEnum . Cartesian.Coordinates.getX &&& showChar . Data.Char.chr . subtract yOriginOffset . fromEnum . Cartesian.Coordinates.getY---- | Shows the specified /coordinates/.-showsCoordinates :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> ShowS-showsCoordinates = uncurry (.) . encode--instance (Enum x, Enum y) => Show (ICCFNumeric x y) where+instance Show ICCFNumeric where showsPrec _ MkICCFNumeric { getMove = move, getMaybePromotionRank = maybePromotionRank- } = showsCoordinates (+ } = Notation.Notation.showsCoordinates notation ( Component.Move.getSource move- ) . showsCoordinates (+ ) . Notation.Notation.showsCoordinates notation ( Component.Move.getDestination move ) . Data.Maybe.maybe id ( shows . Data.Maybe.fromJust . (`lookup` map Data.Tuple.swap toRank) ) maybePromotionRank -- N.B. this merely validates the syntax, leaving any semantic errors to 'Model.Game.validate'.-instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Read (ICCFNumeric x y) where+instance Read ICCFNumeric where readsPrec _ s = case Data.List.Extra.trimStart s of- x : y : x' : y' : remainder -> let- fromICCFNumeric x'' y'' = Cartesian.Coordinates.mkMaybeCoordinates (- toEnum $ Data.Char.ord x'' + xOriginOffset- ) (- toEnum $ Data.Char.ord y'' + yOriginOffset- )- in [+ x : y : x' : y' : remainder -> [ Control.Arrow.first ( mkICCFNumeric $ Component.Move.mkMove source destination ) (@@ -150,12 +120,13 @@ | otherwise -> (Nothing, remainder) _ -> (Nothing, remainder) ) |- source <- Data.Maybe.maybeToList $ fromICCFNumeric x y,- destination <- Data.Maybe.maybeToList $ fromICCFNumeric x' y',+ let mkCoordinatesList = Data.Maybe.maybeToList . Notation.Notation.mkMaybeCoordinates notation,+ source <- mkCoordinatesList (x, y),+ destination <- mkCoordinatesList (x', y'), source /= destination ] -- List-comprehension. _ -> [] -- No parse. -instance Attribute.Rank.Promotable (ICCFNumeric x y) where+instance Attribute.Rank.Promotable ICCFNumeric where getMaybePromotionRank = getMaybePromotionRank
src-lib/BishBosh/Notation/MoveNotation.hs view
@@ -41,6 +41,7 @@ readsQualifiedMove, showNotation, showsMoveSyntax,+ getNotation, getOrigin, showsNotationFloatToNDecimals, -- ** Predicates@@ -54,6 +55,7 @@ import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Notation.ICCFNumeric as Notation.ICCFNumeric+import qualified BishBosh.Notation.Notation as Notation.Notation import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate import qualified BishBosh.Notation.Smith as Notation.Smith import qualified BishBosh.Property.FixedMembership as Property.FixedMembership@@ -101,17 +103,10 @@ pureCoordinate = PureCoordinate -- | Reads a /move/ & /move-type/ from the specified 'MoveNotation'.-readsQualifiedMove :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => MoveNotation- -> ReadS (Component.EitherQualifiedMove.EitherQualifiedMove x y)-readsQualifiedMove ICCFNumeric = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkPartiallyQualifiedMove . (Notation.ICCFNumeric.getMove &&& Attribute.Rank.getMaybePromotionRank)) . reads+readsQualifiedMove :: MoveNotation -> ReadS Component.EitherQualifiedMove.EitherQualifiedMove+readsQualifiedMove ICCFNumeric = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkPartiallyQualifiedMove . (Notation.ICCFNumeric.getMove &&& Attribute.Rank.getMaybePromotionRank)) . reads readsQualifiedMove PureCoordinate = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkPartiallyQualifiedMove . (Notation.PureCoordinate.getMove &&& Attribute.Rank.getMaybePromotionRank)) . reads-readsQualifiedMove Smith = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkFullyQualifiedMove . (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) . Notation.Smith.getQualifiedMove) . reads+readsQualifiedMove Smith = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkFullyQualifiedMove . (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) . Notation.Smith.getQualifiedMove) . reads -- | Show the syntax required by a specific 'MoveNotation'. showsMoveSyntax :: MoveNotation -> ShowS@@ -122,11 +117,15 @@ Smith -> Notation.Smith.regexSyntax ) . showChar '/' +-- | Returns the notation-parameters.+getNotation :: MoveNotation -> Notation.Notation.Notation+getNotation ICCFNumeric = Notation.ICCFNumeric.notation+getNotation PureCoordinate = Notation.PureCoordinate.notation+getNotation Smith = Notation.Smith.notation+ -- | Returns the origin of the specified coordinate-system.-getOrigin :: MoveNotation -> (Int, Int)-getOrigin ICCFNumeric = Notation.ICCFNumeric.origin-getOrigin PureCoordinate = Notation.PureCoordinate.origin-getOrigin Smith = Notation.Smith.origin+getOrigin :: MoveNotation -> Notation.Notation.CoordinatePairI+getOrigin = Notation.Notation.getOrigin . getNotation -- | Predicate. isPureCoordinate :: MoveNotation -> Bool@@ -137,7 +136,7 @@ class ShowNotation a where showsNotation :: MoveNotation -> a -> ShowS -instance (Enum x, Enum y) => ShowNotation (Component.QualifiedMove.QualifiedMove x y) where+instance ShowNotation Component.QualifiedMove.QualifiedMove where showsNotation moveNotation qualifiedMove = case moveNotation of ICCFNumeric -> shows $ Notation.ICCFNumeric.mkICCFNumeric' move moveType PureCoordinate -> shows $ Notation.PureCoordinate.mkPureCoordinate' move moveType@@ -145,13 +144,11 @@ where (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ qualifiedMove -instance (Enum x, Enum y) => ShowNotation (Component.Turn.Turn x y) where+instance ShowNotation Component.Turn.Turn where showsNotation moveNotation = showsNotation moveNotation . Component.Turn.getQualifiedMove -instance (Enum x, Enum y) => ShowNotation (Cartesian.Coordinates.Coordinates x y) where- showsNotation ICCFNumeric = Notation.ICCFNumeric.showsCoordinates- showsNotation PureCoordinate = Notation.PureCoordinate.showsCoordinates- showsNotation Smith = Notation.Smith.showsCoordinates+instance ShowNotation Cartesian.Coordinates.Coordinates where+ showsNotation = Notation.Notation.showsCoordinates . getNotation -- | Show an arbitrary datum using the specified notation. showNotation :: (ShowNotation a) => MoveNotation -> a -> String
+ src-lib/BishBosh/Notation/Notation.hs view
@@ -0,0 +1,157 @@+{-+ 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@]++ * The common basis for standard notations.++ * CAVEAT: this module is only concerned with the representation of /x/ & /y/ coordinates, not any additional move-feature like enpassant, promotion or castling.++-}++module BishBosh.Notation.Notation(+-- * Types+-- ** Type-synonyms+-- CoordinatePairC,+ CoordinatePairI,+-- ** Data-types+ Notation(+-- MkNotation,+ getMinC,+ getMaxC,+ getOrigin,+ getOriginOffset+ ),+-- * Functions+ encode,+ mkMaybeCoordinates,+ showsCoordinates,+ readsCoordinates,+-- ** Constructors+ mkNotation,+-- ** Predicates+ inXRange,+ inYRange+-- inRange+) where++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.Data.Exception as Data.Exception+import qualified BishBosh.Type.Length as Type.Length+import qualified Control.Exception+import qualified Data.Char+import qualified Data.List.Extra+import qualified Data.Maybe++-- | The characters used in a standard notation to denote a 'CoordinatePairI'.+type CoordinatePairC = (Char, Char)++-- | A numeric representation of some coordinates in the standard notation.+type CoordinatePairI = (Type.Length.X, Type.Length.Y)++-- | The parameters defining a generic chess-notation.+data Notation = MkNotation {+ getMinC :: CoordinatePairC, -- ^ The character which a standard notation uses to represent the minimum value on each axis.+ getMaxC :: CoordinatePairC, -- ^ The character which a standard notation uses to represent the maximum value on each axis.+ getOrigin :: CoordinatePairI, -- ^ The numeric pair corresponding to the character-pair.+ getOriginOffset :: CoordinatePairI -- ^ The offset of the application's internal coordinate-system from a standard one.+}++-- | Smart constructor.+mkNotation :: CoordinatePairC -> Notation+mkNotation pair+ | not . uncurry (&&) $ (ok *** ok) pair = Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.Notation.Notation.mkNotation:\tASCII character required."+ | otherwise = notation+ where+ ok = uncurry (&&) . (Data.Char.isAscii &&& Data.Char.isAlphaNum)++ notation = MkNotation {+ getMinC = pair,+ getMaxC = (+ Data.Char.chr . fromIntegral . (+ + pred {-fence-post-} Cartesian.Abscissa.xLength+ ) *** Data.Char.chr . fromIntegral . (+ + pred {-fence-post-} Cartesian.Ordinate.yLength+ )+ ) $ getOrigin notation,+ getOrigin = (+ fromIntegral . Data.Char.ord *** fromIntegral . Data.Char.ord+ ) $ getMinC notation,+ getOriginOffset = (+ (Cartesian.Abscissa.xMin -) *** (Cartesian.Ordinate.yMin -)+ ) $ getOrigin notation+ }++-- | Whether the specified character falls within a standard notation's range.+inXRange :: Notation -> Char -> Bool+inXRange notation c = uncurry (&&) $ ((<= c) . fst {-x-} . getMinC &&& (>= c) . fst {-x-} . getMaxC) notation++-- | Whether the specified character falls within a standard notation's range.+inYRange :: Notation -> Char -> Bool+inYRange notation c = uncurry (&&) $ ((<= c) . snd {-y-} . getMinC &&& (>= c) . snd {-y-} . getMaxC) notation++-- | Whether the specified pair of characters fall within a standard notation's range.+inRange :: Notation -> CoordinatePairC -> Bool+inRange notation = uncurry (&&) . (+ uncurry (&&) . (+ (>= xMinC) &&& (<= xMaxC)+ ) *** uncurry (&&) . (+ (>= yMinC) &&& (<= yMaxC)+ )+ ) where+ ((xMinC, yMinC), (xMaxC, yMaxC)) = getMinC &&& getMaxC $ notation++-- | Encodes the ordinate & abscissa.+encode :: Notation -> Cartesian.Coordinates.Coordinates -> (ShowS, ShowS)+encode notation = showChar . Data.Char.chr . fromIntegral . subtract xOriginOffset . Cartesian.Coordinates.getX &&& showChar . Data.Char.chr . fromIntegral . subtract yOriginOffset . Cartesian.Coordinates.getY where+ (xOriginOffset, yOriginOffset) = getOriginOffset notation++{- |+ * Attempt to construct coordinates from the specified characters.++ * A check that the specified characters are in the permissible bounds is performed before conversion incase the numeric type has a narrower range than 'Char'.+-}+mkMaybeCoordinates :: Notation -> CoordinatePairC -> Maybe Cartesian.Coordinates.Coordinates+mkMaybeCoordinates notation pair+ | inRange notation pair = uncurry Cartesian.Coordinates.mkMaybeCoordinates $ (+ (+ xOriginOffset) . fromIntegral . Data.Char.ord *** (+ yOriginOffset) . fromIntegral . Data.Char.ord+ ) pair+ | otherwise = Nothing+ where+ (xOriginOffset, yOriginOffset) = getOriginOffset notation++-- | Shows the specified /coordinates/.+showsCoordinates :: Notation -> Cartesian.Coordinates.Coordinates -> ShowS+showsCoordinates notation = uncurry (.) . encode notation++-- | Reads coordinates.+readsCoordinates :: Notation -> ReadS Cartesian.Coordinates.Coordinates+readsCoordinates notation s = case Data.List.Extra.trimStart s of+ x : y : remainder+ | inRange notation coordinatePairC -> map (flip (,) remainder) . Data.Maybe.maybeToList $ mkMaybeCoordinates notation coordinatePairC+ | otherwise -> [] -- No parse.+ where+ coordinatePairC = (x, y)+ _ -> [] -- Mo parse.+
src-lib/BishBosh/Notation/PureCoordinate.hs view
@@ -40,19 +40,11 @@ -- getMaybePromotionRank ), -- * Constants--- min',--- xMin,--- xMax,--- yMin,--- yMax,- origin,+ notation, -- xOriginOffset, -- yOriginOffset, regexSyntax, -- * Functions- encode,- showsCoordinates,- readsCoordinates, abscissaParser, ordinateParser, coordinatesParser,@@ -60,18 +52,14 @@ mkPureCoordinate, mkPureCoordinate' -- ** Predicates--- inXRange,--- inYRange ) where -import Control.Arrow((&&&), (***))-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.Component.Move as Component.Move-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.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Notation.Notation as Notation.Notation+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Control.Exception import qualified Data.Char@@ -80,44 +68,26 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# else+# error "USE_POLYPARSE invalid"+# endif #else /* Parsec */ import qualified Text.ParserCombinators.Parsec as Parsec import Text.ParserCombinators.Parsec((<?>)) #endif --- | The minimum permissible values for /x/ & /y/ coordinates.-min' :: (Char, Char)-xMin, yMin :: Char-min'@(xMin, yMin) = ('a', '1')---- | The origin of the coordinate-system.-origin :: (Int, Int)-origin = Data.Char.ord *** Data.Char.ord $ min'+-- | Define the parameters of the notation, using the minimum permissible values for /x/ & /y/ coordinates.+notation :: Notation.Notation.Notation+notation = Notation.Notation.mkNotation ('a', '1') -- | The offset of the application's internal coordinate-system from this conventional one.-xOriginOffset, yOriginOffset :: Int-(xOriginOffset, yOriginOffset) = (Cartesian.Abscissa.xOrigin -) *** (Cartesian.Ordinate.yOrigin -) $ origin---- | The maximum permissible values for /x/ & /y/ coordinates.-xMax, yMax :: Char-(xMax, yMax) = Data.Char.chr . (- + pred {-fence-post-} (fromIntegral Cartesian.Abscissa.xLength)- ) *** Data.Char.chr . (- + pred {-fence-post-} (fromIntegral Cartesian.Ordinate.yLength)- ) $ origin---- | Whether the specified character is a valid abscissa.-inXRange :: Char -> Bool-inXRange = uncurry (&&) . ((>= xMin) &&& (<= xMax))---- | Whether the specified character is a valid ordinate.-inYRange :: Char -> Bool-inYRange = uncurry (&&) . ((>= yMin) &&& (<= yMax))+xOriginOffset :: Type.Length.X+yOriginOffset :: Type.Length.Y+(xOriginOffset, yOriginOffset) = Notation.Notation.getOriginOffset notation -- | Defines using a regex, the required syntax. regexSyntax :: String@@ -127,27 +97,15 @@ #ifdef USE_POLYPARSE -- | Parse an /x/-coordinate.-abscissaParser :: Enum x => Text.Poly.TextParser x-{-# SPECIALISE abscissaParser :: Text.Poly.TextParser Type.Length.X #-}-abscissaParser = (- toEnum . (+ xOriginOffset) . Data.Char.ord- ) `fmap` Poly.satisfyMsg inXRange "Abscissa"+abscissaParser :: Text.Poly.TextParser Type.Length.X+abscissaParser = ((+ xOriginOffset) . fromIntegral . Data.Char.ord) `fmap` Poly.satisfyMsg (Notation.Notation.inXRange notation) "Abscissa" -- | Parse a /y/-coordinate.-ordinateParser :: Enum y => Text.Poly.TextParser y-{-# SPECIALISE ordinateParser :: Text.Poly.TextParser Type.Length.Y #-}-ordinateParser = (- toEnum . (+ yOriginOffset) . Data.Char.ord- ) `fmap` Poly.satisfyMsg inYRange "Ordinate"+ordinateParser :: Text.Poly.TextParser Type.Length.Y+ordinateParser = ((+ yOriginOffset) . fromIntegral . Data.Char.ord) `fmap` Poly.satisfyMsg (Notation.Notation.inYRange notation) "Ordinate" -- | Parse a pair of /coordinates/.-coordinatesParser :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Text.Poly.TextParser (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE coordinatesParser :: Text.Poly.TextParser (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) #-}+coordinatesParser :: Text.Poly.TextParser Cartesian.Coordinates.Coordinates coordinatesParser = do x <- abscissaParser y <- ordinateParser@@ -155,37 +113,29 @@ return {-to Parser-monad-} $ Cartesian.Coordinates.mkCoordinates x y #else /* Parsec */ -- | Parse an /x/-coordinate.-abscissaParser :: Enum x => Parsec.Parser x-{-# SPECIALISE abscissaParser :: Parsec.Parser Type.Length.X #-}-abscissaParser = toEnum . (+ xOriginOffset) . Data.Char.ord <$> Parsec.satisfy inXRange <?> "Abscissa"+abscissaParser :: Parsec.Parser Type.Length.X+abscissaParser = (+ xOriginOffset) . fromIntegral . Data.Char.ord <$> Parsec.satisfy (Notation.Notation.inXRange notation) <?> "Abscissa" -- | Parse a /y/-coordinate.-ordinateParser :: Enum y => Parsec.Parser y-{-# SPECIALISE ordinateParser :: Parsec.Parser Type.Length.X #-}-ordinateParser = toEnum . (+ yOriginOffset) . Data.Char.ord <$> Parsec.satisfy inYRange <?> "Ordinate"+ordinateParser :: Parsec.Parser Type.Length.Y+ordinateParser = (+ yOriginOffset) . fromIntegral . Data.Char.ord <$> Parsec.satisfy (Notation.Notation.inYRange notation) <?> "Ordinate" -- | Parse a pair of /coordinates/.-coordinatesParser :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Parsec.Parser (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE coordinatesParser :: Parsec.Parser (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) #-}+coordinatesParser :: Parsec.Parser Cartesian.Coordinates.Coordinates coordinatesParser = Cartesian.Coordinates.mkCoordinates <$> abscissaParser <*> ordinateParser #endif -- | Defines a /move/, to enable i/o in /PureCoordinate/-notation.-data PureCoordinate x y = MkPureCoordinate {- getMove :: Component.Move.Move x y,+data PureCoordinate = MkPureCoordinate {+ getMove :: Component.Move.Move, getMaybePromotionRank :: Maybe Attribute.Rank.Rank } deriving Eq -- | Smart constructor. mkPureCoordinate- :: Component.Move.Move x y+ :: Component.Move.Move -> Maybe Attribute.Rank.Rank -- ^ The optional promotion-rank.- -> PureCoordinate x y+ -> PureCoordinate mkPureCoordinate move maybePromotionRank | Just rank <- maybePromotionRank , rank `notElem` Attribute.Rank.promotionProspects = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Notation.PureCoordinate.mkPureCoordinate:\tcan't promote to a " $ shows rank "."@@ -197,61 +147,25 @@ -- | Smart constructor. mkPureCoordinate' :: Attribute.Rank.Promotable promotable- => Component.Move.Move x y+ => Component.Move.Move -> promotable -- ^ The datum from which to extract the optional promotion-rank.- -> PureCoordinate x y+ -> PureCoordinate mkPureCoordinate' move = mkPureCoordinate move . Attribute.Rank.getMaybePromotionRank --- | Encodes the ordinate & abscissa.-encode :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> (ShowS, ShowS)-encode = showChar . Data.Char.chr . subtract xOriginOffset . fromEnum . Cartesian.Coordinates.getX &&& showChar . Data.Char.chr . subtract yOriginOffset . fromEnum . Cartesian.Coordinates.getY---- | Shows the specified /coordinates/.-showsCoordinates :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> ShowS-showsCoordinates = uncurry (.) . encode---- | Reads coordinates.-readsCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => ReadS (Cartesian.Coordinates.Coordinates x y)-readsCoordinates s = case Data.List.Extra.trimStart s of- x : y : remainder -> map (- flip (,) remainder- ) . Data.Maybe.maybeToList $ Cartesian.Coordinates.mkMaybeCoordinates (- toEnum $ Data.Char.ord x + xOriginOffset- ) (- toEnum $ Data.Char.ord y + yOriginOffset- )- _ -> [] -- Mo parse.--instance (Enum x, Enum y) => Show (PureCoordinate x y) where+instance Show PureCoordinate where showsPrec _ MkPureCoordinate { getMove = move, getMaybePromotionRank = maybePromotionRank- } = showsCoordinates (+ } = Notation.Notation.showsCoordinates notation ( Component.Move.getSource move- ) . showsCoordinates (+ ) . Notation.Notation.showsCoordinates notation ( Component.Move.getDestination move ) . Data.Maybe.maybe id shows maybePromotionRank -- N.B. this merely validates the syntax, leaving any semantic errors to 'Model.Game.validate'.-instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Read (PureCoordinate x y) where+instance Read PureCoordinate where readsPrec _ s = case Data.List.Extra.trimStart s of- x : y : x' : y' : remainder -> let- translate x'' y'' = Cartesian.Coordinates.mkMaybeCoordinates (- toEnum $ Data.Char.ord x'' + xOriginOffset- ) (- toEnum $ Data.Char.ord y'' + yOriginOffset- )- in [+ x : y : x' : y' : remainder -> [ Control.Arrow.first ( mkPureCoordinate $ Component.Move.mkMove source destination ) (@@ -261,12 +175,13 @@ else (Nothing, remainder) _ -> (Nothing, remainder) ) |- source <- Data.Maybe.maybeToList $ translate x y,- destination <- Data.Maybe.maybeToList $ translate x' y',+ let mkCoordinatesList = Data.Maybe.maybeToList . Notation.Notation.mkMaybeCoordinates notation,+ source <- mkCoordinatesList (x, y),+ destination <- mkCoordinatesList (x', y'), source /= destination ] -- List-comprehension. _ -> [] -- No parse. -instance Attribute.Rank.Promotable (PureCoordinate x y) where+instance Attribute.Rank.Promotable PureCoordinate where getMaybePromotionRank = getMaybePromotionRank
src-lib/BishBosh/Notation/Smith.hs view
@@ -30,77 +30,75 @@ getQualifiedMove ), -- * Constants- origin,--- xOriginOffset,--- yOriginOffset,+ notation,+-- enpassantTag,+-- shortCastleTag,+-- longCastleTag, regexSyntax, -- * Functions--- encode,- showsCoordinates, -- ** Constructor fromQualifiedMove ) where -import Control.Arrow((&&&), (***))+import Control.Arrow((&&&)) 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.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Notation.Notation as Notation.Notation+import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate import qualified Control.Arrow import qualified Data.Char import qualified Data.Default import qualified Data.List.Extra import qualified Data.Maybe --- | The origin.-origin :: (Int, Int)-origin = ($ 'a') &&& ($ '1') $ Data.Char.ord+-- | Define the parameters of the notation, using the minimum permissible values for /x/ & /y/ coordinates.+notation :: Notation.Notation.Notation+notation = Notation.PureCoordinate.notation -- CAVEAT: the encoding of coordinates is only coincidentally identical. --- | The offset of the application's internal coordinate-system from this conventional one.-xOriginOffset, yOriginOffset :: Int-(xOriginOffset, yOriginOffset) = (Cartesian.Abscissa.xOrigin -) *** (Cartesian.Ordinate.yOrigin -) $ origin+-- | Token.+enpassantTag :: Char+enpassantTag = 'E' +-- | Token.+shortCastleTag :: Char+shortCastleTag = 'c'++-- | Token.+longCastleTag :: Char+longCastleTag = 'C'+ -- | Defines using a regex, the required syntax. regexSyntax :: String regexSyntax = showString "([a-h][1-8]){2}[" . showString ( concatMap show Attribute.Rank.range- ) . showString "EcC]?[" $ showString (- Data.List.Extra.upper $ map (head . show) Attribute.Rank.promotionProspects+ ) . showChar enpassantTag . showChar shortCastleTag . showChar longCastleTag . showString "]?[" $ showString (+ Data.List.Extra.upper $ concatMap show Attribute.Rank.promotionProspects ) "]?" -- | Defines a /move/, to enable i/o in /Smith/-notation.-newtype Smith x y = MkSmith {- getQualifiedMove :: Component.QualifiedMove.QualifiedMove x y+newtype Smith = MkSmith {+ getQualifiedMove :: Component.QualifiedMove.QualifiedMove } deriving Eq -- | Constructor.-fromQualifiedMove :: Component.QualifiedMove.QualifiedMove x y -> Smith x y+fromQualifiedMove :: Component.QualifiedMove.QualifiedMove -> Smith fromQualifiedMove = MkSmith --- | Encodes the ordinate & abscissa.-encode :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> (ShowS, ShowS)-encode = showChar . Data.Char.chr . subtract xOriginOffset . fromEnum . Cartesian.Coordinates.getX &&& showChar . Data.Char.chr . subtract yOriginOffset . fromEnum . Cartesian.Coordinates.getY---- | Shows the specified /coordinates/.-showsCoordinates :: (Enum x, Enum y) => Cartesian.Coordinates.Coordinates x y -> ShowS-showsCoordinates = uncurry (.) . encode--instance (Enum x, Enum y) => Show (Smith x y) where+instance Show Smith where showsPrec _ MkSmith { getQualifiedMove = qualifiedMove } = let (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ qualifiedMove- in showsCoordinates (+ in Notation.Notation.showsCoordinates notation ( Component.Move.getSource move- ) . showsCoordinates (+ ) . Notation.Notation.showsCoordinates notation ( Component.Move.getDestination move ) . ( case moveType of Attribute.MoveType.Castle isShort -> showChar $ if isShort- then 'c'- else 'C'- Attribute.MoveType.EnPassant -> showChar 'E'+ then shortCastleTag+ else longCastleTag+ Attribute.MoveType.EnPassant -> showChar enpassantTag _ {-normal-} -> Data.Maybe.maybe id shows ( Attribute.MoveType.getMaybeExplicitlyTakenRank moveType ) . Data.Maybe.maybe id (@@ -111,26 +109,16 @@ ) -- N.B. this merely validates the syntax, leaving any semantic errors to 'Model.Game.validate'.-instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Read (Smith x y) where+instance Read Smith where readsPrec _ s = case Data.List.Extra.trimStart s of- x : y : x' : y' : remainder -> let- fromSmith x'' y'' = Cartesian.Coordinates.mkMaybeCoordinates (- toEnum $ Data.Char.ord x'' + xOriginOffset- ) (- toEnum $ Data.Char.ord y'' + yOriginOffset- )- in [+ x : y : x' : y' : remainder -> [ ( fromQualifiedMove $ Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) moveType, remainder' ) |- source <- Data.Maybe.maybeToList $ fromSmith x y,- destination <- Data.Maybe.maybeToList $ fromSmith x' y',+ let mkCoordinatesList = Data.Maybe.maybeToList . Notation.Notation.mkMaybeCoordinates notation,+ source <- mkCoordinatesList (x, y),+ destination <- mkCoordinatesList (x', y'), source /= destination, (moveType, remainder') <- case remainder of [] -> [(Data.Default.def, remainder)]@@ -157,6 +145,6 @@ ] -- List-comprehension. _ -> [] -- No parse. -instance Attribute.Rank.Promotable (Smith x y) where+instance Attribute.Rank.Promotable Smith where getMaybePromotionRank MkSmith { getQualifiedMove = qualifiedMove } = Attribute.Rank.getMaybePromotionRank $ Component.QualifiedMove.getMoveType qualifiedMove
src-lib/BishBosh/Property/Empty.hs view
@@ -33,12 +33,13 @@ Empty(..) ) where -import qualified Data.IntMap-import qualified Data.Map+import qualified Data.IntMap as IntMap+import qualified Data.Map as Map+import qualified Data.Set -- | An interface which data which can support the concept of being empty, may implement. class Empty a where- empty :: a -- ^ Constant.+ empty :: a -- ^ A constant empty state. instance (Empty a, Empty b) => Empty (a, b) where empty = (empty, empty)@@ -49,9 +50,12 @@ instance Empty [a] where empty = [] -instance Empty (Data.Map.Map i e) where- empty = Data.Map.empty+instance Empty (IntMap.IntMap e) where+ empty = IntMap.empty -instance Empty (Data.IntMap.IntMap e) where- empty = Data.IntMap.empty+instance Empty (Map.Map i e) where+ empty = Map.empty++instance Empty (Data.Set.Set i) where+ empty = Data.Set.empty
src-lib/BishBosh/Property/ExtendedPositionDescription.hs view
@@ -25,10 +25,15 @@ -} module BishBosh.Property.ExtendedPositionDescription(+-- * Types+-- ** Type-synonyms+ EPD, -- * Type-classes ReadsEPD(..), ShowsEPD(..), -- * Constants+ tag,+ rankSeparator, showsNullField, showsSeparator, -- * Functions@@ -44,14 +49,25 @@ class ShowsEPD a where showsEPD :: a -> ShowS -- ^ Stringify a EPD-datum. +-- | Self-documentation.+type EPD = String++-- | Input-format.+tag :: String+tag = "epd"++-- | The delimiter between each row of data.+rankSeparator :: Char+rankSeparator = '/'+ -- | Read from EPD.-readEPD :: ReadsEPD a => String -> a-readEPD s = case readsEPD s of+readEPD :: ReadsEPD a => EPD -> a+readEPD epd = case readsEPD epd of [(a, _)] -> a- _ -> error . showString "BishBosh.Property.ExtendedPositionDescription.readEPD:\tfailed to parse " $ shows s "."+ _ -> error . showString "BishBosh.Property.ExtendedPositionDescription.readEPD:\tfailed to parse " $ shows epd "." -- | Display in EPD.-showEPD :: ShowsEPD a => a -> String+showEPD :: ShowsEPD a => a -> EPD showEPD a = showsEPD a "" -- | The standard way to denote the absence of a field.
src-lib/BishBosh/Property/ForsythEdwards.hs view
@@ -27,6 +27,9 @@ -} module BishBosh.Property.ForsythEdwards(+-- * Types+-- ** Type-synonyms+-- FEN, -- * Type-classes ReadsFEN(..), ShowsFEN(..),@@ -47,13 +50,16 @@ showsFEN :: a -> ShowS -- ^ Stringify a FEN-datum. showsFEN = Property.ExtendedPositionDescription.showsEPD -- Default implementation. +-- | Self-documentation.+type FEN = String+ -- | Read from FEN.-readFEN :: ReadsFEN a => String -> a-readFEN s = case readsFEN s of+readFEN :: ReadsFEN a => FEN -> a+readFEN fen = case readsFEN fen of [(a, _)] -> a- _ -> error . showString "BishBosh.Property.ForsythEdwards.readFEN:\tfailed to parse " $ shows s "."+ _ -> error . showString "BishBosh.Property.ForsythEdwards.readFEN:\tfailed to parse " $ shows fen "." -- | Display in FEN.-showFEN :: ShowsFEN a => a -> String+showFEN :: ShowsFEN a => a -> FEN showFEN a = showsFEN a ""
src-lib/BishBosh/Property/Null.hs view
@@ -33,5 +33,5 @@ -- | An interface for data which can support the concept of being null. class Null a where- isNull :: a -> Bool -- ^ Predicate, cf. 'Prelude.null' for a 'Prelude.Foldable'.+ isNull :: a -> Bool -- ^ Predicate. N.B.: similar to 'Data.Foldable.null', but for unfoldable types.
src-lib/BishBosh/Property/Opposable.hs view
@@ -27,9 +27,14 @@ Opposable(..) ) where -import Prelude()+import Prelude(Ordering(..)) -- | An interface which data which have the concept of an opposite, may implement. class Opposable a where getOpposite :: a -> a++instance Opposable Ordering where+ getOpposite LT = GT+ getOpposite GT = LT+ getOpposite _ = EQ
src-lib/BishBosh/Search/AlphaBeta.hs view
@@ -65,7 +65,6 @@ import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Control.Monad.Reader import qualified Data.Default@@ -73,10 +72,10 @@ import qualified Data.Tree -- | The type returned by 'negaMax'.-data Result x y positionHash = MkResult {- getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData x y positionHash, -- ^ Killer moves & transpositions.- getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y,- getNPositionsEvaluated :: Type.Count.NPositions -- ^ The total number of nodes analysed, before making the selection.+data Result positionHash = MkResult {+ 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. } {- |@@ -86,8 +85,8 @@ -} extractSelectedTurns :: Type.Count.NPlies- -> Result x y positionHash- -> (Search.DynamicMoveData.DynamicMoveData x y positionHash, [Component.Turn.Turn x y], Type.Count.NPositions)+ -> Result positionHash+ -> (Search.DynamicMoveData.DynamicMoveData positionHash, [Component.Turn.Turn], Type.Count.NPositions) extractSelectedTurns nPlies MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = quantifiedGame,@@ -99,16 +98,7 @@ ) -- | Record the last move as a killer, unless it's a capture move.-updateKillerMoves :: (- Ord x,- Ord y,- Enum x,- Enum y,- Show x,- Show y- )- => Model.Game.Game x y- -> Search.DynamicMoveData.Transformation x y positionHash+updateKillerMoves :: Model.Game.Game -> Search.DynamicMoveData.Transformation positionHash updateKillerMoves game | Just lastTurn <- Model.Game.maybeLastTurn game = if Component.Turn.isCapture lastTurn then id -- This move was (assuming appropriate Search-options) statically sorted.@@ -122,17 +112,10 @@ * CAVEAT: the return-value, is quantified from the perspective of the player who is about to move. -}-findTranspositionTerminalQuantifiedGame :: (- Eq x,- Eq y,- Enum x,- Enum y,- Show x,- Show y- )- => Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash- -> Search.TranspositionValue.TranspositionValue (Component.QualifiedMove.QualifiedMove x y)- -> Evaluation.QuantifiedGame.QuantifiedGame x y+findTranspositionTerminalQuantifiedGame+ :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash+ -> 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" $ ( Notation.MoveNotation.showsNotationFloatToNDecimals Data.Default.def {-move-notation-} 3 {-decimal digits-} $ Property.Arboreal.prune (fromIntegral inferredSearchDepth) positionHashQuantifiedGameTree@@ -147,21 +130,14 @@ inferredSearchDepth = Search.TranspositionValue.inferSearchDepth transpositionValue -- | Record a qualifiedMove-sequence in the transposition-table.-updateTranspositions :: (- Eq x,- Eq y,- Enum x,- Enum y,- Ord positionHash,- Show x,- Show y- )+updateTranspositions+ :: Ord positionHash => Search.TranspositionValue.IsOptimal -> Type.Count.NPlies -> positionHash- -> [Component.Turn.Turn x y]- -> Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash- -> Search.DynamicMoveData.Transformation x y positionHash+ -> [Component.Turn.Turn]+ -> Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash+ -> Search.DynamicMoveData.Transformation positionHash updateTranspositions isOptimal nPlies positionHash turns positionHashQuantifiedGameTree = Search.DynamicMoveData.updateTranspositions . Search.Transpositions.insert ( Evaluation.QuantifiedGame.getFitness . findTranspositionTerminalQuantifiedGame positionHashQuantifiedGameTree ) positionHash {-the hash of the game before the first move in the sequence-} . Search.TranspositionValue.mkTranspositionValue isOptimal nPlies $ map Component.Turn.getQualifiedMove turns@@ -173,19 +149,12 @@ * /beta/ is the maximum fitness of which the minimising player is assured. -}-negaMax :: (- Enum x,- Enum y,- Ord positionHash,- Ord x,- Ord y,- Show x,- Show y- )+negaMax+ :: Ord positionHash => Type.Count.NPlies -- ^ The depth to which the tree should be searched; i.e. the number of plies to look-ahead.- -> Search.SearchState.SearchState x y positionHash- -> Input.SearchOptions.Reader (Result x y positionHash)-{-# SPECIALISE negaMax :: Type.Count.NPlies -> Search.SearchState.SearchState Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> Input.SearchOptions.Reader (Result Type.Length.X Type.Length.Y Type.Crypto.PositionHash) #-}+ -> Search.SearchState.SearchState positionHash+ -> Input.SearchOptions.Reader (Result positionHash)+{-# SPECIALISE negaMax :: Type.Count.NPlies -> Search.SearchState.SearchState Type.Crypto.PositionHash -> Input.SearchOptions.Reader (Result Type.Crypto.PositionHash) #-} negaMax initialSearchDepth initialSearchState = do maybeMinimumTranspositionSearchDepth <- Control.Monad.Reader.asks Input.SearchOptions.maybeMinimumTranspositionSearchDepth recordKillerMoves <- Control.Monad.Reader.asks Input.SearchOptions.recordKillerMoves@@ -195,10 +164,10 @@ getNPlies = State.TurnsByLogicalColour.getNPlies . Model.Game.getTurnsByLogicalColour -- Abbreviate. {- descend- :: Evaluation.QuantifiedGame.OpenInterval x y+ :: Evaluation.QuantifiedGame.OpenInterval -> Type.Count.NPlies- -> Search.SearchState.SearchState x y positionHash- -> Result x y positionHash+ -> Search.SearchState.SearchState positionHash+ -> Result positionHash -} descend (maybeAlphaQuantifiedGame, maybeBetaQuantifiedGame) searchDepth searchState | searchDepth == 0 || Model.Game.isTerminated game = MkResult {@@ -255,10 +224,10 @@ ) . Data.Tree.subForest $ Evaluation.PositionHashQuantifiedGameTree.deconstruct positionHashQuantifiedGameTree {- selectMax- :: Search.DynamicMoveData.DynamicMoveData x y positionHash- -> Maybe (Evaluation.QuantifiedGame.QuantifiedGame x y)- -> [Evaluation.PositionHashQuantifiedGameTree.BarePositionHashQuantifiedGameTree x y positionHash]- -> Result x y positionHash+ :: Search.DynamicMoveData.DynamicMoveData positionHash+ -> Maybe Evaluation.QuantifiedGame.QuantifiedGame+ -> [Evaluation.PositionHashQuantifiedGameTree.BarePositionHashQuantifiedGameTree positionHash]+ -> Result positionHash -} selectMax dynamicMoveData' maybeAlphaQuantifiedGame' (node : remainingNodes) | trapRepeatedPositions@@ -343,16 +312,16 @@ ) $ descend Evaluation.QuantifiedGame.unboundedInterval initialSearchDepth initialSearchState -- | The type of a function which transforms the result.-type Transformation x y positionHash = Result x y positionHash -> Result x y positionHash+type Transformation positionHash = Result positionHash -> Result positionHash -- | Mutator.-negateFitnessOfResult :: Transformation x y positionHash+negateFitnessOfResult :: Transformation positionHash negateFitnessOfResult result@MkResult { getQuantifiedGame = quantifiedGame } = result { getQuantifiedGame = Evaluation.QuantifiedGame.negateFitness quantifiedGame } -- | Mutator.-addNPositionsToResult :: Type.Count.NPositions -> Transformation x y positionHash+addNPositionsToResult :: Type.Count.NPositions -> Transformation positionHash addNPositionsToResult nPositions result@MkResult { getNPositionsEvaluated = nPositionsEvaluated } = Control.Exception.assert (nPositions > 0) result { getNPositionsEvaluated = nPositions + nPositionsEvaluated }
src-lib/BishBosh/Search/DynamicMoveData.hs view
@@ -59,36 +59,36 @@ * CAVEAT: there's still ambiguity in this /key/, since it may match either a different piece of the same /rank/ or have a different /move-type/ (though typically only quiet moves are recorded), in sibling games. -}-data KillerMoveKey x y = MkKillerMoveKey (Component.Move.Move x y) Attribute.Rank.Rank deriving (Eq, Ord, Show)+data KillerMoveKey = MkKillerMoveKey Component.Move.Move Attribute.Rank.Rank deriving (Eq, Ord, Show) -- | Constructor.-mkKillerMoveKeyFromTurn :: Component.Turn.Turn x y -> KillerMoveKey x y+mkKillerMoveKeyFromTurn :: Component.Turn.Turn -> KillerMoveKey mkKillerMoveKeyFromTurn = uncurry MkKillerMoveKey . (Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove &&& Component.Turn.getRank) -- | The data on /move/s, gathered while searching.-data DynamicMoveData x y positionHash = MkDynamicMoveData {- getKillerMoves :: Search.KillerMoves.KillerMoves (KillerMoveKey x y),- getTranspositions :: Search.Transpositions.Transpositions (Component.QualifiedMove.QualifiedMove x y) positionHash -- ^ N.B. a qualifiedMove is used to additionally record any promotion-rank.+data DynamicMoveData positionHash = MkDynamicMoveData {+ getKillerMoves :: Search.KillerMoves.KillerMoves KillerMoveKey,+ getTranspositions :: Search.Transpositions.Transpositions Component.QualifiedMove.QualifiedMove positionHash -- ^ N.B. a qualifiedMove is used to additionally record any promotion-rank. } -instance Property.Empty.Empty (DynamicMoveData x y positionHash) where+instance Property.Empty.Empty (DynamicMoveData positionHash) where empty = MkDynamicMoveData { getKillerMoves = Property.Empty.empty, getTranspositions = Property.Empty.empty } -- | The type of a function which transforms the dynamic move-data.-type Transformation x y positionHash = DynamicMoveData x y positionHash -> DynamicMoveData x y positionHash+type Transformation positionHash = DynamicMoveData positionHash -> DynamicMoveData positionHash -- | Mutator.-updateKillerMoves :: Search.KillerMoves.Transformation (KillerMoveKey x y) -> Transformation x y positionHash+updateKillerMoves :: Search.KillerMoves.Transformation KillerMoveKey -> Transformation positionHash updateKillerMoves f dynamicMoveData@MkDynamicMoveData { getKillerMoves = killerMoves } = dynamicMoveData { getKillerMoves = f killerMoves } -- | Mutator.-updateTranspositions :: Search.Transpositions.Transformation (Component.QualifiedMove.QualifiedMove x y) positionHash -> Transformation x y positionHash+updateTranspositions :: Search.Transpositions.Transformation Component.QualifiedMove.QualifiedMove positionHash -> Transformation positionHash updateTranspositions f dynamicMoveData@MkDynamicMoveData { getTranspositions = transpositions } = dynamicMoveData { getTranspositions = f transpositions } -instance Search.EphemeralData.MaybeEphemeralData (DynamicMoveData x y positionHash) where+instance Search.EphemeralData.MaybeEphemeralData (DynamicMoveData positionHash) where maybeEuthanise nPlies maybeRetireKillerMovesAfter maybeRetireTranspositionsAfter MkDynamicMoveData { getKillerMoves = killerMoves, getTranspositions = transpositions
src-lib/BishBosh/Search/KillerMoves.hs view
@@ -43,9 +43,9 @@ import qualified BishBosh.Type.Count as Type.Count import qualified Data.Array.IArray import qualified Data.Foldable-import qualified Data.IntMap.Strict+import qualified Data.IntMap.Strict as IntMap import qualified Data.List-import qualified Data.Map+import qualified Data.Map as Map import qualified Data.Maybe {- |@@ -55,8 +55,8 @@ & the logical colour of the player making the move. -} type NInstancesByNPliesByKeyByLogicalColour killerMoveKey = Attribute.LogicalColour.ArrayByLogicalColour (- Data.Map.Map killerMoveKey (- Data.IntMap.Strict.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.+ 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. ) ) @@ -70,15 +70,15 @@ instance Search.EphemeralData.EphemeralData (KillerMoves killerMoveKey) where getSize MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = fromIntegral $ Data.Foldable.foldl' (- Data.Map.foldl' $ Data.IntMap.Strict.foldl' (+)+ Data.Foldable.foldl' $ Data.Foldable.foldl' (+) ) 0 nInstancesByNPliesByKeyByLogicalColour euthanise nPlies killerMoves@MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } | nPlies <= 0 = killerMoves -- This might occur at the start of the game, because the caller subtracts a fixed value from the current number of plies. | otherwise = MkKillerMoves $ Data.Array.IArray.amap (- Data.Map.mapMaybe $ \m -> let- m' = Data.IntMap.Strict.filterWithKey (\nPlies' _ -> nPlies' > fromIntegral nPlies) m- in if Data.IntMap.Strict.null m'+ Map.mapMaybe $ \m -> let+ m' = IntMap.filterWithKey (\nPlies' _ -> nPlies' > fromIntegral nPlies) m+ in if Data.Foldable.null m' then Nothing else Just m' ) nInstancesByNPliesByKeyByLogicalColour@@ -93,10 +93,10 @@ -> killerMoveKey -> Transformation killerMoveKey insert nPlies killerMoveKey MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = MkKillerMoves $ nInstancesByNPliesByKeyByLogicalColour // [- id &&& Data.Map.insertWith (- Data.IntMap.Strict.unionWith (+)+ id &&& Map.insertWith (+ IntMap.unionWith (+) ) killerMoveKey (- Data.IntMap.Strict.singleton (fromIntegral nPlies) 1+ IntMap.singleton (fromIntegral nPlies) 1 ) . ( nInstancesByNPliesByKeyByLogicalColour ! ) $ if even nPlies@@ -114,8 +114,8 @@ -> [a] {-# INLINABLE sortByHistoryHeuristic #-} sortByHistoryHeuristic logicalColour killerMoveKeyConstructor MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = Data.List.sortOn $ Data.Maybe.maybe 0 (- negate {-largest first-} . Data.IntMap.Strict.foldl' (+) 0+ negate {-largest first-} . Data.Foldable.foldl' (+) 0 ) . (- `Data.Map.lookup` (nInstancesByNPliesByKeyByLogicalColour ! logicalColour)+ `Map.lookup` (nInstancesByNPliesByKeyByLogicalColour ! logicalColour) ) . killerMoveKeyConstructor
src-lib/BishBosh/Search/Search.hs view
@@ -54,27 +54,26 @@ import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Count as Type.Count import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Control.Exception import qualified Control.Monad.Reader import qualified Data.Maybe -- | The type returned by 'search'.-data Result x y positionHash = MkResult {- getSearchState :: Search.SearchState.SearchState x y positionHash,- getQuantifiedGames :: [Evaluation.QuantifiedGame.QuantifiedGame x y], -- ^ The optimal path down the /positionHashQuantifiedGameTree/.- getNPositionsEvaluated :: Type.Count.NPositions -- ^ The total number of nodes in the /positionHashQuantifiedGameTree/ which were analysed.+data Result positionHash = MkResult {+ getSearchState :: Search.SearchState.SearchState positionHash,+ getQuantifiedGames :: [Evaluation.QuantifiedGame.QuantifiedGame], -- ^ The optimal path down the /positionHashQuantifiedGameTree/.+ getNPositionsEvaluated :: Type.Count.NPositions -- ^ The total number of nodes in the /positionHashQuantifiedGameTree/ which were analysed. } -instance Control.DeepSeq.NFData (Result x y positionHash) where+instance Control.DeepSeq.NFData (Result positionHash) where rnf MkResult { getQuantifiedGames = quantifiedGames } = Control.DeepSeq.rnf quantifiedGames -- CAVEAT: don't evaluate the search-state, since this contains the PositionHashQuantifiedGameTree ! -- | Used to format output. showsSeparator :: ShowS showsSeparator = showString " -> " -instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (Result x y positionHash) where+instance Notation.MoveNotation.ShowNotationFloat (Result positionHash) where showsNotationFloat moveNotation showsDouble result@MkResult { getQuantifiedGames = quantifiedGames, getNPositionsEvaluated = nPositionsEvaluated@@ -87,18 +86,11 @@ ) -- | Smart constructor.-mkResult :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Search.SearchState.SearchState x y positionHash- -> [Evaluation.QuantifiedGame.QuantifiedGame x y]+mkResult+ :: Search.SearchState.SearchState positionHash+ -> [Evaluation.QuantifiedGame.QuantifiedGame] -> Type.Count.NPositions- -> Result x y positionHash+ -> Result positionHash mkResult searchState quantifiedGames nPositionsEvaluated | null quantifiedGames = Control.Exception.throw . Data.Exception.mkNullDatum . showString "BishBosh.Search.Search.mkResult:\tnull quantifiedGames; " $ shows game "." | nPositionsEvaluated < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Search.Search.mkResult:\tnPositionsEvaluated=" . shows nPositionsEvaluated . showString " mustn't be negative; " $ shows game "."@@ -111,19 +103,12 @@ game = Evaluation.QuantifiedGame.getGame . Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame $ Search.SearchState.getPositionHashQuantifiedGameTree searchState -- | Initiates the recursive function 'Search.AlphaBeta.negaMax', then unpacks the results.-search :: (- Enum x,- Enum y,- Ord positionHash,- Ord x,- Ord y,- Show x,- Show y- )+search+ :: Ord positionHash => Type.Count.NPlies -- ^ How deep down the tree to search.- -> Search.SearchState.SearchState x y positionHash- -> Input.SearchOptions.Reader (Result x y positionHash)-{-# SPECIALISE search :: Type.Count.NPlies -> Search.SearchState.SearchState Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> Input.SearchOptions.Reader (Result Type.Length.X Type.Length.Y Type.Crypto.PositionHash) #-}+ -> Search.SearchState.SearchState positionHash+ -> Input.SearchOptions.Reader (Result positionHash)+{-# SPECIALISE search :: Type.Count.NPlies -> Search.SearchState.SearchState Type.Crypto.PositionHash -> Input.SearchOptions.Reader (Result Type.Crypto.PositionHash) #-} search 0 _ = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Search.Search.search:\t" . shows Input.SearchOptions.searchDepthTag . showString " must be at least " $ shows Input.SearchOptions.minimumSearchDepth "." search searchDepth searchState | Just terminationReason <- Model.Game.getMaybeTerminationReason game = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Search.Search.search:\tthe game has already terminated; " $ shows terminationReason "."@@ -154,7 +139,7 @@ game = Evaluation.QuantifiedGame.getGame $ Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame positionHashQuantifiedGameTree -- | Calculate the geometric-mean of the number of plies evaluated at each node.-calculateBranchingFactor :: Floating branchingFactor => Result x y positionHash -> branchingFactor+calculateBranchingFactor :: Floating branchingFactor => Result positionHash -> branchingFactor calculateBranchingFactor MkResult { getQuantifiedGames = quantifiedGames, getNPositionsEvaluated = nPositionsEvaluated
src-lib/BishBosh/Search/SearchState.hs view
@@ -46,23 +46,23 @@ import qualified Control.Exception -- | The data which is both received & returned by 'Search.Search.search', so that it is transported through the entire game.-data SearchState x y positionHash = MkSearchState {- getPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash,- getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData x y positionHash+data SearchState positionHash = MkSearchState {+ getPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash,+ getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData positionHash } -instance Show (SearchState x y positionHash) where+instance Show (SearchState positionHash) where show _ = "SearchState {...}" -- | Constructor. mkSearchState- :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash- -> Search.DynamicMoveData.DynamicMoveData x y positionHash- -> SearchState x y positionHash+ :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash+ -> Search.DynamicMoveData.DynamicMoveData positionHash+ -> SearchState positionHash mkSearchState = MkSearchState -- | Smart constructor.-initialise :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> SearchState x y positionHash+initialise :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree positionHash -> SearchState positionHash initialise positionHashQuantifiedGameTree | Model.Game.isTerminated game = Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.Search.SearchState.initialise:\tcan't search for a move from a terminated game." | otherwise = MkSearchState {@@ -72,7 +72,7 @@ where game = Evaluation.QuantifiedGame.getGame $ Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame positionHashQuantifiedGameTree -instance Search.EphemeralData.MaybeEphemeralData (SearchState x y positionHash) where+instance Search.EphemeralData.MaybeEphemeralData (SearchState positionHash) where maybeEuthanise nPlies maybeRetireKillerMovesAfter maybeRetireTranspositionsAfter searchState@MkSearchState { getDynamicMoveData = dynamicMoveData } = searchState { getDynamicMoveData = Search.EphemeralData.maybeEuthanise nPlies maybeRetireKillerMovesAfter maybeRetireTranspositionsAfter dynamicMoveData -- Forward the request. }
src-lib/BishBosh/Search/Transpositions.hs view
@@ -43,20 +43,21 @@ import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Search.EphemeralData as Search.EphemeralData import qualified BishBosh.Search.TranspositionValue as Search.TranspositionValue-import qualified Data.Map+import qualified Data.Foldable+import qualified Data.Map as Map import qualified Data.Maybe -- | Stores the result of an alpha-beta search from a /position/. newtype Transpositions qualifiedMove positionHash = MkTranspositions {- deconstruct :: Data.Map.Map positionHash (Search.TranspositionValue.TranspositionValue qualifiedMove)+ deconstruct :: Map.Map positionHash (Search.TranspositionValue.TranspositionValue qualifiedMove) } instance Property.Empty.Empty (Transpositions qualifiedMove positionHash) where empty = MkTranspositions Property.Empty.empty instance Search.EphemeralData.EphemeralData (Transpositions qualifiedMove positionHash) where- getSize MkTranspositions { deconstruct = byPositionHash } = Data.Map.size byPositionHash- euthanise nPlies MkTranspositions { deconstruct = byPositionHash } = MkTranspositions $ Data.Map.filter ((> nPlies) . Search.TranspositionValue.getNPlies) byPositionHash+ getSize MkTranspositions { deconstruct = byPositionHash } = Data.Foldable.length byPositionHash+ euthanise nPlies MkTranspositions { deconstruct = byPositionHash } = MkTranspositions $ Map.filter ((> nPlies) . Search.TranspositionValue.getNPlies) byPositionHash -- | Returns any value previously recorded when searching from the specified /position/. find@@ -64,7 +65,7 @@ => positionHash -> Transpositions qualifiedMove positionHash -> Maybe (Search.TranspositionValue.TranspositionValue qualifiedMove)-find positionHash MkTranspositions { deconstruct = byPositionHash } = Data.Map.lookup positionHash byPositionHash+find positionHash MkTranspositions { deconstruct = byPositionHash } = Map.lookup positionHash byPositionHash -- | The type of a function which transforms 'Transpositions'. type Transformation qualifiedMove positionHash = Transpositions qualifiedMove positionHash -> Transpositions qualifiedMove positionHash@@ -80,7 +81,7 @@ -> positionHash -- ^ Represents the game from which the sequence of qualifiedMoves starts. -> Search.TranspositionValue.TranspositionValue qualifiedMove -- ^ The value to record. -> Transformation qualifiedMove positionHash-insert findFitness positionHash proposedValue MkTranspositions { deconstruct = byPositionHash } = MkTranspositions $ Data.Map.alter (+insert findFitness positionHash proposedValue MkTranspositions { deconstruct = byPositionHash } = MkTranspositions $ Map.alter ( Data.Maybe.maybe (Just proposedValue) {-there's no incumbent-} $ \incumbentValue -> if Search.TranspositionValue.isBetter findFitness proposedValue incumbentValue then Just proposedValue -- Upgrade. else Nothing -- Leave incumbent.
src-lib/BishBosh/State/Board.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}+{-# LANGUAGE CPP, FlexibleContexts #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -73,10 +73,10 @@ 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.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.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription@@ -87,18 +87,19 @@ 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.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray import qualified Data.Default+import qualified Data.Foldable import qualified Data.List-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified ToolShed.Data.List @@ -107,38 +108,30 @@ #endif -- | The type of a function which transforms a /board/.-type Transformation x y = Board x y -> Board x y+type Transformation = Board -> Board -- | The number of defenders for each /piece/, belonging to each side.-type NDefendersByCoordinatesByLogicalColour x y = Attribute.LogicalColour.ArrayByLogicalColour (Data.Map.Strict.Map (Cartesian.Coordinates.Coordinates x y) Type.Count.NPieces)+type NDefendersByCoordinatesByLogicalColour = Attribute.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/. * For efficiency some ancillary structures are also maintained. -}-data Board x y = MkBoard {- getMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates x y, -- ^ Defines any /piece/ currently located at each /coordinate/.- getCoordinatesByRankByLogicalColour :: State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour x y, -- ^ The /coordinates/ of each /piece/.- getNDefendersByCoordinatesByLogicalColour :: NDefendersByCoordinatesByLogicalColour x y, -- ^ The number of defenders of each /piece/, indexed by /logical colour/ & then by /coordinates/.+data Board = MkBoard {+ getMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates, -- ^ Defines any /piece/ currently located at each /coordinate/.+ getCoordinatesByRankByLogicalColour :: State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour, -- ^ The /coordinates/ of each /piece/.+ getNDefendersByCoordinatesByLogicalColour :: NDefendersByCoordinatesByLogicalColour, -- ^ The number of defenders of each /piece/, indexed by /logical colour/ & then by /coordinates/. getNPiecesDifferenceByRank :: StateProperty.Censor.NPiecesByRank, -- ^ The difference in the number of /piece/s of each /rank/ held by either side. @White@ /piece/s are arbitrarily considered positive & @Black@ ones negative.- getNPawnsByFileByLogicalColour :: State.CoordinatesByRankByLogicalColour.NPiecesByFileByLogicalColour x, -- ^ The number of @Pawn@s of each /logical colour/, for each /file/.+ getNPawnsByFileByLogicalColour :: StateProperty.Seeker.NPiecesByFileByLogicalColour, -- ^ The number of @Pawn@s of each /logical colour/, for each /file/. getNPieces :: Type.Count.NPieces, -- ^ The total number of pieces on the board, including @Pawn@s.- getPassedPawnCoordinatesByLogicalColour :: State.CoordinatesByRankByLogicalColour.CoordinatesByLogicalColour x y -- ^ The /coordinates/ of any /passed/ @Pawn@s.+ getPassedPawnCoordinatesByLogicalColour :: State.CoordinatesByRankByLogicalColour.CoordinatesByLogicalColour -- ^ The /coordinates/ of any /passed/ @Pawn@s. } -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Eq (Board x y) where+instance Eq Board where MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } == MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates' } = maybePieceByCoordinates == maybePieceByCoordinates' -- N.B.: the remaining fields are implied. -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Board x y) where+instance Control.DeepSeq.NFData Board where rnf MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour,@@ -157,129 +150,55 @@ passedPawnCoordinatesByLogicalColour ) -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Read (Board x y) where- {-# SPECIALISE instance Read (Board Type.Length.X Type.Length.Y) #-}+instance Read Board where readsPrec _ = Property.ForsythEdwards.readsFEN -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Show (Board x y) where+instance Show Board where showsPrec _ = Property.ForsythEdwards.showsFEN -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ExtendedPositionDescription.ReadsEPD (Board x y) where- {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Board Type.Length.X Type.Length.Y) #-}+instance Property.ExtendedPositionDescription.ReadsEPD Board where readsEPD = map (Control.Arrow.first fromMaybePieceByCoordinates) . Property.ExtendedPositionDescription.readsEPD -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ExtendedPositionDescription.ShowsEPD (Board x y) where+instance Property.ExtendedPositionDescription.ShowsEPD Board where showsEPD MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = Property.ExtendedPositionDescription.showsEPD maybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ForsythEdwards.ReadsFEN (Board x y) where- {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Board Type.Length.X Type.Length.Y) #-}+instance Property.ForsythEdwards.ReadsFEN Board where readsFEN = Property.ExtendedPositionDescription.readsEPD -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ForsythEdwards.ShowsFEN (Board x y)+instance Property.ForsythEdwards.ShowsFEN Board -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Data.Default.Default (Board x y) where- {-# SPECIALISE instance Data.Default.Default (Board Type.Length.X Type.Length.Y) #-}+instance Data.Default.Default Board where def = fromMaybePieceByCoordinates Data.Default.def {-MaybePieceByCoordinates-} -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Reflectable.ReflectableOnX (Board x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Board Type.Length.X Type.Length.Y) #-}+instance Property.Empty.Empty Board where+ empty = fromMaybePieceByCoordinates Property.Empty.empty {-MaybePieceByCoordinates-}++instance Property.Reflectable.ReflectableOnX Board where reflectOnX MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ Property.Reflectable.reflectOnX maybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Reflectable.ReflectableOnY (Board x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnY (Board Type.Length.X Type.Length.Y) #-}+instance Property.Reflectable.ReflectableOnY Board where reflectOnY MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ Property.Reflectable.reflectOnY maybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Empty.Empty (Board x y) where- {-# SPECIALISE empty :: Board Type.Length.X Type.Length.Y #-}- empty = fromMaybePieceByCoordinates Property.Empty.empty {-MaybePieceByCoordinates-}+instance StateProperty.Hashable.Hashable Board where+ listRandoms MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Hashable.listRandoms coordinatesByRankByLogicalColour -instance (Enum x, Enum y, Ord x, Ord y) => Component.Zobrist.Hashable2D Board x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms2D MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = Component.Zobrist.listRandoms2D coordinatesByRankByLogicalColour+instance StateProperty.Mutator.Mutator Board where+ defineCoordinates maybePiece coordinates MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ StateProperty.Mutator.defineCoordinates maybePiece coordinates maybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Seeker.Seeker Board x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker Board Type.Length.X Type.Length.Y #-}+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.--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Mutator.Mutator Board x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Mutator.Mutator Board Type.Length.X Type.Length.Y #-}- defineCoordinates maybePiece coordinates MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ StateProperty.Mutator.defineCoordinates maybePiece coordinates maybePieceByCoordinates+ countPawnsByFileByLogicalColour MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour -- Forward the request. -- | Constructor.-fromMaybePieceByCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => State.MaybePieceByCoordinates.MaybePieceByCoordinates x y -> Board x y-{-# SPECIALISE fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Board Type.Length.X Type.Length.Y #-}+fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates -> Board fromMaybePieceByCoordinates maybePieceByCoordinates = board where board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = State.CoordinatesByRankByLogicalColour.fromMaybePieceByCoordinates maybePieceByCoordinates, -- Infer. getNDefendersByCoordinatesByLogicalColour = countDefendersByCoordinatesByLogicalColour board, -- Infer. getNPiecesDifferenceByRank = StateProperty.Censor.countPieceDifferenceByRank coordinatesByRankByLogicalColour, -- Infer.- getNPawnsByFileByLogicalColour = State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour, -- Infer.+ getNPawnsByFileByLogicalColour = StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour, -- Infer. getNPieces = StateProperty.Censor.countPieces coordinatesByRankByLogicalColour, -- Infer. getPassedPawnCoordinatesByLogicalColour = State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour coordinatesByRankByLogicalColour -- Infer. }@@ -291,18 +210,10 @@ * CAVEAT: /castling/ must be implemented by making two calls. -}-movePiece :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Component.Move.Move x y -- ^ N.B.: illegal moves are acceptable.+movePiece+ :: Component.Move.Move -- ^ N.B.: illegal moves are acceptable. -> Maybe Attribute.MoveType.MoveType -- ^ N.B.: this may not be available to the caller, for example during the illegal moves required for rollback.- -> Transformation x y-{-# SPECIALISE movePiece :: Component.Move.Move Type.Length.X Type.Length.Y -> Maybe Attribute.MoveType.MoveType -> Transformation Type.Length.X Type.Length.Y #-}+ -> Transformation movePiece move maybeMoveType board@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour,@@ -310,41 +221,37 @@ getNPiecesDifferenceByRank = nPiecesDifferenceByRank, getNPieces = nPieces }- | Just sourcePiece <- State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates = let- logicalColour = Component.Piece.getLogicalColour sourcePiece+ | Just sourcePiece <- State.MaybePieceByCoordinates.dereference source maybePieceByCoordinates = let+ oppositePiece = Property.Opposable.getOpposite sourcePiece+ (logicalColour, opponentsLogicalColour) = ($ sourcePiece) &&& ($ oppositePiece) $ Component.Piece.getLogicalColour moveType :: Attribute.MoveType.MoveType- moveType -- CAVEAT: one can't call 'State.MaybePieceByCoordinates.inferMoveType', since that performs some validation of the move, which isn't the role of this module.+ 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. | otherwise = Attribute.MoveType.mkNormalMoveType (- Component.Piece.getRank `fmap` State.MaybePieceByCoordinates.dereference destination maybePieceByCoordinates+ Component.Piece.getRank <$> State.MaybePieceByCoordinates.dereference destination maybePieceByCoordinates ) $ if Component.Piece.isPawnPromotion destination sourcePiece then Just Attribute.Rank.defaultPromotionRank else Nothing -- Derive the required values from moveType.+ (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 | Attribute.MoveType.isEnPassant moveType = Left $ Cartesian.Coordinates.retreat logicalColour destination- | otherwise = Right $ Attribute.MoveType.getMaybeExplicitlyTakenRank moveType-- maybePromotionRank :: Maybe Attribute.Rank.Rank- maybePromotionRank = Attribute.Rank.getMaybePromotionRank moveType+ | otherwise = Right maybeExplicitlyTakenRank - destinationPiece :: Component.Piece.Piece- destinationPiece = Data.Maybe.maybe id Component.Piece.promote maybePromotionRank sourcePiece+ eitherPassingPawnsDestinationOrMaybeTakenPiece = fmap (Component.Piece.mkPiece opponentsLogicalColour) <$> 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,- getNDefendersByCoordinatesByLogicalColour = let- oppositePiece = Property.Opposable.getOpposite sourcePiece- opponentsLogicalColour = Component.Piece.getLogicalColour oppositePiece- eitherPassingPawnsDestinationOrMaybeTakenPiece = fmap (Component.Piece.mkPiece opponentsLogicalColour) `fmap` eitherPassingPawnsDestinationOrMaybeTakenRank-- in (+ getNDefendersByCoordinatesByLogicalColour = ( \(nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates) -> Attribute.LogicalColour.listArrayByLogicalColour [nBlackDefendersByCoordinates, nWhiteDefendersByCoordinates] ) . foldr ( \(affectedCoordinates, affectedPiece) -> if Component.Piece.isKing affectedPiece@@ -355,7 +262,7 @@ if Attribute.LogicalColour.isBlack logicalColour' then Control.Arrow.first else Control.Arrow.second- ) . Data.Map.Strict.insert affectedCoordinates {-overwrite-} . fromIntegral . length $ findAttackersOf (+ ) . Map.insert affectedCoordinates {-overwrite-} . fromIntegral . length $ findAttackersOf ( Property.Opposable.getOpposite logicalColour' -- Investigate an attack on the affected coordinates by the affected piece's own logical colour, i.e. defence. ) affectedCoordinates board' ) (@@ -365,29 +272,29 @@ in ( \passingPawnsDestination -> (:) ( opponentsLogicalColour,- Data.Map.Strict.delete passingPawnsDestination nDefendersByCoordinates -- This Pawn has been taken.+ Map.delete passingPawnsDestination nDefendersByCoordinates -- This Pawn has been taken. ) ) ||| (- \maybeExplicitlyTakenRank -> if Data.Maybe.isJust maybeExplicitlyTakenRank+ \maybeExplicitlyTakenRank' -> if Data.Maybe.isJust maybeExplicitlyTakenRank' then (:) ( opponentsLogicalColour,- Data.Map.Strict.delete destination nDefendersByCoordinates -- This piece has been taken.+ Map.delete destination nDefendersByCoordinates -- This piece has been taken. ) else id ) $ eitherPassingPawnsDestinationOrMaybeTakenRank ) [ ( logicalColour,- Data.Map.Strict.delete source $ nDefendersByCoordinatesByLogicalColour ! logicalColour -- This piece has been moved.+ Map.delete source $ nDefendersByCoordinatesByLogicalColour ! logicalColour -- This piece has been moved. ) -- Pair. ] -- Singleton. ) . Data.List.nubBy ( ToolShed.Data.List.equalityBy fst {-coordinates-} ) $ [ (affectedCoordinates, affectedPiece) |- (knightsCoordinates, knight) <- (source, sourcePiece) : map ((,) destination) (destinationPiece : either (const []) Data.Maybe.maybeToList eitherPassingPawnsDestinationOrMaybeTakenPiece),+ (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 :: [Cartesian.Vector.VectorInt]),+ Just affectedCoordinates <- Cartesian.Vector.maybeTranslate knightsCoordinates `map` Cartesian.Vector.attackVectorsForKnight, affectedPiece <- Data.Maybe.maybeToList $ State.MaybePieceByCoordinates.dereference affectedCoordinates maybePieceByCoordinates', Component.Piece.isFriend knight affectedPiece ] {-list-comprehension-} ++ [@@ -448,9 +355,7 @@ then [(Attribute.Rank.Pawn, 1)] -- Increment relative number of Pawns. else Data.Maybe.maybe id ( (:) . flip (,) 1 -- Increment.- ) (- Attribute.MoveType.getMaybeExplicitlyTakenRank moveType- ) $ Data.Maybe.maybe [] (+ ) maybeExplicitlyTakenRank $ Data.Maybe.maybe [] ( \promotionRank -> [ ( promotionRank,@@ -461,14 +366,12 @@ ) ] ) maybePromotionRank,- getNPawnsByFileByLogicalColour = if Component.Piece.isPawn sourcePiece && (- Cartesian.Coordinates.getX source /= Cartesian.Coordinates.getX destination {-includes En-passant-} || Attribute.MoveType.isPromotion moveType- ) || Attribute.MoveType.getMaybeExplicitlyTakenRank moveType == Just Attribute.Rank.Pawn- then State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour'+ getNPawnsByFileByLogicalColour = if Component.Piece.isPawn sourcePiece && not (Attribute.MoveType.isQuiet moveType) || wasPawnTakenExplicitly+ then StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour' -- Recalculate. else getNPawnsByFileByLogicalColour board, getNPieces = Attribute.MoveType.nPiecesMutator moveType nPieces,- getPassedPawnCoordinatesByLogicalColour = if Component.Piece.isPawn sourcePiece {-includes En-passant & promotion-} || Attribute.MoveType.getMaybeExplicitlyTakenRank moveType == Just Attribute.Rank.Pawn- then State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour coordinatesByRankByLogicalColour'+ getPassedPawnCoordinatesByLogicalColour = if Component.Piece.isPawn sourcePiece || wasPawnTakenExplicitly+ then State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour coordinatesByRankByLogicalColour' -- Recalculate. else getPassedPawnCoordinatesByLogicalColour board } @@ -481,16 +384,12 @@ -- | 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).+ 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- Enum x,- Enum y,- Num pieceSquareValue,- Ord x,- Ord y+ Num pieceSquareValue )- => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue- -> Board x y+ => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank pieceSquareValue+ -> Board -> #ifdef USE_UNBOXED_ARRAYS Attribute.LogicalColour.UArrayByLogicalColour@@ -499,8 +398,8 @@ #endif pieceSquareValue {-# SPECIALISE sumPieceSquareValueByLogicalColour- :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue- -> Board Type.Length.X Type.Length.Y+ :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Mass.PieceSquareValue+ -> Board -> #ifdef USE_UNBOXED_ARRAYS Attribute.LogicalColour.UArrayByLogicalColour@@ -512,9 +411,7 @@ sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour, getNPieces = nPieces-} = Attribute.LogicalColour.listArrayByLogicalColour $ State.CoordinatesByRankByLogicalColour.sumPieceSquareValueByLogicalColour (- \logicalColour rank coordinatesList -> Component.PieceSquareByCoordinatesByRank.findPieceSquareValues nPieces logicalColour rank coordinatesList pieceSquareByCoordinatesByRank- ) coordinatesByRankByLogicalColour+} = Attribute.LogicalColour.listArrayByLogicalColour $ Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces coordinatesByRankByLogicalColour {- | * Lists the source-/coordinates/ from which the referenced destination can be attacked.@@ -527,17 +424,11 @@ * 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 :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The defender's /logical colour/.- -> Cartesian.Coordinates.Coordinates x y -- ^ The defender's location.- -> Board x y- -> [(Cartesian.Coordinates.Coordinates x y, Attribute.Rank.Rank)] -- ^ The locations from which the specified square can be attacked by the opposite /logical colour/.-{-# SPECIALISE findAttackersOf :: Attribute.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Board Type.Length.X Type.Length.Y -> [(Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y, Attribute.Rank.Rank)] #-}+findAttackersOf+ :: Attribute.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 } = [ (coordinates, Attribute.Rank.Knight) | coordinates <- StateProperty.Seeker.findProximateKnights (Property.Opposable.getOpposite destinationLogicalColour) destination board@@ -552,17 +443,11 @@ * 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 :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Component.Piece.Piece -- ^ The type of attacker.- -> Cartesian.Coordinates.Coordinates x y -- ^ The defender's location.- -> Board x y- -> [Cartesian.Coordinates.Coordinates x y] -- ^ The sources from which the specified attacker could strike.-{-# SPECIALISE findAttacksBy :: Component.Piece.Piece -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Board Type.Length.X Type.Length.Y -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y] #-}+findAttacksBy+ :: 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 | otherwise = filter (@@ -578,16 +463,10 @@ * CAVEAT: assumes there's exactly one @King@ of the specified /logical colour/. -}-isKingChecked :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ in question.- -> Board x y+isKingChecked+ :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ in question.+ -> Board -> Bool-{-# SPECIALISE isKingChecked :: Attribute.LogicalColour.LogicalColour -> Board Type.Length.X Type.Length.Y -> Bool #-} isKingChecked logicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = not . null $ findAttackersOf logicalColour (State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour) board {- |@@ -597,29 +476,19 @@ * CAVEAT: this function is a performance-hotspot. -}-exposesKing :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player proposing to move.- -> Component.Move.Move x y -- ^ The /move/.- -> Board x y -- ^ The original /board/, i.e. prior to the /move/.+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/. -> Bool-{-# SPECIALISE exposesKing :: Attribute.LogicalColour.LogicalColour -> Component.Move.Move Type.Length.X Type.Length.Y -> Board Type.Length.X Type.Length.Y -> 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 :: Cartesian.Vector.VectorInt- ) -- Confirm that one's own King is on a straight line with the start of the move.+ | 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. , 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. , 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 :: Cartesian.Vector.VectorInt- )+ ) . 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@@ -628,15 +497,9 @@ kingsCoordinates = State.CoordinatesByRankByLogicalColour.getKingsCoordinates logicalColour coordinatesByRankByLogicalColour -- | Count the number of defenders of each /piece/ on the /board/.-countDefendersByCoordinatesByLogicalColour :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => Board x y -> NDefendersByCoordinatesByLogicalColour x y-{-# SPECIALISE countDefendersByCoordinatesByLogicalColour :: Board Type.Length.X Type.Length.Y -> NDefendersByCoordinatesByLogicalColour Type.Length.X Type.Length.Y #-}+countDefendersByCoordinatesByLogicalColour :: Board -> NDefendersByCoordinatesByLogicalColour countDefendersByCoordinatesByLogicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = Attribute.LogicalColour.listArrayByLogicalColour [- Data.Map.Strict.fromList [+ Map.fromList [ ( coordinates, fromIntegral . length $ findAttackersOf (@@ -649,8 +512,8 @@ ] -- List-comprehension. -- | Collapses 'NDefendersByCoordinatesByLogicalColour' into the total number of defenders on either side.-summariseNDefendersByLogicalColour :: Board x y -> Attribute.LogicalColour.ArrayByLogicalColour Type.Count.NPieces+summariseNDefendersByLogicalColour :: Board -> Attribute.LogicalColour.ArrayByLogicalColour Type.Count.NPieces summariseNDefendersByLogicalColour MkBoard { getNDefendersByCoordinatesByLogicalColour = nDefendersByCoordinatesByLogicalColour } = Data.Array.IArray.amap (- Data.Map.Strict.foldl' (+) 0 -- CAVEAT: 'Data.Foldable.sum' is too slow.+ Data.Foldable.foldl' (+) 0 -- CAVEAT: 'Data.Foldable.sum' is too slow. ) nDefendersByCoordinatesByLogicalColour
src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -66,7 +65,6 @@ import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Component.Zobrist as Component.Zobrist-import qualified BishBosh.Data.Enum as Data.Enum import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.FixedMembership as Property.FixedMembership@@ -75,12 +73,12 @@ import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.State.Board as State.Board import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour 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.Char import qualified Data.Default import qualified Data.List@@ -95,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 x = [(Attribute.LogicalColour.LogicalColour, [x])]+type AbscissaeByLogicalColour = [(Attribute.LogicalColour.LogicalColour, [Type.Length.X])] -- | Ensure a predictable order, to facilitate '(==)'.-sortByLogicalColour :: AbscissaeByLogicalColour x -> AbscissaeByLogicalColour x+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 x -> AbscissaeByLogicalColour x+castle :: Attribute.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 x -> AbscissaeByLogicalColour x+relinquishCastlingRights :: Attribute.LogicalColour.LogicalColour -> AbscissaeByLogicalColour -> AbscissaeByLogicalColour relinquishCastlingRights logicalColour = map $ \pair@(logicalColour', _) -> ( if logicalColour' == logicalColour then Control.Arrow.second $ const []@@ -114,7 +112,11 @@ ) pair -- | Remove the right to castle, from the referenced @Rook@.-removeX :: Eq x => Attribute.LogicalColour.LogicalColour -> x -> AbscissaeByLogicalColour x -> AbscissaeByLogicalColour x+removeX+ :: Attribute.LogicalColour.LogicalColour+ -> Type.Length.X+ -> AbscissaeByLogicalColour+ -> AbscissaeByLogicalColour removeX logicalColour x = map $ \pair@(logicalColour', _) -> ( if logicalColour' == logicalColour then Control.Arrow.second $ Data.List.delete x@@ -123,47 +125,37 @@ -- | Predicate. canCastleWith'- :: Eq x- => Attribute.LogicalColour.LogicalColour- -> x -- ^ @Rook@'s abscissa.- -> AbscissaeByLogicalColour x+ :: Attribute.LogicalColour.LogicalColour+ -> Type.Length.X -- ^ @Rook@'s abscissa.+ -> AbscissaeByLogicalColour -> Bool canCastleWith' logicalColour x = Data.Maybe.maybe False {-has castled-} (elem x) . lookup logicalColour -- | 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 x = MkCastleableRooksByLogicalColour {- getAssocs :: AbscissaeByLogicalColour x+newtype CastleableRooksByLogicalColour = MkCastleableRooksByLogicalColour {+ getAssocs :: AbscissaeByLogicalColour } deriving (Eq, Ord) -instance Show x => Show (CastleableRooksByLogicalColour x) where+instance Show CastleableRooksByLogicalColour where showsPrec precedence MkCastleableRooksByLogicalColour { getAssocs = assocs } = showsPrec precedence assocs -instance (- Enum x,- Ord x,- Read x,- Show x- ) => Read (CastleableRooksByLogicalColour x) where+instance Read CastleableRooksByLogicalColour where readsPrec precedence s = Control.Arrow.first fromAssocs `map` readsPrec precedence s -instance Control.DeepSeq.NFData x => Control.DeepSeq.NFData (CastleableRooksByLogicalColour x) where+instance Control.DeepSeq.NFData CastleableRooksByLogicalColour where rnf MkCastleableRooksByLogicalColour { getAssocs = assocs } = Control.DeepSeq.rnf assocs -instance Enum x => Data.Default.Default (CastleableRooksByLogicalColour x) where+instance Data.Default.Default CastleableRooksByLogicalColour where def = MkCastleableRooksByLogicalColour $ map ( flip (,) [Cartesian.Abscissa.xMin, Cartesian.Abscissa.xMax] ) Property.FixedMembership.members -instance Property.Reflectable.ReflectableOnX (CastleableRooksByLogicalColour x) where+instance Property.Reflectable.ReflectableOnX CastleableRooksByLogicalColour where reflectOnX MkCastleableRooksByLogicalColour { getAssocs = assocs } = MkCastleableRooksByLogicalColour . reverse $ map ( Control.Arrow.first Property.Opposable.getOpposite ) assocs -instance (- Enum x,- Ord x,- Show x- ) => Property.ExtendedPositionDescription.ReadsEPD (CastleableRooksByLogicalColour x) where+instance Property.ExtendedPositionDescription.ReadsEPD CastleableRooksByLogicalColour where readsEPD s = case Data.List.Extra.trimStart s of '-' : remainder -> [ (@@ -198,7 +190,7 @@ [([], _)] -> [] -- Zero pieces were read => parse-failure. l -> Control.Arrow.first (fromAssocs . Data.List.Extra.groupSort) `map` l -instance (Enum x, Eq x) => Property.ExtendedPositionDescription.ShowsEPD (CastleableRooksByLogicalColour x) where+instance Property.ExtendedPositionDescription.ShowsEPD CastleableRooksByLogicalColour where showsEPD MkCastleableRooksByLogicalColour { getAssocs = assocs } | all (null . snd) assocs = Property.ExtendedPositionDescription.showsNullField | otherwise = foldr (@@ -210,28 +202,20 @@ canCastleWith' logicalColour rooksX assocs ] -- List-comprehension. -instance (- Enum x,- Ord x,- Show x- ) => Property.ForsythEdwards.ReadsFEN (CastleableRooksByLogicalColour x)+instance Property.ForsythEdwards.ReadsFEN CastleableRooksByLogicalColour -instance (Enum x, Eq x) => Property.ForsythEdwards.ShowsFEN (CastleableRooksByLogicalColour x)+instance Property.ForsythEdwards.ShowsFEN CastleableRooksByLogicalColour -- | Get the list of random numbers required to represent the current castling potential.-instance Eq x => Component.Zobrist.Hashable1D CastleableRooksByLogicalColour x {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms1D MkCastleableRooksByLogicalColour { getAssocs = assocs } zobrist = Data.Maybe.catMaybes [+instance StateProperty.Hashable.Hashable CastleableRooksByLogicalColour where+ listRandoms MkCastleableRooksByLogicalColour { getAssocs = assocs } zobrist = Data.Maybe.catMaybes [ Component.Zobrist.dereferenceRandomByCastleableRooksXByLogicalColour logicalColour x zobrist | logicalColour <- Property.FixedMembership.members, x <- Data.Maybe.fromMaybe [] $ lookup logicalColour assocs ] -- List-comprehension. -- | Smart constructor.-fromAssocs :: (- Enum x,- Ord x,- Show x- ) => AbscissaeByLogicalColour x -> CastleableRooksByLogicalColour x+fromAssocs :: AbscissaeByLogicalColour -> CastleableRooksByLogicalColour fromAssocs assocs | Data.List.Extra.anySame $ map fst {-logicalColour-} assocs = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.State.CastleableRooksByLogicalColour.fromAssocs:\tduplicate logical colours have been defined; " $ shows assocs "." | any (Data.List.Extra.anySame . snd) assocs = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.State.CastleableRooksByLogicalColour.fromAssocs:\tduplicate abscissae have been defined; " $ shows assocs "."@@ -247,13 +231,7 @@ * CAVEAT: doesn't know the move-history, so the wrong answer is possible. -}-fromBoard :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x- ) => State.Board.Board x y -> CastleableRooksByLogicalColour x+fromBoard :: State.Board.Board -> CastleableRooksByLogicalColour fromBoard board | any ( \logicalColour -> hasCastled logicalColour castleableRooksByLogicalColour && all (@@ -262,10 +240,7 @@ Cartesian.Coordinates.mkCoordinates x ( Cartesian.Ordinate.pawnsFirstRank logicalColour ) |- bishopsAbscissa <- [- Cartesian.Abscissa.translate (Data.Enum.translate (+ 2)) Cartesian.Abscissa.xMin,- Cartesian.Abscissa.translate (Data.Enum.translate $ subtract 2) Cartesian.Abscissa.xMax- ],+ bishopsAbscissa <- Cartesian.Abscissa.bishopsFiles, x <- Cartesian.Abscissa.getAdjacents bishopsAbscissa ] -- List-comprehension. ) Property.FixedMembership.members = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.State.CastleableRooksByLogicalColourFromBoard.fromBoard:\tfor castling to have occurred, a Bishop must have been moved, which can only happen when a blocking Pawn is moved; " $ shows (castleableRooksByLogicalColour, board) "."@@ -285,15 +260,10 @@ ) Property.FixedMembership.members -- | Narrow the type, so the /turn/ can be queried.-type TurnsByLogicalColour x y = State.TurnsByLogicalColour.TurnsByLogicalColour (Component.Turn.Turn x y)+type TurnsByLogicalColour = State.TurnsByLogicalColour.TurnsByLogicalColour Component.Turn.Turn -- | Constructor.-fromTurnsByLogicalColour :: (- Enum x,- Enum y,- Eq x,- Eq y- ) => TurnsByLogicalColour x y -> CastleableRooksByLogicalColour x+fromTurnsByLogicalColour :: TurnsByLogicalColour -> CastleableRooksByLogicalColour fromTurnsByLogicalColour turnsByLogicalColour = MkCastleableRooksByLogicalColour $ foldr ( \logicalColour -> let turns = State.TurnsByLogicalColour.dereference logicalColour turnsByLogicalColour@@ -309,49 +279,44 @@ ] -- List-comprehension. ) -- Pair. ) [] Property.FixedMembership.members where- haveMovedFrom, haveMovedTo :: (Eq x, Eq y) => Cartesian.Coordinates.Coordinates x y -> [Component.Turn.Turn x y] -> Bool+ haveMovedFrom, haveMovedTo :: Cartesian.Coordinates.Coordinates -> [Component.Turn.Turn] -> Bool haveMovedFrom coordinates = any $ (== coordinates) . Component.Move.getSource . Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove haveMovedTo coordinates = any $ (== coordinates) . Component.Move.getDestination . Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove -- | Predicate.-hasCastled :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour x -> Bool+hasCastled :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Bool hasCastled logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = all ((/= logicalColour) . fst) assocs -- | Predicate.-canCastle :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour x -> Bool+canCastle :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Bool canCastle logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = Data.Maybe.maybe False {-has castled-} (not . null) $ lookup logicalColour assocs -- | Infer the @Rook@'s ordinate from the /piece/'s /logical colour/.-inferRooksOrdinate :: Enum y => Attribute.LogicalColour.LogicalColour -> y+inferRooksOrdinate :: Attribute.LogicalColour.LogicalColour -> Type.Length.Y inferRooksOrdinate logicalColour | Attribute.LogicalColour.isBlack logicalColour = Cartesian.Ordinate.yMax | otherwise = Cartesian.Ordinate.yMin -- | Predicate.-canCastleWith :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour- -> Cartesian.Coordinates.Coordinates x y -- ^ @Rook@'s coordinates.- -> CastleableRooksByLogicalColour x+canCastleWith+ :: Attribute.LogicalColour.LogicalColour+ -> Cartesian.Coordinates.Coordinates -- ^ @Rook@'s coordinates.+ -> CastleableRooksByLogicalColour -> Bool canCastleWith logicalColour rookSource MkCastleableRooksByLogicalColour { getAssocs = assocs } = 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 x -> Maybe [x]+locateForLogicalColour :: Attribute.LogicalColour.LogicalColour -> CastleableRooksByLogicalColour -> Maybe [Type.Length.X] {-# INLINE locateForLogicalColour #-} locateForLogicalColour logicalColour MkCastleableRooksByLogicalColour { getAssocs = assocs } = lookup logicalColour assocs -- | Self-documentation.-type Transformation x = CastleableRooksByLogicalColour x -> CastleableRooksByLogicalColour x+type Transformation = CastleableRooksByLogicalColour -> CastleableRooksByLogicalColour -- | Relinquish the ability to disambiguate between "have Castled" (& therefore can't subsequently), & "Have lost the option to castle".-unify :: Transformation x+unify :: Transformation unify MkCastleableRooksByLogicalColour { getAssocs = assocs } = MkCastleableRooksByLogicalColour $ foldr ( \logicalColour assocs' -> ( if any ((== logicalColour) . fst) assocs@@ -363,16 +328,10 @@ ) assocs Property.FixedMembership.members -- | Update with the latest /turn/.-takeTurn :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ Defines the side who took the specified turn.- -> Component.Turn.Turn x y- -> Transformation x-{-# SPECIALISE takeTurn :: Attribute.LogicalColour.LogicalColour -> Component.Turn.Turn Type.Length.X Type.Length.Y -> Transformation Type.Length.X #-}+takeTurn+ :: Attribute.LogicalColour.LogicalColour -- ^ Defines the side who took the specified turn.+ -> Component.Turn.Turn+ -> Transformation takeTurn logicalColour turn MkCastleableRooksByLogicalColour { getAssocs = assocs } = MkCastleableRooksByLogicalColour $ ( case lookup logicalColour assocs of Just [] -> id -- This is a terminal state.@@ -384,7 +343,7 @@ (== source) . (`Cartesian.Coordinates.mkCoordinates` inferRooksOrdinate logicalColour) ) rooksXs -> removeX logicalColour $ Cartesian.Coordinates.getX source | otherwise -> id- _ -> id -- This is a terminal state.+ _ -> id -- This is a terminal state. ) $ ( let opponentsLogicalColour = Property.Opposable.getOpposite logicalColour@@ -418,8 +377,8 @@ * CAVEAT: this function depends on one side having lost the right to castle, when the other side already has; this is quite rare. -} cantConverge- :: CastleableRooksByLogicalColour x- -> CastleableRooksByLogicalColour x+ :: CastleableRooksByLogicalColour+ -> CastleableRooksByLogicalColour -> Bool cantConverge castleableRooksByLogicalColour castleableRooksByLogicalColour' = any ( \logicalColour -> case ($ castleableRooksByLogicalColour) &&& ($ castleableRooksByLogicalColour') $ locateForLogicalColour logicalColour of@@ -430,14 +389,13 @@ -- | Generate the additional random-numbers required to correct the hash resulting from a change to the castleable @Rook@s. listIncrementalRandoms- :: Data.Array.IArray.Ix x- => CastleableRooksByLogicalColour x -- ^ The old value.- -> CastleableRooksByLogicalColour x -- ^ The new value.- -> Component.Zobrist.Zobrist x y random+ :: CastleableRooksByLogicalColour -- ^ The old value.+ -> CastleableRooksByLogicalColour -- ^ The new value.+ -> Component.Zobrist.Zobrist random -> [random] listIncrementalRandoms castleableRooksByLogicalColour castleableRooksByLogicalColour' zobrist = [ random | hashable <- [castleableRooksByLogicalColour, castleableRooksByLogicalColour'],- random <- Component.Zobrist.listRandoms1D hashable zobrist+ random <- StateProperty.Hashable.listRandoms hashable zobrist ] -- List-comprehension.
src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -30,7 +29,6 @@ module BishBosh.State.CoordinatesByRankByLogicalColour( -- * Types -- ** Type-synonyms- NPiecesByFileByLogicalColour, -- CoordinatesByRank, CoordinatesByLogicalColour, -- Transformation,@@ -40,11 +38,8 @@ deconstruct ), -- * Functions- countPawnsByFileByLogicalColour, findPassedPawnCoordinatesByLogicalColour, findPiecesOfColour,- sumPieceSquareValueByLogicalColour,--- deleteCoordinates, assocs, listCoordinates, -- ** Accessors@@ -53,6 +48,7 @@ -- ** Constructor fromMaybePieceByCoordinates, -- ** Mutators+-- deleteCoordinates, movePiece, sortCoordinates ) where@@ -65,46 +61,43 @@ 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.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.Component.Zobrist as Component.Zobrist+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.StateProperty.Censor as StateProperty.Censor+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker-import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length-import qualified BishBosh.Type.Mass as Type.Mass 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.Map.Strict+import qualified Data.Map.Strict as Map import qualified Data.Maybe -- | The /coordinate/s of all the pieces of one /rank/.-type CoordinatesByRank x y = Attribute.Rank.ArrayByRank [Cartesian.Coordinates.Coordinates x y]+type CoordinatesByRank = Attribute.Rank.ArrayByRank [Cartesian.Coordinates.Coordinates] {- | * 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 x y = MkCoordinatesByRankByLogicalColour {- deconstruct :: Attribute.LogicalColour.ArrayByLogicalColour (CoordinatesByRank x y)+newtype CoordinatesByRankByLogicalColour = MkCoordinatesByRankByLogicalColour {+ deconstruct :: Attribute.LogicalColour.ArrayByLogicalColour CoordinatesByRank } -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (CoordinatesByRankByLogicalColour x y) where+instance Control.DeepSeq.NFData CoordinatesByRankByLogicalColour where rnf MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Control.DeepSeq.rnf byLogicalColour -instance (Enum x, Enum y) => StateProperty.Censor.Censor (CoordinatesByRankByLogicalColour x y) where+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 !) countPieces MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.foldl' (@@ -115,7 +108,7 @@ zipWith (-) ) . ( ($ Attribute.LogicalColour.White) &&& ($ Attribute.LogicalColour.Black)- ) $ map (fromIntegral . length) . Data.Array.IArray.elems . (byLogicalColour !)+ ) $ map (fromIntegral . length) . Data.Foldable.toList . (byLogicalColour !) hasInsufficientMaterial MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.all ( \byRank -> all (@@ -128,7 +121,7 @@ where [blackKnights, blackBishops, whiteKnights, whiteBishops] = [ byRank ! rank |- byRank <- Data.Array.IArray.elems byLogicalColour,+ byRank <- Data.Foldable.toList byLogicalColour, rank <- [Attribute.Rank.Knight, Attribute.Rank.Bishop] ] -- List-comprehension. @@ -136,8 +129,8 @@ hasBothKings MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = not $ Data.Foldable.any (null . (! Attribute.Rank.King)) byLogicalColour -- CAVEAT: true for more than one King per side also. -instance (Enum x, Enum y, Ord x, Ord y) => Component.Zobrist.Hashable2D CoordinatesByRankByLogicalColour x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms2D MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } zobrist = [+instance StateProperty.Hashable.Hashable CoordinatesByRankByLogicalColour where+ listRandoms MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } zobrist = [ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (logicalColour, rank, coordinates) zobrist | (logicalColour, byRank) <- Data.Array.IArray.assocs byLogicalColour, (rank, coordinatesList) <- Data.Array.IArray.assocs byRank,@@ -149,16 +142,10 @@ * CAVEAT: nothing is said about whether any /piece/ at the specified /coordinates/ belongs to the opponent, as one might expect. -}-instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour Type.Length.X Type.Length.Y #-}+instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour {-CAVEAT: MultiParamTypeClasses-} where findProximateKnights logicalColour destination MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = filter ( \source -> source /= destination {-guard against attempting to constructing a null vector-} && Cartesian.Vector.isKnightsMove (- Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.VectorInt+ Cartesian.Vector.measureDistance source destination ) ) $ byLogicalColour ! logicalColour ! Attribute.Rank.Knight @@ -171,13 +158,23 @@ coordinates <- coordinatesList ] -- List-comprehension. + countPawnsByFileByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Array.IArray.amap (+ Data.List.foldl' (+ \m coordinates -> StateProperty.Seeker.accumulatePawnsByFile (Cartesian.Coordinates.getX coordinates) m+ ) Property.Empty.empty . (! Attribute.Rank.Pawn)+ ) byLogicalColour++instance Component.Accountant.Accountant CoordinatesByRankByLogicalColour where+ sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = map (+ \(logicalColour, byRank) -> Data.List.foldl' (+ \acc (rank, coordinatesList) -> Data.List.foldl' (+ \acc' -> (+ acc') . Component.PieceSquareByCoordinatesByRank.findPieceSquareValue pieceSquareByCoordinatesByRank nPieces logicalColour rank+ ) acc coordinatesList+ ) 0 $ Data.Array.IArray.assocs byRank+ ) $ Data.Array.IArray.assocs byLogicalColour+ -- | Constructor.-fromMaybePieceByCoordinates :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => State.MaybePieceByCoordinates.MaybePieceByCoordinates x y -> CoordinatesByRankByLogicalColour x y+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)@@ -193,13 +190,13 @@ dereference :: Attribute.LogicalColour.LogicalColour -> Attribute.Rank.Rank- -> CoordinatesByRankByLogicalColour x y- -> [Cartesian.Coordinates.Coordinates x y]+ -> CoordinatesByRankByLogicalColour+ -> [Cartesian.Coordinates.Coordinates] {-# INLINE dereference #-} dereference logicalColour rank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = byLogicalColour ! logicalColour ! rank -- | Build an association-list.-assocs :: CoordinatesByRankByLogicalColour x y -> [(Component.Piece.Piece, [Cartesian.Coordinates.Coordinates x y])]+assocs :: CoordinatesByRankByLogicalColour -> [(Component.Piece.Piece, [Cartesian.Coordinates.Coordinates])] assocs MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = [ (Component.Piece.mkPiece logicalColour rank, coordinatesList) | (logicalColour, byRank) <- Data.Array.IArray.assocs byLogicalColour,@@ -207,44 +204,28 @@ ] -- List-comprehension. -- | Access the coordinate-lists.-listCoordinates :: CoordinatesByRankByLogicalColour x y -> [Cartesian.Coordinates.Coordinates x y]+listCoordinates :: CoordinatesByRankByLogicalColour -> [Cartesian.Coordinates.Coordinates] listCoordinates MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = [ coordinates |- byRank <- Data.Array.IArray.elems byLogicalColour,- coordinatesList <- Data.Array.IArray.elems byRank,+ byRank <- Data.Foldable.toList byLogicalColour,+ coordinatesList <- Data.Foldable.toList byRank, coordinates <- coordinatesList ] -- List-comprehension. -- | Get the /coordinates/ of the @King@ of the specified /logical colour/. getKingsCoordinates :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ to find.- -> CoordinatesByRankByLogicalColour x y- -> Cartesian.Coordinates.Coordinates x y+ -> CoordinatesByRankByLogicalColour+ -> 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 --- | The number of /piece/s in each file, for each /logical colour/.-type NPiecesByFileByLogicalColour x = Attribute.LogicalColour.ArrayByLogicalColour (Data.Map.Strict.Map x Type.Count.NPieces)--{- |- * Counts the number of @Pawn@s of each /logical colour/ with similar /x/-coordinates; their /y/-coordinate is irrelevant.-- * N.B.: files lacking any @Pawn@, don't feature in the results.--}-countPawnsByFileByLogicalColour :: Ord x => CoordinatesByRankByLogicalColour x y -> NPiecesByFileByLogicalColour x-{-# INLINABLE countPawnsByFileByLogicalColour #-}-countPawnsByFileByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Array.IArray.amap (- Data.List.foldl' (- \m coordinates -> Data.Map.Strict.insertWith (const succ) (Cartesian.Coordinates.getX coordinates) 1 m- ) Data.Map.Strict.empty . (! Attribute.Rank.Pawn)- ) byLogicalColour- -- | Locate all /piece/s of the specified /logical colour/. findPiecesOfColour :: Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /piece/s to find.- -> CoordinatesByRankByLogicalColour x y- -> [Component.Piece.LocatedPiece x y]+ -> CoordinatesByRankByLogicalColour+ -> [Component.Piece.LocatedPiece] findPiecesOfColour logicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = [ (coordinates, Component.Piece.mkPiece logicalColour rank) | (rank, coordinatesList) <- Data.Array.IArray.assocs $ byLogicalColour ! logicalColour,@@ -252,31 +233,31 @@ ] -- List-comprehension. -- | A list of /coordinates/ for each /logical colour/.-type CoordinatesByLogicalColour x y = Attribute.LogicalColour.ArrayByLogicalColour [Cartesian.Coordinates.Coordinates x y]+type CoordinatesByLogicalColour = Attribute.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 :: (Enum x, Ord x, Ord y) => CoordinatesByRankByLogicalColour x y -> CoordinatesByLogicalColour x y+findPassedPawnCoordinatesByLogicalColour :: CoordinatesByRankByLogicalColour -> CoordinatesByLogicalColour findPassedPawnCoordinatesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Attribute.LogicalColour.listArrayByLogicalColour $ map ( \logicalColour -> let opponentsLogicalColour = Property.Opposable.getOpposite logicalColour opposingPawnYByX = Data.List.foldl' ( \m coordinates -> uncurry (- Data.Map.Strict.insertWith $ if Attribute.LogicalColour.isBlack opponentsLogicalColour+ Map.insertWith $ if Attribute.LogicalColour.isBlack opponentsLogicalColour then max else min ) {-only compare with the least advanced opposing Pawn in each file-} ( Cartesian.Coordinates.getX &&& Cartesian.Coordinates.getY $ coordinates ) m- ) Data.Map.Strict.empty $ findPawns opponentsLogicalColour+ ) Property.Empty.empty $ findPawns opponentsLogicalColour in filter ( \coordinates -> all (- Data.Maybe.maybe True {-the absence of an opposing Pawn doesn't impede advancement-} (+ Data.Maybe.maybe True {-absence of opposition doesn't impede advance-} ( ( /= Attribute.Direction.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.- ) . (`Data.Map.Strict.lookup` opposingPawnYByX)+ ) . (`Map.lookup` opposingPawnYByX) ) . uncurry (:) . ( id &&& Cartesian.Abscissa.getAdjacents ) $ Cartesian.Coordinates.getX coordinates@@ -284,39 +265,24 @@ ) Property.FixedMembership.members where findPawns = (! Attribute.Rank.Pawn) . (byLogicalColour !) --- | Calculate the total value of the /coordinates/ occupied by the /piece/s of either side.-sumPieceSquareValueByLogicalColour- :: (Num pieceSquareValue)- => Component.PieceSquareByCoordinatesByRank.FindPieceSquareValues x y pieceSquareValue- -> CoordinatesByRankByLogicalColour x y- -> [pieceSquareValue]-{-# SPECIALISE sumPieceSquareValueByLogicalColour :: Component.PieceSquareByCoordinatesByRank.FindPieceSquareValues Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue -> CoordinatesByRankByLogicalColour Type.Length.X Type.Length.Y -> [Type.Mass.PieceSquareValue] #-}-sumPieceSquareValueByLogicalColour findPieceSquareValues MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = map (- \(logicalColour, byRank) -> Data.List.foldl' (- \acc -> Data.List.foldl' (+) acc . uncurry (findPieceSquareValues logicalColour)- ) 0 $ Data.Array.IArray.assocs byRank- ) $ Data.Array.IArray.assocs byLogicalColour- -- | Self-documentation.-type Transformation x y = CoordinatesByRankByLogicalColour x y -> CoordinatesByRankByLogicalColour x y+type Transformation = CoordinatesByRankByLogicalColour -> CoordinatesByRankByLogicalColour -- | Remove the specified /coordinates/ from those recorded for the specified /rank/. deleteCoordinates- :: (Eq x, Eq y)- => Cartesian.Coordinates.Coordinates x y+ :: Cartesian.Coordinates.Coordinates -> Attribute.Rank.Rank- -> CoordinatesByRank x y- -> CoordinatesByRank x y+ -> CoordinatesByRank+ -> CoordinatesByRank deleteCoordinates coordinates rank byRank = byRank // [(rank, Data.List.delete coordinates $ byRank ! rank)] -- | Adjust the array to reflect a new /move/. movePiece- :: (Eq x, Eq y)- => Component.Move.Move x y- -> Component.Piece.Piece -- ^ The piece which moved.- -> Maybe Attribute.Rank.Rank -- ^ The (possibly promoted) rank to place at the destination.- -> Either (Cartesian.Coordinates.Coordinates x y) (Maybe Attribute.Rank.Rank) -- ^ Either the destination of any passed @Pawn@, or the /rank/ of any /piece/ taken.- -> Transformation x y+ :: 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@@ -343,6 +309,6 @@ deleteOpponentsCoordinates coordinates rank = id &&& deleteCoordinates coordinates rank . (byLogicalColour !) $ Property.Opposable.getOpposite logicalColour -- | Independently sort each list of /coordinates/.-sortCoordinates :: (Ord x, Ord y) => Transformation x y+sortCoordinates :: Transformation sortCoordinates MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ Data.Array.IArray.amap (Data.Array.IArray.amap Data.List.sort) byLogicalColour
src-lib/BishBosh/State/EnPassantAbscissa.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -43,34 +42,28 @@ 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.StateProperty.Hashable as StateProperty.Hashable import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq-import qualified Data.Array.IArray import qualified Data.Maybe -- | Defines the file on which an En-passant option currently exists.-newtype EnPassantAbscissa x = MkEnPassantAbscissa {- getAbscissa :: x -- ^ The file on which an En-passant option currently exists.+newtype EnPassantAbscissa = MkEnPassantAbscissa {+ getAbscissa :: Type.Length.X -- ^ The file on which an En-passant option currently exists. } deriving (Eq, Ord) -instance Data.Array.IArray.Ix x => Component.Zobrist.Hashable1D EnPassantAbscissa x {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms1D MkEnPassantAbscissa { getAbscissa = x } = return {-to List-monad-} . Component.Zobrist.dereferenceRandomByEnPassantAbscissa x--instance Control.DeepSeq.NFData x => Control.DeepSeq.NFData (EnPassantAbscissa x) where+instance Control.DeepSeq.NFData EnPassantAbscissa where 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+ -- | Constructor.-mkMaybeEnPassantAbscissa :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The player who moves next, & who may have an En-passant capture-option.- -> State.MaybePieceByCoordinates.MaybePieceByCoordinates x y- -> Component.Turn.Turn x y -- ^ The last /turn/ taken.- -> Maybe (EnPassantAbscissa x)-{-# SPECIALISE mkMaybeEnPassantAbscissa :: Attribute.LogicalColour.LogicalColour -> State.MaybePieceByCoordinates.MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Component.Turn.Turn Type.Length.X Type.Length.Y -> Maybe (EnPassantAbscissa Type.Length.X) #-}+mkMaybeEnPassantAbscissa+ :: Attribute.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.+ -> 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
src-lib/BishBosh/State/InstancesByPosition.hs view
@@ -25,7 +25,8 @@ module BishBosh.State.InstancesByPosition( -- * Types -- ** Type-synonyms--- Transformation.+-- NPositionsByPosition,+-- Transformation, -- * Constants leastCyclicPlies, -- ** Data-types@@ -39,19 +40,20 @@ mkInstancesByPosition, mkSingleton, -- ** Mutators+-- insertPosition', insertPosition, deletePosition, -- ** Predicates anyInstancesByPosition ) where -import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Property.Empty as Property.Empty 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.Foldable-import qualified Data.Map.Strict+import qualified Data.Map.Strict as Map -- | The smallest number of repeatable plies (applied by alternating players) required to form a cycle. leastCyclicPlies :: Type.Count.NPlies@@ -64,8 +66,15 @@ * The /position/ can either be represented by a physical 'State.Position.Position', or by proxy using a hash. -}+type NPositionsByPosition position = Map.Map position Type.Count.NPositions++-- | Insert a position into the unwrapped collection.+insertPosition' :: Ord position => position -> NPositionsByPosition position -> NPositionsByPosition position+insertPosition' = flip (Map.insertWith $ const succ) 1++-- | Wrap the type, so that class-instances can be hung from it. newtype InstancesByPosition position = MkInstancesByPosition {- getNPositionsByPosition :: Data.Map.Strict.Map position Type.Count.NPositions+ getNPositionsByPosition :: NPositionsByPosition position } deriving Eq instance Control.DeepSeq.NFData position => Control.DeepSeq.NFData (InstancesByPosition position) where@@ -75,37 +84,40 @@ Ord position, Property.Reflectable.ReflectableOnX position ) => Property.Reflectable.ReflectableOnX (InstancesByPosition position) where- reflectOnX MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition $ Data.Map.Strict.mapKeys Property.Reflectable.reflectOnX m+ reflectOnX MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition $ Map.mapKeys Property.Reflectable.reflectOnX m --- | Smart constructor.-mkInstancesByPosition :: Data.Map.Strict.Map position Type.Count.NPositions -> InstancesByPosition position-mkInstancesByPosition nPositionsByPosition- | Data.Foldable.any (< 1) nPositionsByPosition = Control.Exception.throw $ Data.Exception.mkOutOfBounds "BishBosh.State.InstancesByPosition.mkInstancesByPosition:\teach specified position must have been visited at least once."- | otherwise = MkInstancesByPosition nPositionsByPosition+-- | Construct from repeatable data.+mkInstancesByPosition+ :: (Foldable foldable, Ord position)+ => (a -> position) -- ^ Position-constructor.+ -> foldable a -- ^ Data from which to construct positions.+ -> InstancesByPosition position+mkInstancesByPosition f = MkInstancesByPosition . Data.Foldable.foldr (insertPosition' . f) Property.Empty.empty -- | Constructor. mkSingleton :: position -> InstancesByPosition position-mkSingleton position = MkInstancesByPosition $ Data.Map.Strict.singleton position 1+mkSingleton = MkInstancesByPosition . (`Map.singleton` 1) + {- | * Count the total number of consecutive repeatable plies amongst recent moves. * This is equivalent to the number of entries in the map, since adding a non-repeatable move triggers a purge. -} countConsecutiveRepeatablePlies :: InstancesByPosition position -> Type.Count.NPlies-countConsecutiveRepeatablePlies MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Map.Strict.foldl' (+) (+countConsecutiveRepeatablePlies MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Foldable.foldl' (+) ( negate 1 -- The map is never empty, since before the first move a singleton is constructed with the initial position. ) m -- | Count the total number of repetitions of /position/s. countPositionRepetitions :: InstancesByPosition position -> Type.Count.NPositions-countPositionRepetitions MkInstancesByPosition { getNPositionsByPosition = m } = Data.Map.Strict.foldl' (+countPositionRepetitions MkInstancesByPosition { getNPositionsByPosition = m } = Data.Foldable.foldl' ( (+) . pred -- The initial instance isn't a repetition. ) 0 m -- | The number of distinct /position/s. getNDistinctPositions :: InstancesByPosition position -> Type.Count.NPositions-getNDistinctPositions MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Map.Strict.size m {-the number of keys-}+getNDistinctPositions MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Foldable.length m {-the number of keys-} -- | Predicate: apply the specified predicate to the map. anyInstancesByPosition@@ -121,8 +133,8 @@ -} findMaximumInstances :: InstancesByPosition position -> Type.Count.NPositions findMaximumInstances MkInstancesByPosition { getNPositionsByPosition = m }- | Data.Map.Strict.null m = 0 -- CAVEAT: this shouldn't happen.- | otherwise = Data.Foldable.maximum m+ | Data.Foldable.null m = 0 -- CAVEAT: this shouldn't happen.+ | otherwise = Data.Foldable.maximum m -- | The type of a function which transforms the collection. type Transformation position = InstancesByPosition position -> InstancesByPosition position@@ -134,14 +146,14 @@ -> position -> Transformation position insertPosition isRepeatable position MkInstancesByPosition { getNPositionsByPosition = m }- | isRepeatable = MkInstancesByPosition $ Data.Map.Strict.insertWith (const succ) position 1 m -- Include this position.- | otherwise = mkSingleton position -- The previous position can't be revisited without rolling-back.+ | isRepeatable = MkInstancesByPosition $ insertPosition' position m -- Include this position.+ | otherwise = mkSingleton position -- The previous position can't be revisited without rolling-back. -- | Remove a /position/ from the collection, as required to implement rollback. deletePosition :: Ord position => position -> Transformation position-deletePosition position MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition . Data.Map.Strict.update (+deletePosition position MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition . Map.update ( \n -> if n == 1 then Nothing -- Delete the entry. else Just $ pred n -- Decrement the number of instances.- ) position $ Control.Exception.assert (Data.Map.Strict.member position m) m+ ) position $ Control.Exception.assert (Map.member position m) m
src-lib/BishBosh/State/MaybePieceByCoordinates.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -36,13 +35,10 @@ -- Transformation, -- ** Data-types MaybePieceByCoordinates(),--- * Constants--- rankSeparator, -- * Functions inferMoveType, findBlockingPiece, findAttackerInDirection,- sumPieceSquareValueByLogicalColour, listDestinationsFor, -- listToRaster, -- shows2D,@@ -64,6 +60,7 @@ 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@@ -74,12 +71,14 @@ 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.Component.Accountant as Component.Accountant import qualified BishBosh.Component.CastlingMove as Component.CastlingMove 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.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Notation.Figurine as Notation.Figurine import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.FixedMembership as Property.FixedMembership@@ -88,17 +87,18 @@ import qualified BishBosh.Property.Orientated as Property.Orientated import qualified BishBosh.Property.Reflectable as Property.Reflectable 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.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Length as Type.Length-import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray import qualified Data.Char import qualified Data.Default+import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra import qualified Data.Maybe@@ -109,42 +109,24 @@ * 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 x y = MkMaybePieceByCoordinates {- deconstruct :: Cartesian.Coordinates.ArrayByCoordinates x y (+newtype MaybePieceByCoordinates = MkMaybePieceByCoordinates {+ 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>.-rankSeparator :: Char-rankSeparator = '/'- -- | 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-} -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Read (MaybePieceByCoordinates x y) where+instance Read MaybePieceByCoordinates where readsPrec _ = Property.ForsythEdwards.readsFEN -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Show (MaybePieceByCoordinates x y) where+instance Show MaybePieceByCoordinates where showsPrec _ = Property.ForsythEdwards.showsFEN -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ExtendedPositionDescription.ReadsEPD (MaybePieceByCoordinates x y) where+instance Property.ExtendedPositionDescription.ReadsEPD MaybePieceByCoordinates where readsEPD s | length rows /= fromIntegral Cartesian.Ordinate.yLength || any ( (/= fromIntegral Cartesian.Abscissa.xLength) . length@@ -158,21 +140,18 @@ [(i, "")] -> replicate i Nothing -- Expand the runlength-code so that each row has the same length. _ -> [Just piece | (piece, []) <- Property.ExtendedPositionDescription.readsEPD [c]] -- List-comprehension. )- ) . Text.ShowList.splitOn (== rankSeparator)+ ) . Text.ShowList.splitOn (== Property.ExtendedPositionDescription.rankSeparator) ) . span (- `elem` rankSeparator : concatMap Property.ExtendedPositionDescription.showEPD Component.Piece.range ++ concatMap show [1 .. Cartesian.Abscissa.xLength]+ `elem` (+ Property.ExtendedPositionDescription.rankSeparator : Component.Piece.epdCharacterSet ++ concatMap show [1 .. Cartesian.Abscissa.xLength]+ ) ) $ Data.List.Extra.trimStart s -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ExtendedPositionDescription.ShowsEPD (MaybePieceByCoordinates x y) where+instance Property.ExtendedPositionDescription.ShowsEPD MaybePieceByCoordinates where showsEPD MkMaybePieceByCoordinates { deconstruct = byCoordinates } = foldr1 ( >>> -- Render the line with the highest y-coordinate first. ) . Data.List.intersperse (- showChar rankSeparator -- Separate the lines.+ showChar Property.ExtendedPositionDescription.rankSeparator -- Separate the lines. ) . map ( foldr1 (.) . concatMap ( \(runLength, maybePiece) -> Data.Maybe.maybe [@@ -181,29 +160,14 @@ replicate runLength . Property.ExtendedPositionDescription.showsEPD -- Render each piece. ) maybePiece ) . ToolShed.Data.List.Runlength.encode- ) . listToRaster $ Data.Array.IArray.elems byCoordinates+ ) . listToRaster $ Data.Foldable.toList byCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ForsythEdwards.ReadsFEN (MaybePieceByCoordinates x y)+instance Property.ForsythEdwards.ReadsFEN MaybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.ForsythEdwards.ShowsFEN (MaybePieceByCoordinates x y)+instance Property.ForsythEdwards.ShowsFEN MaybePieceByCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Data.Default.Default (MaybePieceByCoordinates x y) where- def = Property.ForsythEdwards.readFEN . Data.List.intercalate [rankSeparator] $ map ($ Attribute.LogicalColour.Black) [+instance Data.Default.Default MaybePieceByCoordinates where+ def = Property.ForsythEdwards.readFEN . Data.List.intercalate [Property.ExtendedPositionDescription.rankSeparator] $ map ($ Attribute.LogicalColour.Black) [ showNobility, showPawnRow ] ++ replicate 4 "8" ++ map ($ Attribute.LogicalColour.White) [@@ -217,44 +181,21 @@ showPawnRow logicalColour = showPieces . replicate (fromIntegral Cartesian.Abscissa.xLength) $ Component.Piece.mkPawn logicalColour showNobility logicalColour = showPieces $ map (Component.Piece.mkPiece logicalColour) Attribute.Rank.nobility -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Reflectable.ReflectableOnX (MaybePieceByCoordinates x y) where+instance Property.Reflectable.ReflectableOnX MaybePieceByCoordinates where reflectOnX MkMaybePieceByCoordinates { deconstruct = byCoordinates } = MkMaybePieceByCoordinates . Cartesian.Coordinates.arrayByCoordinates . map ( Property.Reflectable.reflectOnX *** fmap Property.Opposable.getOpposite ) $ Data.Array.IArray.assocs byCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Reflectable.ReflectableOnY (MaybePieceByCoordinates x y) where+instance Property.Reflectable.ReflectableOnY MaybePieceByCoordinates where reflectOnY MkMaybePieceByCoordinates { deconstruct = byCoordinates } = MkMaybePieceByCoordinates $ Data.Array.IArray.ixmap (minBound, maxBound) Property.Reflectable.reflectOnY byCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Empty.Empty (MaybePieceByCoordinates x y) where+instance Property.Empty.Empty MaybePieceByCoordinates where empty = MkMaybePieceByCoordinates . Cartesian.Coordinates.listArrayByCoordinates $ repeat Property.Empty.empty -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (MaybePieceByCoordinates x y) where+instance Control.DeepSeq.NFData MaybePieceByCoordinates where rnf MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Control.DeepSeq.rnf byCoordinates -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Censor.Censor (MaybePieceByCoordinates x y) where+instance StateProperty.Censor.Censor MaybePieceByCoordinates where countPiecesByLogicalColour = Data.List.foldl' ( \acc piece -> let acc'@(nBlack, nWhite) = (@@ -302,17 +243,17 @@ ([_], [_]) -> True _ -> False -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Component.Zobrist.Hashable2D MaybePieceByCoordinates x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms2D MkMaybePieceByCoordinates { deconstruct = byCoordinates } zobrist = [+instance StateProperty.Hashable.Hashable MaybePieceByCoordinates where+ listRandoms MkMaybePieceByCoordinates { deconstruct = byCoordinates } zobrist = [ Component.Zobrist.dereferenceRandomByCoordinatesByRankByLogicalColour (Component.Piece.getLogicalColour piece, Component.Piece.getRank piece, coordinates) zobrist | (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 (+ Data.Maybe.isJust maybePiece || Data.Maybe.isJust (byCoordinates ! coordinates)+ ) . MkMaybePieceByCoordinates $ byCoordinates // [(coordinates, maybePiece)]+ {- | * Find any @Knight@s of the specified /logical colour/, in attack-range around the specified /coordinates/. @@ -320,13 +261,7 @@ * CAVEAT: less efficient than 'State.CoordinatesByRankByLogicalColour.findProximateKnights'. -}-instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Seeker.Seeker MaybePieceByCoordinates x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker MaybePieceByCoordinates Type.Length.X Type.Length.Y #-}+instance StateProperty.Seeker.Seeker MaybePieceByCoordinates where findProximateKnights logicalColour destination MkMaybePieceByCoordinates { deconstruct = byCoordinates } = filter ( (== Just knight) . (byCoordinates !) ) $ Component.Piece.findAttackDestinations destination knight where@@ -338,44 +273,32 @@ predicate piece ] -- List-comprehension. -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => StateProperty.Mutator.Mutator MaybePieceByCoordinates x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Mutator.Mutator MaybePieceByCoordinates Type.Length.X Type.Length.Y #-}- defineCoordinates maybePiece coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Control.Exception.assert (- Data.Maybe.isJust maybePiece || Data.Maybe.isJust (byCoordinates ! coordinates)- ) . MkMaybePieceByCoordinates $ byCoordinates // [(coordinates, maybePiece)]+instance Component.Accountant.Accountant MaybePieceByCoordinates where+ sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank 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+ 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 -- | Dereference the array.-dereference :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y- -> MaybePieceByCoordinates x y+dereference+ :: Cartesian.Coordinates.Coordinates+ -> MaybePieceByCoordinates -> Maybe Component.Piece.Piece {-# INLINE dereference #-} dereference coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = byCoordinates ! coordinates -- | Infer the type of the specified /move/.-inferMoveType :: (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- )- => Component.Move.Move x y+inferMoveType+ :: Component.Move.Move -> Maybe Attribute.Rank.Rank -- ^ The /rank/ to which a @Pawn@ should be promoted; defaulting to @Queen@.- -> MaybePieceByCoordinates x y+ -> MaybePieceByCoordinates -> Attribute.MoveType.MoveType-{-# SPECIALISE inferMoveType :: Component.Move.Move Type.Length.X Type.Length.Y -> Maybe Attribute.Rank.Rank -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Attribute.MoveType.MoveType #-} inferMoveType move maybePromotionRank maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } | Just sourcePiece <- byCoordinates ! Component.Move.getSource move = Data.Maybe.maybe ( if isEnPassantMove move maybePieceByCoordinates@@ -407,17 +330,11 @@ * CAVEAT: doesn't typically check whether anything (let alone the specified /piece/) exists at the specified source-/coordinates/. -}-listDestinationsFor :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y -- ^ The source for which destinations are required.+listDestinationsFor+ :: Cartesian.Coordinates.Coordinates -- ^ The source for which destinations are required. -> Component.Piece.Piece -- ^ The /piece/ at the specified source.- -> MaybePieceByCoordinates x y- -> [(Cartesian.Coordinates.Coordinates x y, Maybe Attribute.Rank.Rank)] -- ^ The destination & the rank of any piece taken.-{-# SPECIALISE listDestinationsFor :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Component.Piece.Piece -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> [(Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y, Maybe Attribute.Rank.Rank)] #-}+ -> 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 ( byCoordinates ! source == Just piece ) $ if Component.Piece.getRank piece `elem` Attribute.Rank.fixedAttackRange@@ -432,7 +349,7 @@ then findAttackDestinations ( Data.Maybe.maybe False {-unoccupied-} $ (/= logicalColour) . Component.Piece.getLogicalColour ) ++ let- advance :: (Enum y, Ord y) => Cartesian.Coordinates.Coordinates x y -> Cartesian.Coordinates.Coordinates x y+ advance :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates advance = Cartesian.Coordinates.advance logicalColour advancedLocation = advance source@@ -466,114 +383,78 @@ logicalColour = Component.Piece.getLogicalColour piece -- | Show the /board/ in two dimensions, with /x/ & /y/ indexes.-shows2D :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Type.Length.Column -- ^ The column-magnification.+shows2D+ :: Type.Length.Column -- ^ The column-magnification. -> Attribute.ColourScheme.ColourScheme- -> (Int, Int) -- ^ The origin from which axes are labelled.- -> MaybePieceByCoordinates x y- -> ShowS -- ^ The output suitable for display on a terminal.-shows2D boardColumnMagnification colourScheme (xOrigin, yOrigin) MkMaybePieceByCoordinates { deconstruct = byCoordinates } = (+ -> 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 } = ( foldr (- \(y, pairs) showsRow -> showsRow . showString (- Attribute.PhysicalColour.selectGraphicsRendition True $ Attribute.PhysicalColour.mkFgColourCode Attribute.PhysicalColour.green- ) . showChar y . foldr (+ \(y, pairs) showsRow -> showsRow . showString axisGraphicsRendition . showChar y . foldr ( \(coordinates, c) acc' -> showString (- Attribute.PhysicalColour.selectGraphicsRendition False . Attribute.PhysicalColour.mkBgColourCode $ (+ Attribute.ANSIColourCode.selectGraphicsRendition False {-isBold-} . Attribute.ANSIColourCode.mkBgColourCode $ ( if Attribute.LogicalColourOfSquare.isBlack $ Cartesian.Coordinates.getLogicalColourOfSquare coordinates then Attribute.ColourScheme.getDarkSquareColour else Attribute.ColourScheme.getLightSquareColour- ) colourScheme+ ) colourScheme ) . showString (- Attribute.PhysicalColour.selectGraphicsRendition True . Attribute.PhysicalColour.mkFgColourCode $ (+ Attribute.ANSIColourCode.selectGraphicsRendition True {-isBold-} . Attribute.ANSIColourCode.mkFgColourCode $ ( if Data.Char.isLower c {-Black-} then Attribute.ColourScheme.getDarkPieceColour else Attribute.ColourScheme.getLightPieceColour- ) colourScheme+ ) colourScheme ) . let showPadding = showString (fromIntegral (pred boardColumnMagnification) `replicate` ' ') in showPadding . showChar c . showPadding . acc' ) showsReset pairs . showChar '\n' ) id . zip (- take (fromIntegral Cartesian.Ordinate.yLength) . enumFrom $ Data.Char.chr yOrigin+ take (fromIntegral Cartesian.Ordinate.yLength) . enumFrom . Data.Char.chr $ fromIntegral yOrigin ) . listToRaster . map (- Control.Arrow.second . Data.Maybe.maybe ' ' $ head . show -- Represent each piece as a single character.+ Control.Arrow.second . Data.Maybe.maybe ' ' $ if depictFigurine+ then Notation.Figurine.toFigurine -- Represent each piece as a Unicode figurine.+ else head . show -- Represent each piece as an ASCII character. ) $ Data.Array.IArray.assocs byCoordinates ) . showString ( replicate (fromIntegral boardColumnMagnification) ' ' -- Shift the line of x-axis labels right.- ) . showString (- Attribute.PhysicalColour.selectGraphicsRendition True $ Attribute.PhysicalColour.mkFgColourCode Attribute.PhysicalColour.green- ) . foldr (.) showsReset (+ ) . showString axisGraphicsRendition . foldr (.) showsReset ( Data.List.intersperse ( showString $ replicate (2 * fromIntegral (pred boardColumnMagnification)) ' ' -- Separate each of the x-axis labels. ) . map showChar . take ( fromIntegral Cartesian.Abscissa.xLength- ) . enumFrom $ Data.Char.chr xOrigin+ ) . enumFrom . Data.Char.chr $ fromIntegral xOrigin ) where+ axisGraphicsRendition :: Attribute.ANSIColourCode.GraphicsRendition+ axisGraphicsRendition = Attribute.ANSIColourCode.selectGraphicsRendition True {-isBold-} $ Attribute.ANSIColourCode.mkFgColourCode Attribute.PhysicalColour.green+ showsReset :: ShowS- showsReset = showString $ Attribute.PhysicalColour.selectGraphicsRendition False 0+ showsReset = showString $ Attribute.ANSIColourCode.selectGraphicsRendition False Data.Default.def -- | Show the board using a two-dimensional representation.-show2D :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Type.Length.Column -- ^ The column-magnification.+show2D+ :: Type.Length.Column -- ^ The column-magnification. -> Attribute.ColourScheme.ColourScheme- -> (Int, Int) -- ^ The origin from which axes are labelled.- -> MaybePieceByCoordinates x y- -> String -- ^ The output suitable for display on a terminal.-show2D boardColumnMagnification colourScheme (xOrigin, yOrigin) maybePieceByCoordinates = shows2D boardColumnMagnification colourScheme (xOrigin, yOrigin) maybePieceByCoordinates ""+ -> 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 "" -- | Extract the pieces from the board, discarding their coordinates.-getPieces :: (- Enum x,- Enum y,- Ord x,- Ord y- ) => MaybePieceByCoordinates x y -> [Component.Piece.Piece]-getPieces MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.catMaybes $ Data.Array.IArray.elems byCoordinates+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/. * CAVEAT: this is a performance-hotspot. -}-findBlockingPiece :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.Direction.Direction -- ^ The direction in which to search.- -> Cartesian.Coordinates.Coordinates x y -- ^ The starting point.- -> MaybePieceByCoordinates x y- -> Maybe (Component.Piece.LocatedPiece x y)-{-# SPECIALISE findBlockingPiece :: Attribute.Direction.Direction -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Maybe (Component.Piece.LocatedPiece Type.Length.X Type.Length.Y) #-}-{- CAVEAT: too slow.-findBlockingPiece direction source MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.listToMaybe . Data.Maybe.mapMaybe (- uncurry fmap . ((,) &&& (byCoordinates !))- ) $ Cartesian.Coordinates.extrapolate direction source-findBlockingPiece direction source maybePieceByCoordinates = fmap (- id &&& Data.Maybe.fromJust . (deconstruct maybePieceByCoordinates !)- ) . Data.List.find (`isOccupied` maybePieceByCoordinates) $ Cartesian.Coordinates.extrapolate direction source-findBlockingPiece direction source MkMaybePieceByCoordinates { deconstruct = byCoordinates } = slave $ Cartesian.Coordinates.extrapolate direction source where- slave (coordinates : remainder) = case byCoordinates ! coordinates of- Nothing -> slave remainder -- Recurse.- Just piece -> Just (coordinates, piece)- slave _ = Nothing-findBlockingPiece direction source MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.listToMaybe [- (coordinates, piece) |- coordinates <- Cartesian.Coordinates.extrapolate direction source,- piece <- Data.Maybe.maybeToList $ byCoordinates ! coordinates- ] -- List-comprehension.--}+findBlockingPiece+ :: Attribute.Direction.Direction -- ^ The direction in which to search.+ -> 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@@ -584,18 +465,12 @@ * N.B.: there no requirement for there to actually be a /piece/ to attack at the specified target. -}-findAttackerInDirection :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The defender's /logical colour/.+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.- -> Cartesian.Coordinates.Coordinates x y -- ^ The defender's square.- -> MaybePieceByCoordinates x y- -> Maybe (Cartesian.Coordinates.Coordinates x y, Attribute.Rank.Rank) -- ^ Any opposing /piece/ which can attack the specified square from the specified /direction/.-{-# SPECIALISE findAttackerInDirection :: Attribute.LogicalColour.LogicalColour -> Attribute.Direction.Direction -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Maybe (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y, Attribute.Rank.Rank) #-}+ -> Cartesian.Coordinates.Coordinates -- ^ The defender's square.+ -> MaybePieceByCoordinates+ -> Maybe (Cartesian.Coordinates.Coordinates, Attribute.Rank.Rank) -- ^ Any opposing /piece/ which can attack the specified square from the specified /direction/. findAttackerInDirection destinationLogicalColour direction destination = (=<<) ( \(source, sourcePiece) -> if Component.Piece.getLogicalColour sourcePiece /= destinationLogicalColour && Component.Piece.canAttackAlong source destination sourcePiece then Just (source, Component.Piece.getRank sourcePiece)@@ -603,27 +478,17 @@ ) . findBlockingPiece direction destination -- | Whether the specified /coordinates/ are unoccupied.-isVacant :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y- -> MaybePieceByCoordinates x y+isVacant+ :: Cartesian.Coordinates.Coordinates+ -> MaybePieceByCoordinates -> Bool {-# INLINE isVacant #-} isVacant coordinates MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Data.Maybe.isNothing $ byCoordinates ! coordinates -- | Whether the specified /coordinates/ are occupied.-isOccupied :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y- -> MaybePieceByCoordinates x y+isOccupied+ :: Cartesian.Coordinates.Coordinates+ -> MaybePieceByCoordinates -> Bool {-# INLINE isOccupied #-} isOccupied coordinates = not . isVacant coordinates@@ -635,34 +500,22 @@ * N.B.: the specified end-points are uninspected. -}-isClear :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y -- ^ Source.- -> Cartesian.Coordinates.Coordinates x y -- ^ Destination.- -> MaybePieceByCoordinates x y+isClear+ :: Cartesian.Coordinates.Coordinates -- ^ Source.+ -> Cartesian.Coordinates.Coordinates -- ^ Destination.+ -> MaybePieceByCoordinates -> Bool {-# INLINABLE isClear #-} -- N.B.: required to ensure specialisation of 'Cartesian.Coordinates.interpolate'.-{-# SPECIALISE isClear :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Bool #-} isClear source destination maybePieceByCoordinates = 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 -- | Whether there's a blockage between a /piece/ presumed to exist at the specified source, & a /piece/ presumed to exist @ the specified destination.-isObstructed :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Cartesian.Coordinates.Coordinates x y -- ^ Source.- -> Cartesian.Coordinates.Coordinates x y -- ^ Destination.- -> MaybePieceByCoordinates x y+isObstructed+ :: Cartesian.Coordinates.Coordinates -- ^ Source.+ -> Cartesian.Coordinates.Coordinates -- ^ Destination.+ -> MaybePieceByCoordinates -> Bool-{-# SPECIALISE isObstructed :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Bool #-} isObstructed source destination = not . isClear source destination {- |@@ -671,16 +524,10 @@ * 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 :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Component.Move.Move x y- -> MaybePieceByCoordinates x y+isEnPassantMove+ :: Component.Move.Move+ -> MaybePieceByCoordinates -> Bool-{-# SPECIALISE isEnPassantMove :: Component.Move.Move Type.Length.X Type.Length.Y -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Bool #-} isEnPassantMove move maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } | Just piece <- byCoordinates ! source , let logicalColour = Component.Piece.getLogicalColour piece@@ -690,24 +537,18 @@ (source, destination) = Component.Move.getSource &&& Component.Move.getDestination $ move -- | Self-documentation.-type Transformation x y = MaybePieceByCoordinates x y -> MaybePieceByCoordinates x y+type Transformation = MaybePieceByCoordinates -> MaybePieceByCoordinates {- | * Adjust the array to reflect a move. * CAVEAT: regrettably this allocates an entire array. -}-movePiece :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Component.Move.Move x y- -> Component.Piece.Piece -- ^ The (possibly promoted) piece to place at the destination.- -> Maybe (Cartesian.Coordinates.Coordinates x y) -- ^ Destination of any En-passant @Pawn@.- -> Transformation x y-{-# SPECIALISE movePiece :: Component.Move.Move Type.Length.X Type.Length.Y -> Component.Piece.Piece -> Maybe (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) -> Transformation Type.Length.X Type.Length.Y #-}+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 [@@ -719,27 +560,4 @@ Just destinationPiece -- Place the piece at the destination, removing any opposing incumbent as a side-effect. ) ]---- | Calculate the total value of the /coordinates/ occupied by the /piece/s of either side.-sumPieceSquareValueByLogicalColour :: (- Enum x,- Enum y,- Num pieceSquareValue,- Ord x,- Ord y- )- => Component.PieceSquareByCoordinatesByRank.FindPieceSquareValue x y pieceSquareValue- -> MaybePieceByCoordinates x y- -> [pieceSquareValue]-{-# SPECIALISE sumPieceSquareValueByLogicalColour :: Component.PieceSquareByCoordinatesByRank.FindPieceSquareValue Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue -> MaybePieceByCoordinates Type.Length.X Type.Length.Y -> [Type.Mass.PieceSquareValue] #-}-sumPieceSquareValueByLogicalColour findPieceSquareValue = (- \(b, w) -> [b, w]- ) . Data.List.foldl' (- \(b, w) (coordinates, piece) -> let- logicalColour = Component.Piece.getLogicalColour piece- pieceSquareValue = findPieceSquareValue logicalColour (Component.Piece.getRank piece) coordinates- in if Attribute.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
src-lib/BishBosh/State/Position.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -52,26 +51,19 @@ import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour import qualified BishBosh.State.EnPassantAbscissa as State.EnPassantAbscissa import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates-import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable import qualified Control.DeepSeq-import qualified Data.Array.IArray import qualified Data.Maybe -- | The state of the game, without regard to how it arrived there.-data Position x y = MkPosition {+data Position = MkPosition { getNextLogicalColour :: Attribute.LogicalColour.LogicalColour, -- ^ The next player to move.- getMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates x y,- getCastleableRooksByLogicalColour :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x,- getMaybeEnPassantAbscissa :: Maybe (State.EnPassantAbscissa.EnPassantAbscissa x)+ getMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates,+ getCastleableRooksByLogicalColour :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour,+ getMaybeEnPassantAbscissa :: Maybe State.EnPassantAbscissa.EnPassantAbscissa } deriving Eq -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Ord (Position x y) where- {-# SPECIALISE instance Ord (Position Type.Length.X Type.Length.Y) #-}+instance Ord Position where position@MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates@@ -90,10 +82,7 @@ getMaybeEnPassantAbscissa position' ) -instance (- Control.DeepSeq.NFData x,- Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Position x y) where+instance Control.DeepSeq.NFData Position where rnf MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates,@@ -101,12 +90,7 @@ getMaybeEnPassantAbscissa = maybeEnPassantAbscissa } = Control.DeepSeq.rnf (nextLogicalColour, maybePieceByCoordinates, castleableRooksByLogicalColour, maybeEnPassantAbscissa) -instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Property.Reflectable.ReflectableOnX (Position x y) where+instance Property.Reflectable.ReflectableOnX Position where reflectOnX position@MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates,@@ -117,8 +101,8 @@ getCastleableRooksByLogicalColour = Property.Reflectable.reflectOnX castleableRooksByLogicalColour } -instance (Data.Array.IArray.Ix x, Enum x, Enum y, Ord y) => Component.Zobrist.Hashable2D Position x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where- listRandoms2D MkPosition {+instance StateProperty.Hashable.Hashable Position where+ listRandoms MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -128,22 +112,16 @@ then (Component.Zobrist.getRandomForBlacksMove zobrist :) else id ) . Data.Maybe.maybe id (- (++) . (`Component.Zobrist.listRandoms1D` zobrist)- ) maybeEnPassantAbscissa $ Component.Zobrist.listRandoms1D castleableRooksByLogicalColour zobrist ++ Component.Zobrist.listRandoms2D maybePieceByCoordinates zobrist+ (++) . (`StateProperty.Hashable.listRandoms` zobrist)+ ) maybeEnPassantAbscissa $ StateProperty.Hashable.listRandoms castleableRooksByLogicalColour zobrist ++ StateProperty.Hashable.listRandoms maybePieceByCoordinates zobrist -- | Constructor.-mkPosition :: (- Enum x,- Enum y,- Ord x,- Ord y- )- => Attribute.LogicalColour.LogicalColour -- ^ The logical colour of the next player to move.- -> State.MaybePieceByCoordinates.MaybePieceByCoordinates x y- -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x- -> Maybe (Component.Turn.Turn x y) -- ^ The last /turn/ made.- -> Position x y-{-# SPECIALISE mkPosition :: Attribute.LogicalColour.LogicalColour -> State.MaybePieceByCoordinates.MaybePieceByCoordinates Type.Length.X Type.Length.Y -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour Type.Length.X -> Maybe (Component.Turn.Turn Type.Length.X Type.Length.Y) -> Position Type.Length.X Type.Length.Y #-}+mkPosition+ :: Attribute.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.+ -> Position mkPosition nextLogicalColour maybePieceByCoordinates castleableRooksByLogicalColour maybeLastTurn = MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates, -- N.B.: one could have used 'State.CoordinatesByRankByLogicalColour.CoordinatesByRankByLogicalColour', except that the coordinates have an undefined order.
+ src-lib/BishBosh/StateProperty/Hashable.hs view
@@ -0,0 +1,64 @@+{-+ 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 random-numbers required to construct a hash of a chess-position.++ * Facilitates the construction of a hash from arbitrary data.+-}++module BishBosh.StateProperty.Hashable(+-- * Type-classes+ Hashable(..),+-- * Constants+-- combiningOp,+-- * Functions+ hash,+ combine+) where++import qualified BishBosh.Component.Zobrist as Component.Zobrist+import qualified Data.Bits+import qualified Data.List++-- | An interface to which hashable data can conform.+class Hashable hashable where+ listRandoms :: hashable -> Component.Zobrist.Zobrist positionHash -> [positionHash]++-- | The operator used when combining random numbers to compose a hash.+combiningOp :: Data.Bits.Bits positionHash => positionHash -> positionHash -> positionHash+combiningOp = Data.Bits.xor++-- | Resolve a hashable into a hash.+hash :: (+ Data.Bits.Bits positionHash,+ Hashable hashable+ )+ => hashable+ -> Component.Zobrist.Zobrist positionHash+ -> positionHash+hash hashable = Data.List.foldl1' combiningOp . listRandoms hashable++-- | Include a list of random numbers in the hash.+combine :: Data.Bits.Bits positionHash => positionHash -> [positionHash] -> positionHash+combine = Data.List.foldl' combiningOp+
src-lib/BishBosh/StateProperty/Mutator.hs view
@@ -47,12 +47,12 @@ * CAVEAT: this function isn't called during normal play. -}-class Mutator mutator x y where+class Mutator mutator where defineCoordinates- :: Maybe Component.Piece.Piece -- ^ The optional /piece/ to place (or remove if @Nothing@ is specified).- -> Cartesian.Coordinates.Coordinates x y -- ^ The /coordinates/ to define.- -> mutator x y- -> mutator x y+ :: Maybe Component.Piece.Piece -- ^ The optional /piece/ to place (or remove if @Nothing@ is specified).+ -> Cartesian.Coordinates.Coordinates -- ^ The /coordinates/ to define.+ -> mutator+ -> mutator {- | * Place a /piece/ at the specified /coordinates/.@@ -60,38 +60,38 @@ * CAVEAT: any /piece/ previously at the specified /coordinates/ will be obliterated. -} placePiece- :: Mutator mutator x y+ :: Mutator mutator => Component.Piece.Piece- -> Cartesian.Coordinates.Coordinates x y- -> mutator x y- -> mutator x y+ -> Cartesian.Coordinates.Coordinates+ -> mutator+ -> mutator placePiece piece = defineCoordinates $ Just piece -- | Place the first /piece/. placeFirstPiece :: (- Property.Empty.Empty (mutator x y),- Mutator mutator x y+ Property.Empty.Empty mutator,+ Mutator mutator ) => Component.Piece.Piece- -> Cartesian.Coordinates.Coordinates x y- -> mutator x y+ -> Cartesian.Coordinates.Coordinates+ -> mutator placeFirstPiece piece coordinates = placePiece piece coordinates Property.Empty.empty -- | Place /pieces/ from scratch. placeAllPieces :: (- Property.Empty.Empty (mutator x y),- Mutator mutator x y+ Property.Empty.Empty mutator,+ Mutator mutator )- => [(Component.Piece.Piece, Cartesian.Coordinates.Coordinates x y)]- -> mutator x y+ => [(Component.Piece.Piece, Cartesian.Coordinates.Coordinates)]+ -> mutator placeAllPieces = foldr (uncurry placePiece) Property.Empty.empty -- | Remove a /piece/ from the /board/. removePiece- :: Mutator mutator x y- => Cartesian.Coordinates.Coordinates x y- -> mutator x y- -> mutator x y+ :: Mutator mutator+ => Cartesian.Coordinates.Coordinates+ -> mutator+ -> mutator removePiece = defineCoordinates Nothing
src-lib/BishBosh/StateProperty/Seeker.hs view
@@ -24,32 +24,81 @@ -} module BishBosh.StateProperty.Seeker(+-- * Types+-- ** Type-synonyms+-- NPiecesByFile,+ NPiecesByFileByLogicalColour, -- * Type-classes Seeker(..), -- * Functions- findAllPieces+ accumulatePawnsByFile,+ findAllPieces,+ summariseNPawnsByLogicalColour ) where +import Control.Arrow((***)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Property.Empty as Property.Empty+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.Map.Strict as Map +-- | The number of /piece/s in each file, for each /logical colour/.+type NPiecesByFile = Map.Map Type.Length.X Type.Count.NPieces++-- | Add a Pawn's file to the map.+accumulatePawnsByFile :: Type.Length.X -> NPiecesByFile -> NPiecesByFile+{-# INLINE accumulatePawnsByFile #-}+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+ -- | An interface which may be implemented by data which can search the board.-class Seeker seeker x y where- -- | Locate any @Knight@s capable of taking a piece at the specified coordinates.+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 x y -- ^ The destination to which the @Knight@ is required to be capable of jumping.- -> seeker x y- -> [Cartesian.Coordinates.Coordinates x y]+ -> Cartesian.Coordinates.Coordinates -- ^ The destination to which the @Knight@ is required to be capable of jumping.+ -> seeker+ -> [Cartesian.Coordinates.Coordinates] -- | Locate any /piece/s satisfying the specified predicate. findPieces :: (Component.Piece.Piece -> Bool) -- ^ Predicate.- -> seeker x y- -> [Component.Piece.LocatedPiece x y]+ -> seeker+ -> [Component.Piece.LocatedPiece] + {- |+ * Counts the number of @Pawn@s of each /logical colour/ with similar /x/-coordinates; their /y/-coordinate is irrelevant.++ * N.B.: files lacking any @Pawn@, don't feature in the results.+ -}+ countPawnsByFileByLogicalColour :: seeker -> NPiecesByFileByLogicalColour+ countPawnsByFileByLogicalColour = (+ \(mB, mW) -> Attribute.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+ )+ ) Property.Empty.empty . findPieces Component.Piece.isPawn+ -- | Locate all /piece/s on the board.-findAllPieces :: Seeker seeker x y => seeker x y -> [Component.Piece.LocatedPiece x y]+findAllPieces :: Seeker seeker => seeker -> [Component.Piece.LocatedPiece] 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 = Data.Array.IArray.amap (+ Data.Foldable.foldl' (+) 0+ ) . countPawnsByFileByLogicalColour
src-lib/BishBosh/Text/Poly.hs view
@@ -37,10 +37,12 @@ import qualified BishBosh.Data.Integral as Data.Integral import qualified Data.Char -#if USE_POLYPARSE == 1+#if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+#elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly+#else+# error "USE_POLYPARSE invalid" #endif -- | Self-documentation.
+ src-lib/BishBosh/Text/ShowColouredPrefix.hs view
@@ -0,0 +1,53 @@+{-+ 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@] Define standard prefixes for log-messages.+-}++module BishBosh.Text.ShowColouredPrefix(+-- * Constants+ showsPrefixInfo,+ showsPrefixWarning,+ 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++-- | 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+ ) $ 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+ ) $ 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+ ) $ Text.ShowPrefix.showsPrefixError ""+
src-lib/BishBosh/Time/GameClock.hs view
@@ -63,11 +63,11 @@ | 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- ) . mapM Property.Switchable.toggle . Data.Array.IArray.elems $ deconstruct gameClock+ ) . mapM Property.Switchable.toggle . Data.Foldable.toList $ deconstruct gameClock switchOff = fmap ( MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour- ) . mapM Property.Switchable.switchOff . Data.Array.IArray.elems . deconstruct -- CAVEAT: this invalidates the clock, since a subsequent call to 'toggle' would activate both stop-watches.+ ) . 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. @@ -75,7 +75,7 @@ instance Property.SelfValidating.SelfValidating GameClock where findInvalidity = Property.SelfValidating.findErrors [- ((/= 1) . length . filter Property.Switchable.isOn . Data.Array.IArray.elems . deconstruct, "The two stop-watches must be in opposite states")+ ((/= 1) . length . filter Property.Switchable.isOn . Data.Foldable.toList . deconstruct, "The two stop-watches must be in opposite states") ] -- | Show the elapsed times.
src-lib/BishBosh/Type/Count.hs view
@@ -22,7 +22,7 @@ [@DESCRIPTION@] - * Defines distinct types for various countable quantities to prevent accidental conflation between conceptually different quantities.+ * Defines distinct types for various conceptually different countable quantities to prevent accidental conflation. * Nothing but the type is exported, facilitating reversion to unwrapped types. -}@@ -32,6 +32,7 @@ -- ** Type-synonyms -- Base, -- ** Data-types+ NCoordinates, NDecimalDigits, NDirections, NGames,@@ -50,9 +51,19 @@ import qualified Text.XML.HXT.Arrow.Pickle as HXT #endif --- | The private type which is wrapped by countable data-types.+-- | The private type which is wrapped by various countable data-types. type Base = Int +-- | A number of (board) coordinates.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NCoordinates = MkNCoordinates Base deriving (Enum, Eq, Integral, Num, Ord, Real)++instance Show NCoordinates where+ showsPrec precedence (MkNCoordinates n) = showsPrec precedence n+#else+type NCoordinates = Base+#endif+ -- | A number of decimal digits. #ifdef USE_NEWTYPE_WRAPPERS newtype NDecimalDigits = MkNDecimalDigits Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real)@@ -63,7 +74,7 @@ type NDecimalDigits = Base #endif --- | A number of decimal digits.+-- | A number of directions. #ifdef USE_NEWTYPE_WRAPPERS newtype NDirections = MkNDirections Base deriving (Enum, Eq, Integral, Num, Ord, Real) #else
src-lib/BishBosh/Type/Length.hs view
@@ -23,8 +23,10 @@ [@DESCRIPTION@] - * Defines suitable concrete types with which to specialise length-related type-parameters.+ * Defines distinct types for various conceptually different length-related quantities to prevent accidental conflation. + * Nothing but the type is exported, facilitating reversion to unwrapped types.+ * CAVEAT: use of narrow numeric types, results in marginally slower performance without any reduction in space-requirements. -} @@ -32,11 +34,11 @@ -- * Types -- ** Type-synonyms -- Base,- Distance,+-- ** Data-types X, Y,- Row(),- Column()+ Row,+ Column ) where #if defined(USE_NARROW_NUMBERS) || defined(USE_NEWTYPE_WRAPPERS)@@ -45,12 +47,14 @@ # endif # ifdef USE_NEWTYPE_WRAPPERS+import qualified Control.Arrow import qualified Control.DeepSeq+import qualified Data.Array.IArray # endif import qualified Text.XML.HXT.Arrow.Pickle as HXT #endif --- | The preferred type by which to represent the abscissa. CAVEAT: while conceptually unsigned, various unguarded calls to 'pred' prevent this.+-- | The private type which is wrapped by various length-related data-types. type Base = #ifdef USE_NARROW_NUMBERS Data.Int.Int8@@ -61,36 +65,49 @@ Int #endif -{- |- * The preferred type by which to represent the signed distance of a move.+-- | The board-abscissa.+#ifdef USE_NEWTYPE_WRAPPERS+newtype X = MkX Base deriving (Control.DeepSeq.NFData, Data.Array.IArray.Ix, Enum, Eq, Integral, Num, Ord, Real) - * N.B.: since /distance/ is used to represent only the horizontal or vertical component of a move, rather than a diagonal length, it can be represented by an integral value.--}-type Distance = Base -- N.B.: conceptually independent of both 'X' & 'Y' which could be unsigned.+instance Read X where+ readsPrec precision = map (Control.Arrow.first MkX) . readsPrec precision --- | The distance along the abscissa.-type X = Base+instance Show X where+ showsPrec precision (MkX x) = showsPrec precision x+#else+type X = Base+#endif --- | The distance along the ordinate.-type Y = Base -- N.B.: it can be independent of 'X'.+-- | The board-ordinate; independent of /X/.+#ifdef USE_NEWTYPE_WRAPPERS+newtype Y = MkY Base deriving (Control.DeepSeq.NFData, Enum, Eq, Integral, Num, Ord, Real) +instance Read Y where+ readsPrec precision = map (Control.Arrow.first MkY) . readsPrec precision++instance Show Y where+ showsPrec precision (MkY y) = showsPrec precision y+#else+type Y = Base+#endif+ -- | Indexes screen-coordinates in the vertical direction. #ifdef USE_NEWTYPE_WRAPPERS-newtype Row = MkRow Y deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real)+newtype Row = MkRow Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real) instance Show Row where showsPrec precision (MkRow row) = showsPrec precision row #else-type Row = Y+type Row = Base #endif -- | Indexes screen-coordinates in the horizontal direction. #ifdef USE_NEWTYPE_WRAPPERS-newtype Column = MkColumn X deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real)+newtype Column = MkColumn Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real) instance Show Column where showsPrec precision (MkColumn column) = showsPrec precision column #else-type Column = X+type Column = Base #endif
src-lib/BishBosh/Type/Mass.hs view
@@ -38,20 +38,28 @@ PieceSquareValue ) where +#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 =-#ifdef USE_NARROW_NUMBERS+#ifdef USE_PRECISION+ Rational+#else /* Floating-point */+# ifdef USE_NARROW_NUMBERS Float instance HXT.XmlPickler Float where xpickle = HXT.xpPrim-#else- Double -- N.B.: 'Rational' is a more accurate, but slower alternative.+# else+ Double instance HXT.XmlPickler Double where xpickle = HXT.xpPrim+# endif #endif -- | The preferred type by which to value criteria.
src-lib/BishBosh/UI/Command.hs view
@@ -28,13 +28,13 @@ -- ** Data-types Command(..), -- * Constants- commandPrefix,+-- commandPrefix, -- hintTag, printTag, -- quitTag, -- reportTag, -- resignTag,- restartTag,+-- restartTag, -- rollBackTag, -- saveTag, setTag,@@ -48,17 +48,18 @@ -- * Functions readsCommand, showsCommand,+ issueCommand, autoComplete ) where import qualified BishBosh.Data.List-import qualified BishBosh.Input.Options as Input.Options-import qualified BishBosh.Input.SearchOptions as Input.SearchOptions-import qualified BishBosh.Text.AutoComplete as Text.AutoComplete-import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.UI.PrintObject as UI.PrintObject-import qualified BishBosh.UI.ReportObject as UI.ReportObject-import qualified BishBosh.UI.SetObject as UI.SetObject+import qualified BishBosh.Input.Options as Input.Options+import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription+import qualified BishBosh.Text.AutoComplete as Text.AutoComplete+import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.UI.PrintObject as UI.PrintObject+import qualified BishBosh.UI.ReportObject as UI.ReportObject+import qualified BishBosh.UI.SetObject as UI.SetObject import qualified Control.Arrow import qualified Control.DeepSeq import qualified Data.List@@ -125,24 +126,25 @@ -- | The format of the argument to the runtime-command /set/. setArgs :: String setArgs = Data.List.intercalate alternationTag [- showString Input.SearchOptions.searchDepthTag " <Int>"+ showString Property.ExtendedPositionDescription.tag " <EPD>",+ showString UI.SetObject.searchDepthTag " <Int>" ] -- | The sum-type of commands that a user may issue.-data Command x y- = Hint -- ^ Request a move-suggestion.- | Print UI.PrintObject.PrintObject -- ^ Print the requested static data.- | Quit -- ^ Terminate this application.- | Report UI.ReportObject.ReportObject -- ^ Report on the requested dynamic data.- | Resign -- ^ Admit defeat.- | Restart -- ^ Abandon the current game, & start afresh.- | RollBack (Maybe Type.Count.NPlies) -- ^ Roll-back the optionally specified number of plies.- | Save -- ^ Persist the current game-state.- | Set UI.SetObject.SetObject -- ^ I.E. mutate a configuration-value.- | Swap -- ^ Swap options between the two sides; which causes the players to swap sides.+data Command+ = Hint -- ^ Request a move-suggestion.+ | Print UI.PrintObject.PrintObject -- ^ Print the requested static data.+ | Quit -- ^ Terminate this application.+ | Report UI.ReportObject.ReportObject -- ^ Report on the requested dynamic data.+ | Resign -- ^ Admit defeat.+ | Restart -- ^ Abandon the current game, & start afresh.+ | RollBack (Maybe Type.Count.NPlies) -- ^ Roll-back the optionally specified number of plies.+ | Save -- ^ Persist the current game-state.+ | Set UI.SetObject.SetObject -- ^ I.E. mutate something.+ | Swap -- ^ Swap options between the two sides; which causes the players to swap sides. deriving (Eq, Show) -instance Control.DeepSeq.NFData (Command x y) where+instance Control.DeepSeq.NFData Command where rnf (Print printObject) = Control.DeepSeq.rnf printObject rnf (Set setObject) = Control.DeepSeq.rnf setObject rnf _ = ()@@ -185,7 +187,7 @@ ), ( setTag, Just setArgs,- showString "Mutate " Input.Options.tag+ "Mutate something" ), ( swapTag, Nothing,@@ -213,7 +215,7 @@ objectFieldWidth = succ $ maximum [length arg | (_, Just arg, _) <- commands] -- | Reads a /command/.-readsCommand :: String -> Either String (Command x y, String)+readsCommand :: String -> Either String (Command, String) readsCommand [] = Left . showString "null command received; specify one of " . show $ map (\(tag, _, _) -> tag) commands readsCommand s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of [("hint", s')] -> Right (Hint, s')@@ -243,7 +245,7 @@ _ -> Left "no command received" -- | Shows a /command/.-showsCommand :: Command x y -> ShowS+showsCommand :: Command -> ShowS showsCommand = \case Hint -> showString hintTag Print printObject -> showString printTag . showChar ' ' . shows printObject@@ -251,10 +253,14 @@ Report reportObject -> showString reportTag . showChar ' ' . shows reportObject Resign -> showString resignTag Restart -> showString restartTag- RollBack maybeNMoves -> showString rollBackTag . Data.Maybe.maybe id (\nMoves -> showChar ' ' . shows nMoves) maybeNMoves+ RollBack maybeNPlies -> showString rollBackTag . Data.Maybe.maybe id (\nPlies -> showChar ' ' . shows nPlies) maybeNPlies Save -> showString saveTag Set setObject -> showString setTag . showChar ' ' . shows setObject Swap -> showString swapTag++-- | Show the specified command in the format required by this application's parser.+issueCommand :: Command -> ShowS+issueCommand command = showChar commandPrefix . shows command -- | Replace the first word of the specified string with the name of a command of which it is an unambiguous case-insensitive prefix. autoComplete :: ShowS
src-lib/BishBosh/UI/ReportObject.hs view
@@ -29,7 +29,6 @@ -- * Constants -- availableMovesTag, -- boardTag,--- epdTag, -- fenTag, -- gameTag, -- maxPositionInstancesTag,@@ -41,8 +40,10 @@ autoComplete ) where -import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Text.AutoComplete as Text.AutoComplete+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Text.AutoComplete as Text.AutoComplete import qualified Control.Arrow import qualified Control.DeepSeq import qualified Data.List.Extra@@ -56,10 +57,6 @@ boardTag = "board" -- | Input-format.-epdTag :: String-epdTag = "epd"---- | Input-format. fenTag :: String fenTag = "fen" @@ -73,7 +70,7 @@ -- | Input-format. movesTag :: String-movesTag = "moves"+movesTag = showString Component.Move.tag "s" -- | Input-format. pgnTag :: String@@ -102,7 +99,7 @@ instance Show ReportObject where show AvailableMoves = availableMovesTag show Board = boardTag- show EPD = epdTag+ show EPD = Property.ExtendedPositionDescription.tag show FEN = fenTag show Game = gameTag show MaxPositionInstances = maxPositionInstancesTag@@ -135,7 +132,7 @@ autoComplete = Text.AutoComplete.autoComplete [ availableMovesTag, boardTag,- epdTag,+ Property.ExtendedPositionDescription.tag, fenTag, gameTag, maxPositionInstancesTag,
src-lib/BishBosh/UI/SetObject.hs view
@@ -19,42 +19,62 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Defines the fields a user can mutate.+ [@DESCRIPTION@] Defines the things a user can mutate at runtime. -} module BishBosh.UI.SetObject ( -- * Types -- ** Data-types SetObject(..),+-- * Constants+ searchDepthTag, -- * Functions autoComplete, -- ** Constructors+ mkEPD, mkSearchDepth ) where -import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Input.SearchOptions as Input.SearchOptions-import qualified BishBosh.Text.AutoComplete as Text.AutoComplete-import qualified BishBosh.Type.Count as Type.Count++import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Input.SearchOptions as Input.SearchOptions+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription+import qualified BishBosh.Text.AutoComplete as Text.AutoComplete+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.List.Extra --- | The fields a user can mutate; currently there's only one.-newtype SetObject = SearchDepth Type.Count.NPlies deriving Eq+-- | Input-format.+searchDepthTag :: String+searchDepthTag = Input.SearchOptions.searchDepthTag +-- | The sum-type of fields a user can mutate.+data SetObject+ = EPD Model.Game.Game -- ^ Define the position.+ | SearchDepth Type.Count.NPlies -- ^ Set the number of plies to to search ahead for the optimal move.+ deriving Eq+ instance Control.DeepSeq.NFData SetObject where- rnf (SearchDepth searchDepth) = Control.DeepSeq.rnf searchDepth+ rnf (EPD epd) = Control.DeepSeq.rnf epd+ rnf (SearchDepth searchDepth) = Control.DeepSeq.rnf searchDepth instance Show SetObject where- showsPrec _ (SearchDepth searchDepth) = showString Input.SearchOptions.searchDepthTag . showChar ' ' . shows searchDepth+ showsPrec _ (EPD epd) = showString Property.ExtendedPositionDescription.tag . showChar ' ' . Property.ExtendedPositionDescription.showsEPD epd+ showsPrec _ (SearchDepth searchDepth) = showString searchDepthTag . showChar ' ' . shows searchDepth instance Read SetObject where- readsPrec _ s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of- [("searchdepth", s')] -> Control.Arrow.first (mkSearchDepth . fromInteger) `map` reads s'- _ -> [] -- No parse.+ readsPrec precedence s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of+ [("epd", epd)] -> Control.Arrow.first EPD `map` Property.ExtendedPositionDescription.readsEPD epd+ [("searchdepth", s')] -> Control.Arrow.first (mkSearchDepth . fromInteger) `map` readsPrec precedence s'+ _ -> [] -- No parse. +-- | Constructor.+mkEPD :: Model.Game.Game -> SetObject+mkEPD = EPD+ -- | Smart constructor. mkSearchDepth :: Type.Count.NPlies -> SetObject mkSearchDepth searchDepth@@ -63,5 +83,5 @@ -- | Replace the first word of the specified string with the name of a command of which it is an unambiguous case-insensitive prefix. autoComplete :: ShowS-autoComplete = Text.AutoComplete.autoComplete [Input.SearchOptions.searchDepthTag]+autoComplete = Text.AutoComplete.autoComplete [Property.ExtendedPositionDescription.tag, searchDepthTag]
src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs view
@@ -23,9 +23,6 @@ -} module BishBosh.Test.HUnit.Cartesian.Coordinates(--- * Types--- ** Type-synonyms- Coordinates, -- * Constants testCases ) where@@ -33,31 +30,27 @@ 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.Type.Length as Type.Length import qualified Data.Array.IArray import qualified Data.List import qualified Test.HUnit import Test.HUnit((~?), (~?=), (~:)) --- | Defines a concrete type for testing.-type Coordinates = Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y- -- | 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 :: Coordinates)+ Cartesian.Coordinates.extrapolate maxBound {-direction-} (minBound :: Cartesian.Coordinates.Coordinates) ) ~? "'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 (- Property.FixedMembership.members :: [Coordinates]+ Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates] ), "'BishBosh.Cartesian.Coordinates' failed to visit all squares." ~: length (- Property.FixedMembership.members :: [Coordinates]- ) ~?= Cartesian.Coordinates.nSquares,+ Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates]+ ) ~?= fromIntegral Cartesian.Coordinates.nSquares, "instance 'Data.Array.IArray.Ix Coordinates' is incompatible with instance 'Ord Coordinates'." ~: Data.Array.IArray.indices (- Cartesian.Coordinates.listArrayByCoordinates [0 .. ] :: Cartesian.Coordinates.ArrayByCoordinates Type.Length.X Type.Length.Y Int+ Cartesian.Coordinates.listArrayByCoordinates [0 .. ] :: Cartesian.Coordinates.ArrayByCoordinates Int ) ~?= Property.FixedMembership.members ]
src-test/BishBosh/Test/HUnit/Cartesian/Vector.hs view
@@ -32,28 +32,23 @@ import Control.Arrow((&&&)) import qualified BishBosh.Cartesian.Vector as Cartesian.Vector import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Maybe import qualified Test.HUnit import Test.HUnit((~?)) -- | Sum the absolute value of /x/ & /y/ distances.-measureLength :: Cartesian.Vector.VectorInt -> Type.Length.Distance-measureLength = uncurry (+) . (abs . Cartesian.Vector.getXDistance &&& abs . Cartesian.Vector.getYDistance)+measureLength :: Cartesian.Vector.Vector -> Int+measureLength = uncurry (+) . (fromIntegral . abs . Cartesian.Vector.getXDistance &&& fromIntegral . abs . Cartesian.Vector.getYDistance) -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [ all ( Data.Maybe.isJust . Cartesian.Vector.toMaybeDirection- ) (- Cartesian.Vector.attackVectorsForKing :: [Cartesian.Vector.VectorInt]- ) ~? "'BishBosh.Cartesian.Vector.attackVectorsForKing' failed.",+ ) Cartesian.Vector.attackVectorsForKing ~? "'BishBosh.Cartesian.Vector.attackVectorsForKing' failed.", all ( Data.Maybe.isNothing . Cartesian.Vector.toMaybeDirection- ) (- Cartesian.Vector.attackVectorsForKnight :: [Cartesian.Vector.VectorInt]- ) ~? "'BishBosh.Cartesian.Vector.attackVectorsForKnight' failed.",+ ) Cartesian.Vector.attackVectorsForKnight ~? "'BishBosh.Cartesian.Vector.attackVectorsForKnight' failed.", all ( uncurry (&&) . ( all ((== 2) . measureLength) &&& (== 2) . length
src-test/BishBosh/Test/HUnit/Component/CastlingMove.hs view
@@ -33,7 +33,6 @@ import qualified BishBosh.Component.CastlingMove as Component.CastlingMove import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Test.HUnit.Component.Move as Test.HUnit.Component.Move import qualified BishBosh.Type.Length as Type.Length import qualified Data.List import qualified Test.HUnit@@ -49,7 +48,7 @@ and [ (== 1) . length . Data.List.nub $ map ( map (- \castlingMove -> getAbscissa (getMove castlingMove :: Test.HUnit.Component.Move.Move)+ \castlingMove -> getAbscissa (getMove castlingMove :: Component.Move.Move) ) . Component.CastlingMove.getCastlingMoves ) Property.FixedMembership.members | getMove <- [Component.CastlingMove.getKingsMove, Component.CastlingMove.getRooksMove],@@ -58,7 +57,7 @@ ] ~? "'BishBosh.Component.CastlingMove':\tdistance spanned by castling-moves should be independent of logical colour.", all ( \logicalColour -> (== 1) . length $ Data.List.nub [- Cartesian.Coordinates.getY $ getTerminus (getMove castlingMove :: Test.HUnit.Component.Move.Move) |+ Cartesian.Coordinates.getY $ getTerminus (getMove castlingMove :: Component.Move.Move) | castlingMove <- Component.CastlingMove.getCastlingMoves logicalColour, getMove <- [Component.CastlingMove.getKingsMove, Component.CastlingMove.getRooksMove], getTerminus <- [Component.Move.getSource, Component.Move.getDestination]@@ -67,7 +66,7 @@ and [ abs ( Cartesian.Vector.getXDistance $ Component.Move.measureDistance (- Component.CastlingMove.getKingsMove castlingMove :: Test.HUnit.Component.Move.Move+ Component.CastlingMove.getKingsMove castlingMove :: Component.Move.Move ) ) == kingsMoveLength | logicalColour <- Property.FixedMembership.members,
src-test/BishBosh/Test/HUnit/Component/Move.hs view
@@ -23,9 +23,6 @@ -} module BishBosh.Test.HUnit.Component.Move(--- * Types--- ** Type-synonyms- Move, -- * Constants testCases ) where@@ -35,19 +32,15 @@ import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Notation.Smith as Notation.Smith-import qualified BishBosh.Type.Length as Type.Length import qualified Test.HUnit import Test.HUnit((~?)) --- | Defines a concrete type for testing.-type Move = Component.Move.Move Type.Length.X Type.Length.Y- -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [ all ( \(direction, s) -> let- move :: Move+ 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 ) [
src-test/BishBosh/Test/HUnit/Component/Piece.hs view
@@ -28,15 +28,15 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Cartesian.Vector as Cartesian.Vector-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.Notation.Smith as Notation.Smith-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Test.HUnit.Cartesian.Coordinates as Test.HUnit.Cartesian.Coordinates+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.Component.Move as Component.Move+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Notation.Smith as Notation.Smith+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified Data.List import qualified Test.HUnit import Test.HUnit((~?), (~?=), (~:))@@ -52,16 +52,14 @@ Data.List.sort . uncurry (++) $ (Component.Piece.getAttackDirections . Component.Piece.mkBishop &&& Component.Piece.getAttackDirections . Component.Piece.mkRook) Attribute.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.VectorInt] -> Int- ) Cartesian.Vector.attackVectorsForKing ~?= length (Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black)+ length Cartesian.Vector.attackVectorsForKing ~?= length (Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black) ), "'BishBosh.Component.Piece.getAttackDirections' failed for King." ~: Data.List.sort ( Component.Piece.getAttackDirections $ Component.Piece.mkKing Attribute.LogicalColour.Black {-arbitrarily-} ) ~?= Property.FixedMembership.members, all ( \((s, logicalColour), rank) -> let- source, destination :: Test.HUnit.Cartesian.Coordinates.Coordinates+ source, destination :: Cartesian.Coordinates.Coordinates (source, destination) = (Component.Move.getSource &&& Component.Move.getDestination) . Component.QualifiedMove.getMove . Notation.Smith.getQualifiedMove $ read s in Component.Piece.canAttackAlong source destination $ Component.Piece.mkPiece logicalColour rank ) (@@ -116,7 +114,7 @@ not ( any ( \((s, logicalColour), rank) -> let- source, destination :: Test.HUnit.Cartesian.Coordinates.Coordinates+ source, destination :: Cartesian.Coordinates.Coordinates (source, destination) = (Component.Move.getSource &&& Component.Move.getDestination) . Component.QualifiedMove.getMove . Notation.Smith.getQualifiedMove $ read s in Component.Piece.canAttackAlong source destination $ Component.Piece.mkPiece logicalColour rank ) $ concat [
src-test/BishBosh/Test/HUnit/Component/Zobrist.hs view
@@ -25,27 +25,26 @@ module BishBosh.Test.HUnit.Component.Zobrist( -- * Types -- ** Type-synonyms- Zobrist,+-- Zobrist, -- * Constants testCases ) where import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Default import qualified Data.Foldable import qualified Test.HUnit import Test.HUnit((~:), (~?=)) -- | Defines a concrete type for testing.-type Zobrist = Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash+type Zobrist = Component.Zobrist.Zobrist Type.Crypto.PositionHash -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [- "'BishBosh.Component.Zobrist.Zobrist' contains the wrong number of random numbers." ~: length (- Data.Foldable.toList (Data.Default.def :: Zobrist)+ "'BishBosh.Component.Zobrist.Zobrist' contains the wrong number of random numbers." ~: Data.Foldable.length (+ Data.Default.def :: Zobrist ) ~?= 781 -- <https://www.chessprogramming.org/Zobrist_Hashing> ]
src-test/BishBosh/Test/HUnit/ContextualNotation/PGN.hs view
@@ -24,64 +24,61 @@ -} module BishBosh.Test.HUnit.ContextualNotation.PGN(--- * Types--- ** Type-synonyms--- PGN, -- * Constants testCases ) where import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN-import qualified BishBosh.Type.Length as Type.Length import qualified Test.HUnit import Test.HUnit((~?)) #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Data.Char import qualified Text.ParserCombinators.Poly.Lazy as Poly-# else /* Plain */+# elif USE_POLYPARSE == 'P' import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly+# else+# error "USE_POLYPARSE invalid" # endif #else /* Parsec */ import Control.Arrow((|||)) import qualified Text.ParserCombinators.Parsec as Parsec #endif -#if !defined(USE_POLYPARSE) || USE_POLYPARSE != 1+#if !defined(USE_POLYPARSE) || USE_POLYPARSE != 'L' import qualified BishBosh.Data.Exception as Data.Exception import qualified Control.Exception #endif --- | Test-subject.-type PGN = ContextualNotation.PGN.PGN Type.Length.X Type.Length.Y- -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test $ map ( \(isStrictlySequential, validateMoves, s) -> #ifdef USE_POLYPARSE-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' ( \s' -> all Data.Char.isSpace s' ~? showString "Unparsed input: " (show s') ) . snd-# else /* Plain */+# elif USE_POLYPARSE == 'P' ( Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.PGN.testCases:\tfailed: " . show ||| const ( True ~? "" ) ) . fst+# else+# error "USE_POLYPARSE invalid" # endif $ Poly.runParser (- ContextualNotation.PGN.parser isStrictlySequential validateMoves [] :: Text.Poly.TextParser PGN+ ContextualNotation.PGN.parser isStrictlySequential validateMoves [] :: Text.Poly.TextParser ContextualNotation.PGN.PGN ) #else /* Parsec */ Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.PGN.testCases:\tfailed: " . show ||| const ( True ~? "" ) $ Parsec.parse (- ContextualNotation.PGN.parser isStrictlySequential validateMoves [] :: Parsec.Parser PGN+ ContextualNotation.PGN.parser isStrictlySequential validateMoves [] :: Parsec.Parser ContextualNotation.PGN.PGN ) "PGN-parser" #endif s
src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -24,7 +24,10 @@ module BishBosh.Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree( -- * Constants- testCases+ testCases,+-- * Functions+-- mkGame,+-- checkMatch ) where import qualified BishBosh.Component.EitherQualifiedMove as Component.EitherQualifiedMove@@ -36,68 +39,78 @@ import qualified BishBosh.ContextualNotation.PositionHashQualifiedMoveTree as ContextualNotation.PositionHashQualifiedMoveTree import qualified BishBosh.ContextualNotation.QualifiedMoveForest as ContextualNotation.QualifiedMoveForest import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Test.HUnit.Component.Move as Test.HUnit.Component.Move import qualified BishBosh.Test.HUnit.Model.Game as Test.HUnit.Model.Game import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Default import qualified Test.HUnit import Test.HUnit((~:), (~?=)) +mkGame :: [String] -> Model.Game.Game+mkGame = either (+ \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree.mkGame:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."+ ) id . Test.HUnit.Model.Game.applyMoves++checkMatch+ :: ContextualNotation.PositionHashQualifiedMoveTree.MatchSwitches+ -> Model.Game.Game -- ^ Standard opening.+ -> [String] -- ^ Move-sequence required to construct test-game.+ -> Component.Move.Move -- ^ Expected move.+ -> Test.HUnit.Test+checkMatch matchSwitches game moveStrings expectedMove = map (+ 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+ ]+ ) ~?= [expectedMove]+ -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [- "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves" ~: checkMatch (True, False, False) sicilianDragon "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p f3d4p g8f6 b1c3" finalMove, -- Exact match for standard-opening.- "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/transposition" ~: checkMatch (False, False, False) sicilianDragon "e2e4 c7c5 d2d4 c5d4p g1f3 d7d6 f3d4p g8f6 b1c3" finalMove, -- White's 2nd & 3rd moves have been transposed & Black's 2nd & 3rd move also have been transposed.- "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/join" ~: checkMatch (False, True {-TryToMatchViaJoiningMove-}, False) sicilianDragon "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p b1c3 g8f6" (- standardOpeningMoves !! 6+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves" ~: checkMatch (True, False, False) game2 (init moveStrings2) finalMove2, -- Exact match for standard-opening.+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/transposition" ~: checkMatch (False, False, False) game1 (words "e2e4 c7c5 d2d4 c5d4p g1f3 d7d6 f3d4p g8f6 b1c3") finalMove1, -- White's 2nd & 3rd moves have been transposed & Black's 2nd & 3rd move also have been transposed.+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/transposition" ~: checkMatch (False, False, False) game2 (words "g1f3 d7d6 e2e4 c7c5 d2d4 c5d4p f3d4p g8f6 b1c3 a7a6 c1g5 e7e6 f2f4 d8b6 d1d2 b6b2p a1b1 b2a3 f4f5 b8c6 f5e6p f7e6p d4c6n b7c6n e4e5 d6e5p g5f6n g7f6b c3e4 f8e7 f1e2 h7h5 b1b3 a3a4") finalMove2, -- White & also Black's 1st & 2nd moves have been transposed.+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/join" ~: checkMatch (False, True {-TryToMatchViaJoiningMove-}, False) game1 (words "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p b1c3 g8f6") (+ moves1 !! 6 ), -- White still has to make the 2nd last move.- "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/colourFlip" ~: checkMatch (False, False, True {-TryToMatchColourFlippedPosition-}) sicilianDragon "c2c3 e7e5 c3c4 g8f6 d2d3 d7d5 c4d5p f6d5p g1f3 b8c6" (- Property.Reflectable.reflectOnX finalMove+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/join" ~: checkMatch (False, True {-TryToMatchViaJoiningMove-}, False) game2 (words "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p f3d4p g8f6 b1c3 a7a6 c1g5 e7e6 f2f4 d8b6 d1d2 b6b2p a1b1 b2a3 f4f5 b8c6 f5e6p f7e6p d4c6n b7c6n e4e5 d6e5p g5f6n g7f6b c3e4 f8e7 f1e2 a3a4 b1b3") (+ moves2 !! 31+ ), -- White still has to make the 2nd last move.+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/colourFlip" ~: checkMatch (False, False, True {-TryToMatchColourFlippedPosition-}) game1 (words "c2c3 e7e5 c3c4 g8f6 d2d3 d7d5 c4d5p f6d5p g1f3 b8c6") (+ Property.Reflectable.reflectOnX finalMove1 ), -- White's first two moves are achievable in only one.- "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/colourFlip/transposition" ~: checkMatch (False, False, True {-TryToMatchColourFlippedPosition-}) sicilianDragon "c2c3 g8f6 c3c4 e7e5 d2d3 d7d5 c4d5p f6d5p g1f3 b8c6" (- Property.Reflectable.reflectOnX finalMove+ "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/colourFlip/transposition" ~: checkMatch (False, False, True {-TryToMatchColourFlippedPosition-}) game1 (words "c2c3 g8f6 c3c4 e7e5 d2d3 d7d5 c4d5p f6d5p g1f3 b8c6") (+ Property.Reflectable.reflectOnX finalMove1 ), -- White's first two moves are achievable in only one & Black's first two moves have been transposed. "ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves/colourFlip/join" ~: checkMatch (False, True, True) (- mkGame $ showString sicilianDragonString " f2f3" -- Append a move after the match.- ) "c2c3 g8f6 c3c4 e7e5 d2d3 d7d5 c4d5p f6d5p g2g3 b8c6" . Component.EitherQualifiedMove.getMove . fst . head $ Notation.MoveNotation.readsQualifiedMove Data.Default.def "g1f3"+ mkGame $ moveStrings1 ++ ["f2f3"] -- Append a move after the match.+ ) (words "c2c3 g8f6 c3c4 e7e5 d2d3 d7d5 c4d5p f6d5p g2g3 b8c6") . Component.EitherQualifiedMove.getMove . fst . head $ Notation.MoveNotation.readsQualifiedMove Data.Default.def "g1f3" ] where- mkGame :: String -> Test.HUnit.Model.Game.Game- mkGame = either (- \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.ContextualNotation.QualifiedMoveForest.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."- ) id . Test.HUnit.Model.Game.applyMoves . words-- sicilianDragonString = "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p f3d4p g8f6 b1c3 g7g6"+ moveStrings1, moveStrings2 :: [String]+ moveStrings1 = words "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p f3d4p g8f6 b1c3 g7g6"+ moveStrings2 = words "e2e4 c7c5 g1f3 d7d6 d2d4 c5d4p f3d4p g8f6 b1c3 a7a6 c1g5 e7e6 f2f4 d8b6 d1d2 b6b2p a1b1 b2a3 f4f5 b8c6 f5e6p f7e6p d4c6n b7c6n e4e5 d6e5p g5f6n g7f6b c3e4 f8e7 f1e2 h7h5 b1b3 a3a4 c2c4" -- ECO B97x. - sicilianDragon :: Test.HUnit.Model.Game.Game- sicilianDragon = mkGame sicilianDragonString+ game1, game2 :: Model.Game.Game+ game1 = mkGame moveStrings1+ game2 = mkGame moveStrings2 - standardOpeningMoves = map (Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove) $ Model.Game.listTurnsChronologically sicilianDragon- finalMove = last standardOpeningMoves+ moves1, moves2 :: [Component.Move.Move]+ [moves1, moves2] = map (+ map (Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove) . Model.Game.listTurnsChronologically+ ) [game1, game2] - checkMatch- :: Input.StandardOpeningOptions.MatchSwitches- -> Test.HUnit.Model.Game.Game- -> String- -> Test.HUnit.Component.Move.Move- -> Test.HUnit.Test- checkMatch tryToMatchSwitches game s expectedMove = map (- Component.QualifiedMove.getMove . fst {-qualifiedMove-}- ) (- ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches (- mkGame s- ) . ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest False {-incrementalEvaluation-} (- Data.Default.def :: Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash- ) $ ContextualNotation.QualifiedMoveForest.fromPGNDatabase [- ContextualNotation.PGN.mkPGN' [] [- (ContextualNotation.PGN.dateTag, "2018.01.01")- ] game- ]- ) ~?= [expectedMove]+ finalMove1, finalMove2 :: Component.Move.Move+ finalMove1 = last moves1+ finalMove2 = last moves2
src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs view
@@ -38,7 +38,6 @@ import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Empty as Property.Empty-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@@ -47,10 +46,12 @@ #ifdef USE_POLYPARSE import Test.HUnit((~?=))-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-# else /* Plain */+# elif USE_POLYPARSE == 'P' import qualified Text.ParserCombinators.Poly.Plain as Poly+# else+# error "USE_POLYPARSE invalid" # endif #else /* Parsec */ import Control.Arrow((|||))@@ -66,17 +67,19 @@ in #ifdef USE_POLYPARSE fst (Poly.runParser parser san) ~?=-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' standardAlgebraic-# else /* Plain */+# elif USE_POLYPARSE == 'P' Right standardAlgebraic+# else+# error "USE_POLYPARSE invalid" # endif #else /* Parsec */ (\parseError -> False ~? show parseError) ||| (~?= standardAlgebraic) $ Text.ParserCombinators.Parsec.parse parser "SAN-parser" san #endif ) $ map ( \s -> let- game :: Test.HUnit.Model.Game.Game+ game :: Model.Game.Game game = Data.Default.def in case Notation.MoveNotation.readsQualifiedMove Data.Default.def s of [(eitherQualifiedMove, "")] -> let
src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs view
@@ -40,7 +40,6 @@ 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.Test.HUnit.State.Board as Test.HUnit.State.Board import qualified BishBosh.Text.ShowList as Text.ShowList import qualified Control.Exception import qualified Data.Default@@ -53,7 +52,7 @@ "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after moving King." ~: case Notation.MoveNotation.readsQualifiedMove Data.Default.def "e1e3" {-move King (illegally)-} of [(eitherQualifiedMove, "")] -> Evaluation.Fitness.measureValueOfCastlingPotential ( Model.Game.applyEitherQualifiedMove eitherQualifiedMove (- Data.Default.def :: Test.HUnit.Model.Game.Game+ Data.Default.def :: Model.Game.Game ) ) ~?= negate 1 _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed to parse move.",@@ -65,13 +64,13 @@ ) sourceCoordinates -- Construct two White moves. ) Data.Default.def {-moveType-} ) (- Data.Default.def :: Test.HUnit.State.Board.Board+ Data.Default.def :: State.Board.Board ) $ Cartesian.Coordinates.rooksStartingCoordinates Attribute.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 ( Model.Game.applyEitherQualifiedMove eitherQualifiedMove (- Data.Default.def :: Test.HUnit.Model.Game.Game+ Data.Default.def :: Model.Game.Game ) ) ~?= negate ( fromRational $ recip 2 -- Moving Queen's Rook still permits castling on the King's side.@@ -80,7 +79,7 @@ "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after taking Black Queen's Rook." ~: case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a2a8" {-take Queen's Rook (illegally)-} of [(eitherQualifiedMove, "")] -> Evaluation.Fitness.measureValueOfCastlingPotential ( Model.Game.applyEitherQualifiedMove eitherQualifiedMove (- Data.Default.def :: Test.HUnit.Model.Game.Game+ Data.Default.def :: Model.Game.Game ) ) ~?= fromRational ( recip 2 -- Taking Queen's Rook still permits castling on the King's side.@@ -98,27 +97,27 @@ ], "'BishBosh.Evaluation.Fitness.measureValueOfDoubledPawns' failed." ~: Evaluation.Fitness.measureValueOfDoubledPawns ( Model.Game.fromBoard (- read "4k3/p6p/8/3PP3/3PP3/3PP3/3PP3/4K3" :: Test.HUnit.State.Board.Board+ read "4k3/p6p/8/3PP3/3PP3/3PP3/3PP3/4K3" :: State.Board.Board ) ) ~?= 1, -- White is the next player, so Black is assumed to have just moved to an optimal position. "'BishBosh.Evaluation.Fitness.measureValueOfIsolatedPawns' failed for four columns of two rows of Pawns." ~: Evaluation.Fitness.measureValueOfIsolatedPawns ( Model.Game.fromBoard (- read "4k3/pppppppp/8/8/P1P1P1P1/8/P1P1P1P1/4K3" :: Test.HUnit.State.Board.Board+ read "4k3/pppppppp/8/8/P1P1P1P1/8/P1P1P1P1/4K3" :: State.Board.Board ) ) ~?= 1, -- White is the next player, so Black is assumed to have just moved to an optimal position. "'BishBosh.Evaluation.Fitness.measureValueOfIsolatedPawns' failed for two columns of two four of Pawns." ~: Evaluation.Fitness.measureValueOfIsolatedPawns ( Model.Game.fromBoard (- read "4k3/pppppppp/8/2P2P2/2P2P2/2P2P2/2P2P2/4K3" :: Test.HUnit.State.Board.Board+ read "4k3/pppppppp/8/2P2P2/2P2P2/2P2P2/2P2P2/4K3" :: State.Board.Board ) ) ~?= 1, -- White is the next player, so Black is assumed to have just moved to an optimal position. "'BishBosh.Evaluation.Fitness.measureValueOfPassedPawns' failed." ~: Evaluation.Fitness.measureValueOfPassedPawns ( Model.Game.fromBoard (- read "4k3/8/8/8/8/8/pppppppp/4K3" :: Test.HUnit.State.Board.Board+ read "4k3/8/8/8/8/8/pppppppp/4K3" :: State.Board.Board ) ) ~?= 1, -- White is the next player, so Black is assumed to have just moved to an optimal position. "'BishBosh.Evaluation.Fitness.measureValueOfPassedPawns' failed." ~: Evaluation.Fitness.measureValueOfPassedPawns ( Model.Game.fromBoard (- read "8/PPPPPPPP/8/8/8/8/8/k3K3" :: Test.HUnit.State.Board.Board+ read "8/PPPPPPPP/8/8/8/8/8/k3K3" :: State.Board.Board ) ) ~?= negate 1, -- White is the next player, so Black is assumed to have just moved to the worst possible position. "'BishBosh.Evaluation.Fitness.measureValueOfDefence' failed for default board." ~: Evaluation.Fitness.measureValueOfDefence (@@ -129,7 +128,7 @@ not . uncurry (||) . (Component.Piece.isBlack &&& Component.Piece.isKing) ) . State.Board.getCoordinatesByRankByLogicalColour ) (- Data.Default.def :: Test.HUnit.State.Board.Board+ Data.Default.def :: State.Board.Board ) ) ~?= fromRational ( 19 / fromIntegral {-NPieces-} Evaluation.Fitness.maximumDefended@@ -137,7 +136,7 @@ "'BishBosh.Evaluation.Fitness.measureValueOfDefence' failed after Pawn-advance." ~: case Notation.MoveNotation.readsQualifiedMove Data.Default.def "g2g3" {-advance King's Knight's Pawn-} of [(eitherQualifiedMove, "")] -> Evaluation.Fitness.measureValueOfDefence ( Model.Game.applyEitherQualifiedMove eitherQualifiedMove (- Data.Default.def :: Test.HUnit.Model.Game.Game+ Data.Default.def :: Model.Game.Game ) ) ~?= fromRational ( recip $ fromIntegral {-NPieces-} Evaluation.Fitness.maximumDefended@@ -155,7 +154,7 @@ ], "'BishBosh.Evaluation.Fitness.measureValueOfDefence' failed." ~: Evaluation.Fitness.measureValueOfDefence ( Model.Game.fromBoard (- read "k7/8/2p5/8/4RQQB/4QQQN/4NQQK/4BQQR" :: Test.HUnit.State.Board.Board+ read "k7/8/2p5/8/4RQQB/4QQQN/4NQQK/4BQQR" :: State.Board.Board ) ) ~?= negate 1 -- White is the next player. ]
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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Data.List@@ -82,7 +81,7 @@ (== Just (head optionsList)) ( (HXT.unpickleDoc HXT.xpickle . HXT.pickleDoc HXT.xpickle) =<< Data.Maybe.listToMaybe ( optionsList :: [- Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y+ Input.Options.Options Type.Mass.PieceSquareValue ] ) ) @? "Input.Options.pickler failed."
src-test/BishBosh/Test/HUnit/Model/Game.hs view
@@ -23,9 +23,6 @@ -} module BishBosh.Test.HUnit.Model.Game(--- * Types--- ** Type-synonyms- Game, -- * Constants testCases, -- * Functions@@ -48,32 +45,27 @@ import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason-import qualified BishBosh.Test.HUnit.Cartesian.Coordinates as Test.HUnit.Cartesian.Coordinates import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Default import qualified Data.Maybe import qualified Test.HUnit import Test.HUnit((~?), (~:), (~?=)) --- | Defines a concrete type for testing.-type Game = Model.Game.Game Type.Length.X Type.Length.Y- -- | Apply moves specified in Smith-notation, to the default opening board.-applyMoves :: [String] -> Either (String, String) Game+applyMoves :: [String] -> Either (String, String) Model.Game.Game applyMoves = Model.Game.applyEitherQualifiedMoves ( \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 :: Game+ Data.Default.def :: Model.Game.Game ) -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [- "'BishBosh.Model.Game.showFEN' failed" ~: Property.ForsythEdwards.showFEN (Data.Default.def :: Game) ~?= "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1",+ "'BishBosh.Model.Game.showFEN' failed" ~: Property.ForsythEdwards.showFEN (Data.Default.def :: Model.Game.Game) ~?= "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", "'BishBosh.Model.Game.showFEN' failed" ~: either ( \(moveString, s) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t" . showString moveString . showString "; " $ showString s "." ) Property.ForsythEdwards.showFEN (@@ -91,7 +83,7 @@ ) ~?= "rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq - 1 2", all ( (- $ (Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "r3k2r/8/8/8/8/8/8/R3K2R" :: Game)+ $ (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@@ -102,7 +94,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" :: Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "8/3K4/4q3/3bb3/8/8/8/4k3" :: Model.Game.Game ) ~?= [ Component.QualifiedMove.mkQualifiedMove ( Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 6)) `Component.Move.mkMove` Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 7))@@ -114,14 +106,14 @@ 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" :: Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "4k3/8/8/8/1b6/3p4/3R4/4K3" :: Model.Game.Game ) ) ~? "'BishBosh.Model.Game.isValidQualifiedMove' failed", let- pawnsCoordinates :: Test.HUnit.Cartesian.Coordinates.Coordinates+ pawnsCoordinates :: Cartesian.Coordinates.Coordinates pawnsCoordinates = Cartesian.Coordinates.translateY pred maxBound - game :: Game+ game :: Model.Game.Game game = Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "4k3/7P/8/8/8/8/8/4K3" in Model.Game.getBoard ( fst {-game-} . head . Model.Game.rollBack $ Model.Game.applyQualifiedMove (@@ -131,7 +123,7 @@ ) game ) == Model.Game.getBoard game ~? "'BishBosh.Model.Game.rollback' failed to undo a Pawn-promotion", let- game :: Game+ game :: Model.Game.Game game = Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "4k3/8/8/8/8/8/8/R3K2R" in all ( (@@ -172,12 +164,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" :: Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN "rnbqk2r/pppppp2/8/8/8/7p/6np/6bK" :: Model.Game.Game ) ) ~? "'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 :: Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Model.Game.Game ) ) [ "2k5/8/1KB5/3B4/8/8/8/8",@@ -186,7 +178,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 :: Game+ Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Model.Game.Game ) ) [ "k7/8/K7/8/8/8/8/1Q6",@@ -267,7 +259,7 @@ 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" :: Game+ Property.ForsythEdwards.readFEN "r2qkbnr/ppp1pppp/2np4/5b2/3P4/NQP5/PP1BPPPP/R3KBNR w KQkq - 5 6" :: Model.Game.Game ) ~? "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@@ -288,7 +280,7 @@ \epd -> ( epd, case Property.ExtendedPositionDescription.readsEPD epd of- [(game, "")] -> Property.ExtendedPositionDescription.showEPD (game :: Game)+ [(game, "")] -> Property.ExtendedPositionDescription.showEPD (game :: Model.Game.Game) [(_, remainder)] -> Control.Exception.throw . Data.Exception.mkRedundantData . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tparsed EPD=" . shows epd . showString ", but leaving " $ shows remainder " unparsed." _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed to parse EPD=" $ shows epd "." ) -- Pair.@@ -297,7 +289,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" :: Game)+ `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) ) terminalMoves ~? "BishBosh.Test.HUnit.Model.Game.testCases:\tterminal move unavailable." ]
src-test/BishBosh/Test/HUnit/Model/GameTree.hs view
@@ -38,7 +38,6 @@ import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Default import qualified Data.Maybe import qualified Data.Tree@@ -57,22 +56,17 @@ ) 0 [1 .. searchDepth] ) [1 .. 4], "'BishBosh.Model.GameTree.sortGameTree/MVVLVA' failed" ~: map (- \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn Type.Length.X Type.Length.Y)+ \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"], "'BishBosh.Model.GameTree.sortGameTree/SEE' failed" ~: map (- \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn Type.Length.X Type.Length.Y)+ \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"] ] where- sortAvailableMoves :: (- Integral x,- Integral y,- Show x,- Show y- ) => Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> String -> [Component.Turn.Turn x y]+ 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 (
src-test/BishBosh/Test/HUnit/Search/Search.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP#-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -42,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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Control.Monad.Reader@@ -52,14 +52,10 @@ import Test.HUnit((~?)) -- | Constant.-evaluationOptions :: (- Fractional pieceSquareValue,- Integral x,- Integral y- ) => Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y+evaluationOptions :: Fractional pieceSquareValue => Input.EvaluationOptions.EvaluationOptions pieceSquareValue evaluationOptions = Input.EvaluationOptions.mkEvaluationOptions Data.Default.def {-rankValues-} Data.Default.def {- Input.CriteriaWeights.getWeightOfMobility = 24 / 1000,- Input.CriteriaWeights.getWeightOfCastlingPotential = 5 / 1000+ Input.CriteriaWeights.getWeightOfMobility = fromRational $ 24 / 1000,+ Input.CriteriaWeights.getWeightOfCastlingPotential = fromRational $ 5 / 1000 } False {-IncrementalEvaluation-} Nothing {-Maybe PieceSquareTable-} -- | Constant.@@ -73,50 +69,61 @@ -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test $ map (- \(searchDepth, epd, moveOptions) -> case Property.ExtendedPositionDescription.readsEPD epd of+ \(searchDepth, epd, match, moveOptions) -> case Property.ExtendedPositionDescription.readsEPD epd of [(game, "")] -> let 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 Type.Length.X Type.Length.Y- ) searchOptions Data.Default.def {-Zobrist-} Property.Empty.empty {-MoveFrequency-} game :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash+ evaluationOptions :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue+ ) searchOptions Data.Default.def {-Zobrist-} Property.Empty.empty {-MoveFrequency-} game :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree Type.Crypto.PositionHash ) ) searchOptions of quantifiedGame : _ -> Evaluation.QuantifiedGame.getLastTurn quantifiedGame _ -> Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Test.HUnit.Search.Search.testCases:\tfailed." moveStrings = words moveOptions- in elem turnString moveStrings ~? showString "Bratko-Kopec:\t" (- shows turnString . showString " !~ /" $ showString (Data.List.intercalate "|" moveStrings) "/."+ in (+ if match+ then elem+ else notElem+ ) turnString moveStrings ~? (+ shows turnString . showChar ' ' . showString (+ if match+ then "!~"+ else "=~"+ ) . showString " /" $ showString (Data.List.intercalate "|" moveStrings) "/." ) _ -> Control.Exception.throw $ Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Search.Search.testCases:\tfailed to parse " $ shows epd "." ) [--- EPD Accepted move-options Observed move, at various search-depths.--- 4 5- (4, "1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 w - -", "e3a7p"),- (4, "3r1k2/4npp1/1ppr3p/p6P/P2PPPP1/1NR5/5K2/2R5 w - -", "d4d5"), -- f2g2 e4e5.- (4, "2q1rr1k/3bbnnp/p2p1pp1/2pPp3/PpP1P1P1/1P2BNNP/2BQ1PRK/7R b - -", "f6f5"), -- c8b7 d7g4p.- (4, "rnbqkb1r/p3pppp/1p6/2ppP3/3N4/2P5/PPP1QPPP/R1B1KB1R w KQkq -", "e5e6"), -- d4b3 c1g5.- (4, "r1b2rk1/2q1b1pp/p2ppn2/1p6/3QP3/1BN1B3/PPP3PP/R4RK1 w - -", "c3d5 a3a4"), -- e3g5 d4b6.- (4, "2r3k1/pppR1pp1/4p3/4P1P1/5P2/1P4K1/P1P5/8 w - -", "g5g6"), -- g3f2 g3f2.- (4, "1nk1r1r1/pp2n1pp/4p3/q2pPp1N/b1pP1P2/B1P2R2/2P1B1PP/R2Q2K1 w - -", "h5f6"), -- a3d6 a3e7n.- (4, "4b3/p3kp2/6p1/3pP2p/2pP1P2/4K1P1/P3N2P/8 w - -", "f4f5"), -- e2c3 e2c3.- (4, "2kr1bnr/pbpq4/2n1pp2/3p3p/3P1P1B/2N2N1Q/PPP3PP/2KR1B1R w - -", "f4f5"), -- f1b5.- (4, "3rr1k1/pp3pp1/1qn2np1/8/3p4/PP1R1P2/2P1NQPP/R1B3K1 b - -", "c6e5"),- (4, "2r1nrk1/p2q1ppp/bp1p4/n1pPp3/P1P1P3/2PBB1N1/4QPPP/R4RK1 w - -", "f3f4"), -- f1e1.- (4, "r3r1k1/ppqb1ppp/8/4p1NQ/8/2P5/PP3PPP/R3R1K1 b - -", "d7f5"),- (4, "r2q1rk1/4bppp/p2p4/2pP4/3pP3/3Q4/PP1B1PPP/R3R1K1 w - -", "b2b4"),- (4, "rnb2r1k/pp2p2p/2pp2p1/q2P1p2/8/1Pb2NP1/PB2PPBP/R2Q1RK1 w - -", "d1d2 d1e1"),- (4, "2r3k1/1p2q1pp/2b1pr2/p1pp4/6Q1/1P1PP1R1/P1PN2PP/5RK1 w - -", "g4g7p"), -- g4h3.- (4, "r1bqkb1r/4npp1/p1p4p/1p1pP1B1/8/1B6/PPPN1PPP/R2Q1RK1 w kq -", "d2e4"), -- g5h4.- (4, "r2q1rk1/1ppnbppp/p2p1nb1/3Pp3/2P1P1P1/2N2N1P/PPB1QP2/R1B2RK1 b - -", "h7h5"), -- f6e8.- (4, "r1bq1rk1/pp2ppbp/2np2p1/2n5/P3PP2/N1P2N2/1PB3PP/R1B1QRK1 b - -", "c5b3"), -- c8g4.- (4, "3rr3/2pq2pk/p2p1pnp/8/2QBPP2/1P6/P5PP/4RRK1 b - -", "e8e4p"), -- d6d5.- (4, "r4k2/pb2bp1r/1p1qp2p/3pNp2/3P1P2/2N3P1/PPP1Q2P/2KRR3 w - -", "g3g4"), -- c3b5.- (4, "3rn2k/ppb2rpp/2ppqp2/5N2/2P1P3/1P5Q/PB3PPP/3RR1K1 w - -", "f5h6"), -- f5h4.- (4, "2r2rk1/1bqnbpp1/1p1ppn1p/pP6/N1P1P3/P2B1N1P/1B2QPP1/R2R2K1 b - -", "b7e4p"), -- d7e5.- (4, "r1bqk2r/pp2bppp/2p5/3pP3/P2Q1P2/2N1B3/1PP3PP/R4RK1 b kq -", "f7f6"), -- c8f5.- (4, "r2qnrnk/p2b2b1/1p1p2pp/2pPpp2/1PP1P3/PRNBB3/3QNPPP/5RK1 w - -", "f2f4") -- e4f5p.+-- EPD Match Move-options Observed move, at various search-depths.+-- 4 5+#ifdef USE_BRATKO_KOPEC+ (4, "1k1r4/pp1b1R2/3q2pp/4p3/2B5/4Q3/PPP2B2/2K5 w - -", True, "e3a7p"),+ (4, "3r1k2/4npp1/1ppr3p/p6P/P2PPPP1/1NR5/5K2/2R5 w - -", True, "d4d5"), -- f2g2 e4e5.+ (4, "2q1rr1k/3bbnnp/p2p1pp1/2pPp3/PpP1P1P1/1P2BNNP/2BQ1PRK/7R b - -", True, "f6f5"), -- c8b7 d7g4p.+ (4, "rnbqkb1r/p3pppp/1p6/2ppP3/3N4/2P5/PPP1QPPP/R1B1KB1R w KQkq -", True, "e5e6"), -- d4b3 c1g5.+ (4, "r1b2rk1/2q1b1pp/p2ppn2/1p6/3QP3/1BN1B3/PPP3PP/R4RK1 w - -", True, "c3d5 a3a4"), -- e3g5 d4b6.+ (4, "2r3k1/pppR1pp1/4p3/4P1P1/5P2/1P4K1/P1P5/8 w - -", True, "g5g6"), -- g3f2 g3f2.+ (4, "1nk1r1r1/pp2n1pp/4p3/q2pPp1N/b1pP1P2/B1P2R2/2P1B1PP/R2Q2K1 w - -", True, "h5f6"), -- a3d6 a3e7n.+ (4, "4b3/p3kp2/6p1/3pP2p/2pP1P2/4K1P1/P3N2P/8 w - -", True, "f4f5"), -- e2c3 e2c3.+ (4, "2kr1bnr/pbpq4/2n1pp2/3p3p/3P1P1B/2N2N1Q/PPP3PP/2KR1B1R w - -", True, "f4f5"), -- f1b5.+ (4, "3rr1k1/pp3pp1/1qn2np1/8/3p4/PP1R1P2/2P1NQPP/R1B3K1 b - -", True, "c6e5"),+ (4, "2r1nrk1/p2q1ppp/bp1p4/n1pPp3/P1P1P3/2PBB1N1/4QPPP/R4RK1 w - -", True, "f3f4"), -- f1e1.+ (4, "r3r1k1/ppqb1ppp/8/4p1NQ/8/2P5/PP3PPP/R3R1K1 b - -", True, "d7f5"),+ (4, "r2q1rk1/4bppp/p2p4/2pP4/3pP3/3Q4/PP1B1PPP/R3R1K1 w - -", True, "b2b4"),+ (4, "rnb2r1k/pp2p2p/2pp2p1/q2P1p2/8/1Pb2NP1/PB2PPBP/R2Q1RK1 w - -", True, "d1d2 d1e1"),+ (4, "2r3k1/1p2q1pp/2b1pr2/p1pp4/6Q1/1P1PP1R1/P1PN2PP/5RK1 w - -", True, "g4g7p"), -- g4h3.+ (4, "r1bqkb1r/4npp1/p1p4p/1p1pP1B1/8/1B6/PPPN1PPP/R2Q1RK1 w kq -", True, "d2e4"), -- g5h4.+ (4, "r2q1rk1/1ppnbppp/p2p1nb1/3Pp3/2P1P1P1/2N2N1P/PPB1QP2/R1B2RK1 b - -", True, "h7h5"), -- f6e8.+ (4, "r1bq1rk1/pp2ppbp/2np2p1/2n5/P3PP2/N1P2N2/1PB3PP/R1B1QRK1 b - -", True, "c5b3"), -- c8g4.+ (4, "3rr3/2pq2pk/p2p1pnp/8/2QBPP2/1P6/P5PP/4RRK1 b - -", True, "e8e4p"), -- d6d5.+ (4, "r4k2/pb2bp1r/1p1qp2p/3pNp2/3P1P2/2N3P1/PPP1Q2P/2KRR3 w - -", True, "g3g4"), -- c3b5.+ (4, "3rn2k/ppb2rpp/2ppqp2/5N2/2P1P3/1P5Q/PB3PPP/3RR1K1 w - -", True, "f5h6"), -- f5h4.+ (4, "2r2rk1/1bqnbpp1/1p1ppn1p/pP6/N1P1P3/P2B1N1P/1B2QPP1/R2R2K1 b - -", True, "b7e4p"), -- d7e5.+ (4, "r1bqk2r/pp2bppp/2p5/3pP3/P2Q1P2/2N1B3/1PP3PP/R4RK1 b kq -", True, "f7f6"), -- c8f5.+ (4, "r2qnrnk/p2b2b1/1p1p2pp/2pPpp2/1PP1P3/PRNBB3/3QNPPP/5RK1 w - -", True, "f2f4"), -- e4f5p.+#endif+ (4, "8/k6P/7R/8/8/8/8/1R5K w - -", False, "h7h8Q h7h8R") -- Experimental test of Stalemate-avoidance. ]
src-test/BishBosh/Test/HUnit/State/Board.hs view
@@ -23,60 +23,50 @@ -} module BishBosh.Test.HUnit.State.Board(--- * Types--- ** Type-synonyms- Board, -- * Constants testCases ) where 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.Cartesian.Ordinate as Cartesian.Ordinate-import qualified BishBosh.Cartesian.Vector as Cartesian.Vector-import qualified BishBosh.Component.Move as Component.Move-import qualified BishBosh.Component.Piece as Component.Piece-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-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.Test.HUnit.Cartesian.Coordinates as Test.HUnit.Cartesian.Coordinates-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.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Cartesian.Vector as Cartesian.Vector+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+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.Seeker as StateProperty.Seeker import qualified Control.Arrow import qualified Data.Array.IArray import qualified Data.Default import qualified Data.Foldable-import qualified Data.Map+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified Test.HUnit import qualified ToolShed.Data.Foldable import Test.HUnit((~:), (~?=), (~?)) --- | Defines a concrete type for testing.-type Board = State.Board.Board Type.Length.X Type.Length.Y- -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test 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- ) (Property.FixedMembership.members :: [Test.HUnit.Cartesian.Coordinates.Coordinates])+ ) (Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates]) ) ~?= [32, 8, 2, 2, 2, 1, 1, 8, 2, 2, 2, 1, 1], let- kingsColour = Attribute.LogicalColour.Black+ kingsColour = minBound destination = Cartesian.Coordinates.mkRelativeCoordinates ((+ 3) *** (+ 3)) directionToCoordinates = last . (`Cartesian.Coordinates.extrapolate` destination) mkPiece = Component.Piece.mkPiece $ Property.Opposable.getOpposite kingsColour-- maybeShift :: Cartesian.Vector.VectorInt -> Maybe Test.HUnit.Cartesian.Coordinates.Coordinates- 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-} ) (@@ -96,73 +86,92 @@ in map ((,) attacker . directionToCoordinates) $ Component.Piece.getAttackDirections attacker ] ) ~? "'BishBosh.State.Board.isKingChecked' failed.",- "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed, for passed Pawn adjacent to opposing Pawn of equal rank." ~: Data.Array.IArray.elems (+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for adjacent Pawns." ~: Data.Foldable.toList ( Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map ( Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates ) [ (- Attribute.LogicalColour.Black,+ minBound, id ), (- Attribute.LogicalColour.White,+ maxBound, Control.Arrow.first succ ) ] ) ~?= [1, 1],- "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for passed Pawns isolated from opposing Pawn." ~: Data.Array.IArray.elems (+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for isolated Pawns." ~: Data.Foldable.toList ( Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map ( Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates ) [ (- Attribute.LogicalColour.Black,+ minBound, Control.Arrow.second succ ), (- Attribute.LogicalColour.White,+ maxBound, Control.Arrow.first (+ 2) ) ] ) ~?= [1, 1],- "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed Pawn approaching opposing Pawn." ~: Data.Array.IArray.elems (+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for doubled Pawns." ~: Data.Foldable.toList (+ Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map (+ Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates+ ) $ map ((,) minBound) [+ (+ 4) *** (+ 3),+ (+ 4) *** (+ 4)+ ] ++ map ((,) maxBound) [+ (+ 5) *** (+ 4),+ (+ 5) *** (+ 5)+ ]+ ) ~?= [2, 2],+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for asymmetric Pawns." ~: Data.Foldable.toList (+ Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map (+ Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates+ ) $ (minBound, (+ 4) *** (+ 4)) : map ((,) maxBound) [+ (+ 5) *** (+ 4),+ (+ 5) *** (+ 5)+ ]+ ) ~?= [1, 2],+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed diagonally adjacent Pawns." ~: Data.Foldable.toList ( Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map ( Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates ) [ (- Attribute.LogicalColour.White,+ maxBound, id ), (- Attribute.LogicalColour.Black,+ minBound, succ *** succ ) ] ) ~?= [0, 0],- "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed Pawn sandwiched by opposing Pawns." ~: Data.Array.IArray.elems (+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed Pawn sandwiched by opposing Pawns." ~: Data.Foldable.toList ( Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map ( Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates ) [ (- Attribute.LogicalColour.Black,+ minBound, id ), (- Attribute.LogicalColour.White,+ maxBound, succ *** succ ), (- Attribute.LogicalColour.Black,+ minBound, (+ 2) *** (+ 2) ) ] ) ~?= [1, 0],- "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed Pawn between doubled opposing Pawns." ~: Data.Array.IArray.elems (+ "'BishBosh.State.CoordinatesByRankByLogicalColour.countPassedPawns' failed for un-passed Pawn between doubled opposing Pawns." ~: Data.Foldable.toList ( Data.Array.IArray.amap length . State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map ( Component.Piece.mkPawn *** Cartesian.Coordinates.mkRelativeCoordinates ) [ (- Attribute.LogicalColour.Black,+ minBound, id ), (- Attribute.LogicalColour.Black,+ minBound, Control.Arrow.second (+ 2) ), (- Attribute.LogicalColour.White,+ maxBound, succ *** succ ) ]@@ -170,17 +179,17 @@ let whitePawnsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing Attribute.LogicalColour.White (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance Attribute.LogicalColour.White whitePawnsCoordinates+ State.Board.exposesKing maxBound (+ Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates ) $ placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkPawn Attribute.LogicalColour.White,+ Component.Piece.mkPawn maxBound, whitePawnsCoordinates ), (- Component.Piece.mkPawn Attribute.LogicalColour.Black,+ Component.Piece.mkPawn minBound, Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2) ) ]@@ -188,17 +197,17 @@ let whitePawnsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing Attribute.LogicalColour.White (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance Attribute.LogicalColour.White whitePawnsCoordinates+ State.Board.exposesKing maxBound (+ Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates ) $ placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkPawn Attribute.LogicalColour.White,+ Component.Piece.mkPawn maxBound, whitePawnsCoordinates ), (- Component.Piece.mkKing Attribute.LogicalColour.Black,+ Component.Piece.mkKing minBound, Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2) ) ]@@ -206,53 +215,53 @@ let whiteBishopsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ in not (- State.Board.exposesKing Attribute.LogicalColour.White (+ State.Board.exposesKing maxBound ( Component.Move.mkMove whiteBishopsCoordinates $ Cartesian.Coordinates.translate (succ *** succ) whiteBishopsCoordinates -- Move towards Black Queen. ) $ placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkBishop Attribute.LogicalColour.White,+ Component.Piece.mkBishop maxBound, whiteBishopsCoordinates ), (- Component.Piece.mkQueen Attribute.LogicalColour.Black,+ Component.Piece.mkQueen minBound, maxBound ) ] ) ~? "'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 Attribute.LogicalColour.White (- Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance Attribute.LogicalColour.White whitePawnsCoordinates -- Expose attack from Black Queen.+ in State.Board.exposesKing maxBound (+ Component.Move.mkMove whitePawnsCoordinates $ Cartesian.Coordinates.advance maxBound whitePawnsCoordinates -- Expose attack from Black Queen. ) ( placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkPawn Attribute.LogicalColour.White,+ Component.Piece.mkPawn maxBound, whitePawnsCoordinates ), (- Component.Piece.mkQueen Attribute.LogicalColour.Black,+ Component.Piece.mkQueen minBound, maxBound ) ] ) ~? "'BishBosh.State.Board.exposesKing failed after advancing White Pawn.", let whiteKnightsCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ- in State.Board.exposesKing Attribute.LogicalColour.White (+ in State.Board.exposesKing maxBound ( Component.Move.mkMove whiteKnightsCoordinates . Cartesian.Coordinates.mkRelativeCoordinates $ (+ 3) *** (+ 2) -- Expose attack from Black Queen. ) ( placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkKnight Attribute.LogicalColour.White,+ Component.Piece.mkKnight maxBound, whiteKnightsCoordinates ), (- Component.Piece.mkQueen Attribute.LogicalColour.Black,+ Component.Piece.mkQueen minBound, maxBound ) ]@@ -260,20 +269,20 @@ let whiteRooksCoordinates = Cartesian.Coordinates.mkRelativeCoordinates $ (+ 2) *** (+ 2) in not (- State.Board.exposesKing Attribute.LogicalColour.White (- Component.Move.mkMove whiteRooksCoordinates $ Cartesian.Coordinates.advance Attribute.LogicalColour.White whiteRooksCoordinates -- Shift blocking-role to Pawn.+ State.Board.exposesKing maxBound (+ Component.Move.mkMove whiteRooksCoordinates $ Cartesian.Coordinates.advance maxBound whiteRooksCoordinates -- Shift blocking-role to Pawn. ) $ placePieces [ (- Component.Piece.mkKing Attribute.LogicalColour.White,+ Component.Piece.mkKing maxBound, minBound ), (- Component.Piece.mkPawn Attribute.LogicalColour.White,+ Component.Piece.mkPawn maxBound, Cartesian.Coordinates.mkRelativeCoordinates $ succ *** succ ), (- Component.Piece.mkRook Attribute.LogicalColour.White,+ Component.Piece.mkRook maxBound, whiteRooksCoordinates ), (- Component.Piece.mkQueen Attribute.LogicalColour.Black,+ Component.Piece.mkQueen minBound, maxBound ) ]@@ -281,11 +290,13 @@ Data.Foldable.all ( Data.Foldable.all (== 1) ) (- State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour $ State.Board.getCoordinatesByRankByLogicalColour (Data.Default.def :: Board)+ StateProperty.Seeker.countPawnsByFileByLogicalColour $ State.Board.getCoordinatesByRankByLogicalColour (Data.Default.def :: State.Board.Board) ) ~? "'BishBosh.State.Board.countPawnsByFileByLogicalColour': failed for default board", (- (== [(0, 3), (2, 2), (4, 1)]) . Data.Map.assocs . (! Attribute.LogicalColour.White) . State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map (- (,) (Component.Piece.mkPawn Attribute.LogicalColour.White) . Cartesian.Coordinates.mkRelativeCoordinates+ (+ == map (Control.Arrow.first (Cartesian.Abscissa.xMin +)) [(0, 3), (2, 2), (4, 1)]+ ) . Map.toList . (! maxBound) . StateProperty.Seeker.countPawnsByFileByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour . placePieces $ map (+ (,) (Component.Piece.mkPawn maxBound) . Cartesian.Coordinates.mkRelativeCoordinates ) [ Control.Arrow.second succ, Control.Arrow.second (+ 3),@@ -296,17 +307,17 @@ ] ) ~? "'BishBosh.State.Board.countPawnsByFileByLogicalColour': failed", (- Data.Map.unions (- Data.Array.IArray.elems $ State.Board.countDefendersByCoordinatesByLogicalColour (Data.Default.def :: Board)+ Map.unions (+ Data.Foldable.toList $ State.Board.countDefendersByCoordinatesByLogicalColour (Data.Default.def :: State.Board.Board) ) == foldr (- Data.Map.delete . Cartesian.Coordinates.kingsStartingCoordinates+ Map.delete . Cartesian.Coordinates.kingsStartingCoordinates ) (- Data.Map.fromList $ zip [+ Map.fromList $ zip [ Cartesian.Coordinates.mkCoordinates x y | y <- [ Cartesian.Ordinate.yMax,- Cartesian.Ordinate.pawnsFirstRank Attribute.LogicalColour.Black,- Cartesian.Ordinate.pawnsFirstRank Attribute.LogicalColour.White,+ Cartesian.Ordinate.pawnsFirstRank minBound,+ Cartesian.Ordinate.pawnsFirstRank maxBound, Cartesian.Ordinate.yMin ], x <- Cartesian.Abscissa.xRange@@ -319,6 +330,6 @@ ) Property.FixedMembership.members ) ~? "'BoshBosh.State.Board.countDefendersByCoordinatesByLogicalColour': failed" ] where- placePieces :: [(Component.Piece.Piece, Test.HUnit.Cartesian.Coordinates.Coordinates)] -> Board+ placePieces :: [(Component.Piece.Piece, Cartesian.Coordinates.Coordinates)] -> State.Board.Board placePieces = StateProperty.Mutator.placeAllPieces
src-test/BishBosh/Test/HUnit/Time/GameClock.hs view
@@ -74,7 +74,7 @@ relativeError :: Rational relativeError = pred . (/ Time.StopWatch.getElapsedTime stoppedWatch) . Data.Foldable.sum . Data.Array.IArray.amap Time.StopWatch.getElapsedTime $ Time.GameClock.deconstruct stoppedGameClock - abs relativeError < recip 50000 @? showString "Time.GameClock.GameClock:\trelative error between sum of game-clock times & stop-watch time = " (+ abs relativeError < recip 10000 @? showString "Time.GameClock.GameClock:\trelative error between sum of game-clock times & stop-watch time = " ( shows (realToFrac relativeError :: Double) "." ) ] where
src-test/BishBosh/Test/QuickCheck/Attribute/MoveType.hs view
@@ -61,6 +61,12 @@ f = Test.QuickCheck.label "MoveType.prop_isQuiet" . uncurry (==) . ( Attribute.MoveType.isQuiet &&& not . uncurry (||) . (Attribute.MoveType.isCapture &&& Attribute.MoveType.isPromotion) )+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64} f,+ let+ f :: Attribute.MoveType.MoveType -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "MoveType.prop_isSimple" . uncurry (==) . (+ Attribute.MoveType.isSimple &&& uncurry (&&) . (Attribute.MoveType.isQuiet &&& not . Attribute.MoveType.isCastle)+ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64} f ]
src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs view
@@ -24,13 +24,8 @@ -} module BishBosh.Test.QuickCheck.Cartesian.Coordinates(--- * Types--- ** Type-synonyms- Coordinates, -- * Constants- results,--- * Functions- translate+ results ) where import BishBosh.Test.QuickCheck.Attribute.Direction()@@ -42,7 +37,6 @@ 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.Length as Type.Length import qualified Data.Array.IArray import qualified Data.List import qualified Data.List.Extra@@ -51,82 +45,54 @@ import qualified ToolShed.Test.ReversibleIO import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type Coordinates = Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y--instance (Enum x, Enum y) => Test.QuickCheck.Arbitrary (Cartesian.Coordinates.Coordinates x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Coordinates #-}+instance Test.QuickCheck.Arbitrary Cartesian.Coordinates.Coordinates where arbitrary = Test.QuickCheck.elements Property.FixedMembership.members --- | Re-cast the specified coordinates.-translate :: (- Integral x,- Integral y,- Num p,- Num q- )- => Cartesian.Coordinates.Coordinates x y- -> Cartesian.Coordinates.Coordinates p q-translate coordinates = coordinates {- Cartesian.Coordinates.getX = fromIntegral $ Cartesian.Coordinates.getX coordinates,- Cartesian.Coordinates.getY = fromIntegral $ Cartesian.Coordinates.getY coordinates-}- -- Check that one can interpolate between the coordinates.-isValidMove :: (- Enum x,- Enum y,- Eq x,- Eq y- )- => Cartesian.Coordinates.Coordinates x y- -> Cartesian.Coordinates.Coordinates x y- -> Bool-isValidMove source destination = source /= destination && Property.Orientated.isStraight (- Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.VectorInt- )+isValidMove :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates -> Bool+isValidMove source destination = source /= destination && Property.Orientated.isStraight (Cartesian.Vector.measureDistance source destination) -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f = Test.QuickCheck.label "Coordinates.prop_readPrependedWhiteSpace" . ToolShed.Test.ReversibleIO.readPrependedWhiteSpace in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let f :: String -> Test.QuickCheck.Property f garbage = Test.QuickCheck.label "Coordinates.prop_read" $ case (- reads garbage :: [(Coordinates, String)]+ reads garbage :: [(Cartesian.Coordinates.Coordinates, String)] ) of [_] -> True _ -> True -- Unless the read-implementation throws an exception. in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> String -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> String -> Test.QuickCheck.Property f coordinates = Test.QuickCheck.label "Coordinates.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) coordinates in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f = Test.QuickCheck.label "Coordinates.prop_ix" . ToolShed.Test.Ix.index in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f = Test.QuickCheck.label "Coordinates.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f = Test.QuickCheck.label "Coordinates.prop_reflectOnY" . uncurry (==) . (id &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnY) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ 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 :: Coordinates -> Test.QuickCheck.Property+ 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,@@ -134,7 +100,7 @@ ] in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f coordinates = Test.QuickCheck.label "Coordinates.prop_rotate180/identity" . Data.List.Extra.allSame $ map ($ coordinates) [ Property.Rotatable.rotate180, Property.Rotatable.rotate90 . Property.Rotatable.rotate90,@@ -142,25 +108,7 @@ ] in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Coordinates -> Test.QuickCheck.Property- f source destination = isValidMove source destination ==> Test.QuickCheck.label "Coordinates.prop_interpolateInt" $ Cartesian.Coordinates.interpolate source destination == map translate (- Cartesian.Coordinates.interpolate (- translate source :: Cartesian.Coordinates.Coordinates Integer Integer -- Force use of unspecialised instance.- ) (- translate destination- )- )- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,- let- f :: Attribute.Direction.Direction -> Coordinates -> Test.QuickCheck.Property- f direction source = Test.QuickCheck.label "Coordinates.prop_extrapolateInt" $ Cartesian.Coordinates.extrapolate direction source == map translate (- Cartesian.Coordinates.extrapolate direction (- translate source :: Cartesian.Coordinates.Coordinates Integer Integer -- Force use of unspecialised instance.- )- )- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,- let- f :: Attribute.Direction.Direction -> Coordinates -> Test.QuickCheck.Property+ f :: Attribute.Direction.Direction -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f direction source = Test.QuickCheck.label "Coordinates.prop_extrapolate" . ( \extrapolation -> let destination@@ -172,13 +120,13 @@ ) $ Cartesian.Coordinates.extrapolate direction source in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Coordinates -> Coordinates -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property f source destination = isValidMove source destination ==> Test.QuickCheck.label "Coordinates.prop_interpolate" $ source : Cartesian.Coordinates.interpolate source destination == reverse ( destination : Cartesian.Coordinates.interpolate destination source ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: [Coordinates] -> Test.QuickCheck.Property+ f :: [Cartesian.Coordinates.Coordinates] -> Test.QuickCheck.Property f = Test.QuickCheck.label "Coordinates.prop_areSquaresIsochromatic" . uncurry (==) . ( Cartesian.Coordinates.areSquaresIsochromatic &&& uncurry (||) . ( null &&& (== 1) . length . Data.List.nub . map Cartesian.Coordinates.getLogicalColourOfSquare
src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward@@ -28,22 +29,25 @@ results ) where +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.Test.QuickCheck.Cartesian.Coordinates as Test.QuickCheck.Cartesian.Coordinates-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 Test.QuickCheck import Test.QuickCheck((==>)) -instance (Num distance, Ord distance) => Test.QuickCheck.Arbitrary (Cartesian.Vector.Vector distance) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Cartesian.Vector.VectorInt #-}+#ifdef USE_NEWTYPE_WRAPPERS+import BishBosh.Test.QuickCheck.Type.Length()+#endif++instance Test.QuickCheck.Arbitrary Cartesian.Vector.Vector where arbitrary = do- source <- Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen Test.QuickCheck.Cartesian.Coordinates.Coordinates+ source <- Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen Cartesian.Coordinates.Coordinates destination <- Test.QuickCheck.suchThat Test.QuickCheck.arbitrary (/= source) return {-to Gen-monad-} $ Cartesian.Vector.measureDistance source destination@@ -52,46 +56,46 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Cartesian.Vector.VectorInt -> Test.QuickCheck.Property+ f :: Cartesian.Vector.Vector -> Test.QuickCheck.Property 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.VectorInt -> 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.VectorInt -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: (Type.Length.Distance, Type.Length.Distance) -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ 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 = (- + fromIntegral (+ + ( (distanceX `mod` Cartesian.Abscissa.xLength) - (Cartesian.Abscissa.xLength `div` 2) )- )+ ) -- Section. deltaY :: Type.Length.Y -> Type.Length.Y deltaY = (- + fromIntegral (+ + ( (distanceY `mod` Cartesian.Ordinate.yLength) - (Cartesian.Ordinate.yLength `div` 2) )- )+ ) -- Section. in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ 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.VectorInt+ Cartesian.Vector.measureDistance source destination :: Cartesian.Vector.Vector ) == destination in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ 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.VectorInt+ Cartesian.Vector.measureDistance destination source :: Cartesian.Vector.Vector ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/Component/Move.hs view
@@ -24,78 +24,62 @@ -} module BishBosh.Test.QuickCheck.Component.Move(--- * Types--- ** Type-synonyms- Move, -- * Constants results ) where import BishBosh.Test.QuickCheck.Cartesian.Coordinates() import Control.Arrow((&&&))-import qualified BishBosh.Cartesian.Vector as Cartesian.Vector import qualified BishBosh.Component.Move as Component.Move 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.Length as Type.Length import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type Move = Component.Move.Move Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Eq x,- Eq y- ) => Test.QuickCheck.Arbitrary (Component.Move.Move x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Move #-}+instance Test.QuickCheck.Arbitrary Component.Move.Move where arbitrary = fmap (uncurry Component.Move.mkMove) . Test.QuickCheck.suchThat Test.QuickCheck.arbitrary $ uncurry (/=) -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Move -> Test.QuickCheck.Property+ f :: Component.Move.Move -> Test.QuickCheck.Property f = Test.QuickCheck.label "Move.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 "Move.prop_read" $ case (reads garbage :: [(Move, String)]) of+ f garbage = Test.QuickCheck.label "Move.prop_read" $ case (reads garbage :: [(Component.Move.Move, 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 :: Move -> String -> Test.QuickCheck.Property+ f :: Component.Move.Move -> String -> Test.QuickCheck.Property f move = Test.QuickCheck.label "Move.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) move in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Move -> Test.QuickCheck.Property+ 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 :: Move -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Move -> Test.QuickCheck.Property+ 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 :: 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 :: Cartesian.Vector.VectorInt- )+ 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) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Move -> Test.QuickCheck.Property+ f :: Component.Move.Move -> Test.QuickCheck.Property f = Test.QuickCheck.label "Move.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Move -> Test.QuickCheck.Property+ f :: Component.Move.Move -> Test.QuickCheck.Property f = Test.QuickCheck.label "Move.prop_reflectOnY" . uncurry (==) . (id &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnY) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/Component/Piece.hs view
@@ -29,16 +29,12 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates-import qualified BishBosh.Component.Piece as Component.Piece-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.Test.QuickCheck.Cartesian.Coordinates as Test.QuickCheck.Cartesian.Coordinates+import qualified BishBosh.Component.Piece as Component.Piece+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 import qualified ToolShed.Test.ReversibleIO-import Test.QuickCheck((==>)) instance Test.QuickCheck.Arbitrary Component.Piece.Piece where arbitrary = Test.QuickCheck.elements Property.FixedMembership.members@@ -69,14 +65,6 @@ f piece = Test.QuickCheck.label "Piece.prop_fen" $ case Property.ForsythEdwards.readsFEN $ Property.ForsythEdwards.showFEN piece of [(piece', "")] -> piece' == piece _ -> False- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f,- let- f :: Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Component.Piece.Piece -> Test.QuickCheck.Property- f coordinates piece = Component.Piece.getRank piece `elem` Attribute.Rank.fixedAttackRange ==> Test.QuickCheck.label "Piece.prop_findAttackDestinationsInt" $ Component.Piece.findAttackDestinations coordinates piece == map Test.QuickCheck.Cartesian.Coordinates.translate (- Component.Piece.findAttackDestinations (- Test.QuickCheck.Cartesian.Coordinates.translate coordinates :: Cartesian.Coordinates.Coordinates Integer Integer -- Force use of unspecialised instance.- ) piece- )- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f ]
src-test/BishBosh/Test/QuickCheck/Component/QualifiedMove.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Component.QualifiedMove(--- * Types--- ** Type-synonyms--- QualifiedMove, -- * Constants results ) where@@ -36,41 +33,31 @@ import Control.Arrow((&&&)) import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type QualifiedMove = Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Eq x,- Eq y- ) => Test.QuickCheck.Arbitrary (Component.QualifiedMove.QualifiedMove x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary QualifiedMove #-}+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. -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: QualifiedMove -> Test.QuickCheck.Property+ f :: Component.QualifiedMove.QualifiedMove -> Test.QuickCheck.Property f = Test.QuickCheck.label "QualifiedMove.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 "QualifiedMove.prop_read" $ case (reads garbage :: [(QualifiedMove, String)]) of+ f garbage = Test.QuickCheck.label "QualifiedMove.prop_read" $ case (reads garbage :: [(Component.QualifiedMove.QualifiedMove, 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 :: QualifiedMove -> String -> Test.QuickCheck.Property+ f :: Component.QualifiedMove.QualifiedMove -> String -> Test.QuickCheck.Property f qualifiedMove = Test.QuickCheck.label "QualifiedMove.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) qualifiedMove in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: QualifiedMove -> Test.QuickCheck.Property+ f :: Component.QualifiedMove.QualifiedMove -> Test.QuickCheck.Property f = Test.QuickCheck.label "QualifiedMove.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/Component/Turn.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Component.Turn(--- * Types--- ** Type-synonyms- Turn, -- * Constants -- rankValues, results@@ -47,7 +44,6 @@ import qualified BishBosh.Input.RankValues as Input.RankValues import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Data.List import qualified Data.Maybe@@ -55,15 +51,7 @@ import qualified ToolShed.Data.List import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type Turn = Component.Turn.Turn Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (Component.Turn.Turn x y) where+instance Test.QuickCheck.Arbitrary Component.Turn.Turn where arbitrary = do moveType <- Test.QuickCheck.arbitrary (move, piece) <- case moveType of@@ -85,25 +73,25 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Turn -> Test.QuickCheck.Property+ f :: Component.Turn.Turn -> Test.QuickCheck.Property f = Test.QuickCheck.label "Turn.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 "Turn.prop_read" $ case (reads garbage :: [(Turn, String)]) of+ f garbage = Test.QuickCheck.label "Turn.prop_read" $ case (reads garbage :: [(Component.Turn.Turn, 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 :: Turn -> String -> Test.QuickCheck.Property+ f :: Component.Turn.Turn -> String -> Test.QuickCheck.Property f turn = Test.QuickCheck.label "Turn.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) turn in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Turn -> Test.QuickCheck.Property+ f :: Component.Turn.Turn -> Test.QuickCheck.Property f = Test.QuickCheck.label "Turn.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f, let- f :: Input.RankValues.RankValues -> [Turn] -> Test.QuickCheck.Property+ 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')@@ -113,7 +101,7 @@ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: [Turn] -> Test.QuickCheck.Property+ 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.@@ -125,7 +113,7 @@ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: [Turn] -> Test.QuickCheck.Property+ f :: [Component.Turn.Turn] -> Test.QuickCheck.Property f = Test.QuickCheck.label "Turn.prop_compareByMVVLVA/LVA" . all ( ( \ranks -> uncurry (++) (
src-test/BishBosh/Test/QuickCheck/Component/Zobrist.hs view
@@ -26,79 +26,23 @@ module BishBosh.Test.QuickCheck.Component.Zobrist( -- * Types -- ** Type-synonyms- Zobrist,--- * Constants,- results+ Zobrist ) where -import Control.Arrow((&&&))-import qualified BishBosh.Component.Zobrist as Component.Zobrist-import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game-import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length-import qualified Data.Array.IArray+import qualified BishBosh.Component.Zobrist as Component.Zobrist+import qualified BishBosh.Type.Crypto as Type.Crypto import qualified Data.Bits-import qualified Data.List import qualified System.Random import qualified Test.QuickCheck -- | Defines a concrete type for testing.-type Zobrist = Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash+type Zobrist = Component.Zobrist.Zobrist Type.Crypto.PositionHash -instance (- Data.Array.IArray.Ix x,- Data.Bits.FiniteBits positionHash,- Enum x,- Enum y,- Ord y,- System.Random.Random positionHash- ) => Test.QuickCheck.Arbitrary (Component.Zobrist.Zobrist x y positionHash) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Zobrist #-}+instance (Data.Bits.FiniteBits positionHash, System.Random.Random positionHash) => Test.QuickCheck.Arbitrary (Component.Zobrist.Zobrist positionHash) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary Zobrist #-} arbitrary = Component.Zobrist.mkZobrist <$> fmap ( fmap ( `mod` 3 -- CAVEAT: this value is limited by the width of 'Crypto.PositionHash'. )- ) Test.QuickCheck.arbitrary <*> fmap System.Random.mkStdGen Test.QuickCheck.arbitrary---- | The constant test-results for this data-type.-results :: IO [Test.QuickCheck.Result]-results = sequence [- let- f :: Zobrist -> Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property- f zobrist game = Test.QuickCheck.label "Zobrist.prop_hash2D(Game)/unique" . areUnique . map (- (`Component.Zobrist.hash2D` zobrist) . (`Model.Game.applyQualifiedMove` game)- ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f,- let- f :: Zobrist -> Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property- f zobrist game = Test.QuickCheck.label "Zobrist.prop_hash2D(Position)/unique" . areUnique . map (- (`Component.Zobrist.hash2D` 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 :: Zobrist -> Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property- f zobrist game = Test.QuickCheck.label "Zobrist.prop_(hash2D(Game) == hash2D(Position))" . all (- uncurry (==) . (- (- `Component.Zobrist.hash2D` zobrist- ) &&& (- `Component.Zobrist.hash2D` 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 :: Zobrist -> Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property- f zobrist game = Test.QuickCheck.label "Zobrist.prop_incrementalEvaluation" . all (- (- \game' -> Component.Zobrist.hash2D game' zobrist == Model.Game.updateIncrementalPositionHash game (- Component.Zobrist.hash2D game zobrist- ) game' zobrist- ) . (`Model.Game.applyQualifiedMove` game)- ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f- ] where- areUnique :: Ord a => [a] -> Bool- areUnique = all ((== 1) . length) . Data.List.group . Data.List.sort+ ) Test.QuickCheck.arbitrary {-MaybeMinimumHammingDistance-} <*> fmap System.Random.mkStdGen Test.QuickCheck.arbitrary
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGN.hs view
@@ -25,9 +25,6 @@ -} module BishBosh.Test.QuickCheck.ContextualNotation.PGN(--- * Types--- ** Type-synonyms- PGN, -- * Constants -- ficsGamesDBGameNoTag, -- ecoCodeTag,@@ -37,23 +34,24 @@ ) where import BishBosh.Test.QuickCheck.ContextualNotation.PGNComment()+import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN import qualified BishBosh.ContextualNotation.PGNComment as ContextualNotation.PGNComment import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Word import qualified Test.QuickCheck #ifndef USE_POLYPARSE import Control.Arrow((|||)) import qualified Text.ParserCombinators.Parsec-#elif USE_POLYPARSE == 1-import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+#elif USE_POLYPARSE == 'L'+import qualified Text.ParserCombinators.Poly.Lazy as Poly+#elif USE_POLYPARSE == 'P' import Control.Arrow((|||))-import qualified Text.ParserCombinators.Poly.Plain as Poly+import qualified Text.ParserCombinators.Poly.Plain as Poly+#else+# error "USE_POLYPARSE invalid" #endif -- | Qualifies a value.@@ -73,18 +71,7 @@ return {-to Gen-monad-} [c, i, j] --- | Defines a concrete type for testing.-type PGN = ContextualNotation.PGN.PGN Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Test.QuickCheck.Arbitrary (ContextualNotation.PGN.PGN x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary PGN #-}+instance Test.QuickCheck.Arbitrary ContextualNotation.PGN.PGN where arbitrary = let arbitraryString :: Test.QuickCheck.Gen String arbitraryString = do@@ -124,13 +111,15 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Model.Game.Game -> Test.QuickCheck.Property f isStrictlySequential validateMoves game = Test.QuickCheck.label "PGN.prop_moveTextParser" . #ifdef USE_POLYPARSE-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' (Model.Game.listTurns game ==) . Model.Game.listTurns-# else /* Plain */+# elif USE_POLYPARSE == 'P' (const False ||| (Model.Game.listTurns game ==) . Model.Game.listTurns)+# else+# error "USE_POLYPARSE invalid" # endif . fst {-discard unparsed text-} . Poly.runParser moveTextParser #else /* Parsec */@@ -141,13 +130,15 @@ moveTextParser = ContextualNotation.PGN.moveTextParser isStrictlySequential validateMoves in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f, let- f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> PGN -> [ContextualNotation.PGNComment.PGNComment] -> Test.QuickCheck.Property+ f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> ContextualNotation.PGN.PGN -> [ContextualNotation.PGNComment.PGNComment] -> Test.QuickCheck.Property f isStrictlySequential validateMoves pgn pgnComments = Test.QuickCheck.label "PGN.prop_pgnParser" . #ifdef USE_POLYPARSE-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' (== pgn)-# else /* Plain */+# elif USE_POLYPARSE == 'P' (const False ||| (== pgn))+# else+# error "USE_POLYPARSE invalid" # endif . fst {-discard unparsed text-} . Poly.runParser parser #else /* Parsec */
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGNComment.hs view
@@ -35,11 +35,13 @@ #ifndef USE_POLYPARSE import Control.Arrow((|||)) import qualified Text.ParserCombinators.Parsec-#elif USE_POLYPARSE == 1+#elif USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+#elif USE_POLYPARSE == 'P' import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly+#else+# error "USE_POLYPARSE invalid" #endif instance Test.QuickCheck.Arbitrary ContextualNotation.PGNComment.PGNComment where@@ -56,10 +58,12 @@ f :: ContextualNotation.PGNComment.PGNComment -> Test.QuickCheck.Property f pgnComment = Test.QuickCheck.label "PGNComment.prop_io" . #ifdef USE_POLYPARSE-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' (== s)-# else /* Plain */+# elif USE_POLYPARSE == 'P' (const False ||| (== s))+# else+# error "USE_POLYPARSE invalid" # endif . fst {-discard unparsed text-} . Poly.runParser ContextualNotation.PGNComment.parser #else /* Parsec */
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -24,27 +24,21 @@ -} module BishBosh.Test.QuickCheck.ContextualNotation.PositionHashQualifiedMoveTree(--- * Types--- ** Type-synonyms--- PositionHashQualifiedMoveTree, -- * Constants results ) where +import BishBosh.Test.QuickCheck.ContextualNotation.QualifiedMoveForest() import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.ContextualNotation.PositionHashQualifiedMoveTree as ContextualNotation.PositionHashQualifiedMoveTree import qualified BishBosh.ContextualNotation.QualifiedMoveForest as ContextualNotation.QualifiedMoveForest import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions-import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Model.GameTree as Model.GameTree import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.Test.QuickCheck.Component.Zobrist as Test.QuickCheck.Component.Zobrist-import qualified BishBosh.Test.QuickCheck.ContextualNotation.QualifiedMoveForest as Test.QuickCheck.ContextualNotation.QualifiedMoveForest import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length-import qualified Data.Array.IArray import qualified Data.Bits import qualified Data.List import qualified Data.Maybe@@ -53,28 +47,19 @@ import qualified Test.QuickCheck import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type PositionHashQualifiedMoveTree = ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash- instance (- Data.Array.IArray.Ix x, Data.Bits.FiniteBits positionHash,- Enum x,- Enum y, Num positionHash,- Ord y,- Show x,- Show y, System.Random.Random positionHash- ) => Test.QuickCheck.Arbitrary (ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary PositionHashQualifiedMoveTree #-}+ ) => Test.QuickCheck.Arbitrary (ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree positionHash) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary (ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Crypto.PositionHash) #-} arbitrary = ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest <$> Test.QuickCheck.arbitrary {-IncrementalEvaluation-} <*> Test.QuickCheck.arbitrary {-Zobrist-} <*> Test.QuickCheck.arbitrary {-QualifiedMoveForest-} -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Input.EvaluationOptions.IncrementalEvaluation -> Input.StandardOpeningOptions.MatchSwitches -> Test.QuickCheck.Component.Zobrist.Zobrist -> Test.QuickCheck.ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> Test.QuickCheck.Property+ f :: Input.EvaluationOptions.IncrementalEvaluation -> ContextualNotation.PositionHashQualifiedMoveTree.MatchSwitches -> Test.QuickCheck.Component.Zobrist.Zobrist -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> Test.QuickCheck.Property f incrementalEvaluation tryToMatchSwitches zobrist qualifiedMoveForest = not (Property.Null.isNull qualifiedMoveForest) ==> Test.QuickCheck.label "PositionHashQualifiedMoveTree.prop_findNextOnymousQualifiedMoves" $ all ( ( \(previousGame, lastTurn) -> Data.Maybe.isJust . Data.List.find (
src-test/BishBosh/Test/QuickCheck/ContextualNotation/QualifiedMoveForest.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.ContextualNotation.QualifiedMoveForest(--- * Types--- ** Type-synonyms- QualifiedMoveForest, -- * Constants results ) where@@ -38,31 +35,19 @@ import qualified BishBosh.Model.GameTree as Model.GameTree import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Foldable import qualified Data.Tree import qualified Test.QuickCheck import Test.QuickCheck((==>)) -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Test.QuickCheck.Arbitrary (ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary QualifiedMoveForest #-}+instance Test.QuickCheck.Arbitrary ContextualNotation.QualifiedMoveForest.QualifiedMoveForest where arbitrary = fmap ContextualNotation.QualifiedMoveForest.fromPGNDatabase Test.QuickCheck.arbitrary --- | Defines a concrete type for testing.-type QualifiedMoveForest = ContextualNotation.QualifiedMoveForest.QualifiedMoveForest Type.Length.X Type.Length.Y- -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: QualifiedMoveForest -> Test.QuickCheck.Property+ f :: ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> Test.QuickCheck.Property f = Test.QuickCheck.label "QualifiedMoveForest.prop_findMinimumPieces" . uncurry (==) . ( ContextualNotation.QualifiedMoveForest.findMinimumPieces &&& Data.Foldable.minimum . fmap ( State.Board.getNPieces . Model.Game.getBoard@@ -70,7 +55,7 @@ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: QualifiedMoveForest -> Test.QuickCheck.Property+ f :: ContextualNotation.QualifiedMoveForest.QualifiedMoveForest -> Test.QuickCheck.Property f qualifiedMoveForest = not (Property.Null.isNull qualifiedMoveForest) ==> Test.QuickCheck.label "QualifiedMoveForest.prop_count" . uncurry (==) $ ( snd {-nPositions-} . ContextualNotation.QualifiedMoveForest.count &&& fromIntegral . length . tail {-remove the apex-} . Data.Tree.flatten . Model.GameTree.deconstruct . ContextualNotation.QualifiedMoveForest.toGameTree ) qualifiedMoveForest
src-test/BishBosh/Test/QuickCheck/ContextualNotation/StandardAlgebraic.hs view
@@ -29,20 +29,22 @@ ) where import BishBosh.Test.QuickCheck.Attribute.Rank()+import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game import qualified Test.QuickCheck #ifdef USE_POLYPARSE import Control.Arrow((***))-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' import qualified Text.ParserCombinators.Poly.Lazy as Poly-# else /* Plain */+# elif USE_POLYPARSE == 'P' import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly+# else+# error "USE_POLYPARSE invalid" # endif #else /* Parsec */ import Control.Arrow((|||))@@ -57,19 +59,21 @@ f rank = Test.QuickCheck.label "StandardAlgebraic.prop_san" $ ContextualNotation.StandardAlgebraic.toRank (ContextualNotation.StandardAlgebraic.fromRank rank) == rank in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Test.QuickCheck.Model.Game.Game -> ContextualNotation.StandardAlgebraic.ExplicitEnPassant -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Test.QuickCheck.Property+ f :: Model.Game.Game -> ContextualNotation.StandardAlgebraic.ExplicitEnPassant -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Test.QuickCheck.Property f game explicitEnPassant validateMoves = Test.QuickCheck.label "StandardAlgebraic.prop_sanParser" $ all ( \(game', turn) -> let qualifiedMove = Component.Turn.getQualifiedMove turn in #ifdef USE_POLYPARSE uncurry (&&) . (-# if USE_POLYPARSE == 1+# if USE_POLYPARSE == 'L' (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove *** null {-unparsed input-}-# else /* Plain */+# elif USE_POLYPARSE == 'P' ( const False ||| (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove ) *** null {-unparsed input-}+# else+# error "USE_POLYPARSE invalid" # endif ) . Poly.runParser ( ContextualNotation.StandardAlgebraic.parser explicitEnPassant validateMoves game'
src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -28,19 +28,16 @@ ) where 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.Arboreal as Property.Arboreal 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.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game import qualified BishBosh.Type.Crypto as Type.Crypto-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass import qualified Data.List.Extra import qualified Data.Ord@@ -51,36 +48,16 @@ -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [-{- let f :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Test.QuickCheck.Component.Zobrist.Zobrist- -> Test.QuickCheck.Model.Game.Game- -> Test.QuickCheck.Property- f evaluationOptions searchOptions zobrist game = Test.QuickCheck.label "PositionHashQuantifiedGameTree.prop_mkPositionHashQuantifiedGameTree" $ prune (- Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree evaluationOptions {- Input.EvaluationOptions.getIncrementalEvaluation = False- } searchOptions zobrist Property.Empty.empty {-MoveFrequency-} game :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash- ) == prune (- Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree evaluationOptions {- Input.EvaluationOptions.getIncrementalEvaluation = True -- CAVEAT: unrealistic given rounding-errors in incremental calculation of pieceSquareValue.- } searchOptions zobrist Property.Empty.empty {-MoveFrequency-} game- ) where- prune = Property.Arboreal.prune 3- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4 } f,--}- let- f- :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions- -> Input.SearchOptions.SearchOptions- -> Test.QuickCheck.Component.Zobrist.Zobrist- -> Test.QuickCheck.Model.Game.Game+ -> Model.Game.Game -> Test.QuickCheck.Property f evaluationOptions searchOptions zobrist game = not (null matches) ==> Test.QuickCheck.label "PositionHashQuantifiedGameTree.prop_hashCollisions" $ all ( Data.List.Extra.allSame . map (- Model.Game.mkPosition . Evaluation.QuantifiedGame.getGame . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame :: Evaluation.PositionHashQuantifiedGameTree.NodeLabel Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> State.Position.Position Type.Length.X Type.Length.Y+ Model.Game.mkPosition . Evaluation.QuantifiedGame.getGame . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame :: Evaluation.PositionHashQuantifiedGameTree.NodeLabel Type.Crypto.PositionHash -> State.Position.Position ) ) matches where matches = filter (@@ -94,13 +71,13 @@ :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions -> Input.SearchOptions.SearchOptions -> Test.QuickCheck.Component.Zobrist.Zobrist- -> Test.QuickCheck.Model.Game.Game+ -> Model.Game.Game -> Test.QuickCheck.Property f evaluationOptions searchOptions zobrist = Test.QuickCheck.label "PositionHashQuantifiedGameTree.prop_fitness" . all ( (<= 1) . abs ) . take 10000 . map (- Evaluation.QuantifiedGame.getFitness . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame :: Evaluation.PositionHashQuantifiedGameTree.NodeLabel Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> Type.Mass.WeightedMean+ Evaluation.QuantifiedGame.getFitness . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame :: Evaluation.PositionHashQuantifiedGameTree.NodeLabel Type.Crypto.PositionHash -> Type.Mass.WeightedMean ) . Data.Tree.flatten . Evaluation.PositionHashQuantifiedGameTree.deconstruct . Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree evaluationOptions searchOptions zobrist Property.Empty.empty {-MoveFrequency-}- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs view
@@ -31,47 +31,40 @@ results ) where -import BishBosh.Data.Bool()-import BishBosh.Test.QuickCheck.Attribute.Rank() import BishBosh.Test.QuickCheck.Input.CriteriaWeights() import BishBosh.Test.QuickCheck.Input.PieceSquareTable() import BishBosh.Test.QuickCheck.Input.RankValues()+import BishBosh.Test.QuickCheck.State.Board() import Control.Arrow((&&&))-import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank-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.Property.Reflectable as Property.Reflectable-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.Test.QuickCheck.State.Board as Test.QuickCheck.State.Board-import qualified BishBosh.Type.Length as Type.Length-import qualified BishBosh.Type.Mass as Type.Mass+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+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified Test.QuickCheck import Test.QuickCheck((==>)) -- | Defines a concrete type for testing.-type EvaluationOptions = Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y+type EvaluationOptions = Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary EvaluationOptions #-}+ ) => Test.QuickCheck.Arbitrary (Input.EvaluationOptions.EvaluationOptions pieceSquareValue) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary EvaluationOptions #-} arbitrary = do- criteriaWeights <- Test.QuickCheck.arbitrary+ rankValues <- Test.QuickCheck.arbitrary+ criteriaWeights <- Test.QuickCheck.suchThat Test.QuickCheck.arbitrary $ \c -> Input.RankValues.calculateMaximumTotalValue rankValues /= 0 || Input.CriteriaWeights.getWeightOfMaterial c == 0 - Input.EvaluationOptions.mkEvaluationOptions <$> Test.QuickCheck.arbitrary {-RankValues-} <*> return {-to Gen-monad-} criteriaWeights <*> Test.QuickCheck.arbitrary {-incrementalEvaluation-} <*> if Input.CriteriaWeights.getWeightOfPieceSquareValue criteriaWeights == minBound+ Input.EvaluationOptions.mkEvaluationOptions rankValues criteriaWeights <$> Test.QuickCheck.arbitrary {-incrementalEvaluation-} <*> if Input.CriteriaWeights.getWeightOfPieceSquareValue criteriaWeights == minBound then return {-to Gen-monad-} Nothing else do (pieceSquareTable, pieceSquareTable', ranks) <- Test.QuickCheck.arbitrary@@ -79,7 +72,7 @@ return {-to Gen-monad-} $ Just ( pieceSquareTable, pieceSquareTable' {- Input.PieceSquareTable.getPieceSquareValueByCoordinatesByRank = foldr Data.Map.delete (Input.PieceSquareTable.getPieceSquareValueByCoordinatesByRank pieceSquareTable') $ Data.List.nub ranks -- Delete arbitrary ranks from the end-game table.+ Input.PieceSquareTable.getPieceSquareValueByCoordinatesByRank = foldr Map.delete (Input.PieceSquareTable.getPieceSquareValueByCoordinatesByRank pieceSquareTable') $ Data.List.nub ranks -- Delete arbitrary ranks from the end-game table. } ) -- Pair. @@ -87,7 +80,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: EvaluationOptions -> Test.QuickCheck.State.Board.Board -> Test.QuickCheck.Property+ 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 ) board where@@ -95,13 +88,9 @@ sumPieceSquareValueByLogicalColour = State.Board.sumPieceSquareValueByLogicalColour $ Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Input.EvaluationOptions.EvaluationOptions Rational {-precision is required-} Type.Length.X Type.Length.Y -> Test.QuickCheck.State.Board.Board -> Test.QuickCheck.Property+ 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 (==) $ (- State.CoordinatesByRankByLogicalColour.sumPieceSquareValueByLogicalColour (- \logicalColour rank coordinatesList -> Component.PieceSquareByCoordinatesByRank.findPieceSquareValues nPieces logicalColour rank coordinatesList pieceSquareByCoordinatesByRank- ) . State.Board.getCoordinatesByRankByLogicalColour &&& State.MaybePieceByCoordinates.sumPieceSquareValueByLogicalColour (- \logicalColour rank coordinates -> Component.PieceSquareByCoordinatesByRank.findPieceSquareValue nPieces logicalColour rank coordinates pieceSquareByCoordinatesByRank- ) . State.Board.getMaybePieceByCoordinates+ Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces . State.Board.getCoordinatesByRankByLogicalColour &&& Component.Accountant.sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank nPieces . State.Board.getMaybePieceByCoordinates ) board where maybePieceSquareByCoordinatesByRank = Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions pieceSquareByCoordinatesByRank = Data.Maybe.fromJust maybePieceSquareByCoordinatesByRank
src-test/BishBosh/Test/QuickCheck/Input/NativeUIOptions.hs view
@@ -33,7 +33,7 @@ instance Test.QuickCheck.Arbitrary Input.NativeUIOptions.NativeUIOptions where arbitrary = Input.NativeUIOptions.mkNativeUIOptions <$> fmap ( mkOddNaturalNumber *** mkOddNaturalNumber- ) Test.QuickCheck.arbitrary {-BoardMagnification-} <*> return {-to Gen-monad-} Data.Default.def {-ColourScheme-} where+ ) Test.QuickCheck.arbitrary {-BoardMagnification-} <*> return {-to Gen-monad-} Data.Default.def {-ColourScheme-} <*> Test.QuickCheck.arbitrary {-DepictFigurine-} where mkOddNaturalNumber :: Num n => Integer -> n mkOddNaturalNumber = fromInteger . succ . (* 2) . (`mod` 3)
src-test/BishBosh/Test/QuickCheck/Input/Options.hs view
@@ -26,7 +26,7 @@ module BishBosh.Test.QuickCheck.Input.Options( -- * Types -- ** Type-synonyms- Options,+-- Options, -- * Constants results ) where@@ -34,30 +34,33 @@ import BishBosh.Test.QuickCheck.Input.EvaluationOptions() import BishBosh.Test.QuickCheck.Input.IOOptions() import BishBosh.Test.QuickCheck.Input.SearchOptions()-import qualified BishBosh.Input.Options as Input.Options-import qualified BishBosh.Type.Length as Type.Length-import qualified BishBosh.Type.Mass as Type.Mass+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 Type.Length.X Type.Length.Y+type Options = Input.Options.Options Type.Mass.PieceSquareValue instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.Options.Options pieceSquareValue x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Options #-}+ ) => Test.QuickCheck.Arbitrary (Input.Options.Options pieceSquareValue) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary Options #-} arbitrary = do (maybeMaximumPlies, maybeRandomSeed, evaluationOptions, searchOptions, ioOptions) <- Test.QuickCheck.arbitrary return {-to Gen-monad-} $ Input.Options.mkOptions ( fmap (fromInteger . succ . abs) maybeMaximumPlies- ) maybeRandomSeed evaluationOptions searchOptions ioOptions+ ) maybeRandomSeed evaluationOptions (+ if null $ Input.IOOptions.getPGNOptionsList ioOptions+ then searchOptions {+ Input.SearchOptions.getSortOnStandardOpeningMoveFrequency = False+ }+ else searchOptions+ ) ioOptions -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs view
@@ -26,36 +26,30 @@ module BishBosh.Test.QuickCheck.Input.PieceSquareTable( -- * Types -- ** Type-synonyms- PieceSquareTable,+-- PieceSquareTable, -- * Constants results ) where import BishBosh.Test.QuickCheck.Attribute.Rank()-import BishBosh.Test.QuickCheck.Component.Piece() import qualified BishBosh.Attribute.Rank as Attribute.Rank 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.Length as Type.Length 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.Length.X Type.Length.Y Type.Mass.PieceSquareValue+type PieceSquareTable = Input.PieceSquareTable.PieceSquareTable Type.Mass.PieceSquareValue instance (- Enum x,- Enum y, Fractional pieceSquareValue, Ord pieceSquareValue,- Ord x,- Ord y, Show pieceSquareValue- ) => Test.QuickCheck.Arbitrary (Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary PieceSquareTable #-}+ ) => Test.QuickCheck.Arbitrary (Input.PieceSquareTable.PieceSquareTable pieceSquareValue) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary PieceSquareTable #-} arbitrary = do reflectOnY <- Test.QuickCheck.arbitrary @@ -68,7 +62,7 @@ if reflectOnY then (`div` 2) else id- ) Cartesian.Coordinates.nSquares+ ) $ fromIntegral Cartesian.Coordinates.nSquares ) ) ) Property.FixedMembership.members
src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs view
@@ -31,12 +31,12 @@ import Control.Arrow((***)) import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified Data.Foldable-import qualified Data.Map+import qualified Data.Map.Strict as Map import qualified Test.QuickCheck instance Test.QuickCheck.Arbitrary Input.SearchOptions.SearchOptions where arbitrary = do- searchDepthByLogicalColour <- Data.Map.map (+ searchDepthByLogicalColour <- Map.map ( (+ Input.SearchOptions.minimumSearchDepth) . fromInteger . (`mod` 4) ) <$> Test.QuickCheck.arbitrary @@ -45,13 +45,13 @@ ) <*> ( fmap (fromInteger . (`mod` 4)) <$> Test.QuickCheck.arbitrary -- maybeRetireKillerMovesAfter. ) <*> Test.QuickCheck.arbitrary {-trapRepeatedPositions-} <*> (- if Data.Map.size searchDepthByLogicalColour == 1+ if Data.Foldable.length searchDepthByLogicalColour == 1 then Test.QuickCheck.arbitrary else return {-to Gen-monad-} False -- UsePondering. ) <*> ( fmap ( fromInteger . (`mod` 3) *** (- if Data.Map.null searchDepthByLogicalColour+ if Data.Foldable.null searchDepthByLogicalColour then id else min $ Data.Foldable.maximum searchDepthByLogicalColour ) . fromInteger . succ . (`mod` 3)
src-test/BishBosh/Test/QuickCheck/Input/StandardOpeningOptions.hs view
@@ -29,5 +29,5 @@ import qualified Test.QuickCheck instance Test.QuickCheck.Arbitrary Input.StandardOpeningOptions.StandardOpeningOptions where- arbitrary = Input.StandardOpeningOptions.mkStandardOpeningOptions <$> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary+ arbitrary = Input.StandardOpeningOptions.mkStandardOpeningOptions <$> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary
src-test/BishBosh/Test/QuickCheck/Model/Game.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward@@ -24,43 +25,39 @@ -} module BishBosh.Test.QuickCheck.Model.Game(--- * Types--- ** Type-synonyms- Game, -- * Constants results ) where -import BishBosh.Test.QuickCheck.State.Board() import Control.Arrow((&&&))-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.Ordinate as Cartesian.Ordinate-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.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.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length+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 Data.Array.IArray import qualified Data.Default import qualified Data.Foldable import qualified Data.List-import qualified Data.Map+import qualified Data.Map as Map import qualified Data.Maybe import qualified Data.Ord import qualified System.Random@@ -70,18 +67,7 @@ import qualified ToolShed.Test.ReversibleIO import Test.QuickCheck((==>)) --- | Defines a concrete type for testing.-type Game = Model.Game.Game Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y- ) => Test.QuickCheck.Arbitrary (Model.Game.Game x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Game #-}+instance Test.QuickCheck.Arbitrary Model.Game.Game where arbitrary = let play game (randomGen : randomGens) | Model.Game.isTerminated game = game@@ -99,25 +85,25 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.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 "Game.prop_read" $ case (reads garbage :: [(Game, String)]) of+ f garbage = Test.QuickCheck.label "Game.prop_read" $ case (reads garbage :: [(Model.Game.Game, 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 :: Game -> String -> Test.QuickCheck.Property+ f :: Model.Game.Game -> String -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen/nFields" . (== 6) . length . words $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen/Half move clock" $ uncurry (&&) . ( (>= 0) &&& (<= Rule.DrawReason.maximumConsecutiveRepeatablePlies) ) . fromInteger . read . (@@ -125,7 +111,7 @@ ) . words $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen/Full move counter" $ ( > (0 :: Type.Count.NMoves) ) . fromInteger . read . (@@ -133,7 +119,7 @@ ) . words $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen" . ( \game' -> and [ uncurry (==) $ (($ game) &&& ($ game')) Model.Game.getNextLogicalColour,@@ -144,11 +130,11 @@ ) . Property.ForsythEdwards.readFEN $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4096 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_findOrderedQualifiedMovesAvailableToNextPlayer" . ( == if Model.Game.isTerminated game then []@@ -170,7 +156,7 @@ maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4096 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_inferMoveType" . all ( \qualifiedMove -> let moveType = Component.QualifiedMove.getMoveType qualifiedMove@@ -181,34 +167,34 @@ ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_findQualifiedMovesAvailableToNextPlayer/unique" . uncurry (==) . (id &&& Data.List.nub) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_getNextLogicalColour" . uncurry (==) . (Model.Game.getNextLogicalColour &&& State.TurnsByLogicalColour.inferNextLogicalColour . Model.Game.getTurnsByLogicalColour) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ 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 :: Game -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ 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- ) . Data.Map.lookup nextLogicalColour $ Model.Game.getAvailableQualifiedMovesByLogicalColour game where+ ) . 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 :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(findQualifiedMovesAvailableTo => countPliesAvailableTo)" $ all ( \logicalColour -> Model.Game.countPliesAvailableTo logicalColour game == ( if Model.Game.isTerminated game@@ -218,25 +204,19 @@ ) Property.FixedMembership.members in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_(getNDefendersByCoordinatesByLogicalColour == countDefendersByCoordinatesByLogicalColour)" . uncurry (==) . ( State.Board.getNDefendersByCoordinatesByLogicalColour &&& State.Board.countDefendersByCoordinatesByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 2048 } f, let- f :: Game -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Game.prop_(getNPawnsByFileByLogicalColour => countPawnsByFileByLogicalColour)" . uncurry (==) . (- State.Board.getNPawnsByFileByLogicalColour &&& State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour- ) . Model.Game.getBoard- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_getNPawnsByFileByLogicalColour/non-zero" . Data.Foldable.all ( Data.Foldable.all (> 0) ) . State.Board.getNPawnsByFileByLogicalColour . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ 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@@ -245,51 +225,51 @@ board = Model.Game.getBoard game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_(getPassedPawnCoordinatesByLogicalColour == findPassedPawnCoordinatesByLogicalColour)" . uncurry (==) . ( State.Board.getPassedPawnCoordinatesByLogicalColour &&& State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f, let- f :: Game -> Test.QuickCheck.Property+ 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) ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.(prop_getCastleableRooksByLogicalColour == fromTurnsByLogicalColour)" . uncurry (==) . ( Model.Game.getCastleableRooksByLogicalColour &&& State.CastleableRooksByLogicalColour.fromTurnsByLogicalColour . Model.Game.getTurnsByLogicalColour ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Game -> Test.QuickCheck.Property+ 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 ) . Model.Game.rollBack . Property.Reflectable.reflectOnX in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Game.prop_cantConverge" . not . any ( \(game, turn) -> Model.Game.cantConverge game $ Model.Game.takeTurn turn game ) . Model.Game.rollBack in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = not (Property.Null.isNull game) ==> Test.QuickCheck.label "Game.prop_rollBack/restart" . (== Data.Default.def) . fst {-game-} . last {-original-} $ Model.Game.rollBack game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_rollBack/takeTurn" . (== game) . foldr ( Model.Game.takeTurn . snd {-turn-} ) Data.Default.def $ Model.Game.rollBack game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Game -> Test.QuickCheck.Property+ 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 ( Component.Piece.mkPiece (Property.Opposable.getOpposite destinationLogicalColour) sourceRank@@ -304,7 +284,7 @@ maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Game -> Test.QuickCheck.Property+ 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 ( Property.Opposable.getOpposite $ Component.Piece.getLogicalColour piece@@ -318,12 +298,31 @@ maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Game -> Test.QuickCheck.Property- f game = Test.QuickCheck.label "Game.prop_pawnOrdinates" . all (- uncurry (&&) . (- (/= Cartesian.Ordinate.yMin) &&& (/= Cartesian.Ordinate.yMax)- ) . Cartesian.Coordinates.getY . fst {-coordinates-}- ) . StateProperty.Seeker.findPieces Component.Piece.isPawn . State.Board.getCoordinatesByRankByLogicalColour $ Model.Game.getBoard game- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ f :: Test.QuickCheck.Input.EvaluationOptions.EvaluationOptions -> Model.Game.Game -> Test.QuickCheck.Property+ f evaluationOptions game = Data.Maybe.isJust (+ Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank evaluationOptions+ ) && not (+ Property.Null.isNull game+ ) ==> Test.QuickCheck.label "Game.prop_measurePieceSquareValueIncrementally" .+#ifdef USE_PRECISION+ uncurry (==)+#else+ (+ < recip+# if USE_NARROW_NUMBERS+ 100000+# else+ 10000000000+# endif+ ) . abs . uncurry (-) -- Tolerance for floating-point errors.+#endif+ $ (+ Evaluation.Fitness.measurePieceSquareValue pieceSquareByCoordinatesByRank &&& Evaluation.Fitness.measurePieceSquareValueIncrementally (+ Evaluation.Fitness.measurePieceSquareValue pieceSquareByCoordinatesByRank 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 ]
src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs view
@@ -24,36 +24,29 @@ -} module BishBosh.Test.QuickCheck.Model.GameTree(--- * Types--- ** Type-synonyms- GameTree, -- * Constants results ) where -import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTree as Model.GameTree-import qualified BishBosh.Property.Arboreal as Property.Arboreal-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game-import qualified BishBosh.Type.Length as Type.Length+import BishBosh.Test.QuickCheck.Model.Game()+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Model.GameTree as Model.GameTree+import qualified BishBosh.Property.Arboreal as Property.Arboreal import qualified Data.Default import qualified Data.Maybe import qualified Test.QuickCheck -instance (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => Test.QuickCheck.Arbitrary (Model.GameTree.GameTree x y) where+instance Test.QuickCheck.Arbitrary Model.GameTree.GameTree where arbitrary = do depth <- Test.QuickCheck.elements [1 .. 3] fmap (Property.Arboreal.prune depth . Model.GameTree.fromGame) Test.QuickCheck.arbitrary --- | Define a concrete type for testing.-type GameTree = Model.GameTree.GameTree Type.Length.X Type.Length.Y- -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "GameTree.prop_traceRoute" . ( \turns -> Data.Maybe.maybe False ( (== Just turns) . mapM Model.Game.maybeLastTurn
src-test/BishBosh/Test/QuickCheck/Model/MoveFrequency.hs view
@@ -27,9 +27,9 @@ results ) where -import qualified BishBosh.Model.GameTree as Model.GameTree-import qualified BishBosh.Model.MoveFrequency as Model.MoveFrequency-import qualified BishBosh.Test.QuickCheck.Model.GameTree as Test.QuickCheck.Model.GameTree+import BishBosh.Test.QuickCheck.Model.GameTree()+import qualified BishBosh.Model.GameTree as Model.GameTree+import qualified BishBosh.Model.MoveFrequency as Model.MoveFrequency import qualified Data.Foldable import qualified Test.QuickCheck @@ -37,7 +37,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Test.QuickCheck.Model.GameTree.GameTree -> Test.QuickCheck.Property+ f :: Model.GameTree.GameTree -> Test.QuickCheck.Property f gameTree = Test.QuickCheck.label "MoveFrequency.prop_countMoves" $ Model.MoveFrequency.countEntries ( Model.GameTree.toMoveFrequency gameTree ) == pred {-the apex is counted in 'getNPlies'-} (
+ src-test/BishBosh/Test/QuickCheck/Notation/Figurine.hs view
@@ -0,0 +1,43 @@+{-+ 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.Notation.Figurine(+-- * Constants+ results+) where++import BishBosh.Test.QuickCheck.Component.Piece()+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Notation.Figurine as Notation.Figurine+import qualified Test.QuickCheck++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Component.Piece.Piece -> Test.QuickCheck.Property+ f piece = Test.QuickCheck.label "Figurine.prop_figurine" $ Notation.Figurine.fromFigurine (Notation.Figurine.toFigurine piece) == Just piece+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f+ ]+
src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Notation.ICCFNumeric(--- * Types--- ** Type-synonyms--- ICCFNumeric, -- * Constants results ) where@@ -39,25 +36,15 @@ import qualified BishBosh.Cartesian.Vector as Cartesian.Vector import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Notation.ICCFNumeric as Notation.ICCFNumeric-import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type ICCFNumeric = Notation.ICCFNumeric.ICCFNumeric Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (Notation.ICCFNumeric.ICCFNumeric x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary ICCFNumeric #-}+instance Test.QuickCheck.Arbitrary Notation.ICCFNumeric.ICCFNumeric where arbitrary = do move <- Test.QuickCheck.arbitrary Notation.ICCFNumeric.mkICCFNumeric move `fmap` if abs (- Cartesian.Vector.getXDistance (Component.Move.measureDistance move :: Cartesian.Vector.VectorInt)+ Cartesian.Vector.getXDistance (Component.Move.measureDistance move) ) <= 1 && ( Cartesian.Coordinates.getY . Component.Move.getSource &&& Cartesian.Coordinates.getY . Component.Move.getDestination $ move ) `elem` [@@ -74,19 +61,19 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: ICCFNumeric -> Test.QuickCheck.Property+ f :: Notation.ICCFNumeric.ICCFNumeric -> Test.QuickCheck.Property f = Test.QuickCheck.label "ICCFNumeric.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 "ICCFNumeric.prop_read" $ case (- reads garbage :: [(Notation.ICCFNumeric.ICCFNumeric Int Int, String)]+ reads garbage :: [(Notation.ICCFNumeric.ICCFNumeric, 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 :: ICCFNumeric -> String -> Test.QuickCheck.Property+ f :: Notation.ICCFNumeric.ICCFNumeric -> String -> Test.QuickCheck.Property f coordinate = Test.QuickCheck.label "ICCFNumeric.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage ( `elem` concatMap (show . fst {-digit-}) Notation.ICCFNumeric.toRank ) coordinate
src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs view
@@ -23,12 +23,57 @@ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'. -} -module BishBosh.Test.QuickCheck.Notation.MoveNotation () where+module BishBosh.Test.QuickCheck.Notation.MoveNotation (+-- * Constants+ results+) where +import BishBosh.Test.QuickCheck.Cartesian.Coordinates()+import BishBosh.Test.QuickCheck.Model.Game()+import Control.Arrow((&&&), (|||))+import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates+import qualified BishBosh.Component.EitherQualifiedMove as Component.EitherQualifiedMove+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.Model.Game as Model.Game import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+import qualified BishBosh.Notation.Notation as Notation.Notation import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates+import qualified Data.Maybe import qualified Test.QuickCheck+import Test.QuickCheck((==>)) instance Test.QuickCheck.Arbitrary Notation.MoveNotation.MoveNotation where arbitrary = Test.QuickCheck.elements Property.FixedMembership.members++results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Notation.MoveNotation.MoveNotation -> Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f moveNotation = Test.QuickCheck.label "MoveNotation.prop_(read.show)Coordinates" . uncurry (==) . (+ Notation.Notation.readsCoordinates (Notation.MoveNotation.getNotation moveNotation) . Notation.MoveNotation.showNotation moveNotation &&& return . flip (,) ""+ )+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f,+ let+ f :: Notation.MoveNotation.MoveNotation -> Model.Game.Game -> Test.QuickCheck.Property+ f moveNotation game = not (Property.Null.isNull game) ==> Test.QuickCheck.label "MoveNotation.prop_(read.show)QualifiedMove" $ case Notation.MoveNotation.readsQualifiedMove moveNotation $ Notation.MoveNotation.showNotation moveNotation turn of+ [(eitherQualifiedMove, "")] -> uncurry (&&) $ (+ (== move) . Component.EitherQualifiedMove.getMove &&& (+ Data.Maybe.maybe (not $ Attribute.MoveType.isPromotion moveType) (== rank) ||| (== moveType)+ ) . Component.EitherQualifiedMove.getPromotionRankOrMoveType+ ) eitherQualifiedMove+ _ -> False+ 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++ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f+ ]
src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Notation.PureCoordinate(--- * Types--- ** Type-synonyms--- PureCoordinate, -- * Constants results ) where@@ -39,26 +36,16 @@ import qualified BishBosh.Cartesian.Vector as Cartesian.Vector import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate-import qualified BishBosh.Type.Length as Type.Length import qualified Data.Char import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type PureCoordinate = Notation.PureCoordinate.PureCoordinate Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (Notation.PureCoordinate.PureCoordinate x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary PureCoordinate #-}+instance Test.QuickCheck.Arbitrary Notation.PureCoordinate.PureCoordinate where arbitrary = do move <- Test.QuickCheck.arbitrary Notation.PureCoordinate.mkPureCoordinate move `fmap` if abs (- Cartesian.Vector.getXDistance (Component.Move.measureDistance move :: Cartesian.Vector.VectorInt)+ Cartesian.Vector.getXDistance (Component.Move.measureDistance move) ) <= 1 && ( Cartesian.Coordinates.getY . Component.Move.getSource &&& Cartesian.Coordinates.getY . Component.Move.getDestination $ move ) `elem` [@@ -75,19 +62,19 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: PureCoordinate -> Test.QuickCheck.Property+ f :: Notation.PureCoordinate.PureCoordinate -> Test.QuickCheck.Property f = Test.QuickCheck.label "PureCoordinate.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 "PureCoordinate.prop_read" $ case (- reads garbage :: [(Notation.PureCoordinate.PureCoordinate Int Int, String)]+ reads garbage :: [(Notation.PureCoordinate.PureCoordinate, 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 :: PureCoordinate -> String -> Test.QuickCheck.Property+ f :: Notation.PureCoordinate.PureCoordinate -> String -> Test.QuickCheck.Property f coordinate = Test.QuickCheck.label "PureCoordinate.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage ( ( `elem` concatMap show Attribute.Rank.promotionProspects
src-test/BishBosh/Test/QuickCheck/Notation/Smith.hs view
@@ -24,9 +24,6 @@ -} module BishBosh.Test.QuickCheck.Notation.Smith(--- * Types--- ** Type-synonyms--- Smith, -- * Constants results ) where@@ -34,39 +31,29 @@ import BishBosh.Test.QuickCheck.Component.QualifiedMove() import qualified BishBosh.Component.Piece as Component.Piece import qualified BishBosh.Notation.Smith as Notation.Smith-import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type Smith = Notation.Smith.Smith Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (Notation.Smith.Smith x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Smith #-}+instance Test.QuickCheck.Arbitrary Notation.Smith.Smith where arbitrary = fmap Notation.Smith.fromQualifiedMove Test.QuickCheck.arbitrary -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Smith -> Test.QuickCheck.Property+ f :: Notation.Smith.Smith -> Test.QuickCheck.Property f = Test.QuickCheck.label "Smith.prop_readPrependedWhiteSpace" . ToolShed.Test.ReversibleIO.readPrependedWhiteSpace in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let f :: String -> Test.QuickCheck.Property f garbage = Test.QuickCheck.label "Smith.prop_read" $ case (- reads garbage :: [(Notation.Smith.Smith Int Int, String)]+ reads garbage :: [(Notation.Smith.Smith, 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 :: Smith -> String -> Test.QuickCheck.Property+ f :: Notation.Smith.Smith -> String -> Test.QuickCheck.Property f smith = Test.QuickCheck.label "Smith.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` ("cCE" ++ Component.Piece.showPieces)) smith in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f ]
src-test/BishBosh/Test/QuickCheck/Search/KillerMoves.hs view
@@ -26,8 +26,7 @@ module BishBosh.Test.QuickCheck.Search.KillerMoves( -- * Types -- ** Type-synonyms--- Key,- KillerMoves,+-- KillerMoves, -- * Constants results -- * Functions@@ -42,19 +41,9 @@ import qualified BishBosh.Search.EphemeralData as Search.EphemeralData import qualified BishBosh.Search.KillerMoves as Search.KillerMoves import qualified BishBosh.Type.Count as Type.Count-import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck --- | Defines a concrete type for testing.-type KillerMoveKey = Search.DynamicMoveData.KillerMoveKey Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (Search.DynamicMoveData.KillerMoveKey x y) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary KillerMoveKey #-}+instance Test.QuickCheck.Arbitrary Search.DynamicMoveData.KillerMoveKey where arbitrary = fmap Search.DynamicMoveData.mkKillerMoveKeyFromTurn Test.QuickCheck.arbitrary -- | Map the integer-domain into a smaller non-negative number of plies.@@ -66,19 +55,20 @@ populate = foldr (\(nPlies, killerMoveKey) -> Search.KillerMoves.insert (normalise nPlies) killerMoveKey) Property.Empty.empty {-KillerMoves-} -- | Defines a concrete type for testing.-type KillerMoves = Search.KillerMoves.KillerMoves KillerMoveKey+type KillerMoves = Search.KillerMoves.KillerMoves Search.DynamicMoveData.KillerMoveKey instance ( Ord key, Test.QuickCheck.Arbitrary key ) => Test.QuickCheck.Arbitrary (Search.KillerMoves.KillerMoves key) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary KillerMoves #-} arbitrary = fmap populate Test.QuickCheck.arbitrary -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: [(Int, KillerMoveKey)] -> Test.QuickCheck.Property+ f :: [(Int, Search.DynamicMoveData.KillerMoveKey)] -> Test.QuickCheck.Property f = Test.QuickCheck.label "KillerMoves.prop_insert/getNMoves" . uncurry (==) . (Search.EphemeralData.getSize . populate &&& length) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/Search/Search.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -34,11 +35,16 @@ import qualified BishBosh.Search.Search as Search.Search import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.Test.QuickCheck.Search.SearchState as Test.QuickCheck.Search.SearchState+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Monad.Reader import qualified Data.Default import qualified Test.QuickCheck import Test.QuickCheck((==>)) +#ifdef USE_NEWTYPE_WRAPPERS+import BishBosh.Test.QuickCheck.Type.Count()+#endif+ -- | The constant test-results. results :: IO [Test.QuickCheck.Result] results = sequence [@@ -50,7 +56,7 @@ let f :: Input.SearchOptions.SearchOptions- -> Int -- ^ Search-depth.+ -> Type.Count.NPlies -- ^ Search-depth. -> Test.QuickCheck.Search.SearchState.SearchState -> Test.QuickCheck.Property f searchOptions searchDepth searchState = searchOptions /= Data.Default.def && not (
src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs view
@@ -39,36 +39,27 @@ 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.Length as Type.Length import qualified BishBosh.Type.Mass as Type.Mass-import qualified Data.Array.IArray import qualified Data.Bits import qualified System.Random import qualified Test.QuickCheck -- | A suitable concrete type for testing.-type SearchState = Search.SearchState.SearchState Type.Length.X Type.Length.Y Type.Crypto.PositionHash+type SearchState = Search.SearchState.SearchState Type.Crypto.PositionHash -instance forall x y positionHash. (- Data.Array.IArray.Ix x,- Data.Bits.FiniteBits positionHash,- Integral x,- Integral y,- Num positionHash,- Show positionHash,- Show x,- Show y,- System.Random.Random positionHash,- Test.QuickCheck.Arbitrary x,- Test.QuickCheck.Arbitrary y- ) => Test.QuickCheck.Arbitrary (Search.SearchState.SearchState x y positionHash) where+instance forall positionHash. (+ Data.Bits.FiniteBits positionHash,+ Num positionHash,+ Show positionHash,+ System.Random.Random positionHash+ ) => 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 x y+ 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-} )
src-test/BishBosh/Test/QuickCheck/State/Board.hs view
@@ -24,57 +24,43 @@ -} module BishBosh.Test.QuickCheck.State.Board(--- * Types--- ** Type-synonyms- Board, -- * Constants results ) where import BishBosh.Test.QuickCheck.Attribute.LogicalColour()-import BishBosh.Test.QuickCheck.Component.Piece()+import BishBosh.Test.QuickCheck.Cartesian.Coordinates() 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.Component.Move as Component.Move-import qualified BishBosh.Component.Piece as Component.Piece-import qualified BishBosh.Property.Empty as Property.Empty-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.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.Seeker as StateProperty.Seeker-import qualified BishBosh.Test.QuickCheck.Cartesian.Coordinates as Test.QuickCheck.Cartesian.Coordinates-import qualified BishBosh.Type.Length as Type.Length+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.Component.Move as Component.Move+import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Property.Empty as Property.Empty+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.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.Seeker as StateProperty.Seeker import qualified Control.Monad import qualified Data.Foldable import qualified Data.List-import qualified Data.Map+import qualified Data.Map.Strict as Map import qualified Data.Maybe import qualified Data.Ord import qualified Data.Set import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Defines a concrete type for testing.-type Board = State.Board.Board Type.Length.X Type.Length.Y--instance (- Enum x,- Enum y,- Ord x,- Ord y- ) => Test.QuickCheck.Arbitrary (State.Board.Board x y) where- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Board #-}+instance Test.QuickCheck.Arbitrary State.Board.Board where arbitrary = let- isKingChecked :: (Enum x, Enum y, Ord x, Ord y) => Attribute.LogicalColour.LogicalColour -> State.Board.Board x y -> Bool+ isKingChecked :: Attribute.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@@ -98,41 +84,41 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f = Test.QuickCheck.label "Board.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 "Board.prop_read" $ case (reads garbage :: [(Board, String)]) of+ f garbage = Test.QuickCheck.label "Board.prop_read" $ case (reads garbage :: [(State.Board.Board, 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 :: Board -> String -> Test.QuickCheck.Property+ f :: State.Board.Board -> String -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` ('/' : Component.Piece.showPieces ++ concatMap show [1 .. Cartesian.Abscissa.xLength])) board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_fen" $ case Property.ForsythEdwards.readsFEN $ Property.ForsythEdwards.showFEN board of [(board', "")] -> board' == board _ -> False in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f, let- f :: Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Attribute.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 piece = Component.Piece.mkBishop logicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Property+ f :: Cartesian.Coordinates.Coordinates -> Attribute.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 piece = Component.Piece.mkKnight logicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_listDestinationsFor/unique" $ all ( \(coordinates, piece) -> uncurry (==) . ( length &&& length . Data.List.nub@@ -141,27 +127,27 @@ maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_(findAttacksBy <=> findAttackersOf)" $ all ( \(piece, coordinates) -> let logicalColour = Component.Piece.getLogicalColour piece in all ( \destination -> foldr ( \rank m -> foldr (- \source -> Data.Map.insertWith Data.Set.union source $ Data.Set.singleton rank+ \source -> Map.insertWith Data.Set.union source $ Data.Set.singleton rank ) m $ State.Board.findAttacksBy ( Component.Piece.mkPiece (Property.Opposable.getOpposite logicalColour) rank ) destination board- ) Data.Map.empty Property.FixedMembership.members == foldr (- \(source, rank) -> Data.Map.insertWith Data.Set.union source $ Data.Set.singleton rank- ) Data.Map.empty (+ ) 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 ) ) coordinates ) . State.CoordinatesByRankByLogicalColour.assocs $ State.Board.getCoordinatesByRankByLogicalColour board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ 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@@ -176,26 +162,26 @@ maybePieceByCoordinates = State.Board.getMaybePieceByCoordinates board in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ 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 ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f = Test.QuickCheck.label "Board.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f = Test.QuickCheck.label "Board.prop_reflectOnY" . uncurry (==) . (id &&& Property.Reflectable.reflectOnY . Property.Reflectable.reflectOnY) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f = Test.QuickCheck.label "Board.prop_countPawnsByFileByLogicalColour" . ( \coordinatesByRankByLogicalColour -> all ( uncurry (==) . ( Data.Foldable.sum . (- State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour !+ StateProperty.Seeker.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour ! ) &&& fromIntegral . length . ( \logicalColour -> State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn coordinatesByRankByLogicalColour )@@ -204,7 +190,7 @@ ) . State.Board.getCoordinatesByRankByLogicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Board -> Test.QuickCheck.Property+ 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 ) [@@ -217,7 +203,7 @@ ] -- List-comprehension. in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f, let- f :: Board -> Test.QuickCheck.Property+ f :: State.Board.Board -> Test.QuickCheck.Property f board = Test.QuickCheck.label "Board.prop_findProximateKnights" . all ( \(coordinates, piece) -> let logicalColour = Property.Opposable.getOpposite $ Component.Piece.getLogicalColour piece
src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs view
@@ -24,14 +24,12 @@ -} module BishBosh.Test.QuickCheck.State.CastleableRooksByLogicalColour(--- * Types--- ** Type-synonyms- CastleableRooksByLogicalColour, -- * Constants results ) where import BishBosh.Test.QuickCheck.Attribute.LogicalColour()+import BishBosh.Test.QuickCheck.Cartesian.Coordinates() import Control.Arrow((&&&)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa@@ -40,19 +38,13 @@ import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour-import qualified BishBosh.Test.QuickCheck.Cartesian.Coordinates as Test.QuickCheck.Cartesian.Coordinates-import qualified BishBosh.Type.Length as Type.Length import qualified Data.List import qualified Data.List.Extra import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO import Test.QuickCheck((==>)) -instance (- Enum x,- Ord x,- Show x- ) => Test.QuickCheck.Arbitrary (State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour x) where+instance Test.QuickCheck.Arbitrary State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour where arbitrary = fmap ( State.CastleableRooksByLogicalColour.fromAssocs . Data.List.Extra.groupSort ) . Test.QuickCheck.elements $ Data.List.subsequences [@@ -61,38 +53,35 @@ x <- [Cartesian.Abscissa.xMin, Cartesian.Abscissa.xMax] ] -- List-comprehension. --- | Defines a concrete type for testing.-type CastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour Type.Length.X- -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f = Test.QuickCheck.label "CastleableRooksByLogicalColour.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 "CastleableRooksByLogicalColour.prop_read" $ case (reads garbage :: [(CastleableRooksByLogicalColour, String)]) of+ f garbage = Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_read" $ case (reads garbage :: [(State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour, 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 :: CastleableRooksByLogicalColour -> String -> Test.QuickCheck.Property+ f :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> String -> Test.QuickCheck.Property f castleableRooksByLogicalColour = Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) castleableRooksByLogicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f = Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_reflectOnX" . uncurry (==) . (id &&& Property.Reflectable.reflectOnX . Property.Reflectable.reflectOnX) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f :: State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f = Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_fen" . uncurry (==) . ( State.CastleableRooksByLogicalColour.unify . Property.ForsythEdwards.readFEN . Property.ForsythEdwards.showFEN &&& State.CastleableRooksByLogicalColour.unify ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ 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)@@ -100,7 +89,7 @@ ) Property.FixedMembership.members in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f, let- f :: Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ f :: Attribute.LogicalColour.LogicalColour -> Cartesian.Coordinates.Coordinates -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour -> Test.QuickCheck.Property f logicalColour coordinates castleableRooksByLogicalColour = coordinates `notElem` [ minBound, Cartesian.Coordinates.bottomRight,@@ -109,14 +98,14 @@ ] ==> Test.QuickCheck.label "CastleableRooksByLogicalColour.prop_canCastleWith" . not $ State.CastleableRooksByLogicalColour.canCastleWith logicalColour coordinates castleableRooksByLogicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64} f, let- f :: Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64, Test.QuickCheck.maxDiscardRatio = 128 } f, let- f :: Attribute.LogicalColour.LogicalColour -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> CastleableRooksByLogicalColour -> Test.QuickCheck.Property+ 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 in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]
src-test/BishBosh/Test/QuickCheck/State/InstancesByPosition.hs view
@@ -28,16 +28,16 @@ ) where import Control.Arrow((&&&))+import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.State.InstancesByPosition as State.InstancesByPosition-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game import qualified Test.QuickCheck -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "InstancesByPosition.prop_countPositionRepetitions" . uncurry (==) . ( State.InstancesByPosition.countPositionRepetitions &&& uncurry (-) . ( succ . fromIntegral . State.InstancesByPosition.countConsecutiveRepeatablePlies &&& State.InstancesByPosition.getNDistinctPositions@@ -45,7 +45,7 @@ ) . Model.Game.getInstancesByPosition in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "InstancesByPosition.prop_anyInstancesByPosition (< 1)" . not . State.InstancesByPosition.anyInstancesByPosition (< 1) . Model.Game.getInstancesByPosition in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/State/Position.hs view
@@ -28,6 +28,7 @@ ) where import Control.Arrow((&&&))+import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.Move as Component.Move@@ -35,7 +36,6 @@ import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.State.EnPassantAbscissa as State.EnPassantAbscissa import qualified BishBosh.State.Position as State.Position-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game import qualified Data.List import qualified Test.QuickCheck @@ -43,7 +43,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Position.prop_getMaybeEnPassantAbscissa" . uncurry (==) . ( fmap ( Cartesian.Coordinates.getX . Component.Move.getDestination . Component.QualifiedMove.getMove -- Extract the abscissa.
src-test/BishBosh/Test/QuickCheck/State/TurnsByLogicalColour.hs view
@@ -32,25 +32,23 @@ ) where import BishBosh.Test.QuickCheck.Component.Turn()+import BishBosh.Test.QuickCheck.Model.Game() import Control.Arrow((&&&)) import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa 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.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game-import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO --- | Define a concrete type for testing.-type TurnsByLogicalColour = State.TurnsByLogicalColour.TurnsByLogicalColour (Component.Turn.Turn Type.Length.X Type.Length.Y)+type TurnsByLogicalColour = State.TurnsByLogicalColour.TurnsByLogicalColour Component.Turn.Turn instance (- Show a,- Test.QuickCheck.Arbitrary a- ) => Test.QuickCheck.Arbitrary (State.TurnsByLogicalColour.TurnsByLogicalColour a) where--- {-# SPECIALISE instance Test.QuickCheck.Arbitrary TurnsByLogicalColour #-}+ Show turn,+ Test.QuickCheck.Arbitrary turn+ ) => Test.QuickCheck.Arbitrary (State.TurnsByLogicalColour.TurnsByLogicalColour turn) where+ {-# SPECIALISE instance Test.QuickCheck.Arbitrary TurnsByLogicalColour #-} arbitrary = do turns <- Test.QuickCheck.arbitrary @@ -76,7 +74,7 @@ f turnsByLogicalColour = Test.QuickCheck.label "TurnsByLogicalColour.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` ('/' : Component.Piece.showPieces ++ concatMap show [1 .. Cartesian.Abscissa.xLength])) turnsByLogicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "TurnsByLogicalColour.prop_getNPlies" . uncurry (==) . (State.TurnsByLogicalColour.getNPlies &&& State.TurnsByLogicalColour.countPlies) . Model.Game.getTurnsByLogicalColour in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/StateProperty/Censor.hs view
@@ -28,10 +28,10 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.StateProperty.Censor as StateProperty.Censor-import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game+import BishBosh.Test.QuickCheck.Model.Game()+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified Test.QuickCheck -- import Test.QuickCheck((==>)) @@ -39,32 +39,32 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_countPiecesByLogicalColour" . uncurry (==) . ( StateProperty.Censor.countPiecesByLogicalColour . State.Board.getMaybePieceByCoordinates &&& StateProperty.Censor.countPiecesByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_countPieces" . uncurry (==) . ( StateProperty.Censor.countPieces . State.Board.getMaybePieceByCoordinates &&& StateProperty.Censor.countPieces . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_countPieces/bounds" . uncurry (&&) . ( (> 2) &&& (<= 32) ) . StateProperty.Censor.countPieces . State.Board.getCoordinatesByRankByLogicalColour . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_countPieceDifferenceByRank" . uncurry (==) . ( StateProperty.Censor.countPieceDifferenceByRank . State.Board.getMaybePieceByCoordinates &&& StateProperty.Censor.countPieceDifferenceByRank . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, {- let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f game = Model.Game.isTerminated game ==> Test.QuickCheck.label "Censor.prop_hasInsufficientMaterial" . uncurry (==) . ( StateProperty.Censor.hasInsufficientMaterial . State.Board.getMaybePieceByCoordinates &&& StateProperty.Censor.hasInsufficientMaterial . State.Board.getCoordinatesByRankByLogicalColour ) $ Model.Game.getBoard game@@ -74,19 +74,19 @@ } f, -} let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_hasBothKings" . uncurry (==) . ( StateProperty.Censor.hasBothKings . State.Board.getMaybePieceByCoordinates &&& StateProperty.Censor.hasBothKings . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_(getNPieces == countPieces)" . uncurry (==) . ( State.Board.getNPieces &&& StateProperty.Censor.countPieces . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let- f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property+ f :: Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "Censor.prop_(getNPiecesDifferenceByRank == countPieceDifferenceByRank)" . uncurry (==) . ( State.Board.getNPiecesDifferenceByRank &&& StateProperty.Censor.countPieceDifferenceByRank . State.Board.getCoordinatesByRankByLogicalColour ) . Model.Game.getBoard
+ src-test/BishBosh/Test/QuickCheck/StateProperty/Hashable.hs view
@@ -0,0 +1,78 @@+{-+ 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 tests.+-}++module BishBosh.Test.QuickCheck.StateProperty.Hashable(+-- * Constants,+ results+) where++import BishBosh.Test.QuickCheck.Model.Game()+import Control.Arrow((&&&))+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.StateProperty.Hashable as StateProperty.Hashable+import qualified BishBosh.Test.QuickCheck.Component.Zobrist as Test.QuickCheck.Component.Zobrist+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 :: 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)+ ) $ 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)+ ) $ 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+ ) . (`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_incrementalEvaluation" . all (+ (+ \game' -> StateProperty.Hashable.hash game' zobrist == Model.Game.updateIncrementalPositionHash game (+ StateProperty.Hashable.hash game zobrist+ ) game' zobrist+ ) . (`Model.Game.applyQualifiedMove` game)+ ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ ] where+ areUnique :: Ord a => [a] -> Bool+ areUnique = all ((== 1) . length) . Data.List.group . Data.List.sort+
+ src-test/BishBosh/Test/QuickCheck/StateProperty/Seeker.hs view
@@ -0,0 +1,72 @@+{-+ 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.Seeker(+-- * Constants+ results+) where++import BishBosh.Test.QuickCheck.Model.Game()+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.Component.Piece as Component.Piece+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker+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 "Seeker.prop_(getNPawnsByFileByLogicalColour => countPawnsByFileByLogicalColour)" . uncurry (==) . (+ State.Board.getNPawnsByFileByLogicalColour &&& StateProperty.Seeker.countPawnsByFileByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour+ ) . 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 "Seeker.prop_countPawnsByFileByLogicalColour" . uncurry (==) . (+ StateProperty.Seeker.countPawnsByFileByLogicalColour . State.Board.getMaybePieceByCoordinates &&& StateProperty.Seeker.countPawnsByFileByLogicalColour . State.Board.getCoordinatesByRankByLogicalColour+ ) . 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 "Seeker.prop_(summariseNPawnsByLogicalColour vs getNPiecesDifferenceByRank)" . uncurry (==) . (+ uncurry (-) . ((! maxBound) &&& (! minBound)) . StateProperty.Seeker.summariseNPawnsByLogicalColour &&& (! Attribute.Rank.Pawn) . State.Board.getNPiecesDifferenceByRank+ ) . Model.Game.getBoard+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Model.Game.Game -> Test.QuickCheck.Property+ f game = Test.QuickCheck.label "Seeker.prop_pawnOrdinates" . all (+ uncurry (&&) . (+ (/= Cartesian.Ordinate.yMin) &&& (/= Cartesian.Ordinate.yMax)+ ) . Cartesian.Coordinates.getY . fst {-coordinates-}+ ) . StateProperty.Seeker.findPieces Component.Piece.isPawn . State.Board.getCoordinatesByRankByLogicalColour $ Model.Game.getBoard game+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ ]+
+ src-test/BishBosh/Test/QuickCheck/Type/Count.hs view
@@ -0,0 +1,36 @@+{-# 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.Count() where++#ifdef USE_NEWTYPE_WRAPPERS+import qualified BishBosh.Type.Count as Type.Count+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Type.Count.NPlies where+ arbitrary = fromInteger <$> Test.QuickCheck.elements [0 .. 9]+#endif+
+ src-test/BishBosh/Test/QuickCheck/Type/Length.hs view
@@ -0,0 +1,41 @@+{-# 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.Length() where++#ifdef USE_NEWTYPE_WRAPPERS+import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa+import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate+import qualified BishBosh.Type.Length as Type.Length+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Type.Length.X where+ arbitrary = Test.QuickCheck.elements Cartesian.Abscissa.xRange++instance Test.QuickCheck.Arbitrary Type.Length.Y where+ arbitrary = Test.QuickCheck.elements Cartesian.Ordinate.yRange+#endif+
src-test/BishBosh/Test/QuickCheck/UI/Command.hs view
@@ -24,23 +24,16 @@ -} module BishBosh.Test.QuickCheck.UI.Command (--- * Types--- ** Type-synonyms--- Command, -- * Constants results ) where import BishBosh.Test.QuickCheck.UI.PrintObject() import BishBosh.Test.QuickCheck.UI.SetObject()-import qualified BishBosh.Type.Length as Type.Length import qualified BishBosh.UI.Command as UI.Command import qualified Test.QuickCheck --- | Define a concrete type for testing.-type Command = UI.Command.Command Type.Length.X Type.Length.Y--instance Test.QuickCheck.Arbitrary (UI.Command.Command x y) where+instance Test.QuickCheck.Arbitrary UI.Command.Command where arbitrary = Test.QuickCheck.oneof [ Test.QuickCheck.elements [ UI.Command.Hint,@@ -59,7 +52,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Command -> Test.QuickCheck.Property+ f :: UI.Command.Command -> Test.QuickCheck.Property f command = Test.QuickCheck.label "Command.prop_io" $ UI.Command.readsCommand (UI.Command.showsCommand command "") == Right (command, "") in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/UI/SetObject.hs view
@@ -28,13 +28,17 @@ results ) where +import BishBosh.Test.QuickCheck.Model.Game() import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.UI.SetObject as UI.SetObject import qualified Test.QuickCheck import qualified ToolShed.Test.ReversibleIO instance Test.QuickCheck.Arbitrary UI.SetObject.SetObject where- arbitrary = fmap (UI.SetObject.mkSearchDepth . (+ Input.SearchOptions.minimumSearchDepth) . fromInteger . (`mod` 4)) Test.QuickCheck.arbitrary+ arbitrary = Test.QuickCheck.oneof [+-- UI.SetObject.mkEPD <$> Test.QuickCheck.arbitrary, -- CAVEAT: this is problematic, since move-information is irretrievably lost from the game in the conversion to EPD.+ Test.QuickCheck.elements $ map UI.SetObject.mkSearchDepth $ take 4 [Input.SearchOptions.minimumSearchDepth .. ]+ ] -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]@@ -54,6 +58,4 @@ f setObject = Test.QuickCheck.label "SetObject.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` (".-+eEoOxX" ++ ['0' .. '9'])) setObject in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024} f ]--
src-test/HUnit.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2021 Dr. Alistair Ward @@ -42,16 +41,13 @@ import qualified BishBosh.Test.HUnit.Model.Game as Test.HUnit.Model.Game import qualified BishBosh.Test.HUnit.Model.GameTree as Test.HUnit.Model.GameTree import qualified BishBosh.Test.HUnit.Model.PositionHashTree as Test.HUnit.Model.PositionHashTree+import qualified BishBosh.Test.HUnit.Search.Search as Test.HUnit.Search.Search import qualified BishBosh.Test.HUnit.State.Board as Test.HUnit.State.Board import qualified BishBosh.Test.HUnit.Text.AutoComplete as Test.HUnit.Text.AutoComplete import qualified BishBosh.Test.HUnit.Time.GameClock as Test.HUnit.Time.GameClock import qualified BishBosh.Test.HUnit.Time.StopWatch as Test.HUnit.Time.StopWatch import qualified Test.HUnit -#ifdef USE_SEARCH-import qualified BishBosh.Test.HUnit.Search.Search as Test.HUnit.Search.Search-#endif- -- | Entry-point to the test-suite. main :: IO () main = mapM_ Test.HUnit.runTestTT [@@ -75,9 +71,7 @@ Test.HUnit.ContextualNotation.PGN.testCases, Test.HUnit.ContextualNotation.PositionHashQualifiedMoveTree.testCases, Test.HUnit.Input.Options.testCases,-#ifdef USE_SEARCH- Test.HUnit.Search.Search.testCases,-#endif- Test.HUnit.Evaluation.Fitness.testCases+ Test.HUnit.Evaluation.Fitness.testCases,+ Test.HUnit.Search.Search.testCases ]
src-test/QuickCheck.hs view
@@ -34,7 +34,6 @@ import qualified BishBosh.Test.QuickCheck.Component.Piece as Test.QuickCheck.Component.Piece import qualified BishBosh.Test.QuickCheck.Component.QualifiedMove as Test.QuickCheck.Component.QualifiedMove import qualified BishBosh.Test.QuickCheck.Component.Turn as Test.QuickCheck.Component.Turn-import qualified BishBosh.Test.QuickCheck.Component.Zobrist as Test.QuickCheck.Component.Zobrist import qualified BishBosh.Test.QuickCheck.ContextualNotation.PGN as Test.QuickCheck.ContextualNotation.PGN import qualified BishBosh.Test.QuickCheck.ContextualNotation.PGNComment as Test.QuickCheck.ContextualNotation.PGNComment import qualified BishBosh.Test.QuickCheck.ContextualNotation.PositionHashQualifiedMoveTree as Test.QuickCheck.ContextualNotation.PositionHashQualifiedMoveTree@@ -51,7 +50,9 @@ import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game import qualified BishBosh.Test.QuickCheck.Model.GameTree as Test.QuickCheck.Model.GameTree import qualified BishBosh.Test.QuickCheck.Model.MoveFrequency as Test.QuickCheck.Model.MoveFrequency+import qualified BishBosh.Test.QuickCheck.Notation.Figurine as Test.QuickCheck.Notation.Figurine import qualified BishBosh.Test.QuickCheck.Notation.ICCFNumeric as Test.QuickCheck.Notation.ICCFNumeric+import qualified BishBosh.Test.QuickCheck.Notation.MoveNotation as Test.QuickCheck.Notation.MoveNotation import qualified BishBosh.Test.QuickCheck.Notation.PureCoordinate as Test.QuickCheck.Notation.PureCoordinate import qualified BishBosh.Test.QuickCheck.Notation.Smith as Test.QuickCheck.Notation.Smith import qualified BishBosh.Test.QuickCheck.Rule.GameTerminationReason as Test.QuickCheck.Rule.GameTerminationReason@@ -63,6 +64,8 @@ import qualified BishBosh.Test.QuickCheck.State.InstancesByPosition as Test.QuickCheck.State.InstancesByPosition 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.Seeker as Test.QuickCheck.StateProperty.Seeker 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@@ -95,19 +98,22 @@ Test.QuickCheck.Component.Turn.results, Test.QuickCheck.Rule.GameTerminationReason.results, Test.QuickCheck.Rule.Result.results,+ Test.QuickCheck.Notation.Figurine.results, Test.QuickCheck.Notation.ICCFNumeric.results, Test.QuickCheck.Notation.PureCoordinate.results, Test.QuickCheck.Notation.Smith.results,+ Test.QuickCheck.Notation.MoveNotation.results, Test.QuickCheck.State.CastleableRooksByLogicalColour.results, Test.QuickCheck.State.Position.results, Test.QuickCheck.State.InstancesByPosition.results, Test.QuickCheck.State.Board.results, Test.QuickCheck.State.TurnsByLogicalColour.results, Test.QuickCheck.StateProperty.Censor.results,+ Test.QuickCheck.StateProperty.Hashable.results,+ Test.QuickCheck.StateProperty.Seeker.results, Test.QuickCheck.Model.Game.results, Test.QuickCheck.Model.GameTree.results, Test.QuickCheck.Model.MoveFrequency.results,- Test.QuickCheck.Component.Zobrist.results, Test.QuickCheck.ContextualNotation.PositionHashQualifiedMoveTree.results, Test.QuickCheck.ContextualNotation.StandardAlgebraic.results, Test.QuickCheck.ContextualNotation.PGNComment.results,