-- |
-- Module      :  Chess
-- Copyright   :  Miika-Petteri Matikainen 2021
-- License     :  GPL-2
--
-- Maintainer  :  miikapetteri@gmail.com
-- Stability   :  experimental
-- Portability :  unknown
--
-- Visualize chess games
module Chess.UI (
             printBoard,
             coordinateNotation
              ) where

import Data.Array
import Data.List
import Data.Char
import Data.Maybe
import Chess.Internal.Board
import Chess.Internal.Piece
import Chess.Internal.Move

-- | Prints the board in ASCII.
--
-- Example for the initial position:
-- @
--
--   +---+---+---+---+---+---+---+---+
-- 8 | r | n | b | q | k | b | n | r |
--   +---+---+---+---+---+---+---+---+
-- 7 | p | p | p | p | p | p | p | p |
--   +---+---+---+---+---+---+---+---+
-- 6 |   |   |   |   |   |   |   |   |
--   +---+---+---+---+---+---+---+---+
-- 5 |   |   |   |   |   |   |   |   |
--   +---+---+---+---+---+---+---+---+
-- 4 |   |   |   |   |   |   |   |   |
--   +---+---+---+---+---+---+---+---+
-- 3 |   |   |   |   |   |   |   |   |
--   +---+---+---+---+---+---+---+---+
-- 2 | P | P | P | P | P | P | P | P |
--   +---+---+---+---+---+---+---+---+
-- 1 | R | N | B | Q | K | B | N | R |
--   +---+---+---+---+---+---+---+---+
--     a   b   c   d   e   f   g   h
--  @
printBoard :: Board -> String
printBoard :: Board -> String
printBoard = String -> String
addCoordinates (String -> String) -> (Board -> String) -> Board -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Square]] -> String
printRows ([[Square]] -> String) -> (Board -> [[Square]]) -> Board -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Square] -> [[Square]]
forall a. [a] -> [[a]]
intoRows ([Square] -> [[Square]])
-> (Board -> [Square]) -> Board -> [[Square]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Board -> [Square]
forall i e. Array i e -> [e]
elems
    where intoRows :: [a] -> [[a]]
intoRows [] = []
          intoRows [a]
xs = Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
take Int
8 [a]
xs [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [a] -> [[a]]
intoRows (Int -> [a] -> [a]
forall a. Int -> [a] -> [a]
drop Int
8 [a]
xs)

addCoordinates :: String -> String
addCoordinates :: String -> String
addCoordinates String
str = [String] -> String
unlines ((String -> String -> String) -> [String] -> [String] -> [String]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith String -> String -> String
forall a. [a] -> [a] -> [a]
(++) [String]
numbers (String -> [String]
lines String
str)) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
chars
    where numbers :: [String]
numbers = String -> [String]
lines (String -> [String]) -> String -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ [String
"  \n" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> Char
intToDigit Int
n Char -> String -> String
forall a. a -> [a] -> [a]
: String
" " | Int
n <- [Int] -> [Int]
forall a. [a] -> [a]
reverse [Int
1..Int
8]] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"  "]
          chars :: String
chars = String
"    a   b   c   d   e   f   g   h\n"

printRows :: [[Square]] -> String
printRows :: [[Square]] -> String
printRows [[Square]]
rows = String
line String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
line (([Square] -> String) -> [[Square]] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map [Square] -> String
printRow [[Square]]
rows) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
line
    where line :: String
line = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat (Int -> String -> [String]
forall a. Int -> a -> [a]
replicate Int
8 String
"+---") String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"+" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"

printRow :: [Square] -> String
printRow :: [Square] -> String
printRow [Square]
row = String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
sep ((Square -> String) -> [Square] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Square -> String
printSquare [Square]
row) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
sep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\n"
    where sep :: String
sep = String
"|"

printSquare :: Square -> String
printSquare :: Square -> String
printSquare Square
Empty = String
"   "
printSquare (Square Piece
p) = String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Piece -> String
printPiece Piece
p String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "

-- | Prints the move in coordinate notation.
-- E.g. "e2-e4", "g1-g3", "b2-c1q"
coordinateNotation :: Move -> String
coordinateNotation :: Move -> String
coordinateNotation (Movement Piece
_ Coordinates
c1 Coordinates
c2) = Coordinates -> String
printCoordinate Coordinates
c1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Coordinates -> String
printCoordinate Coordinates
c2
coordinateNotation (Capture Piece
_ Coordinates
c1 Coordinates
c2) = Coordinates -> String
printCoordinate Coordinates
c1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Coordinates -> String
printCoordinate Coordinates
c2
coordinateNotation (EnPassant Piece
_ Coordinates
c1 Coordinates
c2) = Coordinates -> String
printCoordinate Coordinates
c1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Coordinates -> String
printCoordinate Coordinates
c2
coordinateNotation (PawnDoubleMove Piece
_ Coordinates
c1 Coordinates
c2) = Coordinates -> String
printCoordinate Coordinates
c1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Coordinates -> String
printCoordinate Coordinates
c2
coordinateNotation (Promotion Piece
_ Coordinates
c1 Coordinates
c2 PieceType
p) = Coordinates -> String
printCoordinate Coordinates
c1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Coordinates -> String
printCoordinate Coordinates
c2 String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char -> Char
toLower (Maybe Char -> Char
forall a. HasCallStack => Maybe a -> a
fromJust (PieceType -> [(PieceType, Char)] -> Maybe Char
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup PieceType
p [(PieceType, Char)]
pieceChars))]
coordinateNotation (Castling Color
White CastlingType
Short) = String
"e1-g1"
coordinateNotation (Castling Color
White CastlingType
Long) = String
"e1-c1"
coordinateNotation (Castling Color
Black CastlingType
Short) = String
"e8-g8"
coordinateNotation (Castling Color
Black CastlingType
Long) = String
"e8-c8"