游戏是3个玩家(只是为了让它易于解释)。两个玩家将从桌牌中玩牌,一个玩家将从筹码中玩牌。两种类型的玩家都会拿一张牌并在有用的情况下使用它(替换你手中的一张牌)或者只是转储它(如果没有)。 胜利只是全屋或直接。
他们中的两个人有一些
understanding
,这是他们之前同意互相帮助的事情。就像我从桌子上拿K(让我们说)而下一手牌我从表中取出4意味着我要去一个满屋子,因此如果你可以以任何可能的方式你应该帮助。这些玩家中的每一个都应该互相帮助,这样他们中的一个应该在玩家玩堆栈之前赢得胜利而不是牺牲自己。表共有5张牌,每位玩家也是如此
在两个玩家之间实施理解:
我被困在如何跟踪其他玩家从桌子上拿走了什么。我试图通过将卡片添加到我自己手中来实现这一点(几乎记住了这个东西),而在我的手(真实)的洞计算中,我将只采取前五张卡片,同时进行计算以帮助他我要丢掉五张牌,然后用它做计算。 有没有更好的策略来做同样的事情?这可能是微不足道的,但我是哈斯克尔世界的业余爱好者。如果你想要代码,我可以把它拿出来。
我的游戏的基本设置:
data Card = Card {
c :: (Int, Char)
} deriving (Eq, Ord, Show)
data Deck = Deck {
d :: [Card]
} deriving (Show, Eq, Ord)
data Game = Game {
bact1Hand :: [Card],
bact2Hand :: [Card],
orgHand :: [Card],
tableCards :: [Card],
deck :: Deck
} deriving (Show, Eq, Ord)
type GameState a = State Game a`
答案 0 :(得分:1)
如果你想保持简单并且还没有为高级Haskell做好准备,你可以使用递归变换,就像你在评论中建议的一样。
主要思想是创建一个完整描述游戏状态的数据类型data Game
;然后你写了一个“玩家A制作动作1”的功能转换游戏(例如act:: Player -> Action -> Game -> Game
)。
这样的功能改变了整个游戏状态:
它保留从输入到输出的状态,但改变它的某些部分,与玩家和动作有关(例如,手头添加一张牌)。
最后一步是将函数绑定到IO
操作:在最简单的设置中,您创建一个主循环,其中Game
发生更改,等待每次迭代的IO
输入(例如,像OpenGL主循环)。或者,您可以使用Control.Concurrent.MVar异步传递IO
个操作。
所以,简短的代码:
-- | State of the AI
data Mind = Mind
{ overallLogic :: ???
, perPlayerLogic :: [(PlayerID, Understanding)]
}
-- | Undersanding of one player by another player
data Understanding = ???
newtype PlayerID = PlayerID Int
-- | Full state of the player
data Player = Player
{ id :: PlayerID
, hand :: [Card]
, mind :: Mind
, ...
}
-- | indication of the game state
data Status = PlayersTurn PlayerID | PlayerWon PlayerID
-- | Full state of the game
data Game = Game
{ status :: Status
, players :: [Player] -- or consider (Int)Map of player-id
, ...
}
-- | Events in game are passed from IO: they indicate players' actions
data Event = PlayersTurn PlayerID Action ...
| WhateverElseEvent
-- | the function to transform Game's state
react :: Event -> Game -> Game
react ev game = game'
where game' = ... -- here is game logic
在某处您将主循环放在一个单独的线程中:
mainLoop :: MVar Event -> Game -> IO ()
mainLoop mevent game = do
event <- takeMVar mevent
let game' = react event game
if checkIfFinished game'
then return ()
else mainLoop mevent game'
注意尾递归调用 - 循环一直持续到checkIfFinished
返回True
。根据{{1}}州,checkIfFinished
是您决定是否完成游戏的逻辑。
Game
等待另一个线程放东西。
在其他线程中,您可以添加用于输入用户输入的IO操作,从中获取takeMVar
数据,并使用Event
将其放置。
更新:感谢评论,我把一些偏离主题的部分答案放在了底部作为“进一步阅读”。
如果您想记住全球状态,GHC会为您提供两种类型: Data.STRef和Control.Concurrent.MVar。 但是,这不是“纯功能”方法。 你可以在这里阅读有关状态计算和读者monad的http://learnyouahaskell.com/。评论员认为,状态monad比目前的读者monad更好 - 谢谢,我承认这一点。无论如何,learnyouahaskell是这些信息的重要来源:)。
应用程序方法中最纯粹的功能和用途是使用Functional Reactive Programming。 行为有一个概念来表示时变值。 有些人会说玻璃钢在这里有点过分,而且可能他们是对的。 但是,当您决定添加GUI和其他IO时,使用由reactive-banana会大大简化您的生活。