module Game.Chess.Internal.Square (
  IsSquare(..), Sq(..), isDark, isLight, toCoord
) where

import Data.Bits (Bits(testBit))
import Data.Char (chr, ord)
import Data.Ix (Ix)
import Data.String (IsString(fromString))
import Data.Word

class IsSquare sq where
  toIndex :: sq -> Int
  toRF :: sq -> (Int, Int)
  toRF sq
sq = sq -> Int
forall sq. IsSquare sq => sq -> Int
toIndex sq
sq Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int
8

instance IsSquare Int where
  toIndex :: Int -> Int
toIndex = Int -> Int
forall a. a -> a
id

instance IsSquare (Int, Int) where
  toIndex :: (Int, Int) -> Int
toIndex (Int
r, Int
f) = Int
rInt -> Int -> Int
forall a. Num a => a -> a -> a
*Int
8 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
f
  toRF :: (Int, Int) -> (Int, Int)
toRF = (Int, Int) -> (Int, Int)
forall a. a -> a
id

data Sq = A1 | B1 | C1 | D1 | E1 | F1 | G1 | H1
        | A2 | B2 | C2 | D2 | E2 | F2 | G2 | H2
        | A3 | B3 | C3 | D3 | E3 | F3 | G3 | H3
        | A4 | B4 | C4 | D4 | E4 | F4 | G4 | H4
        | A5 | B5 | C5 | D5 | E5 | F5 | G5 | H5
        | A6 | B6 | C6 | D6 | E6 | F6 | G6 | H6
        | A7 | B7 | C7 | D7 | E7 | F7 | G7 | H7
        | A8 | B8 | C8 | D8 | E8 | F8 | G8 | H8
        deriving (Sq
Sq -> Sq -> Bounded Sq
forall a. a -> a -> Bounded a
maxBound :: Sq
$cmaxBound :: Sq
minBound :: Sq
$cminBound :: Sq
Bounded, Int -> Sq
Sq -> Int
Sq -> [Sq]
Sq -> Sq
Sq -> Sq -> [Sq]
Sq -> Sq -> Sq -> [Sq]
(Sq -> Sq)
-> (Sq -> Sq)
-> (Int -> Sq)
-> (Sq -> Int)
-> (Sq -> [Sq])
-> (Sq -> Sq -> [Sq])
-> (Sq -> Sq -> [Sq])
-> (Sq -> Sq -> Sq -> [Sq])
-> Enum Sq
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: Sq -> Sq -> Sq -> [Sq]
$cenumFromThenTo :: Sq -> Sq -> Sq -> [Sq]
enumFromTo :: Sq -> Sq -> [Sq]
$cenumFromTo :: Sq -> Sq -> [Sq]
enumFromThen :: Sq -> Sq -> [Sq]
$cenumFromThen :: Sq -> Sq -> [Sq]
enumFrom :: Sq -> [Sq]
$cenumFrom :: Sq -> [Sq]
fromEnum :: Sq -> Int
$cfromEnum :: Sq -> Int
toEnum :: Int -> Sq
$ctoEnum :: Int -> Sq
pred :: Sq -> Sq
$cpred :: Sq -> Sq
succ :: Sq -> Sq
$csucc :: Sq -> Sq
Enum, Sq -> Sq -> Bool
(Sq -> Sq -> Bool) -> (Sq -> Sq -> Bool) -> Eq Sq
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Sq -> Sq -> Bool
$c/= :: Sq -> Sq -> Bool
== :: Sq -> Sq -> Bool
$c== :: Sq -> Sq -> Bool
Eq, Ord Sq
Ord Sq
-> ((Sq, Sq) -> [Sq])
-> ((Sq, Sq) -> Sq -> Int)
-> ((Sq, Sq) -> Sq -> Int)
-> ((Sq, Sq) -> Sq -> Bool)
-> ((Sq, Sq) -> Int)
-> ((Sq, Sq) -> Int)
-> Ix Sq
(Sq, Sq) -> Int
(Sq, Sq) -> [Sq]
(Sq, Sq) -> Sq -> Bool
(Sq, Sq) -> Sq -> Int
forall a.
Ord a
-> ((a, a) -> [a])
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Int)
-> ((a, a) -> a -> Bool)
-> ((a, a) -> Int)
-> ((a, a) -> Int)
-> Ix a
unsafeRangeSize :: (Sq, Sq) -> Int
$cunsafeRangeSize :: (Sq, Sq) -> Int
rangeSize :: (Sq, Sq) -> Int
$crangeSize :: (Sq, Sq) -> Int
inRange :: (Sq, Sq) -> Sq -> Bool
$cinRange :: (Sq, Sq) -> Sq -> Bool
unsafeIndex :: (Sq, Sq) -> Sq -> Int
$cunsafeIndex :: (Sq, Sq) -> Sq -> Int
index :: (Sq, Sq) -> Sq -> Int
$cindex :: (Sq, Sq) -> Sq -> Int
range :: (Sq, Sq) -> [Sq]
$crange :: (Sq, Sq) -> [Sq]
$cp1Ix :: Ord Sq
Ix, Eq Sq
Eq Sq
-> (Sq -> Sq -> Ordering)
-> (Sq -> Sq -> Bool)
-> (Sq -> Sq -> Bool)
-> (Sq -> Sq -> Bool)
-> (Sq -> Sq -> Bool)
-> (Sq -> Sq -> Sq)
-> (Sq -> Sq -> Sq)
-> Ord Sq
Sq -> Sq -> Bool
Sq -> Sq -> Ordering
Sq -> Sq -> Sq
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Sq -> Sq -> Sq
$cmin :: Sq -> Sq -> Sq
max :: Sq -> Sq -> Sq
$cmax :: Sq -> Sq -> Sq
>= :: Sq -> Sq -> Bool
$c>= :: Sq -> Sq -> Bool
> :: Sq -> Sq -> Bool
$c> :: Sq -> Sq -> Bool
<= :: Sq -> Sq -> Bool
$c<= :: Sq -> Sq -> Bool
< :: Sq -> Sq -> Bool
$c< :: Sq -> Sq -> Bool
compare :: Sq -> Sq -> Ordering
$ccompare :: Sq -> Sq -> Ordering
$cp1Ord :: Eq Sq
Ord, Int -> Sq -> ShowS
[Sq] -> ShowS
Sq -> String
(Int -> Sq -> ShowS)
-> (Sq -> String) -> ([Sq] -> ShowS) -> Show Sq
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Sq] -> ShowS
$cshowList :: [Sq] -> ShowS
show :: Sq -> String
$cshow :: Sq -> String
showsPrec :: Int -> Sq -> ShowS
$cshowsPrec :: Int -> Sq -> ShowS
Show, ReadPrec [Sq]
ReadPrec Sq
Int -> ReadS Sq
ReadS [Sq]
(Int -> ReadS Sq)
-> ReadS [Sq] -> ReadPrec Sq -> ReadPrec [Sq] -> Read Sq
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Sq]
$creadListPrec :: ReadPrec [Sq]
readPrec :: ReadPrec Sq
$creadPrec :: ReadPrec Sq
readList :: ReadS [Sq]
$creadList :: ReadS [Sq]
readsPrec :: Int -> ReadS Sq
$creadsPrec :: Int -> ReadS Sq
Read)

instance IsSquare Sq where
  toIndex :: Sq -> Int
toIndex = Sq -> Int
forall a. Enum a => a -> Int
fromEnum

toCoord :: (IsSquare sq, IsString s) => sq -> s
toCoord :: sq -> s
toCoord (sq -> (Int, Int)
forall sq. IsSquare sq => sq -> (Int, Int)
toRF -> (Int
r,Int
f)) = String -> s
forall a. IsString a => String -> a
fromString [Int -> Char
chr (Int
f Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Char -> Int
ord Char
'a'), Int -> Char
chr (Int
r Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Char -> Int
ord Char
'1')]

isDark :: IsSquare sq => sq -> Bool
isDark :: sq -> Bool
isDark sq
sq = (Word64
0xaa55aa55aa55aa55 :: Word64) Word64 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
`testBit` sq -> Int
forall sq. IsSquare sq => sq -> Int
toIndex sq
sq

isLight :: IsSquare sq => sq -> Bool
isLight :: sq -> Bool
isLight = Bool -> Bool
not (Bool -> Bool) -> (sq -> Bool) -> sq -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. sq -> Bool
forall sq. IsSquare sq => sq -> Bool
isDark