I want to use reactive-banana to write a traveller game that people can write bots for. FRP is completely new to me, and I'm having trouble making a start. I created a more elaborate Graph, when I began, but for my purposes here, I have tried to make it as simple as possible. I'd like some guidance, mostly on where to begin, and how to break this bigger problem down into smaller problems to solve. Here's the initial design.
The idea is to have a Graph of LNodes (with weighted edges I am ignoring for now for simplicity's sake). These LNodes I describe as Planet
s. The Planet
s have a name, a Map of the Players on the Planet
and Resource
s. Players have an id, resources and a Planet.Here's the Data Structues and some associated functions, followed by more discussion.
-- Graph-building records and functions
data PlanetName = Vulcan
| Mongo
| Arakis
| Dantooine
| Tatooine
deriving (Enum,Bounded,Show)
data Planet = Planet {pName :: PlanetName
,player :: IntMap Player
,resources :: Int
} deriving Show
data Player = Player {pid :: Int
,resources :: Int
} deriving Show
makePlanetNodes :: PlanetName -> [LNode Planet]
makePlanetNodes planet = Prelude.map makePlanetNodes' $
zip [planet ..] [0 ..]
where makePlanetNodes' (planet,i) =
(i,Planet {pName = planet, players = IM.empty})
makePlanetGraph p = mkGraph p [(0,1,1),(1,2,2),(2,3,4),(3,4,3),(4,0,2)]
-- Networking and command functions
prepareSocket :: PortNumber -> IO Socket
prepareSocket port = do
sock' <- socket AF_INET Stream defaultProtocol
let socketAddress = SockAddrInet port 0000
bindSocket sock' socketAddress
listen sock' 1
putStrLn $ "Listening on " ++ (show port)
return sock'
acceptConnections :: Socket -> IO ()
acceptConnections sock' = do
forever $ do
(sock, sockAddr) <- Network.Socket.accept sock'
handle <- socketToHandle sock ReadWriteMode
sockHandler sock handle
sockHandler :: Socket -> Handle -> IO ()
sockHandler sock' handle = do
hSetBuffering handle LineBuffering
forkIO $ commandProcessor handle
return ()
commandProcessor :: Handle -> IO ()
commandProcessor handle = untilM (hIsEOF handle) handleCommand >> hClose handle
where
handleCommand = do
line <- hGetLine handle
let (cmd:arg) = words line
case cmd of
"echo" -> echoCommand handle arg
"move" -> moveCommand handle arg
"join" -> joinCommand handle arg
"take" -> takeCommand handle arg
"give" -> giveCommand handle arg
_ -> do hPutStrLn handle "Unknown command"
echoCommand :: Handle -> [String] -> IO ()
echoCommand handle arg = do
hPutStrLn handle (unwords arg)
moveCommand = undefined
joinCommand = undefined
takeCommand = undefined
giveCommand = undefined
Here's what I know so far, my Events will involve types Planet
and Player
. Behaviors
will involve move,join,take,and give. When a player joins, it will create a new Player
event and update the Map on Vulcan with that Player
. Move will allow a traversal from one
LNode
to another,provided the LNode
s are connected by an edge. Take will remove resources
from the current Planet
the Player
is "on" and add those resources
to the
Player
. Give will do the opposite.
How can I break this big problem into smaller problems so I can get my head around this stuff?
Update: Turns out Hunt the Wumpus is not a good choice to help learn FRP, See an explaination of what FRP is for here. It's in a response by Heinrich Apfelmus.
That said, I will totally ignore networking code for now. I could just write some dummy bots to test timing etc.
Update: Some people seem to be interested in this problem, so I am going to track related questions here.