module Wordify.Rules.Player (Player, LetterRack, name, rack, score, makePlayer, increaseScore, giveTiles, tilesOnRack,
removePlayedTiles, removeTiles, hasEmptyRack, tileValues, reduceScore, exchange) where
import Wordify.Rules.Tile
import Data.List
import Data.Maybe
import qualified Data.Map as Map
type Score = Int
type Name = String
data LetterRack = LetterRack [Tile] deriving (Show, Eq)
data Player = Player {name :: Name
, rack :: LetterRack
, score :: Score } deriving (Show, Eq)
makePlayer :: String -> Player
makePlayer playerName = Player playerName (LetterRack []) 0
tilesOnRack :: Player -> [Tile]
tilesOnRack (Player _ (LetterRack letters) _) = letters
increaseScore :: Player -> Int -> Player
increaseScore player justScored = player {score = currentScore + justScored}
where
currentScore = score player
reduceScore :: Player -> Int -> Player
reduceScore player removeScore = player {score = currentScore removeScore}
where
currentScore = score player
hasEmptyRack :: Player -> Bool
hasEmptyRack player = null $ tilesOnRack player
tileValues :: Player -> Int
tileValues player = sum $ map tileValue (tilesOnRack player)
giveTiles :: Player -> [Tile] -> Player
giveTiles player newTiles = player {rack = LetterRack $ newTiles ++ tilesOnRack player}
removeTiles :: Player -> [Tile] -> Player
removeTiles player toRemove = player {rack = LetterRack $ tilesOnRack player \\ toRemove}
removePlayedTiles :: Player -> [Tile] -> Maybe Player
removePlayedTiles player tiles =
if (playerCanPlace player tiles)
then Just $ player `removedFromRack` tiles
else Nothing
where
removedFromRack playing playedTiles = player {rack = LetterRack (deleteFirstsBy isPlayable (tilesOnRack playing) playedTiles) }
playerCanPlace :: Player -> [Tile] -> Bool
playerCanPlace player played = isNothing $ find isInvalid playedList
where
(playedFrequencies, rackFrequencies) = tileFrequencies played $ tilesOnRack player
playedList = Map.toList playedFrequencies
isInvalid (tile, freq) =
case tile of
Blank Nothing -> False
Blank _ -> freq > Map.findWithDefault 0 (Blank Nothing) rackFrequencies
Letter chr val -> freq > Map.findWithDefault 0 (Letter chr val) rackFrequencies
exchange :: Player -> [Tile] -> [Tile] -> Maybe Player
exchange player exchanged received =
if not (playerCanExchange player exchanged) then Nothing
else
Just $ giveTiles (removeTiles player exchanged) received
playerCanExchange :: Player -> [Tile] -> Bool
playerCanExchange (Player _ ( LetterRack letterRack) _ ) exchanged = isNothing $ find cannotExchange exchangedList
where
(exchangedFrequencies, rackFrequencies) = tileFrequencies exchanged letterRack
exchangedList = Map.toList exchangedFrequencies
cannotExchange (tile, freq) =
case tile of
Blank (Just _) -> False
Blank _ -> freq > Map.findWithDefault 0 (Blank Nothing) rackFrequencies
Letter chr val -> freq > Map.findWithDefault 0 (Letter chr val) rackFrequencies
tileFrequencies :: [Tile] -> [Tile] -> ((Map.Map Tile Int), (Map.Map Tile Int))
tileFrequencies given letterRack = (givenFrequencies, rackFrequencies)
where
buildFrequencies tiles = foldl addFrequency (Map.empty) tiles
addFrequency dict tile = Map.alter newFrequency tile dict
newFrequency m = Just $ maybe 1 succ m
givenFrequencies = buildFrequencies given
rackFrequencies = buildFrequencies letterRack