bishbosh 0.1.0.0 → 0.1.1.0
raw patch · 194 files changed
+4202/−3565 lines, 194 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- BishBosh.Attribute.CriterionValue: calculateWeightedMean :: (NFData criterionValue, Fractional weightedMean, Real criterionValue, Real criterionWeight) => [(CriterionValue criterionValue, CriterionWeight criterionWeight)] -> WeightedMeanAndCriterionValues weightedMean criterionValue
- BishBosh.Attribute.CriterionValue: data CriterionValue criterionValue
- BishBosh.Attribute.CriterionValue: instance GHC.Classes.Eq criterionValue => GHC.Classes.Eq (BishBosh.Attribute.CriterionValue.CriterionValue criterionValue)
- BishBosh.Attribute.CriterionValue: instance GHC.Num.Num criterionValue => GHC.Enum.Bounded (BishBosh.Attribute.CriterionValue.CriterionValue criterionValue)
- BishBosh.Attribute.CriterionValue: instance GHC.Show.Show criterionValue => GHC.Show.Show (BishBosh.Attribute.CriterionValue.CriterionValue criterionValue)
- BishBosh.Attribute.CriterionValue: mkCriterionValue :: (Num criterionValue, Ord criterionValue) => criterionValue -> CriterionValue criterionValue
- BishBosh.Attribute.CriterionValue: zero :: Num criterionValue => CriterionValue criterionValue
- BishBosh.Attribute.CriterionWeight: data CriterionWeight criterionWeight
- BishBosh.Attribute.CriterionWeight: instance (Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler criterionWeight, GHC.Num.Num criterionWeight, GHC.Classes.Ord criterionWeight, GHC.Show.Show criterionWeight) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance Control.DeepSeq.NFData criterionWeight => Control.DeepSeq.NFData (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance GHC.Classes.Eq criterionWeight => GHC.Classes.Eq (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance GHC.Classes.Ord criterionWeight => GHC.Classes.Ord (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance GHC.Num.Num criterionWeight => Data.Default.Class.Default (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance GHC.Num.Num criterionWeight => GHC.Enum.Bounded (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: instance GHC.Show.Show criterionWeight => GHC.Show.Show (BishBosh.Attribute.CriterionWeight.CriterionWeight criterionWeight)
- BishBosh.Attribute.CriterionWeight: mkCriterionWeight :: (Num criterionWeight, Ord criterionWeight, Show criterionWeight) => criterionWeight -> CriterionWeight criterionWeight
- BishBosh.Attribute.Direction: type NDirections = Int
- BishBosh.Attribute.RankValues: calculateMaximumTotalValue :: Num rankValue => RankValues rankValue -> rankValue
- BishBosh.Attribute.RankValues: data RankValues rankValue
- BishBosh.Attribute.RankValues: findRankValue :: Rank -> RankValues rankValue -> rankValue
- BishBosh.Attribute.RankValues: fromAssocs :: (Fractional rankValue, Ord rankValue, Show rankValue) => [(Rank, rankValue)] -> RankValues rankValue
- BishBosh.Attribute.RankValues: instance (GHC.Real.Fractional rankValue, GHC.Classes.Ord rankValue, GHC.Show.Show rankValue) => Data.Default.Class.Default (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance (GHC.Real.Fractional rankValue, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler rankValue, GHC.Classes.Ord rankValue, GHC.Show.Show rankValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance Control.DeepSeq.NFData rankValue => Control.DeepSeq.NFData (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance GHC.Classes.Eq rankValue => GHC.Classes.Eq (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance GHC.Read.Read rankValue => GHC.Read.Read (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance GHC.Real.Real rankValue => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: instance GHC.Show.Show rankValue => GHC.Show.Show (BishBosh.Attribute.RankValues.RankValues rankValue)
- BishBosh.Attribute.RankValues: tag :: String
- BishBosh.Attribute.WeightedMeanAndCriterionValues: criterionValuesTag :: String
- BishBosh.Attribute.WeightedMeanAndCriterionValues: data WeightedMeanAndCriterionValues weightedMean criterionValue
- BishBosh.Attribute.WeightedMeanAndCriterionValues: instance (GHC.Classes.Eq weightedMean, GHC.Classes.Eq criterionValue) => GHC.Classes.Eq (BishBosh.Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue)
- BishBosh.Attribute.WeightedMeanAndCriterionValues: instance (GHC.Real.Real criterionValue, GHC.Real.Real weightedMean) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue)
- BishBosh.Attribute.WeightedMeanAndCriterionValues: instance (GHC.Show.Show weightedMean, GHC.Show.Show criterionValue) => GHC.Show.Show (BishBosh.Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue)
- BishBosh.Attribute.WeightedMeanAndCriterionValues: instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (BishBosh.Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue)
- BishBosh.Attribute.WeightedMeanAndCriterionValues: mkWeightedMeanAndCriterionValues :: weightedMean -> [criterionValue] -> WeightedMeanAndCriterionValues weightedMean criterionValue
- BishBosh.Attribute.WeightedMeanAndCriterionValues: negateWeightedMean :: Num weightedMean => WeightedMeanAndCriterionValues weightedMean criterionValue -> WeightedMeanAndCriterionValues weightedMean criterionValue
- BishBosh.Attribute.WeightedMeanAndCriterionValues: weightedMeanTag :: String
- BishBosh.Component.Move: type NMoves = Int
- BishBosh.Component.Move: type NPlies = NMoves
- BishBosh.Component.Piece: type NPieces = Int
- BishBosh.Data.Float: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Types.Double
- BishBosh.Data.Float: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Types.Float
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Int.Int16
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Int.Int32
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Int.Int8
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Types.Word
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Word.Word16
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Word.Word32
- BishBosh.Data.Integral: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Word.Word8
- BishBosh.Data.Time: measureElapsedTime :: UTCTime -> IO NominalDiffTime
- BishBosh.Data.Time: showsTimeAsSeconds :: PrintfArg i => i -> NominalDiffTime -> ShowS
- 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 weightedMean, GHC.Classes.Eq criterionValue) => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash criterionValue weightedMean)
- 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 weightedMean, GHC.Classes.Eq criterionValue) => GHC.Classes.Eq (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean)
- 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 weightedMean, GHC.Show.Show criterionValue) => GHC.Show.Show (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash criterionValue weightedMean)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Real weightedMean) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash criterionValue weightedMean)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Real weightedMean) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Arboreal.Prunable (BishBosh.Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: instance BishBosh.Property.Null.Null (BishBosh.Evaluation.PositionHashQuantifiedGameTree.NodeLabel x y positionHash criterionValue weightedMean)
- BishBosh.Evaluation.QuantifiedGame: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Classes.Eq weightedMean, GHC.Classes.Eq criterionValue) => GHC.Classes.Eq (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)
- 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 weightedMean, GHC.Show.Show criterionValue) => GHC.Show.Show (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)
- BishBosh.Evaluation.QuantifiedGame: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Real criterionValue, GHC.Real.Real weightedMean) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)
- BishBosh.Evaluation.QuantifiedGame: instance BishBosh.Property.Null.Null (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)
- BishBosh.Evaluation.QuantifiedGame: instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (BishBosh.Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)
- BishBosh.Input.CriteriaWeights: instance (Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler criterionWeight, GHC.Num.Num criterionWeight, GHC.Classes.Ord criterionWeight, GHC.Show.Show criterionWeight) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance Control.DeepSeq.NFData criterionWeight => Control.DeepSeq.NFData (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance GHC.Classes.Eq criterionWeight => GHC.Classes.Eq (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance GHC.Num.Num criterionWeight => Data.Default.Class.Default (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance GHC.Num.Num criterionWeight => GHC.Enum.Bounded (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance GHC.Real.Real criterionWeight => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: instance GHC.Show.Show criterionWeight => GHC.Show.Show (BishBosh.Input.CriteriaWeights.CriteriaWeights criterionWeight)
- BishBosh.Input.CriteriaWeights: perturbWeights :: (Fractional criterionWeight, Real criterionWeight, Show criterionWeight, RandomGen randomGen) => randomGen -> criterionWeight -> Transformation criterionWeight
- BishBosh.Input.EvaluationOptions: instance (Control.DeepSeq.NFData criterionWeight, Control.DeepSeq.NFData pieceSquareValue, Control.DeepSeq.NFData rankValue, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue 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 rankValue, GHC.Classes.Eq criterionWeight, GHC.Classes.Eq pieceSquareValue) => GHC.Classes.Eq (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue 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 criterionWeight, GHC.Real.Real pieceSquareValue, GHC.Real.Real rankValue, GHC.Show.Show pieceSquareValue) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue 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 rankValue, GHC.Show.Show criterionWeight, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue) => GHC.Show.Show (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Fractional pieceSquareValue, GHC.Real.Fractional rankValue, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler criterionWeight, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler rankValue, GHC.Num.Num criterionWeight, GHC.Classes.Ord criterionWeight, GHC.Classes.Ord pieceSquareValue, GHC.Classes.Ord rankValue, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real pieceSquareValue, GHC.Show.Show pieceSquareValue, GHC.Show.Show criterionWeight, GHC.Show.Show rankValue) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y)
- BishBosh.Input.EvaluationOptions: instance (GHC.Real.Fractional rankValue, GHC.Num.Num criterionWeight, GHC.Classes.Ord rankValue, GHC.Show.Show rankValue) => Data.Default.Class.Default (BishBosh.Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y)
- BishBosh.Input.IOOptions: instance (Control.DeepSeq.NFData column, Control.DeepSeq.NFData row) => Control.DeepSeq.NFData (BishBosh.Input.IOOptions.IOOptions row column)
- BishBosh.Input.IOOptions: instance (GHC.Classes.Eq row, GHC.Classes.Eq column) => GHC.Classes.Eq (BishBosh.Input.IOOptions.IOOptions row column)
- BishBosh.Input.IOOptions: instance (GHC.Num.Num column, GHC.Num.Num row) => Data.Default.Class.Default (BishBosh.Input.IOOptions.IOOptions row column)
- BishBosh.Input.IOOptions: instance (GHC.Show.Show column, GHC.Show.Show row) => GHC.Show.Show (BishBosh.Input.IOOptions.IOOptions row column)
- BishBosh.Input.IOOptions: instance (Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler column, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler row, GHC.Real.Integral column, GHC.Real.Integral row, GHC.Show.Show column, GHC.Show.Show row) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.IOOptions.IOOptions row column)
- BishBosh.Input.IOOptions: type MaximumPGNNames = Int
- BishBosh.Input.NativeUIOptions: instance (Control.DeepSeq.NFData column, Control.DeepSeq.NFData row) => Control.DeepSeq.NFData (BishBosh.Input.NativeUIOptions.NativeUIOptions row column)
- BishBosh.Input.NativeUIOptions: instance (GHC.Classes.Eq row, GHC.Classes.Eq column) => GHC.Classes.Eq (BishBosh.Input.NativeUIOptions.NativeUIOptions row column)
- BishBosh.Input.NativeUIOptions: instance (GHC.Num.Num row, GHC.Num.Num column) => Data.Default.Class.Default (BishBosh.Input.NativeUIOptions.NativeUIOptions row column)
- BishBosh.Input.NativeUIOptions: instance (GHC.Show.Show row, GHC.Show.Show column) => GHC.Show.Show (BishBosh.Input.NativeUIOptions.NativeUIOptions row column)
- BishBosh.Input.NativeUIOptions: instance (Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler column, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler row, GHC.Real.Integral column, GHC.Real.Integral row, GHC.Show.Show column, GHC.Show.Show row) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.NativeUIOptions.NativeUIOptions row column)
- BishBosh.Input.NativeUIOptions: type ScreenCoordinates row column = (row, column)
- BishBosh.Input.Options: instance (Control.DeepSeq.NFData column, Control.DeepSeq.NFData criterionWeight, Control.DeepSeq.NFData pieceSquareValue, Control.DeepSeq.NFData rankValue, Control.DeepSeq.NFData row, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y) => Control.DeepSeq.NFData (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row 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 rankValue, GHC.Classes.Eq criterionWeight, GHC.Classes.Eq pieceSquareValue, GHC.Classes.Eq row, GHC.Classes.Eq column) => GHC.Classes.Eq (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row 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 criterionWeight, GHC.Real.Real pieceSquareValue, GHC.Real.Real rankValue, GHC.Show.Show column, GHC.Show.Show pieceSquareValue, GHC.Show.Show row) => BishBosh.Property.ShowFloat.ShowFloat (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row 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 rankValue, GHC.Show.Show criterionWeight, GHC.Show.Show x, GHC.Show.Show y, GHC.Show.Show pieceSquareValue, GHC.Show.Show column, GHC.Show.Show row) => GHC.Show.Show (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y)
- BishBosh.Input.Options: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Fractional pieceSquareValue, GHC.Real.Fractional rankValue, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler column, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler criterionWeight, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler rankValue, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler row, GHC.Real.Integral column, GHC.Real.Integral row, GHC.Num.Num criterionWeight, GHC.Classes.Ord pieceSquareValue, GHC.Classes.Ord rankValue, GHC.Classes.Ord x, GHC.Classes.Ord y, GHC.Real.Real criterionWeight, GHC.Real.Real pieceSquareValue, GHC.Show.Show column, GHC.Show.Show criterionWeight, GHC.Show.Show pieceSquareValue, GHC.Show.Show rankValue, GHC.Show.Show row) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y)
- BishBosh.Input.Options: instance (GHC.Real.Fractional rankValue, GHC.Num.Num criterionWeight, GHC.Num.Num column, GHC.Num.Num row, GHC.Classes.Ord rankValue, GHC.Show.Show rankValue) => Data.Default.Class.Default (BishBosh.Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y)
- BishBosh.Input.SearchOptions: type SearchDepth = NPlies
- BishBosh.Input.UIOptions: instance (Control.DeepSeq.NFData column, Control.DeepSeq.NFData row) => Control.DeepSeq.NFData (BishBosh.Input.UIOptions.UIOptions row column)
- BishBosh.Input.UIOptions: instance (GHC.Classes.Eq row, GHC.Classes.Eq column) => GHC.Classes.Eq (BishBosh.Input.UIOptions.UIOptions row column)
- BishBosh.Input.UIOptions: instance (GHC.Num.Num row, GHC.Num.Num column) => Data.Default.Class.Default (BishBosh.Input.UIOptions.UIOptions row column)
- BishBosh.Input.UIOptions: instance (GHC.Show.Show row, GHC.Show.Show column) => GHC.Show.Show (BishBosh.Input.UIOptions.UIOptions row column)
- BishBosh.Input.UIOptions: instance (Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler column, Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler row, GHC.Real.Integral column, GHC.Real.Integral row, GHC.Show.Show column, GHC.Show.Show row) => Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler (BishBosh.Input.UIOptions.UIOptions row column)
- BishBosh.Model.DrawReason: byAgreement :: DrawReason
- BishBosh.Model.DrawReason: data DrawReason
- BishBosh.Model.DrawReason: fiveFoldRepetition :: DrawReason
- BishBosh.Model.DrawReason: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: instance Control.DeepSeq.NFData BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: instance GHC.Classes.Eq BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: instance GHC.Classes.Ord BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: instance GHC.Read.Read BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: instance GHC.Show.Show BishBosh.Model.DrawReason.DrawReason
- BishBosh.Model.DrawReason: insufficientMaterial :: DrawReason
- BishBosh.Model.DrawReason: maximumConsecutiveRepeatablePlies :: NPlies
- BishBosh.Model.DrawReason: maximumConsecutiveRepeatablePositions :: NMoves
- BishBosh.Model.DrawReason: seventyFiveMoveRule :: DrawReason
- BishBosh.Model.DrawReason: staleMate :: DrawReason
- BishBosh.Model.Game: countMovesAvailableTo :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> Game x y -> NPlies
- BishBosh.Model.Game: type NGames = Int
- BishBosh.Model.GameTerminationReason: data GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance BishBosh.Property.Opposable.Opposable BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance Control.DeepSeq.NFData BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance GHC.Classes.Eq BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance GHC.Classes.Ord BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance GHC.Read.Read BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: instance GHC.Show.Show BishBosh.Model.GameTerminationReason.GameTerminationReason
- BishBosh.Model.GameTerminationReason: isCheckMate :: GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: isCheckMateBy :: LogicalColour -> GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: isDraw :: GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: isDrawByInsufficientMaterial :: GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: isResignation :: GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: isStaleMate :: GameTerminationReason -> Bool
- BishBosh.Model.GameTerminationReason: mkCheckMate :: LogicalColour -> GameTerminationReason
- BishBosh.Model.GameTerminationReason: mkDraw :: DrawReason -> GameTerminationReason
- BishBosh.Model.GameTerminationReason: mkResignation :: LogicalColour -> GameTerminationReason
- BishBosh.Model.GameTerminationReason: toResult :: GameTerminationReason -> Result
- BishBosh.Model.GameTree: countMoves :: Depth -> NGames
- BishBosh.Model.Result: data Result
- BishBosh.Model.Result: findMaybeVictor :: Result -> Maybe LogicalColour
- BishBosh.Model.Result: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Model.Result.Result
- BishBosh.Model.Result: instance BishBosh.Property.Opposable.Opposable BishBosh.Model.Result.Result
- BishBosh.Model.Result: instance Control.DeepSeq.NFData BishBosh.Model.Result.Result
- BishBosh.Model.Result: instance GHC.Classes.Eq BishBosh.Model.Result.Result
- BishBosh.Model.Result: instance GHC.Read.Read BishBosh.Model.Result.Result
- BishBosh.Model.Result: instance GHC.Show.Show BishBosh.Model.Result.Result
- BishBosh.Model.Result: isDraw :: Result -> Bool
- BishBosh.Model.Result: mkResult :: Maybe LogicalColour -> Result
- BishBosh.Property.ShowFloat: type NDecimalDigits = Int
- BishBosh.Search.Search: instance (GHC.Enum.Enum x, GHC.Enum.Enum y, GHC.Real.Real criterionValue, GHC.Real.Real weightedMean) => BishBosh.Notation.MoveNotation.ShowNotationFloat (BishBosh.Search.Search.Result x y positionHash criterionValue weightedMean)
- BishBosh.Search.Search: instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (BishBosh.Search.Search.Result x y positionHash criterionValue weightedMean)
- BishBosh.Search.SearchState: 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 criterionValue, GHC.Show.Show positionHash, GHC.Show.Show weightedMean) => GHC.Show.Show (BishBosh.Search.SearchState.SearchState x y positionHash criterionValue weightedMean)
- BishBosh.Search.SearchState: instance BishBosh.Search.EphemeralData.MaybeEphemeralData (BishBosh.Search.SearchState.SearchState x y positionHash criterionValue weightedMean)
- BishBosh.State.Board: type NBoards = Int
- BishBosh.Types: type CriterionValue = CriterionWeight
- BishBosh.Types: type CriterionWeight = Double
- BishBosh.Types: type Distance = X
- BishBosh.Types: type PieceSquareValue = CriterionValue
- BishBosh.Types: type PositionHash = Word
- BishBosh.Types: type RankValue = CriterionValue
- BishBosh.Types: type WeightedMean = CriterionValue
- BishBosh.Types: type X = Int
- BishBosh.Types: type Y = X
+ BishBosh.ContextualNotation.PGNDatabase: type MaybeMaximumGames = Maybe NGames
+ 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.CECPOptions: pause :: StopWatch -> CECPOptions -> CECPOptions
+ BishBosh.Input.CECPOptions: resume :: CECPOptions -> CECPOptions
+ BishBosh.Input.CriteriaWeights: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance Control.DeepSeq.NFData BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance Data.Default.Class.Default BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance GHC.Classes.Eq BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance GHC.Enum.Bounded BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance GHC.Show.Show BishBosh.Input.CriteriaWeights.CriteriaWeights
+ BishBosh.Input.CriteriaWeights: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.CriteriaWeights.CriteriaWeights
+ 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.IOOptions: instance Control.DeepSeq.NFData BishBosh.Input.IOOptions.IOOptions
+ BishBosh.Input.IOOptions: instance Data.Default.Class.Default BishBosh.Input.IOOptions.IOOptions
+ BishBosh.Input.IOOptions: instance GHC.Classes.Eq BishBosh.Input.IOOptions.IOOptions
+ BishBosh.Input.IOOptions: instance GHC.Show.Show BishBosh.Input.IOOptions.IOOptions
+ BishBosh.Input.IOOptions: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.IOOptions.IOOptions
+ BishBosh.Input.NativeUIOptions: instance Control.DeepSeq.NFData BishBosh.Input.NativeUIOptions.NativeUIOptions
+ BishBosh.Input.NativeUIOptions: instance Data.Default.Class.Default BishBosh.Input.NativeUIOptions.NativeUIOptions
+ BishBosh.Input.NativeUIOptions: instance GHC.Classes.Eq BishBosh.Input.NativeUIOptions.NativeUIOptions
+ BishBosh.Input.NativeUIOptions: instance GHC.Show.Show BishBosh.Input.NativeUIOptions.NativeUIOptions
+ BishBosh.Input.NativeUIOptions: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.NativeUIOptions.NativeUIOptions
+ 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.RankValues: calculateMaximumTotalValue :: RankValues -> RankValue
+ BishBosh.Input.RankValues: data RankValues
+ BishBosh.Input.RankValues: findRankValue :: Rank -> RankValues -> RankValue
+ BishBosh.Input.RankValues: fromAssocs :: [(Rank, RankValue)] -> RankValues
+ BishBosh.Input.RankValues: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance Control.DeepSeq.NFData BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance Data.Default.Class.Default BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance GHC.Classes.Eq BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance GHC.Read.Read BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance GHC.Show.Show BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.RankValues.RankValues
+ BishBosh.Input.RankValues: tag :: String
+ BishBosh.Input.SearchOptions: identifyAutomatedPlayers :: SearchOptions -> [LogicalColour]
+ BishBosh.Input.UIOptions: instance Control.DeepSeq.NFData BishBosh.Input.UIOptions.UIOptions
+ BishBosh.Input.UIOptions: instance Data.Default.Class.Default BishBosh.Input.UIOptions.UIOptions
+ BishBosh.Input.UIOptions: instance GHC.Classes.Eq BishBosh.Input.UIOptions.UIOptions
+ BishBosh.Input.UIOptions: instance GHC.Show.Show BishBosh.Input.UIOptions.UIOptions
+ BishBosh.Input.UIOptions: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Input.UIOptions.UIOptions
+ BishBosh.Metric.CriterionValue: type CriterionValue = CriterionValue
+ BishBosh.Metric.CriterionWeight: data CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance Control.DeepSeq.NFData BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance Data.Default.Class.Default BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Classes.Eq BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Classes.Ord BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Enum.Bounded BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Num.Num BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Real.Fractional BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Real.Real BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance GHC.Show.Show BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.CriterionWeight: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Metric.CriterionWeight.CriterionWeight
+ BishBosh.Metric.RankValue: data RankValue
+ BishBosh.Metric.RankValue: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance Control.DeepSeq.NFData BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Classes.Eq BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Classes.Ord BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Num.Num BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Read.Read BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Real.Fractional BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Real.Real BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance GHC.Show.Show BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.RankValue: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler BishBosh.Metric.RankValue.RankValue
+ BishBosh.Metric.WeightedMeanAndCriterionValues: calculateWeightedMean :: [(CriterionValue, CriterionWeight)] -> WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: criterionValuesTag :: String
+ BishBosh.Metric.WeightedMeanAndCriterionValues: data WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: instance Control.DeepSeq.NFData BishBosh.Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: instance GHC.Classes.Eq BishBosh.Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: instance GHC.Show.Show BishBosh.Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: mkWeightedMeanAndCriterionValues :: WeightedMean -> [CriterionValue] -> WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: negateWeightedMean :: WeightedMeanAndCriterionValues -> WeightedMeanAndCriterionValues
+ BishBosh.Metric.WeightedMeanAndCriterionValues: weightedMeanTag :: String
+ BishBosh.Model.Game: countPliesAvailableTo :: (Enum x, Enum y, Ord x, Ord y, Show x, Show y) => LogicalColour -> Game x y -> NPlies
+ BishBosh.Model.GameTree: countPositions :: Depth -> NPositions
+ BishBosh.Property.SelfValidating: class SelfValidating a
+ BishBosh.Property.SelfValidating: findErrors :: [(selfValidator -> Bool, String)] -> selfValidator -> [String]
+ BishBosh.Property.SelfValidating: findInvalidity :: SelfValidating a => a -> [String]
+ BishBosh.Property.SelfValidating: instance BishBosh.Property.SelfValidating.SelfValidating a => BishBosh.Property.SelfValidating.SelfValidating [a]
+ BishBosh.Property.SelfValidating: isInvalid :: SelfValidating a => a -> Bool
+ BishBosh.Property.SelfValidating: isValid :: SelfValidating a => a -> Bool
+ BishBosh.Property.ShowFloat: showsFloatToN' :: RealFloat a => NDecimalDigits -> a -> ShowS
+ BishBosh.Property.Switchable: class Switchable a
+ BishBosh.Property.Switchable: flick :: Switchable switchable => Int -> switchable -> IO switchable
+ BishBosh.Property.Switchable: isOff :: Switchable a => a -> Bool
+ BishBosh.Property.Switchable: isOn :: Switchable a => a -> Bool
+ BishBosh.Property.Switchable: on :: Switchable a => IO a
+ BishBosh.Property.Switchable: switchOff :: Switchable a => a -> IO a
+ BishBosh.Property.Switchable: toggle :: Switchable a => a -> IO a
+ BishBosh.Rule.DrawReason: byAgreement :: DrawReason
+ BishBosh.Rule.DrawReason: data DrawReason
+ BishBosh.Rule.DrawReason: fiveFoldRepetition :: DrawReason
+ BishBosh.Rule.DrawReason: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: instance Control.DeepSeq.NFData BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: instance GHC.Classes.Eq BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: instance GHC.Classes.Ord BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: instance GHC.Read.Read BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: instance GHC.Show.Show BishBosh.Rule.DrawReason.DrawReason
+ BishBosh.Rule.DrawReason: insufficientMaterial :: DrawReason
+ BishBosh.Rule.DrawReason: maximumConsecutiveRepeatablePlies :: NPlies
+ BishBosh.Rule.DrawReason: maximumConsecutiveRepeatablePositions :: NPositions
+ BishBosh.Rule.DrawReason: seventyFiveMoveRule :: DrawReason
+ BishBosh.Rule.DrawReason: staleMate :: DrawReason
+ BishBosh.Rule.GameTerminationReason: data GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance BishBosh.Property.Opposable.Opposable BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance Control.DeepSeq.NFData BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance GHC.Classes.Eq BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance GHC.Classes.Ord BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance GHC.Read.Read BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: instance GHC.Show.Show BishBosh.Rule.GameTerminationReason.GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: isCheckMate :: GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: isCheckMateBy :: LogicalColour -> GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: isDraw :: GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: isDrawByInsufficientMaterial :: GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: isResignation :: GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: isStaleMate :: GameTerminationReason -> Bool
+ BishBosh.Rule.GameTerminationReason: mkCheckMate :: LogicalColour -> GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: mkDraw :: DrawReason -> GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: mkResignation :: LogicalColour -> GameTerminationReason
+ BishBosh.Rule.GameTerminationReason: toResult :: GameTerminationReason -> Result
+ BishBosh.Rule.Result: data Result
+ BishBosh.Rule.Result: findMaybeVictor :: Result -> Maybe LogicalColour
+ BishBosh.Rule.Result: instance BishBosh.Property.FixedMembership.FixedMembership BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: instance BishBosh.Property.Opposable.Opposable BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: instance Control.DeepSeq.NFData BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: instance GHC.Classes.Eq BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: instance GHC.Read.Read BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: instance GHC.Show.Show BishBosh.Rule.Result.Result
+ BishBosh.Rule.Result: isDraw :: Result -> Bool
+ BishBosh.Rule.Result: mkResult :: Maybe LogicalColour -> Result
+ 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.Time.GameClock: data GameClock
+ BishBosh.Time.GameClock: instance BishBosh.Property.SelfValidating.SelfValidating BishBosh.Time.GameClock.GameClock
+ BishBosh.Time.GameClock: instance BishBosh.Property.Switchable.Switchable BishBosh.Time.GameClock.GameClock
+ BishBosh.Time.GameClock: showsElapsedTimes :: NDecimalDigits -> GameClock -> IO ShowS
+ BishBosh.Time.StopWatch: data StopWatch
+ BishBosh.Time.StopWatch: getElapsedTime :: Fractional f => StopWatch -> f
+ BishBosh.Time.StopWatch: instance BishBosh.Property.ShowFloat.ShowFloat BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: instance BishBosh.Property.Switchable.Switchable BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: instance Control.DeepSeq.NFData BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: instance Data.Default.Class.Default BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: instance GHC.Classes.Eq BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: instance GHC.Show.Show BishBosh.Time.StopWatch.StopWatch
+ BishBosh.Time.StopWatch: mkStoppedWatch :: NominalDiffTime -> StopWatch
+ BishBosh.Type.Count: type NDecimalDigits = Base
+ BishBosh.Type.Count: type NDirections = Base
+ BishBosh.Type.Count: type NGames = Base
+ BishBosh.Type.Count: type NLogicalColours = Base
+ BishBosh.Type.Count: type NMoves = Base
+ BishBosh.Type.Count: type NPieces = Base
+ BishBosh.Type.Count: type NPlies = Base
+ BishBosh.Type.Count: type NPositions = Base
+ BishBosh.Type.Count: type NRanks = Base
+ BishBosh.Type.Count: type NSeconds = Base
+ BishBosh.Type.Crypto: type PositionHash = Word
+ BishBosh.Type.Length: type Column = X
+ BishBosh.Type.Length: type Distance = Base
+ BishBosh.Type.Length: type Row = Y
+ BishBosh.Type.Length: type X = Base
+ BishBosh.Type.Length: type Y = Base
+ BishBosh.Type.Mass: instance Text.XML.HXT.Arrow.Pickle.Xml.XmlPickler GHC.Types.Double
+ BishBosh.Type.Mass: type CriterionValue = CriterionWeight
+ BishBosh.Type.Mass: type CriterionWeight = Double
+ BishBosh.Type.Mass: type PieceSquareValue = CriterionValue
+ BishBosh.Type.Mass: type RankValue = CriterionValue
+ BishBosh.Type.Mass: type WeightedMean = CriterionValue
- BishBosh.Attribute.LogicalColour: nDistinctLogicalColours :: Int
+ BishBosh.Attribute.LogicalColour: nDistinctLogicalColours :: NLogicalColours
- BishBosh.Attribute.Rank: compareByLVA :: Ord rankValue => EvaluateRank rankValue -> Rank -> Rank -> Ordering
+ BishBosh.Attribute.Rank: compareByLVA :: EvaluateRank -> Rank -> Rank -> Ordering
- BishBosh.Attribute.Rank: type EvaluateRank rankValue = Rank -> rankValue
+ BishBosh.Attribute.Rank: type EvaluateRank = Rank -> RankValue
- BishBosh.Component.Turn: compareByLVA :: Ord rankValue => EvaluateRank rankValue -> Turn x y -> Turn x y -> Ordering
+ BishBosh.Component.Turn: compareByLVA :: EvaluateRank -> Turn x y -> Turn x y -> Ordering
- BishBosh.Component.Turn: compareByMVVLVA :: Ord rankValue => EvaluateRank rankValue -> Turn x y -> Turn x y -> Ordering
+ BishBosh.Component.Turn: compareByMVVLVA :: EvaluateRank -> Turn x y -> Turn x y -> Ordering
- BishBosh.ContextualNotation.QualifiedMoveForest: count :: QualifiedMoveForest x y -> (NGames, NPlies)
+ BishBosh.ContextualNotation.QualifiedMoveForest: count :: QualifiedMoveForest x y -> (NGames, NPositions)
- BishBosh.ContextualNotation.QualifiedMoveForest: showsNames :: Maybe Int -> [Name] -> ShowS
+ BishBosh.ContextualNotation.QualifiedMoveForest: showsNames :: Maybe NGames -> [Name] -> ShowS
- BishBosh.Evaluation.Fitness: evaluateFitness :: (NFData criterionValue, Enum x, Enum y, Fractional criterionValue, Fractional pieceSquareValue, Fractional rankValue, Fractional weightedMean, Ord x, Ord y, Real criterionValue, Real criterionWeight, Real pieceSquareValue, Real rankValue, Show x, Show y) => Maybe pieceSquareValue -> Game x y -> Reader criterionWeight pieceSquareValue rankValue x y (WeightedMeanAndCriterionValues weightedMean criterionValue)
+ 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: measureValueOfCastlingPotential :: (Fractional criterionValue, Ord criterionValue) => Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfCastlingPotential :: Game x y -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfDefence :: (Fractional criterionValue, Ord criterionValue) => Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfDefence :: Game x y -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfDoubledPawns :: (Fractional criterionValue, Ord criterionValue) => Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfDoubledPawns :: Game x y -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfIsolatedPawns :: (Enum x, Fractional criterionValue, Ord criterionValue, Ord x) => Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfIsolatedPawns :: (Enum x, Ord x) => Game x y -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfMaterial :: (Fractional criterionValue, Fractional rankValue, Ord criterionValue, Real rankValue) => RankValues rankValue -> Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfMaterial :: RankValues -> RankValue -> Game x y -> CriterionValue
- BishBosh.Evaluation.Fitness: measureValueOfPassedPawns :: forall x y criterionValue. (Enum y, Fractional criterionValue, Ord criterionValue) => Game x y -> CriterionValue criterionValue
+ BishBosh.Evaluation.Fitness: measureValueOfPassedPawns :: forall x y. Enum y => Game x y -> CriterionValue
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: MkPositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: MkPositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: [deconstruct] :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: [deconstruct] :: PositionHashQuantifiedGameTree x y positionHash -> BarePositionHashQuantifiedGameTree x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: data NodeLabel x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: data NodeLabel x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> positionHash
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash -> positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> QuantifiedGame x y criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash -> QuantifiedGame x y
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> QuantifiedGame x y criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash -> QuantifiedGame x y
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: mkPositionHashQuantifiedGameTree :: (NFData criterionValue, Ix x, Bits positionHash, Fractional criterionValue, Fractional pieceSquareValue, Fractional rankValue, Fractional weightedMean, Integral x, Integral y, Real criterionValue, Real criterionWeight, Real pieceSquareValue, Real rankValue, Show x, Show y) => EvaluationOptions criterionWeight pieceSquareValue rankValue x y -> SearchOptions -> Zobrist x y positionHash -> MoveFrequency x y -> Game x y -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ 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: newtype PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: newtype PositionHashQuantifiedGameTree x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoves :: (Eq x, Eq y) => [QualifiedMove x y] -> Forest x y positionHash criterionValue weightedMean -> Maybe (Forest x y positionHash criterionValue weightedMean)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: promoteMatchingMoves :: (Eq x, Eq y) => [QualifiedMove x y] -> Forest x y positionHash -> Maybe (Forest x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: reduce :: IsMatch (NodeLabel x y positionHash criterionValue weightedMean) -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> Maybe (PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean)
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: reduce :: IsMatch (NodeLabel x y positionHash) -> PositionHashQuantifiedGameTree x y positionHash -> Maybe (PositionHashQuantifiedGameTree x y positionHash)
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: resign :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: resign :: PositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: sortNonCaptureMoves :: (Forest x y positionHash criterionValue weightedMean -> Forest x y positionHash criterionValue weightedMean) -> Forest x y positionHash criterionValue weightedMean -> Forest x y positionHash criterionValue weightedMean
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: sortNonCaptureMoves :: (Forest x y positionHash -> Forest x y positionHash) -> Forest x y positionHash -> Forest x y positionHash
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoves :: (Eq x, Eq y) => PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> [QualifiedMove x y] -> Maybe [NodeLabel x y positionHash criterionValue weightedMean]
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceMatchingMoves :: (Eq x, Eq y) => PositionHashQuantifiedGameTree x y positionHash -> [QualifiedMove x y] -> Maybe [NodeLabel x y positionHash]
- BishBosh.Evaluation.PositionHashQuantifiedGameTree: traceRoute :: (Turn x y -> IsMatch (NodeLabel x y positionHash criterionValue weightedMean)) -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> [Turn x y] -> Maybe [NodeLabel x y positionHash criterionValue weightedMean]
+ 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: type Forest x y positionHash criterionValue weightedMean = [BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean]
+ BishBosh.Evaluation.PositionHashQuantifiedGameTree: type Forest x y positionHash = [BarePositionHashQuantifiedGameTree x y positionHash]
- BishBosh.Evaluation.QuantifiedGame: compareFitness :: Ord weightedMean => QuantifiedGame x y criterionValue weightedMean -> QuantifiedGame x y criterionValue weightedMean -> Ordering
+ BishBosh.Evaluation.QuantifiedGame: compareFitness :: QuantifiedGame x y -> QuantifiedGame x y -> Ordering
- BishBosh.Evaluation.QuantifiedGame: data QuantifiedGame x y criterionValue weightedMean
+ BishBosh.Evaluation.QuantifiedGame: data QuantifiedGame x y
- BishBosh.Evaluation.QuantifiedGame: fromGame :: (NFData criterionValue, Enum x, Enum y, Fractional criterionValue, Fractional pieceSquareValue, Fractional rankValue, Fractional weightedMean, Ord x, Ord y, Real criterionValue, Real criterionWeight, Real pieceSquareValue, Real rankValue, Show x, Show y) => Maybe pieceSquareValue -> Game x y -> Reader criterionWeight pieceSquareValue rankValue x y (QuantifiedGame x y criterionValue weightedMean)
+ 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: getFitness :: QuantifiedGame x y criterionValue weightedMean -> weightedMean
+ BishBosh.Evaluation.QuantifiedGame: getFitness :: QuantifiedGame x y -> WeightedMean
- BishBosh.Evaluation.QuantifiedGame: getLastTurn :: QuantifiedGame x y criterionValue weightedMean -> Turn x y
+ BishBosh.Evaluation.QuantifiedGame: getLastTurn :: QuantifiedGame x y -> Turn x y
- BishBosh.Evaluation.QuantifiedGame: getLatestTurns :: NPlies -> QuantifiedGame x y criterionValue weightedMean -> [Turn x y]
+ BishBosh.Evaluation.QuantifiedGame: getLatestTurns :: NPlies -> QuantifiedGame x y -> [Turn x y]
- BishBosh.Evaluation.QuantifiedGame: negateFitness :: Num weightedMean => QuantifiedGame x y criterionValue weightedMean -> QuantifiedGame x y criterionValue weightedMean
+ BishBosh.Evaluation.QuantifiedGame: negateFitness :: QuantifiedGame x y -> QuantifiedGame x y
- BishBosh.Evaluation.QuantifiedGame: negateInterval :: Num weightedMean => OpenInterval x y criterionValue weightedMean -> OpenInterval x y criterionValue weightedMean
+ BishBosh.Evaluation.QuantifiedGame: negateInterval :: OpenInterval x y -> OpenInterval x y
- BishBosh.Evaluation.QuantifiedGame: type OpenInterval x y criterionValue weightedMean = (Maybe (QuantifiedGame x y criterionValue weightedMean), Maybe (QuantifiedGame x y criterionValue weightedMean))
+ BishBosh.Evaluation.QuantifiedGame: type OpenInterval x y = (Maybe (QuantifiedGame x y), Maybe (QuantifiedGame x y))
- BishBosh.Evaluation.QuantifiedGame: unboundedInterval :: OpenInterval x y criterionValue weightedMean
+ BishBosh.Evaluation.QuantifiedGame: unboundedInterval :: OpenInterval x y
- BishBosh.Input.CECPOptions: mkCECPOptions :: Mode -> Bool -> Mode -> Mode -> Maybe NominalDiffTime -> Mode -> Mode -> ProtocolVersion -> CECPFeatures -> CECPOptions
+ BishBosh.Input.CECPOptions: mkCECPOptions :: Mode -> Bool -> Mode -> Mode -> Maybe StopWatch -> Mode -> Mode -> ProtocolVersion -> CECPFeatures -> CECPOptions
- BishBosh.Input.CriteriaWeights: calculateWeightedMean :: (NFData criterionValue, Fractional weightedMean, Real criterionValue, Real criterionWeight) => CriteriaWeights criterionWeight -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> CriterionValue criterionValue -> WeightedMeanAndCriterionValues weightedMean criterionValue
+ BishBosh.Input.CriteriaWeights: calculateWeightedMean :: CriteriaWeights -> CriterionValue -> CriterionValue -> CriterionValue -> CriterionValue -> CriterionValue -> CriterionValue -> CriterionValue -> CriterionValue -> WeightedMeanAndCriterionValues
- BishBosh.Input.CriteriaWeights: data CriteriaWeights criterionWeight
+ BishBosh.Input.CriteriaWeights: data CriteriaWeights
- BishBosh.Input.CriteriaWeights: mkCriteriaWeights :: (Eq criterionWeight, Num criterionWeight) => CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriterionWeight criterionWeight -> CriteriaWeights criterionWeight
+ BishBosh.Input.CriteriaWeights: mkCriteriaWeights :: CriterionWeight -> CriterionWeight -> CriterionWeight -> CriterionWeight -> CriterionWeight -> CriterionWeight -> CriterionWeight -> CriterionWeight -> CriteriaWeights
- BishBosh.Input.CriteriaWeights: normalise :: (Fractional criterionWeight, Ord criterionWeight, Show criterionWeight) => Transformation criterionWeight
+ BishBosh.Input.CriteriaWeights: normalise :: Transformation
- BishBosh.Input.EvaluationOptions: data EvaluationOptions criterionWeight pieceSquareValue rankValue x y
+ BishBosh.Input.EvaluationOptions: data EvaluationOptions pieceSquareValue x y
- BishBosh.Input.EvaluationOptions: mkEvaluationOptions :: (Enum x, Enum y, Eq criterionWeight, Fractional pieceSquareValue, Num criterionWeight, Ord x, Ord y) => RankValues rankValue -> CriteriaWeights criterionWeight -> IncrementalEvaluation -> Maybe (PieceSquareTablePair x y pieceSquareValue) -> EvaluationOptions criterionWeight pieceSquareValue rankValue x y
+ 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: type Reader criterionWeight pieceSquareValue rankValue x y = Reader (EvaluationOptions criterionWeight pieceSquareValue rankValue x y)
+ BishBosh.Input.EvaluationOptions: type Reader pieceSquareValue x y = Reader (EvaluationOptions pieceSquareValue x y)
- BishBosh.Input.IOOptions: data IOOptions row column
+ BishBosh.Input.IOOptions: data IOOptions
- BishBosh.Input.IOOptions: deleteCECPFeature :: Feature -> Transformation row column
+ BishBosh.Input.IOOptions: deleteCECPFeature :: Feature -> Transformation
- BishBosh.Input.IOOptions: mkIOOptions :: Maybe FilePath -> Maybe MaximumPGNNames -> [PGNOptions] -> Maybe (FilePath, Bool) -> UIOptions row column -> IOOptions row column
+ BishBosh.Input.IOOptions: mkIOOptions :: Maybe FilePath -> Maybe NGames -> [PGNOptions] -> Maybe (FilePath, Bool) -> UIOptions -> IOOptions
- BishBosh.Input.IOOptions: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions row column -> Transformation row column
+ BishBosh.Input.IOOptions: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation
- BishBosh.Input.IOOptions: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation row column
+ BishBosh.Input.IOOptions: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation
- BishBosh.Input.IOOptions: setMaybePrintMoveTree :: Maybe Depth -> Transformation row column
+ BishBosh.Input.IOOptions: setMaybePrintMoveTree :: Maybe Depth -> Transformation
- BishBosh.Input.IOOptions: setVerbosity :: Verbosity -> Transformation row column
+ BishBosh.Input.IOOptions: setVerbosity :: Verbosity -> Transformation
- BishBosh.Input.IOOptions: updateCECPFeature :: Feature -> Transformation row column
+ BishBosh.Input.IOOptions: updateCECPFeature :: Feature -> Transformation
- BishBosh.Input.NativeUIOptions: data NativeUIOptions row column
+ BishBosh.Input.NativeUIOptions: data NativeUIOptions
- BishBosh.Input.NativeUIOptions: mkNativeUIOptions :: (Integral column, Integral row, Show column, Show row) => ScreenCoordinates row column -> ColourScheme -> NativeUIOptions row column
+ BishBosh.Input.NativeUIOptions: mkNativeUIOptions :: ScreenCoordinates -> ColourScheme -> NativeUIOptions
- BishBosh.Input.Options: data Options column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: data Options pieceSquareValue x y
- BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions criterionWeight pieceSquareValue rankValue x y -> SearchOptions -> IOOptions row column -> Options column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: mkOptions :: Maybe NPlies -> Maybe RandomSeed -> EvaluationOptions pieceSquareValue x y -> SearchOptions -> IOOptions -> Options pieceSquareValue x y
- BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions row column -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setMaybeOutputConfigFilePath :: Maybe FilePath -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setMaybePersistence :: Maybe (FilePath, Bool) -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setMaybePrintMoveTree :: Maybe Depth -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: setVerbosity :: Verbosity -> Transformation pieceSquareValue x y
- BishBosh.Input.Options: swapSearchDepth :: Transformation column criterionWeight pieceSquareValue rankValue row x y
+ BishBosh.Input.Options: swapSearchDepth :: Transformation pieceSquareValue x y
- BishBosh.Input.PGNOptions: mkPGNOptions :: FilePath -> Maybe Decompressor -> IsStrictlySequential -> ValidateMoves -> TextEncoding -> [Tag] -> NPlies -> Maybe Int -> PGNOptions
+ BishBosh.Input.PGNOptions: mkPGNOptions :: FilePath -> Maybe Decompressor -> IsStrictlySequential -> ValidateMoves -> TextEncoding -> [Tag] -> NPlies -> MaybeMaximumGames -> PGNOptions
- BishBosh.Input.SearchOptions: defaultSearchDepth :: SearchDepth
+ BishBosh.Input.SearchOptions: defaultSearchDepth :: NPlies
- BishBosh.Input.SearchOptions: getSearchDepth :: SearchOptions -> SearchDepth
+ BishBosh.Input.SearchOptions: getSearchDepth :: SearchOptions -> NPlies
- BishBosh.Input.SearchOptions: maybeMinimumTranspositionSearchDepth :: SearchOptions -> Maybe SearchDepth
+ BishBosh.Input.SearchOptions: maybeMinimumTranspositionSearchDepth :: SearchOptions -> Maybe NPlies
- BishBosh.Input.SearchOptions: minimumSearchDepth :: SearchDepth
+ BishBosh.Input.SearchOptions: minimumSearchDepth :: NPlies
- BishBosh.Input.SearchOptions: setSearchDepth :: SearchDepth -> Transformation
+ BishBosh.Input.SearchOptions: setSearchDepth :: NPlies -> Transformation
- BishBosh.Input.SearchOptions: type MaybeUseTranspositions = Maybe (NMoves, SearchDepth)
+ BishBosh.Input.SearchOptions: type MaybeUseTranspositions = Maybe (NMoves, NPlies)
- BishBosh.Input.UIOptions: data UIOptions row column
+ BishBosh.Input.UIOptions: data UIOptions
- BishBosh.Input.UIOptions: deleteCECPFeature :: Feature -> Transformation row column
+ BishBosh.Input.UIOptions: deleteCECPFeature :: Feature -> Transformation
- BishBosh.Input.UIOptions: isCECPManualMode :: UIOptions row column -> Bool
+ BishBosh.Input.UIOptions: isCECPManualMode :: UIOptions -> Bool
- BishBosh.Input.UIOptions: mkUIOptions :: MoveNotation -> Maybe Depth -> NDecimalDigits -> EitherNativeUIOrCECPOptions row column -> Verbosity -> UIOptions row column
+ BishBosh.Input.UIOptions: mkUIOptions :: MoveNotation -> Maybe Depth -> NDecimalDigits -> EitherNativeUIOrCECPOptions -> Verbosity -> UIOptions
- BishBosh.Input.UIOptions: type EitherNativeUIOrCECPOptions row column = Either (NativeUIOptions row column) CECPOptions
+ BishBosh.Input.UIOptions: type EitherNativeUIOrCECPOptions = Either NativeUIOptions CECPOptions
- BishBosh.Input.UIOptions: updateCECPFeature :: Feature -> Transformation row column
+ BishBosh.Input.UIOptions: updateCECPFeature :: Feature -> Transformation
- BishBosh.Model.GameTree: sortGameTree :: (Integral x, Integral y, Num rankValue, Ord rankValue) => Maybe CaptureMoveSortAlgorithm -> EvaluateRank rankValue -> MoveFrequency x y -> Transformation x y
+ BishBosh.Model.GameTree: sortGameTree :: (Integral x, Integral y) => Maybe CaptureMoveSortAlgorithm -> EvaluateRank -> MoveFrequency x y -> Transformation x y
- BishBosh.Model.MoveFrequency: countEntries :: MoveFrequency move -> NMoves
+ BishBosh.Model.MoveFrequency: countEntries :: MoveFrequency move -> NPlies
- BishBosh.Model.PositionHashTree: countDistinctPositions :: Ord positionHash => Depth -> PositionHashTree positionHash -> NGames
+ BishBosh.Model.PositionHashTree: countDistinctPositions :: Ord positionHash => Depth -> PositionHashTree positionHash -> NPositions
- BishBosh.Search.AlphaBeta: extractSelectedTurns :: NPlies -> Result x y positionHash criterionValue weightedMean -> (DynamicMoveData x y positionHash, [Turn x y], NPlies)
+ BishBosh.Search.AlphaBeta: extractSelectedTurns :: NPlies -> Result x y positionHash -> (DynamicMoveData x y positionHash, [Turn x y], NPositions)
- BishBosh.Search.AlphaBeta: negaMax :: (Enum x, Enum y, Eq criterionValue, Ord positionHash, Ord x, Ord y, Real weightedMean, Show x, Show y) => SearchDepth -> SearchState x y positionHash criterionValue weightedMean -> Reader (Result x y positionHash criterionValue weightedMean)
+ 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.Search: data Result x y positionHash criterionValue weightedMean
+ BishBosh.Search.Search: data Result x y positionHash
- BishBosh.Search.Search: search :: (Enum x, Enum y, Eq criterionValue, Ord positionHash, Ord x, Ord y, Real weightedMean, Show x, Show y) => SearchDepth -> SearchState x y positionHash criterionValue weightedMean -> Reader (Result x y positionHash criterionValue weightedMean)
+ 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.SearchState: data SearchState x y positionHash criterionValue weightedMean
+ BishBosh.Search.SearchState: data SearchState x y positionHash
- BishBosh.Search.SearchState: initialise :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> SearchState x y positionHash criterionValue weightedMean
+ BishBosh.Search.SearchState: initialise :: PositionHashQuantifiedGameTree x y positionHash -> SearchState x y positionHash
- BishBosh.Search.SearchState: mkSearchState :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> DynamicMoveData x y positionHash -> SearchState x y positionHash criterionValue weightedMean
+ BishBosh.Search.SearchState: mkSearchState :: PositionHashQuantifiedGameTree x y positionHash -> DynamicMoveData x y positionHash -> SearchState x y positionHash
- BishBosh.Search.TranspositionValue: isBetter :: Ord weightedMean => FindFitness qualifiedMove weightedMean -> TranspositionValue qualifiedMove -> TranspositionValue qualifiedMove -> Bool
+ BishBosh.Search.TranspositionValue: isBetter :: FindFitness qualifiedMove -> TranspositionValue qualifiedMove -> TranspositionValue qualifiedMove -> Bool
- BishBosh.Search.TranspositionValue: type FindFitness qualifiedMove weightedMean = TranspositionValue qualifiedMove -> weightedMean
+ BishBosh.Search.TranspositionValue: type FindFitness qualifiedMove = TranspositionValue qualifiedMove -> WeightedMean
- BishBosh.Search.Transpositions: insert :: (Ord positionHash, Ord weightedMean) => FindFitness qualifiedMove weightedMean -> positionHash -> TranspositionValue qualifiedMove -> Transformation qualifiedMove positionHash
+ BishBosh.Search.Transpositions: insert :: Ord positionHash => FindFitness qualifiedMove -> positionHash -> TranspositionValue qualifiedMove -> Transformation qualifiedMove positionHash
- BishBosh.State.InstancesByPosition: anyInstancesByPosition :: (NBoards -> Bool) -> InstancesByPosition position -> Bool
+ BishBosh.State.InstancesByPosition: anyInstancesByPosition :: (NPositions -> Bool) -> InstancesByPosition position -> Bool
- BishBosh.State.InstancesByPosition: countPositionRepetitions :: InstancesByPosition position -> NBoards
+ BishBosh.State.InstancesByPosition: countPositionRepetitions :: InstancesByPosition position -> NPositions
- BishBosh.State.InstancesByPosition: findMaximumInstances :: InstancesByPosition position -> NBoards
+ BishBosh.State.InstancesByPosition: findMaximumInstances :: InstancesByPosition position -> NPositions
- BishBosh.State.InstancesByPosition: getNDistinctPositions :: InstancesByPosition position -> NBoards
+ BishBosh.State.InstancesByPosition: getNDistinctPositions :: InstancesByPosition position -> NPositions
- BishBosh.State.InstancesByPosition: mkInstancesByPosition :: NBoardsByPosition position -> InstancesByPosition position
+ BishBosh.State.InstancesByPosition: mkInstancesByPosition :: Map position NPositions -> InstancesByPosition position
- BishBosh.State.MaybePieceByCoordinates: show2D :: (Enum x, Enum y, Integral column, Ord x, Ord y) => column -> ColourScheme -> (Int, Int) -> MaybePieceByCoordinates x y -> String
+ BishBosh.State.MaybePieceByCoordinates: show2D :: (Enum x, Enum y, Ord x, Ord y) => Column -> ColourScheme -> (Int, Int) -> MaybePieceByCoordinates x y -> String
- BishBosh.UI.SetObject: SearchDepth :: SearchDepth -> SetObject
+ BishBosh.UI.SetObject: SearchDepth :: NPlies -> SetObject
- BishBosh.UI.SetObject: mkSearchDepth :: SearchDepth -> SetObject
+ BishBosh.UI.SetObject: mkSearchDepth :: NPlies -> SetObject
Files
- README.markdown +1/−0
- bishbosh.cabal +43/−25
- bishbosh.spec +1/−1
- changelog.markdown +92/−56
- config/bishbosh.dtd +2/−3
- config/bishbosh.rng +1/−2
- config/rankValues_Carlson.xml +6/−6
- config/rankValues_Kaufman.xml +6/−6
- config/rankValues_Medvedev.xml +6/−6
- copyright +1/−0
- makefile +36/−28
- man/man1/duel.1 +22/−10
- src-exe/BishBosh/Concurrent/Pondering.hs +1/−0
- src-exe/BishBosh/Play.hs +12/−34
- src-exe/BishBosh/State/ApplicationTerminationReason.hs +2/−2
- src-exe/BishBosh/State/PlayState.hs +42/−67
- src-exe/BishBosh/UI/CECP.hs +100/−147
- src-exe/BishBosh/UI/Raw.hs +68/−112
- src-exe/Duel.hs +19/−3
- src-exe/Duel/Data/Options.hs +48/−31
- src-exe/Duel/IO/Logger.hs +1/−0
- src-exe/Duel/Process/Handles.hs +95/−0
- src-exe/Duel/Process/Intermediary.hs +135/−76
- src-exe/Main.hs +29/−35
- src-lib/BishBosh/Attribute/CriterionValue.hs +0/−109
- src-lib/BishBosh/Attribute/CriterionWeight.hs +0/−90
- src-lib/BishBosh/Attribute/Direction.hs +4/−7
- src-lib/BishBosh/Attribute/LogicalColour.hs +3/−2
- src-lib/BishBosh/Attribute/LogicalColourOfSquare.hs +1/−0
- src-lib/BishBosh/Attribute/MoveType.hs +1/−1
- src-lib/BishBosh/Attribute/Rank.hs +19/−19
- src-lib/BishBosh/Attribute/RankValues.hs +0/−142
- src-lib/BishBosh/Attribute/WeightedMeanAndCriterionValues.hs +0/−83
- src-lib/BishBosh/Cartesian/Abscissa.hs +2/−2
- src-lib/BishBosh/Cartesian/Coordinates.hs +15/−15
- src-lib/BishBosh/Cartesian/Ordinate.hs +2/−2
- src-lib/BishBosh/Cartesian/Vector.hs +3/−3
- src-lib/BishBosh/Component/CastlingMove.hs +3/−3
- src-lib/BishBosh/Component/Move.hs +9/−16
- src-lib/BishBosh/Component/Piece.hs +9/−12
- src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs +30/−27
- src-lib/BishBosh/Component/QualifiedMove.hs +3/−3
- src-lib/BishBosh/Component/Turn.hs +5/−7
- src-lib/BishBosh/ContextualNotation/PGN.hs +24/−22
- src-lib/BishBosh/ContextualNotation/PGNDatabase.hs +19/−16
- src-lib/BishBosh/ContextualNotation/PositionHashQualifiedMoveTree.hs +42/−43
- src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs +34/−34
- src-lib/BishBosh/ContextualNotation/StandardAlgebraic.hs +10/−10
- src-lib/BishBosh/Data/Either.hs +2/−1
- src-lib/BishBosh/Data/Exception.hs +3/−2
- src-lib/BishBosh/Data/Float.hs +0/−35
- src-lib/BishBosh/Data/Integral.hs +1/−26
- src-lib/BishBosh/Data/Num.hs +1/−0
- src-lib/BishBosh/Data/Time.hs +0/−41
- src-lib/BishBosh/Evaluation/Fitness.hs +77/−116
- src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs +57/−72
- src-lib/BishBosh/Evaluation/QuantifiedGame.hs +37/−47
- src-lib/BishBosh/Input/CECPFeatures.hs +10/−13
- src-lib/BishBosh/Input/CECPOptions.hs +38/−27
- src-lib/BishBosh/Input/CategorisedCommandLineOptions.hs +1/−0
- src-lib/BishBosh/Input/CriteriaWeights.hs +78/−114
- src-lib/BishBosh/Input/EvaluationOptions.hs +32/−42
- src-lib/BishBosh/Input/IOOptions.hs +20/−33
- src-lib/BishBosh/Input/NativeUIOptions.hs +17/−30
- src-lib/BishBosh/Input/Options.hs +26/−56
- src-lib/BishBosh/Input/PGNOptions.hs +6/−6
- src-lib/BishBosh/Input/PieceSquareTable.hs +3/−2
- src-lib/BishBosh/Input/RankValues.hs +133/−0
- src-lib/BishBosh/Input/SearchOptions.hs +28/−25
- src-lib/BishBosh/Input/UIOptions.hs +30/−46
- src-lib/BishBosh/Metric/CriterionValue.hs +79/−0
- src-lib/BishBosh/Metric/CriterionWeight.hs +96/−0
- src-lib/BishBosh/Metric/RankValue.hs +97/−0
- src-lib/BishBosh/Metric/WeightedMeanAndCriterionValues.hs +121/−0
- src-lib/BishBosh/Model/DrawReason.hs +0/−100
- src-lib/BishBosh/Model/Game.hs +68/−72
- src-lib/BishBosh/Model/GameTerminationReason.hs +0/−124
- src-lib/BishBosh/Model/GameTree.hs +34/−46
- src-lib/BishBosh/Model/MoveFrequency.hs +25/−36
- src-lib/BishBosh/Model/PositionHashTree.hs +8/−7
- src-lib/BishBosh/Model/Result.hs +0/−98
- src-lib/BishBosh/Notation/MoveNotation.hs +3/−3
- src-lib/BishBosh/Notation/PureCoordinate.hs +7/−7
- src-lib/BishBosh/Property/Opposable.hs +1/−0
- src-lib/BishBosh/Property/SelfValidating.hs +61/−0
- src-lib/BishBosh/Property/ShowFloat.hs +7/−7
- src-lib/BishBosh/Property/Switchable.hs +53/−0
- src-lib/BishBosh/Rule/DrawReason.hs +102/−0
- src-lib/BishBosh/Rule/GameTerminationReason.hs +124/−0
- src-lib/BishBosh/Rule/Result.hs +98/−0
- src-lib/BishBosh/Search/AlphaBeta.hs +41/−44
- src-lib/BishBosh/Search/DynamicMoveData.hs +3/−2
- src-lib/BishBosh/Search/EphemeralData.hs +5/−4
- src-lib/BishBosh/Search/KillerMoves.hs +7/−6
- src-lib/BishBosh/Search/Search.hs +34/−35
- src-lib/BishBosh/Search/SearchState.hs +8/−18
- src-lib/BishBosh/Search/TranspositionValue.hs +10/−10
- src-lib/BishBosh/Search/Transpositions.hs +2/−2
- src-lib/BishBosh/State/Board.hs +45/−51
- src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs +4/−4
- src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs +16/−13
- src-lib/BishBosh/State/EnPassantAbscissa.hs +2/−2
- src-lib/BishBosh/State/InstancesByPosition.hs +25/−31
- src-lib/BishBosh/State/MaybePieceByCoordinates.hs +32/−27
- src-lib/BishBosh/State/Position.hs +3/−3
- src-lib/BishBosh/State/TurnsByLogicalColour.hs +10/−8
- src-lib/BishBosh/StateProperty/Censor.hs +8/−15
- src-lib/BishBosh/Text/Case.hs +1/−0
- src-lib/BishBosh/Text/ShowPrefix.hs +1/−0
- src-lib/BishBosh/Time/GameClock.hs +88/−0
- src-lib/BishBosh/Time/StopWatch.hs +82/−0
- src-lib/BishBosh/Type/Count.hs +155/−0
- src-lib/BishBosh/Type/Crypto.hs +45/−0
- src-lib/BishBosh/Type/Length.hs +96/−0
- src-lib/BishBosh/Type/Mass.hs +72/−0
- src-lib/BishBosh/Types.hs +0/−99
- src-lib/BishBosh/UI/Command.hs +6/−5
- src-lib/BishBosh/UI/PrintObject.hs +2/−4
- src-lib/BishBosh/UI/ReportObject.hs +9/−11
- src-lib/BishBosh/UI/SetObject.hs +4/−3
- src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs +3/−3
- src-test/BishBosh/Test/HUnit/Cartesian/Vector.hs +2/−2
- src-test/BishBosh/Test/HUnit/Component/CastlingMove.hs +2/−2
- src-test/BishBosh/Test/HUnit/Component/Move.hs +2/−2
- src-test/BishBosh/Test/HUnit/Component/Zobrist.hs +3/−2
- src-test/BishBosh/Test/HUnit/ContextualNotation/PGN.hs +16/−16
- src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs +3/−2
- src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs +8/−7
- src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs +32/−44
- src-test/BishBosh/Test/HUnit/Input/Options.hs +5/−7
- src-test/BishBosh/Test/HUnit/Model/Game.hs +12/−12
- src-test/BishBosh/Test/HUnit/Model/GameTree.hs +11/−9
- src-test/BishBosh/Test/HUnit/Model/PositionHashTree.hs +4/−3
- src-test/BishBosh/Test/HUnit/Search/Search.hs +10/−14
- src-test/BishBosh/Test/HUnit/State/Board.hs +2/−2
- src-test/BishBosh/Test/HUnit/Time/GameClock.hs +83/−0
- src-test/BishBosh/Test/HUnit/Time/StopWatch.hs +63/−0
- src-test/BishBosh/Test/QuickCheck/Attribute/CriterionWeight.hs +0/−37
- src-test/BishBosh/Test/QuickCheck/Attribute/MoveType.hs +1/−0
- src-test/BishBosh/Test/QuickCheck/Attribute/RankValues.hs +0/−49
- src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs +6/−5
- src-test/BishBosh/Test/QuickCheck/Component/Move.hs +5/−4
- src-test/BishBosh/Test/QuickCheck/Component/QualifiedMove.hs +5/−4
- src-test/BishBosh/Test/QuickCheck/Component/Turn.hs +20/−20
- src-test/BishBosh/Test/QuickCheck/Component/Zobrist.hs +4/−5
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGN.hs +15/−12
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGNComment.hs +8/−5
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs +4/−4
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/QualifiedMoveForest.hs +3/−3
- src-test/BishBosh/Test/QuickCheck/ContextualNotation/StandardAlgebraic.hs +13/−10
- src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs +7/−4
- src-test/BishBosh/Test/QuickCheck/Input/CECPFeatures.hs +3/−5
- src-test/BishBosh/Test/QuickCheck/Input/CECPOptions.hs +2/−1
- src-test/BishBosh/Test/QuickCheck/Input/CriteriaWeights.hs +13/−15
- src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs +13/−19
- src-test/BishBosh/Test/QuickCheck/Input/IOOptions.hs +1/−6
- src-test/BishBosh/Test/QuickCheck/Input/NativeUIOptions.hs +5/−8
- src-test/BishBosh/Test/QuickCheck/Input/Options.hs +12/−32
- src-test/BishBosh/Test/QuickCheck/Input/PGNOptions.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs +4/−3
- src-test/BishBosh/Test/QuickCheck/Input/RankValues.hs +37/−0
- src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs +4/−4
- src-test/BishBosh/Test/QuickCheck/Input/UIOptions.hs +3/−7
- src-test/BishBosh/Test/QuickCheck/Input/Verbosity.hs +1/−0
- src-test/BishBosh/Test/QuickCheck/Metric/CriterionWeight.hs +33/−0
- src-test/BishBosh/Test/QuickCheck/Metric/RankValue.hs +56/−0
- src-test/BishBosh/Test/QuickCheck/Model/DrawReason.hs +0/−34
- src-test/BishBosh/Test/QuickCheck/Model/Game.hs +13/−12
- src-test/BishBosh/Test/QuickCheck/Model/GameTerminationReason.hs +0/−48
- src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs +3/−2
- src-test/BishBosh/Test/QuickCheck/Model/MoveFrequency.hs +3/−7
- src-test/BishBosh/Test/QuickCheck/Model/Result.hs +0/−63
- src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs +3/−2
- src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs +1/−0
- src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs +3/−2
- src-test/BishBosh/Test/QuickCheck/Notation/Smith.hs +3/−2
- src-test/BishBosh/Test/QuickCheck/Rule/DrawReason.hs +34/−0
- src-test/BishBosh/Test/QuickCheck/Rule/GameTerminationReason.hs +48/−0
- src-test/BishBosh/Test/QuickCheck/Rule/Result.hs +63/−0
- src-test/BishBosh/Test/QuickCheck/Search/KillerMoves.hs +12/−15
- src-test/BishBosh/Test/QuickCheck/Search/Search.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs +8/−19
- src-test/BishBosh/Test/QuickCheck/State/Board.hs +3/−3
- src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/State/InstancesByPosition.hs +1/−1
- src-test/BishBosh/Test/QuickCheck/State/TurnsByLogicalColour.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/Time/StopWatch.hs +33/−0
- src-test/BishBosh/Test/QuickCheck/UI/Command.hs +2/−2
- src-test/BishBosh/Test/QuickCheck/UI/PrintObject.hs +1/−0
- src-test/BishBosh/Test/QuickCheck/UI/ReportObject.hs +1/−0
- src-test/BishBosh/Test/QuickCheck/UI/SetObject.hs +1/−1
- src-test/HUnit.hs +4/−0
- src-test/QuickCheck.hs +7/−5
README.markdown view
@@ -39,3 +39,4 @@ ## Author This application is written & maintained by Dr. Alistair Ward.+
bishbosh.cabal view
@@ -1,4 +1,4 @@-cabal-version: 2.0+cabal-version: 2.4 -- This file is part of BishBosh. --@@ -16,10 +16,9 @@ -- along with BishBosh. If not, see <http://www.gnu.org/licenses/>. Name: bishbosh-Version: 0.1.0.0+Version: 0.1.1.0 Copyright: (C) 2018 Dr. Alistair Ward--- License: GPL-3.0-or-later-License: GPL-3+License: GPL-3.0-or-later License-file: LICENSE Author: Dr. Alistair Ward Stability: stable@@ -86,6 +85,12 @@ Manual: True Default: False +-- Whether, to wrap common types in 'newtype' for increased type-safety. CAVEAT: there's a ~10% performance-penalty.+flag newtypewrappers+ Description: Wrap common types in newtype for increased type-safety.+ 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.@@ -112,16 +117,12 @@ Exposed-modules: BishBosh.Attribute.CaptureMoveSortAlgorithm BishBosh.Attribute.ColourScheme- BishBosh.Attribute.CriterionValue- BishBosh.Attribute.CriterionWeight BishBosh.Attribute.Direction BishBosh.Attribute.LogicalColour BishBosh.Attribute.LogicalColourOfSquare BishBosh.Attribute.MoveType BishBosh.Attribute.PhysicalColour BishBosh.Attribute.Rank- BishBosh.Attribute.RankValues- BishBosh.Attribute.WeightedMeanAndCriterionValues BishBosh.Cartesian.Abscissa BishBosh.Cartesian.Coordinates BishBosh.Cartesian.Ordinate@@ -144,14 +145,12 @@ BishBosh.Data.Either BishBosh.Data.Enum BishBosh.Data.Exception- BishBosh.Data.Float BishBosh.Data.Foldable BishBosh.Data.Integral BishBosh.Data.List BishBosh.Data.Num BishBosh.Data.Ratio BishBosh.Data.RoseTree- BishBosh.Data.Time BishBosh.Evaluation.Fitness BishBosh.Evaluation.PositionHashQuantifiedGameTree BishBosh.Evaluation.QuantifiedGame@@ -166,17 +165,19 @@ BishBosh.Input.Options BishBosh.Input.PGNOptions BishBosh.Input.PieceSquareTable+ BishBosh.Input.RankValues BishBosh.Input.SearchOptions BishBosh.Input.StandardOpeningOptions BishBosh.Input.UIOptions BishBosh.Input.Verbosity- BishBosh.Model.DrawReason+ BishBosh.Metric.CriterionValue+ BishBosh.Metric.CriterionWeight+ BishBosh.Metric.RankValue+ BishBosh.Metric.WeightedMeanAndCriterionValues BishBosh.Model.Game- BishBosh.Model.GameTerminationReason BishBosh.Model.GameTree BishBosh.Model.MoveFrequency BishBosh.Model.PositionHashTree- BishBosh.Model.Result BishBosh.Notation.ICCFNumeric BishBosh.Notation.MoveNotation BishBosh.Notation.PureCoordinate@@ -191,7 +192,12 @@ BishBosh.Property.Orientated BishBosh.Property.Reflectable BishBosh.Property.Rotatable+ BishBosh.Property.SelfValidating BishBosh.Property.ShowFloat+ BishBosh.Property.Switchable+ BishBosh.Rule.DrawReason+ BishBosh.Rule.GameTerminationReason+ BishBosh.Rule.Result BishBosh.Search.AlphaBeta BishBosh.Search.DynamicMoveData BishBosh.Search.EphemeralData@@ -216,7 +222,12 @@ BishBosh.Text.Encoding BishBosh.Text.ShowList BishBosh.Text.ShowPrefix- BishBosh.Types+ BishBosh.Time.GameClock+ BishBosh.Time.StopWatch+ BishBosh.Type.Count+ BishBosh.Type.Crypto+ BishBosh.Type.Length+ BishBosh.Type.Mass BishBosh.UI.Command BishBosh.UI.PrintObject BishBosh.UI.ReportObject@@ -255,7 +266,7 @@ if flag(polyparse) Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=1+ CPP-Options: -DUSE_POLYPARSE=2 Exposed-modules: BishBosh.Text.Poly else Build-depends: parsec@@ -263,6 +274,9 @@ if flag(narrownumbers) CPP-Options: -DUSE_NARROW_NUMBERS + if flag(newtypewrappers)+ CPP-Options: -DUSE_NEWTYPE_WRAPPERS+ if flag(threaded) Build-depends: parallel >= 3.0 CPP-Options: -DUSE_PARALLEL@@ -304,7 +318,6 @@ hxt, mtl, random,- time, toolshed >= 0.18 if impl(ghc >= 7.0)@@ -356,6 +369,7 @@ Other-modules: Duel.Data.Options Duel.IO.Logger+ Duel.Process.Handles Duel.Process.Intermediary Paths_bishbosh @@ -365,6 +379,7 @@ containers, data-default, filepath,+ hxt, process >= 1.6.4 CPP-Options: -DMOVE_NOTATION='S'@@ -406,6 +421,8 @@ BishBosh.Test.HUnit.Search.Search BishBosh.Test.HUnit.State.Board BishBosh.Test.HUnit.Text.AutoComplete+ BishBosh.Test.HUnit.Time.GameClock+ BishBosh.Test.HUnit.Time.StopWatch Paths_bishbosh Build-depends:@@ -418,16 +435,15 @@ HUnit, hxt, mtl,+ random, toolshed >= 0.18 --- CPP-Options: -DUSE_SEARCH- if impl(ghc >= 8.0) GHC-options: -Wredundant-constraints if flag(polyparse) Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=1+ CPP-Options: -DUSE_POLYPARSE=2 else Build-depends: parsec @@ -441,12 +457,10 @@ Other-modules: BishBosh.Test.QuickCheck.Attribute.CaptureMoveSortAlgorithm- BishBosh.Test.QuickCheck.Attribute.CriterionWeight BishBosh.Test.QuickCheck.Attribute.Direction BishBosh.Test.QuickCheck.Attribute.LogicalColour BishBosh.Test.QuickCheck.Attribute.MoveType BishBosh.Test.QuickCheck.Attribute.Rank- BishBosh.Test.QuickCheck.Attribute.RankValues BishBosh.Test.QuickCheck.Cartesian.Coordinates BishBosh.Test.QuickCheck.Cartesian.Vector BishBosh.Test.QuickCheck.Component.Move@@ -471,20 +485,23 @@ BishBosh.Test.QuickCheck.Input.Options BishBosh.Test.QuickCheck.Input.PGNOptions BishBosh.Test.QuickCheck.Input.PieceSquareTable+ BishBosh.Test.QuickCheck.Input.RankValues BishBosh.Test.QuickCheck.Input.SearchOptions BishBosh.Test.QuickCheck.Input.StandardOpeningOptions BishBosh.Test.QuickCheck.Input.UIOptions BishBosh.Test.QuickCheck.Input.Verbosity- BishBosh.Test.QuickCheck.Model.DrawReason+ BishBosh.Test.QuickCheck.Metric.CriterionWeight+ BishBosh.Test.QuickCheck.Metric.RankValue BishBosh.Test.QuickCheck.Model.Game- BishBosh.Test.QuickCheck.Model.GameTerminationReason BishBosh.Test.QuickCheck.Model.GameTree BishBosh.Test.QuickCheck.Model.MoveFrequency- BishBosh.Test.QuickCheck.Model.Result BishBosh.Test.QuickCheck.Notation.ICCFNumeric BishBosh.Test.QuickCheck.Notation.MoveNotation BishBosh.Test.QuickCheck.Notation.PureCoordinate BishBosh.Test.QuickCheck.Notation.Smith+ BishBosh.Test.QuickCheck.Rule.DrawReason+ BishBosh.Test.QuickCheck.Rule.GameTerminationReason+ BishBosh.Test.QuickCheck.Rule.Result BishBosh.Test.QuickCheck.Search.KillerMoves BishBosh.Test.QuickCheck.Search.Search BishBosh.Test.QuickCheck.Search.SearchState@@ -495,6 +512,7 @@ BishBosh.Test.QuickCheck.StateProperty.Censor BishBosh.Test.QuickCheck.State.TurnsByLogicalColour BishBosh.Test.QuickCheck.Text.Encoding+ BishBosh.Test.QuickCheck.Time.StopWatch BishBosh.Test.QuickCheck.UI.Command BishBosh.Test.QuickCheck.UI.PrintObject BishBosh.Test.QuickCheck.UI.ReportObject@@ -519,7 +537,7 @@ if flag(polyparse) Build-depends: polyparse- CPP-Options: -DUSE_POLYPARSE=1+ CPP-Options: -DUSE_POLYPARSE=2 else Build-depends: parsec
bishbosh.spec view
@@ -24,7 +24,7 @@ Summary: BishBosh is a chess-game. Name: bishbosh-Version: 0.1.0.0+Version: 0.1.1.0 Release: 1 License: GPLv3 # From '/usr/share/doc/packages/rpm/GROUPS'.
changelog.markdown view
@@ -4,79 +4,115 @@ * First version of the package. ## 0.0.0.2-Minor changes required to build on Windows.+* Minor changes required to build on Windows. ## 0.0.0.3-Added **Paths_bishbosh** to **Other-modules** section of cabal file.+* Added **Paths_bishbosh** to **Other-modules** section of cabal file. ## 0.0.0.4-Changed references to author's domain-name.+* Changed references to author's domain-name. ## 0.0.0.5-Added ability to specify the text-encoding used in a PGN-database file.-Updated list of test-compilers.+* Added ability to specify the text-encoding used in a PGN-database file.+* Updated list of test-compilers. ## 0.0.0.6-Fixed failure to persist game-state after requesting that the game be restarted.-Fixed parsing of **TextEncoding** in **PGNOptions**.-Replaced module **Distribution.Verbosity** with **BishBosh.Input.Verbosity**.+* Fixed failure to persist game-state after requesting that the game be restarted.+* Fixed parsing of **TextEncoding** in **PGNOptions**.+* Replaced module **Distribution.Verbosity** with **BishBosh.Input.Verbosity**. ## 0.0.0.7-Rewrote function **BishBosh.Data.RoseTree.countTerminalNodes** in accordance with the suggestions of David Feuer.-Amended function **BishBosh.State.EnPassantAbscissa.mkMaybeEnPassantAbscissa** to guard against exposing one's King after En-passant capture.+* Rewrote function **BishBosh.Data.RoseTree.countTerminalNodes** in accordance with the suggestions of David Feuer.+* Amended function **BishBosh.State.EnPassantAbscissa.mkMaybeEnPassantAbscissa** to guard against exposing one's King after En-passant capture. ## 0.0.0.8-Corrected the parsing of FEN when an Enpassant-destination defined on file **b** was erroneously interpreted as a bishop in the previous **CastleableRooks** field.-Added parent class **BishBosh.Property.ExtendedPositionDescription.EPD** for **Property.ForsythEdwards.FEN**, for which the latter typically has a default implementation of both methods.+* Corrected the parsing of FEN when an Enpassant-destination defined on file **b** was erroneously interpreted as a bishop in the previous **CastleableRooks** field.+* Added parent class **BishBosh.Property.ExtendedPositionDescription.EPD** for **Property.ForsythEdwards.FEN**, for which the latter typically has a default implementation of both methods. ## 0.1.0.0 ### Bug-fixes:- * Upgraded the transposition-table in module **Search.DynamicMoveData**, from merely recording moves (which doesn't include the rank to which a Pawn is promoted), to recording qualified-moves.- * In function **Search.AlphaBeta.negaMax.descend.selectMax**, amended bound function **isFitter** to prefer shorter move-sequences where fitness is equal, & corrected the scenario in which all nodes were skipped because they were repetitious, but without ever defining alpha.+* Upgraded the transposition-table in module **Search.DynamicMoveData**, from merely recording moves (which doesn't include the rank to which a Pawn is promoted), to recording qualified-moves.+* In function **Search.AlphaBeta.negaMax.descend.selectMax**, amended bound function **isFitter** to prefer shorter move-sequences where fitness is equal, & corrected the scenario in which all nodes were skipped because they were repetitious, but without ever defining alpha.+ ### Features:- * Added the configurable runtime ability to asynchronously decompress PGN-databases, & to set a maximum number of games to read.- * Added a configuration-option to normalise the values of specified piece-square tables into the closed unit-interval.- * Modularised the packaged config-files, by defining XML **External Entities** in the DTD.- * Added suggestions on failure to parse a user-command, & created a module **Text.AutoComplete** to contain common code.- * Added runtime commands:- ------------------------------------------ Command | Purpose- --------------------------------| -------- **availableMoves** | to report all available moves from the current position.- **maxPositionInstances** | to reveal the maximum number of instances any available position has been visited.- **reversiblePlyCount** | to count the number of consecutive reversible plies that have been made.- ------------------------------------------ * Added **makefile** to facilitate common tasks.- * Removed the configuration-option **preferMovesTowardsCentre** & its implementation in function **Cartesian.Coordinates.radiusSquared**, because of it's conceptually wobbly foundations.+* Added the configurable runtime ability to asynchronously decompress PGN-databases, & to set a maximum number of games to read.+* Added a configuration-option to normalise the values of specified piece-square tables into the closed unit-interval.+* Modularised the packaged config-files, by defining XML **External Entities** in the DTD.+* Added suggestions on failure to parse a user-command, & created a module **Text.AutoComplete** to contain common code.+* Added **makefile** to facilitate common tasks.+* Removed the configuration-option **preferMovesTowardsCentre** & its implementation in function **Cartesian.Coordinates.radiusSquared**, because of it's conceptually wobbly foundations.++### New Runtime Cmmands:+-----------------------------------------+Command | Purpose+--------------------------------| -------+**availableMoves** | to report all available moves from the current position.+**maxPositionInstances** | to reveal the maximum number of instances any available position has been visited.+**reversiblePlyCount** | to count the number of consecutive reversible plies that have been made.+-----------------------------------------+ ### Command-line Options:- * Added a new module **Input.CategorisedCommandLineOptions** to improved the partitioning of command-line options into functional categories.- * Added a command-line option **--formatPieceSquareTableForGNUPlot** to print the piece-square tables in a format suitable for **GNUPlot**.+* Added a new module **Input.CategorisedCommandLineOptions** to improved the partitioning of command-line options into functional categories.+* Added a command-line option **--formatPieceSquareTableForGNUPlot** to print the piece-square tables in a format suitable for **GNUPlot**.+ ### Performance:- * Included a compilation-flag **unboxedarrays**, to request the use of unboxed arrays where (infrequently) possible.- * Changed data-type **Component.PieceSquareByCoordinatesByRank.EitherPieceSquareValueByNPiecesByCoordinates**, bringing type **Cartesian.Coordinates.ByCoordinates** inside **Either**, leading to significant space/time gains.- * Constructed each large constant data-structure in parallel. Bracketed all data-parallel operations with CPP-conditionals controlled by the compilation-flag **threaded**.- * Parallelised function **Attribute.CriterionValue.calculateWeightedMean**.-### Architectural:- * Added new modules:- ------------------------------------------ Module | Purpose- --------------------------------| -------- **Component.CastlingMove** | Forked from module **Component.Move**- **Data.Enum** | Currently single-function.- **Data.Foldable** | Currently single-function.- **Property.FixedMembership** | Defines a class to which sum-types can conform.- **StateProperty.Censor** | Relocated from directory **State/**- **StateProperty.Mutator** | defines a class to express the dual implementations within **State.Board**.- **StateProperty.Seeker** | defines a class to express the dual implementations within **State.Board**.- **Text.Case** | Forked from **Text.ShowList** to contain case-related operations.- **Text.Prefix** | Forked from **Text.ShowList** to define the constant prefixes of log-messages.- -----------------------------------------+* Included a compilation-flag **unboxedarrays**, to request the use of unboxed arrays where (infrequently) possible.+* Changed data-type **Component.PieceSquareByCoordinatesByRank.EitherPieceSquareValueByNPiecesByCoordinates**, bringing type **Cartesian.Coordinates.ByCoordinates** inside **Either**, leading to significant space/time gains.+* Constructed each large constant data-structure in parallel. Bracketed all data-parallel operations with CPP-conditionals controlled by the compilation-flag **threaded**.+* Parallelised function **Attribute.CriterionValue.calculateWeightedMean**.++### New Modules:+-----------------------------------------+Module | Purpose+--------------------------------| -------+**Component.CastlingMove** | Forked from module **Component.Move**.+**Data.Enum** | Currently single-function.+**Data.Foldable** | Currently single-function.+**Property.FixedMembership** | Defines a class to which sum-types can conform.+**StateProperty.Censor** | Relocated from directory **State/**.+**StateProperty.Mutator** | defines a class to express the dual implementations within **State.Board**.+**StateProperty.Seeker** | defines a class to express the dual implementations within **State.Board**.+**Text.Case** | Forked from **Text.ShowList** to contain case-related operations.+**Text.Prefix** | Forked from **Text.ShowList** to define the constant prefixes of log-messages.+-----------------------------------------+ ### Testing:- * Split **src-test/Main.hs** into **src-test/HUnit.hs** & **src-test/QuickCheck.hs**, each referenced independently from the cabal file.- * Added an executable **duel** (to coordinate a battle between two independently configured instances of **bishbosh**) & a corresponding section-1 man-page.- * Validated the list of ranks supplied to construct either **Attribute.RankValues.RankValues** or **Input.PieceSquareTable.PieceSquareTable**.+* Split **src-test/Main.hs** into **src-test/HUnit.hs** & **src-test/QuickCheck.hs**, each referenced independently from the cabal file.+* Added an executable **duel** (to coordinate a battle between two independently configured instances of **bishbosh**) & a corresponding section-1 man-page.+* Validated the list of ranks supplied to construct either **Attribute.RankValues.RankValues** or **Input.PieceSquareTable.PieceSquareTable**.+ ### Refactoring:- * Flattened the nested array **Component.Zobrist.getRandomByCoordinatesByRankByLogicalColour**, by means of a composite index.- * Reimplemented function **Cartesian.Coordinates.getLogicalColourOfSquare**.- * Reimplemented function **Cartesian.Coordinates.interpolationsByDestinationBySource** in terms of function **Cartesian.Coordinates.extrapolationsByDirectionByCoordinates**.- * Used the **LambdaCase** language-extension.+* Flattened the nested array **Component.Zobrist.getRandomByCoordinatesByRankByLogicalColour**, by means of a composite index.+* Reimplemented function **Cartesian.Coordinates.getLogicalColourOfSquare**.+* Reimplemented function **Cartesian.Coordinates.interpolationsByDestinationBySource** in terms of function **Cartesian.Coordinates.extrapolationsByDirectionByCoordinates**.+* Used the **LambdaCase** language-extension.++## 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.++### 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**.++### BishBosh:+* Created a new directory **Rule/** to which **Model.**{**DrawReason**, **GameTerminationReason**, **Result**} were relocated.+* Refactored functions **BishBosh.ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition**, **BishBosh.Model.MoveFrequency.insertMoves** & **BishBosh.Model.GameTree.toMoveFrequency**.+* Evaluation-criteria:+ + Moved **BishBosh.Attribute.**{**CriterionValue**, **CriterionWeight**, **WeightedMeanAndCriterionValues**} to a new directory **Metric/**+ + Implemented classes [**Num**, **Fractional**, **Real**] for data-types **BishBosh.Metric.**{**CriterionValue.CriterionValue**, **CriterionWeight.CriterionWeight**}, nullifying the requirement for exports.+ + Replaced the pointless polymorphic payloads in data-types **BishBosh.Metric.**{**CriterionValue.CriterionValue**, **CriterionWeight.CriterionWeight**, **WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues**} with concrete types.+* Moved **BishBosh.Attribute.RankValues** to **BishBosh.Input**.+* Checked that (with the possible exception of the King) the Queen is configured as the most valuable rank.+* Avoided repeated calls from module **BishBosh.Evaluation.Fitness** to function **IBishBosh.nput.RankValues.calculateMaximumTotalValue** by adding the record-field **BishBosh.Input.EvaluationOptions.getMaximumTotalRankValue**.+
config/bishbosh.dtd view
@@ -30,8 +30,8 @@ > <!ELEMENT rankValues EMPTY> <!ATTLIST rankValues- rank (p | r | n | b | q | k) #REQUIRED- value CDATA #REQUIRED+ rank (p | r | n | b | q | k) #REQUIRED+ rankValue CDATA #REQUIRED > <!ENTITY rankValues_Carlson SYSTEM "rankValues_Carlson.xml"> <!ENTITY rankValues_Kaufman SYSTEM "rankValues_Kaufman.xml">@@ -145,7 +145,6 @@ displaySAN (False | True) #IMPLIED editMode (False | True) #IMPLIED forceMode (False | True) #IMPLIED- pause CDATA #IMPLIED ponderMode (False | True) #IMPLIED postMode (False | True) #IMPLIED protocolVersion CDATA #IMPLIED
config/bishbosh.rng view
@@ -20,7 +20,7 @@ <zeroOrMore> <element name="rankValues"> <ref name="Rank"/>- <attribute name="value">+ <attribute name="rankValue"> <ref name="ClosedUnitInterval"/> </attribute> </element>@@ -268,7 +268,6 @@ <name>displaySAN</name> <name>editMode</name> <name>forceMode</name>- <name>pause</name> <name>ponderMode</name> <name>postMode</name> </choice>
config/rankValues_Carlson.xml view
@@ -22,9 +22,9 @@ These are the values (in the closed unit-interval rather than the traditional centi-pawns) of various ranks of piece. N.B.: derived from <https://www.chessprogramming.org/Point_Value_by_Regression_Analysis#Human_Players>. -->-<rankValues rank="p" value="0.127"/> <!-- Pawn -->-<rankValues rank="r" value="0.448"/> <!-- Rook -->-<rankValues rank="b" value="0.309"/> <!-- Bishop -->-<rankValues rank="n" value="0.271"/> <!-- Knight -->-<rankValues rank="q" value="1"/> <!-- Queen -->-<rankValues rank="k" value="0"/> <!-- King -->+<rankValues rank="p" rankValue="0.127"/> <!-- Pawn -->+<rankValues rank="r" rankValue="0.448"/> <!-- Rook -->+<rankValues rank="b" rankValue="0.309"/> <!-- Bishop -->+<rankValues rank="n" rankValue="0.271"/> <!-- Knight -->+<rankValues rank="q" rankValue="1"/> <!-- Queen -->+<rankValues rank="k" rankValue="0"/> <!-- King -->
config/rankValues_Kaufman.xml view
@@ -22,9 +22,9 @@ These are the values (in the closed unit-interval rather than the traditional centi-pawns) of various ranks of piece N.B.: derived from Larry Kaufman's values; <https://www.chessprogramming.org/Point_Value> -->-<rankValues rank="p" value="0.1"/> <!-- Pawn -->-<rankValues rank="r" value="0.525"/> <!-- Rook -->-<rankValues rank="b" value="0.35"/> <!-- Bishop -->-<rankValues rank="n" value="0.35"/> <!-- Knight -->-<rankValues rank="q" value="1"/> <!-- Queen -->-<rankValues rank="k" value="0"/> <!-- King -->+<rankValues rank="p" rankValue="0.1"/> <!-- Pawn -->+<rankValues rank="r" rankValue="0.525"/> <!-- Rook -->+<rankValues rank="b" rankValue="0.35"/> <!-- Bishop -->+<rankValues rank="n" rankValue="0.35"/> <!-- Knight -->+<rankValues rank="q" rankValue="1"/> <!-- Queen -->+<rankValues rank="k" rankValue="0"/> <!-- King -->
config/rankValues_Medvedev.xml view
@@ -22,9 +22,9 @@ These are the values (in the closed unit-interval rather than the traditional centi-pawns) of various ranks of piece. N.B.: derived from https://www.chessprogramming.org/Point_Value_by_Regression_Analysis. -->-<rankValues rank="p" value="0.093"/> <!-- Pawn -->-<rankValues rank="r" value="0.446"/> <!-- Rook -->-<rankValues rank="b" value="0.320"/> <!-- Bishop -->-<rankValues rank="n" value="0.267"/> <!-- Knight -->-<rankValues rank="q" value="1"/> <!-- Queen -->-<rankValues rank="k" value="0"/> <!-- King -->+<rankValues rank="p" rankValue="0.093"/> <!-- Pawn -->+<rankValues rank="r" rankValue="0.446"/> <!-- Rook -->+<rankValues rank="b" rankValue="0.320"/> <!-- Bishop -->+<rankValues rank="n" rankValue="0.267"/> <!-- Knight -->+<rankValues rank="q" rankValue="1"/> <!-- Queen -->+<rankValues rank="k" rankValue="0"/> <!-- King -->
copyright view
@@ -9,3 +9,4 @@ License: GNU GENERAL PUBLIC LICENSE Version 3; see '/usr/share/common-licenses/GPL-3' or '/usr/share/doc/licenses/gpl-3.0.txt' where available, or the local packaged file 'LICENSE'.+
makefile view
@@ -13,61 +13,61 @@ # You should have received a copy of the GNU General Public License # along with BishBosh. If not, see <http://www.gnu.org/licenses/>. -.PHONY: hlint test prof cabalCheck sdist findOmissions xboard duel haddock graphmod+.PHONY: cabalCheck duel findOmissions graphmod haddock hlint prof randomTest sdist test xboard PACKAGE_NAME = bishbosh SHELL = /bin/bash GHC_OPTIONS = --ghc-options='-j' BIN_DIR = $$HOME/.local/bin/ -# Build hlint.-$(BIN_DIR)/hlint:- @stack install hlint+$(BIN_DIR)/graphmod $(BIN_DIR)/hlint:+ @[ -x $@ ] || stack install $(suffix @) $(GHC_OPTIONS) -# Check for lint.+# Display the module-dependency graph.+graphmod: $(BIN_DIR)/graphmod+ @$@ --graph-dim='40,24' -i 'src-lib' -i 'src-exe' Main | tred | dot -Tsvg | display++# Groom sourcecode. hlint: $(BIN_DIR)/hlint- @$@ --cpp-define 'USE_PARALLEL'\+ @$@ -j --no-exit-code\+ --cpp-define 'USE_PARALLEL'\ --cpp-define 'USE_POLYPARSE=1'\ --cpp-define 'USE_UNBOXED_ARRAYS'\+ --cpp-define 'USE_NEWTYPE_WRAPPERS'\ --ignore 'Use tuple-section'\- src-lib/ +RTS -N -RTS || true- @$@ --cpp-define 'USE_HXTRELAXNG'\+ src-lib/ +RTS -N -RTS+ @$@ -j --no-exit-code\+ --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 || true- @$@ --cpp-define 'USE_PARALLEL'\+ src-exe/ +RTS -N -RTS+ @$@ -j --cpp-define 'USE_PARALLEL'\ --cpp-define 'USE_POLYPARSE=1'\ --cpp-define 'USE_SEARCH'\ --ignore 'Use tuple-section'\ src-test/ +RTS -N -RTS -# Compile with various CPP-flags & run the test-suites.+# Serially compile with various CPP-flags & run the test-suites. test:- @for FLAG in -narrownumbers -polyparse -hxtrelaxng narrownumbers -threaded unboxedarrays; do\+ @for FLAG in -polyparse newtypewrappers -hxtrelaxng narrownumbers unboxedarrays -threaded; 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;\+ stack test $${FLAGS} $(GHC_OPTIONS)+ # Profile. prof: @stack install --library-profiling --executable-profiling $(GHC_OPTIONS) @$(PACKAGE_NAME) -i 'config/Raw/$(PACKAGE_NAME)_$@.xml' +RTS -p -N2 -RTS -# Check the cabal-file.-cabalCheck:- @cabal check--# Package for upload to Hackage.-sdist:- @cabal '$@'--# Find source-files missing from the distribution.-findOmissions: sdist- @diff <(find src-* -type f \( -name '*.hs' -a ! -name 'Setup.hs' \) | sed 's!^\./!!' | sort) <(tar -ztf dist*/sdist/$(PACKAGE_NAME)-*.tar.gz | grep '\.hs$$' | sed 's!^$(PACKAGE_NAME)-[0-9.]*/!!' | sort)- # Install this product. $(BIN_DIR)/$(PACKAGE_NAME) $(BIN_DIR)/duel: @stack install $(GHC_OPTIONS)@@ -78,13 +78,21 @@ # Start a battle. duel: $(BIN_DIR)/duel- @$@ --verbosity='Verbose' --nGames=128 --readTimeout=30 -i 'config/Raw/bishbosh_$@_white.xml' -i 'config/Raw/bishbosh_$@_black.xml'+ @$@ --nGames=32 --verbosity='Verbose' -i 'config/Raw/$(PACKAGE_NAME)_$@_white.xml' -i 'config/Raw/$(PACKAGE_NAME)_$@_black.xml' # Build the source-code documentation. haddock: @stack '$@' --no-$@-deps $(GHC_OPTIONS) -# Show module-dependency graph.-graphmod:- @$@ --graph-dim='40,24' -i 'src-exe' -i 'src-lib' Main | tred | dot -Tsvg | display # CAVEAT: doesn't include 'Duel'.+# Package for upload to Hackage.+sdist:+ @cabal '$@'++# Check the cabal-file.+cabalCheck:+ @cabal check++# 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)
man/man1/duel.1 view
@@ -7,7 +7,8 @@ .PP An application which automatically plays chess, by forking two independently configured instances of \fBbishbosh\fR. One instance automates the moves of White & the other automates the moves of Black.-This application merely acts as an intermediary, passing moves between these instances to synchronise their positions, while collating the game-results to permit comparison of the fitness of their respective configurations.+This application merely acts as an intermediary, passing moves between these instances to synchronise their positions,+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. .SH OPTIONS@@ -15,21 +16,32 @@ \fB--verbosity=\fR(\fBSilent\fR|\fBNormal\fR|\fBVerbose\fR|\fBDeafening\fR), defaulting to "\fBNormal\fR". Defines the quantity of ancillary output required. .TP+\fB-d\fR \fIInt\fR, \fB--nDecimalDigits=\fR\fIInt\fR, defaulting to "\fB0\fR".+The precision with which to display the total time taken by each side.+.TP \fB-n\fR \fIInt\fR, \fB--nGames=\fR\fIInt\fR, defaulting to "\fB1\fR". The number of games to be played before presenting the results. .TP \fB-t\fR \fIInt\fR, \fB--readTimeout=\fR\fIInt\fR, defaulting to \fIindefinitely\fR.-The number of seconds to wait for a move before aborting.-CAVEAT: the period typically required depends on;+The maximum number of seconds to wait for one of the forked processes to return a move, before aborting.+CAVEAT: the required period typically required depends on; .IP \(bu the machine's speed, .IP \(bu what else is running on the machine, .IP \(bu-the search-depth,+the size of the machine's RAM, .IP \(bu-the fitness-evaluation criteria.+the time initially required to process any PGN-database,+.IP \(bu+\fBbishbosh\fR's configuration (e.g. search-depth or fitness-evaluation criteria). .TP+.B --verifyConfiguration+Verify the mutual compatibility of the two configuration-files before forwarding each to a forked instance of \fBbishbosh\fR,+where the syntactic & semantic correctness will be independently verified.+The configurations are required to define the same move-notation & to define the logical colour of the automated player in the correct order to avoid deadlock.+N.B. since verification of this compatibility-requirement necessitates parsing, syntactic-verification is an inevitable side-effect.+.TP \fB-i\fR \fIFile-path\fR, \fB--appendInputConfigFilePath=\fR\fIFile-path\fR; there is no default. Define the path to a configuration-file to forward to \fBbishbosh\fR. Two such paths are required, the first will be passed to the instance playing White & the second to the instance playing Black.@@ -44,20 +56,22 @@ \fB0\fR on success, & >\fB0\fR if an error occurs. .SH EXAMPLES .nf-.B duel --verbosity='Verbose' --nGames=128 -i 'config/Raw/bishbosh_duel_white.xml' -i 'config/Raw/bishbosh_duel_black.xml'+.B duel --nGames=32 --verbosity='Verbose' --verifyConfiguration -i 'config/Raw/bishbosh_duel_white.xml' -i 'config/Raw/bishbosh_duel_black.xml' .fi .IP \(bu The application has been instructed to provide a relatively large amount of feedback. .IP \(bu-Two packaged configuration-files have been referenced, the first referring to the instance playing White, as required.+Two packaged configuration-files have been referenced. .IP \(bu+The compatibility of the configuration-files is verified to confirm that they automate White & Black respectively, & that they use the same move-notation.+.IP \(bu CAVEAT: assumes that the executable exists on \fB$PATH\fR, otherwise an explicit path will be required. .PP .nf .B make duel .fi .IP \(bu-The same as above.+Much the same as the previous example, but verification is unnecessary since the configuration-files are hard-coded. .IP \(bu The current working directory must be \fBbishbosh\fR's installation-directory where the required \fBmakefile\fR is defined. .SH FILES@@ -74,8 +88,6 @@ .SH AUTHOR Written by Dr. Alistair Ward. .SH BUGS-.IP \(bu-The comparison between the configurations of the two instances doesn't factor the time taken by each instance. .SS "REPORTING BUGS" Report bugs to "\fBbishbosh@functionalley.com\fR". .SH COPYRIGHT
src-exe/BishBosh/Concurrent/Pondering.hs view
@@ -91,3 +91,4 @@ ) ( const $ return {-to IO-monad-} "purging MVar." )+
src-exe/BishBosh/Play.hs view
@@ -38,7 +38,7 @@ play ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.ContextualNotation.PositionHashQualifiedMoveTree as ContextualNotation.PositionHashQualifiedMoveTree import qualified BishBosh.ContextualNotation.QualifiedMoveForest as ContextualNotation.QualifiedMoveForest@@ -54,7 +54,9 @@ import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.State.PlayState as State.PlayState import qualified BishBosh.Text.ShowColouredPrefix as Text.ShowColouredPrefix-import qualified BishBosh.Types as T+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@@ -74,15 +76,7 @@ -- | Plays the game according to the specified configuration. play :: (- Control.DeepSeq.NFData column,-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Control.DeepSeq.NFData criterionWeight, Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row,- Control.DeepSeq.NFData weightedMean, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y, Data.Array.IArray.Ix x,@@ -90,45 +84,29 @@ 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 criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean,- Integral column, Integral x, Integral y, Ord positionHash, Read x, Read y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Real weightedMean,- Show column, Show pieceSquareValue,- Show row, Show x, Show y, System.Random.Random positionHash, System.Random.RandomGen randomGen ) => randomGen- -> Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y+ -> Input.Options.Options pieceSquareValue x y -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y -- ^ Standard openings.- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)-{-# SPECIALISE play :: (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row,- Integral column,- Show column,- Show row,- System.Random.RandomGen randomGen- )+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+{-# SPECIALISE play+ :: System.Random.RandomGen randomGen => randomGen- -> Input.Options.Options column T.CriterionWeight T.PieceSquareValue T.RankValue row T.X T.Y- -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest T.X T.Y- -> IO (State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y)+ -> 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) #-} play randomGen options qualifiedMoveForest = Data.Maybe.maybe ( return {-to IO-monad-} Data.Default.def {-game-}@@ -169,7 +147,7 @@ else Property.Empty.empty {-MoveFrequency-} ) ) >>= (- const UI.Raw.takeTurns `either` const UI.CECP.takeTurns $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- Select a user-interface.+ const UI.Raw.takeTurns ||| const UI.CECP.takeTurns $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- Select a user-interface. ) ( ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest ( Input.EvaluationOptions.getIncrementalEvaluation $ Input.Options.getEvaluationOptions options
src-exe/BishBosh/State/ApplicationTerminationReason.hs view
@@ -40,8 +40,8 @@ | MaximumPlies -- ^ The configured maximum number of /turn/s has been reached. instance Show ApplicationTerminationReason where- showsPrec _ ByRequest = showString "by request"- showsPrec _ MaximumPlies = showString "because the configured maximum number of plies has been reached"+ show ByRequest = "by request"+ show MaximumPlies = "because the configured maximum number of plies has been reached" instance Control.DeepSeq.NFData ApplicationTerminationReason where rnf _ = ()
src-exe/BishBosh/State/PlayState.hs view
@@ -65,13 +65,16 @@ import qualified BishBosh.Input.IOOptions as Input.IOOptions import qualified BishBosh.Input.Options as Input.Options import qualified BishBosh.Input.UIOptions as Input.UIOptions+import qualified BishBosh.Metric.CriterionValue as Metric.CriterionValue import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Model.GameTree as Model.GameTree import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.State.ApplicationTerminationReason as State.ApplicationTerminationReason import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Types as T+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@@ -81,58 +84,45 @@ import qualified Data.Ord import qualified Factory.Math.Statistics -#ifdef USE_PARALLEL-import qualified Control.DeepSeq-#endif- #ifdef USE_UNBOXED_ARRAYS import qualified Data.Array.Unboxed #endif -- | The type threaded through the sequence of /game/s during play.-data PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y = MkPlayState {- getCriterionValues :: [[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 criterionValue weightedMean,- getOptions :: Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y, -- ^ The constant options by which the game is configured.- getMaybeApplicationTerminationReason :: Maybe State.ApplicationTerminationReason.ApplicationTerminationReason -- ^ Whether the game has terminated.+data PlayState pieceSquareValue positionHash x y = 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.+ getMaybeApplicationTerminationReason :: Maybe State.ApplicationTerminationReason.ApplicationTerminationReason -- ^ Whether the game has terminated. } -- | Constructor. initialise :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif 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). #endif Data.Bits.Bits positionHash,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y )- => Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y+ => Input.Options.Options pieceSquareValue x y -> Component.Zobrist.Zobrist x y positionHash -> Model.GameTree.MoveFrequency x y -> Model.Game.Game x y- -> PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ -> PlayState pieceSquareValue positionHash x y {-# SPECIALISE initialise- :: Input.Options.Options column T.CriterionWeight T.PieceSquareValue T.RankValue row T.X T.Y- -> Component.Zobrist.Zobrist T.X T.Y T.PositionHash- -> Model.GameTree.MoveFrequency T.X T.Y- -> Model.Game.Game T.X T.Y- -> PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y+ :: 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 #-} initialise options zobrist moveFrequency game = MkPlayState { getCriterionValues = [],@@ -146,41 +136,32 @@ } -- | Accessor.-getGame :: PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y -> Model.Game.Game x y+getGame :: PlayState pieceSquareValue positionHash x y -> Model.Game.Game x y 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 column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y = PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y -> PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+type Transformation pieceSquareValue positionHash x y = PlayState pieceSquareValue positionHash x y -> PlayState pieceSquareValue positionHash x y -- | Mutator.-setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+setPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> Transformation pieceSquareValue positionHash x y setPositionHashQuantifiedGameTree positionHashQuantifiedGameTree playState@MkPlayState { getSearchState = searchState } = playState { getSearchState = searchState { Search.SearchState.getPositionHashQuantifiedGameTree = positionHashQuantifiedGameTree } } -- | Reconstruct the /positionHashQuantifiedGameTree/ (in the /searchState/), with the apex set to the specified game. reconstructPositionHashQuantifiedGameTree :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif 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). #endif Data.Bits.Bits positionHash,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y- ) => Model.Game.Game x y -> Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ ) => Model.Game.Game x y -> Transformation pieceSquareValue positionHash x y reconstructPositionHashQuantifiedGameTree game playState@MkPlayState { getZobrist = zobrist, getMoveFrequency = moveFrequency,@@ -193,27 +174,18 @@ -- | Reset to the initial state. resetPositionHashQuantifiedGameTree :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif 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). #endif Data.Bits.Bits positionHash,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y- ) => Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ ) => Transformation pieceSquareValue positionHash x y resetPositionHashQuantifiedGameTree playState = reconstructPositionHashQuantifiedGameTree Data.Default.def playState { getCriterionValues = [], getMaybeApplicationTerminationReason = Nothing@@ -221,19 +193,16 @@ -- | Mutator. updateWithAutomaticMove- :: [criterionValue]- -> Search.SearchState.SearchState x y positionHash criterionValue weightedMean- -> Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ :: [Metric.CriterionValue.CriterionValue]+ -> Search.SearchState.SearchState x y positionHash+ -> Transformation pieceSquareValue positionHash x y updateWithAutomaticMove criterionValues searchState playState = playState { getCriterionValues = criterionValues : getCriterionValues playState, getSearchState = searchState } -- | Mutator.-updateWithManualMove :: (- Eq x,- Eq y- ) => Model.Game.Game x y -> Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+updateWithManualMove :: (Eq x, Eq y) => Model.Game.Game x y -> Transformation pieceSquareValue positionHash x y updateWithManualMove game playState@MkPlayState { getSearchState = searchState } = setPositionHashQuantifiedGameTree ( Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.State.PlayState.updateWithManualMove:\tEvaluation.PositionHashQuantifiedGameTree.reduce failed."@@ -251,15 +220,20 @@ -- | Calculate the /root-mean-square/ & the /standard-deviation/, of the values of each type of /criterion/. calculateCriterionValueStatistics :: ( Floating standardDeviation,- Fractional mean,- Real criterionValue- ) => PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y -> [(mean, standardDeviation)]+ Fractional mean+ )+ => PlayState pieceSquareValue positionHash x y+ -> [(mean, standardDeviation)] calculateCriterionValueStatistics MkPlayState { getCriterionValues = criterionValues } = map (- Factory.Math.Statistics.getMean &&& Factory.Math.Statistics.getStandardDeviation+ (+ Factory.Math.Statistics.getMean &&& Factory.Math.Statistics.getStandardDeviation+ ) . map (+ \criterionValue -> realToFrac criterionValue :: Type.Mass.CriterionValue+ ) ) $ Data.List.transpose criterionValues -- | Resignation by the player who currently holds the choice of move.-resign :: Transformation column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+resign :: Transformation pieceSquareValue positionHash x y resign playState@MkPlayState { getSearchState = searchState } = setPositionHashQuantifiedGameTree ( Evaluation.PositionHashQuantifiedGameTree.resign $ Search.SearchState.getPositionHashQuantifiedGameTree searchState ) playState@@ -274,7 +248,7 @@ Show y ) => String -- ^ Move-string.- -> PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ -> PlayState pieceSquareValue positionHash x y -> [String] -- ^ Suggested corrections. suggestCorrections moveString playState@MkPlayState { getOptions = options } | Model.Game.isTerminated game = []@@ -286,11 +260,12 @@ -- | Whether the game in the first /play-state/ has more plies than that in the second. hasMorePlies- :: PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y+ :: PlayState pieceSquareValue positionHash x y+ -> PlayState pieceSquareValue positionHash x y -> 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 column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y -> Bool+hasApplicationTerminationBeenRequested :: PlayState pieceSquareValue positionHash x y -> Bool hasApplicationTerminationBeenRequested MkPlayState { getMaybeApplicationTerminationReason = maybeApplicationTerminationReason } = Data.Maybe.isJust maybeApplicationTerminationReason+
src-exe/BishBosh/UI/CECP.hs view
@@ -43,11 +43,9 @@ takeTurns ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) import Control.Monad((>=>)) import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn@@ -57,7 +55,6 @@ import qualified BishBosh.ContextualNotation.QualifiedMoveForest as ContextualNotation.QualifiedMoveForest import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Data.Time as Data.Time import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame@@ -66,15 +63,18 @@ 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.RankValues as Input.RankValues import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions+import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason import qualified BishBosh.Search.Search as Search.Search import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.State.ApplicationTerminationReason as State.ApplicationTerminationReason@@ -82,7 +82,11 @@ import qualified BishBosh.State.PlayState as State.PlayState import qualified BishBosh.Text.ShowList as Text.ShowList import qualified BishBosh.Text.ShowPrefix as Text.ShowPrefix-import qualified BishBosh.Types as T+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 import qualified BishBosh.UI.ReportObject as UI.ReportObject@@ -99,8 +103,6 @@ import qualified Data.List.Extra import qualified Data.Map import qualified Data.Maybe-import qualified Data.Time.Clock-import qualified Numeric import qualified System.IO import qualified System.Random import qualified ToolShed.System.Random@@ -111,23 +113,23 @@ -- | Used in output to prefix hints. hintTag :: String-hintTag = "Hint:"+hintTag = "Hint:" -- | Used in output, to prefix moves. moveTag :: String-moveTag = "move"+moveTag = "move" -- | Used in output, to qualify a draw-offer. offerTag :: String-offerTag = "offer"+offerTag = "offer" -- | The response to a ping request. pongTag :: String-pongTag = "pong"+pongTag = "pong" -- | The command used to request the version of the CECP protocol. protoverTag :: String-protoverTag = "protover"+protoverTag = "protover" -- | Constant. explicitEnpassant :: ContextualNotation.StandardAlgebraic.ExplicitEnPassant@@ -164,29 +166,24 @@ mkParseFailureError :: ShowS mkParseFailureError = mkErrorMessage "parse-failure" --- | Format thinking-output suitable to be posted to xboard.-showsThinking :: (- Fractional rankValue,- Real rankValue,- Real weightedMean- )- => Input.SearchOptions.SearchDepth- -> Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y- -> weightedMean- -> Data.Time.Clock.NominalDiffTime -- ^ Elapsed time.- -> Component.Move.NPlies -- ^ Nodes searched.- -> String -- ^ Principal variation.+-- | Format thinking-output suitable to be posted to /xboard/.+showsThinking+ :: Property.ShowFloat.ShowFloat stoppedWatch+ => Type.Count.NPlies -- ^ Search-depth.+ -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y+ -> Type.Mass.WeightedMean+ -> stoppedWatch+ -> Type.Count.NPositions -- ^ Nodes searched.+ -> String -- ^ Principal variation. -> ShowS-showsThinking searchDepth evaluationOptions weightedMean elapsedTime nPlies principalVariation = Text.ShowList.showsDelimitedList (showChar ' ') id id [+showsThinking searchDepth evaluationOptions weightedMean stoppedWatch nPlies principalVariation = Text.ShowList.showsDelimitedList (showChar ' ') id id [ shows searchDepth,- shows . (- round :: Double -> Int- ) $ 100 {-centi-Pawns-} * realToFrac (+ shows . (round :: Type.Mass.RankValue -> Int) $ 100 {-centi-Pawns-} * ( uncurry (/) . (- Attribute.RankValues.calculateMaximumTotalValue &&& Attribute.RankValues.findRankValue Attribute.Rank.Pawn+ Input.RankValues.calculateMaximumTotalValue &&& realToFrac . Input.RankValues.findRankValue Attribute.Rank.Pawn ) $ Input.EvaluationOptions.getRankValues evaluationOptions ) * realToFrac weightedMean,- shows (round $ 100 {-centi-seconds-} * elapsedTime :: Int),+ Property.ShowFloat.showsFloat (shows . (round :: Double -> Int) . (* 100)) stoppedWatch, shows nPlies ] . showChar '\t' . showString principalVariation @@ -195,15 +192,8 @@ * 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 column criterionValue criterionWeight pieceSquareValue positionHash randomGen rankValue row weightedMean x y. (- Control.DeepSeq.NFData column,-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Control.DeepSeq.NFData criterionWeight,+readMove :: forall pieceSquareValue positionHash randomGen x y. ( Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y, Data.Array.IArray.Ix x,@@ -211,45 +201,31 @@ 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 criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y, Ord positionHash,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Real weightedMean,- Show column, Show pieceSquareValue,- Show row, Show x, Show y, System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash -> randomGen- -> Data.Time.Clock.UTCTime- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)-{-# SPECIALISE readMove :: (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row,- Show column,- Show row,- System.Random.RandomGen randomGen- )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree T.X T.Y T.PositionHash+ -> Time.StopWatch.StopWatch+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+{-# SPECIALISE readMove+ :: System.Random.RandomGen randomGen+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> randomGen- -> Data.Time.Clock.UTCTime- -> State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y- -> IO (State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y)+ -> 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) #-} readMove positionHashQualifiedMoveTree randomGen = slave where- slave startUTCTime playState = let+ slave runningWatch playState = let (game, options) = State.PlayState.getGame &&& State.PlayState.getOptions $ playState (searchOptions, ioOptions) = Input.Options.getSearchOptions &&& Input.Options.getIOOptions $ options @@ -261,13 +237,13 @@ moveNotation = Input.UIOptions.getMoveNotation uiOptions nDecimalDigits = Input.UIOptions.getNDecimalDigits uiOptions verbosity = Input.UIOptions.getVerbosity uiOptions- in (- const . Control.Exception.throwIO $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.readMove.slave:\tunexpectedly found 'NativeUIOptions'."- ) `either` (+ in const (+ Control.Exception.throwIO $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.readMove.slave:\tunexpectedly found 'NativeUIOptions'."+ ) ||| ( \cecpOptions -> let displaySAN = Input.CECPOptions.getDisplaySAN cecpOptions - onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -285,7 +261,7 @@ ) ( flip (ContextualNotation.StandardAlgebraic.showTurn explicitEnpassant) game ) . Model.Game.maybeLastTurn $ Evaluation.QuantifiedGame.getGame quantifiedGame- else Notation.MoveNotation.showNotation moveNotation $ Evaluation.QuantifiedGame.getLastTurn (quantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)+ else Notation.MoveNotation.showNotation moveNotation $ Evaluation.QuantifiedGame.getLastTurn (quantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y) _ -> 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@@ -345,7 +321,7 @@ ) ( \(filePath, _) -> Control.Exception.catch ( do- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` (Data.Default.def :: Model.Game.Game T.X T.Y))+ 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)@@ -361,13 +337,14 @@ } } onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Component.Move.NPlies -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) rollBack nPlies- | (game', _) : _ <- drop (pred nPlies) $ Model.Game.rollBack game = return {-to IO-monad-} $ State.PlayState.reconstructPositionHashQuantifiedGameTree game' playState- | otherwise = onCommand UI.Command.Restart+ | (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 = succ $ Data.Map.size searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies.+ 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. in do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "rolling-back " $ shows nPlies " plies." @@ -403,7 +380,7 @@ do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "setting " $ shows setObject "." - slave startUTCTime playState {+ slave runningWatch playState { State.PlayState.getOptions = Control.DeepSeq.force $ case setObject of UI.SetObject.SearchDepth searchDepth -> options { Input.Options.getSearchOptions = Input.SearchOptions.setSearchDepth searchDepth $ Input.Options.getSearchOptions options@@ -420,12 +397,12 @@ 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." eventLoop- | otherwise = do+ | otherwise = do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "swapping " $ shows Input.SearchOptions.searchDepthTag "." return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash x y) eventLoop = getLine >>= \line -> do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "received \"" $ showString line "\"." @@ -674,13 +651,13 @@ eventLoop | otherwise -> do- elapsedTime <- Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- Property.Switchable.toggle runningWatch - Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "paused => stopping the clock at " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "paused => stopping the watch at " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.setEitherNativeUIOrCECPOptions (- Right cecpOptions { Input.CECPOptions.getMaybePaused = Just elapsedTime }+ Right $ Input.CECPOptions.pause stoppedWatch cecpOptions ) options } "playother"@@ -705,16 +682,14 @@ ) options } "resume"- | Just timeTaken <- maybePaused -> do- startUTCTime' <- Data.Time.Clock.getCurrentTime+ | Just stoppedWatch <- maybePaused -> do+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowPrefix.showsPrefixInfo "resuming => restarting the watch." - Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr $ Text.ShowPrefix.showsPrefixInfo "resuming => restarting the clock."+ runningWatch' <- Property.Switchable.toggle stoppedWatch - slave (- Data.Time.Clock.addUTCTime (negate timeTaken) startUTCTime' -- Restart the clock.- ) playState {+ slave runningWatch' playState { State.PlayState.getOptions = Input.Options.setEitherNativeUIOrCECPOptions (- Right cecpOptions { Input.CECPOptions.getMaybePaused = Nothing }+ Right $ Input.CECPOptions.resume cecpOptions ) options } | otherwise -> do@@ -922,7 +897,7 @@ | Just value <- featureName `lookup` Input.CECPFeatures.getFeatures cecpFeatures -> do Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixWarning . showString Input.CECPFeatures.featureTag . Text.ShowList.showsAssociation $ shows arg' " rejected." - slave startUTCTime playState {+ slave runningWatch playState { State.PlayState.getOptions = either ( \i -> if i /= 0 then \options' -> options' {@@ -940,7 +915,7 @@ [(featureName, stringArg)] -> do Control.Monad.when (verbosity >= Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixWarning . showString Input.CECPFeatures.featureTag . Text.ShowList.showsAssociation $ shows arg' " rejected because of syntax." - slave startUTCTime playState {+ slave runningWatch playState { State.PlayState.getOptions = options { Input.Options.getIOOptions = Input.IOOptions.deleteCECPFeature ( featureName,@@ -1014,7 +989,7 @@ maybePaused = Input.CECPOptions.getMaybePaused cecpOptions - moveCommand :: String -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ moveCommand :: String -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) moveCommand moveString = case Notation.MoveNotation.readsQualifiedMove moveNotation moveString of [(eitherQualifiedMove, "")] | Just errorMessage <- Model.Game.validateEitherQualifiedMove eitherQualifiedMove game -> do@@ -1024,9 +999,7 @@ eventLoop -- Recurse. | otherwise -> do- elapsedTime <- if forceMode- then return {-to IO-monad-} 0- else Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- Property.Switchable.toggle runningWatch let game' = Model.Game.applyEitherQualifiedMove eitherQualifiedMove game@@ -1037,7 +1010,7 @@ Notation.MoveNotation.showNotation moveNotation . Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.UI.CECP.readMove.onCommand.moveCommand:\tModel.Game.maybeLastTurn failed." ) $ Model.Game.maybeLastTurn game'- ) . showString " was requested after " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ ) . showString " was requested after " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition game' positionHashQualifiedMoveTree of [] -> return ()@@ -1066,16 +1039,8 @@ ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall column criterionValue criterionWeight pieceSquareValue positionHash randomGen rankValue row weightedMean x y. (- Control.DeepSeq.NFData column,-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Control.DeepSeq.NFData criterionWeight,+takeTurns :: forall pieceSquareValue positionHash randomGen x y. ( Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row,- Control.DeepSeq.NFData weightedMean, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y, Data.Array.IArray.Ix x,@@ -1083,40 +1048,26 @@ 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 criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y, Ord positionHash,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Real weightedMean,- Show column, Show pieceSquareValue,- Show row, Show x, Show y, System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash -> randomGen- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)-{-# SPECIALISE takeTurns :: (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row,- Show column,- Show row,- System.Random.RandomGen randomGen- )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree T.X T.Y T.PositionHash+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+{-# SPECIALISE takeTurns+ :: System.Random.RandomGen randomGen+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> randomGen- -> State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y- -> IO (State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y)+ -> 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) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = do mVar <- Control.Concurrent.newEmptyMVar@@ -1136,24 +1087,24 @@ slave :: Maybe (Concurrent.Pondering.Pondering (Component.Move.Move x y))- -> Maybe Component.Move.NPlies+ -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) 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) = either (- const . Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.takeTurns.slave:\tunexpectedly found 'NativeUIOptions'."- ) (+ (ponderMode, isPostMode) = const (+ Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.takeTurns.slave:\tunexpectedly found 'NativeUIOptions'."+ ) ||| ( Input.CECPOptions.getPonderMode &&& Input.CECPOptions.getPostMode ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions' in Data.Maybe.maybe ( do- startUTCTime <- Data.Time.Clock.getCurrentTime+ runningWatch <- Property.Switchable.on Data.Maybe.maybe ( do- playState'' <- readMove positionHashQualifiedMoveTree randomGen' startUTCTime playState' -- Read the user's command or move.+ playState'' <- readMove positionHashQualifiedMoveTree randomGen' runningWatch playState' -- Read the user's command or move. (,) playState'' `fmap` ( if playState' `State.PlayState.hasMorePlies` playState''@@ -1199,30 +1150,30 @@ quantifiedGames@(quantifiedGame : continuation {-optimal move-sequence-}) -> let bestTurn = Evaluation.QuantifiedGame.getLastTurn quantifiedGame in do- elapsedTime <- bestTurn `seq` Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- bestTurn `seq` Property.Switchable.toggle runningWatch Control.Monad.when (verbosity > Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . ( if verbosity == maxBound then Property.ShowFloat.showsFloatToN nDecimalDigits ( Control.Monad.Reader.runReader ( Evaluation.Fitness.evaluateFitness Nothing game'- ) evaluationOptions :: Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue+ ) evaluationOptions :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues ) . Search.Search.showsSeparator -- Prepend the fitness of the original game prior to the result. else id- ) . Notation.MoveNotation.showsNotationFloatToNDecimals moveNotation nDecimalDigits searchResult' . showString " in " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ ) . Notation.MoveNotation.showsNotationFloatToNDecimals moveNotation nDecimalDigits searchResult' . showString " in " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." Control.Monad.when isPostMode . putStrLn $ showsThinking searchDepth' evaluationOptions ( Evaluation.QuantifiedGame.getFitness $ last quantifiedGames- ) elapsedTime (- Search.Search.getNPliesEvaluated searchResult'+ ) stoppedWatch (+ Search.Search.getNPositionsEvaluated searchResult' ) ( Text.ShowList.showsDelimitedList ( showChar ' ' ) id id ( zipWith (- \turn originalGame -> if either (- const . Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.takeTurns:\tunexpectedly found 'NativeUIOptions'."- ) Input.CECPOptions.getDisplaySAN $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions+ \turn originalGame -> if const (+ Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.UI.CECP.takeTurns:\tunexpectedly found 'NativeUIOptions'."+ ) ||| Input.CECPOptions.getDisplaySAN $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions then ContextualNotation.StandardAlgebraic.showsTurn explicitEnpassant turn originalGame else Notation.MoveNotation.showsNotation moveNotation turn ) (@@ -1235,7 +1186,7 @@ (,) ( State.PlayState.updateWithAutomaticMove (- Attribute.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame+ Metric.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) searchState' playState' ) `fmap` if ponderMode && Input.SearchOptions.getUsePondering searchOptions then case continuation of@@ -1258,7 +1209,7 @@ ) ) ( \(qualifiedMove, names) -> do- elapsedTime <- Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- Property.Switchable.toggle runningWatch Data.Maybe.maybe ( return {-to IO-monad-} ()@@ -1268,12 +1219,14 @@ let selectedGame = Model.Game.applyQualifiedMove qualifiedMove game' - Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "selected " . Notation.MoveNotation.showsNotation moveNotation qualifiedMove . showString " from:" . ContextualNotation.QualifiedMoveForest.showsNames maybeMaximumPGNNames names . showString "\n\tin " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowPrefix.showsPrefixInfo . showString "selected " . Notation.MoveNotation.showsNotation moveNotation qualifiedMove . showString " from:" . ContextualNotation.QualifiedMoveForest.showsNames maybeMaximumPGNNames names . showString "\n\tin " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." - Control.Monad.when isPostMode . putStrLn $ showsThinking searchDepth' evaluationOptions (0 :: weightedMean) elapsedTime 0 (+ Control.Monad.when isPostMode . putStrLn $ showsThinking searchDepth' evaluationOptions 0 stoppedWatch 0 ( Data.List.intercalate ( showString ".\n" $ replicate 4 ' ' -- Continuations must be preceded by at least 4 spaces.- ) $ Data.Maybe.maybe names (`take` names) maybeMaximumPGNNames+ ) $ Data.Maybe.maybe names (+ (`take` names) . fromIntegral+ ) maybeMaximumPGNNames ) "." putStrLn . showString moveTag . showChar ' ' $ Notation.MoveNotation.showNotation moveNotation qualifiedMove -- Send the move to the GUI.@@ -1306,13 +1259,13 @@ ) ) ( \gameTerminationReason -> do- putStrLn . shows (Model.GameTerminationReason.toResult gameTerminationReason) . showString " {" $ shows gameTerminationReason "}" -- Send the result to the GUI.+ putStrLn . shows (Rule.GameTerminationReason.toResult gameTerminationReason) . showString " {" $ shows gameTerminationReason "}" -- Send the result to the GUI. let criterionValueStatistics = State.PlayState.calculateCriterionValueStatistics playState' showsFloat :: Double -> ShowS- showsFloat = Numeric.showFFloat $ Just nDecimalDigits+ showsFloat = Property.ShowFloat.showsFloatToN' nDecimalDigits Control.Monad.when ( verbosity == maxBound && not (null criterionValueStatistics)@@ -1321,7 +1274,7 @@ ) criterionValueStatistics "." readMove positionHashQualifiedMoveTree randomGen' (- Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.UI.CECP.takeTurns.slave:\tundefined startUTCTime."+ Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.UI.CECP.takeTurns.slave:\tundefined stop-watch." ) playState' {-there're zero valid moves, but the user can issue commands-} >>= slave Nothing maybeMaximumPlies randomGens -- Tail recurse. ) $ Model.Game.getMaybeTerminationReason game'
src-exe/BishBosh/UI/Raw.hs view
@@ -29,9 +29,8 @@ takeTurns ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) import Control.Monad((>=>), (<=<))-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn@@ -40,7 +39,6 @@ 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.Data.Time as Data.Time import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame@@ -50,11 +48,13 @@ import qualified BishBosh.Input.SearchOptions as Input.SearchOptions import qualified BishBosh.Input.StandardOpeningOptions as Input.StandardOpeningOptions import qualified BishBosh.Input.UIOptions as Input.UIOptions+import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Property.Switchable as Property.Switchable import qualified BishBosh.Search.Search as Search.Search import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.State.ApplicationTerminationReason as State.ApplicationTerminationReason@@ -65,7 +65,11 @@ 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.Types as T+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 import qualified BishBosh.UI.ReportObject as UI.ReportObject@@ -81,8 +85,6 @@ import qualified Data.List.Extra import qualified Data.Map import qualified Data.Maybe-import qualified Data.Time.Clock-import qualified Numeric import qualified System.IO import qualified System.Random import qualified ToolShed.System.Random@@ -96,15 +98,8 @@ * 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 column criterionValue criterionWeight pieceSquareValue positionHash randomGen rankValue row weightedMean x y. (- Control.DeepSeq.NFData column,-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Control.DeepSeq.NFData criterionWeight,+readMove :: forall pieceSquareValue positionHash randomGen x y. ( Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y, Data.Array.IArray.Ix x,@@ -112,48 +107,32 @@ 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 criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean,- Integral column, Integral x, Integral y, Ord positionHash, Read x, Read y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Real weightedMean,- Show column, Show pieceSquareValue,- Show row, Show x, Show y, System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash -> randomGen- -> Data.Time.Clock.UTCTime- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)-{-# SPECIALISE readMove :: (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row,- Integral column,- Show column,- Show row,- System.Random.RandomGen randomGen- )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree T.X T.Y T.PositionHash+ -> Time.StopWatch.StopWatch+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+{-# SPECIALISE readMove+ :: System.Random.RandomGen randomGen+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> randomGen- -> Data.Time.Clock.UTCTime- -> State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y- -> IO (State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y)+ -> 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) #-}-readMove positionHashQualifiedMoveTree randomGen startUTCTime playState = let+readMove positionHashQualifiedMoveTree randomGen runningWatch playState = let (game, options) = State.PlayState.getGame &&& State.PlayState.getOptions $ playState (searchOptions, ioOptions) = Input.Options.getSearchOptions &&& Input.Options.getIOOptions $ options @@ -174,7 +153,7 @@ Notation.MoveNotation.getOrigin moveNotation ) . State.Board.getMaybePieceByCoordinates . Model.Game.getBoard - onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ onCommand :: UI.Command.Command x y -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) onCommand UI.Command.Hint = do Control.Monad.unless (Model.Game.isTerminated game) . Data.Maybe.maybe ( do@@ -244,7 +223,7 @@ ) ( \(filePath, _) -> Control.Exception.catch ( do- System.IO.withFile filePath System.IO.WriteMode (`System.IO.hPrint` (Data.Default.def :: Model.Game.Game T.X T.Y))+ 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)@@ -252,16 +231,17 @@ return {-to IO-monad-} $ State.PlayState.resetPositionHashQuantifiedGameTree playState onCommand (UI.Command.RollBack maybeNPlies) = let- rollBack :: Component.Move.NPlies -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ rollBack :: Type.Count.NPlies -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) rollBack nPlies- | (game', _) : _ <- drop (pred nPlies) $ Model.Game.rollBack game = do+ | (game', _) : _ <- drop (fromIntegral $ pred nPlies) $ Model.Game.rollBack game = do Control.Monad.when (verbosity == maxBound) . putStrLn $ show2D game' return {-to IO-monad-} $ State.PlayState.reconstructPositionHashQuantifiedGameTree game' playState | otherwise = onCommand UI.Command.Restart in Data.Maybe.maybe ( let- nPlies = succ $ Data.Map.size searchDepthByLogicalColour -- In fully manual play, rollback one ply, in semi-manual play rollback two plies.+ 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. in do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "rolling-back " $ shows nPlies " plies." @@ -297,7 +277,7 @@ do Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "setting " $ shows setObject "." - readMove positionHashQualifiedMoveTree randomGen startUTCTime playState {+ readMove positionHashQualifiedMoveTree randomGen runningWatch playState { State.PlayState.getOptions = Control.DeepSeq.force $ case setObject of UI.SetObject.SearchDepth searchDepth -> options { Input.Options.getSearchOptions = Input.SearchOptions.setSearchDepth searchDepth $ Input.Options.getSearchOptions options@@ -319,21 +299,23 @@ return {-to IO-monad-} playState { State.PlayState.getOptions = Input.Options.swapSearchDepth options } - eventLoop :: IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ eventLoop :: IO (State.PlayState.PlayState pieceSquareValue positionHash x y) eventLoop = getLine >>= \line -> case Data.List.Extra.trim line of "?" -> onCommand $ UI.Command.Print UI.PrintObject.Help- ':' : s -> either (- \errorMessage -> do- System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixError $ showString errorMessage "."-- eventLoop- ) (- \(command, remainder) -> if null $ Data.List.Extra.trimStart remainder- then onCommand command- else do- System.IO.hPutStrLn System.IO.stderr . showString "unexpected trailing text " $ shows remainder "."+ ':' : s -> (+ (+ \errorMessage -> do+ System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixError $ showString errorMessage "." eventLoop+ ) ||| (+ \(command, remainder) -> if null $ Data.List.Extra.trimStart remainder+ then onCommand command+ else do+ System.IO.hPutStrLn System.IO.stderr . showString "unexpected trailing text " $ shows remainder "."++ eventLoop+ ) ) . UI.Command.readsCommand $ UI.Command.autoComplete s s -> let corrections = State.PlayState.suggestCorrections s playState@@ -346,7 +328,7 @@ eventLoop -- Recurse. | otherwise -> do- elapsedTime <- Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- Property.Switchable.toggle runningWatch let game' = Model.Game.applyEitherQualifiedMove eitherQualifiedMove game@@ -357,7 +339,7 @@ Notation.MoveNotation.showNotation moveNotation . Data.Maybe.fromMaybe ( Control.Exception.throw $ Data.Exception.mkResultUndefined "BishBosh.UI.Raw.readMove.eventLoop:\tModel.Game.maybeLastTurn failed." ) $ Model.Game.maybeLastTurn game'- ) . showString " was requested after " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ ) . showString " was requested after " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." case ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMovesForPosition game' positionHashQualifiedMoveTree of [] -> return {-to IO-monad-} ()@@ -383,21 +365,13 @@ Control.Monad.unless (verbosity == minBound) . putStrLn . showString "Enter either a move in " . shows moveNotation . showString "-notation, or '?' for " $ showString UI.PrintObject.helpTag ":" eventLoop- ) `either` (- const . Control.Exception.throwIO $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.readMove:\tunexpected CECP-options."+ ) ||| const (+ Control.Exception.throwIO $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.readMove:\tunexpected CECP-options." ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions -- | Plays the game.-takeTurns :: forall column criterionValue criterionWeight pieceSquareValue positionHash randomGen rankValue row weightedMean x y. (- Control.DeepSeq.NFData column,-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Control.DeepSeq.NFData criterionWeight,+takeTurns :: forall pieceSquareValue positionHash randomGen x y. ( Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row,- Control.DeepSeq.NFData weightedMean, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y, Data.Array.IArray.Ix x,@@ -405,44 +379,28 @@ 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 criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean,- Integral column, Integral x, Integral y, Ord positionHash, Read x, Read y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Real weightedMean,- Show column, Show pieceSquareValue,- Show row, Show x, Show y, System.Random.RandomGen randomGen ) => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree x y positionHash -> randomGen- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)-{-# SPECIALISE takeTurns :: (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row,- Integral column,- Show column,- Show row,- System.Random.RandomGen randomGen- )- => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree T.X T.Y T.PositionHash+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y)+{-# SPECIALISE takeTurns+ :: System.Random.RandomGen randomGen+ => ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash -> randomGen- -> State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y- -> IO (State.PlayState.PlayState column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue row T.WeightedMean T.X T.Y)+ -> 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) #-} takeTurns positionHashQualifiedMoveTree randomGen playState = let options = State.PlayState.getOptions playState@@ -468,19 +426,19 @@ slave :: Maybe (Concurrent.Pondering.Pondering (Component.Move.Move x y))- -> Maybe Component.Move.NPlies+ -> Maybe Type.Count.NPlies -> [randomGen]- -> State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y- -> IO (State.PlayState.PlayState column criterionValue criterionWeight pieceSquareValue positionHash rankValue row weightedMean x y)+ -> State.PlayState.PlayState pieceSquareValue positionHash x y+ -> IO (State.PlayState.PlayState pieceSquareValue positionHash x y) slave maybePondering maybeMaximumPlies ~(randomGen' : randomGens) playState' = let (game', searchOptions') = State.PlayState.getGame &&& Input.Options.getSearchOptions . State.PlayState.getOptions $ playState' -- Deconstruct. in Data.Maybe.maybe ( do- startUTCTime <- Data.Time.Clock.getCurrentTime+ runningWatch <- Property.Switchable.on Data.Maybe.maybe ( do- playState'' <- readMove positionHashQualifiedMoveTree randomGen' startUTCTime playState' -- Block reading a command-sequence terminating in a move from a manual player.+ playState'' <- readMove positionHashQualifiedMoveTree randomGen' runningWatch playState' -- Block reading a command-sequence terminating in a move from a manual player. (,) playState'' `fmap` ( if playState' `State.PlayState.hasMorePlies` playState''@@ -527,7 +485,7 @@ bestTurn = Evaluation.QuantifiedGame.getLastTurn quantifiedGame showsMove = Notation.MoveNotation.showsNotation moveNotation bestTurn in do- elapsedTime <- bestTurn `seq` Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- bestTurn `seq` Property.Switchable.toggle runningWatch if verbosity == minBound then putStrLn $ showsMove "" -- CAVEAT: potentially machine-interpreted.@@ -537,20 +495,18 @@ then Property.ShowFloat.showsFloatToN nDecimalDigits ( Control.Monad.Reader.runReader ( Evaluation.Fitness.evaluateFitness Nothing game'- ) $ Input.Options.getEvaluationOptions options :: Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue+ ) $ Input.Options.getEvaluationOptions options :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues ) . Search.Search.showsSeparator -- Prepend the fitness of the original game prior to the new result. else id- ) $ (- if verbosity > Data.Default.def- then Notation.MoveNotation.showsNotationFloatToNDecimals moveNotation nDecimalDigits searchResult' . showString " in " . Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime- else showsMove- ) "."+ ) $ if verbosity > Data.Default.def+ then Notation.MoveNotation.showsNotationFloatToNDecimals moveNotation nDecimalDigits searchResult' . showString " in " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s."+ else showsMove "." putStrLn . show2D $ Evaluation.QuantifiedGame.getGame quantifiedGame (,) ( State.PlayState.updateWithAutomaticMove (- Attribute.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame+ Metric.WeightedMeanAndCriterionValues.getCriterionValues $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) searchState' playState' ) `fmap` if Input.SearchOptions.getUsePondering searchOptions then case continuation of@@ -573,7 +529,7 @@ ) ) ( \(qualifiedMove, names) -> do- elapsedTime <- Data.Time.measureElapsedTime startUTCTime+ stoppedWatch <- Property.Switchable.toggle runningWatch Data.Maybe.maybe ( return {-to IO-monad-} ()@@ -589,7 +545,7 @@ else do Control.Monad.when (verbosity > Data.Default.def) . System.IO.hPutStrLn System.IO.stderr . Text.ShowColouredPrefix.showsPrefixInfo . showString "selected " . Notation.MoveNotation.showsNotation moveNotation qualifiedMove . showString " from:" . ContextualNotation.QualifiedMoveForest.showsNames ( Input.IOOptions.getMaybeMaximumPGNNames ioOptions- ) names . showString "\n\tin " $ Data.Time.showsTimeAsSeconds nDecimalDigits elapsedTime "."+ ) names . showString "\n\tin " $ Property.ShowFloat.showsFloatToN nDecimalDigits stoppedWatch "s." putStrLn $ show2D selectedGame @@ -632,7 +588,7 @@ criterionValueStatistics = State.PlayState.calculateCriterionValueStatistics playState' showsFloat :: Double -> ShowS- showsFloat = Numeric.showFFloat $ Just nDecimalDigits+ showsFloat = Property.ShowFloat.showsFloatToN' nDecimalDigits Control.Monad.when ( verbosity == maxBound && not (null criterionValueStatistics)@@ -641,7 +597,7 @@ ) criterionValueStatistics "." readMove positionHashQualifiedMoveTree randomGen' (- Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.takeTurns.slave:\tundefined startUTCTime."+ Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.takeTurns.slave:\tundefined stop-watch." ) playState' {-there're zero valid moves, but the user can issue commands-} >>= slave Nothing maybeMaximumPlies randomGens -- Tail recurse. ) $ Model.Game.getMaybeTerminationReason game'@@ -649,7 +605,7 @@ Control.Monad.unless (verbosity == minBound) . putStrLn . show2D $ State.PlayState.getGame playState slave Nothing (Input.Options.getMaybeMaximumPlies options) (ToolShed.System.Random.randomGens randomGen) playState- ) `either` (- const . Control.Exception.throwIO $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.takeTurns:\tunexpected CECP-options."+ ) ||| const (+ Control.Exception.throwIO $ Data.Exception.mkInvalidDatum "BishBosh.UI.Raw.takeTurns:\tunexpected CECP-options." ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions
src-exe/Duel.hs view
@@ -75,26 +75,41 @@ ) . mkTypeSpecification $ Text.Case.toUpperInitial Input.Verbosity.tag ) . showString "define the log-level; default '" $ shows (Data.Default.def :: Input.Verbosity.Verbosity) "'.", let+ flag = "nDecimalDigits"+ in G.Option "d" [flag] (+ G.ReqArg (+ Just . (,) flag . Just &&& Input.CommandLineOption.mkOptionsMutator . Data.Options.setNDecimalDigits . Input.CommandLineOption.readBoundedIntegral+ ) $ mkTypeSpecification "Int"+ ) . showString "define the precision with which to display floating-point numbers; default " $ shows (Data.Options.getNDecimalDigits Data.Default.def) ".",+ let flag = "nGames" in G.Option "n" [flag] ( G.ReqArg ( Just . (,) flag . Just &&& Input.CommandLineOption.mkOptionsMutator . Data.Options.setNGames . Input.CommandLineOption.readBoundedIntegral ) $ mkTypeSpecification "Int"- ) "define the number of games to play.",+ ) . showString "define the number of games to play; default " $ shows (Data.Options.getNGames Data.Default.def) ".", let flag = "readTimeout" in G.Option "t" [flag] ( G.ReqArg ( Just . (,) flag . Just &&& Input.CommandLineOption.mkOptionsMutator . Data.Options.setReadTimeout . Input.CommandLineOption.readBoundedIntegral- ) $ mkTypeSpecification "s"+ ) $ mkTypeSpecification "Seconds" ) . showString "define the read-timeout; default " $ shows (Data.Options.getReadTimeout Data.Default.def) " s.", let+ flag = "verifyConfiguration"+ in G.Option "" [flag] (+ G.NoArg (+ Nothing {-N/A-},+ Input.CommandLineOption.mkOptionsMutator $ Data.Options.setVerifyConfiguration True+ )+ ) "verify the mutual compatibility of the two configuration-files before forwarding each to a forked instance of 'bishbosh'.",+ let flag = "appendInputConfigFilePath" in G.Option "i" [flag] ( G.ReqArg ( Just . (,) flag . Just &&& Input.CommandLineOption.mkOptionsMutator . Data.Options.appendInputConfigFilePath ) $ mkTypeSpecification "File-path"- ) . showString "define the path to an XML-file, to forward to an instance of bishbosh; " $ shows Data.Options.requiredInputConfigFiles " are required, White's first, then Black's."+ ) "define the path to an XML-file, to forward to a forked instance of 'bishbosh'; specify White's first, then Black's." ] where author :: String author = "Dr. Alistair Ward"@@ -119,3 +134,4 @@ (_, nonOptions, []) -> Control.Exception.throwIO . Data.Exception.mkRedundantData . showString "unexpected command-line arguments; " $ shows nonOptions "." (_, _, errors) -> Control.Exception.throwIO . Data.Exception.mkParseFailure $ concat errors ) . G.getOpt G.RequireOrder optDescrList+
src-exe/Duel/Data/Options.hs view
@@ -26,74 +26,91 @@ module Duel.Data.Options( -- * Types--- ** Type-synonyms- ReadTimeout, -- ** Data-types Options( -- MkOptions,- getVerbosity,+ getInputConfigFilePaths,+ getNDecimalDigits, getNGames, getReadTimeout,- getInputConfigFilePaths+ getVerbosity,+ getVerifyConfiguration ),--- * Constants- requiredInputConfigFiles, -- * Functions -- ** Mutators- setVerbosity,+ setNDecimalDigits, setNGames, setReadTimeout,+ setVerbosity,+ setVerifyConfiguration, appendInputConfigFilePath ) where import qualified Control.Exception import qualified Data.Default-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Input.Verbosity as Input.Verbosity-import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Input.Verbosity as Input.Verbosity+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Type.Count as Type.Count import qualified System.FilePath --- | The read-timeout in ms.-type ReadTimeout = Int---- | Container for all comand-line options.+-- | Container for all command-line options. data Options = MkOptions {+ getInputConfigFilePaths :: [System.FilePath.FilePath], -- ^ The configuration-file paths for White & Black respectively.+ getNDecimalDigits :: Type.Count.NDecimalDigits, -- ^ The precision with which floating-point quantities are diaplayed.+ getNGames :: Type.Count.NGames, -- ^ The number of successive games to play.+ getReadTimeout :: Type.Count.NSeconds, -- ^ The seconds to wait for a move before timing-out. CAVEAT: any positive value should account for both configuration-options (e.g. search-depth) & the machine-speed. getVerbosity :: Input.Verbosity.Verbosity, -- ^ The extent to which logging is required. CAVEAT: this isn't forwarded to the forked instances of BishBosh.- getNGames :: Model.Game.NGames, -- ^ The number of successive games to play.- getReadTimeout :: ReadTimeout, -- ^ The seconds to wait for a move before timing-out. CAVEAT: a positive value should account for both search-depth & the machine-speed.- getInputConfigFilePaths :: [System.FilePath.FilePath]+ getVerifyConfiguration :: Bool -- ^ Whether to check the configuration-files before forwarding them. } deriving (Eq, Show) instance Data.Default.Default Options where def = MkOptions {- getVerbosity = Data.Default.def,+ getInputConfigFilePaths = [], -- CAVEAT: invalid; there must be exactly 2.+ getNDecimalDigits = 0, getNGames = 1, getReadTimeout = -1, -- N.B.: a negative value is interpreted as an indefinite period.- getInputConfigFilePaths = []+ getVerbosity = Data.Default.def,+ getVerifyConfiguration = False } +instance Property.SelfValidating.SelfValidating Options where+ findInvalidity = Property.SelfValidating.findErrors [+ ((/= Attribute.LogicalColour.nDistinctLogicalColours) . fromIntegral . length . getInputConfigFilePaths, "There must be exactly one configuration file for White & one for Black.")+ ]+ -- | Mutator.-setVerbosity :: Input.Verbosity.Verbosity -> Options -> Options-setVerbosity verbosity options = options { getVerbosity = verbosity }+setNDecimalDigits :: Type.Count.NDecimalDigits -> Options -> Options+setNDecimalDigits nDecimalDigits options+ | nDecimalDigits < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "Duel.Data.Options:\tnDecimalDigits=" $ shows nDecimalDigits " mustn't be negative."+ | otherwise = options { getNDecimalDigits = nDecimalDigits } -- | Mutator.-setNGames :: Model.Game.NGames -> Options -> Options-setNGames n options- | n <= 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "Duel.Data.Options:\tnGames=" $ shows n " must exceed zero."- | otherwise = options { getNGames = n }+setNGames :: Type.Count.NGames -> Options -> Options+setNGames nGames options+ | nGames <= 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "Duel.Data.Options:\tnGames=" $ shows nGames " must exceed zero."+ | otherwise = options { getNGames = nGames } -- | Mutator.-setReadTimeout :: ReadTimeout -> Options -> Options+setReadTimeout :: Type.Count.NSeconds -> Options -> Options setReadTimeout t options = options { getReadTimeout = t } --- | The constant exact number of input config-files required.-requiredInputConfigFiles :: Int-requiredInputConfigFiles = 2+-- | Mutator.+setVerbosity :: Input.Verbosity.Verbosity -> Options -> Options+setVerbosity verbosity options = options { getVerbosity = verbosity } -- | Mutator.+setVerifyConfiguration :: Bool -> Options -> Options+setVerifyConfiguration b options = options { getVerifyConfiguration = b }++-- | Mutator. appendInputConfigFilePath :: System.FilePath.FilePath -> Options -> Options appendInputConfigFilePath s options- | length inputConfigFilePaths == requiredInputConfigFiles = Control.Exception.throw . Data.Exception.mkRedundantData . showString "Duel.Data.Options:\texactly " . shows requiredInputConfigFiles . showString " files are required:\t" $ shows inputConfigFilePaths "."- | otherwise = options { getInputConfigFilePaths = s : inputConfigFilePaths }+ | fromIntegral (+ length inputConfigFilePaths+ ) == Attribute.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkRedundantData . showString "Duel.Data.Options:\texactly " . shows Attribute.LogicalColour.nDistinctLogicalColours . showString " file-paths are required:\t" $ shows inputConfigFilePaths "."+ | otherwise = options { getInputConfigFilePaths = s : inputConfigFilePaths } where inputConfigFilePaths = getInputConfigFilePaths options+
src-exe/Duel/IO/Logger.hs view
@@ -61,3 +61,4 @@ System.IO.hGetLine handle >>= putString slave -- Recurse.+
+ src-exe/Duel/Process/Handles.hs view
@@ -0,0 +1,95 @@+{-+ 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@] Wraps "System.Process".+-}++module Duel.Process.Handles(+-- * Types+-- ** Data-types+ Handles(+-- MkHandles,+-- getStdIn,+-- getStdOut,+ getStdErr+-- getPId+ ),+-- * Functions+ cleanupHandles,+ showHandles,+-- ** Accessors+ getHandlePair,+-- ** Constructor+ mkHandles+) where++import qualified System.IO+import qualified System.Process++-- | A container for the IO-handles & process-id of a child process.+data Handles = MkHandles {+ getStdIn :: System.IO.Handle,+ getStdOut :: System.IO.Handle,+ getStdErr :: System.IO.Handle,+ getPId :: System.Process.ProcessHandle+}++-- | Constructor.+mkHandles :: String -> [String] -> IO Handles+mkHandles command args = do+ (stdIn, stdOut, stdErr, pId) <- System.Process.runInteractiveProcess command args Nothing Nothing++ sequence_ $ [+ (`System.IO.hSetBuffering` System.IO.LineBuffering),+ (`System.IO.hSetEncoding` System.IO.latin1)+ ] <*> [stdIn, stdOut]++ return {- to IO-monad -} MkHandles {+ getStdIn = stdIn,+ getStdOut = stdOut,+ getStdErr = stdErr,+ getPId = pId+ }++-- | Accessor.+getHandlePair :: Handles -> (System.IO.Handle, System.IO.Handle)+getHandlePair MkHandles {+ getStdIn = stdIn,+ getStdOut = stdOut+} = (stdIn, stdOut)++-- | Show the configuration of the IO-handles.+showHandles :: Handles -> IO [String]+showHandles MkHandles {+ getStdIn = stdIn,+ getStdOut = stdOut,+ getStdErr = stdErr+} = mapM System.IO.hShow [stdIn, stdOut, stdErr]++-- | Terminates the child-process & closes any IO-handles.+cleanupHandles :: Handles -> IO ()+cleanupHandles MkHandles {+ getStdIn = stdIn,+ getStdOut = stdOut,+ getStdErr = stdErr,+ getPId = pId+} = System.Process.cleanupProcess (Just stdIn, Just stdOut, Just stdErr, pId)+
src-exe/Duel/Process/Intermediary.hs view
@@ -21,7 +21,6 @@ [@AUTHOR@] Dr. Alistair Ward [@DESCRIPTION@] Starts the two bishbosh-processes & acts as an intermediary.- -} module Duel.Process.Intermediary (@@ -37,17 +36,30 @@ -- purge, -- startGame -- startProcess,+-- bracketProcess initialise ) where +import Control.Arrow((&&&), (|||))+import Control.Category((>>>)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.CommandLineOption as Input.CommandLineOption+import qualified BishBosh.Input.IOOptions as Input.IOOptions+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.GameTerminationReason as Model.GameTerminationReason+import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified BishBosh.Types as T+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason+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 Control.Exception import qualified Control.Monad@@ -56,10 +68,11 @@ import qualified Data.Maybe import qualified Duel.Data.Options as Data.Options import qualified Duel.IO.Logger as IO.Logger+import qualified Duel.Process.Handles as Process.Handles import qualified System.Exit import qualified System.FilePath import qualified System.IO-import qualified System.Process+import qualified Text.XML.HXT.Core as HXT #ifdef MOVE_NOTATION # if MOVE_NOTATION == 'I'@@ -82,7 +95,7 @@ runBishBosh :: Input.Verbosity.Verbosity -> System.FilePath.FilePath -- ^ The path to a configuration-file.- -> IO (System.IO.Handle, System.IO.Handle, System.IO.Handle, System.Process.ProcessHandle)+ -> IO Process.Handles.Handles runBishBosh verbosity configFilePath = let command = "bishbosh" args = [@@ -95,19 +108,23 @@ in do Control.Monad.when (verbosity > Data.Default.def) . IO.Logger.printInfo . showString "Starting command; " $ shows (command, args) "." - System.Process.runInteractiveProcess command args Nothing Nothing+ Process.Handles.mkHandles command args -- | Read either a move or a game-termination reason from the specified handle. readMove :: Input.Verbosity.Verbosity- -> Data.Options.ReadTimeout+ -> 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 Model.GameTerminationReason.GameTerminationReason (MoveNotation T.X T.Y))+ -> IO (Either Rule.GameTerminationReason.GameTerminationReason (MoveNotation Type.Length.X Type.Length.Y)) readMove verbosity readTimeout logicalColour stdOut = do- Control.Monad.when (verbosity == maxBound) . IO.Logger.printInfo . showString "Waiting for " $ shows logicalColour "."+ Control.Monad.when (verbosity == maxBound) . IO.Logger.printInfo . showString "Waiting " . (+ if readTimeout < 0+ then showString "indefinitely"+ else showString "for up to " . shows readTimeout . showString " s"+ ) . showString " for " $ shows logicalColour " to move." - inputReady <- System.IO.hWaitForInput stdOut $ 1000 * readTimeout+ inputReady <- System.IO.hWaitForInput stdOut $ 1000 * fromIntegral readTimeout Control.Monad.unless inputReady . Control.Exception.throwIO . Data.Exception.mkRequestFailure . showString "Duel.Process.Intermediary.readMove:\ttimed-out after " $ shows readTimeout " s." @@ -128,45 +145,45 @@ -- | Read either a move from the first handle & write it to the second. copyMove :: Input.Verbosity.Verbosity- -> Data.Options.ReadTimeout+ -> Type.Count.NSeconds -- ^ Read-timout. -> Attribute.LogicalColour.LogicalColour -- ^ Whose turn it is. -> System.IO.Handle -- ^ Output handle from which move should be read. -> System.IO.Handle -- ^ Input handle to which move should be forwarded.- -> IO (Maybe Model.GameTerminationReason.GameTerminationReason)+ -> IO (Maybe Rule.GameTerminationReason.GameTerminationReason) copyMove verbosity readTimeout logicalColour stdOut stdIn = do- readMove verbosity readTimeout logicalColour stdOut >>= (- return {-to IO-monad-} . Just- ) `either` (+ readMove verbosity readTimeout logicalColour stdOut >>= return {-to IO-monad-} . Just ||| ( \move -> do System.IO.hPrint stdIn move return {-to IO-monad-} Nothing ) --- | Contains stdin & stdout handles respectively.+-- | Contains /stdin/ & /stdout/ handles respectively. type IOHandles = (System.IO.Handle, System.IO.Handle) -- | Shuttle moves between the two child processes until the game terminates. play- :: Input.Verbosity.Verbosity- -> Data.Options.ReadTimeout+ :: Property.Switchable.Switchable gameClock+ => Input.Verbosity.Verbosity+ -> Type.Count.NSeconds -- ^ Read-timout. -> IOHandles -> IOHandles- -> IO Model.GameTerminationReason.GameTerminationReason+ -> gameClock+ -> IO (Rule.GameTerminationReason.GameTerminationReason, gameClock) play verbosity readTimeout = slave maxBound where- slave logicalColour producer@(_, stdOut) consumer@(stdIn', stdOut') = copyMove verbosity readTimeout logicalColour stdOut stdIn' >>= Data.Maybe.maybe (+ slave logicalColour producer@(_, stdOut) consumer@(stdIn', stdOut') gameClock = copyMove verbosity readTimeout logicalColour stdOut stdIn' >>= Data.Maybe.maybe ( do Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Swapping player-roles." - slave (Property.Opposable.getOpposite logicalColour) consumer producer -- Recurse.+ Property.Switchable.toggle gameClock >>= slave (Property.Opposable.getOpposite logicalColour) consumer producer -- Recurse. ) ( \gameTerminationReason -> do readMove verbosity readTimeout logicalColour stdOut' >>= ( \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- ) `either` (+ return {-to IO-monad-} (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 "'." ) )@@ -181,33 +198,42 @@ {- | * 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.Model.GameTerminationReason'.+ * 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 Model.GameTerminationReason.GameTerminationReason Int+type GameTerminationReasonsMap = Data.Map.Strict.Map Rule.GameTerminationReason.GameTerminationReason Type.Count.NGames {- |- * Start two independently configured (though of matching move-notation) instances of 'bishbosh'.+ * Constructs a game-clock. + * Starts two independently configured (though of matching move-notation) concurrent instances of 'bishbosh'.+ * One instance automates White & one automates Black. * Shuttle moves between the instances. - * Plays repeatedly & accumulating the final results of each game.+ * 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. -} startGame :: Input.Verbosity.Verbosity- -> Data.Options.ReadTimeout- -> IOHandles -- ^ White's handles.- -> IOHandles -- ^ Black's handles.+ -> Type.Count.NDecimalDigits+ -> Type.Count.NSeconds -- ^ Read-timeout.+ -> IOHandles -- ^ White's handles.+ -> IOHandles -- ^ Black's handles. -> GameTerminationReasonsMap- -> Model.Game.NGames+ -> Type.Count.NGames -> IO GameTerminationReasonsMap-startGame verbosity readTimeout producer consumer = slave where- slave gameTerminationReasonsMap 0 = return {-to IO-monad-} gameTerminationReasonsMap- slave gameTerminationReasonsMap nGames = do+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+ Time.GameClock.showsElapsedTimes nDecimalDigits gameClock >>= IO.Logger.printInfo . showString "Elapsed time" . Text.ShowList.showsAssociation . ($ ".")++ return {-to IO-monad-} gameTerminationReasonsMap'+ slave gameTerminationReasonsMap' nGames' gameClock = do Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Starting game." - gameTerminationReason <- play verbosity readTimeout producer consumer+ (gameTerminationReason, gameClock') <- play verbosity readTimeout producer consumer gameClock sequence_ $ [ \(_, stdOut) -> do@@ -221,58 +247,91 @@ ] <*> [consumer, producer] slave (- Data.Map.Strict.insertWith (const succ) gameTerminationReason 1 gameTerminationReasonsMap- ) $ pred nGames -- Recurse.+ Data.Map.Strict.insertWith (const succ) gameTerminationReason 1 gameTerminationReasonsMap'+ ) (+ pred nGames' -- Recurse.+ ) gameClock' --- | Start 'bishbosh', print any errors, unbuffer its I/O, & return the process-handles.+-- | Start 'bishbosh', print any errors, & return the process-handles. startProcess :: Input.Verbosity.Verbosity -> System.FilePath.FilePath -- ^ The path to a configuration-file.- -> IO (System.IO.Handle, System.IO.Handle, System.IO.Handle, System.Process.ProcessHandle)+ -> IO Process.Handles.Handles startProcess verbosity configFilePath = do- handles@(stdIn, stdOut, stdErr, _) <- runBishBosh verbosity configFilePath-- IO.Logger.dump stdErr+ handles <- runBishBosh verbosity configFilePath - sequence_ $ [- (`System.IO.hSetBuffering` System.IO.LineBuffering),- (`System.IO.hSetEncoding` System.IO.latin1)- ] <*> [stdIn, stdOut]+ IO.Logger.dump $ Process.Handles.getStdErr handles - Control.Monad.when (verbosity == maxBound) $ mapM System.IO.hShow [stdIn, stdOut, stdErr] >>= IO.Logger.printInfo . show+ Control.Monad.when (verbosity == maxBound) $ Process.Handles.showHandles handles >>= mapM_ IO.Logger.printInfo return {-to IO-monad-} handles --- | Play the requested number of games & display the accumulated results.+-- | Starts the process, performs the requested action, then clean-up.+bracketProcess+ :: Input.Verbosity.Verbosity+ -> [System.FilePath.FilePath] -- ^ The configuration-file paths for White & Black respectively.+ -> ([Process.Handles.Handles] -> IO ()) -- ^ Run the game.+ -> IO ()+bracketProcess verbosity inputConfigFilePaths = Control.Exception.bracket (+ startProcess verbosity `mapM` inputConfigFilePaths+ ) (+ sequence . (+ [+ IO.Logger.dump . Process.Handles.getStdErr,+ Process.Handles.cleanupHandles+ ] <*>+ )+ )++{- |+ * Unpacks the configuration-options.++ * Optionally verifies the compatibility of the two configuration-files.++ * Plays the requested number of games.++ * Prints the results.+-} initialise :: Data.Options.Options -> IO ()-initialise options = let- verbosity = Data.Options.getVerbosity options- in Control.Exception.catch (- Control.Exception.bracket (- startProcess verbosity `mapM` Data.Options.getInputConfigFilePaths options- ) (- \processes@[(_, _, stdErr, _), (_, _, stdErr', _)] -> do- mapM_ IO.Logger.dump [stdErr, stdErr']+initialise options+ | errorMessages@(_ : _) <- Property.SelfValidating.findInvalidity options = Control.Exception.throwIO . Data.Exception.mkInsufficientData . showString "Duel.Process.Intermediary.initialise:\tinvalid options; " $ show errorMessages+ | otherwise = let+ (verbosity, inputConfigFilePaths) = Data.Options.getVerbosity &&& Data.Options.getInputConfigFilePaths $ options+ hxtTraceLevel = fromEnum verbosity `min` 2 {-CAVEAT: HXT trace-levels 3 & 4 are too verbose-}+ in Control.Exception.catch (+ do+ Control.Monad.when (Data.Options.getVerifyConfiguration options) $ do+ [(logicalColoursFirst, moveNotationFirst), (logicalColoursSecond, moveNotationSecond)] <- mapM (+ \configFilePath -> do+ [pair] <- HXT.runX $ HXT.setTraceLevel hxtTraceLevel+ >>> HXT.xunpickleDocument HXT.xpickle [+ HXT.withRemoveWS HXT.yes,+ 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.+ )+ ) -- Lift function into an arrow. - Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Cleaning-up child processes."+ return {-to IO-monad-} pair+ ) inputConfigFilePaths - mapM_ (- \(hIn, hOut, hErr, pId) -> System.Process.cleanupProcess (Just hIn, Just hOut, Just hErr, pId)- ) processes- ) (- \[(stdIn, stdOut, _, _), (stdIn', stdOut', _, _)] -> startGame verbosity (- Data.Options.getReadTimeout options- ) (- stdIn, stdOut- ) (- stdIn', stdOut'- ) Data.Map.Strict.empty (- Data.Options.getNGames options- ) >>= IO.Logger.printInfo . show . Data.Map.Strict.toList- )- ) $ \e -> do- IO.Logger.printError . showString "caught " $ show (e :: Control.Exception.SomeException)+ Control.Monad.unless (logicalColoursFirst == [maxBound] && logicalColoursSecond == [minBound]) . Control.Exception.throwIO . Data.Exception.mkIncompatibleData . showString "Duel.Process.Intermediary.initialise:\tconfiguration-files must automate White & Black respectively; " $ shows (logicalColoursFirst ++ logicalColoursSecond) "." - Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Exiting."+ 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) "." - System.Exit.exitFailure+ 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 (+ Data.Options.getNGames options+ ) >>= IO.Logger.printInfo . show . Data.Map.Strict.toList+ ) $ \e -> do+ IO.Logger.printError . showString "caught " $ show (e :: Control.Exception.SomeException)++ Control.Monad.when (verbosity == maxBound) $ IO.Logger.printInfo "Exiting."++ System.Exit.exitFailure+
src-exe/Main.hs view
@@ -29,9 +29,8 @@ module Main(main) where -import BishBosh.Data.Float()--- import BishBosh.Data.Ratio() -- Required if either criterionWeight or criterionValue is Rational.-import Control.Arrow((&&&), (***))+--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((!)) import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank@@ -58,14 +57,16 @@ 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.Types as T+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 import qualified Data.Default import qualified Data.List import qualified Data.Maybe import qualified Data.Version-import qualified Numeric import qualified Paths_bishbosh as Paths -- Either local stub, or package-instance auto-generated by 'Setup build'. import qualified System.Console.GetOpt as G import qualified System.Directory@@ -81,10 +82,6 @@ import qualified ToolShed.System.File import System.FilePath((</>), (<.>)) -#ifdef USE_NARROW_NUMBERS-import BishBosh.Data.Integral() -- HXT.XmlPickler.-#endif- #ifdef USE_HXTRELAXNG import qualified Text.XML.HXT.RelaxNG #endif@@ -98,9 +95,7 @@ #endif -- Define concrete types to resolve the underlying polymorphic functions.-type Row = T.Y-type Column = T.X -- N.B. there's no requirement to be the same type as Row.-type Options = Input.Options.Options Column T.CriterionWeight T.PieceSquareValue T.RankValue Row T.X T.Y+type Options = Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y writeXMLToFile :: HXT.XmlPickler pickleable@@ -232,9 +227,9 @@ mkTypeSpecification s = showChar '<' $ showString s ">" intTypeSpecification, filePathTypeSpecification :: String- (intTypeSpecification, filePathTypeSpecification) = ($ intString) &&& ($ filePathString) $ mkTypeSpecification+ (intTypeSpecification, filePathTypeSpecification) = ($ intString) &&& ($ filePathString) $ mkTypeSpecification - defaultUIOptions :: Input.UIOptions.UIOptions Row Column+ defaultUIOptions :: Input.UIOptions.UIOptions defaultUIOptions = Data.Default.def defaultRandomSeed :: Input.Options.RandomSeed@@ -282,7 +277,7 @@ ) ["Opening", "End"] ) $ map ( \selector -> Component.PieceSquareByCoordinatesByRank.formatForGNUPlot (- Numeric.showFFloat . Just . 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. ) ( showChar '\t' -- Column-delimiter. ) (@@ -331,17 +326,6 @@ configDir :: System.FilePath.FilePath configDir = dataDir </> "config" - inputSysConfigList :: HXT.SysConfigList- inputSysConfigList = [- HXT.withRemoveWS HXT.yes, -- Remove white-space, e.g. any indentation which might have been introduced by 'HXT.withIndent'.- HXT.withStrictInput HXT.yes, -- Read the input file strictly (cf. lazily), this ensures file-closure even if not completely read.-#ifdef USE_HXTRELAXNG- Text.XML.HXT.RelaxNG.withRelaxNG $ configDir </> progName <.> "rng" -- Validate against the referenced RelaxNG schema.-#else- HXT.withValidate HXT.yes -- Validate against any DTD referenced from the specified XML-file.-#endif- ]- hxtTraceLevel :: Int hxtTraceLevel = fromEnum preVerbosity `min` 2 {-CAVEAT: HXT trace-levels 3 & 4 are too verbose-} @@ -365,7 +349,7 @@ (showsInfoPrefix, showsWarningPrefix) = const ( Text.ShowColouredPrefix.showsPrefixInfo, Text.ShowColouredPrefix.showsPrefixWarning- ) `either` const (+ ) ||| const ( Text.ShowPrefix.showsPrefixInfo, Text.ShowPrefix.showsPrefixWarning ) $ Input.UIOptions.getEitherNativeUIOrCECPOptions uiOptions@@ -423,14 +407,16 @@ ) executablePath in ( \pgnDatabase -> do- Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . showsInfoPrefix . showString "read PGN-database" . Text.ShowList.showsAssociation . shows pgnDatabaseFilePath . showString " containing (nGames, nMoves)" . Text.ShowList.showsAssociation $ shows (+ Control.Monad.when (verbosity == maxBound) . System.IO.hPutStrLn System.IO.stderr . showsInfoPrefix . showString "read PGN-database" . Text.ShowList.showsAssociation . shows pgnDatabaseFilePath . showString " containing (nGames, nPositions)" . Text.ShowList.showsAssociation $ shows ( Data.List.foldl' ( \acc pgn -> let- acc'@(nGames, nPlies) = succ *** (- + State.TurnsByLogicalColour.getNPlies (Model.Game.getTurnsByLogicalColour $ ContextualNotation.PGN.getGame pgn)+ acc'@(nGames, nPositions) = succ *** (+ + State.TurnsByLogicalColour.getNPlies (+ Model.Game.getTurnsByLogicalColour $ ContextualNotation.PGN.getGame pgn+ ) ) $ acc- in nGames `seq` nPlies `seq` acc'- ) (0 :: Model.Game.NGames, 0) pgnDatabase+ in nGames `seq` nPositions `seq` acc'+ ) (0 :: Type.Count.NGames, 0) pgnDatabase ) "." -- CAVEAT: this stalls rendering of the native UI. return {-to IO-monad-} $ ContextualNotation.QualifiedMoveForest.mergePGNDatabase pgnDatabase qualifiedMoveForest@@ -460,16 +446,24 @@ ) Property.Empty.empty {-QualifiedMoveForest-} (Input.IOOptions.getPGNOptionsList ioOptions) let- maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Column T.CriterionValue T.CriterionWeight T.PieceSquareValue T.PositionHash T.RankValue Row T.WeightedMean T.X T.Y)+ maybeApplicationTerminationReason = State.PlayState.getMaybeApplicationTerminationReason (playState :: State.PlayState.PlayState Type.Mass.PieceSquareValue Type.Crypto.PositionHash Type.Length.X Type.Length.Y) 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) "." return {-to IO-monad-} options' in Control.Monad.void {-discard the state returned by processInputOptions-} . HXT.runX $ HXT.setTraceLevel hxtTraceLevel- >>> HXT.xunpickleDocument HXT.xpickle inputSysConfigList configFilePath+ >>> HXT.xunpickleDocument HXT.xpickle [+ HXT.withRemoveWS HXT.yes, -- Remove white-space, e.g. any indentation which might have been introduced by 'HXT.withIndent'.+ HXT.withStrictInput HXT.yes, -- Read the input file strictly (cf. lazily), this ensures file-closure even if not completely read.+#ifdef USE_HXTRELAXNG+ Text.XML.HXT.RelaxNG.withRelaxNG $ configDir </> progName <.> "rng" -- Validate against the referenced RelaxNG schema.+#else+ HXT.withValidate HXT.yes -- Validate against any DTD referenced from the specified XML-file.+#endif+ ] configFilePath >>> HXT.traceMsg hxtTraceLevel (showString Input.Options.tag " parsed")- >>> HXT.arrIO processInputOptions+ >>> HXT.arrIO processInputOptions -- Lift an IO-function into an arrow. | otherwise -> Control.Exception.throwIO . Data.Exception.mkInsufficientData $ shows (Input.CommandLineOption.longFlagPrefix ++ inputConfigFilePathFlag) " must be specified." where categorisedCommandLineOptions = Input.CommandLineOption.categorise $ map snd commandLineOptions
− src-lib/BishBosh/Attribute/CriterionValue.hs
@@ -1,109 +0,0 @@-{-# LANGUAGE CPP #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines the value of a single /criterion/, which quantifies the significance of some concept;- many such criteria may exist, & their weighted-mean drives automated selection of /move/s.-- * Each /criterion-value/ is normalised into the /signed closed unit-interval/.-- [@CAVEAT@]-- * While this data-type could implement the classes 'Num', 'Fractional' & 'Real', these interfaces would allow one to construct invalid instances.--}--module BishBosh.Attribute.CriterionValue(--- * Types--- ** Data-types- CriterionValue(),--- * Constants- zero,--- * Functions- calculateWeightedMean,--- ** Constructor- mkCriterionValue-) where--import Control.Arrow((&&&))-import qualified BishBosh.Attribute.CriterionWeight as Attribute.CriterionWeight-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues-import qualified BishBosh.Types as T-import qualified Control.Exception-import qualified Factory.Math.Statistics--#ifdef USE_PARALLEL-import qualified Control.DeepSeq-import qualified Control.Parallel.Strategies-#endif---- | Quantifies some criterion; the larger the signed value, the better.-newtype CriterionValue criterionValue = MkCriterionValue criterionValue deriving (Eq, Show)--instance Num criterionValue => Bounded (CriterionValue criterionValue) where- minBound = MkCriterionValue $ negate 1- maxBound = MkCriterionValue 1---- | Smart constructor.-mkCriterionValue :: (- Num criterionValue,- Ord criterionValue- ) => criterionValue -> CriterionValue criterionValue-mkCriterionValue criterionValue = Control.Exception.assert (abs criterionValue <= 1) $ MkCriterionValue criterionValue---- | Constant.-zero :: Num criterionValue => CriterionValue criterionValue-zero = MkCriterionValue 0--{- |- * Calculates the /weighted mean/ of the specified 'CriterionValue's using the corresponding /criterion-weight/s.-- * Also writes individual unweighted 'CriterionValue's, to facilitate post-analysis;- if the corresponding weight is @0@, evaluation of the criterion is, for efficiency, avoided.-- * CAVEAT: if all weights are @0@, then the result is indeterminate.--}-calculateWeightedMean :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Fractional weightedMean,- Real criterionValue,- Real criterionWeight- ) => [(CriterionValue criterionValue, Attribute.CriterionWeight.CriterionWeight criterionWeight)] -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue-{-# INLINABLE calculateWeightedMean #-}-{-# SPECIALISE calculateWeightedMean :: [(CriterionValue T.CriterionValue, Attribute.CriterionWeight.CriterionWeight T.CriterionWeight)] -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues T.WeightedMean T.CriterionValue #-}-calculateWeightedMean assocs = uncurry Attribute.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues $ (- Factory.Math.Statistics.getWeightedMean &&& map fst- )-#ifdef USE_PARALLEL- $ Control.Parallel.Strategies.withStrategy (- Control.Parallel.Strategies.parList $ Control.Parallel.Strategies.evalTuple2 Control.Parallel.Strategies.rdeepseq Control.Parallel.Strategies.r0- )-#endif- [- (bareCriterionValue, bareCriterionWeight) |- (MkCriterionValue bareCriterionValue, criterionWeight) <- assocs,- let bareCriterionWeight = Attribute.CriterionWeight.deconstruct criterionWeight,- bareCriterionWeight /= 0- ] -- List-comprehension.-
− src-lib/BishBosh/Attribute/CriterionWeight.hs
@@ -1,90 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines the weight associated with some 'Attribute.CriterionValue.CriterionValue'.-- * Each weighting is constrained to the unsigned /closed unit-interval/; negative values aren't permitted.-- * If the /criterion-value/ is considered unimportant, then its weight can be set to @0@, whilst concepts of great significance can be set to @1@.-- [@CAVEAT@]-- * While this data-type could implement the classes 'Functor', 'Num', 'Fractional' & 'Real', these interfaces allow one to construct invalid instances.--}--module BishBosh.Attribute.CriterionWeight(--- * Types--- ** Data-types- CriterionWeight(--- MkCriterionWeight,- deconstruct- ),--- * Functions--- ** Constructor- mkCriterionWeight-) where--import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Data.Num as Data.Num-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified Control.DeepSeq-import qualified Control.Exception-import qualified Data.Default-import qualified Text.XML.HXT.Arrow.Pickle as HXT---- | Quantifies the relative significance, of a criterion-value; the larger the weight, the more significant the criterion is relative to other criteria.-newtype CriterionWeight criterionWeight = MkCriterionWeight {- deconstruct :: criterionWeight-} deriving (Eq, Ord)--instance Show criterionWeight => Show (CriterionWeight criterionWeight) where- showsPrec _ (MkCriterionWeight criterionWeight) = shows criterionWeight--instance Num criterionWeight => Bounded (CriterionWeight criterionWeight) where- minBound = MkCriterionWeight 0- maxBound = MkCriterionWeight 1--instance Num criterionWeight => Data.Default.Default (CriterionWeight criterionWeight) where- def = minBound--instance Control.DeepSeq.NFData criterionWeight => Control.DeepSeq.NFData (CriterionWeight criterionWeight) where- rnf (MkCriterionWeight criterionWeight) = Control.DeepSeq.rnf criterionWeight--instance (- HXT.XmlPickler criterionWeight,- Num criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => HXT.XmlPickler (CriterionWeight criterionWeight) where- xpickle = HXT.xpWrap (mkCriterionWeight, deconstruct) HXT.xpickle---- | Smart constructor.-mkCriterionWeight :: (- Num criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => criterionWeight -> CriterionWeight criterionWeight-mkCriterionWeight criterionWeight- | Data.Num.inClosedUnitInterval criterionWeight = MkCriterionWeight criterionWeight- | otherwise = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Attribute.CriterionWeight.mkCriterionWeight:\tweight" . Text.ShowList.showsAssociation $ shows criterionWeight " must be within the closed unit-interval, '[0,1]'."-
src-lib/BishBosh/Attribute/Direction.hs view
@@ -32,7 +32,6 @@ module BishBosh.Attribute.Direction( -- * Types -- ** Type-synonyms- NDirections, ArrayByDirection, -- ** Data-types Direction(@@ -73,6 +72,7 @@ import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.Orientated as Property.Orientated import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray@@ -116,9 +116,6 @@ se :: Direction se = MkDirection GT LT --- | A number of /direction/s.-type NDirections = Int -- N.B.: 'Data.Int.Int8' saves neither time nor space.- -- | 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.@@ -224,7 +221,7 @@ instance Property.FixedMembership.FixedMembership Direction where members = range --- | Smart-constructor.+-- | Smart constructor. mkDirection :: Ordering -- ^ The sense of the change in the /x/-coordinate. -> Ordering -- ^ The sense of the change in the /y/-coordinate.@@ -241,8 +238,8 @@ diagonals = [sw, nw, se, ne] -- | The constant number of distinct /direction/s.-nDistinctDirections :: NDirections-nDistinctDirections = length range+nDistinctDirections :: Type.Count.NDirections+nDistinctDirections = fromIntegral $ length range {- | * Returns a list of /direction/s, each paired with its anti-parallel.
src-lib/BishBosh/Attribute/LogicalColour.hs view
@@ -51,6 +51,7 @@ import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ForsythEdwards as Property.ForsythEdwards import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray@@ -92,8 +93,8 @@ members = range -- | The constant number of distinct /logical colour/s.-nDistinctLogicalColours :: Int-nDistinctLogicalColours = length range+nDistinctLogicalColours :: Type.Count.NLogicalColours+nDistinctLogicalColours = fromIntegral $ length range instance HXT.XmlPickler LogicalColour where xpickle = HXT.xpAttr tag . HXT.xpWrap (read, show) . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range
src-lib/BishBosh/Attribute/LogicalColourOfSquare.hs view
@@ -56,3 +56,4 @@ -- | Whether the specified /logical colour/ is @Black@. isBlack :: LogicalColourOfSquare -> Bool isBlack MkLogicalColourOfSquare { deconstruct = logicalColour } = Attribute.LogicalColour.isBlack logicalColour+
src-lib/BishBosh/Attribute/MoveType.hs view
@@ -170,7 +170,7 @@ maybePromotionRank <- Nothing : map Just Attribute.Rank.promotionProspects ] -- List-comprehension. --- | Smart-constructor for normal move-types.+-- | Smart constructor for normal move-types. mkMaybeNormalMoveType :: Maybe Attribute.Rank.Rank -- ^ The /rank/ of any opposing /piece/ which was just taken. -> Maybe Attribute.Rank.Rank -- ^ The /rank/ to which a @Pawn@ was just promoted.
src-lib/BishBosh/Attribute/Rank.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LambdaCase #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -31,7 +30,6 @@ -- * Types -- ** Type-synonyms EvaluateRank,--- NRanks, ArrayByRank, UArrayByRank, -- ** Data-types@@ -51,6 +49,7 @@ earthBound, expendable, nDistinctRanks,+-- allocationPerSide, -- * Functions compareByLVA, findUndefinedRanks,@@ -59,7 +58,9 @@ arrayByRank ) where +import qualified BishBosh.Metric.RankValue as Metric.RankValue import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray@@ -104,17 +105,16 @@ index (lower, upper) = Control.Exception.assert (lower == minBound && upper == maxBound) . fromEnum instance Show Rank where- showsPrec _ = showChar . \case- Pawn -> 'p'- Rook -> 'r'- Knight -> 'n'- Bishop -> 'b'- Queen -> 'q'- King -> 'k'+ show Pawn = "p"+ show Rook = "r"+ show Knight = "n"+ show Bishop = "b"+ show Queen = "q"+ show King = "k" instance Read Rank where- readsPrec _ (c : s)- | Data.Char.isSpace c = reads s -- Consume.+ readsPrec precedence (c : s)+ | Data.Char.isSpace c = readsPrec precedence s -- Consume. | otherwise = map (flip (,) s) $ case Data.Char.toLower c of 'p' -> [Pawn] 'r' -> [Rook]@@ -180,7 +180,7 @@ expendable = Data.List.delete King range -- | The type of a function which returns a /rank/'s value.-type EvaluateRank rankValue = Rank -> rankValue+type EvaluateRank = Rank -> Metric.RankValue.RankValue {- | * Given two alternative capture moves, this function compares the rank-value of the aggressors.@@ -188,8 +188,7 @@ * N.B.: a @King@ is always considered most valuable, regardless of the evaluation-function supplied. -} compareByLVA- :: Ord rankValue- => EvaluateRank rankValue+ :: EvaluateRank -> Rank -> Rank -> Ordering@@ -199,12 +198,13 @@ | rankR == King = LT | otherwise = Data.Ord.comparing evaluateRank rankL rankR --- | A number of ranks.-type NRanks = Int- -- | The constant number of distinct /rank/s.-nDistinctRanks :: NRanks-nDistinctRanks = length range+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] -- | A boxed array indexed by /rank/, of arbitrary values. type ArrayByRank = Data.Array.IArray.Array Rank
− src-lib/BishBosh/Attribute/RankValues.hs
@@ -1,142 +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@]-- * The relative values of the various /rank/s of chess-piece.-- * <https://en.wikipedia.org/wiki/Chess_piece_relative_value#Hans_Berliner.27s_system%20Chess-piece%20relative%20values>--}--module BishBosh.Attribute.RankValues(--- * Types--- ** Data-types- RankValues(),--- * Constants- tag,--- * Functions- findRankValue,- calculateMaximumTotalValue,--- ** Constructor- fromAssocs-) where--import Control.Arrow((&&&), (***))-import Data.Array.IArray((!))-import qualified BishBosh.Attribute.Rank as Attribute.Rank-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.ShowFloat as Property.ShowFloat-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified Control.Arrow-import qualified Control.DeepSeq-import qualified Control.Exception-import qualified Data.Array.IArray-import qualified Data.Default-import qualified Data.List-import qualified Text.XML.HXT.Arrow.Pickle as HXT---- | Used to qualify XML.-tag :: String-tag = "rankValues"--{- |- * The constant value associated with each /rank/; the higher, the more valuable it is considered to be.-- * N.B.: only relative values are significant; the absolute value associated with any /rank/ is irrelevant; typically ranks are valued in /centipawns/.-- * CAVEAT: a @King@ can never be taken, but assigning the value /infinity/ creates problems, so typically it has the value @0@.--}-newtype RankValues rankValue = MkRankValues {- deconstruct :: Attribute.Rank.ArrayByRank rankValue-} deriving (Eq, Read, Show)--instance Real rankValue => Property.ShowFloat.ShowFloat (RankValues rankValue) where- showsFloat fromDouble = Text.ShowList.showsAssociationList' . map (show *** fromDouble . realToFrac) . Data.Array.IArray.assocs . deconstruct--instance (- Fractional rankValue,- Ord rankValue,- Show rankValue- ) => Data.Default.Default (RankValues rankValue) where- def = fromAssocs $ map (- Control.Arrow.second (/ 10) -- Map into the closed unit-interval.- ) [- (- Attribute.Rank.Pawn, 1- ), (- Attribute.Rank.Rook, 5- ), (- Attribute.Rank.Knight, 3- ), (- Attribute.Rank.Bishop, 3- ), (- Attribute.Rank.Queen, 9- ), (- Attribute.Rank.King, 0 -- N.B.: move-selection is independent of this value (since it can't be taken), so it can be defined arbitrarily.- )- ]--instance Control.DeepSeq.NFData rankValue => Control.DeepSeq.NFData (RankValues rankValue) where- rnf (MkRankValues byRank) = Control.DeepSeq.rnf byRank--instance (- Fractional rankValue,- HXT.XmlPickler rankValue,- Ord rankValue,- Show rankValue- ) => HXT.XmlPickler (RankValues rankValue) where- xpickle = HXT.xpDefault Data.Default.def . HXT.xpWrap (- fromAssocs, -- Construct from an association-list.- Data.Array.IArray.assocs . deconstruct -- Deconstruct to an association-list.- ) . HXT.xpList1 . HXT.xpElem tag $ HXT.xpickle {-rank-} `HXT.xpPair` HXT.xpAttr "value" HXT.xpickle---- | Smart-constructor.-fromAssocs :: (- Fractional rankValue,- Ord rankValue,- Show rankValue- ) => [(Attribute.Rank.Rank, rankValue)] -> RankValues rankValue-fromAssocs assocs- | not $ null undefinedRanks = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.Attribute.RankValues.fromAssocs:\tranks" . Text.ShowList.showsAssociation $ shows undefinedRanks " are undefined."- | not $ null duplicateRanks = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Attribute.RankValues.fromAssocs:\tranks must be distinct; " $ shows duplicateRanks "."- | not $ all (- Data.Num.inClosedUnitInterval . snd {-rank-value-}- ) assocs = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Attribute.RankValues.fromAssocs:\tall values must be within the closed unit-interval, [0,1]; " $ shows assocs "."- | otherwise = MkRankValues $ Attribute.Rank.arrayByRank assocs- where- (undefinedRanks, duplicateRanks) = Attribute.Rank.findUndefinedRanks &&& Data.Foldable.findDuplicates $ map fst assocs---- | Query.-findRankValue :: Attribute.Rank.Rank -> RankValues rankValue -> rankValue-findRankValue rank (MkRankValues byRank) = byRank ! rank--{- |- * The maximum total rank-value one side can have.-- * CAVEAT: assumes that zero pieces have been captured, all @Pawn@s have been queened, & that this is the most valuable /rank/ of /piece/.--}-calculateMaximumTotalValue :: Num rankValue => RankValues rankValue -> rankValue-calculateMaximumTotalValue (MkRankValues byRank) = 9 {-accounting for all possible promotions-} * (byRank ! Attribute.Rank.Queen) + 2 * Data.List.foldl' (- \acc -> (+ acc) . (byRank !)- ) 0 Attribute.Rank.flank-
− src-lib/BishBosh/Attribute/WeightedMeanAndCriterionValues.hs
@@ -1,83 +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@] The unweighted values of each criterion used to assess the fitness of a position, & the resulting weighted mean.--}--module BishBosh.Attribute.WeightedMeanAndCriterionValues(--- * Types--- ** Data-types- WeightedMeanAndCriterionValues(--- MkWeightedMeanAndCriterionValues,- getWeightedMean,- getCriterionValues- ),--- * Constants- criterionValuesTag,- weightedMeanTag,--- * Functions- negateWeightedMean,--- ** Constructor- mkWeightedMeanAndCriterionValues-) where--import qualified BishBosh.Property.ShowFloat as Property.ShowFloat-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified Control.DeepSeq---- | Qualifies output.-criterionValuesTag :: String-criterionValuesTag = "criterion-values"---- | Qualifies output.-weightedMeanTag :: String-weightedMeanTag = "weighted-mean"---- | A /weighted mean/ & the individual unweighted criterion-values from which it was composed.-data WeightedMeanAndCriterionValues weightedMean criterionValue = MkWeightedMeanAndCriterionValues {- getWeightedMean :: weightedMean, -- ^ The weighted mean of a list of criterion-values.- getCriterionValues :: [criterionValue] -- ^ The unweighted 'Attribute.CriterionValue.CriterionValue's from which the weighted mean was composed.-} deriving (Eq, Show)--instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (WeightedMeanAndCriterionValues weightedMean criterionValue) where- rnf MkWeightedMeanAndCriterionValues { getWeightedMean = weightedMean } = Control.DeepSeq.rnf weightedMean -- The other field is a prerequisite.--instance (Real criterionValue, Real weightedMean) => Property.ShowFloat.ShowFloat (WeightedMeanAndCriterionValues weightedMean criterionValue) where- showsFloat fromDouble MkWeightedMeanAndCriterionValues {- getWeightedMean = weightedMean,- getCriterionValues = criterionValues- } = Text.ShowList.showsAssociationList' [- (weightedMeanTag, fromDouble $ realToFrac weightedMean),- (criterionValuesTag, Text.ShowList.showsFormattedList' (fromDouble . realToFrac) criterionValues)- ]---- | Constructor.-mkWeightedMeanAndCriterionValues :: weightedMean -> [criterionValue] -> WeightedMeanAndCriterionValues weightedMean criterionValue-mkWeightedMeanAndCriterionValues = MkWeightedMeanAndCriterionValues--{- |- * Negate the /weightedMean/, but leave the criterion-values unaltered.-- * This can be used to assess the fitness of a position from the perspective of one's opponent.--}-negateWeightedMean :: Num weightedMean => WeightedMeanAndCriterionValues weightedMean criterionValue -> WeightedMeanAndCriterionValues weightedMean criterionValue-negateWeightedMean weightedMeanAndCriterionValues@MkWeightedMeanAndCriterionValues { getWeightedMean = weightedMean } = weightedMeanAndCriterionValues { getWeightedMean = negate weightedMean }-
src-lib/BishBosh/Cartesian/Abscissa.hs view
@@ -52,7 +52,7 @@ ) where import qualified BishBosh.Data.Enum as Data.Enum-import qualified BishBosh.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Array.IArray @@ -61,7 +61,7 @@ xOrigin = 0 -- | The constant length of the /x/-axis.-xLength :: T.Distance+xLength :: Type.Length.Distance xLength = 8 -- | The constant lower bound of abscissae.
src-lib/BishBosh/Cartesian/Coordinates.hs view
@@ -92,7 +92,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Array.IArray@@ -122,7 +122,7 @@ rnf MkCoordinates { getX = x, getY = y } = Control.DeepSeq.rnf (x, y) instance (Show x, Show y) => Show (Coordinates x y) where- showsPrec _ MkCoordinates { getX = x, getY = y } = shows (x, y)+ showsPrec precedence MkCoordinates { getX = x, getY = y } = showsPrec precedence (x, y) instance ( Enum x,@@ -132,14 +132,14 @@ Read x, Read y ) => Read (Coordinates x y) where- readsPrec _ s = [+ readsPrec precedence s = [ (coordinates, remainder) |- ((x, y), remainder) <- reads s,+ ((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 T.X T.Y) #-}+ {-# SPECIALISE instance Ord (Coordinates Type.Length.X Type.Length.Y) #-} 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@@ -158,7 +158,7 @@ Ord x, Ord y ) => Data.Array.IArray.Ix (Coordinates x y) where- {-# SPECIALISE instance Data.Array.IArray.Ix (Coordinates T.X T.Y) #-}+ {-# SPECIALISE instance Data.Array.IArray.Ix (Coordinates Type.Length.X Type.Length.Y) #-} 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@@ -193,7 +193,7 @@ nSquares = fromIntegral $ Cartesian.Abscissa.xLength * Cartesian.Ordinate.yLength instance (Enum x, Enum y) => Property.FixedMembership.FixedMembership (Coordinates x y) where- {-# SPECIALISE instance Property.FixedMembership.FixedMembership (Coordinates T.X T.Y) #-}+ {-# SPECIALISE instance Property.FixedMembership.FixedMembership (Coordinates Type.Length.X Type.Length.Y) #-} members = [ MkCoordinates { getX = x,@@ -244,7 +244,7 @@ -- | Convert to an array-index. toIx :: (Enum x, Enum y) => Coordinates x y -> Int-{-# SPECIALISE toIx :: Coordinates T.X T.Y -> Int #-}+{-# SPECIALISE toIx :: Coordinates Type.Length.X Type.Length.Y -> Int #-} toIx MkCoordinates { getX = x, getY = y@@ -426,7 +426,7 @@ extrapolate = extrapolate' -- | A specialisation of 'extrapolate'.-extrapolateInt :: Attribute.Direction.Direction -> Coordinates T.X T.Y -> [Coordinates T.X T.Y]+extrapolateInt :: Attribute.Direction.Direction -> Coordinates Type.Length.X Type.Length.Y -> [Coordinates Type.Length.X Type.Length.Y] extrapolateInt direction coordinates = extrapolationsByDirectionByCoordinates ! coordinates ! direction -- | The constant lists of /coordinates/, extrapolated from every /coordinate/ in the /board/, in every /direction/.@@ -440,7 +440,7 @@ Ord x, Ord y ) => ArrayByCoordinates x y (Attribute.Direction.ArrayByDirection [Coordinates x y])-{-# SPECIALISE extrapolationsByDirectionByCoordinates :: ArrayByCoordinates T.X T.Y (Attribute.Direction.ArrayByDirection [Coordinates T.X T.Y]) #-} -- To promote memoisation.+{-# SPECIALISE extrapolationsByDirectionByCoordinates :: ArrayByCoordinates Type.Length.X Type.Length.Y (Attribute.Direction.ArrayByDirection [Coordinates Type.Length.X Type.Length.Y]) #-} -- To promote memoisation. extrapolationsByDirectionByCoordinates = listArrayByCoordinates #ifdef USE_PARALLEL . Control.Parallel.Strategies.withStrategy (Control.Parallel.Strategies.parList Control.Parallel.Strategies.rdeepseq)@@ -460,7 +460,7 @@ Ord x, Ord y ) => ArrayByCoordinates x y (Data.Map.Map (Coordinates x y) [Coordinates x y])-{-# SPECIALISE interpolationsByDestinationBySource :: ArrayByCoordinates T.X T.Y (Data.Map.Map (Coordinates T.X T.Y) [Coordinates T.X T.Y]) #-} -- To promote memoisation.+{-# 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 = Data.Array.IArray.amap ( Data.Map.fromList . map ( last {-destination-} &&& id {-interpolation-}@@ -496,7 +496,7 @@ | otherwise = Control.Exception.assert ( x == x' || y == y' || ( let- distanceX, distanceY :: T.Distance+ distanceX, distanceY :: Type.Length.Distance (distanceX, distanceY) = measureDistance source destination in abs distanceX == abs distanceY ) -- Check that the move is straight.@@ -509,7 +509,7 @@ EQ -> repeat fromAfter -- | A specialisation of 'interpolate'.-interpolateInt :: Coordinates T.X T.Y -> Coordinates T.X T.Y -> [Coordinates T.X T.Y]+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 -- | The type of a function which changes one set of /coordinates/ to another.@@ -540,7 +540,7 @@ } -- -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' :: T.Distance+ 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@@ -576,7 +576,7 @@ | even $ uncurry (+) distance = Attribute.LogicalColourOfSquare.black | otherwise = Attribute.LogicalColourOfSquare.white where- distance :: (T.Distance, T.Distance)+ distance :: (Type.Length.Distance, Type.Length.Distance) distance = measureDistance minBound coordinates -- | Whether the specified squares have the same /logical colour/.
src-lib/BishBosh/Cartesian/Ordinate.hs view
@@ -58,7 +58,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Array.IArray @@ -67,7 +67,7 @@ yOrigin = Cartesian.Abscissa.xOrigin -- N.B. it doesn't need to be the same. -- | The constant length of the /y/-axis.-yLength :: T.Distance+yLength :: Type.Length.Distance yLength = Cartesian.Abscissa.xLength -- Because the board is square. -- | The constant lower bound of ordinates.
src-lib/BishBosh/Cartesian/Vector.hs view
@@ -63,7 +63,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Control.Exception @@ -116,7 +116,7 @@ isStraight vector = isParallel vector || isDiagonal vector -- | A suitable concrete type.-type VectorInt = Vector T.Distance+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)@@ -230,7 +230,7 @@ => Cartesian.Coordinates.Coordinates x y -> Vector distance -> Maybe (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE maybeTranslate :: Cartesian.Coordinates.Coordinates T.X T.Y -> Vector T.Distance -> Maybe (Cartesian.Coordinates.Coordinates T.X T.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
src-lib/BishBosh/Component/CastlingMove.hs view
@@ -51,7 +51,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception -- | Defines a castling-move.@@ -121,7 +121,7 @@ getCastlingMoves = defineCastlingMoves -- | A specialisation of 'getCastlingMoves'.-getCastlingMovesInt :: Attribute.LogicalColour.LogicalColour -> [CastlingMove T.X T.Y]+getCastlingMovesInt :: Attribute.LogicalColour.LogicalColour -> [CastlingMove Type.Length.X Type.Length.Y] getCastlingMovesInt = (castlingMovesByLogicalColour !) -- | Break-down the two castling-moves for the specified /logical colour/ into a long & a short castling-move.@@ -131,7 +131,7 @@ Eq y, Ord x ) => Attribute.LogicalColour.LogicalColour -> (CastlingMove x y, CastlingMove x y)-{-# SPECIALISE getLongAndShortMoves :: Attribute.LogicalColour.LogicalColour -> (CastlingMove T.X T.Y, CastlingMove T.X T.Y) #-}+{-# SPECIALISE getLongAndShortMoves :: Attribute.LogicalColour.LogicalColour -> (CastlingMove Type.Length.X Type.Length.Y, CastlingMove Type.Length.X Type.Length.Y) #-} getLongAndShortMoves logicalColour | [longCastlingMove, shortCastlingMove] <- getCastlingMoves logicalColour = (longCastlingMove, shortCastlingMove) | otherwise = Control.Exception.throw $ Data.Exception.mkIncompatibleData "BishBosh.Component.CastlingMove.getLongAndShortMoves:\tunexpected list-length."
src-lib/BishBosh/Component/Move.hs view
@@ -25,8 +25,6 @@ module BishBosh.Component.Move( -- * Types -- ** Type-synonyms- NMoves,- NPlies, Move( -- MkMove, getSource,@@ -50,7 +48,8 @@ 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.Types as T+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@@ -60,14 +59,8 @@ tag :: String tag = "move" --- | A number of moves.-type NMoves = Int---- | A number of half-moves into a /game/.-type NPlies = NMoves- -- | The constant number of plies per move.-nPliesPerMove :: NPlies+nPliesPerMove :: Type.Count.NPlies nPliesPerMove = 2 {- |@@ -81,7 +74,7 @@ } deriving Eq instance (Ord x, Ord y) => Ord (Move x y) where- {-# SPECIALISE instance Ord (Move T.X T.Y) #-}+ {-# SPECIALISE instance Ord (Move Type.Length.X Type.Length.Y) #-} move@MkMove { getSource = source } `compare` move'@MkMove { getSource = source' } = case source `compare` source' of EQ -> Data.Ord.comparing getDestination move move' ordering -> ordering@@ -93,10 +86,10 @@ } = Control.DeepSeq.rnf (source, destination) instance (Show x, Show y) => Show (Move x y) where- showsPrec _ MkMove {+ showsPrec precedence MkMove { getSource = source, getDestination = destination- } = shows (source, destination)+ } = showsPrec precedence (source, destination) instance ( Enum x,@@ -106,7 +99,7 @@ Read x, Read y ) => Read (Move x y) where- readsPrec _ = map (Control.Arrow.first $ uncurry mkMove) . reads+ readsPrec precedence = map (Control.Arrow.first $ uncurry mkMove) . readsPrec precedence instance Property.Opposable.Opposable (Move x y) where getOpposite (MkMove source destination) = MkMove {@@ -155,7 +148,7 @@ Num distance, Ord distance ) => Move x y -> Cartesian.Vector.Vector distance-{-# SPECIALISE measureDistance :: Move T.X T.Y -> Cartesian.Vector.VectorInt #-}+{-# SPECIALISE measureDistance :: Move Type.Length.X Type.Length.Y -> Cartesian.Vector.VectorInt #-} measureDistance MkMove { getSource = source, getDestination = destination@@ -168,7 +161,7 @@ Ord x, Ord y ) => Move x y -> [Cartesian.Coordinates.Coordinates x y]-{-# SPECIALISE interpolate :: Move T.X T.Y -> [Cartesian.Coordinates.Coordinates T.X T.Y] #-}+{-# SPECIALISE interpolate :: Move Type.Length.X Type.Length.Y -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y] #-} interpolate move@MkMove { getSource = source, getDestination = destination
src-lib/BishBosh/Component/Piece.hs view
@@ -27,7 +27,6 @@ module BishBosh.Component.Piece( -- * Types -- ** Type-synonyms- NPieces, -- ByRankByLogicalColour, -- AttackDestinationsByCoordinatesByRankByLogicalColour, -- ArrayByPiece,@@ -92,7 +91,8 @@ 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.Types as T+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@@ -111,12 +111,9 @@ tag :: String tag = "piece" --- | A number of /piece/s.-type NPieces = Int -- N.B.: 'Data.Int.Int8' saves neither time nor space.- -- | The initial number of pieces per side in a standard opening position; some of which are duplicates.-nPiecesPerSide :: NPieces-nPiecesPerSide = fromIntegral Cartesian.Abscissa.xLength * 2 {-rows-}+nPiecesPerSide :: Type.Count.NPieces+nPiecesPerSide = fromIntegral $ Cartesian.Abscissa.xLength * 2 {-rows-} -- | A Chess-piece has a /logical colour/ & a /rank/. data Piece = MkPiece {@@ -136,7 +133,7 @@ index (lower, upper) MkPiece { getLogicalColour = logicalColour, getRank = rank- } = Control.Exception.assert (lower == minBound && upper == maxBound) $ fromEnum logicalColour * Attribute.Rank.nDistinctRanks + fromEnum rank+ } = Control.Exception.assert (lower == minBound && upper == maxBound) $ fromEnum logicalColour * fromIntegral Attribute.Rank.nDistinctRanks + fromEnum rank instance Read Piece where readsPrec _ = Property.ForsythEdwards.readsFEN@@ -287,7 +284,7 @@ Ord x, Ord y ) => AttackDestinationsByCoordinatesByRankByLogicalColour x y-{-# SPECIALISE attackDestinationsByCoordinatesByRankByLogicalColour :: AttackDestinationsByCoordinatesByRankByLogicalColour T.X T.Y #-} -- To promote memoisation.+{-# SPECIALISE attackDestinationsByCoordinatesByRankByLogicalColour :: AttackDestinationsByCoordinatesByRankByLogicalColour Type.Length.X Type.Length.Y #-} -- To promote memoisation. attackDestinationsByCoordinatesByRankByLogicalColour = mkByRankByLogicalColour Attribute.Rank.fixedAttackRange $ \logicalColour rank -> Cartesian.Coordinates.listArrayByCoordinates $ map ( `findAttackDestinations'` mkPiece logicalColour rank ) Property.FixedMembership.members@@ -326,7 +323,7 @@ findAttackDestinations = findAttackDestinations' -- | A specialisation of 'findAttackDestinations', more efficiently implemented by calling 'attackDestinationsByCoordinatesByRankByLogicalColour'.-findAttackDestinationsInt :: Cartesian.Coordinates.Coordinates T.X T.Y -> Piece -> [Cartesian.Coordinates.Coordinates T.X T.Y]+findAttackDestinationsInt :: Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y -> Piece -> [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y] findAttackDestinationsInt coordinates MkPiece { getLogicalColour = logicalColour, getRank = rank@@ -373,7 +370,7 @@ -> Cartesian.Coordinates.Coordinates x y -- ^ Destination (victim's location). -> Piece -- ^ Attacker. -> Bool-{-# SPECIALISE canAttackAlong :: Cartesian.Coordinates.Coordinates T.X T.Y -> Cartesian.Coordinates.Coordinates T.X T.Y -> Piece -> 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@@ -400,7 +397,7 @@ -> Cartesian.Coordinates.Coordinates x y -- ^ Destination. -> Piece -> Bool-{-# SPECIALISE canMoveBetween :: Cartesian.Coordinates.Coordinates T.X T.Y -> Cartesian.Coordinates.Coordinates T.X T.Y -> 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
src-lib/BishBosh/Component/PieceSquareByCoordinatesByRank.hs view
@@ -46,7 +46,7 @@ mkPieceSquareByCoordinatesByRank ) where -import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) import Data.Array.IArray((!)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.Rank as Attribute.Rank@@ -56,17 +56,22 @@ import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Reflectable as Property.Reflectable import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+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.List -- | The piece-square value may vary as the game progresses.-type PieceSquareValueByNPieces pieceSquareValue = Data.Array.IArray.Array Component.Piece.NPieces pieceSquareValue+type PieceSquareValueByNPieces pieceSquareValue = Data.Array.IArray.Array Type.Count.NPieces pieceSquareValue -- | The bounds of the number of pieces on the board, at the end-game & opening-game respectively.-nPiecesBounds :: (Component.Piece.NPieces, Component.Piece.NPieces)-nPiecesBounds = (3 {-minimum sufficient material-}, Attribute.LogicalColour.nDistinctLogicalColours * Component.Piece.nPiecesPerSide)+nPiecesBounds :: (Type.Count.NPieces, Type.Count.NPieces)+nPiecesBounds = (+ 3 {-minimum sufficient material-},+ fromIntegral Attribute.LogicalColour.nDistinctLogicalColours * Component.Piece.nPiecesPerSide+ ) -- | Self-documentation. type EitherPieceSquareValueByNPiecesByCoordinates x y pieceSquareValue = Either (@@ -107,24 +112,24 @@ Ord x, Ord y )- => Component.Piece.NPieces -- ^ The progress through the game.+ => 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 -> pieceSquareValue {-# SPECIALISE findPieceSquareValue- :: Component.Piece.NPieces+ :: Type.Count.NPieces -> Attribute.LogicalColour.LogicalColour -> Attribute.Rank.Rank- -> Cartesian.Coordinates.Coordinates T.X T.Y- -> PieceSquareByCoordinatesByRank T.X T.Y T.PieceSquareValue- -> T.PieceSquareValue+ -> 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 } = either (!) (- \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !)- ) (- byRank ! rank+findPieceSquareValue nPieces logicalColour rank coordinates MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = (+ (!) ||| (+ \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !)+ ) $ byRank ! rank ) $ ( if Attribute.LogicalColour.isBlack logicalColour then Property.Reflectable.reflectOnX@@ -145,24 +150,24 @@ Ord x, Ord y )- => Component.Piece.NPieces -- ^ The progress through the game.+ => 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- :: Component.Piece.NPieces+ :: Type.Count.NPieces -> Attribute.LogicalColour.LogicalColour -> Attribute.Rank.Rank- -> [Cartesian.Coordinates.Coordinates T.X T.Y]- -> PieceSquareByCoordinatesByRank T.X T.Y T.PieceSquareValue- -> [T.PieceSquareValue]+ -> [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 } = either (!) (- \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !)- ) (- byRank ! rank+findPieceSquareValues nPieces logicalColour rank coordinatesList MkPieceSquareByCoordinatesByRank { deconstruct = byRank } = (+ (!) ||| (+ \byNPiecesByCoordinates -> (! nPieces) . (byNPiecesByCoordinates !)+ ) $ byRank ! rank ) `map` ( if Attribute.LogicalColour.isBlack logicalColour then map Property.Reflectable.reflectOnX@@ -218,11 +223,9 @@ else id ) . showS ) id . zip (- Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates T.X T.Y]+ Property.FixedMembership.members :: [Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y] ) . Data.List.transpose . map (- Data.Array.IArray.elems `either` (- map selector {-select one pieceSquareValue from interpolated values-} . Data.Array.IArray.elems {-ByCoordinates-}- )+ Data.Array.IArray.elems ||| map selector {-select one pieceSquareValue from interpolated values-} . Data.Array.IArray.elems {-ByCoordinates-} ) $ Data.Array.IArray.elems {-ByRank-} byRank where terminateRow = showChar '\n' showsRow = Text.ShowList.showsDelimitedList columnDelimiter id terminateRow
src-lib/BishBosh/Component/QualifiedMove.hs view
@@ -48,10 +48,10 @@ } deriving Eq instance (Show x, Show y) => Show (QualifiedMove x y) where- showsPrec _ MkQualifiedMove {+ showsPrec precedence MkQualifiedMove { getMove = move, getMoveType = moveType- } = shows (move, moveType)+ } = showsPrec precedence (move, moveType) instance ( Enum x,@@ -61,7 +61,7 @@ Read x, Read y ) => Read (QualifiedMove x y) where- readsPrec _ = map (Control.Arrow.first $ uncurry MkQualifiedMove) . reads+ 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 rnf MkQualifiedMove {
src-lib/BishBosh/Component/Turn.hs view
@@ -81,11 +81,11 @@ } = Control.DeepSeq.rnf (qualifiedMove, rank, isRepeatableMove) instance (Show x, Show y) => Show (Turn x y) where- showsPrec _ MkTurn {+ showsPrec precedence MkTurn { getQualifiedMove = qualifiedMove, getRank = rank -- getIsRepeatableMove = isRepeatableMove- } = shows (+ } = showsPrec precedence ( qualifiedMove, rank -- isRepeatableMove -- Derived.@@ -99,7 +99,7 @@ Read x, Read y ) => Read (Turn x y) where- readsPrec _ = map (Control.Arrow.first $ uncurry mkTurn) . reads+ readsPrec precedence = map (Control.Arrow.first $ uncurry mkTurn) . readsPrec precedence instance Enum y => Property.Reflectable.ReflectableOnX (Turn x y) where reflectOnX turn@MkTurn { getQualifiedMove = qualifiedMove } = turn { getQualifiedMove = Property.Reflectable.reflectOnX qualifiedMove }@@ -138,8 +138,7 @@ -- | Forwards the request to 'Attribute.Rank.compareByLVA'. compareByLVA- :: Ord rankValue- => Attribute.Rank.EvaluateRank rankValue+ :: Attribute.Rank.EvaluateRank -> Turn x y -> Turn x y -> Ordering@@ -155,8 +154,7 @@ * CAVEAT: no account is made for any defenders of the attacked piece, which might recoup transient gains. -} compareByMVVLVA- :: Ord rankValue- => Attribute.Rank.EvaluateRank rankValue+ :: Attribute.Rank.EvaluateRank -> Turn x y -> Turn x y -> Ordering
src-lib/BishBosh/ContextualNotation/PGN.hs view
@@ -75,17 +75,17 @@ import Control.Arrow((&&&), (***)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.ContextualNotation.PGNComment as ContextualNotation.PGNComment import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason-import qualified BishBosh.Model.Result as Model.Result import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason+import qualified BishBosh.Rule.Result as Rule.Result import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+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@@ -215,7 +215,7 @@ Show x, Show y ) => Show (PGN x y) where- {-# SPECIALISE instance Show (PGN T.X T.Y) #-}+ {-# SPECIALISE instance Show (PGN Type.Length.X Type.Length.Y) #-} showsPrec _ MkPGN { getMaybeEventName = maybeEventName, getMaybeSiteName = maybeSiteName,@@ -243,7 +243,7 @@ ), ( blackPlayerNameTag, representUnknownTagValue maybeBlackPlayerName ), (- resultTag, quote . Data.Maybe.maybe (showChar inProgressFlag) (shows . Model.GameTerminationReason.toResult) $ Model.Game.getMaybeTerminationReason game+ resultTag, quote . Data.Maybe.maybe (showChar inProgressFlag) (shows . Rule.GameTerminationReason.toResult) $ Model.Game.getMaybeTerminationReason game ) ] ++ map ( Control.Arrow.second $ quote . showString@@ -308,7 +308,7 @@ setGame :: Model.Game.Game x y -> PGN x y -> PGN x y setGame game pgn = pgn { getGame = game } --- | Smart-constructor.+-- | Smart constructor. mkPGN' :: [Tag] -- ^ Identify fields used to form a unique composite game-identifier. -> [TagPair] -- ^ The data from which to extract the required values.@@ -372,7 +372,7 @@ Show x, Show y ) => Model.Game.Game x y -> ShowS-{-# SPECIALISE showsMoveText :: Model.Game.Game T.X T.Y -> ShowS #-}+{-# SPECIALISE showsMoveText :: Model.Game.Game Type.Length.X Type.Length.Y -> ShowS #-} showsMoveText game = foldr (.) ( Data.Maybe.maybe ( showsBlockComment "Game unfinished" . showChar ' ' . showChar inProgressFlag@@ -380,7 +380,7 @@ ( \(s, showsPGN) -> showsBlockComment s . showChar ' ' . showsPGN ) . (- filter (/= ContextualNotation.PGNComment.blockCommentEnd) . show &&& shows . Model.GameTerminationReason.toResult+ filter (/= ContextualNotation.PGNComment.blockCommentEnd) . show &&& shows . Rule.GameTerminationReason.toResult ) ) $ Model.Game.getMaybeTerminationReason game ) $ Data.List.unfoldr (@@ -396,7 +396,7 @@ ) $ Data.List.splitAt 1 remainder _ -> Nothing ) (- 1 :: Component.Move.NMoves,+ 1 :: Type.Count.NMoves, reverse {-chronological-} $ fst . foldr ( \turn (l, game') -> ( ContextualNotation.StandardAlgebraic.showsTurn False turn game' : l,@@ -416,7 +416,7 @@ Show x, Show y ) => Model.Game.Game x y -> IO ShowS-{-# SPECIALISE showsGame :: Model.Game.Game T.X T.Y -> IO ShowS #-}+{-# SPECIALISE showsGame :: Model.Game.Game Type.Length.X Type.Length.Y -> IO ShowS #-} showsGame game = do utcTime <- Data.Time.Clock.getCurrentTime @@ -453,12 +453,12 @@ * N.B.: officially terminated by a single period (for White), or three (by Black); though this parser is more flexible. -}-moveNumberParser :: Num n =>+moveNumberParser :: #ifdef USE_POLYPARSE- Text.Poly.TextParser n+ Text.Poly.TextParser Type.Count.NMoves moveNumberParser = Control.Applicative.many ContextualNotation.PGNComment.blockCommentParser >> Text.Poly.unsignedDecimal `Poly.discard` Control.Applicative.some (Text.Poly.char moveNumberTerminator) #else /* Parsec */- Parsec.Parser n+ Parsec.Parser Type.Count.NMoves moveNumberParser = Parsec.try $ Control.Applicative.many ContextualNotation.PGNComment.blockCommentParser >> Parsec.spaces >> fmap Data.Integral.stringToUnsignedDecimal ( Parsec.manyTill Parsec.digit ( Control.Applicative.some $ Parsec.char moveNumberTerminator@@ -469,7 +469,7 @@ -- | Parse an optional result. maybeResultParser :: #ifdef USE_POLYPARSE- Text.Poly.TextParser (Maybe Model.Result.Result)+ Text.Poly.TextParser (Maybe Rule.Result.Result) maybeResultParser = Control.Applicative.many ContextualNotation.PGNComment.blockCommentParser >> Text.Poly.spaces >> Poly.oneOf' [ ( "Result",@@ -482,7 +482,7 @@ ) ] #else /* Parsec */- Parsec.Parser (Maybe Model.Result.Result)+ Parsec.Parser (Maybe Rule.Result.Result) maybeResultParser = Control.Applicative.many ContextualNotation.PGNComment.blockCommentParser >> Parsec.spaces >> ( Parsec.try ( Parsec.choice $ map (@@ -507,7 +507,7 @@ => IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Text.Poly.TextParser (Model.Game.Game x y)-{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Text.Poly.TextParser (Model.Game.Game T.X T.Y) #-}+{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Text.Poly.TextParser (Model.Game.Game Type.Length.X Type.Length.Y) #-} moveTextParser isStrictlySequential validateMoves = let elementSequenceParser :: ( Enum x,@@ -518,7 +518,8 @@ Show y ) => Model.Game.Game x y -> Text.Poly.TextParser (Model.Game.Game x y) elementSequenceParser game = let- expectedMoveNumber = succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game+ expectedMoveNumber :: Type.Count.NMoves+ expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game in do moveNumber <- ( if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game@@ -553,7 +554,7 @@ => IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Parsec.Parser (Model.Game.Game x y)-{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Parsec.Parser (Model.Game.Game T.X T.Y) #-}+{-# SPECIALISE moveTextParser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Parsec.Parser (Model.Game.Game Type.Length.X Type.Length.Y) #-} moveTextParser isStrictlySequential validateMoves = let elementSequenceParser :: ( Enum x,@@ -564,7 +565,8 @@ Show y ) => Model.Game.Game x y -> Parsec.Parser (Model.Game.Game x y) elementSequenceParser game = let- expectedMoveNumber = succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game+ expectedMoveNumber :: Type.Count.NMoves+ expectedMoveNumber = fromIntegral . succ . (`div` 2) . State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game in do moveNumber <- ( if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game@@ -614,7 +616,7 @@ -> [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 T.X T.Y) #-}+{-# SPECIALISE parser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -> Text.Poly.TextParser (PGN Type.Length.X Type.Length.Y) #-} parser isStrictlySequential validateMoves identificationTags = do tagPairs <- Control.Applicative.many $ tagPairParser <* Control.Applicative.many ContextualNotation.PGNComment.parser moveText <- moveTextParser' <* Control.Applicative.many ContextualNotation.PGNComment.parser@@ -642,7 +644,7 @@ ) #else /* Parsec */ -> Parsec.Parser (PGN x y)-{-# SPECIALISE parser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -> Parsec.Parser (PGN T.X T.Y) #-}+{-# SPECIALISE parser :: IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [Tag] -> Parsec.Parser (PGN Type.Length.X Type.Length.Y) #-} parser isStrictlySequential validateMoves identificationTags = mkPGN' identificationTags <$> ( removeUnknownTagValues <$> Control.Applicative.many ( tagPairParser <* Control.Applicative.many ContextualNotation.PGNComment.parser
src-lib/BishBosh/ContextualNotation/PGNDatabase.hs view
@@ -35,7 +35,7 @@ PGNDatabase, -- PGNPredicate, Decompressor,--- MaybeMaximumGames,+ MaybeMaximumGames, -- * Functions -- parser, -- parse,@@ -46,7 +46,8 @@ import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Types as T+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@@ -57,12 +58,14 @@ #ifdef USE_POLYPARSE import qualified BishBosh.Text.Poly as Text.Poly-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# else /* Plain */+import qualified Control.Arrow import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# endif #else /* Parsec */+import qualified Control.Arrow import qualified Text.ParserCombinators.Parsec as Parsec import Text.ParserCombinators.Parsec((<?>)) #endif@@ -84,11 +87,11 @@ -> [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 T.X T.Y) #-}+{-# SPECIALISE parser :: ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] -> Text.Poly.TextParser (PGNDatabase Type.Length.X Type.Length.Y) #-} 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 T.X T.Y) #-}+{-# SPECIALISE parser :: ContextualNotation.PGN.IsStrictlySequential -> ContextualNotation.StandardAlgebraic.ValidateMoves -> [ContextualNotation.PGN.Tag] -> Parsec.Parser (PGNDatabase Type.Length.X Type.Length.Y) #-} parser isStrictlySequential validateMoves identificationTags = Parsec.manyTill parser' (Parsec.try $ Parsec.spaces >> Parsec.try Parsec.eof) <?> "PGN-database" #endif where@@ -98,7 +101,7 @@ type PGNPredicate x y = ContextualNotation.PGN.PGN x y -> Bool -- | The optional maximum number of games to read.-type MaybeMaximumGames = Maybe Int+type MaybeMaximumGames = Maybe Type.Count.NGames -- | Parses a PGN-database from the specified string. parse :: (@@ -117,20 +120,20 @@ -> 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 T.X T.Y -> MaybeMaximumGames -> String -> Either String (PGNDatabase T.X T.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) #-} #ifdef USE_POLYPARSE-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 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 */-parse name isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = either (Left . showString "regarding " . shows name . showString ", ") Right-#endif+# else /* Plain */+parse name isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = Control.Arrow.left (showString "regarding " . shows name . showString ", ")+# endif . fst {-discard unparsed data-} . Poly.runParser parser' #else /* Parsec */-parse name isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = either (Left . showString "failed to parse; " . show) Right . Parsec.parse parser' name+parse name isStrictlySequential validateMoves identificationTags pgnPredicate maybeMaximumGames = Control.Arrow.left (showString "failed to parse; " . show) . Parsec.parse parser' name #endif where parser' = (- Data.Maybe.maybe id take maybeMaximumGames . filter pgnPredicate -- CAVEAT: apply the filter before extracting the required number of games.+ Data.Maybe.maybe id (take . fromIntegral) maybeMaximumGames . filter pgnPredicate -- CAVEAT: apply the filter before extracting the required number of games. ) `fmap` parser isStrictlySequential validateMoves identificationTags -- | The name of an executable used to decompress (to stdout) the PGN-file.@@ -154,7 +157,7 @@ -> PGNPredicate x y -- ^ 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 T.X T.Y -> MaybeMaximumGames -> IO (Either String (PGNDatabase T.X T.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)) #-} 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
@@ -54,10 +54,12 @@ import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.ContextualNotation.QualifiedMoveForest as ContextualNotation.QualifiedMoveForest import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.Result as Model.Result 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.Types as T+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@@ -89,7 +91,7 @@ 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 :: Component.Piece.NPieces -- ^ The minimum number of /piece/s remaining after the last /move/ in any game defined in the tree.+ getMinimumPieces :: Type.Count.NPieces -- ^ The minimum number of /piece/s remaining after the last /move/ in any game defined in the tree. } -- | Augment the specified /qualified-move forest/ with a /Zobrist-hash/ of the /position/ & include the default initial game at the apex.@@ -106,7 +108,7 @@ -> Component.Zobrist.Zobrist x y positionHash -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest x y -> PositionHashQualifiedMoveTree x y positionHash-{-# SPECIALISE fromQualifiedMoveForest :: Bool -> Component.Zobrist.Zobrist T.X T.Y T.PositionHash -> ContextualNotation.QualifiedMoveForest.QualifiedMoveForest T.X T.Y -> PositionHashQualifiedMoveTree T.X T.Y T.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 #-} fromQualifiedMoveForest incrementalEvaluation zobrist qualifiedMoveForest = MkPositionHashQualifiedMoveTree { getZobrist = zobrist, getTree = let@@ -199,7 +201,7 @@ Enum y, Ord y ) => FindMatch x y positionHash-{-# SPECIALISE findNextOnymousQualifiedMovesForPosition :: FindMatch T.X T.Y T.PositionHash #-}+{-# SPECIALISE findNextOnymousQualifiedMovesForPosition :: FindMatch Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-} findNextOnymousQualifiedMovesForPosition requiredGame positionHashQualifiedMoveTree@MkPositionHashQualifiedMoveTree { getZobrist = zobrist, getTree = tree@@ -207,26 +209,26 @@ | cantConverge requiredGame positionHashQualifiedMoveTree = [] -- The specified game has fewer pieces than any defined in the tree. | otherwise = slave (2 * Component.Piece.nPiecesPerSide) tree where+ (requiredPositionHash, requiredNPieces) = (`Component.Zobrist.hash2D` zobrist) &&& State.Board.getNPieces . Model.Game.getBoard $ requiredGame+ slave nPieces Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getPositionHash = positionHash }, Data.Tree.subForest = forest- }- | nPieces < State.Board.getNPieces (- Model.Game.getBoard requiredGame- ) = [] -- There are fewer pieces remaining in the tree than required.- | otherwise = (- if positionHash == Component.Zobrist.hash2D requiredGame zobrist- then (- map onymiseQualifiedMove forest ++ -- The Zobrist-hash/position matches, so one can select any move from the forest.- ) -- Section.- else id- ) $ concatMap (- \node@Data.Tree.Node {- Data.Tree.rootLabel = MkNodeLabel { getMaybeQualifiedMoveWithOnymousResult = Just (qualifiedMove, _) }- } -> slave (- Attribute.MoveType.nPiecesMutator (Component.QualifiedMove.getMoveType qualifiedMove) nPieces- ) node -- Recurse to see if deeper matches exist.- ) forest+ } = (+ if positionHash == requiredPositionHash+ then (+ map onymiseQualifiedMove forest ++ -- The position matches, so one can select any move from the forest.+ ) -- Section.+ else id+ ) $ 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.+ ) forest -- | Finds any single /move/s which can join the current /position/ with a member of the forest. findNextJoiningOnymousQualifiedMovesFromPosition :: (@@ -242,24 +244,21 @@ Show x, Show y ) => FindMatch x y positionHash-{-# SPECIALISE findNextJoiningOnymousQualifiedMovesFromPosition :: FindMatch T.X T.Y T.PositionHash #-}-findNextJoiningOnymousQualifiedMovesFromPosition game positionHashQualifiedMoveTree = [- (- preMatchQualifiedMove,- concatMap snd {-[OnymousResult]-} matchingOnymousQualifiedMoves -- Discard the opponent's matching move, but cite the names of archived games it reached.- ) |- not $ Model.Game.isTerminated game,- (preMatchQualifiedMove, matchingOnymousQualifiedMoves) <-+{-# SPECIALISE findNextJoiningOnymousQualifiedMovesFromPosition :: FindMatch Type.Length.X Type.Length.Y Type.Crypto.PositionHash #-}+findNextJoiningOnymousQualifiedMovesFromPosition game positionHashQualifiedMoveTree+ | Model.Game.isTerminated game = []+ | otherwise = [+ Control.Arrow.second (concatMap snd {-[OnymousResult]-}) movePair | -- Discard the opponent's matching move, but cite the names of archived games it reached.+ movePair@(_, _ : _) <- #ifdef USE_PARALLEL- Control.Parallel.Strategies.withStrategy (- Control.Parallel.Strategies.parList $ Control.Parallel.Strategies.evalTuple2 Control.Parallel.Strategies.r0 {-pre-match move-} Control.Parallel.Strategies.rdeepseq {-matching moves-}- ) .+ Control.Parallel.Strategies.withStrategy (+ Control.Parallel.Strategies.parList $ Control.Parallel.Strategies.evalTuple2 Control.Parallel.Strategies.r0 {-pre-match move-} Control.Parallel.Strategies.rdeepseq {-matching moves-}+ ) . #endif- map (- id &&& (`findNextOnymousQualifiedMovesForPosition` positionHashQualifiedMoveTree) . (`Model.Game.applyQualifiedMove` game) -- Apply this player's move.- ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game,- not $ null matchingOnymousQualifiedMoves- ] -- List-comprehension.+ map (+ id &&& (`findNextOnymousQualifiedMovesForPosition` positionHashQualifiedMoveTree) . (`Model.Game.applyQualifiedMove` game) -- Apply this player's move.+ ) $ Model.Game.findQualifiedMovesAvailableToNextPlayer game+ ] -- List-comprehension. {- | * Calls 'findNextOnymousQualifiedMovesForGame' to find an exact match for the current /game/ in the tree.@@ -289,7 +288,7 @@ ) => (Bool, Bool, Bool) -- ^ MatchSwitches. -> FindMatch x y positionHash-{-# SPECIALISE findNextOnymousQualifiedMoves :: (Bool, Bool, Bool) -> FindMatch T.X T.Y T.PositionHash #-}+{-# SPECIALISE findNextOnymousQualifiedMoves :: (Bool, Bool, Bool) -> FindMatch Type.Length.X Type.Length.Y 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 (@@ -336,9 +335,9 @@ :: System.Random.RandomGen randomGen => randomGen -> (Bool, Bool, Bool)- -> Model.Game.Game T.X T.Y- -> PositionHashQualifiedMoveTree T.X T.Y T.PositionHash- -> Maybe (Component.QualifiedMove.QualifiedMove T.X T.Y, [ContextualNotation.QualifiedMoveForest.Name])+ -> 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]) #-} maybeRandomlySelectOnymousQualifiedMove randomGen matchSwitches game positionHashQualifiedMoveTree = case findNextOnymousQualifiedMoves matchSwitches game positionHashQualifiedMoveTree of [] -> Nothing@@ -354,7 +353,7 @@ then id else negate ) 1 {-victory-}- ) . Model.Result.findMaybeVictor . snd {-result-} -- Score the result, according to which side we'd like to win.+ ) . Rule.Result.findMaybeVictor . snd {-result-} -- Score the result, according to which side we'd like to win. ) . snd {-[OnymousResult]-} ) onymousQualifiedMoves
src-lib/BishBosh/ContextualNotation/QualifiedMoveForest.hs view
@@ -50,24 +50,23 @@ import Control.Applicative((<|>)) import Control.Arrow((&&&), (***))-import qualified BishBosh.Attribute.MoveType as Attribute.MoveType-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.ContextualNotation.PGN as ContextualNotation.PGN-import qualified BishBosh.ContextualNotation.PGNDatabase as ContextualNotation.PGNDatabase-import qualified BishBosh.Data.RoseTree as Data.RoseTree-import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason-import qualified BishBosh.Model.GameTree as Model.GameTree-import qualified BishBosh.Model.Result as Model.Result-import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation-import qualified BishBosh.Property.Empty as Property.Empty-import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.State.Board as State.Board-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove+import qualified BishBosh.Component.Turn as Component.Turn+import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN+import qualified BishBosh.ContextualNotation.PGNDatabase as ContextualNotation.PGNDatabase+import qualified BishBosh.Data.RoseTree as Data.RoseTree+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Model.GameTree as Model.GameTree+import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+import qualified BishBosh.Property.Empty as Property.Empty+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@@ -78,7 +77,7 @@ type Name = String -- | The name of a /game/, & it's /result/.-type OnymousResult = (Name, Model.Result.Result)+type OnymousResult = (Name, Rule.Result.Result) {- | * Terminal nodes contain the unique name of the /move/-sequence leading to them, from which other information can be found as required, from the original database.@@ -119,19 +118,19 @@ ) maybeOnymousResult "" ) forest --- | Shows a list of the names of archived games, optionally capped at the specified number.+-- | Shows an optional capped list of the names of archived games. showsNames- :: Maybe Int -- ^ The optional maximum number of names to show.+ :: Maybe Type.Count.NGames -- ^ The optional maximum number of names to show. -> [Name] -> ShowS showsNames maybeMaximumPGNNames names = Text.ShowList.showsUnterminatedList . map ( \name -> showString "\n\t" . showString name ) $ Data.Maybe.maybe id ( \maximumPGNNames -> (- if maximumPGNNames < length names'+ if fromIntegral maximumPGNNames < length names' then (++ ["..."]) else id- ) . take maximumPGNNames+ ) . take (fromIntegral maximumPGNNames) ) maybeMaximumPGNNames names' where names' = Data.List.nub $ Data.List.sort names @@ -144,8 +143,8 @@ mergePGNDatabase pgnDatabase MkQualifiedMoveForest { deconstruct = initialForest } = MkQualifiedMoveForest $ foldr ( \pgn -> merge ( mkCompositeIdentifier &&& Data.Maybe.maybe (- Model.Result.mkResult Nothing -- The game is still in progress.- ) Model.GameTerminationReason.toResult . Model.Game.getMaybeTerminationReason . ContextualNotation.PGN.getGame $ pgn -- Construct an onymous result.+ Rule.Result.mkResult Nothing -- The game is still in progress.+ ) Rule.GameTerminationReason.toResult . Model.Game.getMaybeTerminationReason . ContextualNotation.PGN.getGame $ pgn -- Construct an onymous result. ) ( map Component.Turn.getQualifiedMove . Model.Game.listTurnsChronologically $ ContextualNotation.PGN.getGame pgn -- Extract the list of qualified moves defining this game. )@@ -192,10 +191,10 @@ fromPGNDatabase = (`mergePGNDatabase` Property.Empty.empty {-QualifiedMoveForest-}) -- | Find the minimum number of /piece/s in any of the recorded /game/s.-findMinimumPieces :: QualifiedMoveForest x y -> Component.Piece.NPieces+findMinimumPieces :: QualifiedMoveForest x y -> Type.Count.NPieces findMinimumPieces = slave ( State.Board.getNPieces (- Data.Default.def :: State.Board.Board T.X T.Y -- CAVEAT: this assumes the game to which the moves in the forest refer.+ 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. ) ) . deconstruct where slave nPieces [] = nPieces@@ -208,22 +207,22 @@ ) subForest -- Recurse. ) forest --- | Count the number of /game/s & /plies/.-count :: QualifiedMoveForest x y -> (Model.Game.NGames, Component.Move.NPlies)+-- | Count the number of /game/s & distinct /positions/.+count :: QualifiedMoveForest x y -> (Type.Count.NGames, Type.Count.NPositions) count = slave . deconstruct where slave = Data.List.foldl' (- \(nGames, nPlies) Data.Tree.Node {+ \(nGames, nPositions) Data.Tree.Node { Data.Tree.rootLabel = (_, maybeOnymousResult), Data.Tree.subForest = forest } -> let- acc@(nGames', nPlies') = (+ acc@(nGames', nPositions') = ( (+ nGames) . ( if Data.Maybe.isJust maybeOnymousResult then succ else id- ) *** (+ nPlies) . succ+ ) *** (+ nPositions) . succ ) $ slave forest {-recurse-}- in nGames' `seq` nPlies' `seq` acc+ in nGames' `seq` nPositions' `seq` acc ) (0, 0) {- |@@ -239,7 +238,7 @@ Show x, Show y ) => QualifiedMoveForest x y -> Model.GameTree.GameTree x y-{-# SPECIALISE toGameTree :: QualifiedMoveForest T.X T.Y -> Model.GameTree.GameTree T.X T.Y #-}+{-# SPECIALISE toGameTree :: QualifiedMoveForest Type.Length.X Type.Length.Y -> Model.GameTree.GameTree Type.Length.X Type.Length.Y #-} toGameTree MkQualifiedMoveForest { deconstruct = qualifiedMoveForest } = Model.GameTree.fromBareGameTree Data.Tree.Node { Data.Tree.rootLabel = initialGame, Data.Tree.subForest = map (slave initialGame) qualifiedMoveForest@@ -254,3 +253,4 @@ Data.Tree.subForest = map (slave game') qualifiedMoveForest' -- Recurse. } where game' = Model.Game.applyQualifiedMove qualifiedMove game+
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.Model.GameTerminationReason as Model.GameTerminationReason 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Applicative import qualified Control.Exception import qualified Control.Monad@@ -161,7 +161,7 @@ -> Component.Turn.Turn x y -> Model.Game.Game x y -- ^ The /game/ prior to application of the specified /turn/. -> ShowS-{-# SPECIALISE showsTurn :: ExplicitEnPassant -> Component.Turn.Turn T.X T.Y -> Model.Game.Game T.X T.Y -> 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@@ -200,7 +200,7 @@ ) . showsDestination ) . ( if Data.Maybe.isJust $ Model.Game.getMaybeChecked game'- then showChar $ if Data.Maybe.maybe False Model.GameTerminationReason.isCheckMate $ Model.Game.getMaybeTerminationReason game'+ then showChar $ if Data.Maybe.maybe False Rule.GameTerminationReason.isCheckMate $ Model.Game.getMaybeTerminationReason game' then checkMateFlag else checkFlag else id@@ -237,7 +237,7 @@ -> Component.Turn.Turn x y -> Model.Game.Game x y -- ^ The /game/ prior to application of the specified /turn/. -> String-{-# SPECIALISE showTurn :: ExplicitEnPassant -> Component.Turn.Turn T.X T.Y -> Model.Game.Game T.X T.Y -> 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'.@@ -253,7 +253,7 @@ -> Component.QualifiedMove.QualifiedMove x y -> Model.Game.Game x y -> ShowS-{-# SPECIALISE showsMove :: ExplicitEnPassant -> Component.QualifiedMove.QualifiedMove T.X T.Y -> Model.Game.Game T.X T.Y -> 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."@@ -273,7 +273,7 @@ -> Component.QualifiedMove.QualifiedMove x y -> Model.Game.Game x y -> String-{-# SPECIALISE showMove :: ExplicitEnPassant -> Component.QualifiedMove.QualifiedMove T.X T.Y -> Model.Game.Game T.X T.Y -> 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/.@@ -285,7 +285,7 @@ Show x, Show y ) => StandardAlgebraic x y -> Model.Game.Transformation x y-{-# SPECIALISE movePiece :: StandardAlgebraic T.X T.Y -> Model.Game.Transformation T.X T.Y #-}+{-# SPECIALISE movePiece :: StandardAlgebraic Type.Length.X Type.Length.Y -> Model.Game.Transformation Type.Length.X Type.Length.Y #-} movePiece MkStandardAlgebraic { getQualifiedMove = qualifiedMove } = Model.Game.applyQualifiedMove qualifiedMove #ifdef USE_POLYPARSE@@ -332,7 +332,7 @@ -> Model.Game.Game x y #ifdef USE_POLYPARSE -> Text.Poly.TextParser (StandardAlgebraic x y)-{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game T.X T.Y -> Text.Poly.TextParser (StandardAlgebraic T.X T.Y) #-}+{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game Type.Length.X Type.Length.Y -> Text.Poly.TextParser (StandardAlgebraic Type.Length.X Type.Length.Y) #-} parser explicitEnPassant validateMoves game = let nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour@@ -483,7 +483,7 @@ else return {-to Parser-monad-} qualifiedMove #else /* Parsec */ -> Parsec.Parser (StandardAlgebraic x y)-{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game T.X T.Y -> Parsec.Parser (StandardAlgebraic T.X T.Y) #-}+{-# SPECIALISE parser :: ExplicitEnPassant -> ValidateMoves -> Model.Game.Game Type.Length.X Type.Length.Y -> Parsec.Parser (StandardAlgebraic Type.Length.X Type.Length.Y) #-} parser explicitEnPassant validateMoves game = let nextLogicalColour = Model.Game.getNextLogicalColour game (longCastlingMove, shortCastlingMove) = Component.CastlingMove.getLongAndShortMoves nextLogicalColour
src-lib/BishBosh/Data/Either.hs view
@@ -28,6 +28,7 @@ xpickle ) where +import Control.Arrow((|||)) import qualified Text.XML.HXT.Arrow.Pickle as HXT {-@@ -39,7 +40,7 @@ -- | Pickler for an arbitrary datum of type 'Either'. xpickle :: HXT.PU l -> HXT.PU r -> HXT.PU (Either l r) xpickle lPickler rPickler = HXT.xpAlt (- const 0 `either` const 1 -- Index into the subsequent pickler-list.+ const 0 ||| const 1 -- Index into the subsequent pickler-list. ) [ HXT.xpWrap ( Left, -- Construct.
src-lib/BishBosh/Data/Exception.hs view
@@ -55,6 +55,7 @@ isBadRequest ) where +import Control.Arrow((|||)) import qualified Control.Exception import qualified Data.Typeable @@ -86,10 +87,10 @@ instance Control.Exception.Exception Exception instance Show Exception where- showsPrec _ MkException {+ showsPrec precedence MkException { getType = eitherBadDataOrBadRequest, getDetails = details- } = either shows shows eitherBadDataOrBadRequest . showString "; " . showString details+ } = (showsPrec precedence ||| showsPrec precedence) eitherBadDataOrBadRequest . showString "; " . showString details -- | Constructor. mkDuplicateData :: String -> Exception
− src-lib/BishBosh/Data/Float.hs
@@ -1,35 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of WeekDaze.-- WeekDaze 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.-- WeekDaze 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 WeekDaze. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Defines a /pickler/ for 'Float' & 'Double'.--}--module BishBosh.Data.Float() where--import qualified Text.XML.HXT.Arrow.Pickle as HXT--instance HXT.XmlPickler Float where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Double where- xpickle = HXT.xpPrim-
src-lib/BishBosh/Data/Integral.hs view
@@ -1,4 +1,3 @@-{-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -20,7 +19,7 @@ {- | [@AUTHOR@] Dr. Alistair Ward - [@DESCRIPTION@] Arbitrary operations for integral types.+ [@DESCRIPTION@] Arbitrary operations for numeric types. -} module BishBosh.Data.Integral(@@ -29,31 +28,7 @@ ) where import qualified Data.Char-import qualified Data.Int import qualified Data.List-import qualified Data.Word-import qualified Text.XML.HXT.Arrow.Pickle as HXT--instance HXT.XmlPickler Data.Int.Int8 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Int.Int16 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Int.Int32 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Word.Word8 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Word.Word16 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Word.Word32 where- xpickle = HXT.xpPrim--instance HXT.XmlPickler Data.Word.Word where- xpickle = HXT.xpPrim {- | * N.B. much faster than the instance of 'Read' for the integral type. TODO: compare with 'Numeric.readDec'.
src-lib/BishBosh/Data/Num.hs view
@@ -32,3 +32,4 @@ -- | Whether the specified number lies within the closed unit-interval, @[0,1]@; <https://en.wikipedia.org/wiki/Unit_interval>. inClosedUnitInterval :: (Num n, Ord n) => n -> Bool inClosedUnitInterval = uncurry (&&) . ((>= 0) &&& (<= 1))+
− src-lib/BishBosh/Data/Time.hs
@@ -1,41 +0,0 @@-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]--}--module BishBosh.Data.Time(--- * Functions- showsTimeAsSeconds,- measureElapsedTime- ) where--import qualified Data.Time.Clock-import qualified Text.Printf---- | Shows a time-difference as a number of seconds, to the required precision.-showsTimeAsSeconds :: Text.Printf.PrintfArg i => i -> Data.Time.Clock.NominalDiffTime -> ShowS-showsTimeAsSeconds nDecimalDigits time = showString $ Text.Printf.printf "%.*fs" nDecimalDigits (realToFrac time :: Double)---- | Measure the time which has elapsed since that specified.-measureElapsedTime :: Data.Time.Clock.UTCTime -> IO Data.Time.Clock.NominalDiffTime-measureElapsedTime startUTCTime = (`Data.Time.Clock.diffUTCTime` startUTCTime) `fmap` Data.Time.Clock.getCurrentTime-
src-lib/BishBosh/Evaluation/Fitness.hs view
@@ -49,12 +49,8 @@ import Control.Applicative((<|>)) import Control.Arrow((&&&)) import Data.Array.IArray((!))-import qualified BishBosh.Attribute.CriterionValue as Attribute.CriterionValue-import qualified BishBosh.Attribute.Direction as Attribute.Direction import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Cartesian.Ordinate as Cartesian.Ordinate@@ -65,35 +61,32 @@ import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Input.CriteriaWeights as Input.CriteriaWeights import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions+import qualified BishBosh.Input.RankValues as Input.RankValues+import qualified BishBosh.Metric.CriterionValue as Metric.CriterionValue+import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason import qualified BishBosh.State.Board as State.Board import qualified BishBosh.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour-import qualified BishBosh.Types as T+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.List import qualified Data.Map.Strict import qualified Data.Maybe -#ifdef USE_PARALLEL-import qualified Control.DeepSeq-#endif- #ifdef USE_UNBOXED_ARRAYS import qualified Data.Array.Unboxed #endif -- | Construct a criterion-value from a piece-square value.-mkPieceSquareCriterionValue :: (- Fractional criterionValue,- Ord criterionValue,- Real pieceSquareValue- ) => pieceSquareValue -> Attribute.CriterionValue.CriterionValue criterionValue-mkPieceSquareCriterionValue = Attribute.CriterionValue.mkCriterionValue . (+mkPieceSquareCriterionValue :: Real pieceSquareValue => pieceSquareValue -> Metric.CriterionValue.CriterionValue+mkPieceSquareCriterionValue = fromRational . ( / fromIntegral Component.Piece.nPiecesPerSide- ) . realToFrac+ ) . toRational -- | Measures the piece-square value from the perspective of the last player to move. measurePieceSquareValue :: (@@ -109,7 +102,7 @@ => Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue -> Model.Game.Game x y -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValue :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank T.X T.Y T.PieceSquareValue -> Model.Game.Game T.X T.Y -> T.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.@@ -138,7 +131,7 @@ -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue -> Model.Game.Game x y -> pieceSquareValue-{-# SPECIALISE measurePieceSquareValueIncrementally :: T.PieceSquareValue -> Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank T.X T.Y T.PieceSquareValue -> Model.Game.Game T.X T.Y -> T.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 #-} measurePieceSquareValueIncrementally previousPieceSquareValue pieceSquareByCoordinatesByRank game | Attribute.MoveType.isQuiet $ Component.QualifiedMove.getMoveType qualifiedMove = let findPieceSquareValues coordinatesList = Component.PieceSquareByCoordinatesByRank.findPieceSquareValues (@@ -158,26 +151,24 @@ qualifiedMove = Component.Turn.getQualifiedMove turn -- | Measure the arithmetic difference between the total /rank-value/ of the /piece/s currently held by either side; <https://www.chessprogramming.org/Material>.-measureValueOfMaterial :: (- Fractional criterionValue,- Fractional rankValue,- Ord criterionValue,- Real rankValue- )- => Attribute.RankValues.RankValues rankValue+measureValueOfMaterial+ :: Input.RankValues.RankValues+ -> Type.Mass.RankValue -- ^ Maximum total rank-value. -> Model.Game.Game x y- -> Attribute.CriterionValue.CriterionValue criterionValue--- {-# SPECIALISE measureValueOfMaterial :: Attribute.RankValues.RankValues T.RankValue -> Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfMaterial rankValues game = Attribute.CriterionValue.mkCriterionValue . (- / fromIntegral Component.Piece.nPiecesPerSide -- Normalise.- ) . realToFrac . (+ -> 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.+ ) . ( if Attribute.LogicalColour.isBlack $ Model.Game.getNextLogicalColour game then id -- White just moved. else negate -- Black just moved. ) . Data.List.foldl' (- \acc (rank, nPieces) -> if nPieces == 0- then acc -- Avoid calling 'Attribute.RankValues.findRankValue'.- else acc + Attribute.RankValues.findRankValue rank rankValues * fromIntegral nPieces+ \acc (rank, nPiecesDifference) -> if nPiecesDifference == 0+ then acc -- Avoid calling 'Input.RankValues.findRankValue'.+ else acc + toRational (+ 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 {- |@@ -192,7 +183,7 @@ => getWeightOfMobility * 1 > weightOfMaterial * (8.8 / 102.47) => getWeightOfMobility > weightOfMaterial / 11.6 - The corollary is that one probably shouldn't sacrifice even a @Knight@ to temporarily reduce one's opponent mobility to one.+ The corollary is that one probably shouldn't sacrifice even a @Knight@ to temporarily reduce one's opponent's mobility to one. measureValueOfMobility = 0.5 when mobility = 1, => getWeightOfMobility * 0.5 < weightOfMaterial * (3.2 / 102.47) => getWeightOfMobility < weightOfMaterial / 16.0@@ -201,28 +192,23 @@ This presents a paradox ! -} measureValueOfMobility :: (- Enum x,- Enum y,- Fractional criterionValue,- Ord criterionValue,- Ord x,- Ord y,- Show x,- Show y- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue-{-# SPECIALISE measureValueOfMobility :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfMobility game = Attribute.CriterionValue.mkCriterionValue . uncurry (-) . (+ 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 (-) . ( measureConstriction &&& measureConstriction . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where- measureConstriction logicalColour = recip . fromIntegral . succ {-avoid divide-by-zero-} $ Model.Game.countMovesAvailableTo logicalColour game+ 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 :: (- Fractional criterionValue,- Ord criterionValue- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue--- {-# SPECIALISE measureValueOfCastlingPotential :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfCastlingPotential game = Attribute.CriterionValue.mkCriterionValue . uncurry (-) . (+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 (-) . ( castlingPotential . Property.Opposable.getOpposite {-recent mover-} &&& castlingPotential ) $ Model.Game.getNextLogicalColour game where castlingPotential = Data.Maybe.maybe 1 {-have Castled-} (@@ -238,18 +224,15 @@ * 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 :: (- Fractional criterionValue,- Ord criterionValue- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue--- {-# SPECIALISE measureValueOfDoubledPawns :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfDoubledPawns game = Attribute.CriterionValue.mkCriterionValue . (+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.- ) . fromIntegral . uncurry (-) . (+ ) . fromIntegral {-NPieces-} . uncurry (-) . ( countDoubledPawns &&& countDoubledPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where countDoubledPawns logicalColour = uncurry (-) . (- Data.Map.Strict.foldl' (+) 0 &&& Data.Map.Strict.size {-one Pawn can't be considered to be doubled, so substract one Pawn per column-}+ 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-} ) $ State.Board.getNPawnsByFileByLogicalColour (Model.Game.getBoard game) ! logicalColour {- |@@ -257,19 +240,14 @@ * 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,- Fractional criterionValue,- Ord criterionValue,- Ord x- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue-{-# SPECIALISE measureValueOfIsolatedPawns :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfIsolatedPawns game = Attribute.CriterionValue.mkCriterionValue . (- / fromIntegral 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, ...).- ) . fromIntegral . uncurry (-) . (+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, ...).+ ) . fromIntegral {-NPieces-} . uncurry (-) . ( countIsolatedPawns &&& countIsolatedPawns . Property.Opposable.getOpposite {-recent mover-} ) $ Model.Game.getNextLogicalColour game where- countIsolatedPawns :: Attribute.LogicalColour.LogicalColour -> Component.Piece.NPieces+ 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@@ -280,22 +258,17 @@ 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 criterionValue. (- Enum y,- Fractional criterionValue,- Ord criterionValue- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue-{-# SPECIALISE measureValueOfPassedPawns :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfPassedPawns game = Attribute.CriterionValue.mkCriterionValue . (- / fromIntegral Cartesian.Abscissa.xLength -- Normalise to [-1 .. 1].+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]. ) . uncurry (-) . ( valuePassedPawns . Property.Opposable.getOpposite {-recent mover-} &&& valuePassedPawns ) $ Model.Game.getNextLogicalColour game where- valuePassedPawns :: Attribute.LogicalColour.LogicalColour -> criterionValue valuePassedPawns logicalColour = Data.List.foldl' (- \acc -> (acc +) . recip {-value increases exponentially as distance to promotion decreases-} . fromIntegral . abs . subtract (+ \acc -> (acc +) . recip {-value increases exponentially as distance to promotion decreases-} . fromIntegral {-Int-} . abs . subtract ( fromEnum (- Cartesian.Ordinate.lastRank logicalColour :: y+ Cartesian.Ordinate.lastRank logicalColour :: y -- N.B.: ScopedTypeVariables. ) ) . fromEnum . Cartesian.Coordinates.getY -- Measure the distance to promotion. ) 0 $ State.Board.getPassedPawnCoordinatesByLogicalColour (Model.Game.getBoard game) ! logicalColour@@ -303,16 +276,18 @@ {- | * The constant maximum total number of times the /piece/s of either side, can be defended. - * This calculation assumes that:+ * Assumes all Pawns have been Queened. - ** every /piece/ can defend another in every /direction/ it can attack,- which is impossible, since in a 2-D board one can always draw a perimeter around the /piece/s,- beyond which there're zero /pieces/ to defend, so the outer /piece/s can never be fully utilised;+ * CAVEAT: assuming the optimal arrangement of pieces: - ** all @Pawn@s have been /queened/, which is unrealistic.+ RQQB = 3 + 7 + 3 + 2 = 15+ QQQN = 4 + 6 + 8 + 4 = 22+ NQQK = 4 + 8 + 6 + 0 = 18+ BQQR = 2 + 3 + 7 + 3 = 15+ = 70 -}-maximumDefended :: Component.Piece.NPieces-maximumDefended = (9 {-Queens-} + 1 {-King-} + 2 {-Knights-} + 2 {-Rooks + Bishops-}) * Attribute.Direction.nDistinctDirections+maximumDefended :: Type.Count.NPieces+maximumDefended = 70 {- | * Measure the normalised arithmetic difference between the number of /piece/s defending each of one's own, on either side.@@ -326,14 +301,11 @@ * CAVEAT: this criterion competes with /mobility/, since each defended /piece/ blocks the path of the defender. -}-measureValueOfDefence :: (- Fractional criterionValue,- Ord criterionValue- ) => Model.Game.Game x y -> Attribute.CriterionValue.CriterionValue criterionValue--- {-# SPECIALISE measureValueOfDefence :: Model.Game.Game T.X T.Y -> Attribute.CriterionValue.CriterionValue T.CriterionValue #-}-measureValueOfDefence game = Attribute.CriterionValue.mkCriterionValue . (- / fromIntegral maximumDefended -- Normalise.- ) . fromIntegral . uncurry (-) . (+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.+ ) . fromIntegral {-NPieces-} . uncurry (-) . ( (! Property.Opposable.getOpposite {-recent mover-} nextLogicalColour) &&& (! nextLogicalColour) ) . State.Board.summariseNDefendersByLogicalColour $ Model.Game.getBoard game where nextLogicalColour = Model.Game.getNextLogicalColour game@@ -350,50 +322,39 @@ * Many possible criteria aren't measured because they're, either currently or imminently, represented by those that are, typically by 'measureValueOfMaterial'. -} evaluateFitness :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif #ifdef USE_UNBOXED_ARRAYS Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size). #endif Enum x, Enum y,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Ord x, Ord y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y ) => Maybe pieceSquareValue -- ^ An optional value for the specified game. -> Model.Game.Game x y- -> Input.EvaluationOptions.Reader criterionWeight pieceSquareValue rankValue x y (- Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue- )-{-# SPECIALISE evaluateFitness :: Maybe T.PieceSquareValue -> Model.Game.Game T.X T.Y -> Input.EvaluationOptions.Reader T.CriterionWeight T.PieceSquareValue T.RankValue T.X T.Y (Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues T.WeightedMean T.CriterionValue) #-}+ -> 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 #-} evaluateFitness maybePieceSquareValue game- | Just gameTerminationReason <- Model.Game.getMaybeTerminationReason game = return {-to Reader-monad-} $ Attribute.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues (- if Model.GameTerminationReason.isCheckMate gameTerminationReason+ | Just gameTerminationReason <- Model.Game.getMaybeTerminationReason game = return {-to Reader-monad-} $ Metric.WeightedMeanAndCriterionValues.mkWeightedMeanAndCriterionValues (+ if Rule.GameTerminationReason.isCheckMate gameTerminationReason then 1 -- The last player to move, has won. else 0 -- A draw. ) [] | otherwise = do criteriaWeights <- Control.Monad.Reader.asks Input.EvaluationOptions.getCriteriaWeights- rankValues <- Control.Monad.Reader.asks Input.EvaluationOptions.getRankValues+ rankValuePair <- Control.Monad.Reader.asks $ Input.EvaluationOptions.getRankValues &&& Input.EvaluationOptions.getMaximumTotalRankValue maybePieceSquareByCoordinatesByRank <- Control.Monad.Reader.asks Input.EvaluationOptions.getMaybePieceSquareByCoordinatesByRank return {-to Reader-monad-} $ Input.CriteriaWeights.calculateWeightedMean criteriaWeights (- measureValueOfMaterial rankValues game+ uncurry measureValueOfMaterial rankValuePair game ) ( measureValueOfMobility game ) (- Data.Maybe.maybe Attribute.CriterionValue.zero mkPieceSquareCriterionValue $ maybePieceSquareValue <|> fmap (+ Data.Maybe.maybe 0 mkPieceSquareCriterionValue $ maybePieceSquareValue <|> fmap ( `measurePieceSquareValue` game ) maybePieceSquareByCoordinatesByRank ) (
src-lib/BishBosh/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -66,22 +66,24 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues-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.RoseTree as Data.RoseTree-import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness-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.Model.GameTree as Model.GameTree-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.Types as T+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.RoseTree as Data.RoseTree+import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness+import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame+import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions+import qualified BishBosh.Input.RankValues as Input.RankValues+import qualified BishBosh.Input.SearchOptions as Input.SearchOptions+import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Model.GameTree as Model.GameTree+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.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@@ -89,56 +91,48 @@ import qualified Data.Maybe import qualified Data.Tree -#ifdef USE_PARALLEL-import qualified Control.DeepSeq-#endif- #ifdef USE_UNBOXED_ARRAYS import qualified Data.Array.Unboxed #endif -- | Define a node in the tree to contain the hash of a /game/ & an evaluation of the fitness of that /game/.-data NodeLabel x y positionHash criterionValue weightedMean = MkNodeLabel {+data NodeLabel x y positionHash = MkNodeLabel { getPositionHash :: positionHash, -- ^ The hash of the /game/ contained in 'getQuantifiedGame'.- getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean+ getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y } deriving (Eq, Show) -instance (Enum x, Enum y, Real weightedMean) => Notation.MoveNotation.ShowNotationFloat (NodeLabel x y positionHash criterionValue weightedMean) where+instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (NodeLabel x y positionHash) where showsNotationFloat moveNotation showsDouble MkNodeLabel { getQuantifiedGame = quantifiedGame } = Notation.MoveNotation.showsNotation moveNotation ( Evaluation.QuantifiedGame.getLastTurn quantifiedGame ) . showString "\t=> " . showsDouble (- realToFrac . Attribute.WeightedMeanAndCriterionValues.getWeightedMean $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame+ realToFrac . Metric.WeightedMeanAndCriterionValues.getWeightedMean $ Evaluation.QuantifiedGame.getWeightedMeanAndCriterionValues quantifiedGame ) -instance Property.Null.Null (NodeLabel x y positionHash criterionValue weightedMean) where+instance Property.Null.Null (NodeLabel x y 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 criterionValue weightedMean)+equalsLastQualifiedMove :: (Eq x, Eq y) => Component.QualifiedMove.QualifiedMove x y -> Data.RoseTree.IsMatch (NodeLabel x y 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 criterionValue weightedMean = Data.Tree.Tree (NodeLabel x y positionHash criterionValue weightedMean)+type BarePositionHashQuantifiedGameTree x y positionHash = Data.Tree.Tree (NodeLabel x y positionHash) -- | Accessor.-getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean+getRootQuantifiedGame' :: BarePositionHashQuantifiedGameTree x y positionHash -> Evaluation.QuantifiedGame.QuantifiedGame x y getRootQuantifiedGame' Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getQuantifiedGame = quantifiedGame } } = quantifiedGame -- | Wrap the bare tree.-newtype PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean = MkPositionHashQuantifiedGameTree {- deconstruct :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+newtype PositionHashQuantifiedGameTree x y positionHash = MkPositionHashQuantifiedGameTree {+ deconstruct :: BarePositionHashQuantifiedGameTree x y positionHash } deriving Eq -instance Property.Arboreal.Prunable (PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean) where+instance Property.Arboreal.Prunable (PositionHashQuantifiedGameTree x y positionHash) where prune depth MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree } = MkPositionHashQuantifiedGameTree $ Property.Arboreal.prune depth barePositionHashQuantifiedGameTree -instance (- Enum x,- Enum y,- Real weightedMean- ) => Notation.MoveNotation.ShowNotationFloat (PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean) where+instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (PositionHashQuantifiedGameTree x y 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@@ -147,45 +141,36 @@ toString nodeLabel = Notation.MoveNotation.showsNotationFloat moveNotation showsDouble nodeLabel "" -- | Constructor.-fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+fromBarePositionHashQuantifiedGameTree :: BarePositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash fromBarePositionHashQuantifiedGameTree = MkPositionHashQuantifiedGameTree -- | Constructor. mkPositionHashQuantifiedGameTree :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif 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). #endif Data.Bits.Bits positionHash,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Integral x, Integral y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y )- => Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y+ => Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y -> 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 criterionValue weightedMean+ -> PositionHashQuantifiedGameTree x y positionHash {-# SPECIALISE mkPositionHashQuantifiedGameTree- :: Input.EvaluationOptions.EvaluationOptions T.CriterionWeight T.PieceSquareValue T.RankValue T.X T.Y+ :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y -> Input.SearchOptions.SearchOptions- -> Component.Zobrist.Zobrist T.X T.Y T.PositionHash- -> Model.GameTree.MoveFrequency T.X T.Y- -> Model.Game.Game T.X T.Y- -> PositionHashQuantifiedGameTree T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean+ -> 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 #-} mkPositionHashQuantifiedGameTree evaluationOptions searchOptions zobrist moveFrequency seedGame = MkPositionHashQuantifiedGameTree ( if Input.EvaluationOptions.getIncrementalEvaluation evaluationOptions@@ -237,11 +222,11 @@ bareGameTree = Model.GameTree.deconstruct . Model.GameTree.sortGameTree ( Input.SearchOptions.getMaybeCaptureMoveSortAlgorithm searchOptions ) (- `Attribute.RankValues.findRankValue` Input.EvaluationOptions.getRankValues evaluationOptions+ `Input.RankValues.findRankValue` Input.EvaluationOptions.getRankValues evaluationOptions ) moveFrequency $ Model.GameTree.fromGame seedGame -- | Accessor.-getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> positionHash+getRootPositionHash :: PositionHashQuantifiedGameTree x y positionHash -> positionHash getRootPositionHash MkPositionHashQuantifiedGameTree { deconstruct = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getPositionHash = positionHash }@@ -249,7 +234,7 @@ } = positionHash -- | Accessor.-getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean+getRootQuantifiedGame :: PositionHashQuantifiedGameTree x y positionHash -> Evaluation.QuantifiedGame.QuantifiedGame x y getRootQuantifiedGame MkPositionHashQuantifiedGameTree { deconstruct = Data.Tree.Node { Data.Tree.rootLabel = MkNodeLabel { getQuantifiedGame = quantifiedGame }@@ -258,29 +243,29 @@ -- | Forward request. reduce- :: Data.RoseTree.IsMatch (NodeLabel x y positionHash criterionValue weightedMean)- -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean- -> Maybe (PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean)+ :: Data.RoseTree.IsMatch (NodeLabel x y positionHash)+ -> PositionHashQuantifiedGameTree x y positionHash+ -> Maybe (PositionHashQuantifiedGameTree x y 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 criterionValue weightedMean))- -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+ :: (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 criterionValue weightedMean]+ -> Maybe [NodeLabel x y 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 criterionValue weightedMean+ => PositionHashQuantifiedGameTree x y positionHash -> [Component.QualifiedMove.QualifiedMove x y]- -> Maybe [NodeLabel x y positionHash criterionValue weightedMean] -- ^ Returns 'Nothing', on failure to match a move.+ -> Maybe [NodeLabel x y 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 criterionValue weightedMean -> PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+resign :: PositionHashQuantifiedGameTree x y positionHash -> PositionHashQuantifiedGameTree x y positionHash resign MkPositionHashQuantifiedGameTree { deconstruct = barePositionHashQuantifiedGameTree@Data.Tree.Node { Data.Tree.rootLabel = nodeLabel@MkNodeLabel { getQuantifiedGame = quantifiedGame }@@ -292,7 +277,7 @@ } -- | Self-documentation.-type Forest x y positionHash criterionValue weightedMean = [BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean]+type Forest x y positionHash = [BarePositionHashQuantifiedGameTree x y positionHash] {- | * Promotes the first matching /move/ to the head of the forest, then descends & recursively promotes the next matching move in the sub-forest.@@ -301,9 +286,9 @@ -} 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 criterionValue weightedMean- -> Maybe (Forest x y positionHash criterionValue weightedMean) -- ^ Returns 'Nothing' on failure to match a move.+ => [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. promoteMatchingMoves = Data.RoseTree.promote equalsLastQualifiedMove {- |@@ -312,9 +297,9 @@ * N.B.: this can be used to dynamically re-order the forest using the killer heuristic. -} sortNonCaptureMoves- :: (Forest x y positionHash criterionValue weightedMean -> Forest x y positionHash criterionValue weightedMean)- -> Forest x y positionHash criterionValue weightedMean- -> Forest x y positionHash criterionValue weightedMean+ :: (Forest x y positionHash -> Forest x y positionHash)+ -> Forest x y positionHash+ -> Forest x y 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
@@ -54,17 +54,19 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues-import qualified BishBosh.Component.Move as Component.Move-import qualified BishBosh.Component.Turn as Component.Turn-import qualified BishBosh.Data.Exception as Data.Exception-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.Notation.MoveNotation as Notation.MoveNotation-import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Component.Turn as Component.Turn+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Evaluation.Fitness as Evaluation.Fitness+import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions+import qualified BishBosh.Metric.WeightedMeanAndCriterionValues as Metric.WeightedMeanAndCriterionValues+import qualified BishBosh.Model.Game as Model.Game+import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation+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 import qualified Data.Maybe@@ -75,80 +77,67 @@ #endif -- | The selected /game/ & the criteria against which it was quantified.-data QuantifiedGame x y criterionValue weightedMean = MkQuantifiedGame {+data QuantifiedGame x y = MkQuantifiedGame { getGame :: Model.Game.Game x y, -- ^ The /game/ resulting from a sequence of /turn/s.- getWeightedMeanAndCriterionValues :: Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue+ getWeightedMeanAndCriterionValues :: Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues } deriving (Eq, Show) -instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (QuantifiedGame x y criterionValue weightedMean) where+instance Control.DeepSeq.NFData (QuantifiedGame x y) where rnf MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Control.DeepSeq.rnf weightedMeanAndCriterionValues -- The other field is a prerequisite. -instance (Enum x, Enum y, Real criterionValue, Real weightedMean) => Notation.MoveNotation.ShowNotationFloat (QuantifiedGame x y criterionValue weightedMean) where+instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (QuantifiedGame x y) where showsNotationFloat moveNotation showsDouble quantifiedGame = Text.ShowList.showsAssociationList Text.ShowList.showsSeparator $ map ($ quantifiedGame) [ (,) Component.Move.tag . Notation.MoveNotation.showsNotation moveNotation . getLastTurn,- (,) Attribute.WeightedMeanAndCriterionValues.weightedMeanTag . showsDouble . realToFrac . getFitness,- (,) Attribute.WeightedMeanAndCriterionValues.criterionValuesTag . Text.ShowList.showsFormattedList' (showsDouble . realToFrac) . Attribute.WeightedMeanAndCriterionValues.getCriterionValues . getWeightedMeanAndCriterionValues+ (,) 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 criterionValue weightedMean) where+instance Property.Null.Null (QuantifiedGame x y) where isNull MkQuantifiedGame { getGame = game } = Property.Null.isNull game -- | Accessor.-getFitness :: QuantifiedGame x y criterionValue weightedMean -> weightedMean-getFitness MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Attribute.WeightedMeanAndCriterionValues.getWeightedMean weightedMeanAndCriterionValues+getFitness :: QuantifiedGame x y -> Type.Mass.WeightedMean+getFitness MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = Metric.WeightedMeanAndCriterionValues.getWeightedMean weightedMeanAndCriterionValues --- | Like 'fromGame' except that the caller determines the piece-square value.+-- | Constructor. fromGame :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif #ifdef USE_UNBOXED_ARRAYS Data.Array.Unboxed.IArray Data.Array.Unboxed.UArray pieceSquareValue, -- Requires 'FlexibleContexts'. The unboxed representation of the array-element must be defined (& therefore must be of fixed size). #endif Enum x, Enum y,- Fractional criterionValue, Fractional pieceSquareValue,- Fractional rankValue,- Fractional weightedMean, Ord x, Ord y,- Real criterionValue,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show x, Show y ) => Maybe pieceSquareValue -- ^ The value for the specified game. -> Model.Game.Game x y -- ^ The current state of the /game/.- -> Input.EvaluationOptions.Reader criterionWeight pieceSquareValue rankValue x y (QuantifiedGame x y criterionValue weightedMean)-{-# SPECIALISE fromGame :: Maybe T.PieceSquareValue -> Model.Game.Game T.X T.Y -> Input.EvaluationOptions.Reader T.CriterionWeight T.PieceSquareValue T.RankValue T.X T.Y (QuantifiedGame T.X T.Y T.CriterionValue T.WeightedMean) #-}+ -> 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) #-} fromGame maybePieceSquareValue game = MkQuantifiedGame game `fmap` Evaluation.Fitness.evaluateFitness maybePieceSquareValue game -- | Retrieve the /turn/ used to generate the selected /game/.-getLastTurn :: QuantifiedGame x y criterionValue weightedMean -> Component.Turn.Turn x y+getLastTurn :: QuantifiedGame x y -> Component.Turn.Turn x y 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 --- | Drop the specified number of old turns from the start of the chronological sequence, leaving the most recent.+-- | Drop the specified number of plies from the start of the chronological sequence, leaving the most recent. getLatestTurns- :: Component.Move.NPlies- -> QuantifiedGame x y criterionValue weightedMean+ :: Type.Count.NPlies -- ^ The number of plies to drop from the start of the chronological sequence.+ -> QuantifiedGame x y -> [Component.Turn.Turn x y]-getLatestTurns nPlies MkQuantifiedGame { getGame = game } = drop nPlies $ Model.Game.listTurnsChronologically game+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 :: Num weightedMean => QuantifiedGame x y criterionValue weightedMean -> QuantifiedGame x y criterionValue weightedMean-negateFitness quantifiedGame@MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = quantifiedGame { getWeightedMeanAndCriterionValues = Attribute.WeightedMeanAndCriterionValues.negateWeightedMean weightedMeanAndCriterionValues }+negateFitness :: QuantifiedGame x y -> QuantifiedGame x y+negateFitness quantifiedGame@MkQuantifiedGame { getWeightedMeanAndCriterionValues = weightedMeanAndCriterionValues } = quantifiedGame { getWeightedMeanAndCriterionValues = Metric.WeightedMeanAndCriterionValues.negateWeightedMean weightedMeanAndCriterionValues } -- | Compares fitness.-compareFitness- :: Ord weightedMean- => QuantifiedGame x y criterionValue weightedMean- -> QuantifiedGame x y criterionValue weightedMean- -> Ordering+compareFitness :: QuantifiedGame x y -> QuantifiedGame x y -> Ordering compareFitness = Data.Ord.comparing getFitness {- |@@ -156,12 +145,13 @@ * N.B.: 'Nothing' is interpreted as unbounded. -}-type OpenInterval x y criterionValue weightedMean = (Maybe (QuantifiedGame x y criterionValue weightedMean), Maybe (QuantifiedGame x y criterionValue weightedMean))+type OpenInterval x y = (Maybe (QuantifiedGame x y), Maybe (QuantifiedGame x y)) -- | Constant.-unboundedInterval :: OpenInterval x y criterionValue weightedMean+unboundedInterval :: OpenInterval x y unboundedInterval = (Nothing, Nothing) -- | Reflect the interval about zero.-negateInterval :: Num weightedMean => OpenInterval x y criterionValue weightedMean -> OpenInterval x y criterionValue weightedMean+negateInterval :: OpenInterval x y -> OpenInterval x y negateInterval (maybeAlpha, maybeBeta) = ($ maybeBeta) &&& ($ maybeAlpha) $ fmap negateFitness+
src-lib/BishBosh/Input/CECPFeatures.hs view
@@ -81,8 +81,9 @@ ) where import BishBosh.Data.Bool() -- For 'HXT.XmlPickler Bool'.-import qualified BishBosh.Data.Foldable as Data.Foldable+import Control.Arrow((|||)) import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Foldable as Data.Foldable import qualified BishBosh.Text.ShowList as Text.ShowList import qualified Control.DeepSeq import qualified Control.Exception@@ -329,7 +330,7 @@ \s -> case reads s of [(i, "")] -> Left i _ -> Right s,- \value -> showChar '"' $ either shows showString value "\""+ \value -> showChar '"' $ (shows ||| showString) value "\"" ) ( HXT.xpAttr "value" HXT.xpText0 )@@ -338,17 +339,15 @@ ) where def = Data.Default.def --- | Smart-constructor.+-- | Smart constructor. mkCECPFeatures :: [Feature] -> Bool -> CECPFeatures mkCECPFeatures features done | Just (key, _) <- Data.List.find ( not . all Data.Char.isAlpha . fst {-key-} ) features = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.CECPFeatures.mkCECPFeatures:\tinvalid key" . Text.ShowList.showsAssociation $ shows key "." | Just (_, value) <- Data.List.find (- either (- const False- ) (- any (`elem` "\"\n\r") -- Prevent command-injection.+ (+ const False ||| any (`elem` "\"\n\r") {-Prevent command-injection-} ) . snd {-value-} ) features = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.CECPFeatures.mkCECPFeatures:\tinvalid value" . Text.ShowList.showsAssociation $ shows value "." | not $ null duplicateFeatures = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Input.CECPFeatures.mkCECPFeatures:\tduplicate features " $ shows duplicateFeatures "."@@ -380,11 +379,9 @@ getFeatures = features } = cecpFeatures { getFeatures = filter (- either (- const $ (/= key) . fst- ) (- const (/= feature) -- N.B.: string-valued features must also match the specified value, to account for possibility of duplicates.- ) value+ const (+ (/= key) . fst+ ) ||| const (/= feature) {-N.B.: string-valued features must also match the specified value, to account for possibility of duplicates-} $ value ) features } @@ -403,6 +400,6 @@ } = Data.Maybe.maybe ( Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Input.CECPFeatures.isFeatureDisabled:\t" $ shows key " not found." ) (- (== 0) `either` null+ (== 0) ||| null ) $ lookup key features
src-lib/BishBosh/Input/CECPOptions.hs view
@@ -62,17 +62,20 @@ setProtocolVersion, updateFeature, deleteFeature,- resetModes+ resetModes,+ pause,+ resume ) where import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.CECPFeatures as Input.CECPFeatures+import qualified BishBosh.Property.Switchable as Property.Switchable import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Time.StopWatch as Time.StopWatch import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Default import qualified Data.Maybe-import qualified Data.Time.Clock import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify XML.@@ -119,14 +122,14 @@ -- | Defines options related to CECP. data CECPOptions = MkCECPOptions {- getAnalyseMode :: Mode, -- ^ TODO.- getDisplaySAN :: Bool, -- ^ Whether to display moves in SAN or 'Input.UIOptions.getMoveNotation'.- getEditMode :: Mode, -- ^ Whether the game should be placed in set-up mode.- getForceMode :: Mode, -- ^ Neither player's moves are automated, allowing an arbitrary game to be configured.- getMaybePaused :: Maybe Data.Time.Clock.NominalDiffTime, -- ^ Whether the engine was paused after the specified time.- getPonderMode :: Mode, -- ^ Whether to keep thinking while it's one's opponent's turn.- getPostMode :: Mode, -- ^ Whether to show the details of deliberations.- getProtocolVersion :: ProtocolVersion, -- ^ The version of the CECP-protocol to use.+ getAnalyseMode :: Mode, -- ^ TODO.+ getDisplaySAN :: Bool, -- ^ Whether to display moves in SAN or 'Input.UIOptions.getMoveNotation'.+ getEditMode :: Mode, -- ^ Whether the game should be placed in set-up mode.+ getForceMode :: Mode, -- ^ Neither player's moves are automated, allowing an arbitrary game to be configured.+ getMaybePaused :: Maybe Time.StopWatch.StopWatch, -- ^ Whether the engine was paused & a paused watch.+ getPonderMode :: Mode, -- ^ Whether to keep thinking while it's one's opponent's turn.+ getPostMode :: Mode, -- ^ Whether to show the details of deliberations.+ getProtocolVersion :: ProtocolVersion, -- ^ The version of the CECP-protocol to use. getCECPFeatures :: Input.CECPFeatures.CECPFeatures } deriving Eq @@ -200,19 +203,18 @@ instance HXT.XmlPickler CECPOptions where xpickle = HXT.xpElem tag . HXT.xpWrap (- \(a, b, c, d, e, f, g, h, i) -> mkCECPOptions a b c d e f g h i, -- Construct.+ \(a, b, c, d, e, f, g, h) -> mkCECPOptions a b c d (getMaybePaused def) e f g h, -- Construct. \MkCECPOptions { getAnalyseMode = analyseMode, getDisplaySAN = displaySAN, getEditMode = editMode, getForceMode = forceMode,- getMaybePaused = maybePaused, getPonderMode = ponderMode, getPostMode = postMode, getProtocolVersion = protocolVersion, getCECPFeatures = cecpFeatures- } -> (analyseMode, displaySAN, editMode, forceMode, maybePaused, ponderMode, postMode, protocolVersion, cecpFeatures) -- Deconstruct.- ) $ HXT.xp9Tuple (+ } -> (analyseMode, displaySAN, editMode, forceMode, ponderMode, postMode, protocolVersion, cecpFeatures) -- Deconstruct.+ ) $ HXT.xp8Tuple ( getAnalyseMode def `HXT.xpDefault` HXT.xpAttr analyseModeTag HXT.xpickle ) ( getDisplaySAN def `HXT.xpDefault` HXT.xpAttr displaySANTag HXT.xpickle@@ -221,8 +223,6 @@ ) ( getForceMode def `HXT.xpDefault` HXT.xpAttr forceModeTag HXT.xpickle ) (- HXT.xpOption . HXT.xpWrap (toEnum, fromEnum) $ HXT.xpAttr pausedTag HXT.xpInt- ) ( getPonderMode def `HXT.xpDefault` HXT.xpAttr ponderModeTag HXT.xpickle ) ( getPostMode def `HXT.xpDefault` HXT.xpAttr postModeTag HXT.xpickle@@ -233,23 +233,22 @@ -- | Smart constructor. mkCECPOptions- :: Mode -- ^ Analyse-mode.- -> Bool -- ^ Display SAN.- -> Mode -- ^ Edit-mode.- -> Mode -- ^ Force-mode.- -> Maybe Data.Time.Clock.NominalDiffTime -- ^ Paused.- -> Mode -- ^ Ponder-mode.- -> Mode -- ^ Post-mode.+ :: Mode -- ^ Analyse-mode.+ -> Bool -- ^ Display SAN.+ -> Mode -- ^ Edit-mode.+ -> Mode -- ^ Force-mode.+ -> Maybe Time.StopWatch.StopWatch -- ^ Paused.+ -> Mode -- ^ Ponder-mode.+ -> Mode -- ^ Post-mode. -> ProtocolVersion -> Input.CECPFeatures.CECPFeatures -> CECPOptions mkCECPOptions analyseMode displaySAN editMode forceMode maybePaused ponderMode postMode protocolVersion cecpFeatures- | protocolVersion < 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.UI.CECPOptions.mkCECPOptions:\t" $ shows protocolVersionTag " must exceed zero."- | Data.Maybe.maybe False (< 0) maybePaused = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.UI.CECPOptions.mkCECPOptions:\t" $ shows pausedTag "; time already taken can't be negative."- | otherwise = MkCECPOptions {+ | protocolVersion < 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.UI.CECPOptions.mkCECPOptions:\t" $ shows protocolVersionTag " must exceed zero."+ | otherwise = MkCECPOptions { getAnalyseMode = analyseMode,- getEditMode = editMode, getDisplaySAN = displaySAN,+ getEditMode = editMode, getForceMode = forceMode, getMaybePaused = maybePaused, getPonderMode = ponderMode,@@ -322,4 +321,16 @@ postMode ) ]++-- | Mutator.+pause :: Time.StopWatch.StopWatch -> CECPOptions -> CECPOptions+pause _ MkCECPOptions { getMaybePaused = Just _ } = Control.Exception.throw $ Data.Exception.mkRequestFailure "BishBosh.Input.CECPOptions.pause:\talready paused."+pause stopWatch cecpOptions+ | Property.Switchable.isOn stopWatch = Control.Exception.throw $ Data.Exception.mkRequestFailure "BishBosh.Input.CECPOptions.pause:\tthe stop-watch is still running."+ | otherwise = cecpOptions { getMaybePaused = Just stopWatch }++-- | Mutator.+resume :: CECPOptions -> CECPOptions+resume MkCECPOptions { getMaybePaused = Nothing } = Control.Exception.throw $ Data.Exception.mkRequestFailure "BishBosh.Input.CECPOptions.resume:\talready resumed."+resume cecpOptions = cecpOptions { getMaybePaused = Nothing }
src-lib/BishBosh/Input/CategorisedCommandLineOptions.hs view
@@ -103,3 +103,4 @@ -- | Mutator. prependOptionsMutator :: OptionsMutator options -> Transformation options prependOptionsMutator optionsMutator categorisedCommandLineOptions = categorisedCommandLineOptions { getOptionsMutators = optionsMutator : getOptionsMutators categorisedCommandLineOptions }+
src-lib/BishBosh/Input/CriteriaWeights.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -53,60 +52,60 @@ -- * Functions calculateWeightedMean, normalise,- perturbWeights,+-- perturbWeights, -- ** Constructor mkCriteriaWeights ) where -import qualified BishBosh.Attribute.CriterionValue as Attribute.CriterionValue-import qualified BishBosh.Attribute.CriterionWeight as Attribute.CriterionWeight-import qualified BishBosh.Attribute.WeightedMeanAndCriterionValues as Attribute.WeightedMeanAndCriterionValues-import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Property.ShowFloat as Property.ShowFloat-import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Metric.CriterionValue as Metric.CriterionValue+import qualified BishBosh.Metric.CriterionWeight as Metric.CriterionWeight+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+import qualified Text.XML.HXT.Arrow.Pickle as HXT -- | Used to qualify the XML. tag :: String-tag = "criteriaWeights"+tag = "criteriaWeights" -- | Used to qualify the XML. weightOfMaterialTag :: String-weightOfMaterialTag = "material"+weightOfMaterialTag = "material" -- | Used to qualify the XML. weightOfMobilityTag :: String-weightOfMobilityTag = "mobility"+weightOfMobilityTag = "mobility" -- | Used to qualify the XML. weightOfPieceSquareValueTag :: String-weightOfPieceSquareValueTag = "pieceSquareValue"+weightOfPieceSquareValueTag = "pieceSquareValue" -- | Used to qualify the XML. weightOfCastlingPotentialTag :: String-weightOfCastlingPotentialTag = "castlingPotential"+weightOfCastlingPotentialTag = "castlingPotential" -- | Used to qualify the XML. weightOfDefenceTag :: String-weightOfDefenceTag = "defence"+weightOfDefenceTag = "defence" -- | Used to qualify the XML. weightOfDoubledPawnsTag :: String-weightOfDoubledPawnsTag = "doubledPawns"+weightOfDoubledPawnsTag = "doubledPawns" -- | Used to qualify the XML. weightOfIsolatedPawnsTag :: String-weightOfIsolatedPawnsTag = "isolatedPawns"+weightOfIsolatedPawnsTag = "isolatedPawns" -- | Used to qualify the XML. weightOfPassedPawnsTag :: String-weightOfPassedPawnsTag = "passedPawns"+weightOfPassedPawnsTag = "passedPawns" {- | * The weight of various criteria used to select a /move/ from alternatives, at a specific point in the game.@@ -114,36 +113,35 @@ * CAVEAT: these weights determine the effective value of /isolated/ or /doubled/ @Pawn@s, & this value shouldn't be less than their weighted normalised /rank-value/, otherwise sacrifice would be beneficial. -}-data CriteriaWeights criterionWeight = MkCriteriaWeights {- getWeightOfMaterial :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference between the total /rank-value/ of the /piece/s currently in play on either side; <https://www.chessprogramming.org/Material>.- getWeightOfMobility :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference between the reciprocal of the number of destinations available to the /piece/s of either side. N.B. this weight can be derived from 'getWeightOfMaterial' since losing a @Queen@ is less significant than reducing mobility to zero; <https://www.chessprogramming.org/Mobility>.- getWeightOfPieceSquareValue :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference in the values of the squares occupied by the pieces of either side.- getWeightOfCastlingPotential :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ Whether each player has been permanently prevented from /Castling/.- getWeightOfDefence :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference between the number of /piece/s defending each of one's own, compared with the opponent.- getWeightOfDoubledPawns :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference between the total number of /doubled/ @Pawn@s on either side; <https://www.chessprogramming.org/Doubled_Pawn>.- getWeightOfIsolatedPawns :: Attribute.CriterionWeight.CriterionWeight criterionWeight, -- ^ The arithmetic difference between the total number of /isolated/ @Pawn@s on either side; <https://www.chessprogramming.org/Isolated_Pawn>.- getWeightOfPassedPawns :: Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ The arithmetic difference between the total number of /passed/ @Pawn@s on either side; <https://www.chessprogramming.org/Passed_Pawn>.+data CriteriaWeights = MkCriteriaWeights {+ getWeightOfMaterial :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference between the total /rank-value/ of the /piece/s currently in play on either side; <https://www.chessprogramming.org/Material>.+ getWeightOfMobility :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference between the reciprocal of the number of destinations available to the /piece/s of either side. N.B. this weight can be derived from 'getWeightOfMaterial' since losing a @Queen@ is less significant than reducing mobility to zero; <https://www.chessprogramming.org/Mobility>.+ getWeightOfPieceSquareValue :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference in the values of the squares occupied by the pieces of either side.+ getWeightOfCastlingPotential :: Metric.CriterionWeight.CriterionWeight, -- ^ Whether each player has been permanently prevented from /Castling/.+ getWeightOfDefence :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference between the number of /piece/s defending each of one's own, compared with the opponent.+ getWeightOfDoubledPawns :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference between the total number of /doubled/ @Pawn@s on either side; <https://www.chessprogramming.org/Doubled_Pawn>.+ getWeightOfIsolatedPawns :: Metric.CriterionWeight.CriterionWeight, -- ^ The arithmetic difference between the total number of /isolated/ @Pawn@s on either side; <https://www.chessprogramming.org/Isolated_Pawn>.+ getWeightOfPassedPawns :: Metric.CriterionWeight.CriterionWeight -- ^ The arithmetic difference between the total number of /passed/ @Pawn@s on either side; <https://www.chessprogramming.org/Passed_Pawn>. } deriving (Eq, Show) --- | Smart-constructor.+-- | Smart constructor. mkCriteriaWeights- :: (Eq criterionWeight, Num criterionWeight)- => Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /material/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /mobility/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /pieceSquareValue/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /castlingPotential/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /defence/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /doubledPawns/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /isolatedPawns/.- -> Attribute.CriterionWeight.CriterionWeight criterionWeight -- ^ /passedPawns/.- -> CriteriaWeights criterionWeight+ :: Metric.CriterionWeight.CriterionWeight -- ^ /material/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /mobility/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /pieceSquareValue/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /castlingPotential/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /defence/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /doubledPawns/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /isolatedPawns/.+ -> Metric.CriterionWeight.CriterionWeight -- ^ /passedPawns/.+ -> CriteriaWeights mkCriteriaWeights a b c d e f g h | criteriaWeights == minBound = Control.Exception.throw $ Data.Exception.mkInvalidDatum "BishBosh.Input.CriteriaWeights.mkCriteriaWeights:\tall weights are zero." | otherwise = criteriaWeights where criteriaWeights = MkCriteriaWeights a b c d e f g h -instance Real criterionWeight => Property.ShowFloat.ShowFloat (CriteriaWeights criterionWeight) where+instance Property.ShowFloat.ShowFloat CriteriaWeights where showsFloat fromDouble MkCriteriaWeights { getWeightOfMaterial = weightOfMaterial, getWeightOfMobility = weightOfMobility,@@ -154,7 +152,7 @@ getWeightOfIsolatedPawns = weightOfIsolatedPawns, getWeightOfPassedPawns = weightOfPassedPawns } = Text.ShowList.showsAssociationList' $ map (- Control.Arrow.second $ fromDouble . realToFrac . Attribute.CriterionWeight.deconstruct+ Control.Arrow.second $ fromDouble . realToFrac ) [ ( weightOfMaterialTag, weightOfMaterial@@ -175,7 +173,7 @@ ) ] -instance Num criterionWeight => Data.Default.Default (CriteriaWeights criterionWeight) where+instance Data.Default.Default CriteriaWeights where def = MkCriteriaWeights { getWeightOfMaterial = maxBound, getWeightOfMobility = Data.Default.def,@@ -187,19 +185,14 @@ getWeightOfPassedPawns = Data.Default.def } -instance Control.DeepSeq.NFData criterionWeight => Control.DeepSeq.NFData (CriteriaWeights criterionWeight) where+instance Control.DeepSeq.NFData CriteriaWeights where rnf (MkCriteriaWeights a b c d e f g h) = Control.DeepSeq.rnf [a, b, c, d, e, f, g, h] -instance Num criterionWeight => Bounded (CriteriaWeights criterionWeight) where+instance Bounded CriteriaWeights where maxBound = MkCriteriaWeights maxBound maxBound maxBound maxBound maxBound maxBound maxBound maxBound minBound = MkCriteriaWeights minBound minBound minBound minBound minBound minBound minBound minBound -instance (- HXT.XmlPickler criterionWeight,- Num criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => HXT.XmlPickler (CriteriaWeights criterionWeight) where+instance HXT.XmlPickler CriteriaWeights where xpickle = HXT.xpDefault Data.Default.def . HXT.xpElem tag $ HXT.xpWrap ( \(a, b, c, d, e, f, g, h) -> mkCriteriaWeights a b c d e f g h, -- Construct. \MkCriteriaWeights {@@ -249,36 +242,17 @@ * Also writes individual unweighted /criterion-value/s, to facilitate post-analysis; if the corresponding weight is zero, for efficiency evaluation of the criterion is avoided. -}-calculateWeightedMean :: (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif- Fractional weightedMean,- Real criterionValue,- Real criterionWeight- )- => CriteriaWeights criterionWeight- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /material/: maximum if a player's /move/ equals the maximum total piece value (including /queened/ @Pawn@s), while their opponent has just a @King@.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /mobility/: maximum when the opponent is check-mated.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /pieceSquareValue/: maximum when this player occupies all the strategically important squares & the opponent none.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /castlingPotential/: maximum when this player either has /castled/ or can, but the opponent has been permanently prevented.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /defence/: maximum when this player's /piece/s are fully utilised in defence, but none of the opponent's are.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /doubledPawns/: maximum when this player hasn't any /doubled/ @Pawn@s & the opponent has two files of four @Pawn@s.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /isolatedPawns/: maximum when this player hasn't any /isolated/ @Pawn@s & all the opponent's @Pawn@s are /isolated/.- -> Attribute.CriterionValue.CriterionValue criterionValue -- ^ /passedPawns/: maximum when this player has 8 /passed/ @Pawn@s & the opponent has none.- -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues weightedMean criterionValue -- ^ The individual /criteria/ values, & their /weighted mean/.-{-# SPECIALISE calculateWeightedMean- :: CriteriaWeights T.CriterionWeight- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.CriterionValue.CriterionValue T.CriterionValue- -> Attribute.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues T.WeightedMean T.CriterionValue- #-}+calculateWeightedMean+ :: CriteriaWeights+ -> Metric.CriterionValue.CriterionValue -- ^ /material/: maximum if a player's /move/ equals the maximum total piece value (including /queened/ @Pawn@s), while their opponent has just a @King@.+ -> Metric.CriterionValue.CriterionValue -- ^ /mobility/: maximum when the opponent is check-mated.+ -> Metric.CriterionValue.CriterionValue -- ^ /pieceSquareValue/: maximum when this player occupies all the strategically important squares & the opponent none.+ -> Metric.CriterionValue.CriterionValue -- ^ /castlingPotential/: maximum when this player either has /castled/ or can, but the opponent has been permanently prevented.+ -> Metric.CriterionValue.CriterionValue -- ^ /defence/: maximum when this player's /piece/s are fully utilised in defence, but none of the opponent's are.+ -> Metric.CriterionValue.CriterionValue -- ^ /doubledPawns/: maximum when this player hasn't any /doubled/ @Pawn@s & the opponent has two files of four @Pawn@s.+ -> Metric.CriterionValue.CriterionValue -- ^ /isolatedPawns/: maximum when this player hasn't any /isolated/ @Pawn@s & all the opponent's @Pawn@s are /isolated/.+ -> Metric.CriterionValue.CriterionValue -- ^ /passedPawns/: maximum when this player has 8 /passed/ @Pawn@s & the opponent has none.+ -> Metric.WeightedMeanAndCriterionValues.WeightedMeanAndCriterionValues -- ^ The individual /criteria/ values, & their /weighted mean/. calculateWeightedMean MkCriteriaWeights { getWeightOfMaterial = weightOfMaterial, getWeightOfMobility = weightOfMobility,@@ -288,7 +262,7 @@ getWeightOfDoubledPawns = weightOfDoubledPawns, getWeightOfIsolatedPawns = weightOfIsolatedPawns, getWeightOfPassedPawns = weightOfPassedPawns-} material mobility pieceSquareValue castlingPotential defence doubledPawns isolatedPawns passedPawns = Attribute.CriterionValue.calculateWeightedMean [+} material mobility pieceSquareValue castlingPotential defence doubledPawns isolatedPawns passedPawns = Metric.WeightedMeanAndCriterionValues.calculateWeightedMean [ ( material, weightOfMaterial ), (@@ -309,14 +283,10 @@ ] -- | The type of a function which mutates 'CriteriaWeights'.-type Transformation criterionWeight = CriteriaWeights criterionWeight -> CriteriaWeights criterionWeight+type Transformation = CriteriaWeights -> CriteriaWeights -- | Adjust the mean weight, so that the maximum weight is @1@.-normalise :: (- Fractional criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => Transformation criterionWeight+normalise :: Transformation normalise criteriaWeights@MkCriteriaWeights { getWeightOfMaterial = weightOfMaterial, getWeightOfMobility = weightOfMobility,@@ -338,35 +308,29 @@ getWeightOfIsolatedPawns = normaliseCriterionWeight weightOfIsolatedPawns, getWeightOfPassedPawns = normaliseCriterionWeight weightOfPassedPawns } where- normaliseCriterionWeight = Attribute.CriterionWeight.mkCriterionWeight . (- / Attribute.CriterionWeight.deconstruct (- maximum [- weightOfMaterial,- weightOfMobility,- weightOfPieceSquareValue,- weightOfCastlingPotential,- weightOfDefence,- weightOfDoubledPawns,- weightOfIsolatedPawns,- weightOfPassedPawns- ]- )- ) . Attribute.CriterionWeight.deconstruct+ normaliseCriterionWeight = (+ / maximum [+ weightOfMaterial,+ weightOfMobility,+ weightOfPieceSquareValue,+ weightOfCastlingPotential,+ weightOfDefence,+ weightOfDoubledPawns,+ weightOfIsolatedPawns,+ 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 :: (- Fractional criterionWeight,- Real criterionWeight,- Show criterionWeight,- System.Random.RandomGen randomGen- )+perturbWeights+ :: System.Random.RandomGen randomGen => randomGen- -> criterionWeight -- ^ Change-magnitude.- -> Transformation criterionWeight+ -> Type.Mass.CriterionWeight -- ^ Change-magnitude.+ -> Transformation perturbWeights _ 0 criteriaWeights = criteriaWeights perturbWeights randomGen changeMagnitude MkCriteriaWeights { getWeightOfMaterial = weightOfMaterial,@@ -387,15 +351,15 @@ getWeightOfIsolatedPawns = reduceBy g weightOfIsolatedPawns, getWeightOfPassedPawns = reduceBy h weightOfPassedPawns } where- (a : b : c : d : e : f : g : h : _) = System.Random.randomRs (1 :: Double, succ $ realToFrac changeMagnitude) randomGen- reduceBy randomValue = Attribute.CriterionWeight.mkCriterionWeight . (/ realToFrac randomValue) . Attribute.CriterionWeight.deconstruct -- N.B. this always reduces the weight, leaving 'normalise' to correct this.+ (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 criterionWeight -> Attribute.CriterionWeight.CriterionWeight criterionWeight, -- Accessor.- Attribute.CriterionWeight.CriterionWeight criterionWeight -> Transformation criterionWeight -- Mutator.+ String, -- Tag.+ CriteriaWeights -> Metric.CriterionWeight.CriterionWeight, -- Accessor.+ Metric.CriterionWeight.CriterionWeight -> Transformation -- Mutator. ) -- Triple. ] onymousOperators = [
src-lib/BishBosh/Input/EvaluationOptions.hs view
@@ -38,6 +38,7 @@ EvaluationOptions( -- MkEvaluationOptions, getRankValues,+ getMaximumTotalRankValue, getCriteriaWeights, getIncrementalEvaluation, -- getMaybePieceSquareTablePair,@@ -56,14 +57,15 @@ import BishBosh.Data.Bool() import Control.Arrow((***))-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.CriteriaWeights as Input.CriteriaWeights import qualified BishBosh.Input.PieceSquareTable as Input.PieceSquareTable+import qualified BishBosh.Input.RankValues as Input.RankValues 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.DeepSeq import qualified Control.Exception import qualified Control.Monad.Reader@@ -96,54 +98,53 @@ type PieceSquareTablePair x y pieceSquareValue = (Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue, Input.PieceSquareTable.PieceSquareTable x y pieceSquareValue) -- | Defines the options related to the automatic selection of /move/s.-data EvaluationOptions criterionWeight pieceSquareValue rankValue x y = MkEvaluationOptions {- getRankValues :: Attribute.RankValues.RankValues rankValue, -- ^ The static value associated with each /piece/'s /rank/.- getCriteriaWeights :: Input.CriteriaWeights.CriteriaWeights criterionWeight, -- ^ 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.+data EvaluationOptions pieceSquareValue x y = 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. getMaybePieceSquareByCoordinatesByRank :: Maybe ( Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank x y pieceSquareValue- ) -- ^ The optional value for each rank of /piece/, when occupying each coordinate, at each phase of the game.+ ) -- ^ 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 criterionWeight, Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (EvaluationOptions criterionWeight pieceSquareValue rankValue x y) where+ ) => Control.DeepSeq.NFData (EvaluationOptions pieceSquareValue x y) where rnf MkEvaluationOptions {- getRankValues = rankValues,+-- getRankValues = rankValues,+ getMaximumTotalRankValue = maximumTotalValue, getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, -- getMaybePieceSquareTablePair = maybePieceSquareTablePair, getMaybePieceSquareByCoordinatesByRank = maybePieceSquareByCoordinatesByRank- } = Control.DeepSeq.rnf (rankValues, criteriaWeights, incrementalEvaluation, maybePieceSquareByCoordinatesByRank)+ } = Control.DeepSeq.rnf (maximumTotalValue, criteriaWeights, incrementalEvaluation, maybePieceSquareByCoordinatesByRank) instance ( Enum x, Enum y, Ord x, Ord y,- Real criterionWeight, Real pieceSquareValue,- Real rankValue, Show pieceSquareValue- ) => Property.ShowFloat.ShowFloat (EvaluationOptions criterionWeight pieceSquareValue rankValue x y) where+ ) => Property.ShowFloat.ShowFloat (EvaluationOptions pieceSquareValue x y) where showsFloat fromDouble MkEvaluationOptions { getRankValues = rankValues,+-- getMaximumTotalRankValue = maximumTotalValue, getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, getMaybePieceSquareTablePair = maybePieceSquareTablePair -- getMaybePieceSquareByCoordinatesByRank = maybePieceSquareByCoordinatesByRank } = Text.ShowList.showsAssociationList' $ [ (- Attribute.RankValues.tag, Property.ShowFloat.showsFloat fromDouble rankValues+ Input.RankValues.tag, Property.ShowFloat.showsFloat fromDouble rankValues ), ( incrementalEvaluationTag, shows incrementalEvaluation ), (- Input.CriteriaWeights.tag, Property.ShowFloat.showsFloat fromDouble criteriaWeights+ Input.CriteriaWeights.tag, Property.ShowFloat.showsFloat fromDouble criteriaWeights ) ] ++ Data.Maybe.maybe [] ( \(t, t') -> [@@ -157,42 +158,32 @@ ] ) maybePieceSquareTablePair -instance (- Fractional rankValue,- Num criterionWeight,- Ord rankValue,- Show rankValue- ) => Data.Default.Default (EvaluationOptions criterionWeight pieceSquareValue rankValue x y) where+instance Data.Default.Default (EvaluationOptions pieceSquareValue x y) where def = MkEvaluationOptions {- getRankValues = Data.Default.def,+ getRankValues = rankValues,+ getMaximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues, getCriteriaWeights = Data.Default.def, getIncrementalEvaluation = True, getMaybePieceSquareTablePair = Nothing, getMaybePieceSquareByCoordinatesByRank = Nothing- }+ } where+ rankValues = Data.Default.def instance ( Enum x, Enum y, Fractional pieceSquareValue,- Fractional rankValue,- HXT.XmlPickler criterionWeight,- HXT.XmlPickler rankValue,- Num criterionWeight,- Ord criterionWeight, Ord pieceSquareValue,- Ord rankValue, Ord x, Ord y, Real pieceSquareValue,- Show pieceSquareValue,- Show criterionWeight,- Show rankValue- ) => HXT.XmlPickler (EvaluationOptions criterionWeight pieceSquareValue rankValue x y) where+ Show pieceSquareValue+ ) => HXT.XmlPickler (EvaluationOptions pieceSquareValue x y) where xpickle = HXT.xpDefault def . HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d) -> mkEvaluationOptions a b c d, -- Construct. \MkEvaluationOptions { getRankValues = rankValues,+-- getMaximumTotalRankValue = maximumTotalRankValue, getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, getMaybePieceSquareTablePair = maybePieceSquareTablePair@@ -232,17 +223,15 @@ mkEvaluationOptions :: ( Enum x, Enum y,- Eq criterionWeight, Fractional pieceSquareValue,- Num criterionWeight, Ord x, Ord y )- => Attribute.RankValues.RankValues rankValue -- ^ The static value associated with each /piece/'s /rank/.- -> Input.CriteriaWeights.CriteriaWeights criterionWeight -- ^ The weights applied to the values of the criteria used to select a /move/.+ => Input.RankValues.RankValues -- ^ The static value associated with each /piece/'s /rank/.+ -> Input.CriteriaWeights.CriteriaWeights -- ^ The weights applied to the values of the criteria used to select a /move/. -> IncrementalEvaluation- -> Maybe (PieceSquareTablePair x y pieceSquareValue) -- ^ The value to each type of piece, of each square, during normal play & the end-game.- -> EvaluationOptions criterionWeight pieceSquareValue rankValue x y+ -> 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 mkEvaluationOptions rankValues criteriaWeights incrementalEvaluation maybePieceSquareTablePair | Just (pieceSquareTable, _) <- maybePieceSquareTablePair , let undefinedRanks = Input.PieceSquareTable.findUndefinedRanks pieceSquareTable@@ -253,6 +242,7 @@ = 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." | otherwise = MkEvaluationOptions { getRankValues = rankValues,+ getMaximumTotalRankValue = Input.RankValues.calculateMaximumTotalValue rankValues, -- Infer. getCriteriaWeights = criteriaWeights, getIncrementalEvaluation = incrementalEvaluation, getMaybePieceSquareTablePair = maybePieceSquareTablePair,@@ -260,5 +250,5 @@ } -- | Self-documentation.-type Reader criterionWeight pieceSquareValue rankValue x y = Control.Monad.Reader.Reader (EvaluationOptions criterionWeight pieceSquareValue rankValue x y)+type Reader pieceSquareValue x y = Control.Monad.Reader.Reader (EvaluationOptions pieceSquareValue x y)
src-lib/BishBosh/Input/IOOptions.hs view
@@ -26,7 +26,6 @@ -- * Types -- ** Type-synonyms -- Transformation,- MaximumPGNNames, -- ** Data-types IOOptions( -- MkIOOptions,@@ -63,6 +62,7 @@ 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 Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -95,22 +95,16 @@ automaticTag :: String automaticTag = "automatic" --- | The maximum number names, of matching games from the PGN-database, to display.-type MaximumPGNNames = Int- -- | Defines options related to i/o.-data IOOptions row column = MkIOOptions {+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 MaximumPGNNames, -- ^ The maximum number names, of matching games from the PGN-database, to display; @Nothing@ implies no maximum.- getPGNOptionsList :: [Input.PGNOptions.PGNOptions], -- ^ How to construct PGN-databases.+ 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 row column -- ^ Options which define the user-interface.+ getUIOptions :: Input.UIOptions.UIOptions -- ^ Options which define the user-interface. } deriving Eq -instance (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row- ) => Control.DeepSeq.NFData (IOOptions row column) where+instance Control.DeepSeq.NFData IOOptions where rnf MkIOOptions { getMaybeOutputConfigFilePath = maybeOutputConfigFilePath, getMaybeMaximumPGNNames = maybeMaximumPGNNames,@@ -125,7 +119,7 @@ uiOptions ) -instance (Show column, Show row) => Show (IOOptions row column) where+instance Show IOOptions where showsPrec _ MkIOOptions { getMaybeOutputConfigFilePath = maybeOutputConfigFilePath, getMaybeMaximumPGNNames = maybeMaximumPGNNames,@@ -148,7 +142,7 @@ ) ] -instance (Num column, Num row) => Data.Default.Default (IOOptions row column) where+instance Data.Default.Default IOOptions where def = MkIOOptions { getMaybeOutputConfigFilePath = Nothing, getMaybeMaximumPGNNames = Nothing,@@ -157,14 +151,7 @@ getUIOptions = Data.Default.def } -instance (- HXT.XmlPickler column,- HXT.XmlPickler row,- Integral column,- Integral row,- Show column,- Show row- ) => HXT.XmlPickler (IOOptions row column) where+instance HXT.XmlPickler IOOptions where xpickle = HXT.xpDefault Data.Default.def . HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d, e) -> mkIOOptions a b c d e, -- Construct. \MkIOOptions {@@ -183,7 +170,7 @@ ) $ HXT.xp5Tuple ( HXT.xpOption $ HXT.xpTextAttr outputConfigFilePathTag {-can't be null-} ) (- HXT.xpAttrImplied maximumPGNNamesTag HXT.xpInt+ HXT.xpAttrImplied maximumPGNNamesTag HXT.xpickle ) HXT.xpickle {-PGNOptions-} ( HXT.xpOption $ HXT.xpElem persistenceTag ( HXT.xpTextAttr filePathTag `HXT.xpPair` HXT.xpDefault True (HXT.xpAttr automaticTag HXT.xpickle {-Bool-})@@ -193,11 +180,11 @@ -- | 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 MaximumPGNNames -- ^ The optional maximum number of names, of matching PGN-games, to display; @Nothing@ implies unlimited.+ -> 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.- -> Input.UIOptions.UIOptions row column- -> IOOptions row column+ -> Input.UIOptions.UIOptions+ -> IOOptions mkIOOptions maybeOutputConfigFilePath maybeMaximumPGNNames pgnOptionsList maybePersistence uiOptions | Data.Maybe.maybe False ( not . System.FilePath.isValid {-i.e. non-null on POSIX-}@@ -221,10 +208,10 @@ duplicateFilePaths = Data.Foldable.findDuplicates $ map (System.FilePath.normalise . Input.PGNOptions.getDatabaseFilePath) pgnOptionsList -- | The type of a function used to transform 'IOOptions'.-type Transformation row column = IOOptions row column -> IOOptions row column+type Transformation = IOOptions -> IOOptions -- | Mutator.-setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation row column+setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation setMaybeOutputConfigFilePath maybeOutputConfigFilePath ioOptions | Data.Maybe.maybe False ( not . System.FilePath.isValid {-i.e. non-null on POSIX-}@@ -234,7 +221,7 @@ } -- | Mutator.-setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions row column -> Transformation row column+setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions ioOptions@MkIOOptions { getUIOptions = uiOptions } = ioOptions { getUIOptions = uiOptions { Input.UIOptions.getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions@@ -242,7 +229,7 @@ } -- | Mutator.-setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation row column+setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation setMaybePrintMoveTree maybePrintMoveTree ioOptions@MkIOOptions { getUIOptions = uiOptions } = ioOptions { getUIOptions = uiOptions { Input.UIOptions.getMaybePrintMoveTree = maybePrintMoveTree@@ -250,19 +237,19 @@ } -- | Mutator.-updateCECPFeature :: Input.CECPFeatures.Feature -> Transformation row column+updateCECPFeature :: Input.CECPFeatures.Feature -> Transformation updateCECPFeature feature ioOptions@MkIOOptions { getUIOptions = uiOptions } = ioOptions { getUIOptions = Input.UIOptions.updateCECPFeature feature uiOptions } -- | Mutator.-deleteCECPFeature :: Input.CECPFeatures.Feature -> Transformation row column+deleteCECPFeature :: Input.CECPFeatures.Feature -> Transformation deleteCECPFeature feature ioOptions@MkIOOptions { getUIOptions = uiOptions } = ioOptions { getUIOptions = Input.UIOptions.deleteCECPFeature feature uiOptions } -- | Mutator.-setVerbosity :: Input.Verbosity.Verbosity -> Transformation row column+setVerbosity :: Input.Verbosity.Verbosity -> Transformation setVerbosity verbosity ioOptions@MkIOOptions { getUIOptions = uiOptions } = ioOptions { getUIOptions = uiOptions { Input.UIOptions.getVerbosity = verbosity
src-lib/BishBosh/Input/NativeUIOptions.hs view
@@ -25,7 +25,7 @@ module BishBosh.Input.NativeUIOptions( -- * Types -- ** Type-synonyms- ScreenCoordinates,+-- ScreenCoordinates, -- ** Data-types NativeUIOptions( -- MkNativeUIOptions,@@ -46,6 +46,7 @@ import qualified BishBosh.Attribute.ColourScheme as Attribute.ColourScheme import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Default@@ -67,19 +68,16 @@ nColumnsTag :: String nColumnsTag = "nColumns" --- | The coordinates used to index the screen.-type ScreenCoordinates row column = (row, column)+-- | 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) -- | Constructor.-data NativeUIOptions row column = MkNativeUIOptions {- getBoardMagnification :: ScreenCoordinates row column, -- ^ The factor by which the dimensions of the board are stretched when displayed.+data NativeUIOptions = MkNativeUIOptions {+ getBoardMagnification :: ScreenCoordinates, -- ^ The factor by which the dimensions of the board are stretched when displayed. getColourScheme :: Attribute.ColourScheme.ColourScheme } deriving Eq -instance (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row- ) => Control.DeepSeq.NFData (NativeUIOptions row column) where+instance Control.DeepSeq.NFData NativeUIOptions where rnf MkNativeUIOptions { getBoardMagnification = boardMagnification, getColourScheme = colourScheme@@ -88,34 +86,27 @@ colourScheme ) -instance (Show row, Show column) => Show (NativeUIOptions row column) where- showsPrec _ MkNativeUIOptions {+instance Show NativeUIOptions where+ showsPrec precision MkNativeUIOptions { getBoardMagnification = boardMagnification, getColourScheme = colourScheme } = Text.ShowList.showsAssociationList' [ ( boardMagnificationTag,- shows boardMagnification+ showsPrec precision boardMagnification ), ( Attribute.ColourScheme.tag,- shows colourScheme+ showsPrec precision colourScheme ) ] -instance (Num row, Num column) => Data.Default.Default (NativeUIOptions row column) where+instance Data.Default.Default NativeUIOptions where def = MkNativeUIOptions { getBoardMagnification = (1, 1), getColourScheme = Data.Default.def } -instance (- HXT.XmlPickler column,- HXT.XmlPickler row,- Integral column,- Integral row,- Show column,- Show row- ) => HXT.XmlPickler (NativeUIOptions row column) where+instance HXT.XmlPickler NativeUIOptions where xpickle = HXT.xpElem tag . HXT.xpWrap ( uncurry mkNativeUIOptions, -- Construct. \MkNativeUIOptions {@@ -135,15 +126,10 @@ def = Data.Default.def -- | Smart constructor.-mkNativeUIOptions :: (- Integral column,- Integral row,- Show column,- Show row- )- => ScreenCoordinates row column -- ^ The factor by which the dimensions of the board are stretched when displayed.+mkNativeUIOptions+ :: ScreenCoordinates -- ^ The factor by which the dimensions of the board are stretched when displayed. -> Attribute.ColourScheme.ColourScheme- -> NativeUIOptions row column+ -> NativeUIOptions mkNativeUIOptions boardMagnification colourScheme | uncurry (||) $ ( (< 1) *** (< 1)@@ -155,3 +141,4 @@ getBoardMagnification = boardMagnification, getColourScheme = colourScheme }+
src-lib/BishBosh/Input/Options.hs view
@@ -59,8 +59,6 @@ ) where import BishBosh.Data.Bool() -- For 'HXT.xpickle'.-import BishBosh.Data.Integral() -- For 'HXT.XmlPickler NMoves'.-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Input.IOOptions as Input.IOOptions@@ -70,6 +68,7 @@ import qualified BishBosh.Property.Arboreal as Property.Arboreal import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Default@@ -93,23 +92,19 @@ type RandomSeed = Int -- | Defines the application's options.-data Options column criterionWeight pieceSquareValue rankValue row x y = MkOptions {- getMaybeMaximumPlies :: Maybe Component.Move.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 criterionWeight pieceSquareValue rankValue 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 row column -- ^ The /ioOptions/ by which to receive commands & present results.+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. } deriving (Eq, Show) instance (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData criterionWeight, Control.DeepSeq.NFData pieceSquareValue,- Control.DeepSeq.NFData rankValue,- Control.DeepSeq.NFData row, Control.DeepSeq.NFData x, Control.DeepSeq.NFData y- ) => Control.DeepSeq.NFData (Options column criterionWeight pieceSquareValue rankValue row x y) where+ ) => Control.DeepSeq.NFData (Options pieceSquareValue x y) where rnf MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -123,13 +118,9 @@ Enum y, Ord x, Ord y,- Real criterionWeight, Real pieceSquareValue,- Real rankValue,- Show column,- Show pieceSquareValue,- Show row- ) => Property.ShowFloat.ShowFloat (Options column criterionWeight pieceSquareValue rankValue row x y) where+ Show pieceSquareValue+ ) => Property.ShowFloat.ShowFloat (Options pieceSquareValue x y) where showsFloat fromDouble MkOptions { getMaybeMaximumPlies = maybeMaximumPlies, getMaybeRandomSeed = maybeRandomSeed,@@ -153,14 +144,7 @@ ) ] -instance (- Fractional rankValue,- Num criterionWeight,- Num column,- Num row,- Ord rankValue,- Show rankValue- ) => Data.Default.Default (Options column criterionWeight pieceSquareValue rankValue row x y) where+instance Data.Default.Default (Options pieceSquareValue x y) where def = MkOptions { getMaybeMaximumPlies = Nothing, getMaybeRandomSeed = Nothing,@@ -173,26 +157,12 @@ Enum x, Enum y, Fractional pieceSquareValue,- Fractional rankValue,- HXT.XmlPickler column,- HXT.XmlPickler criterionWeight,- HXT.XmlPickler rankValue,- HXT.XmlPickler row,- Integral column,- Integral row,- Num criterionWeight, Ord pieceSquareValue,- Ord rankValue, Ord x, Ord y,- Real criterionWeight, Real pieceSquareValue,- Show column,- Show criterionWeight,- Show pieceSquareValue,- Show rankValue,- Show row- ) => HXT.XmlPickler (Options column criterionWeight pieceSquareValue rankValue row x y) where+ Show pieceSquareValue+ ) => HXT.XmlPickler (Options pieceSquareValue x y) where xpickle = HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d, e) -> mkOptions a b c d e, -- Construct. \MkOptions {@@ -209,19 +179,19 @@ ioOptions ) -- Deconstruct. ) $ HXT.xp5Tuple (- HXT.xpAttrImplied maximumPliesTag HXT.xpInt {-NMoves-}+ HXT.xpAttrImplied maximumPliesTag HXT.xpickle {-NPlies-} ) ( HXT.xpAttrImplied randomSeedTag HXT.xpInt ) HXT.xpickle {-EvaluationOptions-} HXT.xpickle {-SearchOptions-} HXT.xpickle {-IOOptions-} -- | Smart constructor. mkOptions- :: Maybe Component.Move.NPlies -- ^ The maximum number of plies before the game is terminated; required for profiling the application.+ :: 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 criterionWeight pieceSquareValue rankValue x y+ -> Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y -> Input.SearchOptions.SearchOptions- -> Input.IOOptions.IOOptions row column- -> Options column criterionWeight pieceSquareValue rankValue row x y+ -> Input.IOOptions.IOOptions+ -> Options pieceSquareValue x y 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."@@ -234,22 +204,22 @@ } -- | The type of a function used to transform 'Options'.-type Transformation column criterionWeight pieceSquareValue rankValue row x y = Options column criterionWeight pieceSquareValue rankValue row x y -> Options column criterionWeight pieceSquareValue rankValue row x y+type Transformation pieceSquareValue x y = Options pieceSquareValue x y -> Options pieceSquareValue x y -- | Mutator.-setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setMaybeOutputConfigFilePath :: Maybe System.FilePath.FilePath -> Transformation pieceSquareValue x y setMaybeOutputConfigFilePath maybeOutputConfigFilePath options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybeOutputConfigFilePath maybeOutputConfigFilePath ioOptions } -- | Mutator.-setMaybeRandomSeed :: Maybe RandomSeed -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setMaybeRandomSeed :: Maybe RandomSeed -> Transformation pieceSquareValue x y setMaybeRandomSeed maybeRandomSeed options = options { getMaybeRandomSeed = maybeRandomSeed } -- | Mutator.-setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setMaybePersistence :: Maybe (System.FilePath.FilePath, Bool) -> Transformation pieceSquareValue x y setMaybePersistence maybePersistence options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = ioOptions { Input.IOOptions.getMaybePersistence = maybePersistence@@ -257,25 +227,25 @@ } -- | Mutator.-setVerbosity :: Input.Verbosity.Verbosity -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setVerbosity :: Input.Verbosity.Verbosity -> Transformation pieceSquareValue x y setVerbosity verbosity options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setVerbosity verbosity ioOptions } -- | Mutator.-setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions row column -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setEitherNativeUIOrCECPOptions :: Input.UIOptions.EitherNativeUIOrCECPOptions -> Transformation pieceSquareValue x y setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setEitherNativeUIOrCECPOptions eitherNativeUIOrCECPOptions ioOptions } -- | Mutator.-setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation column criterionWeight pieceSquareValue rankValue row x y+setMaybePrintMoveTree :: Maybe Property.Arboreal.Depth -> Transformation pieceSquareValue x y setMaybePrintMoveTree maybePrintMoveTree options@MkOptions { getIOOptions = ioOptions } = options { getIOOptions = Input.IOOptions.setMaybePrintMoveTree maybePrintMoveTree ioOptions } -- | Mutator.-swapSearchDepth :: Transformation column criterionWeight pieceSquareValue rankValue row x y+swapSearchDepth :: Transformation pieceSquareValue x y swapSearchDepth options@MkOptions { getSearchOptions = searchOptions } = options { getSearchOptions = Input.SearchOptions.swapSearchDepth searchOptions }
src-lib/BishBosh/Input/PGNOptions.hs view
@@ -52,7 +52,6 @@ ) where import BishBosh.Data.Bool()-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN import qualified BishBosh.ContextualNotation.PGNDatabase as ContextualNotation.PGNDatabase import qualified BishBosh.ContextualNotation.StandardAlgebraic as ContextualNotation.StandardAlgebraic@@ -60,6 +59,7 @@ import qualified BishBosh.Data.Foldable as Data.Foldable import qualified BishBosh.Text.Encoding as Text.Encoding import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Char@@ -109,8 +109,8 @@ getValidateMoves :: ContextualNotation.StandardAlgebraic.ValidateMoves, -- ^ Whether moves should be validated, which can become tedious if they're already known to be valid. getTextEncoding :: System.IO.TextEncoding, -- ^ The conversion-scheme between byte-sequences & Unicode characters. getIdentificationTags :: [ContextualNotation.PGN.Tag], -- ^ The tags to extract from this PGN-database to form a unique composite game-identifier.- getMinimumPlies :: Component.Move.NPlies, -- ^ The minimum number of plies required from a recorded game.- getMaybeMaximumGames :: Maybe Int -- ^ The optional maximum number of games to read from the PGN-database.+ getMinimumPlies :: Type.Count.NPlies, -- ^ The minimum number of plies required before a recorded game is considered useful.+ getMaybeMaximumGames :: ContextualNotation.PGNDatabase.MaybeMaximumGames -- ^ The optional maximum number of games to read from the PGN-database. } deriving Eq instance Control.DeepSeq.NFData PGNOptions where@@ -198,7 +198,7 @@ ) HXT.xpickle {-TextEncoding-} ( HXT.xpList . HXT.xpElem identificationTagTag $ HXT.xpTextAttr "tag" ) (- getMinimumPlies def `HXT.xpDefault` HXT.xpAttr minimumPliesTag HXT.xpickle {-NMoves-}+ getMinimumPlies def `HXT.xpDefault` HXT.xpAttr minimumPliesTag HXT.xpickle {-NPlies-} ) ( HXT.xpOption $ HXT.xpAttr maximumGamesTag HXT.xpickle {-NGames-} ) where@@ -212,8 +212,8 @@ -> ContextualNotation.StandardAlgebraic.ValidateMoves -> System.IO.TextEncoding -> [ContextualNotation.PGN.Tag] -- ^ Optional identification tags.- -> Component.Move.NPlies -- ^ The minimum plies.- -> Maybe Int -- ^ The optional maximum number of games to read from the database.+ -> Type.Count.NPlies -- ^ The minimum plies.+ -> ContextualNotation.PGNDatabase.MaybeMaximumGames -- ^ The optional maximum number of games to read from the database. -> PGNOptions mkPGNOptions databaseFilePath maybeDecompressor isStrictlySequential validateMoves textEncoding identificationTags minimumPlies maybeMaximumGames | not $ System.FilePath.isValid databaseFilePath = Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Input.PGNOptions.mkPGNOptions:\tinvalid " . showString databaseFilePathTag . Text.ShowList.showsAssociation $ shows databaseFilePath "."
src-lib/BishBosh/Input/PieceSquareTable.hs view
@@ -75,6 +75,7 @@ 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@@ -183,11 +184,11 @@ showString "by" $ Text.Case.toUpperInitial Attribute.Rank.tag ) $ HXT.xpickle {-rank-} `HXT.xpPair` HXT.xpWrap ( \s -> [- realToFrac (pieceSquareValue :: Double) |+ realToFrac (pieceSquareValue :: Type.Mass.PieceSquareValue) | word <- words s, (pieceSquareValue, "") <- reads word ], -- List-comprehension.- unwords . map (show . (\pieceSquareValue -> realToFrac pieceSquareValue :: Double))+ unwords . map (show . (\pieceSquareValue -> realToFrac pieceSquareValue :: Type.Mass.PieceSquareValue)) ) ( HXT.xpTextAttr . showString "by" $ Text.Case.toUpperInitial Cartesian.Coordinates.tag )
+ src-lib/BishBosh/Input/RankValues.hs view
@@ -0,0 +1,133 @@+{-+ 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@]++ * The relative values of the various /rank/s of chess-piece.++ * <https://en.wikipedia.org/wiki/Chess_piece_relative_value#Hans_Berliner.27s_system%20Chess-piece%20relative%20values>+-}++module BishBosh.Input.RankValues(+-- * Types+-- ** Data-types+ RankValues(+-- MkRankValues,+-- deconstruct+ ),+-- * Constants+ tag,+-- * Functions+ findRankValue,+ calculateMaximumTotalValue,+-- ** Constructor+ fromAssocs+) where++import Control.Arrow((&&&), (***))+import Data.Array.IArray((!))+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Foldable as Data.Foldable+import qualified BishBosh.Metric.RankValue as Metric.RankValue+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.DeepSeq+import qualified Control.Exception+import qualified Data.Array.IArray+import qualified Data.Default+import qualified Data.List+import qualified Text.XML.HXT.Arrow.Pickle as HXT++-- | Used to qualify XML.+tag :: String+tag = "rankValues"++{- |+ * The constant value associated with each /rank/; the higher, the more valuable it is considered to be.++ * N.B.: only relative values are significant; the absolute value associated with any /rank/ is irrelevant; typically ranks are valued in /centipawns/.++ * CAVEAT: a @King@ can never be taken, but assigning the value /infinity/ creates problems, so typically it has the value @0@.+-}+newtype RankValues = MkRankValues {+ deconstruct :: Attribute.Rank.ArrayByRank Metric.RankValue.RankValue+} deriving (Eq, Read, Show)++instance Property.ShowFloat.ShowFloat RankValues where+ showsFloat fromDouble = Text.ShowList.showsAssociationList' . map (show *** Property.ShowFloat.showsFloat fromDouble) . Data.Array.IArray.assocs . deconstruct++instance Data.Default.Default RankValues where+ def = MkRankValues . Attribute.Rank.listArrayByRank $ map (+ fromRational . (/ 10) -- Map into the closed unit-interval.+ ) [+ 1,+ 5,+ 3,+ 3,+ 9,+ 0 -- N.B.: move-selection is independent of the King's value (since it can't be taken), so it can be defined arbitrarily.+ ]++instance Control.DeepSeq.NFData RankValues where+ rnf (MkRankValues byRank) = Control.DeepSeq.rnf byRank++instance HXT.XmlPickler RankValues where+ xpickle = HXT.xpDefault Data.Default.def . HXT.xpWrap (+ fromAssocs, -- Construct from an association-list.+ Data.Array.IArray.assocs . deconstruct -- Deconstruct to an association-list.+ ) . HXT.xpList1 . HXT.xpElem tag $ HXT.xpickle {-Rank-} `HXT.xpPair` HXT.xpickle {-RankValue-}++-- | Smart constructor.+fromAssocs :: [(Attribute.Rank.Rank, Metric.RankValue.RankValue)] -> RankValues+fromAssocs assocs+ | not $ null undefinedRanks = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.Input.RankValues.fromAssocs:\tranks" . Text.ShowList.showsAssociation $ shows undefinedRanks " are undefined."+ | not $ null duplicateRanks = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.Input.RankValues.fromAssocs:\tranks must be distinct; " $ shows duplicateRanks "."+ | all (+ (== 0) . snd {-RankValue-}+ ) assocs = Control.Exception.throw . Data.Exception.mkNullDatum . showString "BishBosh.Input.RankValues.fromAssocs:\tat least one rank should have a non-zero value; " $ shows assocs "."+ | byRank ! Attribute.Rank.Queen /= maximum [+ rankValue |+ (rank, rankValue) <- assocs,+ rank /= Attribute.Rank.King -- Whose rank-value is irrelevant.+ ] {-list-comprehension-} = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.RankValues.fromAssocs:\texcepting possibly the King, the Queen should be the most valuable rank; " $ shows assocs "."+ | otherwise = MkRankValues byRank+ where+ (undefinedRanks, duplicateRanks) = Attribute.Rank.findUndefinedRanks &&& Data.Foldable.findDuplicates $ map fst assocs+ byRank = Attribute.Rank.arrayByRank assocs++-- | Query.+findRankValue :: Attribute.Rank.Rank -> RankValues -> Metric.RankValue.RankValue+findRankValue rank (MkRankValues byRank) = byRank ! rank++{- |+ * The maximum total rank-value one side can have.++ * CAVEAT: assumes that zero pieces have been captured, all @Pawn@s have been queened, & that this is the most valuable /rank/ of /piece/.+-}+calculateMaximumTotalValue :: RankValues -> Type.Mass.RankValue+calculateMaximumTotalValue (MkRankValues byRank) = 9 {-accounting for all possible promotions-} * realToFrac (+ byRank ! Attribute.Rank.Queen+ ) + 2 * Data.List.foldl' (+ \acc -> (+ acc) . realToFrac . (byRank !)+ ) 0 Attribute.Rank.flank+
src-lib/BishBosh/Input/SearchOptions.hs view
@@ -25,7 +25,6 @@ module BishBosh.Input.SearchOptions( -- * Types -- ** Type-synonyms- SearchDepth, SortOnStandardOpeningMoveFrequency, HammingDistance, -- Transformation,@@ -71,6 +70,7 @@ getSearchDepth, maybeRetireTranspositionsAfter, maybeMinimumTranspositionSearchDepth,+ identifyAutomatedPlayers, -- ** Mutators setSearchDepth, swapSearchDepth,@@ -79,17 +79,16 @@ ) where import BishBosh.Data.Bool() -- For 'HXT.xpickle'.-import BishBosh.Data.Integral() -- For 'HXT.XmlPickler NMoves'. import Control.Arrow((***)) import qualified BishBosh.Attribute.CaptureMoveSortAlgorithm as Attribute.CaptureMoveSortAlgorithm import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Component.Move as Component.Move 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.Opposable as Property.Opposable import qualified BishBosh.Text.Case as Text.Case import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Control.Monad.Reader@@ -139,11 +138,8 @@ searchDepthByLogicalColourTag :: String searchDepthByLogicalColourTag = showString searchDepthTag . showString "By" $ Text.Case.toUpperInitial Attribute.LogicalColour.tag --- | The number of plies to search for the optimal move.-type SearchDepth = Component.Move.NPlies- -- | The constant minimum permissible search-depth.-minimumSearchDepth :: SearchDepth+minimumSearchDepth :: Type.Count.NPlies minimumSearchDepth = 1 {- |@@ -151,7 +147,7 @@ * CAVEAT: this is rather arbitrary. -}-defaultSearchDepth :: SearchDepth+defaultSearchDepth :: Type.Count.NPlies defaultSearchDepth = 4 -- | Sort moves on the decreasing frequency of occurrence in standard openings.@@ -161,7 +157,7 @@ type HammingDistance = Int -- | The number of full moves (one for each player) after which to retire killer moves.-type MaybeRetireAfterNMoves = Maybe Component.Move.NMoves+type MaybeRetireAfterNMoves = Maybe Type.Count.NMoves -- | Whether to short-circuit the fitness-evaluation of /position/s which have been visited before in the current /game/. type TrapRepeatedPositions = Bool@@ -170,22 +166,22 @@ type UsePondering = Bool -- | The number of full moves (one for each player) after which to retire transpositions & the search-depth beneath which they aren't recorded at all.-type MaybeUseTranspositions = Maybe (Component.Move.NMoves, SearchDepth)+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 SearchDepth+type SearchDepthByLogicalColour = Data.Map.Strict.Map Attribute.LogicalColour.LogicalColour Type.Count.NPlies -- | Defines options related to searching for a move. data SearchOptions = MkSearchOptions {- getSortOnStandardOpeningMoveFrequency :: SortOnStandardOpeningMoveFrequency,+ getSortOnStandardOpeningMoveFrequency :: SortOnStandardOpeningMoveFrequency, -- ^ Whether to sort moves on the decreasing frequency of occurrence in standard openings. getMaybeCaptureMoveSortAlgorithm :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm,- getMaybeMinimumHammingDistance :: Maybe HammingDistance,- getMaybeRetireKillerMovesAfter :: MaybeRetireAfterNMoves,- getTrapRepeatedPositions :: TrapRepeatedPositions,- getUsePondering :: UsePondering,+ getMaybeMinimumHammingDistance :: Maybe HammingDistance, -- ^ The optional minimum Hamming-distance between the random numbers from which Zobrist-hashes are composed.+ getMaybeRetireKillerMovesAfter :: MaybeRetireAfterNMoves, -- ^ The number of full moves (one for each player) after which to retire killer moves.+ getTrapRepeatedPositions :: TrapRepeatedPositions, -- ^ Whether to short-circuit the fitness-evaluation of /position/s which have been visited before in the current /game/.+ getUsePondering :: UsePondering, -- ^ Whether to ponder about one's next move while the opponent is thinking. getMaybeUseTranspositions :: MaybeUseTranspositions, getStandardOpeningOptions :: Input.StandardOpeningOptions.StandardOpeningOptions,- getSearchDepthByLogicalColour :: SearchDepthByLogicalColour+ getSearchDepthByLogicalColour :: SearchDepthByLogicalColour -- ^ The depth to search for each /logical colour/. } deriving Eq instance Control.DeepSeq.NFData SearchOptions where@@ -297,13 +293,13 @@ ) ( HXT.xpAttrImplied minimumHammingDistanceTag HXT.xpInt ) (- HXT.xpAttrImplied retireKillerMovesAfterTag HXT.xpInt+ HXT.xpAttrImplied retireKillerMovesAfterTag HXT.xpickle {-NMoves-} ) ( getTrapRepeatedPositions def `HXT.xpDefault` HXT.xpAttr trapRepeatedPositionsTag HXT.xpickle {-Bool-} ) ( getUsePondering def `HXT.xpDefault` HXT.xpAttr usePonderingTag HXT.xpickle {-Bool-} ) (- HXT.xpOption . HXT.xpElem "transpositions" $ HXT.xpAttr retireTranspositionsAfterTag HXT.xpInt `HXT.xpPair` HXT.xpAttr minimumTranspositionSearchDepthTag HXT.xpInt+ 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 . (@@ -316,7 +312,7 @@ Data.Map.Strict.toList -- Deconstruct to a List. ) . HXT.xpList {-potentially null-} . HXT.xpElem ( showString "by" $ Text.Case.toUpperInitial Attribute.LogicalColour.tag- ) $ HXT.xpickle {-LogicalColour-} `HXT.xpPair` HXT.xpAttr searchDepthTag HXT.xpInt+ ) $ HXT.xpickle {-LogicalColour-} `HXT.xpPair` HXT.xpAttr searchDepthTag HXT.xpickle {-NPlies-} ) where def = Data.Default.def @@ -365,7 +361,7 @@ } -- | Get either player's search-depth, using a default value when none are defined.-getSearchDepth :: SearchOptions -> SearchDepth+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. -- | Self-documentation.@@ -377,17 +373,17 @@ -- | When to retire transpositions. maybeRetireTranspositionsAfter :: SearchOptions -> MaybeRetireAfterNMoves-maybeRetireTranspositionsAfter MkSearchOptions { getMaybeUseTranspositions = maybeUseTranspositions } = fmap fst maybeUseTranspositions+maybeRetireTranspositionsAfter MkSearchOptions { getMaybeUseTranspositions = maybeUseTranspositions } = fmap fst {-NMoves-} maybeUseTranspositions -- | The search-depth beneath which transpositions aren't recorded.-maybeMinimumTranspositionSearchDepth :: SearchOptions -> Maybe SearchDepth-maybeMinimumTranspositionSearchDepth MkSearchOptions { getMaybeUseTranspositions = maybeUseTranspositions } = fmap snd maybeUseTranspositions+maybeMinimumTranspositionSearchDepth :: SearchOptions -> Maybe Type.Count.NPlies+maybeMinimumTranspositionSearchDepth MkSearchOptions { getMaybeUseTranspositions = maybeUseTranspositions } = fmap snd {-NPlies-} maybeUseTranspositions -- | The type of a function used to transform 'SearchOptions'. type Transformation = SearchOptions -> SearchOptions -- | Mutator.-setSearchDepth :: SearchDepth -> Transformation+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 }@@ -400,5 +396,12 @@ getSearchDepthByLogicalColour = Data.Map.Strict.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+ -- | Self-documentation. type Reader = Control.Monad.Reader.Reader SearchOptions+
src-lib/BishBosh/Input/UIOptions.hs view
@@ -51,8 +51,7 @@ isCECPManualMode ) where -import BishBosh.Data.Integral() -- For 'HXT.XmlPickler NDecimalDigits'.-import Control.Arrow((&&&))+import Control.Arrow((&&&), (|||)) import qualified BishBosh.Data.Either as Data.Either import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.CECPFeatures as Input.CECPFeatures@@ -61,8 +60,8 @@ import qualified BishBosh.Input.Verbosity as Input.Verbosity import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Arboreal as Property.Arboreal-import qualified BishBosh.Property.ShowFloat as Property.ShowFloat import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Default@@ -82,7 +81,7 @@ nDecimalDigitsTag = "nDecimalDigits" -- | The maximum number of decimal digits that can be represented using a double-precision floating-point number.-maxNDecimalDigits :: Property.ShowFloat.NDecimalDigits+maxNDecimalDigits :: Type.Count.NDecimalDigits maxNDecimalDigits = floor $ fromIntegral ( floatDigits ( undefined :: Double -- CAVEAT: the actual type could be merely 'Float', but that's currently unknown.@@ -90,21 +89,18 @@ ) * (logBase 10 2 :: Double) -- | Self-documentation.-type EitherNativeUIOrCECPOptions row column = Either (Input.NativeUIOptions.NativeUIOptions row column) Input.CECPOptions.CECPOptions+type EitherNativeUIOrCECPOptions = Either Input.NativeUIOptions.NativeUIOptions Input.CECPOptions.CECPOptions -- | Defines the application's user-interface.-data UIOptions row column = MkUIOptions {- getMoveNotation :: Notation.MoveNotation.MoveNotation, -- ^ The notation used to describe /move/s.- getMaybePrintMoveTree :: Maybe Property.Arboreal.Depth, -- ^ Print the move-tree to the specified depth.- getNDecimalDigits :: Property.ShowFloat.NDecimalDigits, -- ^ The precision to which fractional auxiliary data is displayed.- getEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions row column, -- ^ When a native display is configured some additional style-parameters are required.- getVerbosity :: Input.Verbosity.Verbosity -- ^ Set the threshold for ancillary information-output.+data UIOptions = MkUIOptions {+ getMoveNotation :: Notation.MoveNotation.MoveNotation, -- ^ The notation used to describe /move/s.+ getMaybePrintMoveTree :: Maybe Property.Arboreal.Depth, -- ^ Print the move-tree to the specified depth.+ getNDecimalDigits :: Type.Count.NDecimalDigits, -- ^ The precision to which fractional auxiliary data is displayed.+ getEitherNativeUIOrCECPOptions :: EitherNativeUIOrCECPOptions, -- ^ When a native display is configured some additional style-parameters are required.+ getVerbosity :: Input.Verbosity.Verbosity -- ^ Set the threshold for ancillary information-output. } deriving Eq -instance (- Control.DeepSeq.NFData column,- Control.DeepSeq.NFData row- ) => Control.DeepSeq.NFData (UIOptions row column) where+instance Control.DeepSeq.NFData UIOptions where rnf MkUIOptions { getMoveNotation = moveNotation, getMaybePrintMoveTree = maybePrintMoveTree,@@ -119,7 +115,7 @@ verbosity ) -instance (Show row, Show column) => Show (UIOptions row column) where+instance Show UIOptions where showsPrec _ MkUIOptions { getMoveNotation = moveNotation, getMaybePrintMoveTree = maybePrintMoveTree,@@ -136,17 +132,14 @@ nDecimalDigitsTag, shows nDecimalDigits ),- either (- (,) Input.NativeUIOptions.tag . shows- ) (- (,) Input.CECPOptions.tag . shows- ) eitherNativeUIOrCECPOptions, (+ (,) Input.NativeUIOptions.tag . shows ||| (,) Input.CECPOptions.tag . shows $ eitherNativeUIOrCECPOptions,+ ( Input.Verbosity.tag, shows verbosity ) ] -instance (Num row, Num column) => Data.Default.Default (UIOptions row column) where+instance Data.Default.Default UIOptions where def = MkUIOptions { getMoveNotation = Data.Default.def, getMaybePrintMoveTree = Nothing,@@ -155,14 +148,7 @@ getVerbosity = Data.Default.def } -instance (- HXT.XmlPickler column,- HXT.XmlPickler row,- Integral column,- Integral row,- Show column,- Show row- ) => HXT.XmlPickler (UIOptions row column) where+instance HXT.XmlPickler UIOptions where xpickle = HXT.xpDefault Data.Default.def . HXT.xpElem tag . HXT.xpWrap ( \(a, b, c, d, e) -> mkUIOptions a b c d e, -- Construct. \MkUIOptions {@@ -193,21 +179,21 @@ mkUIOptions :: Notation.MoveNotation.MoveNotation -- ^ The chess-notation used to describe /move/s. -> Maybe Property.Arboreal.Depth- -> Property.ShowFloat.NDecimalDigits -- ^ The precision to which fractional auxiliary data is displayed.- -> EitherNativeUIOrCECPOptions row column+ -> Type.Count.NDecimalDigits -- ^ The precision to which fractional auxiliary data is displayed.+ -> EitherNativeUIOrCECPOptions -> Input.Verbosity.Verbosity -- ^ Set the threshold for logging.- -> UIOptions row column+ -> UIOptions mkUIOptions moveNotation maybePrintMoveTree nDecimalDigits eitherNativeUIOrCECPOptions verbosity | Just depth <- maybePrintMoveTree- , depth <= 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.UIOptions.mkUIOptions:\t" . showString printMoveTreeTag . Text.ShowList.showsAssociation $ shows depth " must exceed zero."+ , depth <= 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.UIOptions.mkUIOptions:\t" . showString printMoveTreeTag . Text.ShowList.showsAssociation $ shows depth " must exceed zero." | nDecimalDigits < 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.UIOptions.mkUIOptions:\t" . showString nDecimalDigitsTag . Text.ShowList.showsAssociation $ shows nDecimalDigits " must exceed zero." | nDecimalDigits > maxNDecimalDigits = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Input.UIOptions.mkUIOptions:\t" . showString nDecimalDigitsTag . Text.ShowList.showsAssociation . shows nDecimalDigits . showString " shouldn't exceed " $ shows maxNDecimalDigits "." | (- const False `either` const True- ) eitherNativeUIOrCECPOptions && not (+ const False ||| const True $ eitherNativeUIOrCECPOptions+ ) && not ( Notation.MoveNotation.isPureCoordinate moveNotation ) = Control.Exception.throw . Data.Exception.mkIncompatibleData . showString "BishBosh.Input.UIOptions.mkUIOptions:\t" . shows Input.CECPOptions.tag . showString " is incompatible with " . showString Notation.MoveNotation.tag . Text.ShowList.showsAssociation $ shows moveNotation "."- | otherwise = MkUIOptions {+ | otherwise = MkUIOptions { getMoveNotation = moveNotation, getMaybePrintMoveTree = maybePrintMoveTree, getNDecimalDigits = nDecimalDigits,@@ -216,24 +202,22 @@ } -- | Whether the chess-engine has been temporarily turned-off in order to set-up pieces.-isCECPManualMode :: UIOptions row column -> Bool-isCECPManualMode MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = (- const False `either` (- uncurry (||) . (Input.CECPOptions.getEditMode &&& Input.CECPOptions.getForceMode)- )- ) eitherNativeUIOrCECPOptions+isCECPManualMode :: UIOptions -> Bool+isCECPManualMode MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = const False ||| (+ uncurry (||) . (Input.CECPOptions.getEditMode &&& Input.CECPOptions.getForceMode)+ ) $ eitherNativeUIOrCECPOptions -- | The type of a function used to transform 'UIOptions'.-type Transformation row column = UIOptions row column -> UIOptions row column+type Transformation = UIOptions -> UIOptions -- | Mutator.-updateCECPFeature :: Input.CECPFeatures.Feature -> Transformation row column+updateCECPFeature :: Input.CECPFeatures.Feature -> Transformation updateCECPFeature feature uiOptions@MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = uiOptions { getEitherNativeUIOrCECPOptions = Input.CECPOptions.updateFeature feature `fmap` eitherNativeUIOrCECPOptions } -- | Mutator.-deleteCECPFeature :: Input.CECPFeatures.Feature -> Transformation row column+deleteCECPFeature :: Input.CECPFeatures.Feature -> Transformation deleteCECPFeature feature uiOptions@MkUIOptions { getEitherNativeUIOrCECPOptions = eitherNativeUIOrCECPOptions } = uiOptions { getEitherNativeUIOrCECPOptions = Input.CECPOptions.deleteFeature feature `fmap` eitherNativeUIOrCECPOptions }
+ src-lib/BishBosh/Metric/CriterionValue.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE CPP #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines the value of a single /criterion/, which quantifies the significance of some concept;+ many such criteria may exist, & their weighted-mean drives automated selection of /move/s.++ * Each /criterion-value/ is normalised into the /signed closed unit-interval/.+-}++module BishBosh.Metric.CriterionValue(+-- * Types+-- ** Data-types+ CriterionValue(),+-- ** Constructor+-- mkCriterionValue+) where++import qualified BishBosh.Type.Mass as Type.Mass++#ifdef USE_NEWTYPE_WRAPPERS+import qualified BishBosh.Data.Exception as Data.Exception+import qualified Control.Exception++{- |+ * Quantifies some criterion; the larger the signed value, the better.++ * N.B.: the type-constructor is a peg on which to hang class-instances & its data-constructor guards the permissible bounds.+-}+newtype CriterionValue = MkCriterionValue Type.Mass.CriterionValue deriving (Eq, Ord)++instance Show CriterionValue where+ showsPrec precedence (MkCriterionValue criterionValue) = showsPrec precedence criterionValue++instance Num CriterionValue where+ MkCriterionValue l + MkCriterionValue r = mkCriterionValue $ l + r+ MkCriterionValue l * MkCriterionValue r = MkCriterionValue $ l * r+ abs (MkCriterionValue criterionValue) = MkCriterionValue $ abs criterionValue+ signum (MkCriterionValue criterionValue) = MkCriterionValue $ signum criterionValue+ fromInteger = mkCriterionValue . fromInteger+ negate (MkCriterionValue criterionValue) = MkCriterionValue $ negate criterionValue++instance Fractional CriterionValue where+ MkCriterionValue l / MkCriterionValue r = mkCriterionValue $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ fromRational = mkCriterionValue . fromRational++instance Real CriterionValue where+ toRational (MkCriterionValue criterionValue) = toRational criterionValue++-- | Smart constructor.+mkCriterionValue :: Type.Mass.CriterionValue -> CriterionValue+mkCriterionValue criterionValue+ | abs criterionValue > 1 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Metric.CriterionValue.mkCriterionValue:\t" $ shows criterionValue " must be within the closed interval '[-1,1]'."+ | otherwise = MkCriterionValue criterionValue+#else+-- | Quantifies some criterion; the larger the signed value, the better.+type CriterionValue = Type.Mass.CriterionValue+#endif+
+ src-lib/BishBosh/Metric/CriterionWeight.hs view
@@ -0,0 +1,96 @@+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines the weight associated with some 'Metric.CriterionValue.CriterionValue'.++ * Each weighting is constrained to the unsigned /closed unit-interval/; negative values aren't permitted.++ * If the /criterion-value/ is considered unimportant, then its weight can be set to @0@, whilst concepts of great significance can be set to @1@.+-}++module BishBosh.Metric.CriterionWeight(+-- * Types+-- ** Data-types+ CriterionWeight(+-- MkCriterionWeight,+-- deconstruct+ )+-- * Functions+-- ** Constructor+-- mkCriterionWeight+) where++import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Num as Data.Num+import qualified BishBosh.Type.Mass as Type.Mass+import qualified Control.DeepSeq+import qualified Control.Exception+import qualified Data.Default+import qualified Text.XML.HXT.Arrow.Pickle as HXT++{- |+ * Quantifies the relative significance of a /criterion-value/; the larger the weight, the more significant the criterion is relative to other criteria.++ * N.B.: the type-constructor is a peg on which to hang class-instances & its data-constructor guards the permissible bounds.+-}+newtype CriterionWeight = MkCriterionWeight {+ deconstruct :: Type.Mass.CriterionWeight+} deriving (Eq, Ord)++instance Show CriterionWeight where+ showsPrec precedence (MkCriterionWeight criterionWeight) = showsPrec precedence criterionWeight++instance Num CriterionWeight where+ MkCriterionWeight l + MkCriterionWeight r = mkCriterionWeight $ l + r+ MkCriterionWeight l * MkCriterionWeight r = MkCriterionWeight $ l * r+ abs (MkCriterionWeight criterionWeight) = MkCriterionWeight $ abs criterionWeight -- N.B.: if the operand is valid, then this is equivalent to 'id'.+ signum (MkCriterionWeight criterionWeight) = MkCriterionWeight $ signum criterionWeight+ fromInteger = mkCriterionWeight . fromInteger+ negate (MkCriterionWeight criterionWeight) = mkCriterionWeight $ negate criterionWeight -- CAVEAT: only valid for '0'.++instance Fractional CriterionWeight where+ MkCriterionWeight l / MkCriterionWeight r = mkCriterionWeight $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ fromRational = mkCriterionWeight . fromRational++instance Real CriterionWeight where+ toRational (MkCriterionWeight criterionWeight) = toRational criterionWeight++instance Bounded CriterionWeight where+ minBound = MkCriterionWeight 0+ maxBound = MkCriterionWeight 1++instance Data.Default.Default CriterionWeight where+ def = minBound++instance Control.DeepSeq.NFData CriterionWeight where+ rnf (MkCriterionWeight criterionWeight) = Control.DeepSeq.rnf criterionWeight++instance HXT.XmlPickler CriterionWeight where+ xpickle = HXT.xpWrap (mkCriterionWeight, deconstruct) HXT.xpickle++-- | Smart constructor.+mkCriterionWeight :: Type.Mass.CriterionWeight -> CriterionWeight+mkCriterionWeight criterionWeight+ | Data.Num.inClosedUnitInterval criterionWeight = MkCriterionWeight criterionWeight+ | otherwise = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Metric.CriterionWeight.mkCriterionWeight:\t" $ shows criterionWeight " must be within the closed unit-interval '[0,1]'."+
+ src-lib/BishBosh/Metric/RankValue.hs view
@@ -0,0 +1,97 @@+{-+ 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 relative value of a /rank/ of chess-piece.++ * <https://en.wikipedia.org/wiki/Chess_piece_relative_value#Hans_Berliner.27s_system%20Chess-piece%20relative%20values>+-}++module BishBosh.Metric.RankValue(+-- * Types+-- ** Data-types+ RankValue(+-- MkRankValue,+-- deconstruct+ ),+-- * Constants+-- tag,+-- * Functions+-- ** Constructor+-- mkRankValue+) where++import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Data.Num as Data.Num+import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Type.Mass as Type.Mass+import qualified Control.Arrow+import qualified Control.DeepSeq+import qualified Control.Exception+import qualified Data.List.Extra+import qualified Text.XML.HXT.Arrow.Pickle as HXT++-- | Used to qualify XML.+tag :: String+tag = "rankValue"++-- | The constant value associated with a /rank/; the higher, the more valuable it is considered to be.+newtype RankValue = MkRankValue {+ deconstruct :: Type.Mass.RankValue+} deriving (Eq, Ord)++instance Show RankValue where+ showsPrec precision MkRankValue { deconstruct = rankValue } = showsPrec precision rankValue++instance Read RankValue where+ readsPrec precision = map (Control.Arrow.first mkRankValue) . readsPrec precision . Data.List.Extra.trimStart++instance Property.ShowFloat.ShowFloat RankValue where+ showsFloat fromDouble MkRankValue { deconstruct = rankValue } = fromDouble $ realToFrac rankValue++instance Num RankValue where+ MkRankValue { deconstruct = l } + MkRankValue { deconstruct = r } = mkRankValue $ l + r+ MkRankValue { deconstruct = l } * MkRankValue { deconstruct = r } = MkRankValue $ l * r+ abs MkRankValue { deconstruct = rankValue } = MkRankValue $ abs rankValue -- N.B.: if the operand is valid, then this is equivalent to 'id'.+ signum MkRankValue { deconstruct = rankValue } = MkRankValue $ signum rankValue+ fromInteger = mkRankValue . fromInteger+ negate MkRankValue { deconstruct = rankValue } = mkRankValue $ negate rankValue -- CAVEAT: only valid for '0'.++instance Fractional RankValue where+ MkRankValue { deconstruct = l } / MkRankValue { deconstruct = r } = mkRankValue $ l / r -- CAVEAT: it's hard to concoct a scenario in which neither the numerator, denominator nor result are invalid.+ fromRational = mkRankValue . fromRational++instance Real RankValue where+ toRational MkRankValue { deconstruct = rankValue } = toRational rankValue++instance Control.DeepSeq.NFData RankValue where+ rnf MkRankValue { deconstruct = rankValue } = Control.DeepSeq.rnf rankValue++instance HXT.XmlPickler RankValue where+ xpickle = HXT.xpWrap (mkRankValue, deconstruct) $ HXT.xpAttr tag HXT.xpickle++-- | Smart constructor.+mkRankValue :: Type.Mass.RankValue -> RankValue+mkRankValue rankValue+ | Data.Num.inClosedUnitInterval rankValue = MkRankValue rankValue+ | otherwise = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Metric.RankValue.mkRankValue:\t" $ shows rankValue " must be within the closed unit-interval [0,1]."+
+ src-lib/BishBosh/Metric/WeightedMeanAndCriterionValues.hs view
@@ -0,0 +1,121 @@+{-# LANGUAGE CPP #-}+{-+ 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@] The unweighted values of each criterion used to assess the fitness of a position, & the resulting weighted mean.+-}++module BishBosh.Metric.WeightedMeanAndCriterionValues(+-- * Types+-- ** Data-types+ WeightedMeanAndCriterionValues(+-- MkWeightedMeanAndCriterionValues,+ getWeightedMean,+ getCriterionValues+ ),+-- * Constants+ criterionValuesTag,+ weightedMeanTag,+-- * Functions+ negateWeightedMean,+ calculateWeightedMean,+-- ** Constructor+ mkWeightedMeanAndCriterionValues+) where++import Control.Arrow((&&&))+import qualified BishBosh.Metric.CriterionValue as Metric.CriterionValue+import qualified BishBosh.Metric.CriterionWeight as Metric.CriterionWeight+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.DeepSeq+import qualified Factory.Math.Statistics++#ifdef USE_PARALLEL+import qualified Control.Parallel.Strategies+#endif++-- | Qualifies output.+criterionValuesTag :: String+criterionValuesTag = "criterion-values"++-- | Qualifies output.+weightedMeanTag :: String+weightedMeanTag = "weighted-mean"++-- | A /weighted mean/ & the individual unweighted criterion-values from which it was composed.+data WeightedMeanAndCriterionValues = MkWeightedMeanAndCriterionValues {+ getWeightedMean :: Type.Mass.WeightedMean, -- ^ The weighted mean of a list of criterion-values.+ getCriterionValues :: [Metric.CriterionValue.CriterionValue] -- ^ The unweighted /CriterionValue/s from which the weighted mean was composed.+} deriving (Eq, Show)++instance Control.DeepSeq.NFData WeightedMeanAndCriterionValues where+ rnf MkWeightedMeanAndCriterionValues { getWeightedMean = weightedMean } = Control.DeepSeq.rnf weightedMean -- The other field is a prerequisite.++instance Property.ShowFloat.ShowFloat WeightedMeanAndCriterionValues where+ showsFloat fromDouble MkWeightedMeanAndCriterionValues {+ getWeightedMean = weightedMean,+ getCriterionValues = criterionValues+ } = Text.ShowList.showsAssociationList' [+ (weightedMeanTag, fromDouble $ realToFrac weightedMean),+ (criterionValuesTag, Text.ShowList.showsFormattedList' (fromDouble . realToFrac) criterionValues)+ ]++-- | Constructor.+mkWeightedMeanAndCriterionValues+ :: Type.Mass.WeightedMean+ -> [Metric.CriterionValue.CriterionValue]+ -> WeightedMeanAndCriterionValues+mkWeightedMeanAndCriterionValues = MkWeightedMeanAndCriterionValues++{- |+ * Negate the /weightedMean/, but leave the criterion-values unaltered.++ * This can be used to assess the fitness of a position from the perspective of one's opponent.+-}+negateWeightedMean :: WeightedMeanAndCriterionValues -> WeightedMeanAndCriterionValues+negateWeightedMean weightedMeanAndCriterionValues@MkWeightedMeanAndCriterionValues { getWeightedMean = weightedMean } = weightedMeanAndCriterionValues { getWeightedMean = negate weightedMean }++{- |+ * Calculates the /weighted mean/ of the specified /criterion-value/s using the corresponding /criterion-weight/s.++ * Also writes individual unweighted /criterionValue/s, to facilitate post-analysis;+ if the corresponding weight is @0@, evaluation of the criterion is avoided, for efficiency.++ * CAVEAT: if all weights are @0@, then the result is indeterminate.+-}+calculateWeightedMean :: [(Metric.CriterionValue.CriterionValue, Metric.CriterionWeight.CriterionWeight)] -> WeightedMeanAndCriterionValues+{-# INLINABLE calculateWeightedMean #-}+calculateWeightedMean = uncurry mkWeightedMeanAndCriterionValues . (+ Factory.Math.Statistics.getWeightedMean &&& map (realToFrac . fst)+ )+#ifdef USE_PARALLEL+ . Control.Parallel.Strategies.withStrategy (+ Control.Parallel.Strategies.parList $ Control.Parallel.Strategies.evalTuple2 Control.Parallel.Strategies.rdeepseq Control.Parallel.Strategies.r0+ )+#endif+ . map (+ \(criterionValue, criterionWeight) -> (realToFrac criterionValue, realToFrac criterionWeight) :: (Type.Mass.CriterionValue, Type.Mass.CriterionWeight)+ ) . filter (+ (/= 0) . snd {-criterion-weight-} -- Avoid unnecessaily evaluating criterion-values.+ )+
− src-lib/BishBosh/Model/DrawReason.hs
@@ -1,100 +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@]-- * Itemises the ways in which a game may be declared a draw.-- * Each reason corresponds to a rule in chess.--}--module BishBosh.Model.DrawReason(--- * Types--- ** Data-types- DrawReason(),--- * Constants- maximumConsecutiveRepeatablePlies,- maximumConsecutiveRepeatablePositions,- byAgreement,--- fiftyMoveRule,- seventyFiveMoveRule,- insufficientMaterial,- staleMate,--- threeFoldRepetition,- fiveFoldRepetition-) where--import qualified BishBosh.Component.Move as Component.Move-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified Control.DeepSeq---- | The sum-type of ways in which a game can be drawn.-data DrawReason- = ByAgreement -- ^ Both players have agreed to a draw.- | FiftyMoveRule -- ^ A draw can be claimed if fifty consecutive full /move/s have occured without any capture or any @Pawn@ being moved.- | SeventyFiveMoveRule -- ^ Seventy-five consecutive full /move/s have occured without either capture or @Pawn@-movement; <https://www.chessprogramming.org/Repetitions#Fide_Rule>.- | InsufficientMaterial -- ^ Neither player as the fire-power to force /check-mate/.- | StaleMate -- ^ The next player hasn't any legal moves, but isn't /in check/.- | ThreeFoldRepetition -- ^ A draw can be claimed if the same /position/ has been reached on any three occasions.- | FiveFoldRepetition -- ^ The same /position/ has been reached on five successive occasions.- deriving (Eq, Ord, Read, Show)--instance Control.DeepSeq.NFData DrawReason where- rnf _ = ()--instance Property.FixedMembership.FixedMembership DrawReason where- members = [ByAgreement, FiftyMoveRule, SeventyFiveMoveRule, InsufficientMaterial, StaleMate, ThreeFoldRepetition, FiveFoldRepetition]---- | Constant.-byAgreement :: DrawReason-byAgreement = ByAgreement---- | Constant.-fiftyMoveRule :: DrawReason-fiftyMoveRule = FiftyMoveRule---- | Constant.-seventyFiveMoveRule :: DrawReason-seventyFiveMoveRule = SeventyFiveMoveRule---- | Constant.-insufficientMaterial :: DrawReason-insufficientMaterial = InsufficientMaterial---- | Constant.-staleMate :: DrawReason-staleMate = StaleMate---- | Constant.-threeFoldRepetition :: DrawReason-threeFoldRepetition = ThreeFoldRepetition---- | Constant.-fiveFoldRepetition :: DrawReason-fiveFoldRepetition = FiveFoldRepetition---- | The number of consecutive plies required to trigger a draw by the seventy-five move rule.-maximumConsecutiveRepeatablePlies :: Component.Move.NPlies-maximumConsecutiveRepeatablePlies = Component.Move.nPliesPerMove * 75---- | The number of consecutive repeatable positions required for a draw by the five-fold repetition rule.-maximumConsecutiveRepeatablePositions :: Component.Move.NMoves-maximumConsecutiveRepeatablePositions = 5
src-lib/BishBosh/Model/Game.hs view
@@ -32,7 +32,6 @@ module BishBosh.Model.Game( -- * Types -- ** Type-synonyms- NGames, -- InstancesByPosition, -- AvailableQualifiedMoves, -- AvailableQualifiedMovesByLogicalColour,@@ -51,7 +50,7 @@ ), -- * Functions -- inferMaybeTerminationReason,- countMovesAvailableTo,+ countPliesAvailableTo, rollBack, -- listMaybePromotionRanks, -- listQualifiedMovesAvailableTo,@@ -89,7 +88,7 @@ (/~) ) where -import Control.Arrow((&&&), (***))+import Control.Arrow((&&&), (***), (|||)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType import qualified BishBosh.Attribute.Rank as Attribute.Rank@@ -104,9 +103,6 @@ import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception-import qualified BishBosh.Model.DrawReason as Model.DrawReason-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason-import qualified BishBosh.Model.Result as Model.Result import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Notation.PureCoordinate as Notation.PureCoordinate import qualified BishBosh.Property.Empty as Property.Empty@@ -117,6 +113,9 @@ 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.Rule.DrawReason as Rule.DrawReason+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.State.CastleableRooksByLogicalColour as State.CastleableRooksByLogicalColour import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour@@ -129,7 +128,9 @@ 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.Types as T+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@@ -147,9 +148,6 @@ infix 4 =~, /~ -- Same as (==) & (/=). --- | A number of games.-type NGames = Int- {- | * Focus the polymorphic key-type used by 'State.InstancesByPosition.InstancesByPosition'. @@ -193,7 +191,7 @@ 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 Model.GameTerminationReason.GameTerminationReason -- ^ The reason (where appropriate) why the game was terminated.+ getMaybeTerminationReason :: Maybe Rule.GameTerminationReason.GameTerminationReason -- ^ The reason (where appropriate) why the game was terminated. } instance (@@ -272,11 +270,11 @@ Show x, Show y ) => Show (Game x y) where- showsPrec _ MkGame {+ showsPrec precedence MkGame { getBoard = board, getTurnsByLogicalColour = turnsByLogicalColour, getMaybeTerminationReason = maybeTerminationReason- } = shows (+ } = showsPrec precedence ( board, turnsByLogicalColour, maybeTerminationReason@@ -292,8 +290,8 @@ Show x, Show y ) => Read (Game x y) where- {-# SPECIALISE instance Read (Game T.X T.Y) #-}- readsPrec _ = map (+ {-# SPECIALISE instance Read (Game Type.Length.X Type.Length.Y) #-}+ readsPrec precedence = map ( Control.Arrow.first $ \( board, turnsByLogicalColour,@@ -308,7 +306,7 @@ getMaybeTerminationReason = maybeTerminationReason } in game- ) . reads+ ) . readsPrec precedence instance ( Enum x,@@ -318,7 +316,7 @@ Show x, Show y ) => Data.Default.Default (Game x y) where- {-# SPECIALISE instance Data.Default.Default (Game T.X T.Y) #-}+ {-# SPECIALISE instance Data.Default.Default (Game Type.Length.X Type.Length.Y) #-} def = ( mkGame Attribute.LogicalColour.White Data.Default.def {-castleableRooksByLogicalColour-} Data.Default.def {-board-} Data.Default.def {-turnsByLogicalColour-} ) {@@ -336,7 +334,7 @@ Show x, Show y ) => Property.ExtendedPositionDescription.ReadsEPD (Game x y) where- {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Game T.X T.Y) #-}+ {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Game Type.Length.X Type.Length.Y) #-} readsEPD s = [ ( mkGame nextLogicalColour castleableRooksByLogicalColour board turnsByLogicalColour,@@ -350,7 +348,7 @@ s3' -> Control.Arrow.first ( \enPassantDestination -> let opponentsLogicalColour = Property.Opposable.getOpposite nextLogicalColour- in State.TurnsByLogicalColour.fromAssocs [+ in State.TurnsByLogicalColour.fromAssocs [ ( nextLogicalColour, []@@ -400,7 +398,7 @@ Show x, Show y ) => Property.ForsythEdwards.ReadsFEN (Game x y) where- {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Game T.X T.Y) #-}+ {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Game Type.Length.X Type.Length.Y) #-} readsFEN s = [ (game, s3) | (game, s1) <- Property.ExtendedPositionDescription.readsEPD s,@@ -431,7 +429,7 @@ Show x, Show y ) => Property.Empty.Empty (Game x y) where- {-# SPECIALISE instance Property.Empty.Empty (Game T.X T.Y) #-}+ {-# SPECIALISE instance Property.Empty.Empty (Game Type.Length.X Type.Length.Y) #-} 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@@ -451,7 +449,7 @@ Show x, Show y ) => Property.Reflectable.ReflectableOnX (Game x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Game T.X T.Y) #-}+ {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Game Type.Length.X Type.Length.Y) #-} reflectOnX MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -475,7 +473,7 @@ } 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 T.X T.Y #-}+ {-# SPECIALISE instance Component.Zobrist.Hashable2D Game Type.Length.X Type.Length.Y #-} listRandoms2D game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -506,7 +504,7 @@ -> State.Board.Board x y -> State.CastleableRooksByLogicalColour.TurnsByLogicalColour x y -> Game x y-{-# SPECIALISE mkGame :: Attribute.LogicalColour.LogicalColour -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour T.X -> State.Board.Board T.X T.Y -> State.CastleableRooksByLogicalColour.TurnsByLogicalColour T.X T.Y -> Game T.X T.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 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 (@@ -546,7 +544,7 @@ Show x, Show y ) => State.Board.Board x y -> Game x y-{-# SPECIALISE fromBoard :: State.Board.Board T.X T.Y -> Game T.X T.Y #-}+{-# SPECIALISE fromBoard :: State.Board.Board Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y #-} fromBoard board = mkGame Attribute.LogicalColour.White ( State.CastleableRooksByLogicalColour.fromBoard board ) board Property.Empty.empty {-TurnsByLogicalColour-}@@ -586,7 +584,7 @@ Ord x, Ord y ) => Attribute.LogicalColour.LogicalColour -> Game x y -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findAvailableCastlingMoves :: Attribute.LogicalColour.LogicalColour -> Game T.X T.Y -> [Component.QualifiedMove.QualifiedMove T.X T.Y] #-}+{-# SPECIALISE findAvailableCastlingMoves :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-} findAvailableCastlingMoves logicalColour MkGame { getCastleableRooksByLogicalColour = castleableRooksByLogicalColour, getBoard = board,@@ -641,7 +639,7 @@ Show x, Show y ) => Component.Turn.Turn x y -> Transformation x y-{-# SPECIALISE takeTurn :: Component.Turn.Turn T.X T.Y -> Transformation T.X T.Y #-}+{-# SPECIALISE takeTurn :: Component.Turn.Turn Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-} takeTurn turn game@MkGame { getNextLogicalColour = nextLogicalColour, getCastleableRooksByLogicalColour = castleableRooksByLogicalColour,@@ -833,7 +831,7 @@ Show x, Show y ) => Component.QualifiedMove.QualifiedMove x y -> Transformation x y-{-# SPECIALISE applyQualifiedMove :: Component.QualifiedMove.QualifiedMove T.X T.Y -> Transformation T.X T.Y #-}+{-# SPECIALISE applyQualifiedMove :: Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-} 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@@ -850,11 +848,11 @@ Show x, Show y ) => Component.EitherQualifiedMove.EitherQualifiedMove x y -> Transformation x y-{-# SPECIALISE applyEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove T.X T.Y -> Transformation T.X T.Y #-}+{-# SPECIALISE applyEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-} applyEitherQualifiedMove eitherQualifiedMove game@MkGame { getBoard = board } = applyQualifiedMove (- Component.QualifiedMove.mkQualifiedMove move $ either (- ($ State.Board.getMaybePieceByCoordinates board) . State.MaybePieceByCoordinates.inferMoveType move- ) id $ Component.EitherQualifiedMove.getPromotionRankOrMoveType eitherQualifiedMove+ Component.QualifiedMove.mkQualifiedMove move . (+ ($ State.Board.getMaybePieceByCoordinates board) . State.MaybePieceByCoordinates.inferMoveType move ||| id+ ) $ Component.EitherQualifiedMove.getPromotionRankOrMoveType eitherQualifiedMove ) game where move = Component.EitherQualifiedMove.getMove eitherQualifiedMove @@ -871,20 +869,18 @@ -> Game x y -- ^ 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 T.X T.Y)) -> Game T.X T.Y -> [a] -> Either (a, String) (Game T.X T.Y) #-}+{-# 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' ( \eitherGame datum -> eitherGame >>= (- \game -> either (- Left . (,) datum -- Constructor failed.- ) (+ \game -> Left . (,) datum {-Constructor failed-} ||| ( \eitherQualifiedMove -> Data.Maybe.maybe ( Right $ applyEitherQualifiedMove eitherQualifiedMove game- ) (+ ) ( \errorMessage -> Left ( datum, showString "board" . Text.ShowList.showsAssociation . shows (getBoard game) . showString " (" $ shows errorMessage ")" ) -- Pair.- ) $ validateEitherQualifiedMove eitherQualifiedMove game+ ) $ validateEitherQualifiedMove eitherQualifiedMove game ) $ moveConstructor datum ) ) . Right@@ -905,7 +901,7 @@ => Component.QualifiedMove.QualifiedMove x y -> Game x y -- ^ Prior to playing the /qualified move/. -> Maybe String -- ^ Error-message.-{-# SPECIALISE validateQualifiedMove :: Component.QualifiedMove.QualifiedMove T.X T.Y -> Game T.X T.Y -> Maybe String #-}+{-# 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,@@ -1115,7 +1111,7 @@ => Component.EitherQualifiedMove.EitherQualifiedMove x y -> Game x y -- ^ Prior to playing the /move/. -> Maybe String -- ^ Error-message.-{-# SPECIALISE validateEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove T.X T.Y -> Game T.X T.Y -> Maybe String #-}+{-# 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,7 +1126,7 @@ inferredMoveType :: Attribute.MoveType.MoveType inferredMoveType = State.MaybePieceByCoordinates.inferMoveType move (- either id Attribute.Rank.getMaybePromotionRank promotionRankOrMoveType -- Discard any move-type.+ id ||| Attribute.Rank.getMaybePromotionRank $ promotionRankOrMoveType -- Discard any move-type. ) maybePieceByCoordinates -- | Whether the specified /QualifiedMove/ is valid.@@ -1142,7 +1138,7 @@ Show x, Show y ) => Component.QualifiedMove.QualifiedMove x y -> Game x y -> Bool-{-# SPECIALISE isValidQualifiedMove :: Component.QualifiedMove.QualifiedMove T.X T.Y -> Game T.X T.Y -> Bool #-}+{-# SPECIALISE isValidQualifiedMove :: Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-} isValidQualifiedMove qualifiedMove = Data.Maybe.isNothing . validateQualifiedMove qualifiedMove -- | Whether the specified /EitherQualifiedMove/ is valid.@@ -1154,7 +1150,7 @@ Show x, Show y ) => Component.EitherQualifiedMove.EitherQualifiedMove x y -> Game x y -> Bool-{-# SPECIALISE isValidEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove T.X T.Y -> Game T.X T.Y -> Bool #-}+{-# SPECIALISE isValidEitherQualifiedMove :: Component.EitherQualifiedMove.EitherQualifiedMove Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-} isValidEitherQualifiedMove eitherQualifiedMove = Data.Maybe.isNothing . validateEitherQualifiedMove eitherQualifiedMove {- |@@ -1170,7 +1166,7 @@ Show x, Show y ) => Game x y -> [(Game x y, Component.Turn.Turn x y)]-{-# SPECIALISE rollBack :: Game T.X T.Y -> [(Game T.X T.Y, Component.Turn.Turn T.X T.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 = Data.List.unfoldr ( \game@MkGame { getNextLogicalColour = nextLogicalColour,@@ -1247,7 +1243,7 @@ => 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 T.X T.Y -> [Component.QualifiedMove.QualifiedMove T.X T.Y] #-}+{-# SPECIALISE listQualifiedMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-} listQualifiedMovesAvailableTo logicalColour game@MkGame { getBoard = board, getMaybeChecked = maybeChecked@@ -1345,7 +1341,7 @@ Show x, Show y ) => Attribute.LogicalColour.LogicalColour -> Game x y -> AvailableQualifiedMoves x y-{-# SPECIALISE mkAvailableQualifiedMovesFor :: Attribute.LogicalColour.LogicalColour -> Game T.X T.Y -> AvailableQualifiedMoves T.X T.Y #-}+{-# SPECIALISE mkAvailableQualifiedMovesFor :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> AvailableQualifiedMoves Type.Length.X Type.Length.Y #-} mkAvailableQualifiedMovesFor logicalColour = foldr {-maintains destination-order-} ( \qualifiedMove -> let move = Component.QualifiedMove.getMove qualifiedMove@@ -1375,7 +1371,7 @@ => Attribute.LogicalColour.LogicalColour -> Game x y -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findQualifiedMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game T.X T.Y -> [Component.QualifiedMove.QualifiedMove T.X T.Y] #-}+{-# SPECIALISE findQualifiedMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-} findQualifiedMovesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour } | Just availableQualifiedMoves <- Data.Map.lookup logicalColour availableQualifiedMovesByLogicalColour = [ Component.QualifiedMove.mkQualifiedMove (Component.Move.mkMove source destination) moveType |@@ -1384,23 +1380,23 @@ ] -- List-comprehension. | otherwise = listQualifiedMovesAvailableTo logicalColour game -- Generate the list of moves for this player. --- | Count the number of moves (plies) available to the specified player.-countMovesAvailableTo :: (+-- | 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 -> Component.Move.NPlies-{-# SPECIALISE countMovesAvailableTo :: Attribute.LogicalColour.LogicalColour -> Game T.X T.Y -> Component.Move.NPlies #-}-countMovesAvailableTo logicalColour game@MkGame { getAvailableQualifiedMovesByLogicalColour = availableQualifiedMovesByLogicalColour }+ ) => 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 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.- = Data.Map.Strict.foldl' (\acc -> (+ acc) . length) 0 availableQualifiedMoves- | otherwise = length $ listQualifiedMovesAvailableTo logicalColour game+ = fromIntegral $ Data.Map.Strict.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 :: (@@ -1411,7 +1407,7 @@ Show x, Show y ) => Game x y -> [Component.QualifiedMove.QualifiedMove x y]-{-# SPECIALISE findQualifiedMovesAvailableToNextPlayer :: Game T.X T.Y -> [Component.QualifiedMove.QualifiedMove T.X T.Y] #-}+{-# SPECIALISE findQualifiedMovesAvailableToNextPlayer :: Game Type.Length.X Type.Length.Y -> [Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y] #-} findQualifiedMovesAvailableToNextPlayer game@MkGame { getNextLogicalColour = nextLogicalColour } = findQualifiedMovesAvailableTo nextLogicalColour game -- | Let the specified player resign.@@ -1419,7 +1415,7 @@ resignationBy logicalColour game | isTerminated game = game -- Already terminated. | otherwise = game {- getMaybeTerminationReason = Just $ Model.GameTerminationReason.mkResignation logicalColour+ getMaybeTerminationReason = Just $ Rule.GameTerminationReason.mkResignation logicalColour } -- | Resignation by the player who currently holds the choice of /move/.@@ -1431,7 +1427,7 @@ agreeToADraw game | isTerminated game = game -- Already terminated. | otherwise = game {- getMaybeTerminationReason = Just $ Model.GameTerminationReason.mkDraw Model.DrawReason.byAgreement+ getMaybeTerminationReason = Just $ Rule.GameTerminationReason.mkDraw Rule.DrawReason.byAgreement } -- | Whether the game has been terminated.@@ -1450,31 +1446,31 @@ Ord y, Show x, Show y- ) => Game x y -> Maybe Model.GameTerminationReason.GameTerminationReason-{-# SPECIALISE inferMaybeTerminationReason :: Game T.X T.Y -> Maybe Model.GameTerminationReason.GameTerminationReason #-}+ ) => Game x y -> Maybe Rule.GameTerminationReason.GameTerminationReason+{-# SPECIALISE inferMaybeTerminationReason :: Game Type.Length.X Type.Length.Y -> Maybe Rule.GameTerminationReason.GameTerminationReason #-} inferMaybeTerminationReason game@MkGame { getBoard = board, getInstancesByPosition = instancesByPosition } | haveZeroMoves- , Just logicalColour <- getMaybeChecked game = Just $ Model.GameTerminationReason.mkCheckMate logicalColour- | otherwise = fmap Model.GameTerminationReason.mkDraw maybeDrawReason+ , Just logicalColour <- getMaybeChecked game = Just $ Rule.GameTerminationReason.mkCheckMate logicalColour+ | otherwise = fmap Rule.GameTerminationReason.mkDraw maybeDrawReason where haveZeroMoves :: Bool haveZeroMoves = null $ findQualifiedMovesAvailableToNextPlayer game - maybeDrawReason :: Maybe Model.DrawReason.DrawReason+ maybeDrawReason :: Maybe Rule.DrawReason.DrawReason maybeDrawReason- | haveZeroMoves = Just Model.DrawReason.staleMate- | State.InstancesByPosition.anyInstancesByPosition (== Model.DrawReason.maximumConsecutiveRepeatablePositions) instancesByPosition = Just Model.DrawReason.fiveFoldRepetition- | State.InstancesByPosition.countConsecutiveRepeatablePlies instancesByPosition == Model.DrawReason.maximumConsecutiveRepeatablePlies = Just Model.DrawReason.seventyFiveMoveRule- | StateProperty.Censor.hasInsufficientMaterial $ State.Board.getCoordinatesByRankByLogicalColour board = Just Model.DrawReason.insufficientMaterial+ | haveZeroMoves = Just Rule.DrawReason.staleMate+ | State.InstancesByPosition.anyInstancesByPosition (== Rule.DrawReason.maximumConsecutiveRepeatablePositions) instancesByPosition = Just Rule.DrawReason.fiveFoldRepetition+ | State.InstancesByPosition.countConsecutiveRepeatablePlies instancesByPosition == Rule.DrawReason.maximumConsecutiveRepeatablePlies = Just Rule.DrawReason.seventyFiveMoveRule+ | StateProperty.Censor.hasInsufficientMaterial $ State.Board.getCoordinatesByRankByLogicalColour board = Just Rule.DrawReason.insufficientMaterial | 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 :: Model.Result.Result -> Transformation x y+updateTerminationReasonWith :: Rule.Result.Result -> Transformation x y updateTerminationReasonWith result game- | Just victorsLogicalColour <- Model.Result.findMaybeVictor result = resignationBy (Property.Opposable.getOpposite victorsLogicalColour) game+ | Just victorsLogicalColour <- Rule.Result.findMaybeVictor result = resignationBy (Property.Opposable.getOpposite victorsLogicalColour) game | otherwise = agreeToADraw game -- | Forwards request to "State.CastleableRooksByLogicalColour".@@ -1492,7 +1488,7 @@ Ord x, Ord y ) => Game x y -> State.Position.Position x y-{-# SPECIALISE mkPosition :: Game T.X T.Y -> State.Position.Position T.X T.Y #-}+{-# SPECIALISE mkPosition :: Game Type.Length.X Type.Length.Y -> State.Position.Position Type.Length.X Type.Length.Y #-} mkPosition game@MkGame { getNextLogicalColour = nextLogicalColour, getBoard = board,@@ -1508,7 +1504,7 @@ Show x, Show y ) => Game x y -> InstancesByPosition x y-{-# SPECIALISE mkInstancesByPosition :: Game T.X T.Y -> InstancesByPosition T.X T.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-} ) . (@@ -1532,7 +1528,7 @@ Ord x, Ord y ) => Game x y -> Game x y -> Bool-{-# SPECIALISE (=~) :: Game T.X T.Y -> Game T.X T.Y -> Bool #-}+{-# SPECIALISE (=~) :: Game Type.Length.X Type.Length.Y -> Game Type.Length.X Type.Length.Y -> Bool #-} game =~ game' = mkPosition game == mkPosition game' -- | Whether the state of the specified /game/s is different.@@ -1557,7 +1553,7 @@ -> Game x y -- ^ The current game. -> Component.Zobrist.Zobrist x y positionHash -> positionHash-{-# SPECIALISE updateIncrementalPositionHash :: Game T.X T.Y -> T.PositionHash -> Game T.X T.Y -> Component.Zobrist.Zobrist T.X T.Y T.PositionHash -> T.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 . ( let (castleableRooksByLogicalColour, castleableRooksByLogicalColour') = ($ game) &&& ($ game') $ getCastleableRooksByLogicalColour
− src-lib/BishBosh/Model/GameTerminationReason.hs
@@ -1,124 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Itemises the various reasons for terminating a game.-- * Each reason corresponds to a rule in chess.--}--module BishBosh.Model.GameTerminationReason(--- * Types--- ** Data-types- GameTerminationReason(),--- * Function- toResult,--- ** Constructors- mkCheckMate,- mkResignation,- mkDraw,--- ** Predicates- isCheckMateBy,- isCheckMate,- isResignation,- isDraw,- isDrawByInsufficientMaterial,- isStaleMate-) where--import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Model.DrawReason as Model.DrawReason-import qualified BishBosh.Model.Result as Model.Result-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Control.DeepSeq---- | The sum-type of ways in which a game can legally be terminated.-data GameTerminationReason- = CheckMateOf Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /check-mated/ player.- | ResignationBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player who resigned.- | Draw Model.DrawReason.DrawReason- deriving (Eq, Ord, Read, Show)--instance Control.DeepSeq.NFData GameTerminationReason where- rnf (CheckMateOf logicalColour) = Control.DeepSeq.rnf logicalColour- rnf (ResignationBy logicalColour) = Control.DeepSeq.rnf logicalColour- rnf (Draw drawReason) = Control.DeepSeq.rnf drawReason--instance Property.Opposable.Opposable GameTerminationReason where- getOpposite (CheckMateOf logicalColour) = CheckMateOf $ Property.Opposable.getOpposite logicalColour- getOpposite (ResignationBy logicalColour) = ResignationBy $ Property.Opposable.getOpposite logicalColour- getOpposite draw = draw--instance Property.FixedMembership.FixedMembership GameTerminationReason where- members = map CheckMateOf Property.FixedMembership.members ++ map ResignationBy Property.FixedMembership.members ++ map Draw Property.FixedMembership.members---- | Convert to a /result/.-toResult :: GameTerminationReason -> Model.Result.Result-toResult = Property.Opposable.getOpposite . Model.Result.mkResult . \case- CheckMateOf logicalColour -> Just logicalColour- ResignationBy logicalColour -> Just logicalColour- Draw _ -> Nothing---- | Constructor.-mkCheckMate :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason-mkCheckMate = CheckMateOf---- | Constructor.-mkResignation :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason-mkResignation = ResignationBy---- | Constructor.-mkDraw :: Model.DrawReason.DrawReason -> GameTerminationReason-mkDraw = Draw---- | Whether the game was won by the specified player.-isCheckMateBy :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason -> Bool-isCheckMateBy logicalColour (CheckMateOf logicalColour') = logicalColour /= logicalColour'-isCheckMateBy _ _ = False---- | Whether the game terminated in check-mate.-isCheckMate :: GameTerminationReason -> Bool-isCheckMate (CheckMateOf _) = True-isCheckMate _ = False---- | Whether the game was resigned.-isResignation :: GameTerminationReason -> Bool-isResignation (ResignationBy _) = True-isResignation _ = False---- | Whether the game was drawn.-isDraw :: GameTerminationReason -> Bool-isDraw (Draw _) = True-isDraw _ = False---- | Predicate.-isDrawByInsufficientMaterial :: GameTerminationReason -> Bool-isDrawByInsufficientMaterial (Draw draw) = draw == Model.DrawReason.insufficientMaterial-isDrawByInsufficientMaterial _ = False---- | Predicate.-isStaleMate :: GameTerminationReason -> Bool-isStaleMate (Draw draw) = draw == Model.DrawReason.staleMate-isStaleMate _ = False-
src-lib/BishBosh/Model/GameTree.hs view
@@ -44,7 +44,7 @@ -- staticExchangeEvaluation, -- getRankAndMove, countGames,- countMoves,+ countPositions, traceRoute, sortGameTree, toMoveFrequency,@@ -67,10 +67,11 @@ import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Property.Arboreal as Property.Arboreal import qualified BishBosh.Property.Empty as Property.Empty-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.Null as Property.Null-import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Types as T+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 import qualified Data.Foldable@@ -83,8 +84,7 @@ -- | Forwards request to 'Component.Turn.compareByMVVLVA'. compareByMVVLVA- :: Ord rankValue- => Attribute.Rank.EvaluateRank rankValue+ :: Attribute.Rank.EvaluateRank -> BareGameTree x y -> BareGameTree x y -> Ordering@@ -106,18 +106,16 @@ * 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,- Num rankValue,- Ord rankValue- )- => Attribute.Rank.EvaluateRank rankValue+staticExchangeEvaluation+ :: (Eq x, Eq y)+ => Attribute.Rank.EvaluateRank -> BareGameTree x y- -> rankValue+ -> 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 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 node'@Data.Tree.Node { Data.Tree.subForest = forest' } = max 0 {-this player shouldn't progress the battle-} . subtract ( case filter ( (@@ -136,7 +134,7 @@ ) . Model.Game.maybeLastTurn ) forest'' -- Select the least valuable aggressor. in slave node'' . Data.Maybe.fromJust $ getMaybeImplicitlyTakenRank game'' -- Recurse.- ) . evaluateRank {-of victim-}+ ) . realToFrac . evaluateRank {-of victim-} -- | Accessor. getRankAndMove :: Model.MoveFrequency.GetRankAndMove (BareGameTree x y) (Component.Move.Move x y)@@ -156,7 +154,7 @@ Show x, Show y ) => Data.Default.Default (GameTree x y) where- {-# SPECIALISE instance Data.Default.Default (GameTree T.X T.Y) #-}+ {-# SPECIALISE instance Data.Default.Default (GameTree Type.Length.X Type.Length.Y) #-} def = fromGame Data.Default.def instance Property.Arboreal.Prunable (GameTree x y) where@@ -187,7 +185,7 @@ Show x, Show y ) => Model.Game.Game x y -> GameTree x y-{-# SPECIALISE fromGame :: Model.Game.Game T.X T.Y -> GameTree T.X T.Y #-}+{-# SPECIALISE fromGame :: Model.Game.Game Type.Length.X Type.Length.Y -> GameTree Type.Length.X Type.Length.Y #-} fromGame = MkGameTree . Data.Tree.unfoldTree ( \game -> ( game,@@ -204,12 +202,12 @@ * N.B.: some of the /game-state/s may have identical positions, reached by different sequences of /move/s. -}-countGames :: Property.Arboreal.Depth -> Model.Game.NGames-countGames depth = Data.RoseTree.countTerminalNodes . deconstruct $ Property.Arboreal.prune depth (Data.Default.def :: GameTree T.X T.Y)+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) --- | Counts the number of possible plies in chess, down to the specified depth.-countMoves :: Property.Arboreal.Depth -> Model.Game.NGames-countMoves depth = pred {-the apex is constructed without moving-} . Data.Foldable.length . deconstruct $ Property.Arboreal.prune depth (Data.Default.def :: GameTree T.X T.Y)+-- | 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) -- | Trace the route down the tree which matches the specified list of turns. traceRoute@@ -228,21 +226,17 @@ {- | * Independently sorts the forest of moves at each node of the tree, without regard to runtime-data. - * Depending on preferences, the list of moves available to each game is sorted by; either those which capture a valuable piece using a cheap piece, or those which win extended battles at a specific location.+ * Depending on preferences, the list of moves available from each position is sorted by; either those which capture a valuable piece using a cheap piece, or those which win extended battles at a specific location. * The above sort-algorithms are stable & can therefore be applied independently. -}-sortGameTree :: (- Integral x,- Integral y,- Num rankValue,- Ord rankValue- )+sortGameTree+ :: (Integral x, Integral y) => Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm- -> Attribute.Rank.EvaluateRank rankValue+ -> Attribute.Rank.EvaluateRank -> MoveFrequency x y -> Transformation x y-{-# SPECIALISE sortGameTree :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> Attribute.Rank.EvaluateRank T.RankValue -> MoveFrequency T.X T.Y -> Transformation T.X T.Y #-}+{-# SPECIALISE sortGameTree :: Maybe Attribute.CaptureMoveSortAlgorithm.CaptureMoveSortAlgorithm -> Attribute.Rank.EvaluateRank -> MoveFrequency Type.Length.X Type.Length.Y -> Transformation Type.Length.X Type.Length.Y #-} sortGameTree maybeCaptureMoveSortAlgorithm evaluateRank standardOpeningMoveFrequency MkGameTree { deconstruct = bareGameTree } = MkGameTree $ Data.RoseTree.mapForest ( \game -> Data.Maybe.maybe id ( \case@@ -256,8 +250,10 @@ ) bareGameTree {- |- * Count the instances of each /move/ in the specified tree, including any pre-applied to the apex game.+ * Count the instances of each /move/ in the specified tree. + * CAVEAT: assumes that root game hasn't any pre-applied moves; which might occur in a test-case.+ * CAVEAT: ambiguity remains regarding the /move-type/ (especially any piece taken). * CAVEAT: a node is counted as just one instance of the move, rather than the number of games which passed through that node.@@ -265,19 +261,11 @@ 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 MkGameTree {- deconstruct = bareGameTree@Data.Tree.Node { Data.Tree.rootLabel = rootGame }-} = slave (- Data.List.foldl' (- \moveFrequency logicalColour -> Model.MoveFrequency.insertMoves logicalColour (- Component.Turn.getRank &&& Component.QualifiedMove.getMove . Component.Turn.getQualifiedMove- ) moveFrequency . State.TurnsByLogicalColour.dereference logicalColour $ Model.Game.getTurnsByLogicalColour rootGame- ) Property.Empty.empty {-MoveFrequency-} Property.FixedMembership.members- ) bareGameTree where- slave moveFrequency Data.Tree.Node {- Data.Tree.rootLabel = game,- Data.Tree.subForest = forest- } = Data.List.foldl' slave {-recurse-} (- Model.MoveFrequency.insertMoves (Model.Game.getNextLogicalColour game) getRankAndMove moveFrequency forest+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' (+ slave {-recurse-} $ Property.Opposable.getOpposite logicalColour+ ) (+ Model.MoveFrequency.insertMoves logicalColour getRankAndMove moveFrequency forest ) forest
src-lib/BishBosh/Model/MoveFrequency.hs view
@@ -41,12 +41,13 @@ sortByDescendingMoveFrequency ) 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.Component.Move as Component.Move import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.Null as Property.Null+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Foldable import qualified Data.List import qualified Data.List.Extra@@ -54,13 +55,13 @@ import qualified Data.Ord {- |- * Records the number of instances, by /move/, by /rank/, by /logical colour/.+ * Records the number of instances, indexed by /move/, by /rank/, by /logical colour/. - * CAVEAT: no record of the /move-type/ is stored.+ * CAVEAT: the /move-type/ isn't recorded. -} type InstancesByMoveByRankByLogicalColour move = Attribute.LogicalColour.ArrayByLogicalColour ( Attribute.Rank.ArrayByRank (- Data.Map.Strict.Map move Component.Move.NMoves+ Data.Map.Strict.Map move Type.Count.NPlies ) ) @@ -76,14 +77,14 @@ isNull MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.Foldable.all (Data.Foldable.all Data.Map.Strict.null) instancesByMoveByRankByLogicalColour -- | Count the total number of entries.-countEntries :: MoveFrequency move -> Component.Move.NMoves+countEntries :: MoveFrequency move -> Type.Count.NPlies countEntries MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.Foldable.foldl' ( Data.Foldable.foldl' $ \acc -> (acc +) . Data.Foldable.sum ) 0 instancesByMoveByRankByLogicalColour -- | Count the total number of distinct entries.-countDistinctEntries :: MoveFrequency move -> Component.Move.NMoves-countDistinctEntries MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = Data.Foldable.foldl' (+countDistinctEntries :: MoveFrequency move -> Type.Count.NPlies+countDistinctEntries MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = fromIntegral $ Data.Foldable.foldl' ( Data.Foldable.foldl' $ \acc -> (acc +) . Data.Map.Strict.size ) 0 instancesByMoveByRankByLogicalColour @@ -102,40 +103,28 @@ -> MoveFrequency move -> [a] -- ^ The data from each of which, /rank/ & /move/ can be extracted. -> MoveFrequency move-insertMoves logicalColour getRankAndMove MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = MkMoveFrequency . \case- [] -> instancesByMoveByRankByLogicalColour+insertMoves logicalColour getRankAndMove MkMoveFrequency { deconstruct = instancesByMoveByRankByLogicalColour } = MkMoveFrequency . (+ instancesByMoveByRankByLogicalColour //+ ) . return {-to List-monad-} . (,) logicalColour . (+ instancesByMoveByRank //+ ) . \case [datum] -> let (rank, move) = getRankAndMove datum- instancesByMove = instancesByMoveByRank ! rank- in instancesByMoveByRankByLogicalColour // [- (- logicalColour,- instancesByMoveByRank // [- (- rank,- Data.Map.Strict.insertWith (+) move 1 instancesByMove- ) -- Pair.- ] -- Singleton.- ) -- Pair.- ] -- Singleton.- l -> instancesByMoveByRankByLogicalColour // [+ in [id &&& incrementMoveCount move . (instancesByMoveByRank !) $ rank] -- Singleton.+ l -> [ (- logicalColour,- instancesByMoveByRank // [- (- rank,- foldr (- \(_, move) -> Data.Map.Strict.insertWith (+) move 1- ) (- instancesByMoveByRank ! rank- ) assocs--- ) | assocs@((rank, _) : _) <- Data.List.Extra.groupSortOn fst {-rank-} $ map getRankAndMove l -- CAVEAT: wastes space.- ) | assocs@((rank, _) : _) <- Data.List.Extra.groupSortBy (Data.Ord.comparing fst {-rank-}) $ map getRankAndMove l- ] -- List-comprehension.- ) -- Pair.- ] -- Singleton.+ rank,+ foldr (+ incrementMoveCount . snd {-move-}+ ) (+ instancesByMoveByRank ! rank+ ) assocs+-- ) | assocs@((rank, _) : _) <- Data.List.Extra.groupSortOn fst {-rank-} $ map getRankAndMove l -- CAVEAT: wastes space.+ ) | assocs@((rank, _) : _) <- Data.List.Extra.groupSortBy (Data.Ord.comparing fst {-rank-}) $ map getRankAndMove l+ ] -- List-comprehension. where instancesByMoveByRank = instancesByMoveByRankByLogicalColour ! logicalColour+ incrementMoveCount = flip (Data.Map.Strict.insertWith (+)) 1 {- | * Sorts an arbitrary list on the recorded frequency of the /rank/ & /move/ accessible from each list-item.
src-lib/BishBosh/Model/PositionHashTree.hs view
@@ -36,11 +36,12 @@ import qualified BishBosh.Component.Zobrist as Component.Zobrist import qualified BishBosh.Data.Exception as Data.Exception-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.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+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@@ -62,7 +63,7 @@ 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 T.X T.Y)+ def = mkPositionHashTree Data.Default.def (Data.Default.def :: Model.GameTree.GameTree Type.Length.X Type.Length.Y) -- | Hash the specified 'game-tree/. mkPositionHashTree :: (@@ -77,16 +78,16 @@ -> PositionHashTree positionHash mkPositionHashTree zobrist = MkPositionHashTree . fmap (`Component.Zobrist.hash2D` zobrist) . Model.GameTree.deconstruct --- | Count the number of distinct games, irrespective of the sequence of moves taken to reach that state.+-- | Count the number of distinct positions, irrespective of the sequence of moves taken to reach that terminal state. countDistinctPositions :: Ord positionHash => Property.Arboreal.Depth -> PositionHashTree positionHash- -> Model.Game.NGames-{-# SPECIALISE countDistinctPositions :: Property.Arboreal.Depth -> PositionHashTree T.PositionHash -> Model.Game.NGames #-}+ -> Type.Count.NPositions+{-# SPECIALISE countDistinctPositions :: Property.Arboreal.Depth -> PositionHashTree Type.Crypto.PositionHash -> Type.Count.NPositions #-} countDistinctPositions depth MkPositionHashTree { deconstruct = barePositionHashTree } | depth < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Component.PositionHashTree.countDistinctPositions:\tdepth" . Text.ShowList.showsAssociation $ shows depth "must be positive"- | otherwise = Data.Set.size $ slave depth barePositionHashTree+ | otherwise = fromIntegral . Data.Set.size $ slave depth barePositionHashTree where slave 0 Data.Tree.Node { Data.Tree.rootLabel = hash } = Data.Set.singleton hash -- Having reached the maximum depth, include this game's hash. slave _ Data.Tree.Node {
− src-lib/BishBosh/Model/Result.hs
@@ -1,98 +0,0 @@-{-# LANGUAGE LambdaCase #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Defines the result of a /game/.--}--module BishBosh.Model.Result(--- * Types--- ** Data-types- Result(--- VictoryBy,--- Draw- ),--- * Function- findMaybeVictor,--- ** Constructor- mkResult,--- ** Predicates- isDraw-) where--import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Control.DeepSeq-import qualified Data.List.Extra---- | The sum-type of ways in which a game can legally be terminated.-data Result- = VictoryBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the victor.- | Draw- deriving Eq--instance Control.DeepSeq.NFData Result where- rnf (VictoryBy logicalColour) = Control.DeepSeq.rnf logicalColour- rnf Draw = ()---- | Convert a game-termination reason into PGN's @Result@ field; <https://www.chessclub.com/help/pgn-spec>.-instance Show Result where- showsPrec _ = (- \(showsWhiteResult, showsBlackResult) -> showsWhiteResult . showChar '-' . showsBlackResult- ) . \case- VictoryBy Attribute.LogicalColour.Black -> (lose, win)- VictoryBy _ -> (win, lose)- _ -> (draw, draw)- where- lose = showChar '0'- win = showChar '1'- draw = showString "1/2"--instance Read Result where- readsPrec _ s = case Data.List.Extra.trimStart s of- '0' : '-' : '1' : remainder -> [(VictoryBy Attribute.LogicalColour.Black, remainder)]- '1' : '-' : '0' : remainder -> [(VictoryBy Attribute.LogicalColour.White, remainder)]- '1' : '/' : '2' : '-' : '1' : '/' : '2' : remainder -> [(Draw, remainder)]- _ -> [] -- No Parse.--instance Property.Opposable.Opposable Result where- getOpposite (VictoryBy logicalColour) = VictoryBy $ Property.Opposable.getOpposite logicalColour- getOpposite _ = Draw--instance Property.FixedMembership.FixedMembership Result where- members = Draw : map VictoryBy Property.FixedMembership.members---- | Constructor.-mkResult :: Maybe Attribute.LogicalColour.LogicalColour -> Result-mkResult (Just logicalColour) = VictoryBy logicalColour-mkResult _ = Draw---- | Whether the game was drawn.-isDraw :: Result -> Bool-isDraw Draw = True-isDraw _ = False---- | Find any winner.-findMaybeVictor :: Result -> Maybe Attribute.LogicalColour.LogicalColour-findMaybeVictor (VictoryBy logicalColour) = Just logicalColour-findMaybeVictor _ = Nothing-
src-lib/BishBosh/Notation/MoveNotation.hs view
@@ -58,10 +58,10 @@ import qualified BishBosh.Notation.Smith as Notation.Smith import qualified BishBosh.Property.FixedMembership as Property.FixedMembership import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Data.Default-import qualified Numeric import qualified Text.XML.HXT.Arrow.Pickle as HXT import qualified Text.XML.HXT.Arrow.Pickle.Schema @@ -162,6 +162,6 @@ showsNotationFloat :: MoveNotation -> (Double -> ShowS) -> a -> ShowS -- | Render the specified data in the specified notation, & to the specified number of decimal digits.-showsNotationFloatToNDecimals :: ShowNotationFloat a => MoveNotation -> Property.ShowFloat.NDecimalDigits -> a -> ShowS-showsNotationFloatToNDecimals moveNotation nDecimalDigits = showsNotationFloat moveNotation (Numeric.showFFloat $ Just nDecimalDigits)+showsNotationFloatToNDecimals :: ShowNotationFloat a => MoveNotation -> Type.Count.NDecimalDigits -> a -> ShowS+showsNotationFloatToNDecimals moveNotation = showsNotationFloat moveNotation . Property.ShowFloat.showsFloatToN'
src-lib/BishBosh/Notation/PureCoordinate.hs view
@@ -71,7 +71,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Control.Exception import qualified Data.Char@@ -128,14 +128,14 @@ #ifdef USE_POLYPARSE -- | Parse an /x/-coordinate. abscissaParser :: Enum x => Text.Poly.TextParser x-{-# SPECIALISE abscissaParser :: Text.Poly.TextParser T.X #-}+{-# SPECIALISE abscissaParser :: Text.Poly.TextParser Type.Length.X #-} abscissaParser = ( toEnum . (+ xOriginOffset) . Data.Char.ord ) `fmap` Poly.satisfyMsg inXRange "Abscissa" -- | Parse a /y/-coordinate. ordinateParser :: Enum y => Text.Poly.TextParser y-{-# SPECIALISE ordinateParser :: Text.Poly.TextParser T.Y #-}+{-# SPECIALISE ordinateParser :: Text.Poly.TextParser Type.Length.Y #-} ordinateParser = ( toEnum . (+ yOriginOffset) . Data.Char.ord ) `fmap` Poly.satisfyMsg inYRange "Ordinate"@@ -147,7 +147,7 @@ Ord x, Ord y ) => Text.Poly.TextParser (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE coordinatesParser :: Text.Poly.TextParser (Cartesian.Coordinates.Coordinates T.X T.Y) #-}+{-# SPECIALISE coordinatesParser :: Text.Poly.TextParser (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) #-} coordinatesParser = do x <- abscissaParser y <- ordinateParser@@ -156,12 +156,12 @@ #else /* Parsec */ -- | Parse an /x/-coordinate. abscissaParser :: Enum x => Parsec.Parser x-{-# SPECIALISE abscissaParser :: Parsec.Parser T.X #-}+{-# SPECIALISE abscissaParser :: Parsec.Parser Type.Length.X #-} abscissaParser = toEnum . (+ xOriginOffset) . Data.Char.ord <$> Parsec.satisfy inXRange <?> "Abscissa" -- | Parse a /y/-coordinate. ordinateParser :: Enum y => Parsec.Parser y-{-# SPECIALISE ordinateParser :: Parsec.Parser T.X #-}+{-# SPECIALISE ordinateParser :: Parsec.Parser Type.Length.X #-} ordinateParser = toEnum . (+ yOriginOffset) . Data.Char.ord <$> Parsec.satisfy inYRange <?> "Ordinate" -- | Parse a pair of /coordinates/.@@ -171,7 +171,7 @@ Ord x, Ord y ) => Parsec.Parser (Cartesian.Coordinates.Coordinates x y)-{-# SPECIALISE coordinatesParser :: Parsec.Parser (Cartesian.Coordinates.Coordinates T.X T.Y) #-}+{-# SPECIALISE coordinatesParser :: Parsec.Parser (Cartesian.Coordinates.Coordinates Type.Length.X Type.Length.Y) #-} coordinatesParser = Cartesian.Coordinates.mkCoordinates <$> abscissaParser <*> ordinateParser #endif
src-lib/BishBosh/Property/Opposable.hs view
@@ -32,3 +32,4 @@ -- | An interface which data which have the concept of an opposite, may implement. class Opposable a where getOpposite :: a -> a+
+ src-lib/BishBosh/Property/SelfValidating.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 a class to which data capable of validating itself can confirm.+-}++module BishBosh.Property.SelfValidating(+-- * Type-classes+ SelfValidating(..),+-- * Functions+ findErrors,+-- ** Predicates+ isValid,+ isInvalid+ ) where++{- |+ * This class serves data-types which must preserve compatibility beyond that which can be guarded by a smart-constructor.++ * E.g.: data-types which are constructed piece-meal & endure a temporarily invalid state.+-}+class SelfValidating a where+ findInvalidity :: a -> [String]++instance SelfValidating a => SelfValidating [a] where+ findInvalidity = concatMap findInvalidity++-- | Predicate.+isValid :: SelfValidating a => a -> Bool+isValid = null . findInvalidity++-- | Predicate.+isInvalid :: SelfValidating a => a -> Bool+isInvalid = not . isValid++-- | Selects relevant error-messages from the specified association-list, to facilitate implementation of 'findInvalidity'.+findErrors :: [(selfValidator -> Bool, String)] -> selfValidator -> [String]+findErrors assocs selfValidator = [+ errorMessage |+ (predicate, errorMessage) <- assocs,+ predicate selfValidator+ ] -- List-comprehension.+
src-lib/BishBosh/Property/ShowFloat.hs view
@@ -25,23 +25,23 @@ module BishBosh.Property.ShowFloat( -- * Type-classes ShowFloat(..),--- * Types--- ** Type-synonyms- NDecimalDigits, -- * Functions+ showsFloatToN', showsFloatToN ) where +import qualified BishBosh.Type.Count as Type.Count import qualified Numeric --- | A number of decimals digits.-type NDecimalDigits = Int+-- | Render the specified data to the specified number of decimal digits.+showsFloatToN' :: RealFloat a => Type.Count.NDecimalDigits -> a -> ShowS+showsFloatToN' nDecimalDigits = Numeric.showFFloat (Just $ fromIntegral nDecimalDigits) -- | An alternative to 'Show', for floating-point data. class ShowFloat a where showsFloat :: (Double -> ShowS) -> a -> ShowS -- | Render the specified data to the specified number of decimal digits.-showsFloatToN :: ShowFloat a => NDecimalDigits -> a -> ShowS-showsFloatToN nDecimalDigits = showsFloat (Numeric.showFFloat $ Just nDecimalDigits)+showsFloatToN :: ShowFloat a => Type.Count.NDecimalDigits -> a -> ShowS+showsFloatToN nDecimalDigits = showsFloat $ showsFloatToN' nDecimalDigits
+ src-lib/BishBosh/Property/Switchable.hs view
@@ -0,0 +1,53 @@+{-+ 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 class to which IO data-types which can be switched between binary states, can conform.+-}++module BishBosh.Property.Switchable(+-- * Type-classes+ Switchable(..),+-- * Functions+ flick+ ) where++import qualified Data.Foldable++-- | For data which operate like binary switches.+class Switchable a where+ on :: IO a -- ^ Returns a switch in the /on/ state, regardless of any previous state.++ toggle :: a -> IO a -- ^ Switch the binary state.++ switchOff :: a -> IO a -- ^ Turn the switch off, which has no effect if already in the /off/ state.+ switchOff a+ | isOn a = toggle a+ | otherwise = return {-to IO-monad-} a++ isOn :: a -> Bool -- ^ Predicate: whether the switch is currently in the /on/ state.++ isOff :: a -> Bool -- ^ Predicate: whether the switch is currently in the /off/ state.+ isOff = not . isOn++-- | Toggle the switch the specified number of times.+flick :: Switchable switchable => Int -> switchable -> IO switchable+flick n switchable = Data.Foldable.foldrM ($) switchable $ replicate n toggle+
+ src-lib/BishBosh/Rule/DrawReason.hs view
@@ -0,0 +1,102 @@+{-+ 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@]++ * Itemises the ways in which a game may be declared a draw.++ * Each reason corresponds to a rule in chess.+-}++module BishBosh.Rule.DrawReason(+-- * Types+-- ** Data-types+ DrawReason(),+-- * Constants+ maximumConsecutiveRepeatablePlies,+ maximumConsecutiveRepeatablePositions,+ byAgreement,+-- fiftyMoveRule,+ seventyFiveMoveRule,+ insufficientMaterial,+ staleMate,+-- threeFoldRepetition,+ fiveFoldRepetition+) where++import qualified BishBosh.Component.Move as Component.Move+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Type.Count as Type.Count+import qualified Control.DeepSeq++-- | The sum-type of ways in which a game can be drawn.+data DrawReason+ = ByAgreement -- ^ Both players have agreed to a draw.+ | FiftyMoveRule -- ^ A draw can be claimed if fifty consecutive full /move/s have occured without any capture or any @Pawn@ being moved.+ | SeventyFiveMoveRule -- ^ Seventy-five consecutive full /move/s have occured without either capture or @Pawn@-movement; <https://www.chessprogramming.org/Repetitions#Fide_Rule>.+ | InsufficientMaterial -- ^ Neither player as the fire-power to force /check-mate/.+ | StaleMate -- ^ The next player hasn't any legal moves, but isn't /in check/.+ | ThreeFoldRepetition -- ^ A draw can be claimed if the same /position/ has been reached on any three occasions.+ | FiveFoldRepetition -- ^ The same /position/ has been reached on five successive occasions.+ deriving (Eq, Ord, Read, Show)++instance Control.DeepSeq.NFData DrawReason where+ rnf _ = ()++instance Property.FixedMembership.FixedMembership DrawReason where+ members = [ByAgreement, FiftyMoveRule, SeventyFiveMoveRule, InsufficientMaterial, StaleMate, ThreeFoldRepetition, FiveFoldRepetition]++-- | Constant.+byAgreement :: DrawReason+byAgreement = ByAgreement++-- | Constant.+fiftyMoveRule :: DrawReason+fiftyMoveRule = FiftyMoveRule++-- | Constant.+seventyFiveMoveRule :: DrawReason+seventyFiveMoveRule = SeventyFiveMoveRule++-- | Constant.+insufficientMaterial :: DrawReason+insufficientMaterial = InsufficientMaterial++-- | Constant.+staleMate :: DrawReason+staleMate = StaleMate++-- | Constant.+threeFoldRepetition :: DrawReason+threeFoldRepetition = ThreeFoldRepetition++-- | Constant.+fiveFoldRepetition :: DrawReason+fiveFoldRepetition = FiveFoldRepetition++-- | The number of consecutive plies required to trigger a draw by the seventy-five move rule.+maximumConsecutiveRepeatablePlies :: Type.Count.NPlies+maximumConsecutiveRepeatablePlies = Component.Move.nPliesPerMove * 75++-- | The number of consecutive repeatable positions required for a draw by the five-fold repetition rule.+maximumConsecutiveRepeatablePositions :: Type.Count.NPositions+maximumConsecutiveRepeatablePositions = 5+
+ src-lib/BishBosh/Rule/GameTerminationReason.hs view
@@ -0,0 +1,124 @@+{-# LANGUAGE LambdaCase #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Itemises the various reasons for terminating a game.++ * Each reason corresponds to a rule in chess.+-}++module BishBosh.Rule.GameTerminationReason(+-- * Types+-- ** Data-types+ GameTerminationReason(),+-- * Function+ toResult,+-- ** Constructors+ mkCheckMate,+ mkResignation,+ mkDraw,+-- ** Predicates+ isCheckMateBy,+ isCheckMate,+ isResignation,+ isDraw,+ isDrawByInsufficientMaterial,+ isStaleMate+) where++import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Rule.DrawReason as Rule.DrawReason+import qualified BishBosh.Rule.Result as Rule.Result+import qualified Control.DeepSeq++-- | The sum-type of ways in which a game can legally be terminated.+data GameTerminationReason+ = CheckMateOf Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the /check-mated/ player.+ | ResignationBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the player who resigned.+ | Draw Rule.DrawReason.DrawReason+ deriving (Eq, Ord, Read, Show)++instance Control.DeepSeq.NFData GameTerminationReason where+ rnf (CheckMateOf logicalColour) = Control.DeepSeq.rnf logicalColour+ rnf (ResignationBy logicalColour) = Control.DeepSeq.rnf logicalColour+ rnf (Draw drawReason) = Control.DeepSeq.rnf drawReason++instance Property.Opposable.Opposable GameTerminationReason where+ getOpposite (CheckMateOf logicalColour) = CheckMateOf $ Property.Opposable.getOpposite logicalColour+ getOpposite (ResignationBy logicalColour) = ResignationBy $ Property.Opposable.getOpposite logicalColour+ getOpposite draw = draw++instance Property.FixedMembership.FixedMembership GameTerminationReason where+ members = map CheckMateOf Property.FixedMembership.members ++ map ResignationBy Property.FixedMembership.members ++ map Draw Property.FixedMembership.members++-- | Convert to a /result/.+toResult :: GameTerminationReason -> Rule.Result.Result+toResult = Property.Opposable.getOpposite . Rule.Result.mkResult . \case+ CheckMateOf logicalColour -> Just logicalColour+ ResignationBy logicalColour -> Just logicalColour+ Draw _ -> Nothing++-- | Constructor.+mkCheckMate :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason+mkCheckMate = CheckMateOf++-- | Constructor.+mkResignation :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason+mkResignation = ResignationBy++-- | Constructor.+mkDraw :: Rule.DrawReason.DrawReason -> GameTerminationReason+mkDraw = Draw++-- | Whether the game was won by the specified player.+isCheckMateBy :: Attribute.LogicalColour.LogicalColour -> GameTerminationReason -> Bool+isCheckMateBy logicalColour (CheckMateOf logicalColour') = logicalColour /= logicalColour'+isCheckMateBy _ _ = False++-- | Whether the game terminated in check-mate.+isCheckMate :: GameTerminationReason -> Bool+isCheckMate (CheckMateOf _) = True+isCheckMate _ = False++-- | Whether the game was resigned.+isResignation :: GameTerminationReason -> Bool+isResignation (ResignationBy _) = True+isResignation _ = False++-- | Whether the game was drawn.+isDraw :: GameTerminationReason -> Bool+isDraw (Draw _) = True+isDraw _ = False++-- | Predicate.+isDrawByInsufficientMaterial :: GameTerminationReason -> Bool+isDrawByInsufficientMaterial (Draw draw) = draw == Rule.DrawReason.insufficientMaterial+isDrawByInsufficientMaterial _ = False++-- | Predicate.+isStaleMate :: GameTerminationReason -> Bool+isStaleMate (Draw draw) = draw == Rule.DrawReason.staleMate+isStaleMate _ = False+
+ src-lib/BishBosh/Rule/Result.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE LambdaCase #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Defines the result of a /game/.+-}++module BishBosh.Rule.Result(+-- * Types+-- ** Data-types+ Result(+-- VictoryBy,+-- Draw+ ),+-- * Function+ findMaybeVictor,+-- ** Constructor+ mkResult,+-- ** Predicates+ isDraw+) where++import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified Control.DeepSeq+import qualified Data.List.Extra++-- | The sum-type of ways in which a game can legally be terminated.+data Result+ = VictoryBy Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the victor.+ | Draw+ deriving Eq++instance Control.DeepSeq.NFData Result where+ rnf (VictoryBy logicalColour) = Control.DeepSeq.rnf logicalColour+ rnf Draw = ()++-- | Convert a game-termination reason into PGN's @Result@ field; <https://www.chessclub.com/help/pgn-spec>.+instance Show Result where+ showsPrec _ = (+ \(showsWhiteResult, showsBlackResult) -> showsWhiteResult . showChar '-' . showsBlackResult+ ) . \case+ VictoryBy Attribute.LogicalColour.Black -> (lose, win)+ VictoryBy _ -> (win, lose)+ _ -> (draw, draw)+ where+ lose = showChar '0'+ win = showChar '1'+ draw = showString "1/2"++instance Read Result where+ readsPrec _ s = case Data.List.Extra.trimStart s of+ '0' : '-' : '1' : remainder -> [(VictoryBy Attribute.LogicalColour.Black, remainder)]+ '1' : '-' : '0' : remainder -> [(VictoryBy Attribute.LogicalColour.White, remainder)]+ '1' : '/' : '2' : '-' : '1' : '/' : '2' : remainder -> [(Draw, remainder)]+ _ -> [] -- No Parse.++instance Property.Opposable.Opposable Result where+ getOpposite (VictoryBy logicalColour) = VictoryBy $ Property.Opposable.getOpposite logicalColour+ getOpposite _ = Draw++instance Property.FixedMembership.FixedMembership Result where+ members = Draw : map VictoryBy Property.FixedMembership.members++-- | Constructor.+mkResult :: Maybe Attribute.LogicalColour.LogicalColour -> Result+mkResult (Just logicalColour) = VictoryBy logicalColour+mkResult _ = Draw++-- | Whether the game was drawn.+isDraw :: Result -> Bool+isDraw Draw = True+isDraw _ = False++-- | Find any winner.+findMaybeVictor :: Result -> Maybe Attribute.LogicalColour.LogicalColour+findMaybeVictor (VictoryBy logicalColour) = Just logicalColour+findMaybeVictor _ = Nothing+
src-lib/BishBosh/Search/AlphaBeta.hs view
@@ -41,13 +41,12 @@ -- updateTranspositions, negaMax, -- negateFitnessOfResult,--- addNMovesToResult+-- addNPositionsToResult ) where import BishBosh.Model.Game((=~)) import Control.Applicative((<|>)) import Control.Arrow((&&&))-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Data.Exception as Data.Exception@@ -64,7 +63,9 @@ import qualified BishBosh.Search.TranspositionValue as Search.TranspositionValue import qualified BishBosh.State.InstancesByPosition as State.InstancesByPosition import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Types as T+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@@ -72,29 +73,29 @@ import qualified Data.Tree -- | The type returned by 'negaMax'.-data Result x y positionHash criterionValue weightedMean = MkResult {+data Result x y positionHash = MkResult { getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData x y positionHash, -- ^ Killer moves & transpositions.- getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean,- getNPliesEvaluated :: Component.Move.NPlies -- ^ The total number of nodes analysed, before making the selection.+ getQuantifiedGame :: Evaluation.QuantifiedGame.QuantifiedGame x y,+ getNPositionsEvaluated :: Type.Count.NPositions -- ^ The total number of nodes analysed, before making the selection. } {- |- * Drop the specified number of /turn/s; typically those made before starting the search.+ * Drop the specified number of plies; typically those made before starting the search. * CAVEAT: abandons the fitness component of the quantified game. -} extractSelectedTurns- :: Component.Move.NPlies- -> Result x y positionHash criterionValue weightedMean- -> (Search.DynamicMoveData.DynamicMoveData x y positionHash, [Component.Turn.Turn x y], Component.Move.NPlies)+ :: Type.Count.NPlies+ -> Result x y positionHash+ -> (Search.DynamicMoveData.DynamicMoveData x y positionHash, [Component.Turn.Turn x y], Type.Count.NPositions) extractSelectedTurns nPlies MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = quantifiedGame,- getNPliesEvaluated = nPliesEvaluated+ getNPositionsEvaluated = nPositionsEvaluated } = ( dynamicMoveData, Evaluation.QuantifiedGame.getLatestTurns nPlies quantifiedGame,- nPliesEvaluated+ nPositionsEvaluated ) -- | Record the last move as a killer, unless it's a capture move.@@ -126,16 +127,15 @@ Eq y, Enum x, Enum y,- Real weightedMean, Show x, Show y )- => Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+ => Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> Search.TranspositionValue.TranspositionValue (Component.QualifiedMove.QualifiedMove x y)- -> Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean+ -> Evaluation.QuantifiedGame.QuantifiedGame x y 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 inferredSearchDepth positionHashQuantifiedGameTree+ Notation.MoveNotation.showsNotationFloatToNDecimals Data.Default.def {-move-notation-} 3 {-decimal digits-} $ Property.Arboreal.prune (fromIntegral inferredSearchDepth) positionHashQuantifiedGameTree ) "" ) ( (@@ -153,15 +153,14 @@ Enum x, Enum y, Ord positionHash,- Real weightedMean, Show x, Show y ) => Search.TranspositionValue.IsOptimal- -> Component.Move.NPlies+ -> Type.Count.NPlies -> positionHash -> [Component.Turn.Turn x y]- -> Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+ -> Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> Search.DynamicMoveData.Transformation x y positionHash updateTranspositions isOptimal nPlies positionHash turns positionHashQuantifiedGameTree = Search.DynamicMoveData.updateTranspositions . Search.Transpositions.insert ( Evaluation.QuantifiedGame.getFitness . findTranspositionTerminalQuantifiedGame positionHashQuantifiedGameTree@@ -177,18 +176,16 @@ negaMax :: ( Enum x, Enum y,- Eq criterionValue, Ord positionHash, Ord x, Ord y,- Real weightedMean, Show x, Show y )- => Input.SearchOptions.SearchDepth -- ^ The depth to which the tree should be searched; i.e. the number of plies to look-ahead.- -> Search.SearchState.SearchState x y positionHash criterionValue weightedMean- -> Input.SearchOptions.Reader (Result x y positionHash criterionValue weightedMean)-{-# SPECIALISE negaMax :: Input.SearchOptions.SearchDepth -> Search.SearchState.SearchState T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean -> Input.SearchOptions.Reader (Result T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean) #-}+ => 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) #-} negaMax initialSearchDepth initialSearchState = do maybeMinimumTranspositionSearchDepth <- Control.Monad.Reader.asks Input.SearchOptions.maybeMinimumTranspositionSearchDepth recordKillerMoves <- Control.Monad.Reader.asks Input.SearchOptions.recordKillerMoves@@ -198,16 +195,16 @@ getNPlies = State.TurnsByLogicalColour.getNPlies . Model.Game.getTurnsByLogicalColour -- Abbreviate. {- descend- :: Evaluation.QuantifiedGame.OpenInterval x y criterionValue weightedMean- -> Input.SearchOptions.SearchDepth- -> Search.SearchState.SearchState x y positionHash criterionValue weightedMean- -> Result x y positionHash criterionValue weightedMean+ :: Evaluation.QuantifiedGame.OpenInterval x y+ -> Type.Count.NPlies+ -> Search.SearchState.SearchState x y positionHash+ -> Result x y positionHash -} descend (maybeAlphaQuantifiedGame, maybeBetaQuantifiedGame) searchDepth searchState | searchDepth == 0 || Model.Game.isTerminated game = MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = Evaluation.QuantifiedGame.negateFitness quantifiedGame, -- CAVEAT: zero new moves have been applied, so the last move was the opponent's.- getNPliesEvaluated = 1 -- Fitness-negation requires evaluation.+ getNPositionsEvaluated = 1 -- Fitness-negation requires evaluation. } -- Terminate the recursion. | useTranspositions , Just transpositionValue <- Search.Transpositions.find positionHash $ Search.DynamicMoveData.getTranspositions dynamicMoveData -- Look for a previously encountered position with a matching positionHash.@@ -225,7 +222,7 @@ then MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = Control.Exception.assert (transposedQuantifiedGame == getQuantifiedGame selectMaxUsingTranspositions) transposedQuantifiedGame,- getNPliesEvaluated = 0+ getNPositionsEvaluated = 0 } else Data.Maybe.maybe selectMaxUsingTranspositions ( \betaQuantifiedGame -> if Evaluation.QuantifiedGame.compareFitness transposedQuantifiedGame betaQuantifiedGame == LT@@ -233,7 +230,7 @@ else MkResult { getDynamicMoveData = dynamicMoveData, getQuantifiedGame = Control.Exception.assert (betaQuantifiedGame == getQuantifiedGame selectMaxUsingTranspositions) betaQuantifiedGame,- getNPliesEvaluated = 0+ getNPositionsEvaluated = 0 } ) maybeBetaQuantifiedGame | otherwise = selectMaxWithSorter id@@ -259,13 +256,13 @@ {- selectMax :: Search.DynamicMoveData.DynamicMoveData x y positionHash- -> Maybe (Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean)- -> [Evaluation.PositionHashQuantifiedGameTree.BarePositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean]- -> Result x y positionHash criterionValue weightedMean+ -> Maybe (Evaluation.QuantifiedGame.QuantifiedGame x y)+ -> [Evaluation.PositionHashQuantifiedGameTree.BarePositionHashQuantifiedGameTree x y positionHash]+ -> Result x y positionHash -} selectMax dynamicMoveData' maybeAlphaQuantifiedGame' (node : remainingNodes) | trapRepeatedPositions- , nDistinctPositions >= State.InstancesByPosition.leastCyclicPlies -- CAVEAT: accounting for the typically (except when its the initial position) unrepeatable first distinct position.+ , nDistinctPositions >= fromIntegral State.InstancesByPosition.leastCyclicPlies -- CAVEAT: accounting for the typically (except when its the initial position) unrepeatable first distinct position. , State.InstancesByPosition.getNDistinctPositions ( Model.Game.getInstancesByPosition . Evaluation.QuantifiedGame.getGame $ Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame' node -- If the size hasn't increased, then the recently added position must have already been a member; (size == 1) during successive unrepeatable moves also, but that exception is caught above. ) == nDistinctPositions = selectMax dynamicMoveData' (@@ -285,8 +282,8 @@ ) dynamicMoveData'', getQuantifiedGame = betaQuantifiedGame } -- Beta-cutoff; the solution-space is either zero or negative.- | otherwise = addNMovesToResult (- getNPliesEvaluated result''+ | otherwise = addNPositionsToResult (+ getNPositionsEvaluated result'' ) $ let isFitter = Data.Maybe.maybe True {-alpha is undefined => anything qualifies-} ( \alphaQuantifiedGame -> case quantifiedGame'' `Evaluation.QuantifiedGame.compareFitness` alphaQuantifiedGame of@@ -327,7 +324,7 @@ Control.Exception.throw . Data.Exception.mkResultUndefined . showString "BishBosh.Search.AlphaBeta.negaMax.descend.selectMax:\tthere are zero nodes to process, but neither alpha nor beta is defined; " $ shows game "." ) maybeBetaQuantifiedGame -- Return the only viable position known. ) maybeAlphaQuantifiedGame', -- Return the fittest viable position found.- getNPliesEvaluated = 0+ getNPositionsEvaluated = 0 } -- Zero moves remain => terminate the recursion. return {-to Reader-monad-} . ( \result@MkResult {@@ -346,17 +343,17 @@ ) $ descend Evaluation.QuantifiedGame.unboundedInterval initialSearchDepth initialSearchState -- | The type of a function which transforms the result.-type Transformation x y positionHash criterionValue weightedMean = Result x y positionHash criterionValue weightedMean -> Result x y positionHash criterionValue weightedMean+type Transformation x y positionHash = Result x y positionHash -> Result x y positionHash -- | Mutator.-negateFitnessOfResult :: Num weightedMean => Transformation x y positionHash criterionValue weightedMean+negateFitnessOfResult :: Transformation x y positionHash negateFitnessOfResult result@MkResult { getQuantifiedGame = quantifiedGame } = result { getQuantifiedGame = Evaluation.QuantifiedGame.negateFitness quantifiedGame } -- | Mutator.-addNMovesToResult :: Component.Move.NPlies -> Transformation x y positionHash criterionValue weightedMean-addNMovesToResult nPlies result@MkResult { getNPliesEvaluated = nPliesEvaluated } = Control.Exception.assert (nPlies > 0) result {- getNPliesEvaluated = nPlies + nPliesEvaluated+addNPositionsToResult :: Type.Count.NPositions -> Transformation x y positionHash+addNPositionsToResult nPositions result@MkResult { getNPositionsEvaluated = nPositionsEvaluated } = Control.Exception.assert (nPositions > 0) result {+ getNPositionsEvaluated = nPositions + nPositionsEvaluated }
src-lib/BishBosh/Search/DynamicMoveData.hs view
@@ -51,6 +51,7 @@ import qualified BishBosh.Search.EphemeralData as Search.EphemeralData import qualified BishBosh.Search.KillerMoves as Search.KillerMoves import qualified BishBosh.Search.Transpositions as Search.Transpositions+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Maybe {- |@@ -99,6 +100,6 @@ Search.EphemeralData.euthanise . reduceNPlies ) maybeRetireTranspositionsAfter transpositions } where- reduceNPlies :: Component.Move.NMoves -> Component.Move.NPlies- reduceNPlies = (`subtract` nPlies) . (* 2) {-convert full moves to plies-}+ reduceNPlies :: Type.Count.NMoves -> Type.Count.NPlies+ reduceNPlies = (`subtract` nPlies) . (* Component.Move.nPliesPerMove) . fromIntegral
src-lib/BishBosh/Search/EphemeralData.hs view
@@ -28,20 +28,21 @@ MaybeEphemeralData(..) ) where -import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Input.SearchOptions as Input.SearchOptions+import qualified BishBosh.Type.Count as Type.Count import Prelude(Int) -- | An interface for short-lived data. class EphemeralData a where- getSize :: a -> Int -- ^ Get the current size of the collection.- euthanise :: Component.Move.NPlies -> a -> a -- ^ Prune data older than the specified number of plies, from the collection.+ getSize :: a -> Int -- ^ Get the current size of the collection.+ euthanise :: Type.Count.NPlies -> a -> a -- ^ Prune items older than the specified number of plies, from the data. -- | For data which can be killed. class MaybeEphemeralData a where maybeEuthanise- :: Component.Move.NPlies -- ^ The age at which to die.+ :: Type.Count.NPlies -- ^ The age at which to die. -> Input.SearchOptions.MaybeRetireAfterNMoves -- ^ The optional age at which to retire killer-moves. -> Input.SearchOptions.MaybeRetireAfterNMoves -- ^ The optional age at which to retire transpositions. -> a -> a+
src-lib/BishBosh/Search/KillerMoves.hs view
@@ -38,9 +38,9 @@ import Control.Arrow((&&&)) import Data.Array.IArray((!), (//)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Search.EphemeralData as Search.EphemeralData+import qualified BishBosh.Type.Count as Type.Count import qualified Data.Array.IArray import qualified Data.Foldable import qualified Data.IntMap.Strict@@ -56,7 +56,7 @@ -} type NInstancesByNPliesByKeyByLogicalColour killerMoveKey = Attribute.LogicalColour.ArrayByLogicalColour ( Data.Map.Map killerMoveKey (- Data.IntMap.Strict.IntMap Component.Move.NPlies+ 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. ) ) @@ -69,7 +69,7 @@ empty = MkKillerMoves . Attribute.LogicalColour.listArrayByLogicalColour $ repeat Property.Empty.empty instance Search.EphemeralData.EphemeralData (KillerMoves killerMoveKey) where- getSize MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = Data.Foldable.foldl' (+ getSize MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = fromIntegral $ Data.Foldable.foldl' ( Data.Map.foldl' $ Data.IntMap.Strict.foldl' (+) ) 0 nInstancesByNPliesByKeyByLogicalColour @@ -77,7 +77,7 @@ | 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' > nPlies) m+ m' = Data.IntMap.Strict.filterWithKey (\nPlies' _ -> nPlies' > fromIntegral nPlies) m in if Data.IntMap.Strict.null m' then Nothing else Just m'@@ -89,14 +89,14 @@ -- | Insert a killer-move. insert :: Ord killerMoveKey- => Component.Move.NPlies -- ^ The total number of plies applied to the game.+ => Type.Count.NPlies -- ^ The total number of plies applied to the game. -> killerMoveKey -> Transformation killerMoveKey insert nPlies killerMoveKey MkKillerMoves { deconstruct = nInstancesByNPliesByKeyByLogicalColour } = MkKillerMoves $ nInstancesByNPliesByKeyByLogicalColour // [ id &&& Data.Map.insertWith ( Data.IntMap.Strict.unionWith (+) ) killerMoveKey (- Data.IntMap.Strict.singleton nPlies 1+ Data.IntMap.Strict.singleton (fromIntegral nPlies) 1 ) . ( nInstancesByNPliesByKeyByLogicalColour ! ) $ if even nPlies@@ -118,3 +118,4 @@ ) . ( `Data.Map.lookup` (nInstancesByNPliesByKeyByLogicalColour ! logicalColour) ) . killerMoveKeyConstructor+
src-lib/BishBosh/Search/Search.hs view
@@ -29,7 +29,7 @@ -- MkResult, getSearchState, getQuantifiedGames,- getNPliesEvaluated+ getNPositionsEvaluated ), -- * Constants showsSeparator,@@ -41,7 +41,6 @@ ) where import Control.Arrow((&&&))-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame@@ -53,34 +52,36 @@ import qualified BishBosh.Search.SearchState as Search.SearchState import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Text.ShowList as Text.ShowList-import qualified BishBosh.Types as T+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 criterionValue weightedMean = MkResult {- getSearchState :: Search.SearchState.SearchState x y positionHash criterionValue weightedMean,- getQuantifiedGames :: [Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean], -- ^ The optimal path down the /positionHashQuantifiedGameTree/.- getNPliesEvaluated :: Component.Move.NPlies -- ^ The total number of nodes in the /positionHashQuantifiedGameTree/ which were analysed.+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. } -instance Control.DeepSeq.NFData weightedMean => Control.DeepSeq.NFData (Result x y positionHash criterionValue weightedMean) where+instance Control.DeepSeq.NFData (Result x y 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, Real criterionValue, Real weightedMean) => Notation.MoveNotation.ShowNotationFloat (Result x y positionHash criterionValue weightedMean) where+instance (Enum x, Enum y) => Notation.MoveNotation.ShowNotationFloat (Result x y positionHash) where showsNotationFloat moveNotation showsDouble result@MkResult { getQuantifiedGames = quantifiedGames,- getNPliesEvaluated = nPliesEvaluated+ getNPositionsEvaluated = nPositionsEvaluated } = Text.ShowList.showsFormattedList showsSeparator ( Notation.MoveNotation.showsNotationFloat moveNotation showsDouble- ) quantifiedGames . showString "; selected after analysing " . shows nPliesEvaluated . showString " nodes" . (- if null quantifiedGames || nPliesEvaluated == 0+ ) quantifiedGames . showString "; selected after analysing " . shows nPositionsEvaluated . showString " nodes" . (+ if null quantifiedGames || nPositionsEvaluated == 0 then id else showString " (branching-factor" . Text.ShowList.showsAssociation . showsDouble (calculateBranchingFactor result) . showChar ')' )@@ -94,17 +95,17 @@ Show x, Show y )- => Search.SearchState.SearchState x y positionHash criterionValue weightedMean- -> [Evaluation.QuantifiedGame.QuantifiedGame x y criterionValue weightedMean]- -> Component.Move.NPlies- -> Result x y positionHash criterionValue weightedMean-mkResult searchState quantifiedGames nPliesEvaluated+ => Search.SearchState.SearchState x y positionHash+ -> [Evaluation.QuantifiedGame.QuantifiedGame x y]+ -> Type.Count.NPositions+ -> Result x y positionHash+mkResult searchState quantifiedGames nPositionsEvaluated | null quantifiedGames = Control.Exception.throw . Data.Exception.mkNullDatum . showString "BishBosh.Search.Search.mkResult:\tnull quantifiedGames; " $ shows game "."- | nPliesEvaluated < 0 = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.Search.Search.mkResult:\tnPliesEvaluated=" . shows nPliesEvaluated . showString " mustn't be negative; " $ 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 "." | otherwise = MkResult { getSearchState = searchState, getQuantifiedGames = quantifiedGames,- getNPliesEvaluated = nPliesEvaluated+ getNPositionsEvaluated = nPositionsEvaluated } where game = Evaluation.QuantifiedGame.getGame . Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame $ Search.SearchState.getPositionHashQuantifiedGameTree searchState@@ -113,30 +114,28 @@ search :: ( Enum x, Enum y,- Eq criterionValue, Ord positionHash, Ord x, Ord y,- Real weightedMean, Show x, Show y )- => Input.SearchOptions.SearchDepth -- ^ How deep down the tree to search.- -> Search.SearchState.SearchState x y positionHash criterionValue weightedMean- -> Input.SearchOptions.Reader (Result x y positionHash criterionValue weightedMean)-{-# SPECIALISE search :: Input.SearchOptions.SearchDepth -> Search.SearchState.SearchState T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean -> Input.SearchOptions.Reader (Result T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean) #-}+ => 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 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 "." | otherwise = do- (maybeRetireKillerMovesAfter, maybeRetireTranspositionsAfter) <- Control.Monad.Reader.asks $ Input.SearchOptions.getMaybeRetireKillerMovesAfter &&& Input.SearchOptions.maybeRetireTranspositionsAfter+ pair <- Control.Monad.Reader.asks $ Input.SearchOptions.getMaybeRetireKillerMovesAfter &&& Input.SearchOptions.maybeRetireTranspositionsAfter let nPlies = State.TurnsByLogicalColour.getNPlies $ Model.Game.getTurnsByLogicalColour game - searchResult <- Search.AlphaBeta.negaMax searchDepth $ Search.EphemeralData.maybeEuthanise nPlies maybeRetireKillerMovesAfter maybeRetireTranspositionsAfter searchState+ searchResult <- Search.AlphaBeta.negaMax searchDepth $ uncurry (Search.EphemeralData.maybeEuthanise nPlies) pair searchState case Search.AlphaBeta.extractSelectedTurns nPlies searchResult of- (dynamicMoveData, turns@(turn : _), nPliesEvaluated) -> let+ (dynamicMoveData, turns@(turn : _), nPositionsEvaluated) -> let isMatch turn' = (== turn') . Evaluation.QuantifiedGame.getLastTurn . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame in return {-to Reader-monad-} $ mkResult ( Search.SearchState.mkSearchState (@@ -148,21 +147,21 @@ map Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame . Data.Maybe.fromMaybe ( Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Search.Search.search:\tEvaluation.PositionHashQuantifiedGameTree.traceRoute failed; " $ shows turns "." ) $ Evaluation.PositionHashQuantifiedGameTree.traceRoute isMatch positionHashQuantifiedGameTree turns- ) nPliesEvaluated+ ) nPositionsEvaluated _ -> Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Search.Search.search:\tzero turns selected." where positionHashQuantifiedGameTree = Search.SearchState.getPositionHashQuantifiedGameTree searchState 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 criterionValue weightedMean -> branchingFactor+calculateBranchingFactor :: Floating branchingFactor => Result x y positionHash -> branchingFactor calculateBranchingFactor MkResult { getQuantifiedGames = quantifiedGames,- getNPliesEvaluated = nPliesEvaluated+ getNPositionsEvaluated = nPositionsEvaluated }- | null quantifiedGames = Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Search.Search.calculateBranchingFactor:\tnull quantifiedGames."- | nPliesEvaluated == 0 = Control.Exception.throw $ Data.Exception.mkOutOfBounds "BishBosh.Search.Search.calculateBranchingFactor:\tzero plies analysed."- | otherwise = fromIntegral nPliesEvaluated ** recip (- fromIntegral $ length quantifiedGames -- The search-depth.+ | null quantifiedGames = Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Search.Search.calculateBranchingFactor:\tnull quantifiedGames."+ | nPositionsEvaluated == 0 = Control.Exception.throw $ Data.Exception.mkOutOfBounds "BishBosh.Search.Search.calculateBranchingFactor:\tzero plies analysed."+ | otherwise = fromIntegral nPositionsEvaluated ** recip (+ fromIntegral {-Int-} $ length quantifiedGames -- The search-depth. )
src-lib/BishBosh/Search/SearchState.hs view
@@ -46,33 +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 criterionValue weightedMean = MkSearchState {- getPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean,+data SearchState x y positionHash = MkSearchState {+ getPositionHashQuantifiedGameTree :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash, getDynamicMoveData :: Search.DynamicMoveData.DynamicMoveData x y positionHash } -instance (- Enum x,- Enum y,- Ord x,- Ord y,- Show x,- Show y,- Show criterionValue,- Show positionHash,- Show weightedMean- ) => Show (SearchState x y positionHash criterionValue weightedMean) where- showsPrec _ _ = showString "SearchState {...}"+instance Show (SearchState x y positionHash) where+ show _ = "SearchState {...}" -- | Constructor. mkSearchState- :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean+ :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> Search.DynamicMoveData.DynamicMoveData x y positionHash- -> SearchState x y positionHash criterionValue weightedMean+ -> SearchState x y positionHash mkSearchState = MkSearchState -- | Smart constructor.-initialise :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash criterionValue weightedMean -> SearchState x y positionHash criterionValue weightedMean+initialise :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree x y positionHash -> SearchState x y 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 {@@ -82,7 +72,7 @@ where game = Evaluation.QuantifiedGame.getGame $ Evaluation.PositionHashQuantifiedGameTree.getRootQuantifiedGame positionHashQuantifiedGameTree -instance Search.EphemeralData.MaybeEphemeralData (SearchState x y positionHash criterionValue weightedMean) where+instance Search.EphemeralData.MaybeEphemeralData (SearchState x y 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/TranspositionValue.hs view
@@ -42,8 +42,9 @@ isBetter ) where -import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Data.Ord @@ -52,15 +53,15 @@ -- | The type of the values in the transposition-table. data TranspositionValue qualifiedMove = MkTranspositionValue {- getIsOptimal :: IsOptimal, -- ^ Whether the recorded move-sequence is known to be optimal.- getNPlies :: Component.Move.NPlies, -- ^ The number of plies applied to the /game/ before application of any of the specified moves.- getQualifiedMoves :: [qualifiedMove] -- ^ The sequence of qualifiedMoves applied to the /game/, which caused the alpha-beta event.+ getIsOptimal :: IsOptimal, -- ^ Whether the recorded move-sequence is known to be optimal.+ getNPlies :: Type.Count.NPlies, -- ^ The number of plies applied to the /game/ before application of any of the specified moves.+ getQualifiedMoves :: [qualifiedMove] -- ^ The sequence of qualifiedMoves applied to the /game/, which caused the alpha-beta event. } deriving Show -- | Smart constructor. mkTranspositionValue :: IsOptimal- -> Component.Move.NPlies+ -> Type.Count.NPlies -> [qualifiedMove] -> TranspositionValue qualifiedMove mkTranspositionValue _ _ [] = Control.Exception.throw $ Data.Exception.mkNullDatum "BishBosh.Search.TranspositionValue.mkTranspositionValue:\tnull list of qualifiedMoves."@@ -73,15 +74,15 @@ } -- | Infer the search-depth from the length of the qualifiedMove-sequence.-inferSearchDepth :: TranspositionValue qualifiedMove -> Component.Move.NPlies-inferSearchDepth = length . getQualifiedMoves+inferSearchDepth :: TranspositionValue qualifiedMove -> Type.Count.NPlies+inferSearchDepth = fromIntegral . length . getQualifiedMoves {- | * The type of a function which can find the fitness of the game resulting from the recorded sequence of qualifiedMoves. * CAVEAT: the fitness this function returns should be from the perspective of the player to make the first move. -}-type FindFitness qualifiedMove weightedMean = TranspositionValue qualifiedMove -> weightedMean+type FindFitness qualifiedMove = TranspositionValue qualifiedMove -> Type.Mass.WeightedMean {- | * Whether a proposed value is better than the incumbent.@@ -89,8 +90,7 @@ * CAVEAT: this is a narrower concept than addressed by 'Ord', which implies 'Eq'. -} isBetter- :: Ord weightedMean- => FindFitness qualifiedMove weightedMean+ :: FindFitness qualifiedMove -> TranspositionValue qualifiedMove -- ^ The proposed value. -> TranspositionValue qualifiedMove -- ^ The incumbent value. -> Bool
src-lib/BishBosh/Search/Transpositions.hs view
@@ -75,8 +75,8 @@ * If a matching key already exists, it's replaced if the new value is considered to be better. -} insert- :: (Ord positionHash, Ord weightedMean)- => Search.TranspositionValue.FindFitness qualifiedMove weightedMean+ :: Ord positionHash+ => Search.TranspositionValue.FindFitness qualifiedMove -> positionHash -- ^ Represents the game from which the sequence of qualifiedMoves starts. -> Search.TranspositionValue.TranspositionValue qualifiedMove -- ^ The value to record. -> Transformation qualifiedMove positionHash
src-lib/BishBosh/State/Board.hs view
@@ -39,7 +39,6 @@ -- ** Type-synonyms -- Transformation, -- NDefendersByCoordinatesByLogicalColour,- NBoards, -- ** Data-types Board( -- MkBoard,@@ -66,7 +65,7 @@ exposesKing ) 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@@ -90,7 +89,9 @@ import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified BishBosh.StateProperty.Mutator as StateProperty.Mutator import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker-import qualified BishBosh.Types as T+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@@ -109,10 +110,7 @@ type Transformation x y = Board x y -> Board x y -- | 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) Component.Piece.NPieces)---- | A number of boards.-type NBoards = Int+type NDefendersByCoordinatesByLogicalColour x y = Attribute.LogicalColour.ArrayByLogicalColour (Data.Map.Strict.Map (Cartesian.Coordinates.Coordinates x y) Type.Count.NPieces) {- | * The board is modelled as two alternative structures representing the same data, but indexed by either /coordinates/ or /piece/.@@ -120,13 +118,13 @@ * 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/.- 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/.- getNPieces :: Component.Piece.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.+ 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/.+ 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/.+ 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. } instance (@@ -145,9 +143,7 @@ getMaybePieceByCoordinates = maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour, getNDefendersByCoordinatesByLogicalColour = nDefendersByCoordinatesByLogicalColour,-#ifndef USE_UNBOXED_ARRAYS getNPiecesDifferenceByRank = nPiecesDifferenceByRank,-#endif getNPawnsByFileByLogicalColour = nPawnsByFileByLogicalColour, getNPieces = nPieces, getPassedPawnCoordinatesByLogicalColour = passedPawnCoordinatesByLogicalColour@@ -155,9 +151,7 @@ maybePieceByCoordinates, coordinatesByRankByLogicalColour, nDefendersByCoordinatesByLogicalColour,-#ifndef USE_UNBOXED_ARRAYS nPiecesDifferenceByRank,-#endif nPawnsByFileByLogicalColour, nPieces, passedPawnCoordinatesByLogicalColour@@ -169,7 +163,7 @@ Ord x, Ord y ) => Read (Board x y) where- {-# SPECIALISE instance Read (Board T.X T.Y) #-}+ {-# SPECIALISE instance Read (Board Type.Length.X Type.Length.Y) #-} readsPrec _ = Property.ForsythEdwards.readsFEN instance (@@ -186,7 +180,7 @@ Ord x, Ord y ) => Property.ExtendedPositionDescription.ReadsEPD (Board x y) where- {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Board T.X T.Y) #-}+ {-# SPECIALISE instance Property.ExtendedPositionDescription.ReadsEPD (Board Type.Length.X Type.Length.Y) #-} readsEPD = map (Control.Arrow.first fromMaybePieceByCoordinates) . Property.ExtendedPositionDescription.readsEPD instance (@@ -203,7 +197,7 @@ Ord x, Ord y ) => Property.ForsythEdwards.ReadsFEN (Board x y) where- {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Board T.X T.Y) #-}+ {-# SPECIALISE instance Property.ForsythEdwards.ReadsFEN (Board Type.Length.X Type.Length.Y) #-} readsFEN = Property.ExtendedPositionDescription.readsEPD instance (@@ -219,7 +213,7 @@ Ord x, Ord y ) => Data.Default.Default (Board x y) where- {-# SPECIALISE instance Data.Default.Default (Board T.X T.Y) #-}+ {-# SPECIALISE instance Data.Default.Default (Board Type.Length.X Type.Length.Y) #-} def = fromMaybePieceByCoordinates Data.Default.def {-MaybePieceByCoordinates-} instance (@@ -228,7 +222,7 @@ Ord x, Ord y ) => Property.Reflectable.ReflectableOnX (Board x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Board T.X T.Y) #-}+ {-# SPECIALISE instance Property.Reflectable.ReflectableOnX (Board Type.Length.X Type.Length.Y) #-} reflectOnX MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ Property.Reflectable.reflectOnX maybePieceByCoordinates instance (@@ -237,7 +231,7 @@ Ord x, Ord y ) => Property.Reflectable.ReflectableOnY (Board x y) where- {-# SPECIALISE instance Property.Reflectable.ReflectableOnY (Board T.X T.Y) #-}+ {-# SPECIALISE instance Property.Reflectable.ReflectableOnY (Board Type.Length.X Type.Length.Y) #-} reflectOnY MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = fromMaybePieceByCoordinates $ Property.Reflectable.reflectOnY maybePieceByCoordinates instance (@@ -246,7 +240,7 @@ Ord x, Ord y ) => Property.Empty.Empty (Board x y) where- {-# SPECIALISE empty :: Board T.X T.Y #-}+ {-# SPECIALISE empty :: Board Type.Length.X Type.Length.Y #-} empty = fromMaybePieceByCoordinates Property.Empty.empty {-MaybePieceByCoordinates-} instance (Enum x, Enum y, Ord x, Ord y) => Component.Zobrist.Hashable2D Board x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where@@ -258,7 +252,7 @@ Ord x, Ord y ) => StateProperty.Seeker.Seeker Board x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker Board T.X T.Y #-}+ {-# SPECIALISE instance StateProperty.Seeker.Seeker Board Type.Length.X Type.Length.Y #-} 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. @@ -268,7 +262,7 @@ Ord x, Ord y ) => StateProperty.Mutator.Mutator Board x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Mutator.Mutator Board T.X T.Y #-}+ {-# 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 -- | Constructor.@@ -278,15 +272,15 @@ Ord x, Ord y ) => State.MaybePieceByCoordinates.MaybePieceByCoordinates x y -> Board x y-{-# SPECIALISE fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates T.X T.Y -> Board T.X T.Y #-}+{-# SPECIALISE fromMaybePieceByCoordinates :: State.MaybePieceByCoordinates.MaybePieceByCoordinates Type.Length.X Type.Length.Y -> Board Type.Length.X Type.Length.Y #-} 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.+ getNPiecesDifferenceByRank = StateProperty.Censor.countPieceDifferenceByRank coordinatesByRankByLogicalColour, -- Infer. getNPawnsByFileByLogicalColour = State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour, -- Infer.- getNPieces = StateProperty.Censor.countPieces coordinatesByRankByLogicalColour, -- Infer.+ getNPieces = StateProperty.Censor.countPieces coordinatesByRankByLogicalColour, -- Infer. getPassedPawnCoordinatesByLogicalColour = State.CoordinatesByRankByLogicalColour.findPassedPawnCoordinatesByLogicalColour coordinatesByRankByLogicalColour -- Infer. } @@ -308,7 +302,7 @@ => Component.Move.Move x y -- ^ 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 T.X T.Y -> Maybe Attribute.MoveType.MoveType -> Transformation T.X T.Y #-}+{-# SPECIALISE movePiece :: Component.Move.Move Type.Length.X Type.Length.Y -> Maybe Attribute.MoveType.MoveType -> Transformation Type.Length.X Type.Length.Y #-} movePiece move maybeMoveType board@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour,@@ -342,7 +336,7 @@ board'@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates' } = MkBoard { getMaybePieceByCoordinates = State.MaybePieceByCoordinates.movePiece move destinationPiece (- either Just (const Nothing) eitherPassingPawnsDestinationOrMaybeTakenRank+ Just ||| const Nothing $ eitherPassingPawnsDestinationOrMaybeTakenRank ) maybePieceByCoordinates, getCoordinatesByRankByLogicalColour = State.CoordinatesByRankByLogicalColour.movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank coordinatesByRankByLogicalColour, getNDefendersByCoordinatesByLogicalColour = let@@ -361,26 +355,26 @@ if Attribute.LogicalColour.isBlack logicalColour' then Control.Arrow.first else Control.Arrow.second- ) . Data.Map.Strict.insert affectedCoordinates {-overwrite-} . length $ findAttackersOf (+ ) . Data.Map.Strict.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' ) ( (! Attribute.LogicalColour.Black) &&& (! Attribute.LogicalColour.White) $ nDefendersByCoordinatesByLogicalColour // ( let nDefendersByCoordinates = nDefendersByCoordinatesByLogicalColour ! opponentsLogicalColour- in either (+ in ( \passingPawnsDestination -> (:) ( opponentsLogicalColour, Data.Map.Strict.delete passingPawnsDestination nDefendersByCoordinates -- This Pawn has been taken. )- ) (+ ) ||| ( \maybeExplicitlyTakenRank -> if Data.Maybe.isJust maybeExplicitlyTakenRank then (:) ( opponentsLogicalColour, Data.Map.Strict.delete destination nDefendersByCoordinates -- This piece has been taken. ) else id- ) eitherPassingPawnsDestinationOrMaybeTakenRank+ ) $ eitherPassingPawnsDestinationOrMaybeTakenRank ) [ ( logicalColour,@@ -398,7 +392,7 @@ Component.Piece.isFriend knight affectedPiece ] {-list-comprehension-} ++ [ (blockingCoordinates, blockingPiece) |- passingPawnsDestination <- either return {-to List-monad-} (const []) eitherPassingPawnsDestinationOrMaybeTakenRank,+ passingPawnsDestination <- return {-to List-monad-} ||| const [] $ eitherPassingPawnsDestinationOrMaybeTakenRank, (direction, antiParallelDirection) <- Attribute.Direction.opposites, (blockingCoordinates, blockingPiece) <- case ($ direction) &&& ($ antiParallelDirection) $ ($ maybePieceByCoordinates') . (`State.MaybePieceByCoordinates.findBlockingPiece` passingPawnsDestination) of (Just cp, Just cp') -> [@@ -421,7 +415,7 @@ _ -> [] ] {-list-comprehension-} ++ (destination, destinationPiece) : [ (blockingCoordinates, blockingPiece) |- let maybeExplicitlyTakenPiece = either (const Nothing) id eitherPassingPawnsDestinationOrMaybeTakenPiece,+ let maybeExplicitlyTakenPiece = const Nothing ||| id $ eitherPassingPawnsDestinationOrMaybeTakenPiece, (direction, antiParallelDirection) <- Attribute.Direction.opposites, (coordinates, piece) <- [(source, sourcePiece), (destination, destinationPiece)], (blockingCoordinates, blockingPiece) <- case ($ direction) &&& ($ antiParallelDirection) $ ($ maybePieceByCoordinates') . (`State.MaybePieceByCoordinates.findBlockingPiece` coordinates) of@@ -467,12 +461,12 @@ ) ] ) maybePromotionRank,- getNPawnsByFileByLogicalColour = if Component.Piece.isPawn sourcePiece && (+ 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' else getNPawnsByFileByLogicalColour board,- getNPieces = Attribute.MoveType.nPiecesMutator moveType nPieces,+ 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' else getPassedPawnCoordinatesByLogicalColour board@@ -505,15 +499,15 @@ #endif pieceSquareValue {-# SPECIALISE sumPieceSquareValueByLogicalColour- :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank T.X T.Y T.PieceSquareValue- -> Board T.X T.Y+ :: Component.PieceSquareByCoordinatesByRank.PieceSquareByCoordinatesByRank Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue+ -> Board Type.Length.X Type.Length.Y -> #ifdef USE_UNBOXED_ARRAYS Attribute.LogicalColour.UArrayByLogicalColour #else Attribute.LogicalColour.ArrayByLogicalColour #endif- T.PieceSquareValue+ Type.Mass.PieceSquareValue #-} sumPieceSquareValueByLogicalColour pieceSquareByCoordinatesByRank MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour,@@ -543,7 +537,7 @@ -> 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 T.X T.Y -> Board T.X T.Y -> [(Cartesian.Coordinates.Coordinates T.X T.Y, Attribute.Rank.Rank)] #-}+{-# 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 destinationLogicalColour destination board@MkBoard { getMaybePieceByCoordinates = maybePieceByCoordinates } = [ (coordinates, Attribute.Rank.Knight) | coordinates <- StateProperty.Seeker.findProximateKnights (Property.Opposable.getOpposite destinationLogicalColour) destination board@@ -568,7 +562,7 @@ -> 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 T.X T.Y -> Board T.X T.Y -> [Cartesian.Coordinates.Coordinates T.X T.Y] #-}+{-# 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 piece destination board | rank == Attribute.Rank.Knight = StateProperty.Seeker.findProximateKnights logicalColour destination board | otherwise = filter (@@ -593,7 +587,7 @@ => Attribute.LogicalColour.LogicalColour -- ^ The /logical colour/ of the @King@ in question. -> Board x y -> Bool-{-# SPECIALISE isKingChecked :: Attribute.LogicalColour.LogicalColour -> Board T.X T.Y -> 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 {- |@@ -613,7 +607,7 @@ -> Component.Move.Move x y -- ^ The /move/. -> Board x y -- ^ The original /board/, i.e. prior to the /move/. -> Bool-{-# SPECIALISE exposesKing :: Attribute.LogicalColour.LogicalColour -> Component.Move.Move T.X T.Y -> Board T.X T.Y -> 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 (@@ -640,22 +634,22 @@ Ord x, Ord y ) => Board x y -> NDefendersByCoordinatesByLogicalColour x y-{-# SPECIALISE countDefendersByCoordinatesByLogicalColour :: Board T.X T.Y -> NDefendersByCoordinatesByLogicalColour T.X T.Y #-}+{-# SPECIALISE countDefendersByCoordinatesByLogicalColour :: Board Type.Length.X Type.Length.Y -> NDefendersByCoordinatesByLogicalColour Type.Length.X Type.Length.Y #-} countDefendersByCoordinatesByLogicalColour board@MkBoard { getCoordinatesByRankByLogicalColour = coordinatesByRankByLogicalColour } = Attribute.LogicalColour.listArrayByLogicalColour [ Data.Map.Strict.fromList [ ( coordinates,- length $ findAttackersOf (+ fromIntegral . length $ findAttackersOf ( Property.Opposable.getOpposite logicalColour -- Investigate an attack on these coordinates by one's own logical colour. ) coordinates board ) |- rank <- Attribute.Rank.expendable,+ rank <- Attribute.Rank.expendable, -- CAVEAT: there's no point defending one's own King. coordinates <- State.CoordinatesByRankByLogicalColour.dereference logicalColour rank coordinatesByRankByLogicalColour ] {-list-comprehension-} | logicalColour <- Property.FixedMembership.members ] -- List-comprehension. -- | Collapses 'NDefendersByCoordinatesByLogicalColour' into the total number of defenders on either side.-summariseNDefendersByLogicalColour :: Board x y -> Attribute.LogicalColour.ArrayByLogicalColour Component.Piece.NPieces+summariseNDefendersByLogicalColour :: Board x y -> 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. ) nDefendersByCoordinatesByLogicalColour
src-lib/BishBosh/State/CastleableRooksByLogicalColour.hs view
@@ -76,7 +76,7 @@ import qualified BishBosh.State.Board as State.Board import qualified BishBosh.State.CoordinatesByRankByLogicalColour as State.CoordinatesByRankByLogicalColour import qualified BishBosh.State.TurnsByLogicalColour as State.TurnsByLogicalColour-import qualified BishBosh.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -136,7 +136,7 @@ } deriving (Eq, Ord) instance Show x => Show (CastleableRooksByLogicalColour x) where- showsPrec _ MkCastleableRooksByLogicalColour { getAssocs = assocs } = shows assocs+ showsPrec precedence MkCastleableRooksByLogicalColour { getAssocs = assocs } = showsPrec precedence assocs instance ( Enum x,@@ -144,7 +144,7 @@ Read x, Show x ) => Read (CastleableRooksByLogicalColour x) where- readsPrec _ s = Control.Arrow.first fromAssocs `map` reads s+ readsPrec precedence s = Control.Arrow.first fromAssocs `map` readsPrec precedence s instance Control.DeepSeq.NFData x => Control.DeepSeq.NFData (CastleableRooksByLogicalColour x) where rnf MkCastleableRooksByLogicalColour { getAssocs = assocs } = Control.DeepSeq.rnf assocs@@ -372,7 +372,7 @@ => 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 T.X T.Y -> Transformation T.X #-}+{-# SPECIALISE takeTurn :: Attribute.LogicalColour.LogicalColour -> Component.Turn.Turn Type.Length.X Type.Length.Y -> Transformation Type.Length.X #-} takeTurn logicalColour turn MkCastleableRooksByLogicalColour { getAssocs = assocs } = MkCastleableRooksByLogicalColour $ ( case lookup logicalColour assocs of Just [] -> id -- This is a terminal state.
src-lib/BishBosh/State/CoordinatesByRankByLogicalColour.hs view
@@ -57,7 +57,7 @@ sortCoordinates ) 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@@ -74,7 +74,9 @@ import qualified BishBosh.State.MaybePieceByCoordinates as State.MaybePieceByCoordinates import qualified BishBosh.StateProperty.Censor as StateProperty.Censor import qualified BishBosh.StateProperty.Seeker as StateProperty.Seeker-import qualified BishBosh.Types as T+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@@ -103,17 +105,17 @@ rnf MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Control.DeepSeq.rnf byLogicalColour instance (Enum x, Enum y) => StateProperty.Censor.Censor (CoordinatesByRankByLogicalColour x y) where- countPiecesByLogicalColour MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = ($ Attribute.LogicalColour.Black) &&& ($ Attribute.LogicalColour.White) $ Data.List.foldl' (\acc -> (+ acc) . length) 0 . (byLogicalColour !)+ 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' (- Data.List.foldl' $ \acc -> (+ acc) . length+ Data.List.foldl' $ \acc -> (+ acc) . fromIntegral . length ) 0 byLogicalColour countPieceDifferenceByRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Attribute.Rank.listArrayByRank . uncurry ( zipWith (-) ) . ( ($ Attribute.LogicalColour.White) &&& ($ Attribute.LogicalColour.Black)- ) $ map length . Data.Array.IArray.elems . (byLogicalColour !)+ ) $ map (fromIntegral . length) . Data.Array.IArray.elems . (byLogicalColour !) hasInsufficientMaterial MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = Data.Foldable.all ( \byRank -> all (@@ -153,7 +155,7 @@ Ord x, Ord y ) => StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour T.X T.Y #-}+ {-# SPECIALISE instance StateProperty.Seeker.Seeker CoordinatesByRankByLogicalColour Type.Length.X Type.Length.Y #-} 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@@ -223,7 +225,7 @@ 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 Component.Piece.NPieces)+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.@@ -288,7 +290,7 @@ => Component.PieceSquareByCoordinatesByRank.FindPieceSquareValues x y pieceSquareValue -> CoordinatesByRankByLogicalColour x y -> [pieceSquareValue]-{-# SPECIALISE sumPieceSquareValueByLogicalColour :: Component.PieceSquareByCoordinatesByRank.FindPieceSquareValues T.X T.Y T.PieceSquareValue -> CoordinatesByRankByLogicalColour T.X T.Y -> [T.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)@@ -315,11 +317,11 @@ -> 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-movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ byLogicalColour // either (- (:) . (`deleteOpponentsCoordinates` Attribute.Rank.Pawn)- ) (- Data.Maybe.maybe id {-quiet move-} $ (:) . deleteOpponentsCoordinates destination- ) eitherPassingPawnsDestinationOrMaybeTakenRank [+movePiece move sourcePiece maybePromotionRank eitherPassingPawnsDestinationOrMaybeTakenRank MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ byLogicalColour // (+ (:) . (`deleteOpponentsCoordinates` Attribute.Rank.Pawn) ||| Data.Maybe.maybe id {-quiet move-} (+ (:) . deleteOpponentsCoordinates destination+ ) $ eitherPassingPawnsDestinationOrMaybeTakenRank+ ) [ let byRank = byLogicalColour ! logicalColour in (@@ -343,3 +345,4 @@ -- | Independently sort each list of /coordinates/. sortCoordinates :: (Ord x, Ord y) => Transformation x y sortCoordinates MkCoordinatesByRankByLogicalColour { deconstruct = byLogicalColour } = MkCoordinatesByRankByLogicalColour $ Data.Array.IArray.amap (Data.Array.IArray.amap Data.List.sort) byLogicalColour+
src-lib/BishBosh/State/EnPassantAbscissa.hs view
@@ -43,7 +43,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Data.Array.IArray import qualified Data.Maybe@@ -70,7 +70,7 @@ -> 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 T.X T.Y -> Component.Turn.Turn T.X T.Y -> Maybe (EnPassantAbscissa T.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 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,6 @@ module BishBosh.State.InstancesByPosition( -- * Types -- ** Type-synonyms--- NBoardsByPosition, -- Transformation. -- * Constants leastCyclicPlies,@@ -46,49 +45,43 @@ anyInstancesByPosition ) where -import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.State.Board as State.Board+import qualified BishBosh.Type.Count as Type.Count import qualified Control.DeepSeq import qualified Control.Exception import qualified Data.Foldable import qualified Data.Map.Strict --- | The smallest number of repeatable plies required to form a cycle.-leastCyclicPlies :: Component.Move.NPlies+-- | The smallest number of repeatable plies (applied by alternating players) required to form a cycle.+leastCyclicPlies :: Type.Count.NPlies leastCyclicPlies = 4 {- |- * The number of times each /position/ has been encountered.-- * The /position/ can either be represented by a physical 'State.Position.Position', or by proxy using a hash.--}-type NBoardsByPosition position = Data.Map.Strict.Map position State.Board.NBoards--{- | * A count of the number of instances of /position/s which have occurred. * N.B.: a number greater than @1@ represents repetition.++ * The /position/ can either be represented by a physical 'State.Position.Position', or by proxy using a hash. -} newtype InstancesByPosition position = MkInstancesByPosition {- getNBoardsByPosition :: NBoardsByPosition position+ getNPositionsByPosition :: Data.Map.Strict.Map position Type.Count.NPositions } deriving Eq instance Control.DeepSeq.NFData position => Control.DeepSeq.NFData (InstancesByPosition position) where- rnf MkInstancesByPosition { getNBoardsByPosition = m } = Control.DeepSeq.rnf m+ rnf MkInstancesByPosition { getNPositionsByPosition = m } = Control.DeepSeq.rnf m instance ( Ord position, Property.Reflectable.ReflectableOnX position ) => Property.Reflectable.ReflectableOnX (InstancesByPosition position) where- reflectOnX MkInstancesByPosition { getNBoardsByPosition = m } = MkInstancesByPosition $ Data.Map.Strict.mapKeys Property.Reflectable.reflectOnX m+ reflectOnX MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition $ Data.Map.Strict.mapKeys Property.Reflectable.reflectOnX m -- | Smart constructor.-mkInstancesByPosition :: NBoardsByPosition position -> InstancesByPosition position-mkInstancesByPosition nBoardsByPosition- | Data.Foldable.any (< 1) nBoardsByPosition = Control.Exception.throw $ Data.Exception.mkOutOfBounds "BishBosh.State.InstancesByPosition.mkInstancesByPosition:\teach specified position must have been visited at least once."- | otherwise = MkInstancesByPosition nBoardsByPosition+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 -- | Constructor. mkSingleton :: position -> InstancesByPosition position@@ -99,35 +92,35 @@ * This is equivalent to the number of entries in the map, since adding a non-repeatable move triggers a purge. -}-countConsecutiveRepeatablePlies :: InstancesByPosition position -> Component.Move.NPlies-countConsecutiveRepeatablePlies MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.Strict.foldl' (+) (+countConsecutiveRepeatablePlies :: InstancesByPosition position -> Type.Count.NPlies+countConsecutiveRepeatablePlies MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Map.Strict.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 -> State.Board.NBoards-countPositionRepetitions MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.Strict.foldl' (+countPositionRepetitions :: InstancesByPosition position -> Type.Count.NPositions+countPositionRepetitions MkInstancesByPosition { getNPositionsByPosition = m } = Data.Map.Strict.foldl' ( (+) . pred -- The initial instance isn't a repetition. ) 0 m -- | The number of distinct /position/s.-getNDistinctPositions :: InstancesByPosition position -> State.Board.NBoards-getNDistinctPositions MkInstancesByPosition { getNBoardsByPosition = m } = Data.Map.Strict.size m+getNDistinctPositions :: InstancesByPosition position -> Type.Count.NPositions+getNDistinctPositions MkInstancesByPosition { getNPositionsByPosition = m } = fromIntegral $ Data.Map.Strict.size m {-the number of keys-} -- | Predicate: apply the specified predicate to the map. anyInstancesByPosition- :: (State.Board.NBoards -> Bool)+ :: (Type.Count.NPositions -> Bool) -> InstancesByPosition position -> Bool-anyInstancesByPosition predicate MkInstancesByPosition { getNBoardsByPosition = m } = Data.Foldable.any predicate m+anyInstancesByPosition predicate MkInstancesByPosition { getNPositionsByPosition = m } = Data.Foldable.any predicate m {- | * Find the maximum number of times any one position has already been visited. * CAVEAT: only those positions that can still be reached are considered. -}-findMaximumInstances :: InstancesByPosition position -> State.Board.NBoards-findMaximumInstances MkInstancesByPosition { getNBoardsByPosition = m }+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 @@ -140,14 +133,15 @@ => Bool -- ^ Whether the /turn/ which led to the specified /position/, was repeatable. -> position -> Transformation position-insertPosition isRepeatable position MkInstancesByPosition { getNBoardsByPosition = m }+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. -- | Remove a /position/ from the collection, as required to implement rollback. deletePosition :: Ord position => position -> Transformation position-deletePosition position MkInstancesByPosition { getNBoardsByPosition = m } = MkInstancesByPosition . Data.Map.Strict.update (+deletePosition position MkInstancesByPosition { getNPositionsByPosition = m } = MkInstancesByPosition . Data.Map.Strict.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+
src-lib/BishBosh/State/MaybePieceByCoordinates.hs view
@@ -62,6 +62,7 @@ import Control.Applicative((<|>)) import Control.Arrow((&&&), (***))+import Control.Category((>>>)) import Data.Array.IArray((!), (//)) import qualified BishBosh.Attribute.ColourScheme as Attribute.ColourScheme import qualified BishBosh.Attribute.Direction as Attribute.Direction@@ -90,7 +91,8 @@ 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.Types as T+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@@ -168,7 +170,7 @@ Ord y ) => Property.ExtendedPositionDescription.ShowsEPD (MaybePieceByCoordinates x y) where showsEPD MkMaybePieceByCoordinates { deconstruct = byCoordinates } = foldr1 (- flip (.) -- Render the line with the highest y-coordinate first.+ >>> -- Render the line with the highest y-coordinate first. ) . Data.List.intersperse ( showChar rankSeparator -- Separate the lines. ) . map (@@ -263,7 +265,7 @@ in nBlack `seq` nWhite `seq` acc' ) (0, 0) . getPieces - countPieces = length . getPieces+ countPieces = fromIntegral . length . getPieces countPieceDifferenceByRank = Data.Array.IArray.accumArray (+) 0 (minBound, maxBound) . map ( Component.Piece.getRank &&& (@@ -300,7 +302,12 @@ ([_], [_]) -> True _ -> False -instance (Enum x, Enum y, Ord x, Ord y) => Component.Zobrist.Hashable2D MaybePieceByCoordinates x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where+instance (+ Enum x,+ Enum y,+ Ord x,+ Ord y+ ) => Component.Zobrist.Hashable2D MaybePieceByCoordinates x y {-CAVEAT: FlexibleInstances, MultiParamTypeClasses-} where listRandoms2D 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@@ -319,7 +326,7 @@ Ord x, Ord y ) => StateProperty.Seeker.Seeker MaybePieceByCoordinates x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Seeker.Seeker MaybePieceByCoordinates T.X T.Y #-}+ {-# SPECIALISE instance StateProperty.Seeker.Seeker MaybePieceByCoordinates Type.Length.X Type.Length.Y #-} findProximateKnights logicalColour destination MkMaybePieceByCoordinates { deconstruct = byCoordinates } = filter ( (== Just knight) . (byCoordinates !) ) $ Component.Piece.findAttackDestinations destination knight where@@ -337,7 +344,7 @@ Ord x, Ord y ) => StateProperty.Mutator.Mutator MaybePieceByCoordinates x y {-CAVEAT: MultiParamTypeClasses-} where- {-# SPECIALISE instance StateProperty.Mutator.Mutator MaybePieceByCoordinates T.X T.Y #-}+ {-# 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)]@@ -368,7 +375,7 @@ -> Maybe Attribute.Rank.Rank -- ^ The /rank/ to which a @Pawn@ should be promoted; defaulting to @Queen@. -> MaybePieceByCoordinates x y -> Attribute.MoveType.MoveType-{-# SPECIALISE inferMoveType :: Component.Move.Move T.X T.Y -> Maybe Attribute.Rank.Rank -> MaybePieceByCoordinates T.X T.Y -> 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@@ -410,7 +417,7 @@ -> 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 T.X T.Y -> Component.Piece.Piece -> MaybePieceByCoordinates T.X T.Y -> [(Cartesian.Coordinates.Coordinates T.X T.Y, Maybe Attribute.Rank.Rank)] #-}+{-# 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)] #-} listDestinationsFor source piece maybePieceByCoordinates@MkMaybePieceByCoordinates { deconstruct = byCoordinates } = Control.Exception.assert ( byCoordinates ! source == Just piece ) $ if Component.Piece.getRank piece `elem` Attribute.Rank.fixedAttackRange@@ -460,13 +467,12 @@ -- | Show the /board/ in two dimensions, with /x/ & /y/ indexes. shows2D :: (- Enum x,- Enum y,- Integral column,- Ord x,- Ord y+ Enum x,+ Enum y,+ Ord x,+ Ord y )- => column -- ^ The column-magnification.+ => Type.Length.Column -- ^ The column-magnification. -> Attribute.ColourScheme.ColourScheme -> (Int, Int) -- ^ The origin from which axes are labelled. -> MaybePieceByCoordinates x y@@ -513,13 +519,12 @@ -- | Show the board using a two-dimensional representation. show2D :: (- Enum x,- Enum y,- Integral column,- Ord x,- Ord y+ Enum x,+ Enum y,+ Ord x,+ Ord y )- => column -- ^ The column-magnification.+ => Type.Length.Column -- ^ The column-magnification. -> Attribute.ColourScheme.ColourScheme -> (Int, Int) -- ^ The origin from which axes are labelled. -> MaybePieceByCoordinates x y@@ -550,7 +555,7 @@ -> 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 T.X T.Y -> MaybePieceByCoordinates T.X T.Y -> Maybe (Component.Piece.LocatedPiece T.X T.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 !))@@ -590,7 +595,7 @@ -> 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 T.X T.Y -> MaybePieceByCoordinates T.X T.Y -> Maybe (Cartesian.Coordinates.Coordinates T.X T.Y, Attribute.Rank.Rank) #-}+{-# 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) #-} 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)@@ -641,7 +646,7 @@ -> MaybePieceByCoordinates x y -> Bool {-# INLINABLE isClear #-} -- N.B.: required to ensure specialisation of 'Cartesian.Coordinates.interpolate'.-{-# SPECIALISE isClear :: Cartesian.Coordinates.Coordinates T.X T.Y -> Cartesian.Coordinates.Coordinates T.X T.Y -> MaybePieceByCoordinates T.X T.Y -> Bool #-}+{-# 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@@ -657,7 +662,7 @@ -> Cartesian.Coordinates.Coordinates x y -- ^ Destination. -> MaybePieceByCoordinates x y -> Bool-{-# SPECIALISE isObstructed :: Cartesian.Coordinates.Coordinates T.X T.Y -> Cartesian.Coordinates.Coordinates T.X T.Y -> MaybePieceByCoordinates T.X T.Y -> 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 {- |@@ -675,7 +680,7 @@ => Component.Move.Move x y -> MaybePieceByCoordinates x y -> Bool-{-# SPECIALISE isEnPassantMove :: Component.Move.Move T.X T.Y -> MaybePieceByCoordinates T.X T.Y -> 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@@ -702,7 +707,7 @@ -> 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 T.X T.Y -> Component.Piece.Piece -> Maybe (Cartesian.Coordinates.Coordinates T.X T.Y) -> Transformation T.X T.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 move destinationPiece maybeEnPassantDestination MkMaybePieceByCoordinates { deconstruct = byCoordinates } = MkMaybePieceByCoordinates $ byCoordinates // Data.Maybe.maybe id ( (:) . flip (,) Nothing -- Take the Pawn en-passant. ) maybeEnPassantDestination [@@ -726,7 +731,7 @@ => Component.PieceSquareByCoordinatesByRank.FindPieceSquareValue x y pieceSquareValue -> MaybePieceByCoordinates x y -> [pieceSquareValue]-{-# SPECIALISE sumPieceSquareValueByLogicalColour :: Component.PieceSquareByCoordinatesByRank.FindPieceSquareValue T.X T.Y T.PieceSquareValue -> MaybePieceByCoordinates T.X T.Y -> [T.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' (
src-lib/BishBosh/State/Position.hs view
@@ -52,7 +52,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.DeepSeq import qualified Data.Array.IArray import qualified Data.Maybe@@ -71,7 +71,7 @@ Ord x, Ord y ) => Ord (Position x y) where- {-# SPECIALISE instance Ord (Position T.X T.Y) #-}+ {-# SPECIALISE instance Ord (Position Type.Length.X Type.Length.Y) #-} position@MkPosition { getNextLogicalColour = nextLogicalColour, getMaybePieceByCoordinates = maybePieceByCoordinates@@ -143,7 +143,7 @@ -> 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 T.X T.Y -> State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour T.X -> Maybe (Component.Turn.Turn T.X T.Y) -> Position T.X T.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 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/State/TurnsByLogicalColour.hs view
@@ -46,12 +46,12 @@ import Control.Arrow((&&&), (***)) import Data.Array.IArray((!), (//)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Property.Null as Property.Null import qualified BishBosh.Property.Opposable as Property.Opposable import qualified BishBosh.Property.Reflectable as Property.Reflectable+import qualified BishBosh.Type.Count as Type.Count import qualified Control.Arrow import qualified Control.DeepSeq import qualified Control.Exception@@ -63,17 +63,17 @@ -- | The type used to hold a record of each player's /turn/s. data TurnsByLogicalColour turn = MkTurnsByLogicalColour { getTurnsByLogicalColour :: Attribute.LogicalColour.ArrayByLogicalColour [turn],- getNPlies :: Component.Move.NPlies -- ^ The number of plies applied to the game; this could alternatively be derived using 'countPlies'.+ getNPlies :: Type.Count.NPlies -- ^ The total number of plies applied to the game for both players; this could alternatively be derived using 'countPlies'. } instance Eq turn => Eq (TurnsByLogicalColour turn) where MkTurnsByLogicalColour { getTurnsByLogicalColour = aL } == MkTurnsByLogicalColour { getTurnsByLogicalColour = aR } = aL == aR instance (Read turn, Show turn) => Read (TurnsByLogicalColour turn) where- readsPrec _ s = Control.Arrow.first fromAssocs `map` reads s+ readsPrec precedence s = Control.Arrow.first fromAssocs `map` readsPrec precedence s instance Show turn => Show (TurnsByLogicalColour turn) where- showsPrec _ MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = shows $ Data.Array.IArray.assocs byLogicalColour+ showsPrec precedence MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = showsPrec precedence $ Data.Array.IArray.assocs byLogicalColour instance Control.DeepSeq.NFData turn => Control.DeepSeq.NFData (TurnsByLogicalColour turn) where rnf MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = Control.DeepSeq.rnf byLogicalColour@@ -101,7 +101,9 @@ -- | Smart constructor. fromAssocs :: Show turn => [(Attribute.LogicalColour.LogicalColour, [turn])] -> TurnsByLogicalColour turn fromAssocs assocs- | length assocs /= Attribute.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tboth logical colours must be defined; " $ shows assocs "."+ | fromIntegral (+ length assocs+ ) /= Attribute.LogicalColour.nDistinctLogicalColours = Control.Exception.throw . Data.Exception.mkInsufficientData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tboth logical colours must be defined; " $ shows assocs "." | Data.List.Extra.anySame $ map fst {-logicalColour-} assocs = Control.Exception.throw . Data.Exception.mkDuplicateData . showString "BishBosh.State.TurnsByLogicalColour.fromAssocs:\tduplicates specified; " $ shows assocs "." | (> 1) . abs {-allow for Property.Reflectable.reflectOnX-} . uncurry (-) $ ( length . (! Attribute.LogicalColour.White) &&& length . (! Attribute.LogicalColour.Black)@@ -125,12 +127,12 @@ | otherwise = Attribute.LogicalColour.Black {- |- * Count the number of plies.+ * Count the total number of plies, regardless of the player. * CAVEAT: 'getNPlies' is more efficient. -}-countPlies :: TurnsByLogicalColour turn -> Component.Move.NPlies-countPlies MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = Data.Foldable.foldl' (\acc -> (+ acc) . length) 0 byLogicalColour+countPlies :: TurnsByLogicalColour turn -> Type.Count.NPlies+countPlies MkTurnsByLogicalColour { getTurnsByLogicalColour = byLogicalColour } = fromIntegral $ Data.Foldable.foldl' (\acc -> (+ acc) . length) 0 byLogicalColour -- | Dereference. dereference :: Attribute.LogicalColour.LogicalColour -> TurnsByLogicalColour turn -> [turn]
src-lib/BishBosh/StateProperty/Censor.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE CPP #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -31,28 +30,22 @@ Censor(..) ) where -import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Component.Piece as Component.Piece+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Type.Count as Type.Count -- | The difference in the number of /piece/s of each /rank/ held by either side.-type NPiecesByRank =-#ifdef USE_UNBOXED_ARRAYS- Attribute.Rank.UArrayByRank-#else- Attribute.Rank.ArrayByRank-#endif- Component.Piece.NPieces+type NPiecesByRank = Attribute.Rank.ArrayByRank Type.Count.NPieces -- | An interface which may be implemented by data which can perform a census of the /piece/s on the /board/. class Censor censor where- countPiecesByLogicalColour :: censor -> (Component.Piece.NPieces, Component.Piece.NPieces) -- ^ The total number of /piece/s, partitioned into @Black@ & @White@ respectively.+ countPiecesByLogicalColour :: censor -> (Type.Count.NPieces, Type.Count.NPieces) -- ^ The total number of /piece/s, partitioned into @Black@ & @White@ respectively. - countPieces :: censor -> Component.Piece.NPieces -- ^ The total number of /piece/s on the board, regardless of logical colour.+ countPieces :: censor -> Type.Count.NPieces -- ^ The total number of /piece/s on the board, regardless of logical colour. countPieces = uncurry (+) . countPiecesByLogicalColour -- Default implementation. - countPieceDifferenceByRank :: censor -> NPiecesByRank -- ^ Finds the difference between the number of /piece/s of each /rank/ held by each side. N.B. for this purpose, @White@ is arbitrarily considered positive & @Black@ negative.+ countPieceDifferenceByRank :: censor -> NPiecesByRank -- ^ Finds the difference between the number of /piece/s of each /rank/ held by each side. N.B. for this purpose, @White@ is arbitrarily considered positive & @Black@ negative. - hasInsufficientMaterial :: censor -> Bool -- ^ Whether insufficient material remains on the board, to force check-mate; <https://en.wikipedia.org/wiki/Draw_(chess)>.+ hasInsufficientMaterial :: censor -> Bool -- ^ Whether insufficient material remains on the board, to force check-mate; <https://en.wikipedia.org/wiki/Draw_(chess)>. - hasBothKings :: censor -> Bool -- ^ Whether there's exactly one @King@ of each /logical colour/.+ hasBothKings :: censor -> Bool -- ^ Whether there's exactly one @King@ of each /logical colour/.
src-lib/BishBosh/Text/Case.hs view
@@ -43,3 +43,4 @@ -- | Convert the initial letter of the specified string to upper-case. toUpperInitial :: String -> String toUpperInitial = translateInitial Data.Char.toUpper+
src-lib/BishBosh/Text/ShowPrefix.hs view
@@ -40,3 +40,4 @@ -- | Used to qualify output. showsPrefixError :: ShowS showsPrefixError = showString "ERROR:\t"+
+ src-lib/BishBosh/Time/GameClock.hs view
@@ -0,0 +1,88 @@+{-+ 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 two stop-watches, exactly one of which is running at any time.+-}++module BishBosh.Time.GameClock(+-- * Types+-- ** Data-types+ GameClock(+-- MkGameClock,+ deconstruct+ ),+-- * Functions+ showsElapsedTimes+ ) where++import Control.Arrow((***))+import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified BishBosh.Text.ShowList as Text.ShowList+import qualified BishBosh.Time.StopWatch as Time.StopWatch+import qualified BishBosh.Type.Count as Type.Count+import qualified Control.Exception+import qualified Data.Array.IArray+import qualified Data.Default+import qualified Data.Foldable++-- | Models a game-clock, in which each player owns a personal stop-watch, exactly one of which is running at any one time.+newtype GameClock = MkGameClock {+ deconstruct :: Attribute.LogicalColour.ArrayByLogicalColour Time.StopWatch.StopWatch -- ^ Contains one stop-watch for each of two players.+}++instance Property.Switchable.Switchable GameClock where+ on = fmap (+ MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour . (+ Data.Default.def : -- A stopped watch for Black.+ ) . return {-to List-monad-}+ ) Property.Switchable.on -- A running watch for White.++ toggle gameClock+ | errorMessages@(_ : _) <- Property.SelfValidating.findInvalidity gameClock = Control.Exception.throwIO . Data.Exception.mkInsufficientData . showString "Duel.Process.Intermediary.initialise:\tinvalid gameClock; " $ show errorMessages+ | otherwise = fmap (+ MkGameClock . Attribute.LogicalColour.listArrayByLogicalColour+ ) . mapM Property.Switchable.toggle . Data.Array.IArray.elems $ 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.++ isOn = Data.Foldable.any Property.Switchable.isOn . deconstruct -- CAVEAT: includes the dysfunctional state in which both sides are running.++ isOff = Data.Foldable.all Property.Switchable.isOff . deconstruct++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")+ ]++-- | Show the elapsed times.+showsElapsedTimes :: Type.Count.NDecimalDigits -> GameClock -> IO ShowS+showsElapsedTimes nDecimalDigits = fmap (+ Text.ShowList.showsAssociationList' . map (+ show *** Property.ShowFloat.showsFloatToN nDecimalDigits+ ) . Data.Array.IArray.assocs . deconstruct+ ) . Property.Switchable.switchOff+
+ src-lib/BishBosh/Time/StopWatch.hs view
@@ -0,0 +1,82 @@+{-+ 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 stop-watch for use by a single player; so two independent instances will be required to construct a game-clock.+-}++module BishBosh.Time.StopWatch(+-- * Types+-- ** Data-types+ StopWatch(+-- MkStopWatch,+-- deconstruct+ ),+-- * Functions+ getElapsedTime,+-- ** Constructor+ mkStoppedWatch+ ) where++import Control.Arrow((&&&), (|||))+import qualified BishBosh.Data.Exception as Data.Exception+import qualified BishBosh.Property.ShowFloat as Property.ShowFloat+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified Control.DeepSeq+import qualified Control.Exception+import qualified Data.Default+import qualified Data.Time.Clock++-- | The watch is either running & records the time at which it was started, or is stopped & records the elapsed duration.+newtype StopWatch = MkStopWatch {+ deconstruct :: Either Data.Time.Clock.UTCTime Data.Time.Clock.NominalDiffTime -- ^ Either the start-time or the previously elapsed duration.+} deriving (Eq, Show)++instance Control.DeepSeq.NFData StopWatch where+ rnf MkStopWatch { deconstruct = e } = Control.DeepSeq.rnf ||| Control.DeepSeq.rnf $ e++instance Data.Default.Default StopWatch where+ def = mkStoppedWatch 0++instance Property.ShowFloat.ShowFloat StopWatch where+ showsFloat fromDouble = fromDouble . getElapsedTime++instance Property.Switchable.Switchable StopWatch where+ on = Property.Switchable.toggle Data.Default.def++ toggle MkStopWatch { deconstruct = e } = do+ (diffUTCTime', addUTCTime') <- fmap (Data.Time.Clock.diffUTCTime &&& flip Data.Time.Clock.addUTCTime) Data.Time.Clock.getCurrentTime -- Partially apply the functions to the current time.++ return {-to IO-monad-} . MkStopWatch $ (Right . diffUTCTime' ||| Left . addUTCTime' . negate) e -- Complete the function-application. N.B.: Right & Left are reflected.++ isOn MkStopWatch { deconstruct = Left _ } = True+ isOn _ = False++-- | Constructor.+mkStoppedWatch :: Data.Time.Clock.NominalDiffTime -> StopWatch+mkStoppedWatch = MkStopWatch . Right++-- | Extract the elapsed time from a stopped watch.+getElapsedTime :: Fractional f => StopWatch -> f+getElapsedTime MkStopWatch {+ deconstruct = Right nominalDiffTime+} = realToFrac nominalDiffTime+getElapsedTime _ = Control.Exception.throw $ Data.Exception.mkRequestFailure "BishBosh.Time.StopWatch.getElapsedTime:\tthe watch is still running."+
+ src-lib/BishBosh/Type/Count.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-+ 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 distinct types for various countable quantities to prevent accidental conflation between conceptually different quantities.++ * Nothing but the type is exported, facilitating reversion to unwrapped types.+-}++module BishBosh.Type.Count(+-- * Types+-- ** Type-synonyms+-- Base,+-- ** Data-types+ NDecimalDigits,+ NDirections,+ NGames,+ NLogicalColours,+ NMoves,+ NPieces,+ NPlies,+ NPositions,+ NRanks,+ NSeconds,+) where++#ifdef USE_NEWTYPE_WRAPPERS+import qualified Control.DeepSeq+import qualified Data.Array.IArray+import qualified Text.XML.HXT.Arrow.Pickle as HXT+#endif++-- | The private type which is wrapped by countable data-types.+type Base = Int++-- | 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)++instance Show NDecimalDigits where+ showsPrec precedence (MkNDecimalDigits n) = showsPrec precedence n+#else+type NDecimalDigits = Base+#endif++-- | A number of decimal digits.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NDirections = MkNDirections Base deriving (Enum, Eq, Integral, Num, Ord, Real)+#else+type NDirections = Base+#endif++-- | A number of /game/s.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NGames = MkNGames Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real)++instance Show NGames where+ showsPrec precedence (MkNGames n) = showsPrec precedence n+#else+type NGames = Base+#endif++-- | A number of /logical colour/s.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NLogicalColours = MkNLogicalColours Base deriving (Enum, Eq, Integral, Num, Ord, Real)++instance Show NLogicalColours where+ showsPrec precedence (MkNLogicalColours n) = showsPrec precedence n+#else+type NLogicalColours = Base+#endif++-- | A number of /move/s, i.e. each player takes one turn.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NMoves = MkNMoves Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Real)++instance Show NMoves where+ showsPrec precedence (MkNMoves n) = showsPrec precedence n+#else+type NMoves = Base+#endif++-- | A number of /piece/s.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NPieces = MkNPieces Base deriving (Control.DeepSeq.NFData, Data.Array.IArray.Ix, Enum, Eq, Integral, Num, Ord, Real)++instance Show NPieces where+ showsPrec precedence (MkNPieces n) = showsPrec precedence n+#else+type NPieces = Base+#endif++{- |+ * A number of /plies/.++ * CAVEAT: conceptually similar to /NPositions/ in that a ply (half a move) defines a step down the move-tree to a new position; the difference is that positions don't necessarily relate to a consecutive sequence resulting from a game.++ * CAVEAT: arguably the same type as /NMoves/, just double the value.+-}+#ifdef USE_NEWTYPE_WRAPPERS+newtype NPlies = MkNPlies Base deriving (Control.DeepSeq.NFData, Enum, Eq, HXT.XmlPickler, Integral, Num, Ord, Read, Real)++instance Show NPlies where+ showsPrec precedence (MkNPlies n) = showsPrec precedence n+#else+type NPlies = Base+#endif++-- | A number of /position/s.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NPositions = MkNPositions Base deriving (Control.DeepSeq.NFData, Enum, Eq, Integral, Num, Ord, Real)++instance Show NPositions where+ showsPrec precedence (MkNPositions n) = showsPrec precedence n+#else+type NPositions = Base+#endif++-- | A number of /rank/s.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NRanks = MkNRanks Base deriving (Enum, Eq, Integral, Num, Ord, Real)+#else+type NRanks = Base+#endif++-- | A number of seconds.+#ifdef USE_NEWTYPE_WRAPPERS+newtype NSeconds = MkNSeconds Base deriving (Enum, Eq, Integral, Num, Ord, Real)++instance Show NSeconds where+ showsPrec precedence (MkNSeconds n) = showsPrec precedence n+#else+type NSeconds = Base+#endif+
+ src-lib/BishBosh/Type/Crypto.hs view
@@ -0,0 +1,45 @@+{-# LANGUAGE CPP #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@]++ * Defines suitable concrete types with which to specialise miscellaneous type-parameters.++ * CAVEAT: use of narrow numeric types, results in marginally slower performance without any reduction in space-requirements.+-}++module BishBosh.Type.Crypto(+-- * Types+-- ** Type-synonyms+ PositionHash,+) where++import qualified Data.Word++-- | The type of the hash used to uniquely represent a /position/.+type PositionHash =+#ifdef USE_NARROW_NUMBERS+ Data.Word.Word32 -- CAVEAT: hash-collisions become almost inevitable after @ sqrt bits @ trials.+#else+ Data.Word.Word+#endif+
+ src-lib/BishBosh/Type/Length.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE CPP, GeneralizedNewtypeDeriving #-}+{-# 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@]++ * Defines suitable concrete types with which to specialise length-related type-parameters.++ * CAVEAT: use of narrow numeric types, results in marginally slower performance without any reduction in space-requirements.+-}++module BishBosh.Type.Length(+-- * Types+-- ** Type-synonyms+-- Base,+ Distance,+ X,+ Y,+ Row(),+ Column()+) where++#if defined(USE_NARROW_NUMBERS) || defined(USE_NEWTYPE_WRAPPERS)+# ifdef USE_NARROW_NUMBERS+import qualified Data.Int+# endif++# ifdef USE_NEWTYPE_WRAPPERS+import qualified Control.DeepSeq+# 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.+type Base =+#ifdef USE_NARROW_NUMBERS+ Data.Int.Int8++instance HXT.XmlPickler Data.Int.Int8 where+ xpickle = HXT.xpPrim+#else+ Int+#endif++{- |+ * The preferred type by which to represent the signed distance of a move.++ * 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.++-- | The distance along the abscissa.+type X = Base++-- | The distance along the ordinate.+type Y = Base -- N.B.: it can be independent of 'X'.++-- | 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)++instance Show Row where+ showsPrec precision (MkRow row) = showsPrec precision row+#else+type Row = Y+#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)++instance Show Column where+ showsPrec precision (MkColumn column) = showsPrec precision column+#else+type Column = X+#endif+
+ src-lib/BishBosh/Type/Mass.hs view
@@ -0,0 +1,72 @@+{-# 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@]++ * Defines distinct types for various mass (uncountable) quantities.++ * These prevent accidental conflation between conceptually different quantities.+-}++module BishBosh.Type.Mass(+-- * Types+-- ** Type-synonyms+ CriterionWeight,+ CriterionValue,+ WeightedMean,+ RankValue,+ PieceSquareValue+) where++import qualified Text.XML.HXT.Arrow.Pickle as HXT++-- | The preferred type by which to weight criteria.+type CriterionWeight =+#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.++instance HXT.XmlPickler Double where+ xpickle = HXT.xpPrim+#endif++-- | The preferred type by which to value criteria.+type CriterionValue = CriterionWeight++-- | The preferred type by which to represent fitness.+type WeightedMean = CriterionValue++-- | The preferred type by which to represent the value of a /rank/.+type RankValue = CriterionValue++{- |+ * The preferred type by which to represent a /piece-square/ value.++ * CAVEAT: performance of 'BishBosh.Evaluation.Fitness.interpolatePieceSquareValues' suffers from use of 'Rational'.+-}+type PieceSquareValue = CriterionValue+
− src-lib/BishBosh/Types.hs
@@ -1,99 +0,0 @@-{-# LANGUAGE CPP #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@]-- * Defines suitable concrete types with which to specialise type-parameters.-- * CAVEAT: use of the narrow set of numeric types, results in marginally slower performance without any reduction in space-requirements.--}--module BishBosh.Types(--- * Types--- ** Type-synonyms- CriterionWeight,- CriterionValue,- WeightedMean,- X,- Y,- Distance,- RankValue,- PieceSquareValue,- PositionHash-) where--import qualified Data.Word--#ifdef USE_NARROW_NUMBERS-import qualified Data.Int-#endif---- | The preferred type by which to weight criteria.-type CriterionWeight =-#ifdef USE_NARROW_NUMBERS- Float-#else- Double -- N.B.: 'Rational' is more accurate, but slower alternative.-#endif---- | The preferred type by which to value criteria.-type CriterionValue = CriterionWeight---- | The preferred type by which to represent fitness.-type WeightedMean = CriterionValue---- | The preferred type by which to represent the abscissa. CAVEAT: while conceptually unsigned, various unguarded calls to 'pred' prevent this.-type X =-#ifdef USE_NARROW_NUMBERS- Data.Int.Int8-#else- Int-#endif---- | The preferred type by which to represent the ordinate.-type Y = X -- N.B.: it can be independent of 'X'.--{- |- * The preferred type by which to represent the signed distance of a move.-- * 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 = X -- N.B.: conceptually independent of both 'X' & 'Y' which could be unsigned.---- | The preferred type by which to represent the value of a /rank/.-type RankValue = CriterionValue--{- |- * The preferred type by which to represent a /piece-square/ value.-- * CAVEAT: performance of 'BishBosh.Evaluation.Fitness.interpolatePieceSquareValues' suffers from use of 'Rational'.--}-type PieceSquareValue = CriterionValue---- | The type of the hash used to uniquely represent a /position/.-type PositionHash =-#ifdef USE_NARROW_NUMBERS- Data.Word.Word32 -- CAVEAT: hash-collisions become almost inevitable after @ sqrt bits @ trials.-#else- Data.Word.Word-#endif-
src-lib/BishBosh/UI/Command.hs view
@@ -51,11 +51,11 @@ autoComplete ) where -import qualified BishBosh.Component.Move as Component.Move 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@@ -136,7 +136,7 @@ | Report UI.ReportObject.ReportObject -- ^ Report on the requested dynamic data. | Resign -- ^ Admit defeat. | Restart -- ^ Abandon the current game, & start afresh.- | RollBack (Maybe Component.Move.NPlies) -- ^ Roll-back the optionally specified number of plies.+ | 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.@@ -234,9 +234,9 @@ [("rollback", s')] -> case Data.List.Extra.trimStart s' of [] -> Right (RollBack Nothing, s') s'' -> case reads s'' of- [(nMoves, s''')]- | nMoves <= 0 -> Left . showString "the specified number of plies (" $ shows nMoves ") must exceed zero"- | otherwise -> Right (RollBack (Just nMoves), s''')+ [(nPlies, s''')]+ | nPlies <= 0 -> Left . showString "the specified number of plies (" $ shows nPlies ") must exceed zero"+ | otherwise -> Right (RollBack (Just $ fromInteger nPlies), s''') _ -> Left . showString "failed to read the integral number of plies to " . showString rollBackTag . showString " from " $ show s'' [("swap", s')] -> Right (Swap, s') (command, _) : _ -> Left . showString "failed to read a command from " . shows s . showString "; did you mean " . show . BishBosh.Data.List.findClosest command $ map (\(tag, _, _) -> tag) commands@@ -261,3 +261,4 @@ autoComplete = Text.AutoComplete.autoComplete $ "help" : map ( \(tag, _, _) -> tag ) commands+
src-lib/BishBosh/UI/PrintObject.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LambdaCase #-} {- Copyright (C) 2018 Dr. Alistair Ward @@ -59,9 +58,8 @@ rnf _ = () instance Show PrintObject where- showsPrec _ = showString . \case- Configuration -> configurationTag- Help -> helpTag+ show Configuration = configurationTag+ show Help = helpTag instance Read PrintObject where readsPrec _ s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of
src-lib/BishBosh/UI/ReportObject.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE LambdaCase #-} {- Copyright (C) 2021 Dr. Alistair Ward @@ -101,16 +100,15 @@ rnf _ = () instance Show ReportObject where- showsPrec _ = showString . \case- AvailableMoves -> availableMovesTag- Board -> boardTag- EPD -> epdTag- FEN -> fenTag- Game -> gameTag- MaxPositionInstances -> maxPositionInstancesTag- Moves -> movesTag- PGN -> pgnTag- ReversiblePlyCount -> reversiblePlyCountTag+ show AvailableMoves = availableMovesTag+ show Board = boardTag+ show EPD = epdTag+ show FEN = fenTag+ show Game = gameTag+ show MaxPositionInstances = maxPositionInstancesTag+ show Moves = movesTag+ show PGN = pgnTag+ show ReversiblePlyCount = reversiblePlyCountTag instance Read ReportObject where readsPrec _ s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of
src-lib/BishBosh/UI/SetObject.hs view
@@ -35,13 +35,14 @@ 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 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 Input.SearchOptions.SearchDepth deriving Eq+newtype SetObject = SearchDepth Type.Count.NPlies deriving Eq instance Control.DeepSeq.NFData SetObject where rnf (SearchDepth searchDepth) = Control.DeepSeq.rnf searchDepth@@ -51,11 +52,11 @@ instance Read SetObject where readsPrec _ s = case Control.Arrow.first Data.List.Extra.lower `map` lex s of- [("searchdepth", s')] -> Control.Arrow.first mkSearchDepth `map` reads s'+ [("searchdepth", s')] -> Control.Arrow.first (mkSearchDepth . fromInteger) `map` reads s' _ -> [] -- No parse. -- | Smart constructor.-mkSearchDepth :: Input.SearchOptions.SearchDepth -> SetObject+mkSearchDepth :: Type.Count.NPlies -> SetObject mkSearchDepth searchDepth | searchDepth < Input.SearchOptions.minimumSearchDepth = Control.Exception.throw . Data.Exception.mkOutOfBounds . showString "BishBosh.UI.SetObject.mkSearchDepth:\t" $ shows Input.SearchOptions.searchDepthTag " must be positive." | otherwise = SearchDepth searchDepth
src-test/BishBosh/Test/HUnit/Cartesian/Coordinates.hs view
@@ -33,14 +33,14 @@ 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.Types as T+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 T.X T.Y+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@@ -57,7 +57,7 @@ Property.FixedMembership.members :: [Coordinates] ) ~?= 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 T.X T.Y Int+ Cartesian.Coordinates.listArrayByCoordinates [0 .. ] :: Cartesian.Coordinates.ArrayByCoordinates Type.Length.X Type.Length.Y Int ) ~?= Property.FixedMembership.members ]
src-test/BishBosh/Test/HUnit/Cartesian/Vector.hs view
@@ -32,13 +32,13 @@ import Control.Arrow((&&&)) import qualified BishBosh.Cartesian.Vector as Cartesian.Vector import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Types as T+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 -> T.Distance+measureLength :: Cartesian.Vector.VectorInt -> Type.Length.Distance measureLength = uncurry (+) . (abs . Cartesian.Vector.getXDistance &&& abs . Cartesian.Vector.getYDistance) -- | Check the sanity of the implementation, by validating a list of static test-cases.
src-test/BishBosh/Test/HUnit/Component/CastlingMove.hs view
@@ -34,13 +34,13 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.List import qualified Test.HUnit import Test.HUnit((~?)) -- | Give the constant a concrete type.-kingsMoveLength :: T.X+kingsMoveLength :: Type.Length.X kingsMoveLength = Component.CastlingMove.kingsMoveLength -- | Check the sanity of the implementation, by validating a list of static test-cases.
src-test/BishBosh/Test/HUnit/Component/Move.hs view
@@ -35,12 +35,12 @@ 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.Types as T+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 T.X T.Y+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
src-test/BishBosh/Test/HUnit/Component/Zobrist.hs view
@@ -31,14 +31,15 @@ ) where import qualified BishBosh.Component.Zobrist as Component.Zobrist-import qualified BishBosh.Types as T+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 T.X T.Y T.PositionHash+type Zobrist = Component.Zobrist.Zobrist Type.Length.X Type.Length.Y Type.Crypto.PositionHash -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test
src-test/BishBosh/Test/HUnit/ContextualNotation/PGN.hs view
@@ -32,19 +32,21 @@ ) where import qualified BishBosh.ContextualNotation.PGN as ContextualNotation.PGN-import qualified BishBosh.Types as T+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 == 1 import qualified Data.Char import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# else /* Plain */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# endif #else /* Parsec */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Parsec as Parsec #endif @@ -54,32 +56,30 @@ #endif -- | Test-subject.-type PGN = ContextualNotation.PGN.PGN T.X T.Y+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 == 1 ( \s' -> all Data.Char.isSpace s' ~? showString "Unparsed input: " (show s') ) . snd-#else /* Plain */- either (- Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.PGN.testCases:\tfailed: " . show- ) (- const $ True ~? ""+# else /* Plain */+ (+ Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.PGN.testCases:\tfailed: " . show ||| const (+ True ~? ""+ ) ) . fst-#endif+# endif $ Poly.runParser ( ContextualNotation.PGN.parser isStrictlySequential validateMoves [] :: Text.Poly.TextParser PGN ) #else /* Parsec */- either (- Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.ContextualNotation.PGN.testCases:\tfailed: " . show- ) (- const $ True ~? ""+ 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 ) "PGN-parser"
src-test/BishBosh/Test/HUnit/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -43,7 +43,8 @@ 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.Types as T+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@@ -92,7 +93,7 @@ ContextualNotation.PositionHashQualifiedMoveTree.findNextOnymousQualifiedMoves tryToMatchSwitches ( mkGame s ) . ContextualNotation.PositionHashQualifiedMoveTree.fromQualifiedMoveForest False {-incrementalEvaluation-} (- Data.Default.def :: Component.Zobrist.Zobrist T.X T.Y T.PositionHash+ 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")
src-test/BishBosh/Test/HUnit/ContextualNotation/StandardAlgebraic.hs view
@@ -47,12 +47,13 @@ #ifdef USE_POLYPARSE import Test.HUnit((~?=))-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# else /* Plain */ import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# endif #else /* Parsec */+import Control.Arrow((|||)) import Test.HUnit((~?=), (~?)) import qualified Text.ParserCombinators.Parsec #endif@@ -65,13 +66,13 @@ in #ifdef USE_POLYPARSE fst (Poly.runParser parser san) ~?=-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 standardAlgebraic-#else /* Plain */+# else /* Plain */ Right standardAlgebraic-#endif+# endif #else /* Parsec */- either (\parseError -> False ~? show parseError) (~?= standardAlgebraic) $ Text.ParserCombinators.Parsec.parse parser "SAN-parser" san+ (\parseError -> False ~? show parseError) ||| (~?= standardAlgebraic) $ Text.ParserCombinators.Parsec.parse parser "SAN-parser" san #endif ) $ map ( \s -> let
src-test/BishBosh/Test/HUnit/Evaluation/Fitness.hs view
@@ -23,15 +23,11 @@ -} module BishBosh.Test.HUnit.Evaluation.Fitness(--- * Types--- ** Type-synonyms--- CriterionValue, -- * Constants testCases ) where -import Control.Arrow((&&&))-import qualified BishBosh.Attribute.CriterionValue as Attribute.CriterionValue+import Control.Arrow((&&&), (|||)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.Move as Component.Move@@ -46,15 +42,11 @@ 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 BishBosh.Types as T import qualified Control.Exception import qualified Data.Default import qualified Test.HUnit import Test.HUnit((~:), (~?=)) --- | A suitable concrete type.-type CriterionValue = Attribute.CriterionValue.CriterionValue T.CriterionValue- -- | Check the sanity of the implementation, by validating a list of static test-cases. testCases :: Test.HUnit.Test testCases = Test.HUnit.test [@@ -63,9 +55,7 @@ Model.Game.applyEitherQualifiedMove eitherQualifiedMove ( Data.Default.def :: Test.HUnit.Model.Game.Game )- ) ~?= (- minBound :: CriterionValue- )+ ) ~?= negate 1 _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed to parse move.", "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after moving Rooks." ~: Evaluation.Fitness.measureValueOfCastlingPotential ( Model.Game.fromBoard . foldr (@@ -77,16 +67,14 @@ ) ( Data.Default.def :: Test.HUnit.State.Board.Board ) $ Cartesian.Coordinates.rooksStartingCoordinates Attribute.LogicalColour.White- ) ~?= (- maxBound :: CriterionValue- ),+ ) ~?= 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 )- ) ~?= (- Attribute.CriterionValue.mkCriterionValue . negate $ recip 2 :: CriterionValue -- Moving Queen's Rook still permits castling on the King's side.+ ) ~?= negate (+ fromRational $ recip 2 -- Moving Queen's Rook still permits castling on the King's side. ) _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed to parse move.", "'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@@ -94,14 +82,14 @@ Model.Game.applyEitherQualifiedMove eitherQualifiedMove ( Data.Default.def :: Test.HUnit.Model.Game.Game )- ) ~?= (- Attribute.CriterionValue.mkCriterionValue $ recip 2 :: CriterionValue -- Taking Queen's Rook still permits castling on the King's side.+ ) ~?= fromRational (+ recip 2 -- Taking Queen's Rook still permits castling on the King's side. ) _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed to parse move.",- "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after moving one Rook from either side." ~: either (+ "'BishBosh.Evaluation.Fitness.measureValueOfCastlingPotential' failed after moving one Rook from either side." ~: ( \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."- ) (- \game -> Evaluation.Fitness.measureValueOfCastlingPotential game ~?= (Attribute.CriterionValue.zero :: CriterionValue)+ ) ||| (+ \game -> Evaluation.Fitness.measureValueOfCastlingPotential game ~?= 0 ) $ Test.HUnit.Model.Game.applyMoves [ "a2a3", "g8f6",@@ -112,37 +100,27 @@ Model.Game.fromBoard ( read "4k3/p6p/8/3PP3/3PP3/3PP3/3PP3/4K3" :: Test.HUnit.State.Board.Board )- ) ~?= (- maxBound :: CriterionValue -- White is the next player, so Black is assumed to have just moved to an optimal position.- ),+ ) ~?= 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 )- ) ~?= (- maxBound :: CriterionValue -- White is the next player, so Black is assumed to have just moved to an optimal position.- ),+ ) ~?= 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 )- ) ~?= (- maxBound :: CriterionValue -- White is the next player, so Black is assumed to have just moved to an optimal position.- ),+ ) ~?= 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 )- ) ~?= (- maxBound :: CriterionValue -- White is the next player, so Black is assumed to have just moved to an optimal position.- ),+ ) ~?= 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 )- ) ~?= (- minBound :: CriterionValue -- White is the next player, so Black is assumed to have just moved to the worst possible position.- ),+ ) ~?= 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 ( Model.Game.fromBoard . uncurry ( foldr $ \(coordinates, _) -> StateProperty.Mutator.removePiece coordinates@@ -153,22 +131,32 @@ ) ( Data.Default.def :: Test.HUnit.State.Board.Board )- ) ~?= Attribute.CriterionValue.mkCriterionValue (- 19 / fromIntegral Evaluation.Fitness.maximumDefended :: T.CriterionValue+ ) ~?= fromRational (+ 19 / fromIntegral {-NPieces-} Evaluation.Fitness.maximumDefended ), "'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 )- ) ~?= Attribute.CriterionValue.mkCriterionValue (recip $ fromIntegral Evaluation.Fitness.maximumDefended :: T.CriterionValue)+ ) ~?= fromRational (+ recip $ fromIntegral {-NPieces-} Evaluation.Fitness.maximumDefended+ ) _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed to parse move.",- "'BishBosh.Evaluation.Fitness.measureValueOfDefence' failed after Pawn advance & Knight move." ~: either (+ "'BishBosh.Evaluation.Fitness.measureValueOfDefence' failed after Pawn advance & Knight move." ~: ( \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Evaluation.Fitness.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."- ) (- \game -> Evaluation.Fitness.measureValueOfDefence game ~?= Attribute.CriterionValue.mkCriterionValue (3 / fromIntegral Evaluation.Fitness.maximumDefended :: T.CriterionValue)+ ) ||| (+ \game -> Evaluation.Fitness.measureValueOfDefence game ~?= fromRational (+ 3 / fromIntegral {-NPieces-} Evaluation.Fitness.maximumDefended+ ) ) $ Test.HUnit.Model.Game.applyMoves [ "g2g3", -- Advance King's Knight's Pawn. "b8c6" -- Advance Queen's Knight.- ]+ ],+ "'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+ )+ ) ~?= negate 1 -- White is the next player. ]+
src-test/BishBosh/Test/HUnit/Input/Options.hs view
@@ -27,11 +27,12 @@ testCases ) where -import BishBosh.Data.Float() -- HXT.XmlPickler.+--import BishBosh.Data.Ratio() -- Required if either Type.Mass.CriterionWeight or Type.Mass.CriterionValue is Rational. import Control.Category((>>>)) import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Input.Options as Input.Options-import qualified BishBosh.Types as T+import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Type.Mass as Type.Mass import qualified Control.Exception import qualified Data.List import qualified Data.Maybe@@ -55,9 +56,6 @@ HXT.withValidate HXT.yes -- Validate against any DTD referenced from the XML-file. ] - maximumTraceLevel :: Int- maximumTraceLevel = 0- fileName :: System.FilePath.FilePath fileName = "bishbosh_both" <.> "xml" in do@@ -79,12 +77,12 @@ Control.Exception.throw . Data.Exception.mkSearchFailure . showString "BishBosh.Test.HUnit.Input.Options.testCases:\tfailed to locate " . shows fileName . showString " in " $ shows searchPath "." ) ( \path -> do- optionsList <- HXT.runX {-which returns a list-} $ HXT.setTraceLevel maximumTraceLevel >>> HXT.xunpickleDocument HXT.xpickle inputSysConfig path+ optionsList <- HXT.runX {-which returns a list-} $ HXT.setTraceLevel 0 >>> HXT.xunpickleDocument HXT.xpickle inputSysConfig path (== Just (head optionsList)) ( (HXT.unpickleDoc HXT.xpickle . HXT.pickleDoc HXT.xpickle) =<< Data.Maybe.listToMaybe ( optionsList :: [- Input.Options.Options T.Y {-column-} T.CriterionWeight T.PieceSquareValue T.RankValue T.X {-row-} T.X T.Y+ Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y ] ) ) @? "Input.Options.pickler failed."
src-test/BishBosh/Test/HUnit/Model/Game.hs view
@@ -33,7 +33,7 @@ ) where import BishBosh.Model.Game((/~))-import Control.Arrow((&&&), (***))+import Control.Arrow((&&&), (***), (|||)) import Data.Map((!)) import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour import qualified BishBosh.Attribute.MoveType as Attribute.MoveType@@ -43,14 +43,14 @@ import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Model.Game as Model.Game-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified BishBosh.Notation.Smith as Notation.Smith 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Exception import qualified Data.Default import qualified Data.Maybe@@ -58,7 +58,7 @@ import Test.HUnit((~?), (~:), (~?=)) -- | Defines a concrete type for testing.-type Game = Model.Game.Game T.X T.Y+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@@ -145,9 +145,9 @@ "e1g1c", "e1c1C" ] ~? "'BishBosh.Model.Game.rollback' failed to undo castling",- either (+ ( \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."- ) (+ ) ||| ( \game -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a5b6E" of [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove game ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by White." _ -> Control.Exception.throw . Data.Exception.mkParseFailure . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t /~ " $ Notation.MoveNotation.showsMoveSyntax Data.Default.def ""@@ -157,9 +157,9 @@ "a4a5", -- White: Queen's Rook's Pawn. "b7b5" -- Black: Queen's Knight's Pawn. ],- either (+ ( \(moveString, errorMessage) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed for " . showString Component.Move.tag . Text.ShowList.showsAssociation . shows moveString . showString "; " $ showString errorMessage "."- ) (+ ) ||| ( \game -> case Notation.MoveNotation.readsQualifiedMove Data.Default.def "a4b3E" of [(eitherQualifiedMove, "")] -> Model.Game.isValidEitherQualifiedMove eitherQualifiedMove game ~? "'BishBosh.Model.Game.isValidEitherQualifiedMove' failed for En-passant by Black." _ -> Control.Exception.throw $ Data.Exception.mkParseFailure "BishBosh.Test.HUnit.Model.Game.testCases:\tfailed to parse move."@@ -170,13 +170,13 @@ "a5a4", -- Black: Queen's Rook's Pawn. "b2b4" -- White: Queen's Knight's Pawn. ],- Data.Maybe.maybe False Model.GameTerminationReason.isStaleMate (+ 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 ) ) ~? "'BishBosh.Model.Game.getMaybeTerminationReason' failed to detect \"Stale-mate\".", all (- \s -> Data.Maybe.maybe False Model.GameTerminationReason.isDrawByInsufficientMaterial $ Model.Game.getMaybeTerminationReason (+ \s -> Data.Maybe.maybe False Rule.GameTerminationReason.isDrawByInsufficientMaterial $ Model.Game.getMaybeTerminationReason ( Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Game ) ) [@@ -185,7 +185,7 @@ "8/8/2KB4/8/7k/2B5/5b2/8" ] ~? "'BishBosh.Model.Game.getMaybeTerminationReason' failed to detect \"Draw by Insufficient Material\".", all (- \s -> Data.Maybe.maybe True (not . Model.GameTerminationReason.isDrawByInsufficientMaterial) $ Model.Game.getMaybeTerminationReason (+ \s -> Data.Maybe.maybe True (not . Rule.GameTerminationReason.isDrawByInsufficientMaterial) $ Model.Game.getMaybeTerminationReason ( Model.Game.fromBoard $ Property.ForsythEdwards.readFEN s :: Game ) ) [@@ -210,7 +210,7 @@ either ( \(moveString, s) -> Control.Exception.throw . Data.Exception.mkInvalidDatum . showString "BishBosh.Test.HUnit.Model.Game.testCases:\t" . showString moveString . showString "; " $ showString s "." ) (- Data.Maybe.maybe False Model.GameTerminationReason.isDraw . Model.Game.getMaybeTerminationReason+ Data.Maybe.maybe False Rule.GameTerminationReason.isDraw . Model.Game.getMaybeTerminationReason ) ( applyMoves . concat . replicate 4 $ words "g1f3 g8f6 f3g1 f6g8" ) ~? "'BishBosh.Model.Game./~' failed to account for Draw by Five-fold Repetition.",
src-test/BishBosh/Test/HUnit/Model/GameTree.hs view
@@ -30,15 +30,15 @@ ) where import qualified BishBosh.Attribute.CaptureMoveSortAlgorithm as Attribute.CaptureMoveSortAlgorithm-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues import qualified BishBosh.Component.Turn as Component.Turn+import qualified BishBosh.Input.RankValues as Input.RankValues import qualified BishBosh.Model.Game as Model.Game import qualified BishBosh.Model.GameTree as Model.GameTree import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.Default import qualified Data.Maybe import qualified Data.Tree@@ -51,18 +51,18 @@ let maxDepth = 4 in "'BishBosh.Model.GameTree.countGames' failed" ~: map Model.GameTree.countGames [0 .. maxDepth] ~?= take (succ maxDepth) [1, 20, 400, 8902, 197281, 4865609], -- <https://oeis.org/A048987>- "'BishBosh.Model.GameTree.countMoves' failed" ~: map (- \searchDepth -> Model.GameTree.countMoves searchDepth ~?= foldr (+ "'BishBosh.Model.GameTree.countPositions' failed" ~: map (+ \searchDepth -> fromIntegral (Model.GameTree.countPositions searchDepth) ~?= foldr ( (+) . Model.GameTree.countGames ) 0 [1 .. searchDepth] ) [1 .. 4], "'BishBosh.Model.GameTree.sortGameTree/MVVLVA' failed" ~: map (- \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn T.X T.Y)+ \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn Type.Length.X Type.Length.Y) ) ( 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 T.X T.Y)+ \turn -> Notation.MoveNotation.showNotation Data.Default.def (turn :: Component.Turn.Turn Type.Length.X Type.Length.Y) ) ( 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"]@@ -76,9 +76,11 @@ sortAvailableMoves maybeSortAlgorithm = Data.Maybe.mapMaybe ( Model.Game.maybeLastTurn . Data.Tree.rootLabel ) . Data.Tree.subForest . Model.GameTree.deconstruct . Model.GameTree.sortGameTree maybeSortAlgorithm (- `Attribute.RankValues.findRankValue` Attribute.RankValues.fromAssocs (- zip Property.FixedMembership.members $ map (/ 10) [- 1 :: T.RankValue,+ `Input.RankValues.findRankValue` Input.RankValues.fromAssocs (+ zip Property.FixedMembership.members $ map (+ fromRational . (/ 10) -- Map into the closed unit-interval.+ ) [+ 1, -- P 5, -- R 3, -- N 7 / 2, -- B
src-test/BishBosh/Test/HUnit/Model/PositionHashTree.hs view
@@ -30,7 +30,7 @@ ) where import qualified BishBosh.Model.PositionHashTree as Model.PositionHashTree-import qualified BishBosh.Types as T+import qualified BishBosh.Type.Crypto as Type.Crypto import qualified Data.Default import qualified Test.HUnit import Test.HUnit((~:), (~?=))@@ -41,6 +41,7 @@ let maxDepth = 4 in "'BishBosh.Model.PositionhashTree.countDistinctPositions' failed" ~: map (- \i -> Model.PositionHashTree.countDistinctPositions i (Data.Default.def :: Model.PositionHashTree.PositionHashTree T.PositionHash)- ) [0 .. maxDepth] ~?= take (succ maxDepth) [1, 20, 400, 5362, 72078, 822518, 9417681, 96400068, 988187354, 9183421888, 85375278064, 726155461002] -- <https://oeis.org/A083276>. CAVEAT: the point at which this test fails, depends on the square-root of the bits in 'T.PositionHash'.+ \i -> Model.PositionHashTree.countDistinctPositions i (Data.Default.def :: Model.PositionHashTree.PositionHashTree Type.Crypto.PositionHash)+ ) [0 .. maxDepth] ~?= take (succ maxDepth) [1, 20, 400, 5362, 72078, 822518, 9417681, 96400068, 988187354, 9183421888, 85375278064, 726155461002] -- <https://oeis.org/A083276>. CAVEAT: the point at which this test fails, depends on the square-root of the bits in 'Crypto.PositionHash'. ]+
src-test/BishBosh/Test/HUnit/Search/Search.hs view
@@ -30,7 +30,6 @@ ) where import qualified BishBosh.Attribute.CaptureMoveSortAlgorithm as Attribute.CaptureMoveSortAlgorithm-import qualified BishBosh.Attribute.CriterionWeight as Attribute.CriterionWeight import qualified BishBosh.Data.Exception as Data.Exception import qualified BishBosh.Evaluation.PositionHashQuantifiedGameTree as Evaluation.PositionHashQuantifiedGameTree import qualified BishBosh.Evaluation.QuantifiedGame as Evaluation.QuantifiedGame@@ -42,7 +41,9 @@ import qualified BishBosh.Property.ExtendedPositionDescription as Property.ExtendedPositionDescription import qualified BishBosh.Search.Search as Search.Search import qualified BishBosh.Search.SearchState as Search.SearchState-import qualified BishBosh.Types as T+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 import qualified Data.Default@@ -53,18 +54,12 @@ -- | Constant. evaluationOptions :: ( Fractional pieceSquareValue,- Fractional criterionWeight,- Fractional rankValue, Integral x,- Integral y,- Ord criterionWeight,- Ord rankValue,- Show criterionWeight,- Show rankValue- ) => Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y+ Integral y+ ) => Input.EvaluationOptions.EvaluationOptions pieceSquareValue x y evaluationOptions = Input.EvaluationOptions.mkEvaluationOptions Data.Default.def {-rankValues-} Data.Default.def {- Input.CriteriaWeights.getWeightOfMobility = Attribute.CriterionWeight.mkCriterionWeight $ 24 / 1000,- Input.CriteriaWeights.getWeightOfCastlingPotential = Attribute.CriterionWeight.mkCriterionWeight $ 5 / 1000+ Input.CriteriaWeights.getWeightOfMobility = 24 / 1000,+ Input.CriteriaWeights.getWeightOfCastlingPotential = 5 / 1000 } False {-IncrementalEvaluation-} Nothing {-Maybe PieceSquareTable-} -- | Constant.@@ -83,8 +78,8 @@ 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 T.CriterionWeight T.PieceSquareValue T.RankValue T.X T.Y- ) searchOptions Data.Default.def {-Zobrist-} Property.Empty.empty {-MoveFrequency-} game :: Evaluation.PositionHashQuantifiedGameTree.PositionHashQuantifiedGameTree T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean+ 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 ) ) searchOptions of quantifiedGame : _ -> Evaluation.QuantifiedGame.getLastTurn quantifiedGame@@ -124,3 +119,4 @@ (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. ]+
src-test/BishBosh/Test/HUnit/State/Board.hs view
@@ -47,7 +47,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Arrow import qualified Data.Array.IArray import qualified Data.Default@@ -59,7 +59,7 @@ import Test.HUnit((~:), (~?=), (~?)) -- | Defines a concrete type for testing.-type Board = State.Board.Board T.X T.Y+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
+ src-test/BishBosh/Test/HUnit/Time/GameClock.hs view
@@ -0,0 +1,83 @@+{-+ 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@] Static tests.+-}++module BishBosh.Test.HUnit.Time.GameClock(+-- * Constants+ testCases+) where++import qualified BishBosh.Time.GameClock as Time.GameClock+import qualified BishBosh.Time.StopWatch as Time.StopWatch+import qualified BishBosh.Property.SelfValidating as Property.SelfValidating+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified Control.Concurrent+import qualified Data.Array.IArray+import qualified Data.Foldable+import qualified System.Random+import qualified Test.HUnit+import Test.HUnit((@?))++-- | Check the sanity of the implementation, by validating a list of static test-cases.+testCases :: Test.HUnit.Test+testCases = Test.HUnit.test $ map Test.HUnit.TestCase [+ do+ stoppedGameClock <- Property.Switchable.switchOff =<< Property.Switchable.on++ Property.Switchable.isOff (stoppedGameClock :: Time.GameClock.GameClock) @? "Property.Switchable.switchOff failed.",+ do+ runningGameClock <- flick 2++ Property.Switchable.isOn runningGameClock @? "Property.Switchable.Property.Switchable.flick (double) failed.",+ do+ runningGameClock <- flick 3++ Property.Switchable.isOn runningGameClock @? "Property.Switchable.Property.Switchable.flick (triple) failed.",+ do+ runningGameClock <- flick 3++ Property.SelfValidating.isValid runningGameClock @? "Property.Switchable.Property.SelfValidating.isValid failed.",+ let+ delayedFlick :: [Int] -> Time.GameClock.GameClock -> IO Time.GameClock.GameClock+ delayedFlick (t : ts) gameClock = do+ Control.Concurrent.threadDelay t++ Property.Switchable.toggle gameClock >>= delayedFlick ts+ delayedFlick _ gameClock = return {-to IO-monad-} gameClock+ in do+ randomGenerator <- System.Random.getStdGen+ runningWatch <- Property.Switchable.on+ stoppedGameClock <- Property.Switchable.switchOff =<< delayedFlick (take 16 $ System.Random.randomRs (1, 100000 {-uS-}) randomGenerator) =<< Property.Switchable.on+ stoppedWatch <- Property.Switchable.switchOff runningWatch++ let+ 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 = " (+ shows (realToFrac relativeError :: Double) "."+ )+ ] where+ flick :: Int -> IO Time.GameClock.GameClock+ flick n = Property.Switchable.on >>= Property.Switchable.flick n+
+ src-test/BishBosh/Test/HUnit/Time/StopWatch.hs view
@@ -0,0 +1,63 @@+{-+ 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@] Static tests.+-}++module BishBosh.Test.HUnit.Time.StopWatch(+-- * Constants+ testCases+) where++import Control.Arrow((&&&))+import qualified BishBosh.Time.StopWatch as Time.StopWatch+import qualified BishBosh.Property.Switchable as Property.Switchable+import qualified Data.Default+import qualified Test.HUnit+import Test.HUnit((@?))++-- | Check the sanity of the implementation, by validating a list of static test-cases.+testCases :: Test.HUnit.Test+testCases = Test.HUnit.test $ map Test.HUnit.TestCase [+ do+ stoppedWatch' <- Property.Switchable.switchOff =<< Property.Switchable.on++ Property.Switchable.isOff (stoppedWatch' :: Time.StopWatch.StopWatch) @? "Property.Switchable.switchOff failed.",+ do+ runningWatch <- Property.Switchable.flick 2 =<< Property.Switchable.on++ Property.Switchable.isOn (runningWatch :: Time.StopWatch.StopWatch) @? "Property.Switchable.Property.Switchable.flick (double) failed.",+ do+ runningWatch <- Property.Switchable.flick 3 stoppedWatch++ uncurry (/=) (+ ($ stoppedWatch) &&& ($ runningWatch) $ Property.Switchable.isOn+ ) @? "Property.Switchable.Property.Switchable.flick (triple) failed.",+ do+ stoppedWatch' <- Property.Switchable.flick 2 stoppedWatch++ uncurry (==) (+ ($ stoppedWatch) &&& ($ stoppedWatch') $ Property.Switchable.isOn+ ) @? "Property.Switchable.Property.Switchable.flick (double) failed."+ ] where+ stoppedWatch :: Time.StopWatch.StopWatch+ stoppedWatch = Data.Default.def+
− src-test/BishBosh/Test/QuickCheck/Attribute/CriterionWeight.hs
@@ -1,37 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.--}--module BishBosh.Test.QuickCheck.Attribute.CriterionWeight() where--import qualified BishBosh.Attribute.CriterionWeight as Attribute.CriterionWeight-import qualified Test.QuickCheck--instance (- Fractional criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => Test.QuickCheck.Arbitrary (Attribute.CriterionWeight.CriterionWeight criterionWeight) where- arbitrary = (Attribute.CriterionWeight.mkCriterionWeight . (/ 10) . fromInteger) `fmap` Test.QuickCheck.elements [0 .. 9]-
src-test/BishBosh/Test/QuickCheck/Attribute/MoveType.hs view
@@ -63,3 +63,4 @@ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64} f ]+
− src-test/BishBosh/Test/QuickCheck/Attribute/RankValues.hs
@@ -1,49 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.--}--module BishBosh.Test.QuickCheck.Attribute.RankValues(--- * Types--- ** Type-synonyms- RankValues-) where--import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Types as T-import qualified Test.QuickCheck--instance (- Fractional rankValue,- Ord rankValue,- Show rankValue- ) => Test.QuickCheck.Arbitrary (Attribute.RankValues.RankValues rankValue) where- arbitrary = Attribute.RankValues.fromAssocs . zip Property.FixedMembership.members . map (- recip . fromInteger . succ . (`mod` 100) -- Normalise to the half open unit-interval (0,1].- ) <$> Test.QuickCheck.vector Attribute.Rank.nDistinctRanks---- | Defines a concrete type for testing.-type RankValues = Attribute.RankValues.RankValues T.RankValue-
src-test/BishBosh/Test/QuickCheck/Cartesian/Coordinates.hs view
@@ -42,7 +42,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.Array.IArray import qualified Data.List import qualified Data.List.Extra@@ -52,7 +52,7 @@ import Test.QuickCheck((==>)) -- | Defines a concrete type for testing.-type Coordinates = Cartesian.Coordinates.Coordinates T.X T.Y+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 #-}
src-test/BishBosh/Test/QuickCheck/Cartesian/Vector.hs view
@@ -36,11 +36,11 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Test.QuickCheck import Test.QuickCheck((==>)) -instance Integral distance => Test.QuickCheck.Arbitrary (Cartesian.Vector.Vector distance) where+instance (Num distance, Ord distance) => Test.QuickCheck.Arbitrary (Cartesian.Vector.Vector distance) where -- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Cartesian.Vector.VectorInt #-} arbitrary = do source <- Test.QuickCheck.arbitrary :: Test.QuickCheck.Gen Test.QuickCheck.Cartesian.Coordinates.Coordinates@@ -64,18 +64,18 @@ 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 :: (T.Distance, T.Distance) -> Test.QuickCheck.Cartesian.Coordinates.Coordinates -> Test.QuickCheck.Property+ f :: (Type.Length.Distance, Type.Length.Distance) -> Test.QuickCheck.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 :: T.X -> T.X+ deltaX :: Type.Length.X -> Type.Length.X deltaX = ( + fromIntegral ( (distanceX `mod` Cartesian.Abscissa.xLength) - (Cartesian.Abscissa.xLength `div` 2) ) ) - deltaY :: T.Y -> T.Y+ deltaY :: Type.Length.Y -> Type.Length.Y deltaY = ( + fromIntegral ( (distanceY `mod` Cartesian.Ordinate.yLength) - (Cartesian.Ordinate.yLength `div` 2)@@ -95,3 +95,4 @@ ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]+
src-test/BishBosh/Test/QuickCheck/Component/Move.hs view
@@ -38,19 +38,19 @@ 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.Types as T+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 T.X T.Y+type Move = Component.Move.Move Type.Length.X Type.Length.Y instance ( Enum x, Enum y,- Ord x,- Ord y+ Eq x,+ Eq y ) => Test.QuickCheck.Arbitrary (Component.Move.Move x y) where -- {-# SPECIALISE instance Test.QuickCheck.Arbitrary Move #-} arbitrary = fmap (uncurry Component.Move.mkMove) . Test.QuickCheck.suchThat Test.QuickCheck.arbitrary $ uncurry (/=)@@ -99,3 +99,4 @@ 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/QualifiedMove.hs view
@@ -36,18 +36,18 @@ import Control.Arrow((&&&)) import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Types as T+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 T.X T.Y+type QualifiedMove = Component.QualifiedMove.QualifiedMove Type.Length.X Type.Length.Y instance ( Enum x, Enum y,- Ord x,- Ord y+ Eq x,+ Eq y ) => Test.QuickCheck.Arbitrary (Component.QualifiedMove.QualifiedMove x y) where -- {-# SPECIALISE instance Test.QuickCheck.Arbitrary QualifiedMove #-} arbitrary = uncurry Component.QualifiedMove.mkQualifiedMove `fmap` Test.QuickCheck.arbitrary -- CAVEAT: the move & moveType are unlikely to be compatible.@@ -74,3 +74,4 @@ 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
@@ -36,18 +36,18 @@ import BishBosh.Test.QuickCheck.Attribute.MoveType() import BishBosh.Test.QuickCheck.Component.Move() import BishBosh.Test.QuickCheck.Component.Piece()+import BishBosh.Test.QuickCheck.Input.RankValues() import Control.Arrow((&&&))-import qualified BishBosh.Attribute.MoveType as Attribute.MoveType-import qualified BishBosh.Attribute.Rank as Attribute.Rank-import qualified BishBosh.Attribute.RankValues as Attribute.RankValues-import qualified BishBosh.Component.CastlingMove as Component.CastlingMove-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.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Reflectable as Property.Reflectable-import qualified BishBosh.Test.QuickCheck.Attribute.RankValues as Test.QuickCheck.Attribute.RankValues-import qualified BishBosh.Types as T+import qualified BishBosh.Attribute.MoveType as Attribute.MoveType+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Component.CastlingMove as Component.CastlingMove+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.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@@ -56,7 +56,7 @@ import qualified ToolShed.Test.ReversibleIO -- | Defines a concrete type for testing.-type Turn = Component.Turn.Turn T.X T.Y+type Turn = Component.Turn.Turn Type.Length.X Type.Length.Y instance ( Enum x,@@ -78,8 +78,8 @@ return {-to Gen-monad-} . Component.Turn.mkTurn (Component.QualifiedMove.mkQualifiedMove move moveType) $ Component.Piece.getRank piece -- | Distinct rank-values designed for a predictable sort-order.-rankValues :: Test.QuickCheck.Attribute.RankValues.RankValues-rankValues = Attribute.RankValues.fromAssocs . zip Property.FixedMembership.members $ map (/ 10) [1, 5, 3, 4, 9, 0]+rankValues :: Input.RankValues.RankValues+rankValues = Input.RankValues.fromAssocs . zip Property.FixedMembership.members $ map (fromRational . (/ 10)) [1, 5, 3, 4, 9, 0] -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]@@ -103,10 +103,10 @@ 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 :: Test.QuickCheck.Attribute.RankValues.RankValues -> [Turn] -> Test.QuickCheck.Property+ f :: Input.RankValues.RankValues -> [Turn] -> Test.QuickCheck.Property f rankValues' = Test.QuickCheck.label "Turn.prop_compareByMVVLVA/quiet" . uncurry (==) . ( dropWhile Component.Turn.isCapture . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Attribute.RankValues.findRankValue` rankValues')+ Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues') ) &&& filter ( not . Component.Turn.isCapture )@@ -116,12 +116,12 @@ f :: [Turn] -> Test.QuickCheck.Property f = Test.QuickCheck.label "Turn.prop_compareByMVVLVA/MVV" . ( \ranks -> Data.List.sortOn (- negate . (`Attribute.RankValues.findRankValue` rankValues) -- Most valuable victim should be first.+ negate . toRational . (`Input.RankValues.findRankValue` rankValues) -- Most valuable victim should be first. ) ranks == ranks ) . map head . Data.List.group . Data.Maybe.mapMaybe ( Attribute.MoveType.getMaybeImplicitlyTakenRank . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove ) . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Attribute.RankValues.findRankValue` rankValues)+ Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues) ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let@@ -130,14 +130,14 @@ ( \ranks -> uncurry (++) ( Control.Arrow.first (- Data.List.sortOn (`Attribute.RankValues.findRankValue` rankValues) -- Least valuable aggressor should be first.+ Data.List.sortOn (`Input.RankValues.findRankValue` rankValues) -- Least valuable aggressor should be first. ) $ Data.List.partition (/= Attribute.Rank.King) ranks ) == ranks ) . map head . Data.List.group . map Component.Turn.getRank {-aggressor's rank-} ) . Data.List.groupBy ( ToolShed.Data.List.equalityBy $ Attribute.MoveType.getMaybeImplicitlyTakenRank . Component.QualifiedMove.getMoveType . Component.Turn.getQualifiedMove ) . takeWhile Component.Turn.isCapture . Data.List.sortBy (- Component.Turn.compareByMVVLVA (`Attribute.RankValues.findRankValue` rankValues)+ Component.Turn.compareByMVVLVA (`Input.RankValues.findRankValue` rankValues) ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f ]
src-test/BishBosh/Test/QuickCheck/Component/Zobrist.hs view
@@ -35,7 +35,8 @@ 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.Types as T+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@@ -43,22 +44,20 @@ import qualified Test.QuickCheck -- | Defines a concrete type for testing.-type Zobrist = Component.Zobrist.Zobrist T.X T.Y T.PositionHash+type Zobrist = Component.Zobrist.Zobrist 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 positionHash, System.Random.Random positionHash ) => Test.QuickCheck.Arbitrary (Component.Zobrist.Zobrist x y 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 'T.PositionHash'.+ `mod` 3 -- CAVEAT: this value is limited by the width of 'Crypto.PositionHash'. ) ) Test.QuickCheck.arbitrary <*> fmap System.Random.mkStdGen Test.QuickCheck.arbitrary
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGN.hs view
@@ -42,15 +42,17 @@ 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.Types as T+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 */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly #endif @@ -72,7 +74,7 @@ return {-to Gen-monad-} [c, i, j] -- | Defines a concrete type for testing.-type PGN = ContextualNotation.PGN.PGN T.X T.Y+type PGN = ContextualNotation.PGN.PGN Type.Length.X Type.Length.Y instance ( Enum x,@@ -125,14 +127,14 @@ f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> Test.QuickCheck.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 == 1 (Model.Game.listTurns game ==) . Model.Game.listTurns-#else /* Plain */- either (const False) ((Model.Game.listTurns game ==) . Model.Game.listTurns)-#endif+# else /* Plain */+ (const False ||| (Model.Game.listTurns game ==) . Model.Game.listTurns)+# endif . fst {-discard unparsed text-} . Poly.runParser moveTextParser #else /* Parsec */- either (const False) ((Model.Game.listTurns game ==) . Model.Game.listTurns) . Text.ParserCombinators.Parsec.parse moveTextParser "Move-text parser"+ (const False ||| (Model.Game.listTurns game ==) . Model.Game.listTurns) . Text.ParserCombinators.Parsec.parse moveTextParser "Move-text parser" #endif $ ContextualNotation.PGN.showsMoveText game "" where@@ -142,14 +144,14 @@ f :: Bool -> ContextualNotation.StandardAlgebraic.ValidateMoves -> 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 == 1 (== pgn)-#else /* Plain */- either (const False) (== pgn)-#endif+# else /* Plain */+ (const False ||| (== pgn))+# endif . fst {-discard unparsed text-} . Poly.runParser parser #else /* Parsec */- either (const False) (== pgn) . Text.ParserCombinators.Parsec.parse parser "PGN parser"+ (const False ||| (== pgn)) . Text.ParserCombinators.Parsec.parse parser "PGN parser" #endif . unlines . ( \l -> zipWith (++) l $ map (showChar '\t' . show) pgnComments ++ repeat "" {-pad comment-list with null lines-}@@ -158,3 +160,4 @@ parser = ContextualNotation.PGN.parser isStrictlySequential validateMoves [ficsGamesDBGameNoTag, ecoCodeTag] in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f ]+
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PGNComment.hs view
@@ -33,10 +33,12 @@ 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 */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly #endif @@ -54,17 +56,18 @@ 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 == 1 (== s)-#else /* Plain */- either (const False) (== s)-#endif+# else /* Plain */+ (const False ||| (== s))+# endif . fst {-discard unparsed text-} . Poly.runParser ContextualNotation.PGNComment.parser #else /* Parsec */- either (const False) (== s) . Text.ParserCombinators.Parsec.parse ContextualNotation.PGNComment.parser "PGN parser"+ (const False ||| (== s)) . Text.ParserCombinators.Parsec.parse ContextualNotation.PGNComment.parser "PGN parser" #endif $ show pgnComment where s = ContextualNotation.PGNComment.getString pgnComment in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]+
src-test/BishBosh/Test/QuickCheck/ContextualNotation/PositionHashQualifiedMoveTree.hs view
@@ -42,7 +42,8 @@ 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.Types as T+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@@ -53,7 +54,7 @@ import Test.QuickCheck((==>)) -- | Defines a concrete type for testing.-type PositionHashQualifiedMoveTree = ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree T.X T.Y T.PositionHash+type PositionHashQualifiedMoveTree = ContextualNotation.PositionHashQualifiedMoveTree.PositionHashQualifiedMoveTree Type.Length.X Type.Length.Y Type.Crypto.PositionHash instance ( Data.Array.IArray.Ix x,@@ -61,9 +62,7 @@ Enum x, Enum y, Num positionHash,- Ord x, Ord y,- Show positionHash, Show x, Show y, System.Random.Random positionHash@@ -87,3 +86,4 @@ ) . tail {-drop the default game-} . Data.Tree.flatten . Model.GameTree.deconstruct $ ContextualNotation.QualifiedMoveForest.toGameTree qualifiedMoveForest in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f ]+
src-test/BishBosh/Test/QuickCheck/ContextualNotation/QualifiedMoveForest.hs view
@@ -38,7 +38,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.Foldable import qualified Data.Tree import qualified Test.QuickCheck@@ -56,7 +56,7 @@ arbitrary = fmap ContextualNotation.QualifiedMoveForest.fromPGNDatabase Test.QuickCheck.arbitrary -- | Defines a concrete type for testing.-type QualifiedMoveForest = ContextualNotation.QualifiedMoveForest.QualifiedMoveForest T.X T.Y+type QualifiedMoveForest = ContextualNotation.QualifiedMoveForest.QualifiedMoveForest Type.Length.X Type.Length.Y -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]@@ -72,7 +72,7 @@ let f :: QualifiedMoveForest -> Test.QuickCheck.Property f qualifiedMoveForest = not (Property.Null.isNull qualifiedMoveForest) ==> Test.QuickCheck.label "QualifiedMoveForest.prop_count" . uncurry (==) $ (- snd {-nMoves-} . ContextualNotation.QualifiedMoveForest.count &&& length . tail {-remove the apex-} . Data.Tree.flatten . Model.GameTree.deconstruct . ContextualNotation.QualifiedMoveForest.toGameTree+ snd {-nPositions-} . ContextualNotation.QualifiedMoveForest.count &&& fromIntegral . length . tail {-remove the apex-} . Data.Tree.flatten . Model.GameTree.deconstruct . ContextualNotation.QualifiedMoveForest.toGameTree ) qualifiedMoveForest in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f ]
src-test/BishBosh/Test/QuickCheck/ContextualNotation/StandardAlgebraic.hs view
@@ -38,12 +38,14 @@ #ifdef USE_POLYPARSE import Control.Arrow((***))-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 import qualified Text.ParserCombinators.Poly.Lazy as Poly-#else /* Plain */+# else /* Plain */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Poly.Plain as Poly-#endif+# endif #else /* Parsec */+import Control.Arrow((|||)) import qualified Text.ParserCombinators.Parsec #endif @@ -62,19 +64,19 @@ in #ifdef USE_POLYPARSE uncurry (&&) . (-#if USE_POLYPARSE == 1+# if USE_POLYPARSE == 1 (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove *** null {-unparsed input-}-#else /* Plain */- either (const False) (- (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove+# else /* Plain */+ (+ const False ||| (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove ) *** null {-unparsed input-}-#endif+# endif ) . Poly.runParser ( ContextualNotation.StandardAlgebraic.parser explicitEnPassant validateMoves game' ) #else /* Parsec */- either (const False) (- (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove+ (+ const False ||| (== qualifiedMove) . ContextualNotation.StandardAlgebraic.getQualifiedMove ) . Text.ParserCombinators.Parsec.parse ( ContextualNotation.StandardAlgebraic.parser explicitEnPassant validateMoves game' ) "SAN-parser"@@ -83,3 +85,4 @@ ) $ Model.Game.rollBack game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 512 } f ]+
src-test/BishBosh/Test/QuickCheck/Evaluation/PositionHashQuantifiedGameTree.hs view
@@ -39,7 +39,9 @@ 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.Types as T+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 import qualified Data.Tree@@ -60,7 +62,7 @@ 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 T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean+ } 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.@@ -78,7 +80,7 @@ -> 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 T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean -> State.Position.Position T.X T.Y+ 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 ) ) matches where matches = filter (@@ -97,7 +99,8 @@ 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 T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean -> T.WeightedMean+ Evaluation.QuantifiedGame.getFitness . Evaluation.PositionHashQuantifiedGameTree.getQuantifiedGame :: Evaluation.PositionHashQuantifiedGameTree.NodeLabel Type.Length.X Type.Length.Y 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 ]+
src-test/BishBosh/Test/QuickCheck/Input/CECPFeatures.hs view
@@ -25,7 +25,7 @@ module BishBosh.Test.QuickCheck.Input.CECPFeatures() where -import Control.Arrow((***))+import Control.Arrow((***), (+++)) import qualified BishBosh.Input.CECPFeatures as Input.CECPFeatures import qualified Data.Char import qualified Data.List@@ -40,10 +40,8 @@ ) . filter ( not . null . fst {-key-} ) . map (- filter Data.Char.isAlpha *** either (- Left . (`mod` 3)- ) (- Right . filter Data.Char.isAlphaNum+ filter Data.Char.isAlpha *** (+ (`mod` 3) +++ filter Data.Char.isAlphaNum ) ) <$> Test.QuickCheck.arbitrary ) <*> Test.QuickCheck.arbitrary {-done-}
src-test/BishBosh/Test/QuickCheck/Input/CECPOptions.hs view
@@ -26,9 +26,10 @@ module BishBosh.Test.QuickCheck.Input.CECPOptions() where import BishBosh.Test.QuickCheck.Input.CECPFeatures()+import BishBosh.Test.QuickCheck.Time.StopWatch() import qualified BishBosh.Input.CECPOptions as Input.CECPOptions import qualified Test.QuickCheck instance Test.QuickCheck.Arbitrary Input.CECPOptions.CECPOptions where- arbitrary = Input.CECPOptions.mkCECPOptions <$> Test.QuickCheck.arbitrary {-analyseMode-} <*> Test.QuickCheck.arbitrary {-displaySAN-} <*> Test.QuickCheck.arbitrary {-editMode-} <*> Test.QuickCheck.arbitrary {-forceMode-} <*> fmap (fmap $ toEnum . abs) Test.QuickCheck.arbitrary {-Maybe pause-} <*> Test.QuickCheck.arbitrary {-ponderMode-} <*> Test.QuickCheck.arbitrary {-postMode-} <*> Test.QuickCheck.elements [1 .. 3] {-protocolVersion-} <*> Test.QuickCheck.arbitrary {-CECPFeatures-}+ arbitrary = Input.CECPOptions.mkCECPOptions <$> Test.QuickCheck.arbitrary {-analyseMode-} <*> Test.QuickCheck.arbitrary {-displaySAN-} <*> Test.QuickCheck.arbitrary {-editMode-} <*> Test.QuickCheck.arbitrary {-forceMode-} <*> Test.QuickCheck.arbitrary {-Maybe pause-} <*> Test.QuickCheck.arbitrary {-ponderMode-} <*> Test.QuickCheck.arbitrary {-postMode-} <*> Test.QuickCheck.elements [1 .. 3] {-protocolVersion-} <*> Test.QuickCheck.arbitrary {-CECPFeatures-}
src-test/BishBosh/Test/QuickCheck/Input/CriteriaWeights.hs view
@@ -25,33 +25,30 @@ -} module BishBosh.Test.QuickCheck.Input.CriteriaWeights(--- * Types--- ** Type-synonyms--- CriteriaWeights, -- * Constants results ) where -import BishBosh.Test.QuickCheck.Attribute.CriterionWeight()+import BishBosh.Test.QuickCheck.Metric.CriterionWeight() import qualified BishBosh.Input.CriteriaWeights as Input.CriteriaWeights-import qualified BishBosh.Types as T import qualified Test.QuickCheck -instance (- Fractional criterionWeight,- Ord criterionWeight,- Show criterionWeight- ) => Test.QuickCheck.Arbitrary (Input.CriteriaWeights.CriteriaWeights criterionWeight) where- arbitrary = Input.CriteriaWeights.mkCriteriaWeights <$> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary <*> Test.QuickCheck.arbitrary---- | Defines a concrete type for testing.-type CriteriaWeights = Input.CriteriaWeights.CriteriaWeights T.CriterionWeight+instance Test.QuickCheck.Arbitrary Input.CriteriaWeights.CriteriaWeights where+ arbitrary = Input.CriteriaWeights.mkCriteriaWeights+ <$> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary+ <*> Test.QuickCheck.arbitrary -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: CriteriaWeights -> Test.QuickCheck.Property+ f :: Input.CriteriaWeights.CriteriaWeights -> Test.QuickCheck.Property f criteriaWeights = Test.QuickCheck.label "CriteriaWeights.prop_normalise" . (== maxBound) . maximum $ map ($ criteriaWeights') [ Input.CriteriaWeights.getWeightOfMaterial, Input.CriteriaWeights.getWeightOfMobility,@@ -66,3 +63,4 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f ]+
src-test/BishBosh/Test/QuickCheck/Input/EvaluationOptions.hs view
@@ -33,9 +33,9 @@ import BishBosh.Data.Bool() import BishBosh.Test.QuickCheck.Attribute.Rank()-import BishBosh.Test.QuickCheck.Attribute.RankValues() import BishBosh.Test.QuickCheck.Input.CriteriaWeights() import BishBosh.Test.QuickCheck.Input.PieceSquareTable()+import BishBosh.Test.QuickCheck.Input.RankValues() import Control.Arrow((&&&)) import qualified BishBosh.Component.PieceSquareByCoordinatesByRank as Component.PieceSquareByCoordinatesByRank import qualified BishBosh.Input.CriteriaWeights as Input.CriteriaWeights@@ -46,7 +46,8 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Type.Mass as Type.Mass import qualified Data.Array.IArray import qualified Data.List import qualified Data.Map@@ -55,24 +56,17 @@ import Test.QuickCheck((==>)) -- | Defines a concrete type for testing.-type EvaluationOptions = Input.EvaluationOptions.EvaluationOptions T.CriterionWeight T.PieceSquareValue T.RankValue T.X T.Y+type EvaluationOptions = Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y instance (- Enum x,- Enum y,- Fractional criterionWeight,- Fractional pieceSquareValue,- Fractional rankValue,- Ord pieceSquareValue,- Ord rankValue,- Ord x,- Ord y,- Real criterionWeight,- Show criterionWeight,- Show pieceSquareValue,- Show rankValue,- Test.QuickCheck.Arbitrary rankValue- ) => Test.QuickCheck.Arbitrary (Input.EvaluationOptions.EvaluationOptions criterionWeight pieceSquareValue rankValue x y) where+ 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 #-} arbitrary = do criteriaWeights <- Test.QuickCheck.arbitrary@@ -101,7 +95,7 @@ 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 T.CriterionWeight Rational {-precision is required-} T.RankValue T.X T.Y -> Test.QuickCheck.State.Board.Board -> Test.QuickCheck.Property+ f :: Input.EvaluationOptions.EvaluationOptions Rational {-precision is required-} Type.Length.X Type.Length.Y -> Test.QuickCheck.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
src-test/BishBosh/Test/QuickCheck/Input/IOOptions.hs view
@@ -34,12 +34,7 @@ import qualified Test.QuickCheck import System.FilePath((</>), (<.>)) -instance (- Integral column,- Integral row,- Show column,- Show row- ) => Test.QuickCheck.Arbitrary (Input.IOOptions.IOOptions row column) where+instance Test.QuickCheck.Arbitrary Input.IOOptions.IOOptions where arbitrary = do maybePGNOptions <- Test.QuickCheck.arbitrary
src-test/BishBosh/Test/QuickCheck/Input/NativeUIOptions.hs view
@@ -30,13 +30,10 @@ import qualified Data.Default import qualified Test.QuickCheck -instance (- Integral column,- Integral row,- Show column,- Show row- ) => Test.QuickCheck.Arbitrary (Input.NativeUIOptions.NativeUIOptions row column) where+instance Test.QuickCheck.Arbitrary Input.NativeUIOptions.NativeUIOptions where arbitrary = Input.NativeUIOptions.mkNativeUIOptions <$> fmap (- fromInteger . succ . (* 2) . (`mod` 3) *** fromInteger . succ . (* 2) . (`mod` 3)- ) Test.QuickCheck.arbitrary {-BoardMagnification-} <*> return {-to Gen-monad-} Data.Default.def {-ColourScheme-}+ mkOddNaturalNumber *** mkOddNaturalNumber+ ) Test.QuickCheck.arbitrary {-BoardMagnification-} <*> return {-to Gen-monad-} Data.Default.def {-ColourScheme-} where+ mkOddNaturalNumber :: Num n => Integer -> n+ mkOddNaturalNumber = fromInteger . succ . (* 2) . (`mod` 3)
src-test/BishBosh/Test/QuickCheck/Input/Options.hs view
@@ -26,8 +26,6 @@ module BishBosh.Test.QuickCheck.Input.Options( -- * Types -- ** Type-synonyms--- Row,--- Column, Options, -- * Constants results@@ -37,46 +35,28 @@ import BishBosh.Test.QuickCheck.Input.IOOptions() import BishBosh.Test.QuickCheck.Input.SearchOptions() import qualified BishBosh.Input.Options as Input.Options-import qualified BishBosh.Types as T+import qualified BishBosh.Type.Length as Type.Length+import qualified BishBosh.Type.Mass as Type.Mass import qualified Test.QuickCheck -- | Defines a concrete type for testing.-type Row = T.Y---- | Defines a concrete type for testing.-type Column = T.X---- | Defines a concrete type for testing.-type Options = Input.Options.Options Column T.CriterionWeight T.PieceSquareValue T.RankValue Row T.X T.Y+type Options = Input.Options.Options Type.Mass.PieceSquareValue Type.Length.X Type.Length.Y instance (- Enum pieceSquareValue,- Fractional criterionWeight,- Fractional pieceSquareValue,- Fractional rankValue,- Integral column,- Integral row,- Ord pieceSquareValue,- Ord rankValue,- Enum x,- Enum y,- Ord x,- Ord y,- Real criterionWeight,- Show column,- Show criterionWeight,- Show pieceSquareValue,- Show rankValue,- Show row,- Test.QuickCheck.Arbitrary pieceSquareValue,- Test.QuickCheck.Arbitrary rankValue- ) => Test.QuickCheck.Arbitrary (Input.Options.Options column criterionWeight pieceSquareValue rankValue row x y) where+ 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 #-} arbitrary = do (maybeMaximumPlies, maybeRandomSeed, evaluationOptions, searchOptions, ioOptions) <- Test.QuickCheck.arbitrary return {-to Gen-monad-} $ Input.Options.mkOptions (- fmap (succ . abs) maybeMaximumPlies+ fmap (fromInteger . succ . abs) maybeMaximumPlies ) maybeRandomSeed evaluationOptions searchOptions ioOptions -- | The constant test-results for this data-type.
src-test/BishBosh/Test/QuickCheck/Input/PGNOptions.hs view
@@ -40,5 +40,5 @@ ["FICSGamesDBGameNo"], ["ECO"], ["FICSGamesDBGameNo", "ECO"]- ] <*> fmap (`mod` 128) Test.QuickCheck.arbitrary {-minimumPlies-} <*> Test.QuickCheck.elements (Nothing : map Just [1 .. 10]) {-maybeMaximumGames-}+ ] <*> fmap (fromInteger . (`mod` 128)) Test.QuickCheck.arbitrary {-minimumPlies-} <*> Test.QuickCheck.elements (Nothing : map Just [1 .. 10]) {-maybeMaximumGames-}
src-test/BishBosh/Test/QuickCheck/Input/PieceSquareTable.hs view
@@ -37,13 +37,14 @@ 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.Types as T+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 T.X T.Y T.PieceSquareValue+type PieceSquareTable = Input.PieceSquareTable.PieceSquareTable Type.Length.X Type.Length.Y Type.Mass.PieceSquareValue instance ( Enum x,@@ -76,7 +77,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: Input.PieceSquareTable.Assocs Attribute.Rank.Rank T.PieceSquareValue -> Test.QuickCheck.Property+ f :: Input.PieceSquareTable.Assocs Attribute.Rank.Rank Type.Mass.PieceSquareValue -> Test.QuickCheck.Property f assocs = length (Data.List.nub $ concatMap snd assocs) > 1 ==> Test.QuickCheck.label "PieceSquareTable.prop_closedUnitInterval" . Input.PieceSquareTable.inClosedUnitInterval $ Input.PieceSquareTable.normaliseToUnitInterval assocs in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let
+ src-test/BishBosh/Test/QuickCheck/Input/RankValues.hs view
@@ -0,0 +1,37 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.+-}++module BishBosh.Test.QuickCheck.Input.RankValues() where++import BishBosh.Test.QuickCheck.Metric.RankValue()+import qualified BishBosh.Attribute.Rank as Attribute.Rank+import qualified BishBosh.Input.RankValues as Input.RankValues+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified Data.List+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Input.RankValues.RankValues where+ arbitrary = Input.RankValues.fromAssocs . zip Property.FixedMembership.members . Data.List.sort {-ensures Q is most valuable (except K)-} <$> Test.QuickCheck.vector (fromIntegral Attribute.Rank.nDistinctRanks)+
src-test/BishBosh/Test/QuickCheck/Input/SearchOptions.hs view
@@ -37,24 +37,24 @@ instance Test.QuickCheck.Arbitrary Input.SearchOptions.SearchOptions where arbitrary = do searchDepthByLogicalColour <- Data.Map.map (- (+ Input.SearchOptions.minimumSearchDepth) . (`mod` 4)+ (+ Input.SearchOptions.minimumSearchDepth) . fromInteger . (`mod` 4) ) <$> Test.QuickCheck.arbitrary Input.SearchOptions.mkSearchOptions <$> Test.QuickCheck.arbitrary {-SortOnStandardOpeningMoveFrequency-} <*> Test.QuickCheck.arbitrary {-maybeCaptureMoveSortAlgorithm-} <*> ( fmap (succ . (`mod` 3)) <$> Test.QuickCheck.arbitrary -- maybeMinimumHammingDistance. ) <*> (- fmap (`mod` 4) <$> Test.QuickCheck.arbitrary -- maybeRetireKillerMovesAfter.+ fmap (fromInteger . (`mod` 4)) <$> Test.QuickCheck.arbitrary -- maybeRetireKillerMovesAfter. ) <*> Test.QuickCheck.arbitrary {-trapRepeatedPositions-} <*> ( if Data.Map.size searchDepthByLogicalColour == 1 then Test.QuickCheck.arbitrary else return {-to Gen-monad-} False -- UsePondering. ) <*> ( fmap (- (`mod` 3) *** (+ fromInteger . (`mod` 3) *** ( if Data.Map.null searchDepthByLogicalColour then id else min $ Data.Foldable.maximum searchDepthByLogicalColour- ) . succ . (`mod` 3)+ ) . fromInteger . succ . (`mod` 3) ) <$> Test.QuickCheck.arbitrary {-maybeUseTranspositions-} ) <*> Test.QuickCheck.arbitrary {-standardOpeningOptions-} <*> return {-to Gen-monad-} searchDepthByLogicalColour
src-test/BishBosh/Test/QuickCheck/Input/UIOptions.hs view
@@ -29,19 +29,15 @@ import BishBosh.Test.QuickCheck.Input.NativeUIOptions() import BishBosh.Test.QuickCheck.Input.Verbosity() import BishBosh.Test.QuickCheck.Notation.MoveNotation()+import Control.Arrow((|||)) import qualified BishBosh.Input.UIOptions as Input.UIOptions import qualified BishBosh.Notation.MoveNotation as Notation.MoveNotation import qualified Test.QuickCheck -instance (- Integral column,- Integral row,- Show column,- Show row- ) => Test.QuickCheck.Arbitrary (Input.UIOptions.UIOptions row column) where+instance Test.QuickCheck.Arbitrary Input.UIOptions.UIOptions where arbitrary = do eitherNativeUIOrCECPOptions <- Test.QuickCheck.arbitrary- moveNotation <- const Test.QuickCheck.arbitrary `either` const (return {-to Gen-monad-} Notation.MoveNotation.pureCoordinate) $ eitherNativeUIOrCECPOptions+ moveNotation <- const Test.QuickCheck.arbitrary ||| const (return {-to Gen-monad-} Notation.MoveNotation.pureCoordinate) $ eitherNativeUIOrCECPOptions Input.UIOptions.mkUIOptions moveNotation <$> fmap ( fmap $ succ . (`mod` 3) -- maybePrintMoveTree.
src-test/BishBosh/Test/QuickCheck/Input/Verbosity.hs view
@@ -31,3 +31,4 @@ instance Test.QuickCheck.Arbitrary Input.Verbosity.Verbosity where arbitrary = Test.QuickCheck.elements Property.FixedMembership.members+
+ src-test/BishBosh/Test/QuickCheck/Metric/CriterionWeight.hs view
@@ -0,0 +1,33 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.+-}++module BishBosh.Test.QuickCheck.Metric.CriterionWeight() where++import qualified BishBosh.Metric.CriterionWeight as Metric.CriterionWeight+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Metric.CriterionWeight.CriterionWeight where+ arbitrary = Test.QuickCheck.elements $ map fromRational [0, recip 10 .. 1]+
+ src-test/BishBosh/Test/QuickCheck/Metric/RankValue.hs view
@@ -0,0 +1,56 @@+{-# 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' & defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.Metric.RankValue(+-- * Constants+ results+) where++import qualified BishBosh.Metric.RankValue as Metric.RankValue+import qualified Test.QuickCheck+import qualified ToolShed.Test.ReversibleIO++instance Test.QuickCheck.Arbitrary Metric.RankValue.RankValue where+ arbitrary = Test.QuickCheck.elements $ map fromRational [0, recip 10 .. 1]++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Metric.RankValue.RankValue -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "RankValue.prop_readPrependedWhiteSpace" . ToolShed.Test.ReversibleIO.readPrependedWhiteSpace+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 32 } f,+ let+ f :: String -> Test.QuickCheck.Property+ f garbage = Test.QuickCheck.label "RankValue.prop_read" $ case (reads garbage :: [(Metric.RankValue.RankValue, 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 :: Metric.RankValue.RankValue -> String -> Test.QuickCheck.Property+ f rankValue = Test.QuickCheck.label "RankValue.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (`elem` ".-+eEoOxX" ++ ['0' .. '9']) rankValue+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f+ ]+
− src-test/BishBosh/Test/QuickCheck/Model/DrawReason.hs
@@ -1,34 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.--}--module BishBosh.Test.QuickCheck.Model.DrawReason() where--import qualified BishBosh.Model.DrawReason as Model.DrawReason-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified Test.QuickCheck--instance Test.QuickCheck.Arbitrary Model.DrawReason.DrawReason where- arbitrary = Test.QuickCheck.elements Property.FixedMembership.members-
src-test/BishBosh/Test/QuickCheck/Model/Game.hs view
@@ -41,20 +41,21 @@ 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.DrawReason as Model.DrawReason 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.Types as T+import qualified BishBosh.Type.Count as Type.Count+import qualified BishBosh.Type.Length as Type.Length import qualified Data.Array.IArray import qualified Data.Default import qualified Data.Foldable@@ -70,7 +71,7 @@ import Test.QuickCheck((==>)) -- | Defines a concrete type for testing.-type Game = Model.Game.Game T.X T.Y+type Game = Model.Game.Game Type.Length.X Type.Length.Y instance ( Enum x,@@ -118,16 +119,16 @@ let f :: Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen/Half move clock" $ uncurry (&&) . (- (>= 0) &&& (<= Model.DrawReason.maximumConsecutiveRepeatablePlies)- ) . read . (+ (>= 0) &&& (<= Rule.DrawReason.maximumConsecutiveRepeatablePlies)+ ) . fromInteger . read . ( !! 4 -- Half-move Clock. ) . words $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f, let f :: Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_fen/Full move counter" $ (- > (0 :: Component.Move.NMoves)- ) . read . (+ > (0 :: Type.Count.NMoves)+ ) . fromInteger . read . ( !! 5 -- Full Move Counter. ) . words $ Property.ForsythEdwards.showFEN game in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,@@ -208,11 +209,11 @@ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 4096 } f, let f :: Game -> Test.QuickCheck.Property- f game = Test.QuickCheck.label "Game.prop_(findQualifiedMovesAvailableTo => countMovesAvailableTo)" $ all (- \logicalColour -> Model.Game.countMovesAvailableTo logicalColour game == (+ f game = Test.QuickCheck.label "Game.prop_(findQualifiedMovesAvailableTo => countPliesAvailableTo)" $ all (+ \logicalColour -> Model.Game.countPliesAvailableTo logicalColour game == ( if Model.Game.isTerminated game then 0- else length $ Model.Game.findQualifiedMovesAvailableTo logicalColour game+ else fromIntegral . length $ Model.Game.findQualifiedMovesAvailableTo logicalColour game ) ) Property.FixedMembership.members in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,@@ -237,8 +238,8 @@ let f :: Game -> Test.QuickCheck.Property f game = Test.QuickCheck.label "Game.prop_(getCoordinatesByRankByLogicalColour => getNPawnsByFileByLogicalColour)" . all (- \(logicalColour, nPawnsByFile) -> Data.Foldable.sum nPawnsByFile == length (- State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn $ State.Board.getCoordinatesByRankByLogicalColour board+ \(logicalColour, nPawnsByFile) -> Data.Foldable.sum nPawnsByFile == fromIntegral (+ length . State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn $ State.Board.getCoordinatesByRankByLogicalColour board ) ) . Data.Array.IArray.assocs $ State.Board.getNPawnsByFileByLogicalColour board where board = Model.Game.getBoard game
− src-test/BishBosh/Test/QuickCheck/Model/GameTerminationReason.hs
@@ -1,48 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.--}--module BishBosh.Test.QuickCheck.Model.GameTerminationReason(--- * Constants- results-) where--import Control.Arrow((&&&))-import qualified BishBosh.Model.GameTerminationReason as Model.GameTerminationReason-import qualified BishBosh.Property.FixedMembership as Property.FixedMembership-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Test.QuickCheck--instance Test.QuickCheck.Arbitrary Model.GameTerminationReason.GameTerminationReason where- arbitrary = Test.QuickCheck.elements Property.FixedMembership.members---- | The constant test-results for this data-type.-results :: IO [Test.QuickCheck.Result]-results = sequence [- let- f :: Model.GameTerminationReason.GameTerminationReason -> Test.QuickCheck.Property- f = Test.QuickCheck.label "GameTerminationReason.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f- ]-
src-test/BishBosh/Test/QuickCheck/Model/GameTree.hs view
@@ -35,7 +35,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.Default import qualified Data.Maybe import qualified Test.QuickCheck@@ -47,7 +47,7 @@ fmap (Property.Arboreal.prune depth . Model.GameTree.fromGame) Test.QuickCheck.arbitrary -- | Define a concrete type for testing.-type GameTree = Model.GameTree.GameTree T.X T.Y+type GameTree = Model.GameTree.GameTree Type.Length.X Type.Length.Y -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]@@ -61,3 +61,4 @@ ) . Model.Game.listTurnsChronologically in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 64 } f ]+
src-test/BishBosh/Test/QuickCheck/Model/MoveFrequency.hs view
@@ -27,13 +27,10 @@ results ) where -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.State.TurnsByLogicalColour as State.TurnsByLogicalColour import qualified BishBosh.Test.QuickCheck.Model.GameTree as Test.QuickCheck.Model.GameTree import qualified Data.Foldable-import qualified Data.Tree import qualified Test.QuickCheck -- | The constant test-results for this data-type.@@ -43,10 +40,9 @@ f :: Test.QuickCheck.Model.GameTree.GameTree -> Test.QuickCheck.Property f gameTree = Test.QuickCheck.label "MoveFrequency.prop_countMoves" $ Model.MoveFrequency.countEntries ( Model.GameTree.toMoveFrequency gameTree- ) == State.TurnsByLogicalColour.getNPlies (- Model.Game.getTurnsByLogicalColour . Data.Tree.rootLabel $ Model.GameTree.deconstruct gameTree- ) + pred {-the apex is counted in 'getNPlies'-} (- Data.Foldable.length $ Model.GameTree.deconstruct gameTree+ ) == pred {-the apex is counted in 'getNPlies'-} (+ fromIntegral . Data.Foldable.length $ Model.GameTree.deconstruct gameTree ) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 16 } f ]+
− src-test/BishBosh/Test/QuickCheck/Model/Result.hs
@@ -1,63 +0,0 @@-{-# OPTIONS_GHC -fno-warn-orphans #-}-{-- Copyright (C) 2018 Dr. Alistair Ward-- This file is part of BishBosh.-- BishBosh is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- BishBosh is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with BishBosh. If not, see <http://www.gnu.org/licenses/>.--}-{- |- [@AUTHOR@] Dr. Alistair Ward-- [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.--}--module BishBosh.Test.QuickCheck.Model.Result(--- * Constants- results-) where--import BishBosh.Test.QuickCheck.Attribute.LogicalColour()-import Control.Arrow((&&&))-import qualified BishBosh.Model.Result as Model.Result-import qualified BishBosh.Property.Opposable as Property.Opposable-import qualified Test.QuickCheck-import qualified ToolShed.Test.ReversibleIO--instance Test.QuickCheck.Arbitrary Model.Result.Result where- arbitrary = Model.Result.mkResult `fmap` Test.QuickCheck.oneof [fmap Just Test.QuickCheck.arbitrary, return {-to Gen-monad-} Nothing]---- | The constant test-results for this data-type.-results :: IO [Test.QuickCheck.Result]-results = sequence [- let- f :: Model.Result.Result -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Result.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 "Result.prop_read" $ case (reads garbage :: [(Model.Result.Result, 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 :: Model.Result.Result -> String -> Test.QuickCheck.Property- f result = Test.QuickCheck.label "Result.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) result- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,- let- f :: Model.Result.Result -> Test.QuickCheck.Property- f = Test.QuickCheck.label "Result.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)- in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f- ]-
src-test/BishBosh/Test/QuickCheck/Notation/ICCFNumeric.hs view
@@ -39,12 +39,12 @@ 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.Types as T+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 T.X T.Y+type ICCFNumeric = Notation.ICCFNumeric.ICCFNumeric Type.Length.X Type.Length.Y instance ( Enum x,@@ -92,3 +92,4 @@ ) coordinate in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 2048 } f ]+
src-test/BishBosh/Test/QuickCheck/Notation/MoveNotation.hs view
@@ -31,3 +31,4 @@ instance Test.QuickCheck.Arbitrary Notation.MoveNotation.MoveNotation where arbitrary = Test.QuickCheck.elements Property.FixedMembership.members+
src-test/BishBosh/Test/QuickCheck/Notation/PureCoordinate.hs view
@@ -39,13 +39,13 @@ 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.Types as T+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 T.X T.Y+type PureCoordinate = Notation.PureCoordinate.PureCoordinate Type.Length.X Type.Length.Y instance ( Enum x,@@ -95,3 +95,4 @@ ) coordinate in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 2048 } f ]+
src-test/BishBosh/Test/QuickCheck/Notation/Smith.hs view
@@ -34,12 +34,12 @@ 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.Types as T+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 T.X T.Y+type Smith = Notation.Smith.Smith Type.Length.X Type.Length.Y instance ( Enum x,@@ -70,3 +70,4 @@ 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/Rule/DrawReason.hs view
@@ -0,0 +1,34 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary'.+-}++module BishBosh.Test.QuickCheck.Rule.DrawReason() where++import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Rule.DrawReason as Rule.DrawReason+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Rule.DrawReason.DrawReason where+ arbitrary = Test.QuickCheck.elements Property.FixedMembership.members+
+ src-test/BishBosh/Test/QuickCheck/Rule/GameTerminationReason.hs view
@@ -0,0 +1,48 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.Rule.GameTerminationReason(+-- * Constants+ results+) where++import Control.Arrow((&&&))+import qualified BishBosh.Property.FixedMembership as Property.FixedMembership+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Rule.GameTerminationReason as Rule.GameTerminationReason+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Rule.GameTerminationReason.GameTerminationReason where+ arbitrary = Test.QuickCheck.elements Property.FixedMembership.members++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Rule.GameTerminationReason.GameTerminationReason -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "GameTerminationReason.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f+ ]+
+ src-test/BishBosh/Test/QuickCheck/Rule/Result.hs view
@@ -0,0 +1,63 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+{-+ Copyright (C) 2018 Dr. Alistair Ward++ This file is part of BishBosh.++ BishBosh is free software: you can redistribute it and/or modify+ it under the terms of the GNU General Public License as published by+ the Free Software Foundation, either version 3 of the License, or+ (at your option) any later version.++ BishBosh is distributed in the hope that it will be useful,+ but WITHOUT ANY WARRANTY; without even the implied warranty of+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+ GNU General Public License for more details.++ You should have received a copy of the GNU General Public License+ along with BishBosh. If not, see <http://www.gnu.org/licenses/>.+-}+{- |+ [@AUTHOR@] Dr. Alistair Ward++ [@DESCRIPTION@] Implements 'Test.QuickCheck.Arbitrary' & defines /QuickCheck/-properties.+-}++module BishBosh.Test.QuickCheck.Rule.Result(+-- * Constants+ results+) where++import BishBosh.Test.QuickCheck.Attribute.LogicalColour()+import Control.Arrow((&&&))+import qualified BishBosh.Property.Opposable as Property.Opposable+import qualified BishBosh.Rule.Result as Rule.Result+import qualified Test.QuickCheck+import qualified ToolShed.Test.ReversibleIO++instance Test.QuickCheck.Arbitrary Rule.Result.Result where+ arbitrary = Rule.Result.mkResult `fmap` Test.QuickCheck.oneof [fmap Just Test.QuickCheck.arbitrary, return {-to Gen-monad-} Nothing]++-- | The constant test-results for this data-type.+results :: IO [Test.QuickCheck.Result]+results = sequence [+ let+ f :: Rule.Result.Result -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Result.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 "Result.prop_read" $ case (reads garbage :: [(Rule.Result.Result, 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 :: Rule.Result.Result -> String -> Test.QuickCheck.Property+ f result = Test.QuickCheck.label "Result.prop_readTrailingGarbage" . ToolShed.Test.ReversibleIO.readTrailingGarbage (const False) result+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,+ let+ f :: Rule.Result.Result -> Test.QuickCheck.Property+ f = Test.QuickCheck.label "Result.prop_getOpposite" . uncurry (==) . (Property.Opposable.getOpposite . Property.Opposable.getOpposite &&& id)+ in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 8 } f+ ]+
src-test/BishBosh/Test/QuickCheck/Search/KillerMoves.hs view
@@ -37,41 +37,38 @@ import BishBosh.Test.QuickCheck.Component.Turn() import Control.Arrow((&&&))-import qualified BishBosh.Component.Move as Component.Move import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Search.DynamicMoveData as Search.DynamicMoveData import qualified BishBosh.Search.EphemeralData as Search.EphemeralData import qualified BishBosh.Search.KillerMoves as Search.KillerMoves-import qualified BishBosh.Types as T+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 T.X T.Y+type KillerMoveKey = Search.DynamicMoveData.KillerMoveKey Type.Length.X Type.Length.Y instance (- Enum x,- Enum y,- Ord x,- Ord y,- Test.QuickCheck.Arbitrary x,- Test.QuickCheck.Arbitrary y+ Enum x,+ Enum y,+ Ord x,+ Ord y ) => Test.QuickCheck.Arbitrary (Search.DynamicMoveData.KillerMoveKey x y) where -- {-# SPECIALISE instance Test.QuickCheck.Arbitrary KillerMoveKey #-} arbitrary = fmap Search.DynamicMoveData.mkKillerMoveKeyFromTurn Test.QuickCheck.arbitrary --- |-normalise :: Int -> Component.Move.NPlies-normalise = succ . (`mod` 4)+-- | Map the integer-domain into a smaller non-negative number of plies.+normalise :: Integral i => i -> Type.Count.NPlies+normalise = fromIntegral . succ . (`mod` 4) -- |-populate :: Ord key => [(Component.Move.NPlies, key)] -> Search.KillerMoves.KillerMoves key+populate :: Ord key => [(Int, key)] -> Search.KillerMoves.KillerMoves key 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 instance (- Enum key, Ord key, Test.QuickCheck.Arbitrary key ) => Test.QuickCheck.Arbitrary (Search.KillerMoves.KillerMoves key) where@@ -81,7 +78,7 @@ results :: IO [Test.QuickCheck.Result] results = sequence [ let- f :: [(Component.Move.NPlies, KillerMoveKey)] -> Test.QuickCheck.Property+ f :: [(Int, 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
@@ -50,7 +50,7 @@ let f :: Input.SearchOptions.SearchOptions- -> Input.SearchOptions.SearchDepth+ -> Int -- ^ Search-depth. -> Test.QuickCheck.Search.SearchState.SearchState -> Test.QuickCheck.Property f searchOptions searchDepth searchState = searchOptions /= Data.Default.def && not (@@ -65,7 +65,7 @@ } - getQuantifiedGames = Search.Search.getQuantifiedGames . Control.Monad.Reader.runReader (Search.Search.search (Input.SearchOptions.minimumSearchDepth + mod searchDepth 3) searchState)+ getQuantifiedGames = Search.Search.getQuantifiedGames . Control.Monad.Reader.runReader (Search.Search.search (Input.SearchOptions.minimumSearchDepth + fromIntegral (searchDepth `mod` 3)) searchState) in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 128 } f ]
src-test/BishBosh/Test/QuickCheck/Search/SearchState.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, ScopedTypeVariables #-}+{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} {- Copyright (C) 2018 Dr. Alistair Ward@@ -38,48 +38,37 @@ import qualified BishBosh.Input.EvaluationOptions as Input.EvaluationOptions import qualified BishBosh.Property.Empty as Property.Empty import qualified BishBosh.Search.SearchState as Search.SearchState-import qualified BishBosh.Types as T+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 -#ifdef USE_PARALLEL-import qualified Control.DeepSeq-#endif- -- | A suitable concrete type for testing.-type SearchState = Search.SearchState.SearchState T.X T.Y T.PositionHash T.CriterionValue T.WeightedMean+type SearchState = Search.SearchState.SearchState Type.Length.X Type.Length.Y Type.Crypto.PositionHash -instance forall x y positionHash criterionValue weightedMean. (-#ifdef USE_PARALLEL- Control.DeepSeq.NFData criterionValue,-#endif+instance forall x y positionHash. ( Data.Array.IArray.Ix x, Data.Bits.FiniteBits positionHash,- Fractional criterionValue,- Fractional weightedMean, Integral x, Integral y, Num positionHash,- Real criterionValue,- Real weightedMean, Show positionHash, Show x, Show y, System.Random.Random positionHash,- Test.QuickCheck.Arbitrary criterionValue,- Test.QuickCheck.Arbitrary weightedMean, Test.QuickCheck.Arbitrary x, Test.QuickCheck.Arbitrary y- ) => Test.QuickCheck.Arbitrary (Search.SearchState.SearchState x y positionHash criterionValue weightedMean) where+ ) => Test.QuickCheck.Arbitrary (Search.SearchState.SearchState x y positionHash) where {-# SPECIALISE instance Test.QuickCheck.Arbitrary SearchState #-} arbitrary = do evaluationOptions <- Test.QuickCheck.arbitrary Search.SearchState.initialise <$> ( Evaluation.PositionHashQuantifiedGameTree.mkPositionHashQuantifiedGameTree (- evaluationOptions :: Input.EvaluationOptions.EvaluationOptions T.CriterionWeight T.PieceSquareValue T.RankValue x y+ evaluationOptions :: Input.EvaluationOptions.EvaluationOptions Type.Mass.PieceSquareValue x y ) <$> 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
@@ -52,7 +52,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Control.Monad import qualified Data.Foldable import qualified Data.List@@ -64,7 +64,7 @@ import qualified ToolShed.Test.ReversibleIO -- | Defines a concrete type for testing.-type Board = State.Board.Board T.X T.Y+type Board = State.Board.Board Type.Length.X Type.Length.Y instance ( Enum x,@@ -196,7 +196,7 @@ uncurry (==) . ( Data.Foldable.sum . ( State.CoordinatesByRankByLogicalColour.countPawnsByFileByLogicalColour coordinatesByRankByLogicalColour !- ) &&& length . (+ ) &&& fromIntegral . length . ( \logicalColour -> State.CoordinatesByRankByLogicalColour.dereference logicalColour Attribute.Rank.Pawn coordinatesByRankByLogicalColour ) )
src-test/BishBosh/Test/QuickCheck/State/CastleableRooksByLogicalColour.hs view
@@ -41,7 +41,7 @@ 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.Types as T+import qualified BishBosh.Type.Length as Type.Length import qualified Data.List import qualified Data.List.Extra import qualified Test.QuickCheck@@ -62,7 +62,7 @@ ] -- List-comprehension. -- | Defines a concrete type for testing.-type CastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour T.X+type CastleableRooksByLogicalColour = State.CastleableRooksByLogicalColour.CastleableRooksByLogicalColour Type.Length.X -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/BishBosh/Test/QuickCheck/State/InstancesByPosition.hs view
@@ -40,7 +40,7 @@ f :: Test.QuickCheck.Model.Game.Game -> Test.QuickCheck.Property f = Test.QuickCheck.label "InstancesByPosition.prop_countPositionRepetitions" . uncurry (==) . ( State.InstancesByPosition.countPositionRepetitions &&& uncurry (-) . (- succ . State.InstancesByPosition.countConsecutiveRepeatablePlies &&& State.InstancesByPosition.getNDistinctPositions+ succ . fromIntegral . State.InstancesByPosition.countConsecutiveRepeatablePlies &&& State.InstancesByPosition.getNDistinctPositions ) ) . Model.Game.getInstancesByPosition in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 256 } f,
src-test/BishBosh/Test/QuickCheck/State/TurnsByLogicalColour.hs view
@@ -39,12 +39,12 @@ 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.Types as T+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 T.X T.Y)+type TurnsByLogicalColour = State.TurnsByLogicalColour.TurnsByLogicalColour (Component.Turn.Turn Type.Length.X Type.Length.Y) instance ( Show a,
+ src-test/BishBosh/Test/QuickCheck/Time/StopWatch.hs view
@@ -0,0 +1,33 @@+{-# 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.Time.StopWatch() where++import qualified BishBosh.Time.StopWatch as Time.StopWatch+import qualified Test.QuickCheck++instance Test.QuickCheck.Arbitrary Time.StopWatch.StopWatch where+ arbitrary = Time.StopWatch.mkStoppedWatch . toEnum <$> Test.QuickCheck.arbitrary+
src-test/BishBosh/Test/QuickCheck/UI/Command.hs view
@@ -33,12 +33,12 @@ import BishBosh.Test.QuickCheck.UI.PrintObject() import BishBosh.Test.QuickCheck.UI.SetObject()-import qualified BishBosh.Types as T+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 T.X T.Y+type Command = UI.Command.Command Type.Length.X Type.Length.Y instance Test.QuickCheck.Arbitrary (UI.Command.Command x y) where arbitrary = Test.QuickCheck.oneof [
src-test/BishBosh/Test/QuickCheck/UI/PrintObject.hs view
@@ -58,3 +58,4 @@ ) printObject in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f ]+
src-test/BishBosh/Test/QuickCheck/UI/ReportObject.hs view
@@ -58,3 +58,4 @@ ) reportObject in Test.QuickCheck.quickCheckWithResult Test.QuickCheck.stdArgs { Test.QuickCheck.maxSuccess = 1024 } f ]+
src-test/BishBosh/Test/QuickCheck/UI/SetObject.hs view
@@ -34,7 +34,7 @@ import qualified ToolShed.Test.ReversibleIO instance Test.QuickCheck.Arbitrary UI.SetObject.SetObject where- arbitrary = fmap (UI.SetObject.SearchDepth . (+ Input.SearchOptions.minimumSearchDepth) . (`mod` 4)) Test.QuickCheck.arbitrary+ arbitrary = fmap (UI.SetObject.mkSearchDepth . (+ Input.SearchOptions.minimumSearchDepth) . fromInteger . (`mod` 4)) Test.QuickCheck.arbitrary -- | The constant test-results for this data-type. results :: IO [Test.QuickCheck.Result]
src-test/HUnit.hs view
@@ -44,6 +44,8 @@ import qualified BishBosh.Test.HUnit.Model.PositionHashTree as Test.HUnit.Model.PositionHashTree 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@@ -63,6 +65,8 @@ Test.HUnit.Component.Move.testCases, Test.HUnit.Component.CastlingMove.testCases, Test.HUnit.Component.Zobrist.testCases,+ Test.HUnit.Time.StopWatch.testCases,+ Test.HUnit.Time.GameClock.testCases, Test.HUnit.State.Board.testCases, Test.HUnit.Model.Game.testCases, Test.HUnit.Model.GameTree.testCases,
src-test/QuickCheck.hs view
@@ -47,14 +47,15 @@ import qualified BishBosh.Test.QuickCheck.Input.EvaluationOptions as Test.QuickCheck.Input.EvaluationOptions import qualified BishBosh.Test.QuickCheck.Input.Options as Test.QuickCheck.Input.Options import qualified BishBosh.Test.QuickCheck.Input.PieceSquareTable as Test.QuickCheck.Input.PieceSquareTable+import qualified BishBosh.Test.QuickCheck.Metric.RankValue as Test.QuickCheck.Metric.RankValue import qualified BishBosh.Test.QuickCheck.Model.Game as Test.QuickCheck.Model.Game-import qualified BishBosh.Test.QuickCheck.Model.GameTerminationReason as Test.QuickCheck.Model.GameTerminationReason 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.Model.Result as Test.QuickCheck.Model.Result import qualified BishBosh.Test.QuickCheck.Notation.ICCFNumeric as Test.QuickCheck.Notation.ICCFNumeric 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+import qualified BishBosh.Test.QuickCheck.Rule.Result as Test.QuickCheck.Rule.Result import qualified BishBosh.Test.QuickCheck.Search.KillerMoves as Test.QuickCheck.Search.KillerMoves -- import qualified BishBosh.Test.QuickCheck.Search.Search as Test.QuickCheck.Search.Search import qualified BishBosh.Test.QuickCheck.State.Board as Test.QuickCheck.State.Board@@ -83,7 +84,6 @@ Test.QuickCheck.Attribute.Direction.results, Test.QuickCheck.Attribute.Rank.results, Test.QuickCheck.Attribute.MoveType.results,- Test.QuickCheck.Input.CriteriaWeights.results, Test.QuickCheck.Input.EvaluationOptions.results, Test.QuickCheck.Input.Options.results, Test.QuickCheck.Input.PieceSquareTable.results,@@ -93,11 +93,11 @@ Test.QuickCheck.Component.Move.results, Test.QuickCheck.Component.QualifiedMove.results, Test.QuickCheck.Component.Turn.results,+ Test.QuickCheck.Rule.GameTerminationReason.results,+ Test.QuickCheck.Rule.Result.results, Test.QuickCheck.Notation.ICCFNumeric.results, Test.QuickCheck.Notation.PureCoordinate.results, Test.QuickCheck.Notation.Smith.results,- Test.QuickCheck.Model.GameTerminationReason.results,- Test.QuickCheck.Model.Result.results, Test.QuickCheck.State.CastleableRooksByLogicalColour.results, Test.QuickCheck.State.Position.results, Test.QuickCheck.State.InstancesByPosition.results,@@ -113,6 +113,8 @@ Test.QuickCheck.ContextualNotation.PGNComment.results, Test.QuickCheck.ContextualNotation.PGN.results, Test.QuickCheck.ContextualNotation.QualifiedMoveForest.results,+ Test.QuickCheck.Input.CriteriaWeights.results,+ Test.QuickCheck.Metric.RankValue.results, Test.QuickCheck.Evaluation.PositionHashQuantifiedGameTree.results, Test.QuickCheck.Search.KillerMoves.results, Test.QuickCheck.UI.PrintObject.results,