-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathch26monadtrans2.hs
157 lines (125 loc) · 4.07 KB
/
ch26monadtrans2.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
{-# LANGUAGE InstanceSigs #-}
module Chapter26MonadTrans2 where
import Control.Monad
import Control.Monad.IO.Class
import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.Functor.Identity
-- 26.14 Chapter Exercices
-- Write the code
rDec :: Num a => Reader a a
rDec = ReaderT (fmap return (\n -> n - 1))
rShow :: Show a => ReaderT a Identity String
rShow = ReaderT (fmap return show)
rPrintAndInc :: (Num a, Show a) => ReaderT a IO a
rPrintAndInc = ReaderT $ \n -> do
liftIO $ putStrLn $ "Hi: " ++ show n
return $ n + 1
sPrintIncAccum :: (Num a, Show a) => StateT a IO String
sPrintIncAccum = StateT $ \s -> do
liftIO $ putStrLn $ "Hi: " ++ show s
return (show s, s + 1)
-- Fix the code
exciteIsValid :: String -> Bool
exciteIsValid v = '!' `elem` v
maybeExcite :: MaybeT IO String
maybeExcite = do
v <- liftIO getLine
guard $ exciteIsValid v
return v
doExcite :: IO ()
doExcite = do
putStrLn "Di algo excitante!"
excite <- runMaybeT maybeExcite
case excite of
Nothing -> putStrLn "MOAR EXCITE"
Just e -> putStrLn $ "Good, was very excite: " ++ e
-- Hit counter (see "ch26scotty" project)
-- Morra
-- TODO: the current implementation is not really "Morra", but a basic skeleton for a turn based game
data GameState = GameState {
p1 :: Player
, p2 :: Player
, turn :: Turn
, winner :: Maybe Player
}
data Player = Player {
name :: String
, score :: Score
, isHuman :: Bool
} deriving (Show)
data Turn = Turn {
currentPlayer :: GameState -> Player
, updateCurrentPlayer :: GameState -> Player -> GameState
}
type Score = Int
initialGameState :: GameState
initialGameState = GameState {
p1 = Player { name = "p1", score = 0, isHuman = True }
, p2 = Player { name = "p2", score = 0, isHuman = False }
, turn = Turn {
currentPlayer = p1
, updateCurrentPlayer = \gs p -> gs { p1 = p }
}
, winner = Nothing
}
alternateTurns :: GameState -> GameState
alternateTurns gs = if playerName gs == name (p1 gs)
then gs { turn = Turn {
currentPlayer = p2
, updateCurrentPlayer = \gs' p -> gs' { p2 = p }
}
}
else gs { turn = Turn {
currentPlayer = p1
, updateCurrentPlayer = \gs' p -> gs' { p1 = p }
}
}
gameLoop :: StateT GameState IO ()
gameLoop = do
playerInput
gs <- get
when (playerScore gs >= 10) playerWins
gs' <- get
case winner gs' of
Nothing -> changeTurn >> gameLoop
Just _ -> return ()
changeTurn :: StateT GameState IO ()
changeTurn = get >>= (put . alternateTurns)
playerInput :: StateT GameState IO ()
playerInput = do
gs <- get
points <- liftIO $ (if isHuman $ player gs then humanInput else robotInput) gs
incrPlayerScore points
humanInput :: GameState -> IO Score
humanInput gs = do
putStr (playerName gs ++ ": ")
inputS <- getLine
return $ read inputS
robotInput :: GameState -> IO Score
robotInput _ = return 1 -- TODO: improve
incrPlayerScore :: Score -> StateT GameState IO ()
incrPlayerScore n = do
gs <- get
put $ updatePlayerWith gs (\p -> p { score = playerScore gs + n })
playerWins :: StateT GameState IO ()
playerWins = get >>= (put . (\gs -> gs { winner = Just $ player gs }))
player :: GameState -> Player
player gs = currentPlayer (turn gs) gs
playerName :: GameState -> String
playerName = name . player
playerScore :: GameState -> Score
playerScore = score . player
updatePlayer :: GameState -> Player -> GameState
updatePlayer gs = updateCurrentPlayer (turn gs) gs
updatePlayerWith :: GameState -> (Player -> Player) -> GameState
updatePlayerWith gs f = updatePlayer gs (f $ player gs)
main :: IO ()
main = do
(_, gs) <- runStateT gameLoop initialGameState
putStrLn ""
putStrLn "Resultados:"
print $ p1 gs
print $ p2 gs
putStrLn $ "Ganador: " ++ show (winner gs)