-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAdventure_crawl.hs
364 lines (265 loc) · 13.7 KB
/
Adventure_crawl.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
import GameContents
import Texts
import Data.List
import Data.Char
import System.Exit
import System.Random
-- Rooms --
{- The Game datatype represents your game state, in other words: It represent where you are in the game.
Your gamestate is determined by which room you are in, the current availible PossibleDirections , what different Objects and Items that exists in your current room, what items you currently have on you and Introtexts.
INVARIANT: All RoomNumber, PossibleDirections, Items, Objects, Bag, Contents, MoveStates and IntroTexts that currently exists in the game-}
type Game = (RoomNumber, PossibleDirections, Items, Objects, Bag, Contents, MoveStates, IntroTexts)
{- The datatype Roomnumber represents the numbering of the rooms.
It represents each rooms number with an integer.
Invariant: Integers 1-18 -}
type RoomNumber = Integer
{-The datatype PossibleDirections represents every direction you could possibly move in from the room you are currently located in.
PossibleDirections is represented by a list of quadruples containing 2 different RoomNumbers, a Description type and a Bool value
Invariant: RoomNumber, RoomNumber, Description, Bool -}
type PossibleDirections = [(RoomNumber, RoomNumber, Description, Bool)]
{- The datatype Description represents a description for a specific PointOfInterests or a room.
Description is represented by a string.
INVARIANT: A list of all PointOfInterests and rooms that exists in the game.
-}
type Description = String
{- The datatype Items represents items in the game.
Items is represented by a list of strings that corresponds to the items names.
INVARIANT: A list of all the items that exists in the game. -}
type Items = [String]
{- The datatype Objects represents objects in the game
Objects is represented by a list of strings that corresponds to the objects names.
INVARIANT: A list of the possible objects in the game. -}
type Objects = [String]
{- The datatype Bag represents the items that you are currently holding.
Bag is represented by a list of strings that corresponds to the names of items.
INVARIANT: A list of the names of all the items that exists in the game.
-}
type Bag = [String]
{-The datatype Contents represents relevant details of all the rooms
Contents is represented with a list of quadruples containing -}
type Contents = [(RoomNumber, Integer, String, Bool)]
{- The datatype MoveStates represents which rooms that are possible to move to from the room your are currently in.
MoveStates is represented by a list of quadruples that contains your current roomnumber, a roomnumber of a room adjacent to your current room, a description of the adjacant room and a boolean value that determines if you have been in the adjacent room before or not.
INVARIANT: All roomnumbers that exists in the game and their corresponding Description. -}
type MoveStates = [(RoomNumber, RoomNumber, Description, Bool)]
{- The datatype IntroTexts represents which rooms you have entered before and the descriptions of the rooms.
IntroTexts is represented by a a list of touples containing a boolean value which states whether you have been in the room before or not and a Description corresponding to that specific room.
INVARIANT: A list of all descriptions that currently exists in the game. -}
type IntroTexts = [(Bool, [Description])]
{- start
Sets the gamestate to its initial values, in other words, starts the game from the beginning.
PRE: true
RETURNS: Returns the datatype Game with a pretedermined set of values.
EXAMPLES: start = (startLoc, getMoves startLoc startMoveStates, roomItem startLoc,roomObject startLoc, startBag, startContents, startMoveStates, startTexts)
-}
start :: Game
start = (startLoc, getMoves startLoc startMoveStates, roomItem startLoc startContents, roomObject startLoc startContents, startBag, startContents, startMoveStates, startTexts)
startLoc = 1
startBag= [""]
startContents = contentList
startMoveStates = moveList
startTexts = textList
{- actions
Lists up the different actions that the player will be able to make.
PRE: True
RETURNS: Returns a list of five strings.
EXAMPLES: actions = ["- Inspect", "- Take", "- Use", "- Move", "- Quit"]
-}
actions :: [String]
actions = ["- Inspect", "- Take", "- Use", "- Move", "- Quit"]
------ Game loop ------
{- runGame
Updates the gamestate with new values.
PRE: true
-}
runGame :: Game -> IO ()
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts) = do
putStrLn (unlines ["----------------------------------------------------"])
if fst (introTexts!! fromInteger loc) == False then do
putStrLn (unlines (snd (introTexts!!fromInteger loc)))
runGame (loc, dir, items, objects, bag, gameContents, moveStates, newTextList (fromInteger loc) introTexts)
else do
putStrLn " "
putStrLn "You see: "
if items == [""] && objects == [""] then putStrLn (unlines ["Nothing in perticular"])
else putStrLn ((unlines items) ++ (unlines objects))
if bag == [""] then putStrLn (unlines ["Your inventory is empty."])
else putStrLn (unlines ["You have " ++ (concat bag) ++ " in your inventory."])
putStrLn "What would you like to do?"
putStrLn (unlines actions)
action <- getLine
---- Actions ----
-- Quit --
if action == "Quit" then do
exitSuccess
-- Inspect --
else if action == "Inspect" then do
putStrLn "What would you like to inspect?"
putStrLn ((unlines items) ++ (unlines objects))
actionInspect <- getLine
if elem actionInspect items == True then do
putStrLn (unlines (itemDesc loc actionInspect))
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else if elem actionInspect objects == True then do
if actionInspect == "Self" then do
putStrLn (unlines(selfText))
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else do
putStrLn (unlines (objectDesc loc actionInspect))
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else do
putStrLn "Cannot inspect that!"
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
-- Take --
else if action == "Take" then do
putStrLn "What would you like to take?"
putStrLn (unlines items)
actionTake <- getLine
if actionTake == "White gem" then do
runRedDeath
else if elem actionTake items == True
then do
runGame (loc, dir, removeItem actionTake items, objects, actionTake:bag, removeContent actionTake gameContents, moveStates, introTexts)
else do
putStrLn "Cannot take that!"
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
-- Use --
else if action == "Use" then do
if bag == [""] && objects == [""] then do
putStrLn "There is nothing to use."
else if bag /= [""] && objects == [""] then do
putStrLn "You cannot use anyting at the moment."
else do
putStrLn "What would you like to use?"
putStrLn ((unlines bag) ++ (unlines objects))
actionUse <- getLine
if elem actionUse objects == True then do
if actionUse == "Self" then do
putStrLn "You cannot use yourself. But maybe you can use an item on you?"
else if actionUse == "Sphinx" && loc == 10 then do
runSphinx (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else if actionUse == "Mirror" && loc == 13 then do
runFinish
else do
let useOn = ""
if checkEvent loc actionUse useOn == True then do
putStrLn (unlines (eventDesc loc actionUse useOn))
runGame (loc, getMoves loc (changeMoveState loc moveStates), items, objects, bag, gameContents, changeMoveState loc moveStates, introTexts)
else do putStrLn ("Cannot use " ++ actionUse ++".")
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else if elem actionUse bag == True then do
putStrLn ("What would you like to use " ++ actionUse ++ " on?")
putStrLn (unlines objects)
useOn <- getLine
if checkEvent loc useOn actionUse == True then do
putStrLn (unlines (eventDesc loc useOn actionUse))
runGame (loc, getMoves loc (changeMoveState loc moveStates), items, objects, removeItem actionUse bag, gameContents, changeMoveState loc moveStates, introTexts)
else do putStrLn ("Cannot use " ++ actionUse ++ " on " ++ useOn ++ ".")
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else do putStrLn ("Wrong input.")
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
-- Move --
else if action == "Move" then do
if dir == [] then do
putStrLn "You have nowhere to go right now."
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else do
putStrLn (unlines ["Where would you like to go?"])
putStrLn (unlines (getMovesText loc moveStates))
input <- getLine
--if input == "" then do
if elem (checkMove loc input moveStates) dir == False then do
putStrLn ("wrong input: '" ++ input ++ "' is not valid.")
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
else if elem (checkMove loc input moveStates) dir == True then do
runGame ((getNewRoom loc input moveStates), getMoves (getNewRoom loc input moveStates) moveStates, roomItem (getNewRoom loc input moveStates) gameContents, roomObject (getNewRoom loc input moveStates) gameContents, bag, gameContents, moveStates, introTexts)
else do
putStrLn "That is not possible right now."
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
-- Error message if wrong input --
else do
putStrLn ("wrong input: '" ++ action ++ "' is not valid.")
runGame (loc, dir, items, objects, bag, gameContents, moveStates, introTexts)
---- Starts the game ----
{- startGame
PRE: true
RETURNS: Returns a string line, the function "start" and the function runGame.
EXAMPLES: startGame = do
putStrLn (unlines ["----------------------------------------------------"])
putStrLn (unlines (snd (textList!!0)))
runGame start
return ()
-}
startGame :: IO ()
startGame = do
putStrLn (unlines ["----------------------------------------------------"])
putStrLn (unlines (snd (textList!!0)))
runGame start -- Calls the game with starting values
return ()
---- Sphinx scene ----
{- runSphinx
runSphinx starts an event in the game involving a mythical creature known as the Sphinx.
PRE: true
RETURNS: Returns a string line and Game with new values, both depending on the choices the player makes.
EXAMPLES: runSphinx = "I will give you two guesses. If you cannot guess correctly, I will have you for dinner."
-}
runSphinx :: Game -> IO ()
runSphinx (loc, dir, items, objects, bag, gameContents, moveStates, introTexts) = do
putStrLn ("I will give you two guesses. If you cannot guess correctly, I will have you for dinner.")
gen <- newStdGen
let num = fst (randomR (0,9) gen)
let riddle = sphinxList!!num
putStrLn (unlines (tail riddle))
answer <- getLine
if elem answer [(head riddle)] == False then do
putStrLn ("You have one more guess.")
answer2 <- getLine
if elem answer2 [(head riddle)] == True then do
putStrLn ("Good guess. You may pass.")
runGame (12, getMoves 12 moveStates, roomItem 12 gameContents, roomObject 12 gameContents, bag, gameContents, moveStates, introTexts)
else do runSphinxDeath
else do
putStrLn ("Good guess. You may pass.")
runGame (12, getMoves 12 moveStates, roomItem 12 gameContents, roomObject 12 gameContents, bag, gameContents, moveStates, introTexts)
---- Completes the game ----
{- runFinish
runFinish starts the final event of the game and lets the player choose if they want to play again or not.
PRE: true
RETURNS: Returns either "runGame start", "exitSuccess" or putStrLn ("Not a valid input. Answer with Y or N.").
EXAMPLES: runFinish = "You step through the mirror and end up infront of the castle.", "You turn around but can't see the passage you came from.", "Right before your eyes the castle starts to vanish."
-}
runFinish :: IO ()
runFinish = do
putStrLn (unlines(["You step through the mirror and end up infront of the castle.", "You turn around but can't see the passage you came from.", "Right before your eyes the castle starts to vanish."]))
putStrLn (unlines(["Congratulations! You have completed the game.", "Want to play again? (Y,N)"]))
action <- getLine
if action == "Y" then do
runGame start
else if action == "N" then do
exitSuccess
else do putStrLn ("Not a valid input. Answer with Y or N.")
---- Death scenes ----
{- runRedDeath
runRedDeath runs the gamestate through one of the death endings and lets the player choose if they want to play again or not.
PRE: true
RETURNS: Returns a text and a new game state.
EXAMPLES: runRedDeath = "Not a valid input. Answer with Y or N."
-}
runRedDeath :: IO ()
runRedDeath = do
putStrLn (unlines(["\"The door closed!? This is bad! REALLY BAD!\" you shout out.", " ", "A red, thin, wall-like structure is coming towards you very slowly. You try touching it but it immediately burns away the tip of your finger.", "You realize immediately what's happening and that there is no escape.", " ", "You are Dead. Want to try again? (Y,N)"]))
action <- getLine
if action == "Y" then do
runGame start
else if action == "N" then do
exitSuccess
else do putStrLn ("Not a valid input. Answer with Y or N.")
runSphinxDeath :: IO ()
runSphinxDeath = do
putStrLn (unlines(["The Sphinx throws itself onto you. As you feel it's jaw crushing your neck, everything gets dark.", "You are Dead. Want to try again? (Y,N)"]))
action <- getLine
if action == "Y" then do
runGame start
else if action == "N" then do
exitSuccess
else do putStrLn ("Not a valid input. Answer with Y or N.")