module Data.TableTennis
( Playable
, Player (..)
, Team (..)
, GameLength (..)
, Game (..)
, Side (..)
, newSinglesGame
, newDoublesGame
, winPoint
, serviceLength
, valueOf
, serviceToChange
, winner
, changeService
, swapSides
) where
class Playable a where
rotateSide :: a -> a
data Player =
Player
{ name :: String
, handicap :: Int
} deriving (Show)
data Team = Team
{ topPlayer :: Player
, bottomPlayer :: Player
} deriving (Show)
instance Playable Player where
rotateSide a = a
instance Playable Team where
rotateSide (Team pTop pBottom) = Team pBottom pTop
data GameLength = Eleven | TwentyOne deriving (Show)
data Game a =
Game
{ leftSide :: a
, rightSide :: a
, leftScore :: Int
, rightScore :: Int
, gameLength :: GameLength
, serving :: Side
} deriving (Show)
data Side = LeftSide | RightSide deriving (Show)
winPoint :: Playable a => Game a -> Side -> Game a
winPoint (Game l r ls rs gl s) LeftSide = Game l r (ls + 1) rs gl s
winPoint (Game l r ls rs gl s) RightSide = Game l r ls (rs + 1) gl s
newSinglesGame :: Player -> Player -> GameLength -> Side -> Game Player
newSinglesGame leftPlayer rightPlayer gameLen side =
Game leftPlayer rightPlayer 0 0 gameLen side
newDoublesGame :: Team -> Team -> GameLength -> Side -> Game Team
newDoublesGame leftTeam rightTeam gameLen side =
Game leftTeam rightTeam 0 0 gameLen side
valueOf :: GameLength -> Int
valueOf Eleven = 11
valueOf TwentyOne = 21
serviceLength :: GameLength -> Int
serviceLength Eleven = 3
serviceLength TwentyOne = 5
serviceToChange :: Playable a => Game a -> Bool
serviceToChange g@(Game _ _ lScore rScore gameLen _)
| ((lScore + rScore) > (valueOf gameLen)) == True = True
| (lScore + rScore) `rem` (serviceLength gameLen) == 0 = True
| otherwise = False
winner :: Playable a => Game a -> Maybe a
winner (Game leftSide rightSide lScore rScore gameLen _)
| (lScore rScore) > 1 && lScore >= (valueOf gameLen) = Just leftSide
| (rScore lScore) > 1 && rScore >= (valueOf gameLen) = Just rightSide
| otherwise = Nothing
where totalScore = lScore + rScore
changeService :: Playable a => Game a -> Game a
changeService g@(Game lSide rSide lScore rScore gameLen LeftSide) =
Game (rotateSide lSide) rSide lScore rScore gameLen RightSide
changeService g@(Game lSide rSide lScore rScore gameLen RightSide) =
Game lSide (rotateSide rSide) lScore rScore gameLen LeftSide
swapSides :: Playable a => Game a -> Game a
swapSides (Game left right lS rS gameLen side) =
Game right left lS rS gameLen side