Haskell变量更新

时间:2015-10-05 06:16:28

标签: haskell poker

  • 我正在哈斯克尔建立一个游戏(扑克游戏),但我是哈斯凯尔的新手,并且在尝试思考如何用纯粹的功能性语言实现一件事时一般都会陷入困境。*
  

游戏是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`

1 个答案:

答案 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.STRefControl.Concurrent.MVar。 但是,这不是“纯功能”方法。 你可以在这里阅读有关状态计算和读者monad的http://learnyouahaskell.com/。评论员认为,状态monad比目前的读者monad更好 - 谢谢,我承认这一点。无论如何,learnyouahaskell是这些信息的重要来源:)。

应用程序方法中最纯粹的功能和用途是使用Functional Reactive Programming行为有一个概念来表示时变值。 有些人会说玻璃钢在这里有点过分,而且可能他们是对的。 但是,当您决定添加GUI和其他IO时,使用由reactive-banana会大大简化您的生活。