-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A scrabble library capturing the core game logic of scrabble. -- -- A scrabble library which enforces legal transitions between moves. -- Intended to facilitate the development of a playable game. @package haskellscrabble @version 2.2.1 module Wordify.Rules.Tile -- | A tile is a letter with a value, or a Blank tile which may have been -- given a letter. Blank tiles always have the value '0'. data Tile Letter :: Char -> Int -> Tile Blank :: (Maybe Char) -> Tile tileValue :: Tile -> Int -- | isPlayble, applied to a played tile and compared against a tile -- returns true if a player returned a letter tile on their rack, or if -- the player played a Blank that has been given a letter isPlayable :: Tile -> Tile -> Bool tileLetter :: Tile -> Maybe Char -- | Prints a letter in the style found on a scoresheet. E.g. blank letters -- are printed in lowercase. printLetter :: Tile -> Maybe Char instance GHC.Classes.Ord Wordify.Rules.Tile.Tile instance GHC.Classes.Eq Wordify.Rules.Tile.Tile instance GHC.Show.Show Wordify.Rules.Tile.Tile module Wordify.Rules.LetterBag.Internal data LetterBag LetterBag :: [Tile] -> Int -> StdGen -> Map Char Tile -> LetterBag [tiles] :: LetterBag -> [Tile] [bagSize] :: LetterBag -> Int [generator] :: LetterBag -> StdGen [validLetters] :: LetterBag -> Map Char Tile instance GHC.Show.Show Wordify.Rules.LetterBag.Internal.LetterBag instance GHC.Classes.Eq Wordify.Rules.LetterBag.Internal.LetterBag module Wordify.Rules.Square data Square Normal :: (Maybe Tile) -> Square DoubleLetter :: (Maybe Tile) -> Square TripleLetter :: (Maybe Tile) -> Square DoubleWord :: (Maybe Tile) -> Square TripleWord :: (Maybe Tile) -> Square isOccupied :: Square -> Bool -- | 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 squareIfOccupied :: Square -> Maybe Square putTileOn :: Square -> Tile -> Square tileIfOccupied :: Square -> Maybe Tile instance GHC.Classes.Ord Wordify.Rules.Square.Square instance GHC.Classes.Eq Wordify.Rules.Square.Square instance GHC.Show.Show Wordify.Rules.Square.Square module Wordify.Rules.Player data Player data LetterRack makePlayer :: String -> Player name :: Player -> Name rack :: Player -> LetterRack tilesOnRack :: Player -> [Tile] endBonus :: Player -> Int score :: Player -> Score increaseScore :: Player -> Int -> Player reduceScore :: Player -> Int -> Player giveEndLosePenalty :: Player -> Int -> Player giveEndWinBonus :: Player -> Int -> Player giveTiles :: Player -> [Tile] -> Player -- | Removes played tiles from the player's tile rack, if it was possible -- for the player to play those tiles in the first place. A player may -- play a tile on his rack, unless it is a blank, which must first be -- assigned a letter. removePlayedTiles :: Player -> [Tile] -> Maybe Player removeTiles :: Player -> [Tile] -> Player hasEmptyRack :: Player -> Bool tileValues :: Player -> Int exchange :: Player -> [Tile] -> [Tile] -> Maybe Player instance GHC.Classes.Eq Wordify.Rules.Player.Player instance GHC.Show.Show Wordify.Rules.Player.Player instance GHC.Classes.Eq Wordify.Rules.Player.LetterRack instance GHC.Show.Show Wordify.Rules.Player.LetterRack module Wordify.Rules.Pos.Internal data Pos Pos :: !Int -> !Int -> !String -> Pos instance GHC.Classes.Ord Wordify.Rules.Pos.Internal.Pos instance GHC.Show.Show Wordify.Rules.Pos.Internal.Pos instance GHC.Classes.Eq Wordify.Rules.Pos.Internal.Pos module Wordify.Rules.Pos data Pos data Direction Horizontal :: Direction Vertical :: Direction posAt :: (Int, Int) -> Maybe Pos -- | The position above the given position, if it exists. above :: Pos -> Maybe Pos -- | The position below the given position, if it exists. below :: Pos -> Maybe Pos -- | The position to the left of the given position, if it exists. left :: Pos -> Maybe Pos -- | The position to the right of the given position, if it exists. right :: Pos -> Maybe Pos xPos :: Pos -> Int yPos :: Pos -> Int gridValue :: Pos -> String direction :: Pos -> Pos -> Maybe Direction -- | The position of the star square starPos :: Pos posMin :: Int posMax :: Int instance GHC.Classes.Eq Wordify.Rules.Pos.Direction module Wordify.Rules.ScrabbleError data ScrabbleError -- | The caller has supplied an invalid path to a letter bag file, or the -- file is not openable LetterBagFileNotOpenable :: String -> ScrabbleError -- | The letter bag file is marformed, so could not be parsed. MalformedLetterBagFile :: FilePath -> ScrabbleError -- | The path given to a dictionary file was invalid. DictionaryFileNotFound :: FilePath -> ScrabbleError -- | The dictionary file could not be parsed as it was malformed. MalformedDictionaryFile :: String -> ScrabbleError -- | A letter bag with insufficient tiles was used to create a game. NotEnoughLettersInStartingBag :: Int -> ScrabbleError -- | The player has made an illegal tile placement. Tiles placed must form -- a line of tiles. MisplacedLetter :: Pos -> ScrabbleError -- | The tiles the player placed do not connect with any word (applies -- after the first move on the board) DoesNotConnectWithWord :: ScrabbleError -- | The client put the player in the situation to be able to place no -- tiles. NoTilesPlaced :: ScrabbleError -- | The first move on the board does not cover the star. DoesNotCoverTheStarTile :: ScrabbleError -- | The client allowed the player to place tiles on a square that is -- already occupied with tiles. PlacedTileOnOccupiedSquare :: Pos -> Tile -> ScrabbleError -- | A blank tile must be labeled with a letter before being placed. CannotPlaceBlankWithoutLetter :: Pos -> ScrabbleError -- | The tiles the player placed formed one or more words which are not in -- the dictionary. WordsNotInDictionary :: [String] -> ScrabbleError -- | The caller allowed the client to place tiles on the board which were -- not in their rack. PlayerCannotPlace :: LetterRack -> [Tile] -> ScrabbleError -- | The caller allowed the player to attempt to exchange when no letters -- were left in the bag. CannotExchangeWhenNoLettersInBag :: ScrabbleError -- | The caller allowed the player to attempt to exchange tiles that they -- do not have. PlayerCannotExchange :: LetterRack -> [Tile] -> ScrabbleError -- | The caller allowed a move to be made when the game is finished. GameNotInProgress :: ScrabbleError MiscError :: String -> ScrabbleError instance GHC.Classes.Eq Wordify.Rules.ScrabbleError.ScrabbleError instance GHC.Show.Show Wordify.Rules.ScrabbleError.ScrabbleError module Wordify.Rules.LetterBag data LetterBag validLetters :: LetterBag -> Map Char Tile -- | Creates a letter bag from a file where each line contains a space -- delimited letter character, letter value, and letter distribution. A -- blank letter is represented by a '_' character and has a disribution, -- but no value. -- -- If successful, the letter bag is shuffled before it is returned. makeBag :: FilePath -> IO (Either ScrabbleError LetterBag) tiles :: LetterBag -> [Tile] -- | Creates a letter bag from a list of tiles. The order of the tiles is -- retained in the resulting letter bag. -- -- This function is effectful as it is necessary to create a stdGen for -- list to allow it to be shuffled using this generator in the future. bagFromTiles :: [Tile] -> IO LetterBag -- | Creates a letter bag using a list of tiles, and a generator which -- should be used when shuffling the bag. This function allows a game to -- be stepped through from the beginning where the moves and original -- generator were recorded, with any shuffling yielding the same bag as -- in the original game. makeBagUsingGenerator :: [Tile] -> StdGen -> LetterBag -- | Takes n numbers from a letter bag, yielding Nothing if -- there is not enough tiles left in the bag or a Just tuple where -- the left value is the taken tiles, and the right value is the new bag. takeLetters :: LetterBag -> Int -> Maybe ([Tile], LetterBag) -- | Exchanges given tiles for the same number of tiles from the bag. The -- exchanged letters are added to the bag, the bag is then shuffled, and -- then the same number of tiles as exchanged are drawn from the bag. -- -- Returns Nothing if there are not enough letters in the bag to -- exchange the given tiles for. Otherwise returns Just with a -- tuple with the tiles given, and the new letterbag. exchangeLetters :: LetterBag -> [Tile] -> (Maybe ([Tile], LetterBag)) -- | Shuffles the contents of a letter bag. The bag is shuffled using the -- random generator which was created while constructing the bag. -- -- This function should not be used when creating an additional game with -- a new letter bag as the same seed value will be shared across games -- (meaning tiles will come out of the bag in the same order.) When -- constructing an additional game, use shuffleWithNewGenerator. shuffleBag :: LetterBag -> LetterBag -- | Shuffles a letter bag using a new random generator. This function -- should be used when spawning a new game using a letter bag with all -- the tiles remaining so that letter bags are unique between game -- instances. shuffleWithNewGenerator :: LetterBag -> IO LetterBag bagSize :: LetterBag -> Int -- | Get the letter bag's current generator, which will be used to shuffle -- the contents of the bag in the next exchange or shuffle. If taken at -- the start of the game, with the original list of tiles in the bag in -- order, the game moves may be replayed in order with the original -- results of any shuffle retained. getGenerator :: LetterBag -> StdGen module Wordify.Rules.Dictionary data Dictionary -- | Creates a dictionary from a file containing a list of valid words, -- each word being seperated by a newline. makeDictionary :: FilePath -> IO (Either ScrabbleError Dictionary) dictionaryFromWords :: [String] -> Dictionary isValidWord :: Dictionary -> String -> Bool -- | Returns the list of words which are not present in the given -- dictionary from a list of input words. invalidWords :: Dictionary -> [String] -> [String] instance GHC.Show.Show Wordify.Rules.Dictionary.Dictionary module Wordify.Rules.Board.Internal data Board Board :: (Map Pos Square) -> Board instance GHC.Classes.Eq Wordify.Rules.Board.Internal.Board module Wordify.Rules.Board data Board -- | Creates an empty board. emptyBoard :: Board -- | Returns all the squares on the board, ordered by column then row. allSquares :: Board -> [(Pos, Square)] -- | Places a tile on a square and yields the new board, if the target -- square is empty. Otherwise yields Nothing. placeTile :: Board -> Tile -> Pos -> Maybe Board -- | Returns the square at a given position if it is occupied by a tile. -- Otherwise returns Nothing. occupiedSquareAt :: Board -> Pos -> Maybe Square -- | Finds the empty square positions horizontally or vertically from a -- given position, skipping any squares that are occupied by a tile emptySquaresFrom :: Board -> Pos -> Int -> Direction -> [Pos] -- | All letters immediately above a given square until a non-occupied -- square lettersAbove :: Board -> Pos -> Seq (Pos, Square) -- | All letters immediately below a given square until a non-occupied -- square lettersBelow :: Board -> Pos -> Seq (Pos, Square) -- | All letters immediately left of a given square until a non-occupied -- square lettersLeft :: Board -> Pos -> Seq (Pos, Square) -- | All letters immediately right of a given square until a non-occupied -- square lettersRight :: Board -> Pos -> Seq (Pos, Square) -- | Returns the square at a given position if it is not occupied by a -- tile. Otherwise returns Nothing. unoccupiedSquareAt :: Board -> Pos -> Maybe Square -- | Pretty prints a board to a human readable string representation. -- Helpful for development. prettyPrint :: Board -> String instance GHC.Show.Show Wordify.Rules.Board.Internal.Board module Wordify.Rules.Game data Game -- | Starts a new game. -- -- A game has at least 2 players, and 2 optional players (player 3 and -- 4.) The players should be newly created, as tiles from the letter bag -- will be distributed to each player. -- -- Takes a letter bag and dictionary, which should be localised to the -- same language. -- -- Yields a tuple with the first player and the initial game state. -- Returns a Left if there are not enough tiles in the letter bag -- to distribute to the players. makeGame :: (Player, Player, Maybe (Player, Maybe Player)) -> LetterBag -> Dictionary -> Either ScrabbleError Game -- | Returns a history of the moves made in the game. movesMade :: Game -> [Move] gameStatus :: Game -> GameStatus board :: Game -> Board bag :: Game -> LetterBag dictionary :: Game -> Dictionary moveNumber :: Game -> Int player1 :: Game -> Player player2 :: Game -> Player optionalPlayers :: Game -> Maybe (Player, Maybe Player) currentPlayer :: Game -> Player getPlayer :: Game -> Int -> Maybe Player playerNumber :: Game -> Int data GameStatus InProgress :: GameStatus Finished :: GameStatus players :: Game -> [Player] passes :: Game -> Int numberOfPlayers :: Game -> Int history :: Game -> History data History History :: LetterBag -> (Seq Move) -> History module Wordify.Rules.FormedWord data FormedWords type FormedWord = Seq (Pos, Square) type PlacedSquares = Map Pos Square -- | All the words formed by a play. allWords :: FormedWords -> [FormedWord] -- | Returns the main word formed by the played tiles. The main word is the -- linear stretch of tiles formed by the tiles placed. mainWord :: FormedWords -> FormedWord -- | Returns the list of words which were adjacent to the main word formed. adjacentWords :: FormedWords -> [FormedWord] -- | Returns the list of positions mapped to the squares that the player -- placed their tiles on. playerPlaced :: FormedWords -> [(Pos, Square)] playerPlacedMap :: FormedWords -> Map Pos Square -- | Scores an individual word. -- -- Note: overallscore should be used to obtain the overall score as it -- takes into account any bingo bonuses. scoreWord :: PlacedSquares -> FormedWord -> Int -- | Calculates the overall score of the play. -- -- If a player managed to place all 7 of their letters, then they receive -- a bingo bonus of 50 points. overallScore :: FormedWords -> Int -- | Returns true if the player placed all 7 of their letters while forming -- these words, incurring a + 50 score bonus. bingoBonusApplied :: FormedWords -> Bool -- | Pretty prints the places a given formed word intersects with letters -- that were already on the board using brackets. E.g. T(HI)S would -- denote that the player placed a T and an S on to the -- board, using the already placed word HI to form the new word -- THIS. prettyPrintIntersections :: PlacedSquares -> FormedWord -> String makeString :: FormedWord -> String -- | Returns the words formed by the play as strings. wordStrings :: FormedWords -> [String] -- | Scores the words formed by the tiles placed. The first item in the -- tuple is the overall score, while the second item is the list of -- scores for all the words formed. wordsWithScores :: FormedWords -> (Int, [(String, Int)]) -- | Returns the words formed by the tiles played on the board. A played -- word must be connected to a tile already on the board (or intersect -- tiles on the board), and be formed linearly. Any blank tiles must be -- labeled. wordsFormedMidGame :: Board -> Map Pos Tile -> Either ScrabbleError FormedWords -- | Returns the word formed by the first move on the board. The word must -- cover the star tile, and be linear. Any blank tiles must be labeled. wordFormedFirstMove :: Board -> Map Pos Tile -> Either ScrabbleError FormedWords instance GHC.Classes.Eq Wordify.Rules.FormedWord.FormedWords instance GHC.Show.Show Wordify.Rules.FormedWord.FormedWords module Wordify.Rules.Move data Move PlaceTiles :: (Map Pos Tile) -> Move Exchange :: [Tile] -> Move Pass :: Move data GameTransition -- | The new player (with their updated letter rack and score), new game -- state, and the words formed by the move MoveTransition :: Player -> Game -> FormedWords -> GameTransition -- | The new game state, and the player with their rack before and after -- the exchange respectively. ExchangeTransition :: Game -> Player -> Player -> GameTransition -- | The new game state with the opportunity to play passed on to the next -- player. PassTransition :: Game -> GameTransition -- | The game has finished. The final game state, and the final words -- formed (if the game was ended by a player placing their final tiles.) -- The players before their scores were increased or decreased is also -- given. GameFinished :: Game -> (Maybe FormedWords) -> GameTransition -- | Transitiions the game to the next state. If the move places tiles, the -- player must have the tiles to place and place the tiles legally. If -- the move exchanges tiles, the bag must not be empty and the player -- must have the tiles to exchange. A ScrabbleError is returned if these -- condtions are not the case. makeMove :: Game -> Move -> Either ScrabbleError GameTransition newGame :: GameTransition -> Game -- | Restores a game from a list of moves. The game must be set up in the -- way the original game was set up (including the letter bag constructed -- with the same tiles and random generator, dictionary and the list of -- players in the original order.) -- -- If the game is not set up as it was originally, this function will -- return a scrabble error with the move which was invalid with the given -- state. For example, if the original players are not ordered in the -- correct way then the player will not have the required tiles to make -- the move. restoreGame :: Game -> NonEmpty Move -> Either ScrabbleError (NonEmpty GameTransition) -- | Maps each move to a resulting game transition, if the move is legal. -- Has the same semantics as restoreGame but returns a list of -- Either so that laziness can be maintained, meaning all the game -- transitions dont have to be buffered before they can be consumed. restoreGameLazy :: Game -> NonEmpty Move -> NonEmpty (Either ScrabbleError GameTransition)