packages feed

haskell-go-checkers-0.1.1.0: src/Checkers.hs

{-|
    This module has only one function 'playCheckers' that asks
    creates a game and starts the game window.
-}
module Checkers(playCheckers) where

import Data.Map
import BoardCheckers
import Graphics.Gloss
import Graphics.Gloss.Interface.IO.Game

-- | Main function that plays Checkers
playCheckers :: IO()
-- | Play the Game
playCheckers = play window (dark yellow) 0 game render handleEvent (\_ y -> y)
    where -- | The window for 'Game'
          window = InWindow "Checkers Window" (600, 600) (10, 10)
          -- | Get the initial 'BoardMap'
          s = startGame
          -- | Get the starting moves for 'Black'
          moves = validMoves s Black
          -- | Initialize 'Game'
          game = Game s moves Black $ Square (-1) (-1)

-- | Take the 'Game' and return the picture for the "Game"
render :: BoardCheckers.Game -> Picture
-- The final Picture is a collection of blackBoxes, boardBox, greenSquares, blueSquare, pieces, kings
render game@(Game (BoardMap board) moves player (Square x y) ) = pictures [boardBox, (pictures blackboxes), blueSquare, pictures greenSquares, (pictures pieces), (pictures kings), playerBox]
    where -- | Blackboxes of board
          blackboxes = [translate (fromIntegral (2*x -9)*30) (fromIntegral (9-2*y)*30) $ color (greyN 0.25) $ rectangleSolid 60 60 | (Square x y,b) <- assocs board ]
          -- | Pieces on board
          pieces = [translate (fromIntegral (2*x -9)*30) (fromIntegral (9-2*y)*30) $ color c $ circleSolid 24 | (Square x y, Piece pl pt) <- assocs board, c <- [black,red], pl == Black && c == black || pl == Red && c == red]
          -- | Kings on board
          kings = [translate (fromIntegral (2*x -9)*30) (fromIntegral (9-2*y)*30) $ scale 0.17 0.17 $ color white $ text "K" | (Square x y, Piece pl pt) <- assocs board, pt == King]
          -- | Surrounding boardBox
          boardBox = color white $ rectangleSolid 480 480
          -- | Clicked Blue Square
          blueSquare = if x /= (-1) then translate (fromIntegral (2*x -9)*30) (fromIntegral (9-2*y)*30) $ color (light blue) $ rectangleSolid 60 60
                       else translate (fromIntegral (2*x -9)*30) (fromIntegral (9-2*y)*30) $ color (dark yellow) $ rectangleSolid 60 60
          -- | Dest greenSquares
          greenSquares = if x /= (-1) then [ translate (fromIntegral (2*a -9)*30) (fromIntegral (9-2*b)*30) $ color (light green) $ rectangleSolid 60 60 | move <- moves, a <- [1..8], b <- [1..8], getSource move == Square x y, getDestination move == Square a b] else []
          -- | Display turn and log
          playerBox = if length moves == 0 then translate (-100) 270 $ scale 0.2 0.2 $ text $ "Game Over " ++ (if player == Red then "Black wins" else "Red wins")
                      else translate (-100) 270 $ scale 0.2 0.2 $ text $ (if player == Red then "Red's turn" else "Black's turn")

-- | Takes an event and 'Game' and returns the board after the result of this event
handleEvent :: Event -> BoardCheckers.Game -> BoardCheckers.Game
-- | When the left mouse button is pressed ..
handleEvent (EventKey (MouseButton LeftButton) Down _ (x, y)) game@(Game board moves player _)
    | x' < 1 || x' > 8 || y' < 1 || y' > 8 = game -- If pressed outside board do nothing
    | otherwise = Game board moves player $ Square x' y' -- Otherwise update the clicked 'Square'
    where x' = round $ (x+270)/60 -- Get the x coordinate of the clicked square
          y' = round $ (270-y)/60 -- Get the y coordinate of the clicked square
-- | When the left mouse button is unclicked ..
handleEvent (EventKey (MouseButton LeftButton) Up _ (x, y)) game@(Game board moves player (Square x' y'))
    | not isValid = game -- If the move to be done is not a valid move do nothing
    | isJump move && length moreJumps > 0 = Game newBoard moreJumps player $ Square (-1) (-1) -- If the player can continue jumping
    | otherwise = Game newBoard nextMoves nextPlayer $ Square (-1) (-1) -- Else the turn goes to the opposite player
    where (move, isValid) = getMoveFromMoves (Square x' y') (Square x'' y'') moves
          x'' = round $ (x+270)/60 -- Get the x coordinate of the clicked square
          y'' = round $ (270-y)/60 -- Get the y coordinate of the clicked square
          newBoard = playMove board move -- Obtain the new Board by playing the move
          moreJumps = mValidJumps newBoard (Square x'' y'', seekBoard newBoard $ Square x'' y'')  -- Get the jumps possible form the dest 'Sqaure'
          nextPlayer = if player == Red then Black else Red -- Get the next Player
          nextMoves = validMoves newBoard nextPlayer -- Get the moves op the next player
handleEvent _ game = game -- Rest of the events - no response

-- | Takes a src and a dest 'Square' and moves and returns if there is a 'Jump' or a 'March' from src to dest
getMoveFromMoves :: Square -> Square -> [Move] -> (Move, Bool)
getMoveFromMoves src dest moves | not foundMove && not foundJump = (Jump src dest, False) -- If not found set False
                                | not foundMove = (Jump src dest, True) -- If 'Jump' found return the 'Jump' and True
                                | otherwise = (March src dest, True) -- If 'March' found return the 'March' and True
                                where foundMove = elem (March src dest) moves
                                      foundJump = elem (Jump src dest) moves