packages feed

wordify 0.1.0.1 → 0.1.1.0

raw patch · 3 files changed

+286/−196 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Wordify.Rules.Board: loadFromTextRepresentation :: Map Char Tile -> String -> Maybe Board
+ Wordify.Rules.Board: placeTiles :: Board -> [(Tile, Pos)] -> Maybe Board
+ Wordify.Rules.Board: textRepresentation :: Board -> String
+ Wordify.Rules.Pos: abovePositions :: Pos -> Int -> [Pos]
+ Wordify.Rules.Pos: belowPositions :: Pos -> Int -> [Pos]
+ Wordify.Rules.Pos: leftPositions :: Pos -> Int -> [Pos]
+ Wordify.Rules.Pos: rightPositions :: Pos -> Int -> [Pos]

Files

src/Wordify/Rules/Board.hs view
@@ -1,160 +1,219 @@-module Wordify.Rules.Board(Board,-                           emptyBoard,-                           allSquares,-                           placeTile,-                           occupiedSquareAt,-                           emptySquaresFrom,-                           lettersAbove,-                           lettersBelow,-                           lettersLeft,-                           lettersRight,-                           unoccupiedSquareAt,-                           prettyPrint) where+module Wordify.Rules.Board+  ( Board,+    emptyBoard,+    allSquares,+    placeTile,+    placeTiles,+    occupiedSquareAt,+    emptySquaresFrom,+    lettersAbove,+    lettersBelow,+    lettersLeft,+    lettersRight,+    unoccupiedSquareAt,+    textRepresentation,+    loadFromTextRepresentation,+    prettyPrint,+  )+where -  import Wordify.Rules.Square-  import Wordify.Rules.Pos-  import Data.Maybe-  import Wordify.Rules.Tile-  import qualified Data.Map as Map-  import Control.Monad-  import Data.Sequence as Seq-  import Wordify.Rules.Board.Internal-  import Control.Applicative-  import Data.List.Split as S-  import qualified Data.List as L-  import Data.Foldable as F+import Control.Applicative+import Control.Monad+import Data.Foldable as F+import qualified Data.List as L+import Data.List.Split as S+import qualified Data.Map as M+import qualified Data.Map as Map+import Data.Maybe+import Data.Sequence as Seq+import qualified Data.Text as T+import Wordify.Rules.Board.Internal+import Wordify.Rules.Pos+import Wordify.Rules.Square+import Wordify.Rules.Tile -  instance Show Board where-    show = prettyPrint+instance Show Board where+  show = prettyPrint -  {- |-    Returns all the squares on the board, ordered by column then row.-  -}-  allSquares :: Board -> [(Pos, Square)]-  allSquares (Board squares) = Map.toList squares+-- |+--    Returns all the squares on the board, ordered by column then row.+allSquares :: Board -> [(Pos, Square)]+allSquares (Board squares) = Map.toList squares -  {- |-    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-  placeTile board tile pos =-    (\sq -> insertSquare board pos (putTileOn sq tile)) <$> unoccupiedSquareAt board pos+-- |+--    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+placeTile board tile pos =+  (\sq -> insertSquare board pos (putTileOn sq tile)) <$> unoccupiedSquareAt board pos -  insertSquare :: Board -> Pos -> Square -> Board-  insertSquare (Board squares) pos square = Board $ Map.insert pos square squares+-- |+--    Places tiles on the given squares and yields the new board, if+--    all the target squares are empty. Otherwise yields 'Nothing'.+placeTiles :: Board -> [(Tile, Pos)] -> Maybe Board+placeTiles board = foldl tryPlaceTile (Just board)+  where+    tryPlaceTile :: Maybe Board -> (Tile, Pos) -> Maybe Board+    tryPlaceTile Nothing (tile, pos) = Nothing+    tryPlaceTile (Just board) (tile, pos) = placeTile board tile pos -  squareAt :: Board -> Pos -> Maybe Square-  squareAt (Board squares)  = flip Map.lookup squares+insertSquare :: Board -> Pos -> Square -> Board+insertSquare (Board squares) pos square = Board $ Map.insert pos square squares -  {- | Returns the square at a given position if it is not occupied by a tile. Otherwise returns Nothing.-}-  unoccupiedSquareAt :: Board -> Pos -> Maybe Square-  unoccupiedSquareAt board pos =-    squareAt board pos >>= (\sq -> if isOccupied sq then Nothing else Just sq)+squareAt :: Board -> Pos -> Maybe Square+squareAt (Board squares) = flip Map.lookup squares -  {- | Returns the square at a given position if it is occupied by a tile. Otherwise returns Nothing.-}-  occupiedSquareAt :: Board -> Pos -> Maybe Square-  occupiedSquareAt board pos = squareAt board pos >>= squareIfOccupied+-- | Returns the square at a given position if it is not occupied by a tile. Otherwise returns Nothing.+unoccupiedSquareAt :: Board -> Pos -> Maybe Square+unoccupiedSquareAt board pos =+  squareAt board pos >>= (\sq -> if isOccupied sq then Nothing else Just sq) -  {- | All letters immediately above a given square until a non-occupied square -}-  lettersAbove :: Board -> Pos -> Seq (Pos,Square)-  lettersAbove board pos = walkFrom board pos above+-- | Returns the square at a given position if it is occupied by a tile. Otherwise returns Nothing.+occupiedSquareAt :: Board -> Pos -> Maybe Square+occupiedSquareAt board pos = squareAt board pos >>= squareIfOccupied -  {- | All letters immediately below a given square until a non-occupied square -}-  lettersBelow :: Board -> Pos -> Seq (Pos,Square)-  lettersBelow board pos = Seq.reverse $ walkFrom board pos below+-- | All letters immediately above a given square until a non-occupied square+lettersAbove :: Board -> Pos -> Seq (Pos, Square)+lettersAbove board pos = walkFrom board pos above -  {- | All letters immediately left of a given square until a non-occupied square -}-  lettersLeft :: Board -> Pos -> Seq (Pos,Square)-  lettersLeft board pos = Seq.reverse $ walkFrom board pos left+-- | All letters immediately below a given square until a non-occupied square+lettersBelow :: Board -> Pos -> Seq (Pos, Square)+lettersBelow board pos = Seq.reverse $ walkFrom board pos below -  {- | All letters immediately right of a given square until a non-occupied square -}-  lettersRight :: Board -> Pos -> Seq (Pos,Square)-  lettersRight board pos = walkFrom board pos right+-- | All letters immediately left of a given square until a non-occupied square+lettersLeft :: Board -> Pos -> Seq (Pos, Square)+lettersLeft board pos = Seq.reverse $ walkFrom board pos left -  {- | 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]-  emptySquaresFrom board startPos numSquares direction =-    let changingOnwards = [changing .. 15]-    in  L.take numSquares $-            L.filter (isJust . unoccupiedSquareAt board) $-                 mapMaybe posAt $ zipDirection (repeat constant) changingOnwards-    where-        (constant, changing) = if direction == Horizontal then (yPos startPos, xPos startPos) else (xPos startPos, yPos startPos)-        zipDirection = if (direction == Horizontal) then flip L.zip else L.zip+-- | All letters immediately right of a given square until a non-occupied square+lettersRight :: Board -> Pos -> Seq (Pos, Square)+lettersRight board pos = walkFrom board pos right +-- | 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]+emptySquaresFrom board startPos numSquares direction =+  let changingOnwards = [changing .. 15]+   in L.take numSquares $+        L.filter (isJust . unoccupiedSquareAt board) $+          mapMaybe posAt $ zipDirection (repeat constant) changingOnwards+  where+    (constant, changing) = if direction == Horizontal then (yPos startPos, xPos startPos) else (xPos startPos, yPos startPos)+    zipDirection = if (direction == Horizontal) then flip L.zip else L.zip -  {- | Pretty prints a board to a human readable string representation. Helpful for development. -}-  prettyPrint :: Board -> String-  prettyPrint board = rowsWithLabels ++ columnLabelSeparator ++ columnLabels-    where-      rows = L.transpose . S.chunksOf 15 . map (squareToString . snd) . allSquares-      rowsWithLabels = concatMap (\(rowNo, row) -> (rowStr rowNo) ++ concat row ++ "\n") . Prelude.zip [1 .. ] $ (rows board)+-- | Pretty prints a board to a human readable string representation. Helpful for development.+prettyPrint :: Board -> String+prettyPrint board = rowsWithLabels ++ columnLabelSeparator ++ columnLabels+  where+    rows = L.transpose . S.chunksOf 15 . map (squareToString . snd) . allSquares+    rowsWithLabels = concatMap (\(rowNo, row) -> (rowStr rowNo) ++ concat row ++ "\n") . Prelude.zip [1 ..] $ (rows board) -      rowStr :: Int -> String-      rowStr number = if number < 10 then ((show number) ++ " | ") else (show number) ++ "| "-      columnLabelSeparator = "  " ++ (Prelude.take (15 * 5) $ repeat '-') ++ "\n"-      columnLabels = "      " ++ (concat $ Prelude.take (15 * 2) . L.intersperse "    " . map ( : []) $ ['A' .. ])+    rowStr :: Int -> String+    rowStr number = if number < 10 then ((show number) ++ " | ") else (show number) ++ "| "+    columnLabelSeparator = "  " ++ (Prelude.take (15 * 5) $ repeat '-') ++ "\n"+    columnLabels = "      " ++ (concat $ Prelude.take (15 * 2) . L.intersperse "    " . map (: []) $ ['A' ..]) -      squareToString square =-        case (tileIfOccupied square) of-          Just sq -> maybe " |_| " (\lt -> " |" ++ lt : "| ") $ tileLetter sq-          Nothing ->-            case square of-              (Normal _) -> "  N  "-              (DoubleLetter _) -> "  DL "-              (TripleLetter _) -> "  TL "-              (DoubleWord _) -> "  DW "-              (TripleWord _) -> "  TW "+    squareToString square =+      case (tileIfOccupied square) of+        Just sq -> maybe " |_| " (\lt -> " |" ++ lt : "| ") $ tileLetter sq+        Nothing ->+          case square of+            (Normal _) -> "  N  "+            (DoubleLetter _) -> "  DL "+            (TripleLetter _) -> "  TL "+            (DoubleWord _) -> "  DW "+            (TripleWord _) -> "  TW " -  {--    Walks the tiles from a given position in a given direction-    until an empty square is found or the boundary of the board-    is reached.-  -}-  walkFrom :: Board -> Pos -> (Pos -> Maybe Pos) -> Seq (Pos,Square)-  walkFrom board pos direction = maybe mzero (\(next,sq) ->-   (next, sq) <| walkFrom board next direction) neighbourPos-    where-      neighbourPos = direction pos >>= \nextPos -> occupiedSquareAt board nextPos >>=-        \sq -> return (nextPos, sq)+{-+  Walks the tiles from a given position in a given direction+  until an empty square is found or the boundary of the board+  is reached.+-}+walkFrom :: Board -> Pos -> (Pos -> Maybe Pos) -> Seq (Pos, Square)+walkFrom board pos direction =+  maybe+    mzero+    ( \(next, sq) ->+        (next, sq) <| walkFrom board next direction+    )+    neighbourPos+  where+    neighbourPos =+      direction pos >>= \nextPos ->+        occupiedSquareAt board nextPos+          >>= \sq -> return (nextPos, sq) -  {- |-    Creates an empty board.-  -}-  emptyBoard :: Board-  emptyBoard = Board (Map.fromList posSquares)-    where-      layout =-        [["TW","N","N","DL","N","N","N","TW","N","N","N","DL","N","N","TW"]-       ,["N","DW","N","N","N","TL","N","N","N","TL","N","N","N","DW","N"]-       ,["N","N","DW","N","N","N","DL","N","DL","N","N","N","DW","N","N"]-       ,["DL","N","N","DW","N","N","N","DL","N","N","N","DW","N","N","DL"]-       ,["N","N","N","N","DW","N","N","N","N","N","DW","N","N","N","N"]-       ,["N","TL","N","N","N","TL","N","N","N","TL","N","N","N","TL","N"]-       ,["N","N","DL","N","N","N","DL","N","DL","N","N","N","DL","N","N"]-       ,["TW","N","N","DL","N","N","N","DW","N","N","N","DL","N","N","TW"]-       ,["N","N","DL","N","N","N","DL","N","DL","N","N","N","DL","N","N"]-       ,["N","TL","N","N","N","TL","N","N","N","TL","N","N","N","TL","N"]-       ,["N","N","N","N","DW","N","N","N","N","N","DW","N","N","N","N"]-       ,["DL","N","N","DW","N","N","N","DL","N","N","N","DW","N","N","DL"]-       ,["N","N","DW","N","N","N","DL","N","DL","N","N","N","DW","N","N"]-       ,["N","DW","N","N","N","TL","N","N","N","TL","N","N","N","DW","N"]-       ,["TW","N","N","DL","N","N","N","TW","N","N","N","DL","N","N","TW"]]+{-+  Represents the board as a comma delimited string where each character is either the character in the board square+  or an empty string. The string is ordered by column then row, starting at position A1 and ending at O15. -      squares = (map . map) toSquare layout-      columns = Prelude.zip [1..15] squares-      labeledSquares= concatMap (uncurry columnToMapping) columns-      columnToMapping columnNo columnSquares = Prelude.zipWith (\sq y -> ((columnNo,y),sq)) columnSquares [1..15]-      posSquares = mapMaybe (\((x,y), sq) -> fmap (\pos -> (pos, sq)) (posAt (x,y))) labeledSquares+  E.g. an empty board would be representated as 244 contiguous , characters. A -      toSquare :: String -> Square-      toSquare "DL" = DoubleLetter Nothing-      toSquare "TL" = TripleLetter Nothing-      toSquare "DW" = DoubleWord Nothing-      toSquare "TW" = TripleWord Nothing-      toSquare _ = Normal Nothing+  A board with the tile 'H' at position H8 and 'I' at position H9 would look like this:+  ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,H,I,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+-}+textRepresentation :: Board -> String+textRepresentation board = L.intercalate "," (squareStrings board)+  where+    squareStrings :: Board -> [String]+    squareStrings board = map getLetterRepresentation (allSquares board) +    getLetterRepresentation :: (Pos, Square) -> String+    getLetterRepresentation square = toLetterRepresentation ((tileIfOccupied . snd) square >>= tileLetter) +    toLetterRepresentation :: Maybe Char -> String+    toLetterRepresentation (Just char) = [char]+    toLetterRepresentation Nothing = ""++{-+  Loads a board from the string representation of the board generated by the 'textPresentation' function+-}+loadFromTextRepresentation :: M.Map Char Tile -> String -> Maybe Board+loadFromTextRepresentation validTiles textRepresentation =+  let positionsWithLetters = L.zip [0 ..] (S.splitOn "," textRepresentation)+   in let placements = mapMaybe (uncurry positionWithLetter) positionsWithLetters+       in placeTiles emptyBoard placements+  where+    positionWithLetter :: Int -> [Char] -> Maybe (Tile, Pos)+    positionWithLetter oneDimensionalCoordinate [] = Nothing +    positionWithLetter oneDimensionalCoordinate (letter: []) = do+      tile <- M.lookup letter validTiles+      let x = (oneDimensionalCoordinate  `div` 15) + 1+      let y = (oneDimensionalCoordinate `mod` 15) + 1+      coordinate <- posAt (x, y)+      return (tile, coordinate)++-- |+--    Creates an empty board.+emptyBoard :: Board+emptyBoard = Board (Map.fromList posSquares)+  where+    layout =+      [ ["TW", "N", "N", "DL", "N", "N", "N", "TW", "N", "N", "N", "DL", "N", "N", "TW"],+        ["N", "DW", "N", "N", "N", "TL", "N", "N", "N", "TL", "N", "N", "N", "DW", "N"],+        ["N", "N", "DW", "N", "N", "N", "DL", "N", "DL", "N", "N", "N", "DW", "N", "N"],+        ["DL", "N", "N", "DW", "N", "N", "N", "DL", "N", "N", "N", "DW", "N", "N", "DL"],+        ["N", "N", "N", "N", "DW", "N", "N", "N", "N", "N", "DW", "N", "N", "N", "N"],+        ["N", "TL", "N", "N", "N", "TL", "N", "N", "N", "TL", "N", "N", "N", "TL", "N"],+        ["N", "N", "DL", "N", "N", "N", "DL", "N", "DL", "N", "N", "N", "DL", "N", "N"],+        ["TW", "N", "N", "DL", "N", "N", "N", "DW", "N", "N", "N", "DL", "N", "N", "TW"],+        ["N", "N", "DL", "N", "N", "N", "DL", "N", "DL", "N", "N", "N", "DL", "N", "N"],+        ["N", "TL", "N", "N", "N", "TL", "N", "N", "N", "TL", "N", "N", "N", "TL", "N"],+        ["N", "N", "N", "N", "DW", "N", "N", "N", "N", "N", "DW", "N", "N", "N", "N"],+        ["DL", "N", "N", "DW", "N", "N", "N", "DL", "N", "N", "N", "DW", "N", "N", "DL"],+        ["N", "N", "DW", "N", "N", "N", "DL", "N", "DL", "N", "N", "N", "DW", "N", "N"],+        ["N", "DW", "N", "N", "N", "TL", "N", "N", "N", "TL", "N", "N", "N", "DW", "N"],+        ["TW", "N", "N", "DL", "N", "N", "N", "TW", "N", "N", "N", "DL", "N", "N", "TW"]+      ]++    squares = (map . map) toSquare layout+    columns = Prelude.zip [1 .. 15] squares+    labeledSquares = concatMap (uncurry columnToMapping) columns+    columnToMapping columnNo columnSquares = Prelude.zipWith (\sq y -> ((columnNo, y), sq)) columnSquares [1 .. 15]+    posSquares = mapMaybe (\((x, y), sq) -> fmap (\pos -> (pos, sq)) (posAt (x, y))) labeledSquares++    toSquare :: String -> Square+    toSquare "DL" = DoubleLetter Nothing+    toSquare "TL" = TripleLetter Nothing+    toSquare "DW" = DoubleWord Nothing+    toSquare "TW" = TripleWord Nothing+    toSquare _ = Normal Nothing
src/Wordify/Rules/Pos.hs view
@@ -1,74 +1,105 @@+module Wordify.Rules.Pos+  ( Pos,+    Direction (Horizontal, Vertical),+    posAt,+    above,+    below,+    left,+    right,+    abovePositions,+    belowPositions,+    leftPositions,+    rightPositions,+    xPos,+    yPos,+    gridValue,+    direction,+    starPos,+    posMin,+    posMax,+  )+where -module Wordify.Rules.Pos (Pos,-                          Direction(Horizontal, Vertical),-                          posAt,-                          above,-                          below,-                          left,-                          right,-                          xPos,-                          yPos,-                          gridValue,-                          direction,-                          starPos,-                          posMin,-                          posMax) where+import qualified Data.Map as Map+import Data.Maybe+import Wordify.Rules.Pos.Internal -  import qualified Data.Map as Map-  import Wordify.Rules.Pos.Internal-  import Data.Maybe+data Direction = Horizontal | Vertical deriving (Eq) -  data Direction = Horizontal | Vertical deriving Eq+posMin :: Int+posMin = 1 -  posMin :: Int-  posMin = 1+posMax :: Int+posMax = 15 -  posMax :: Int-  posMax = 15+posAt :: (Int, Int) -> Maybe Pos+posAt = flip Map.lookup posMap -  posAt :: (Int, Int) -> Maybe Pos-  posAt = flip Map.lookup posMap+-- | The position above the given position, if it exists.+above :: Pos -> Maybe Pos+above (Pos x y _) = posAt (x, y + 1) -  -- | The position above the given position, if it exists.-  above :: Pos -> Maybe Pos-  above (Pos x y _) = posAt (x,y + 1)+-- | The position below the given position, if it exists.+below :: Pos -> Maybe Pos+below (Pos x y _) = posAt (x, y - 1) -  -- | The position below the given position, if it exists.-  below :: Pos -> Maybe Pos-  below (Pos x y _) = posAt (x, y - 1 )+-- | The position to the left of the given position, if it exists.+left :: Pos -> Maybe Pos+left (Pos x y _) = posAt (x - 1, y) -  -- | The position to the left of the given position, if it exists.-  left :: Pos -> Maybe Pos-  left (Pos x y _) = posAt (x - 1, y)+-- | The position to the right of the given position, if it exists.+right :: Pos -> Maybe Pos+right (Pos x y _) = posAt (x + 1, y) -  -- | The position to the right of the given position, if it exists.-  right :: Pos -> Maybe Pos-  right (Pos x y _) = posAt (x + 1, y)+-- | The positions above the position (inclusive)+abovePositions :: Pos -> Int -> [Pos]+abovePositions pos = walkTimes pos above -  -- | The position of the star square-  starPos :: Pos-  starPos = Pos 8 8 "H8"+-- | The positions below the position (inclusive)+belowPositions :: Pos -> Int -> [Pos]+belowPositions pos = walkTimes pos below -  direction :: Pos -> Pos -> Maybe Direction-  direction startPos endPos-    | xPos startPos == xPos endPos = Just Vertical-    | yPos startPos == yPos endPos = Just Horizontal-    | otherwise = Nothing+-- | The positions to the right of the position (inclusive)+rightPositions :: Pos -> Int -> [Pos]+rightPositions pos = walkTimes pos right -  {- A map keyed by tuples representing (x,y) co-ordinates, and valued by their-  corresponding Pos types -}-  posMap :: Map.Map (Int, Int) Pos-  posMap = Map.fromList $ catMaybes coordTuples-      where-          coordTuples = zipWith makeTuple (sequence [[posMin..posMax], [posMin..posMax]]) $ cycle ['A'..'O']-          makeTuple (x:y:_) gridLetter = Just $ ((y,x) , Pos y x (gridLetter : show x) )-          makeTuple _ _ = Nothing+-- | The positions to the left of the position (inclusive)+leftPositions :: Pos -> Int -> [Pos]+leftPositions pos = walkTimes pos left -  xPos :: Pos -> Int-  xPos (Pos x _ _) = x+walkTimes :: Pos -> (Pos -> Maybe Pos) -> Int -> [Pos]+walkTimes startPosition travelFunction = flip take (walkDirection startPosition travelFunction) -  yPos :: Pos -> Int-  yPos (Pos _ y _) = y+walkDirection :: Pos -> (Pos -> Maybe Pos) -> [Pos]+walkDirection startPosition travelFunction =+  case travelFunction startPosition of+    Nothing -> [startPosition]+    Just nextPosition -> startPosition : walkDirection nextPosition travelFunction -  gridValue :: Pos -> String-  gridValue (Pos _ _ grid) = grid+-- | The position of the star square+starPos :: Pos+starPos = Pos 8 8 "H8"++direction :: Pos -> Pos -> Maybe Direction+direction startPos endPos+  | xPos startPos == xPos endPos = Just Vertical+  | yPos startPos == yPos endPos = Just Horizontal+  | otherwise = Nothing++{- A map keyed by tuples representing (x,y) co-ordinates, and valued by their+corresponding Pos types -}+posMap :: Map.Map (Int, Int) Pos+posMap = Map.fromList $ catMaybes coordTuples+  where+    coordTuples = zipWith makeTuple (sequence [[posMin .. posMax], [posMin .. posMax]]) $ cycle ['A' .. 'O']+    makeTuple (x : y : _) gridLetter = Just $ ((y, x), Pos y x (gridLetter : show x))+    makeTuple _ _ = Nothing++xPos :: Pos -> Int+xPos (Pos x _ _) = x++yPos :: Pos -> Int+yPos (Pos _ y _) = y++gridValue :: Pos -> String+gridValue (Pos _ _ grid) = grid
wordify.cabal view
@@ -7,7 +7,7 @@ -- hash: f28111054d235bc18dc5e0d167dd433a32a9e0c4e9627cc10c02822b5b2ac44e  name:           wordify-version:        0.1.0.1+version:        0.1.1.0 description:    Please see the README on GitHub at <https://github.com/githubuser/wordify#readme> category:       Game homepage:       https://github.com/happy0/wordify#readme