-- |
-- Module      :  Chess.FEN
-- Copyright   :  Miika-Petteri Matikainen 2014
-- License     :  GPL-2
--
-- Maintainer  :  miikapetteri@gmail.com
-- Stability   :  experimental
-- Portability :  unknown
--
-- Parsing chess games from FEN notation
-- (https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation).
module Chess.FEN (writeFEN, readFEN) where

import Chess.Internal.Move
import Chess.Internal.FEN

-- | Write the current game state as FEN notation
writeFEN :: GameState -> String
writeFEN :: GameState -> String
writeFEN GameState
state = [String] -> String
unwords [Board -> String
writeBoard (GameState -> Board
stateBoard GameState
state),
                          Color -> String
writePlayer (GameState -> Color
currentPlayer GameState
state),
                          [CastlingType] -> [CastlingType] -> String
writeCastlings (GameState -> [CastlingType]
whiteCastlingsPossible GameState
state) (GameState -> [CastlingType]
blackCastlingsPossible GameState
state),
                          Maybe Coordinates -> String
writeEnPassant (GameState -> Maybe Coordinates
enPassantSquare GameState
state),
                          Integer -> String
forall a. Show a => a -> String
show (GameState -> Integer
halfmoveClock GameState
state),
                          Integer -> String
forall a. Show a => a -> String
show (GameState -> Integer
moveNumber GameState
state)]

-- | Parse game state from FEN notation
readFEN :: String -> Maybe GameState
readFEN :: String -> Maybe GameState
readFEN String
str | [String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
parts Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
6 = Maybe GameState
forall a. Maybe a
Nothing
            | Bool
otherwise = do Board
board' <- String -> Maybe Board
readBoard (String -> Maybe Board) -> String -> Maybe Board
forall a b. (a -> b) -> a -> b
$ [String] -> String
forall a. [a] -> a
head [String]
parts
                             Color
player <- String -> Maybe Color
readPlayer (String -> Maybe Color) -> String -> Maybe Color
forall a b. (a -> b) -> a -> b
$ [String]
parts [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
1
                             ([CastlingType], [CastlingType])
castlings <- String -> Maybe ([CastlingType], [CastlingType])
readCastlings (String -> Maybe ([CastlingType], [CastlingType]))
-> String -> Maybe ([CastlingType], [CastlingType])
forall a b. (a -> b) -> a -> b
$ [String]
parts [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
2
                             Maybe Coordinates
enPassant <- String -> Maybe (Maybe Coordinates)
readEnPassant (String -> Maybe (Maybe Coordinates))
-> String -> Maybe (Maybe Coordinates)
forall a b. (a -> b) -> a -> b
$ [String]
parts [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
3
                             Integer
halfmoves <- Integer -> String -> Maybe Integer
forall a. (Ord a, Read a) => a -> String -> Maybe a
readNumberWithLimit Integer
0 (String -> Maybe Integer) -> String -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ [String]
parts [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
4
                             Integer
moves <- Integer -> String -> Maybe Integer
forall a. (Ord a, Read a) => a -> String -> Maybe a
readNumberWithLimit Integer
1 (String -> Maybe Integer) -> String -> Maybe Integer
forall a b. (a -> b) -> a -> b
$ [String]
parts [String] -> Int -> String
forall a. [a] -> Int -> a
!! Int
5
                             GameState -> Maybe GameState
forall (m :: * -> *) a. Monad m => a -> m a
return (GameState -> Maybe GameState) -> GameState -> Maybe GameState
forall a b. (a -> b) -> a -> b
$ ([CastlingType]
 -> [CastlingType]
 -> Maybe Coordinates
 -> Integer
 -> Integer
 -> GameState)
-> ([CastlingType], [CastlingType])
-> Maybe Coordinates
-> Integer
-> Integer
-> GameState
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry (Board
-> Color
-> [CastlingType]
-> [CastlingType]
-> Maybe Coordinates
-> Integer
-> Integer
-> GameState
State Board
board' Color
player) ([CastlingType], [CastlingType])
castlings Maybe Coordinates
enPassant Integer
halfmoves Integer
moves
        where parts :: [String]
parts = String -> [String]
words String
str