{-
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@]
* Describes the /y/-axis by which the /board/ is indexed.
* N.B. this coordinate-system is for internal use only, and doesn't attempt to replicate any standard Chess-notation.
-}
module BishBosh.Cartesian.Ordinate(
-- * Constants
yOrigin,
yLength,
yMin,
yMax,
-- yBounds,
yRange,
centre,
-- * Functions
firstRank,
lastRank,
pawnsFirstRank,
enPassantRank,
reflect,
translate,
maybeTranslate,
-- ** Predicates
inBounds
) where
import qualified BishBosh.Attribute.LogicalColour as Attribute.LogicalColour
import qualified BishBosh.Cartesian.Abscissa as Cartesian.Abscissa
import qualified BishBosh.Property.Opposable as Property.Opposable
import qualified BishBosh.Types as T
import qualified Control.Exception
-- | The constant length of the /y/-axis.
yOrigin :: Int
yOrigin = Cartesian.Abscissa.xOrigin -- N.B. it doesn't need to the same.
-- | The constant length of the /y/-axis.
yLength :: T.Distance
yLength = Cartesian.Abscissa.xLength -- Because the board's square.
-- | The constant lower bound of the ordinate.
yMin :: Enum y => y
yMin = toEnum yOrigin
-- | The constant upper bound of the ordinate.
yMax :: Enum y => y
yMax = toEnum $ yOrigin + fromIntegral (pred {-fence-post-} yLength)
-- | The constant bounds of the ordinate.
yBounds :: Enum y => (y, y)
yBounds = (yMin, yMax)
-- | The constant list of ordinates.
yRange :: Enum y => [y]
yRange = uncurry enumFromTo yBounds
{- |
* The constant centre of the span.
* CAVEAT: no square actually exists at this fractional value.
-}
centre :: Fractional centre => centre
centre = fromIntegral (uncurry (+) yBounds :: T.Y) / 2
-- | The /rank/ from which /piece/s conventionally start.
firstRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y
firstRank Attribute.LogicalColour.Black = yMax
firstRank _ = yMin
-- | The final /rank/; i.e. the one on which a @Pawn@ is promoted.
lastRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y
lastRank = firstRank . Property.Opposable.getOpposite
-- | The /rank/ from which @Pawn@s conventionally start.
pawnsFirstRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y
{-# INLINE pawnsFirstRank #-}
pawnsFirstRank Attribute.LogicalColour.Black = pred yMax
pawnsFirstRank _ = succ yMin
-- | The /rank/ from which a @Pawn@ may capture /en-passant/.
enPassantRank :: Enum y => Attribute.LogicalColour.LogicalColour -> y
{-# INLINE enPassantRank #-}
enPassantRank Attribute.LogicalColour.Black = toEnum $ yOrigin + 3
enPassantRank _ = toEnum $ yOrigin + 4
-- | Reflects about the mid-point of the axis.
reflect :: Enum y => y -> y
reflect = toEnum . (
+ (2 * yOrigin + fromIntegral (pred yLength))
) . negate . fromEnum
-- | Predicate.
inBounds :: (Enum y, Ord y) => y -> Bool
{-# INLINE inBounds #-}
inBounds y = y >= yMin && y <= yMax
-- | Translate the specified ordinate.
translate :: (Enum y, Ord y) => (y -> y) -> y -> y
translate transformation = (\y -> Control.Exception.assert (inBounds y) y) . transformation
-- | Where legal, translate the specified ordinate.
maybeTranslate :: (Enum y, Ord y) => (y -> y) -> y -> Maybe y
maybeTranslate transformation = (
\y -> if inBounds y
then Just y
else Nothing
) . transformation