3

I am implementing a game engine. Most of my code currently resides in a StateT Game IO () monad. I use IO to get user input, and in fact all IO channels through one function,

getChoice :: Show a => [ a ] -> IO a

which prompts the user with all presented options, reads in a response, and returns it. For a particular flow of user responses (and initial state), the game proceeds deterministically, and I'd like to factor out these user responses to help with testing.

When I try to convert this to use Pipes, what feels most similar is to change all my code which is currently in StateT Game IO (), and make it run in Proxy p, Monad m => Client p [String] String m (). This way I can still 'request' choices from the user, which allows me to write the engine code in a blocking style, assuming that user choices will be provided as I need them.

However, this seems wrong - surely the user should be the Client, and the game engine the Server? What principles can I use to make this distinction correctly?

4

2 回答 2

1

In pipes, Servers 和Clients 几乎可以互换,就像requestand一样respond,上游和下游。一个区别是通过发出第一个请求Client来启动 a 是我们的工作。Session

http://hackage.haskell.org/packages/archive/pipes/2.5.0/doc/html/Control-Proxy-Tutorial.html

我很确定您可以将游戏玩家定义为ClientServer:这都是关于感官的。为什么不将他/她视为键盘输入服务器?

于 2013-06-20T14:22:46.297 回答
1

就像 nushio 所说,两者Client完全Server对称。唯一引入不对称的是合成算子。( >->) 从Client末尾开始, ( >~>) 从Server末尾开始。

由于您使用的是 ( >->),这意味着该Client组件具有“主动性”并让事情顺利进行。这意味着除非生成.Server否则不会做任何事情。除了 the首先开始之外,和之间没有区别。ClientrequestClientClientServer

>->当您将其专门化为 a 时( ) 的类型ClientServer反映了这种主动性的不对称性:

(>->) => ([String] -> Server [String] String IO r)
      -> (()       -> Client [String] String IO r)
      -> (()       -> Session                IO r)

Server即您的用户)只对Client(即游戏引擎)做出反应,这就是为什么服务器必须接受类型参数[String]才能让球滚动。这反映在这样一个事实中:如果游戏引擎从不提示用户选择,那么用户“永远无法运行”,因为用户没有可供选择的选项集。从您指定问题的方式来看,游戏引擎在控制,而不是用户。如果您以相反的方式指定它并让用户驱动游戏引擎,那么角色将被颠倒。

于 2013-06-20T15:46:45.407 回答