-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathWorld.hs
More file actions
151 lines (115 loc) · 6.44 KB
/
World.hs
File metadata and controls
151 lines (115 loc) · 6.44 KB
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 World where
import Action
import Control.Applicative
import Control.Monad
import Control.Monad.State
import Data.Char
import Data.List
import qualified Data.Map as Map
import Data.Map(Map)
import Data.Maybe
type Conversations = Map String String
type Interactions = Map Action String
type LocationID = String
type LocationMap = Map LocationID Location
type ObjectID = String
type ObjectMap = Map ObjectID Object
type ObjLocMap = Map LocationID ObjectID
-- | Check if a string matches an object and process an action on the object, return the World State, and a string to tell the user what happened.
--
class Actionable f where
actOn :: f -> Action -> State World [String]
match :: String -> f -> Bool
-- | World data type and constructor. Describes the world with the current location, as well as mappings of all locations and objects in the world, and provides a mapping of objects and characters to locations in the mapping. Also provides a smart data constructor.
--
data World = World { currentLocation :: Location
, worldLocations :: LocationMap
, worldObjects :: ObjectMap
, objectLocations :: ObjLocMap }
world :: Location -> LocationMap -> ObjectMap -> ObjLocMap -> World
world = World
-- | Create the location mapping for the world from a list of locations. Maps the location name to the location ID.
--
mapFromLocations :: [Location] -> LocationMap
mapFromLocations locs = Map.fromList $ map ((,) <$> locationName <*> id) locs
-- | Looks in the world map, and provides a location by its name.
--
getLocationByName :: World -> LocationID -> Location
getLocationByName wrld loc = fromMaybe (error "That is not a valid roon name.") $ Map.lookup loc $ worldLocations wrld
-- | Create the object mapping for the world from a list of objects. Maps the object name to the object ID.
--
mapFromObjects :: [Object] -> ObjectMap
mapFromObjects objs = Map.fromList $ map ((,) <$> objectName <*> id) objs
-- | Looks in the world map, and provides an object by its name.
--
getObjectByName :: World -> ObjectID -> Object
getObjectByName wrld obj = fromMaybe (error "That is not a valid object name.") $ Map.lookup obj $ worldObjects wrld
-- | Create the object location mapping for the world from a list of object name and location name pairs. Maps the object name to the location name.
--
mapFromLocObj :: [(ObjectID, LocationID)] -> ObjLocMap -> ObjLocMap
mapFromLocObj [] m = m
mapFromLocObj ((obj, loc):ols) m = mapFromLocObj ols (Map.insert obj loc m)
-- | Looks in the world map, and provides a list of objects in the current location.
--
getLocByObj :: World -> ObjectID -> LocationID
getLocByObj wrld obj = fromMaybe (error "There are no objects in here.") $ Map.lookup obj $ objectLocations wrld
-- | Is the object requested by the user at their location?
--
isAtLoc :: ObjectID -> LocationID -> World -> Bool
isAtLoc obj loc wrld
| obj `elem` (Map.keys (Map.filter (== loc) (objectLocations wrld))) = True
| otherwise = False
-- | Location data type and constructor. Exits are included in this data type, because they are immutable (in the sense that they cannot be moved from one location to another). Also includes a smart data constructor, as well as eq, and ord instances.
--
data Location = Location { locationName :: String
, locationDescription :: String }
location :: String -> String -> Location
location = Location
instance Eq Location where
(==) l1 l2 = locationName l1 == locationName l2
instance Ord Location where
l1 `compare` l2 = locationName l1 `compare` locationName l2
-- | Object data type and constructor. Describes the objects with name/description and actions. Exits are also modeled as objects in this refactored version for increased generalization. Also includes a smart constructor, as well as show, eq, and actionable instances.
--
data Object = Object { objectName :: String
, objectAlias :: [String]
, objectDescription :: String
, objectReactions :: Action -> State World [String] }
object :: String -> [String] -> String -> (Action -> State World [String]) -> Object
object = Object
exit :: String -> [String] -> String -> (Action -> State World [String]) -> Object
exit = Object
-- | Find the interactions available for the selected object, and return to the AdventureEngine to see if an action can be performed on it.
--
findInteractions :: ObjectID -> LocationID -> World -> Maybe (Action -> State World [String])
findInteractions obj loc wrld = case isAtLoc obj loc wrld of
True -> Just (objectReactions (getObjectByName wrld obj))
False -> Nothing
instance Show Object where
show = show . objectName
instance Eq Object where
(==) o1 o2 = objectName o1 == objectName o2
instance Actionable Object where
actOn = objectReactions
match strng = (strng `elem`) . ((:) <$> objectName <*> objectAlias)
-- | Character data type and constructor. I haven't gotten to the maze portion of the map yet, so I don't have this implemented anywhere. Also includes a smart constructor, as well as an actionable instance.
--
data Character = Character { characterName :: String
, characterAlias :: [String]
, characterTopics :: Conversations
, characterReactions :: Interactions }
deriving (Eq,Show)
character :: String -> [String] -> Conversations -> Interactions -> Character
character = Character
instance Actionable Character where
actOn chrctr action = error "This hasn't been implemented yet."
match strng = (strng `elem`) . ((:) <$> characterName <*> characterAlias)
-- | Takes in a room and the movement command, and updates the current location in the world state.
--
basicMove :: Location -> Action -> State World [String]
basicMove loc Go = do get >>= \wrld -> put wrld{ currentLocation = loc } >>= \_ -> singleAnswer $ (map (const '*') (locationName loc)) ++ "\n" ++ (map toUpper (locationName loc)) ++ "\n" ++ (map (const '*') (locationName loc)) ++ "\n" ++ (locationDescription loc)
basicMove _ _ = singleAnswer "You can't go that direction."
-- | Return the result of performing an action.
--
singleAnswer :: String -> State World [String]
singleAnswer = return . (:[])