{- 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 . -} {- | [@AUTHOR@] Dr. Alistair Ward [@DESCRIPTION@] Implements various move-notations . -} module BishBosh.Notation.MoveNotation( -- * Type-classes ShowNotation(..), ShowNotationFloat(..), -- * Types -- ** Data-types MoveNotation(), -- * Constants tag, coordinate, range, -- * Functions readsQualifiedMove, showNotation, showsMoveSyntax, getOrigin, showsNotationFloatToNDecimals, -- ** Predicates isCoordinate ) where import Control.Arrow((&&&)) import qualified BishBosh.Attribute.Rank as Attribute.Rank import qualified BishBosh.Cartesian.Coordinates as Cartesian.Coordinates import qualified BishBosh.Component.EitherQualifiedMove as Component.EitherQualifiedMove import qualified BishBosh.Component.QualifiedMove as Component.QualifiedMove import qualified BishBosh.Component.Turn as Component.Turn import qualified BishBosh.Notation.Coordinate as Notation.Coordinate import qualified BishBosh.Notation.ICCFNumeric as Notation.ICCFNumeric import qualified BishBosh.Notation.Smith as Notation.Smith import qualified BishBosh.Property.ShowFloat as Property.ShowFloat 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 -- | Used to qualify XML. tag :: String tag = "moveNotation" {- | * Identifies the move-notations which can be used. * /Standard Algebraic/ isn't included here because conversion to or from a /QualifiedMove/ requires access to the /game/. -} data MoveNotation = Coordinate -- ^ As used for communication with /xboard/. | ICCFNumeric -- ^ . | Smith -- ^ . deriving (Eq, Read, Show) instance Control.DeepSeq.NFData MoveNotation where rnf _ = () instance Data.Default.Default MoveNotation where def = Smith instance HXT.XmlPickler MoveNotation where xpickle = HXT.xpDefault Data.Default.def . HXT.xpWrap (read, show) . HXT.xpAttr tag . HXT.xpTextDT . Text.XML.HXT.Arrow.Pickle.Schema.scEnum $ map show range -- CAVEAT: whether it'll be used as an XML-attribute or an XML-element isn't currently known. -- | Constant. coordinate :: MoveNotation coordinate = Coordinate -- | The constant complete range of values. range :: [MoveNotation] range = [Coordinate, ICCFNumeric, Smith] -- | Reads a /move/ & /move-type/ from the specified 'MoveNotation'. readsQualifiedMove :: ( Enum x, Enum y, Ord x, Ord y ) => MoveNotation -> ReadS (Component.EitherQualifiedMove.EitherQualifiedMove x y) readsQualifiedMove Coordinate = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkPartiallyQualifiedMove . (Notation.Coordinate.getMove &&& Attribute.Rank.getMaybePromotionRank)) . reads readsQualifiedMove ICCFNumeric = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkPartiallyQualifiedMove . (Notation.ICCFNumeric.getMove &&& Attribute.Rank.getMaybePromotionRank)) . reads readsQualifiedMove Smith = map (Control.Arrow.first $ uncurry Component.EitherQualifiedMove.mkFullyQualifiedMove . (Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType) . Notation.Smith.getQualifiedMove) . reads -- | Show the syntax required by a specific 'MoveNotation'. showsMoveSyntax :: MoveNotation -> ShowS showsMoveSyntax moveNotation = showChar '/' . showString ( case moveNotation of Coordinate -> Notation.Coordinate.regexSyntax ICCFNumeric -> Notation.ICCFNumeric.regexSyntax Smith -> Notation.Smith.regexSyntax ) . showChar '/' -- | Returns the origin of the specified coordinate-system. getOrigin :: MoveNotation -> (Int, Int) getOrigin Coordinate = Notation.Coordinate.origin getOrigin ICCFNumeric = Notation.ICCFNumeric.origin getOrigin Smith = Notation.Smith.origin -- | Predicate. isCoordinate :: MoveNotation -> Bool isCoordinate Coordinate = True isCoordinate _ = False -- | An interface for types which can be rendered in a chess-notation. class ShowNotation a where showsNotation :: MoveNotation -> a -> ShowS instance (Enum x, Enum y) => ShowNotation (Component.QualifiedMove.QualifiedMove x y) where showsNotation moveNotation qualifiedMove = case moveNotation of Coordinate -> shows $ Notation.Coordinate.mkCoordinate' move moveType ICCFNumeric -> shows $ Notation.ICCFNumeric.mkICCFNumeric' move moveType Smith -> shows $ Notation.Smith.fromQualifiedMove qualifiedMove where (move, moveType) = Component.QualifiedMove.getMove &&& Component.QualifiedMove.getMoveType $ qualifiedMove instance (Enum x, Enum y) => ShowNotation (Component.Turn.Turn x y) where showsNotation moveNotation = showsNotation moveNotation . Component.Turn.getQualifiedMove instance (Enum x, Enum y) => ShowNotation (Cartesian.Coordinates.Coordinates x y) where showsNotation Coordinate = Notation.Coordinate.showsCoordinates showsNotation ICCFNumeric = Notation.ICCFNumeric.showsCoordinates showsNotation Smith = Notation.Smith.showsCoordinates -- | Show an arbitrary datum using the specified notation. showNotation :: (ShowNotation a) => MoveNotation -> a -> String showNotation moveNotation = ($ "") . showsNotation moveNotation -- | An alternative to 'Property.ShowFloat.ShowFloat', which permits access to a specific move-notation. class ShowNotationFloat a where 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)