/
GameAction.hs
151 lines (127 loc) · 5.95 KB
/
GameAction.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
module GameAction where
import Types
import Locations
import Objects
import Tools
import Text.Printf(printf)
------------------------------ Ïàðñèíã êîìàíäû ---------------------------------
type Parser a = [String] -> Maybe a
-- Ïàðàëëåëüíàÿ êîìïîçèöèÿ ïàðñåðîâ
(<<|>>) :: Parser a -> Parser a -> Parser a
p1 <<|>> p2 = \ss ->
case p1 ss of
Nothing -> p2 ss
Just x -> Just x
cmdP :: (String, [String], ([String] -> Command)) -> Parser Command
cmdP (_, [], _) = \_ -> Nothing
cmdP (shortS, (cmdS:cmdSS), cmdConstr) = \(o:os) -> if (cmdS == o || shortS == o) && (length cmdSS <= length os)
then Just $ cmdConstr os
else Nothing
-- p :: (String, [String], ([String] -> Command))
lookP = ("L", ["Look"], \_ -> Look)
helpP = ("H", ["Help"], \_ -> Help)
openP = ("O", ["Open", "oName"], \(x:_) -> Open x)
examP = ("E", ["Examine", "oName"], \(x:_) -> Examine x)
invP = ("I", ["Inventory"], \_ -> Inventory)
takeP = ("T", ["Take", "oName"], \(x:_) -> Take x)
weldP = ("W", ["Weld", "oName", "oName"], \(x:y:_) -> Weld x y)
goP = ("G", ["Go", "Direction"], \(x:_) -> Go x)
walkP = ([], ["Walk", "Direction"], \(x:_) -> case reads x of
[(dir, _)] -> Walk dir
_ -> NoCommand)
newP = ([], ["New"], \_ -> New)
quitP = ("Q", ["Quit"], \_ -> Quit "Be seen you...")
cmdParsers = map cmdP [lookP, helpP, openP, examP, invP, takeP, weldP, walkP, goP, newP, quitP]
parseCmd :: String -> Maybe Command
parseCmd [] = Nothing
parseCmd str = (foldr1 (<<|>>) cmdParsers) (map capitalize . words $ str)
---------------------------- Ïàðñèíã îáúåêòà -------------------------------
parseObject :: Room -> Objects -> ObjectName -> Either String Object
parseObject room os oName =
case readObject oName (roomObjects room os) of
[] -> Left $ printf "Can't parse an object %s." oName
(x:[]) -> Right x
xs -> Left $ enumerateObjects "What object of these variants: " xs
tryWalk :: Location -> Direction -> GameState -> GameAction
tryWalk loc dir curGS@(GameState locs _ objects) =
case walk loc dir locs of
(Nothing, str) -> PrintMessage str
(Just walkedLoc, str) -> SaveState newGS (str ++ "\n" ++ msg)
where
(msg, newWalkedLoc) = describeLocation walkedLoc (locationObjects walkedLoc objects)
newLocs = updateLocations newWalkedLoc locs
newGS = curGS {gsLocations = newLocs, gsCurrentRoom = locRoom newWalkedLoc}
tryTake :: Object -> GameState -> GameAction
tryTake obj curGS = let objects = gsObjects curGS
in case pickup obj of
(Just newObj, msg) -> SaveState curGS {gsObjects = (replaceObject newObj objects)} msg
(Nothing, msg) -> PrintMessage msg
-- "Ïðèìåíÿåò" ðåçóëüòàò êîìàíäû Weld. Åñëè íîâûé îáúåêò ìîæíî âçÿòü, îí äîáàâëÿåòñÿ â Èíâåíòàðü, åñëè âçÿòü íåëüçÿ, îñòàåòñÿ â ëîêàöèè.
-- Äâà äðóãèõ îáúåêòà óäàëÿþòñÿ èç ëîêàöèè.
applyWeld :: Object -> Object -> Object -> GameState -> (String, GameState)
applyWeld o1 o2 weldedO curGS =
let
curRoom = gsCurrentRoom curGS
objects = gsObjects curGS
(maybePickedUp, _) = pickup weldedO
weldedInCurrentRoom = weldedO {objectRoom = curRoom}
newO1 = o1 {objectRoom = NoRoom}
newO2 = o2 {objectRoom = NoRoom}
(msg, updatedObjects) =
case maybePickedUp of
Just newObj -> (printf "\n%s added to your Inventory." (showObject newObj),
replaceObjectList [newObj, newO1, newO2] objects)
Nothing -> ("", replaceObjectList [weldedInCurrentRoom, newO1, newO2] objects)
in (msg, curGS {gsObjects = updatedObjects})
tryWeld :: Object -> Object -> GameState -> GameAction
tryWeld obj1 obj2 curGS = case weld obj1 obj2 of
Just (newObj, str) ->
let (msg, newGS) = applyWeld obj1 obj2 newObj curGS in
SaveState newGS (str ++ "\n" ++ msg)
Nothing -> PrintMessage (failureWeldObjectsError obj1 obj2)
tryOpen :: Object -> GameState -> GameAction
tryOpen o gs@(GameState _ _ objects) = case open o of
(Nothing, msg) -> PrintMessage msg
(Just obj, msg)-> SaveState (gs {gsObjects = replaceObject obj objects}) msg
tryExamineObject :: Object -> GameAction
tryExamineObject obj = PrintMessage (objectDescription' obj)
-------------------------------------------------------------------------
showInventory' :: GameState -> GameAction
showInventory' (GameState _ _ objects) = PrintMessage $ showInventory objects
look' :: GameState -> GameAction
look' (GameState locs room objects) = case getLocation room locs of
Just loc -> PrintMessage $ lookAround loc objects
Nothing -> PrintMessage $ printf "Some error: no location on room %s was found." (show room)
tryWalk' :: Direction -> GameState -> GameAction
tryWalk' dir curGS@(GameState locs room _) =
case getLocation room locs of
Just loc -> tryWalk loc dir curGS
Nothing -> PrintMessage $ printf "Some error: no location on room %s was found." (show room)
tryGo' :: String -> GameState -> GameAction
tryGo' dirStr curGS = case reads dirStr of
[(dir, _)] -> tryWalk' dir curGS
_ -> PrintMessage $ printf "Some error: can not parse direction %s." dirStr
tryTake' :: ObjectName -> GameState -> GameAction
tryTake' objN gs@(GameState _ room objects) =
case parseObject room objects objN of
Left msg -> PrintMessage msg
Right obj -> tryTake obj gs
tryWeld' :: ObjectName -> ObjectName -> GameState -> GameAction
tryWeld' obj1N obj2N gs@(GameState _ room objects) =
case parseObject room objects obj1N of
Left msg1 -> PrintMessage msg1
Right obj1 -> case parseObject room objects obj2N of
Left msg2 -> PrintMessage msg2
Right obj2 -> tryWeld obj1 obj2 gs
tryOpen' :: ObjectName -> GameState -> GameAction
tryOpen' objN gs@(GameState _ room objects) =
case parseObject room objects objN of
Left _ -> case parseObject InventoryRoom objects objN of
Left msg -> PrintMessage msg
Right obj -> tryOpen obj gs
Right obj -> tryOpen obj gs
tryExamineObject' :: ObjectName -> GameState -> GameAction
tryExamineObject' objN (GameState _ room objects) =
case parseObject room objects objN of
Left msg -> PrintMessage msg
Right obj -> tryExamineObject obj