module Wordify.Rules.Square (Square(Normal, DoubleLetter, TripleLetter, DoubleWord, TripleWord), isOccupied, scoreSquares, squareIfOccupied, putTileOn, tileIfOccupied) where import Wordify.Rules.Tile import Data.Sequence as Seq import qualified Data.Foldable as F import Data.Maybe data Square = Normal (Maybe Tile) | DoubleLetter (Maybe Tile) | TripleLetter (Maybe Tile) | DoubleWord (Maybe Tile) | TripleWord (Maybe Tile) deriving (Show,Eq,Ord) putTileOn :: Square -> Tile -> Square putTileOn (Normal _) tile = Normal $ Just tile putTileOn (DoubleLetter _) tile = DoubleLetter $ Just tile putTileOn (TripleLetter _) tile = TripleLetter $ Just tile putTileOn (DoubleWord _) tile = DoubleWord $ Just tile putTileOn (TripleWord _) tile = TripleWord $ Just tile {- | Calculates the score of one played word. The first list contains squares that are already on the board (and thus are not subject to bonuses). The second list contains squares that are newly occupied. -} scoreSquares :: Seq Square -> Seq Square -> Int -- Calculate the base score then add the letter bonuses (doubleLetter, doubleWord), -- then multiply by word bonuses (DoubleWord, TripleWord) scoreSquares xs ys = addBonuses (addBonuses baseScore letterBonuses) wordBonuses where calcBaseScore = F.foldr (\square acc -> baseValue square + acc) 0 addBonuses = F.foldr applyWordBonus baseScore = calcBaseScore xs + calcBaseScore ys (wordBonuses, letterBonuses) = Seq.partition isWordBonus ys {- | The bonus operations that should be applied to the score of a word once it has been calculated. When using to calculate score, double and triple word bonuses should be applied last. -} applyWordBonus :: Square -> Int -> Int applyWordBonus (Normal _ ) = (+0) applyWordBonus (DoubleLetter (Just tile)) = (+ tileValue tile) applyWordBonus (TripleLetter (Just tile)) = (+ tileValue tile * 2) applyWordBonus (DoubleWord _) = (*2) applyWordBonus (TripleWord _) = (*3) applyWordBonus _ = (+0) isWordBonus :: Square -> Bool isWordBonus (DoubleWord _) = True isWordBonus (TripleWord _) = True isWordBonus _ = False -- | Base value of a square, without bonuses baseValue :: Square -> Int baseValue sq = maybe 0 tileValue $ tileIfOccupied sq squareIfOccupied :: Square -> Maybe Square squareIfOccupied sq = tileIfOccupied sq >> Just sq tileIfOccupied :: Square -> Maybe Tile tileIfOccupied (Normal (Just tile)) = Just tile tileIfOccupied (DoubleLetter (Just tile)) = Just tile tileIfOccupied (TripleLetter (Just tile)) = Just tile tileIfOccupied (DoubleWord (Just tile)) = Just tile tileIfOccupied (TripleWord (Just tile)) = Just tile tileIfOccupied _ = Nothing isOccupied :: Square -> Bool isOccupied = isJust . squareIfOccupied