{-|
This module has only one function 'playGo' that asks
user for size as input, creates a game and starts the game window.
-}
module Go(playGo) where
import Data.Map
import BoardGo
import Graphics.Gloss
import Graphics.Gloss.Interface.IO.Game
-- | 'PlayGo' functions asks for size of board, creates a 'Game' object and starts the game display
playGo :: IO ()
playGo = do
putStrLn "Please enter the size of the board - 9 13 or 19"
sizeString <- getLine
let size = read sizeString
-- If invalid size is given then ask again
if size /= 9 && size /= 13 && size /= 19 then playGo else do
let game = createGame size
let window = InWindow "Go Window" (20 * size + 180, 20 * size +240) (10, 10)
play window (dark yellow) 0 game render handleEvent (\_ y -> y)
-- | 'handleEvent' handles mouse click and keyboard events
handleEvent :: Event -> Game -> Game
-- ^ If clicked on point on alive game, then check if valid move and play the move
handleEvent (EventKey (MouseButton LeftButton) Down _ (x, y)) game@(Game _ lm s _ _ Alive)
| validMove game p st = playMove (removeKo game) p st
where p = BoardGo.Point (round ((x + 10*(fromIntegral s+1))/20)) (round ((-1*y + 10*(fromIntegral s+1))/20))
st = getOppositeStoneFromLastMove lm
-- ^ If p is pressed on keyboard on alive game then play pass by current stone
handleEvent (EventKey (Char 'p') Down _ _) game@(Game _ lm s _ _ Alive)
| lm == Pass Black = killGame game
| otherwise = playPass (removeKo game) st
where st = getOppositeStoneFromLastMove lm
-- ^ If clicked on point on dead game then take the point as part of hopeless string
handleEvent (EventKey (MouseButton LeftButton) Down _ (x, y)) game@(Game m lm s sb sw Dead) = Game (removePiece m (BoardGo.Point x' y')) lm s sb' sw' Dead
where x' = round ((x + 10*(fromIntegral s+1))/20)
y' = round ((-1*y + 10*(fromIntegral s+1))/20)
sb' = if seekBoard game (BoardGo.Point x' y') == White then sb+1 else sb
sw' = if seekBoard game (BoardGo.Point x' y') == Black then sw+1 else sw
-- ^ If e is pressed on keyboard on dead group then end the game
handleEvent (EventKey (Char 'e') Down _ _) game@(Game _ lm s _ _ Dead) = finishGame game
-- ^ Ignore all other events
handleEvent _ game = game
-- | This function returns opposite stone from given 'Move'
getOppositeStoneFromLastMove :: Move -> Stone
getOppositeStoneFromLastMove (Move _ st) = getOppositeStone st
getOppositeStoneFromLastMove (Pass st) = getOppositeStone st
-- | 'render' functions gives picture of the Game that will be displayed on the window
render :: Game -> Picture
render game@(Game m lm s sb sw status) = pictures [ (pictures gameHorizontalLines), (pictures gameVerticalLines), (pictures stones), scoreBlack, scoreWhite, statusText]
where -- Horizontal and vertical lines of the board
gameHorizontalLines = [line [(fromIntegral (10 - 10*s),fromIntegral (10*s - 10 - 20*x)), (fromIntegral (20*s - 10 - 10*s),fromIntegral (10*s - 10 - 20*x))] | x <- [0..(s-1)]]
gameVerticalLines = [line [(fromIntegral (10*s - 10 - 20*x),fromIntegral (10 - 10*s)), (fromIntegral (10*s - 10 - 20*x),fromIntegral (-10*s + 20*s - 10))] | x <- [0..(s-1)]]
-- All stones present on the game
stones = [translate (fromIntegral (x*20 - 10*s-10)) (fromIntegral (10*s - y*20 + 10)) $ color c $ circleSolid 8 | (BoardGo.Point x y, st) <- (assocs m) , c <- [black,white], ((st == Black && c == black) || (st == White && c == white))]
-- Score of black stone
scoreBlack = translate 0 (fromIntegral (10*s + 40)) $ scale 0.1 0.1 $ text $ "Black's Score : " ++ (show sb)
-- Score of White stone
scoreWhite = translate 0 (fromIntegral (10*s + 60)) $ scale 0.1 0.1 $ text $ "White's Score : " ++ (show sw)
-- Display tirn if game is alive or instruction for capturing hopeless strings if game is dead oe winner if game is over
statusText = if status == Alive then translate (fromIntegral (-10*s)) (fromIntegral (-10*s - 60)) $ scale 0.2 0.2 $ text $ (show $ getOppositeStone (getPiece lm)) ++ "'s turn"
else if status == Dead then translate (fromIntegral (-10*s)) (fromIntegral (-10*s - 60)) $ scale 0.1 0.1 $ text "Click on hopeless stones and enter e"
else translate (fromIntegral (-10*s)) (fromIntegral (-10*s - 60)) $ scale 0.2 0.2 $ text $ getWinner game