packages feed

snorkels-0.2.0.0: src/Snorkels/Types.hs

module Snorkels.Types ( Position
                      , Snorkel (..)
                      , Player
                      , Group (..)
                      , Piece (..)
                      , Game (..)
                      , isSnorkel
                      , getPlayer
                      , isBlocking
                      , PlayerType (..)
                      ) where

import qualified Data.Bimap as Bimap
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set


-- | Some (x, y) coordinate on the board
type Position = (Int, Int)


-- | Some player's pieces' color
data Snorkel = Green | Purple | Red | Yellow | Cyan
    deriving (Show, Eq, Ord, Enum, Read)


-- | Each player has a distinctive color
type Player = Snorkel


-- | 
-- An horizontally or vertically connected group of 'Snorkel's that belong to
-- the same 'Player'
data Group = Group { positions :: Set.Set Position
                   , player :: Player
                   } deriving (Show, Eq, Ord)


-- |
-- Any type of piece on the board: either a 'Snorkel' or a 'Stone'
data Piece = Snorkel Snorkel | Stone
    deriving (Show, Eq)


-- This is just a shortcut for (isJust . getPlayer)
-- | Check whether the 'Piece' is a 'Snorkel'
isSnorkel :: Piece -> Bool
isSnorkel Stone = False
isSnorkel _ = True


-- | Get the player owning the 'Piece' or 'Nothing' if the piece is a 'Stone'
getPlayer :: Piece -> Maybe Player
getPlayer Stone = Nothing
getPlayer (Snorkel p) = Just p


-- | 
-- Check whether the contents of a given 'Position' on the board suppose a block
-- for a given 'Player'. Only 'Stone's and 'Snorkel's from a different 'Player'
-- suppose a block.
isBlocking :: Player -> Maybe Piece -> Bool
isBlocking _ Nothing = False
isBlocking player (Just piece) = maybe True (/= player) (getPlayer piece)


data PlayerType = PlayerType {
    -- | Maybe print an error message and get a position to move to or a quit.
      getMove :: Game -> Maybe String -> IO (Maybe Position)
    -- | Maybe print an error message and get a player to switch to.
    , getSwitch :: Game -> Maybe String -> IO Player
    -- | Report the player about the winner of the game
    , reportWinner :: Game -> Player -> IO ()
    -- | Only one of the playertypes marked as local is notified about the
    -- winner. FIXME: There must be a cleverer way of doing this.
    , isLocal :: Bool
}


data Game = Game { 
    -- | Only 'Position's occupied by 'Piece's are here
      pieces :: Map.Map Position Piece
    -- | Width and height limits of the board
    , boardSize :: (Int, Int)
    -- | List of 'Player's that didn't 'Quit'
    , playerTypes :: Map.Map Player PlayerType
    -- | 'Player' that plays next
    , currentPlayer :: Player
    -- | Map of what each player chooses to be when asked to switch
    , switches :: Bimap.Bimap Player Player
}