3
\$\begingroup\$

As a beginner I try to implement a vokable memory game. It is still missing some feature (Loading, Display), but I would like to hear how to improve what is already there.

The user should identify matching pairs. Theses are then removed from the game. The game ends when there are not any pairs left.

I think there has to be nicer way to write the code for game' in mainLoop.

Any other suggestions to improve the code are also welcome.

module Main where

import Data.Maybe (fromMaybe)
import qualified Data.List.Safe as List
import Data.List (foldl')

type Vokabel = (String,String)

data Tile = Tile { _front   :: Bool
                 , _vokabel :: Vokabel
                 } deriving (Show)

instance Eq Tile where
  (==) (Tile _ v1) (Tile _ v2) = v1 == v2

getText :: Tile -> String
getText (Tile b (s1,s2)) | b  = s1
                         | not b = s2

newtype Game = Game { _tiles      :: [Tile]
                 } deriving Show

displayGame :: Game -> String
displayGame g = let
                tile2Line s x = s ++ getText x ++ "\n"
                in  foldl' tile2Line "" . _tiles $ g --(foldl' "" tile2Line) . _tiles $ g

makeTile s = Tile True (s++"-Front",s++"-Back")
makeVok s = (s++"-Front",s++"-Back")

gameExampel :: Game
gameExampel = generateGame . map makeVok $ ["Alpha","Beta","Gamma"]

generateGame :: [Vokabel] -> Game
generateGame vs = Game (map (Tile True) vs ++ map (Tile False) vs)

main :: IO ()
main = do
  putStrLn "Vokabel Memory"
  mainLoop gameExampel
  pure ()

chooseTile :: Game -> Int -> Maybe Tile
chooseTile g x = _tiles g List.!! x

mainLoop :: Game -> IO ()
mainLoop game = do
  putStrLn . displayGame $ game
  putStrLn "choose Tile, or exit"
  input <- getLine
  if input == "exit"
    then
      do
    putStrLn "exit now!"
    pure()
  else
    do
    let indexA = read input
    let choosenTileA = chooseTile game indexA
    putStrLn ("choosen: " ++  maybe  "nothing" getText choosenTileA)
    indexB <- read <$> getLine
    let choosenTileB = chooseTile game indexB
    putStrLn ("choosen: " ++  maybe  "nothing" getText choosenTileB)
    let game' = fromMaybe game (do
                                  vokA <- _vokabel <$> choosenTileA
                                  vokB <- _vokabel <$> choosenTileB
                                  if vokA == vokB && indexA /= indexB then
                                            Game <$> ((List.delete <$> choosenTileB) <*> ((List.delete <$> choosenTileA) <*> (pure . _tiles $ game)))
                                          else
                                            pure game
                               )
    if null . drop 1 . _tiles $ game' then
        return ()
      else
        mainLoop game'

EDIT: Having thought about it: I would like to know how to use the state monade in this example.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.