目前,我尝试编写一个小游戏程序(Skat)作为一个爱好项目。Skat 是一个花样游戏,两个玩家对抗一个玩家。由于有不同种类的播放器(本地播放器、网络播放器、计算机等),我想抽象出播放器的接口。
我的基本想法是使用 typeclass Player
,它定义了所有类型的事情,玩家必须做和知道的(打牌,得到关于谁赢了把戏的通知等)。然后,整个游戏只是由一个函数playSkat :: (Player a, Player b, Player c) => a -> b -> c -> IO ()
where完成a
,b
并且c
可能是不同类型的玩家。然后玩家可能会以实现定义的方式做出反应。本地玩家会在他的终端上收到一些消息,网络玩家可能会通过网络发送一些信息,而计算机玩家可能会计算新策略。
因为玩家可能想要做一些 IO 并且肯定想要有某种状态来跟踪私人事物,所以它必须生活在某种 Monad 中。所以我想像这样定义Player
类:
class Player p where
playCard :: [Card] -> p -> IO (Card,p)
notifyFoo :: Event -> p -> IO p
...
这种模式似乎与状态转换器非常相似,但我不知道如何处理它。如果我把它写成 IO 之上的一个额外的 monad-transformer,那么一天结束时我就有了三个不同的 monad。我怎样才能以一种好的方式编写这个抽象?
澄清一下,我需要的是,通常的控制流程应该是这样的:
玩花样时,第一个玩家出牌,然后是第二个,最后是第三个。为此,逻辑需要playCard
为每个玩家执行函数 trice。之后,逻辑决定哪位玩家获胜,并将获胜者的信息发送给所有玩家。