-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathApi.hs
162 lines (133 loc) · 4.81 KB
/
Api.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
{-# LANGUAGE OverloadedStrings #-}
module Vindinium.Api
( startTraining
, startArena
, move
)
where
import Vindinium.Types
import Network.HTTP.Client
import Network.HTTP.Types
import Data.Text (Text, pack, unpack)
import Data.Aeson
import Data.Monoid ((<>))
import Control.Monad (liftM, mzero)
import Control.Monad.IO.Class (liftIO)
import Control.Applicative ((<$>), (<*>))
startTraining :: Maybe Int -> Maybe BoardId -> Vindinium State
startTraining mi mb = do
url <- startUrl "training"
let obj = object ( maybe [] (\i -> [("turns", toJSON i)]) mi
<> maybe [] (\b -> [("map", toJSON b)]) mb
)
request url obj
move :: State -> Dir -> Vindinium State
move s d = do
let url = statePlayUrl s
obj = object [("dir", toJSON d)]
request url obj
startArena :: Vindinium State
startArena = do
url <- startUrl "arena"
let obj = object []
request url obj
startUrl :: Text -> Vindinium Text
startUrl v = liftM (\x -> x <> "/api/" <> v) $ asks settingsUrl
request :: Text -> Value -> Vindinium State
request url val = do
key <- asks settingsKey
initReq <- liftIO $ parseUrl $ unpack url
let req = initReq
{ method = "POST"
, requestHeaders =
[ (hContentType, "application/json")
, (hAccept, "application/json")
, (hUserAgent, "vindinium-starter-haskell")
]
, requestBody = jsonBody (injectKey val key)
}
liftIO $ withManager defaultManagerSettings $ \mgr ->
liftM (decodeBody . responseBody) $ httpLbs req mgr
where
jsonBody = RequestBodyLBS . encode
decodeBody body = case eitherDecode body of
Left e -> error $ "request: unable to decode state: " ++ e
Right s -> s
injectKey (Object a) k =
let
(Object b) = object [("key", toJSON k)]
in
Object (a <> b)
parseBoard :: Int -> String -> Board
parseBoard s t =
Board s $ map parse (chunks t)
where
chunks [] = []
chunks (_:[]) = error "chunks: even chars number"
chunks (a:b:xs) = (a, b):chunks xs
parse (' ', ' ') = FreeTile
parse ('#', '#') = WoodTile
parse ('@', x) = HeroTile $ HeroId $ read [x]
parse ('[', ']') = TavernTile
parse ('$', '-') = MineTile Nothing
parse ('$', x) = MineTile $ Just $ HeroId $ read [x]
parse (a, b) = error $ "parse: unknown tile pattern " ++ (show $ a:b:[])
printTiles :: [Tile] -> Text
printTiles =
foldl (<>) "" . map printTile
where
printTile FreeTile = " "
printTile WoodTile = "##"
printTile (HeroTile (HeroId i)) = "@" <> (pack $ show i)
printTile TavernTile = "[]"
printTile (MineTile Nothing) = "$-"
printTile (MineTile (Just (HeroId i))) = "$" <> (pack $ show i)
instance ToJSON Key where
toJSON (Key k) = String k
instance ToJSON Board where
toJSON b = object [ "size" .= boardSize b
, "tiles" .= (printTiles $ boardTiles b)
]
instance FromJSON State where
parseJSON (Object o) = State <$> o .: "game"
<*> o .: "hero"
<*> o .: "token"
<*> o .: "viewUrl"
<*> o .: "playUrl"
parseJSON _ = mzero
instance FromJSON Game where
parseJSON (Object o) = Game <$> o .: "id"
<*> o .: "turn"
<*> o .: "maxTurns"
<*> o .: "heroes"
<*> o .: "board"
<*> o .: "finished"
parseJSON _ = mzero
instance FromJSON GameId where
parseJSON x = GameId <$> parseJSON x
instance FromJSON Hero where
parseJSON (Object o) = Hero <$> o .: "id"
<*> o .: "name"
<*> o .:? "userId"
<*> o .:? "elo"
<*> o .: "pos"
<*> o .: "life"
<*> o .: "gold"
<*> o .: "mineCount"
<*> o .: "spawnPos"
<*> o .: "crashed"
parseJSON _ = mzero
instance FromJSON HeroId where
parseJSON x = HeroId <$> parseJSON x
instance FromJSON Pos where
parseJSON (Object o) = Pos <$> o .: "x" <*> o .: "y"
parseJSON _ = mzero
instance FromJSON Board where
parseJSON (Object o) = parseBoard <$> o .: "size" <*> o .: "tiles"
parseJSON _ = mzero
instance ToJSON Dir where
toJSON Stay = String "Stay"
toJSON North = String "North"
toJSON South = String "South"
toJSON East = String "East"
toJSON West = String "West"