我尝试将随机生成的骰子值存储在一些数据结构中,但不知道如何在Haskell中确切地做到这一点。到目前为止,我只能生成随机整数,但我希望能够将它们与相应的颜色值进行比较,并存储颜色(不能真正想象函数会是什么样子)。这是我的代码--
module Main where
import System.IO
import System.Random
import Data.List
diceColor = [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
diceRoll = []
rand :: Int -> [Int] -> IO ()
rand n rlst = do
num <- randomRIO (1::Int, 6)
if n == 0
then printList rlst -- here is where I need to do something to store the values
else rand (n-1) (num:rlst)
printList x = putStrLn (show (sort x))
--matchColor x = doSomething()
main :: IO ()
main = do
--hSetBuffering stdin LineBuffering
putStrLn "roll, keep, score?"
cmd <- getLine
doYahtzee cmd
--rand (read cmd) []
doYahtzee :: String -> IO ()
doYahtzee cmd = do
if cmd == "roll"
then do rand 5 []
else putStrLn "Whatever"在此之后,我想让用户能够保持相同的骰子(就像它的累积点),并让他们选择在骰子上重新滚动左边的骰子-我认为这可以通过遍历数据结构(带有骰子值)并将重复的骰子计数为点并将其存储在另一个数据结构中来实现。如果用户选择重新滚动,他必须能够再次调用随机数并替换原始数据结构中的值。
我来自OOP背景,而Haskell对我来说是一个新领域。非常感谢您的帮助。
发布于 2012-03-07 04:27:10
所以,有几个问题,让我们逐一回答:
First:如何使用System.Random中的函数生成整数以外的其他东西(这是一个很慢的生成器,但对于您的应用程序来说,性能并不重要)。有几种方法,对于你的列表,你必须编写一个函数intToColor:
intToColor :: Int -> String
intToColor n = head . filter (\p -> snd p == n) $ [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]不是很好。不过,如果你以(键,值)的顺序编写这对代码,你会做得更好,因为在Data.List中有一点对“关联列表”的支持,带有查找函数:
intToColor n = fromJust . lookup n $ [(1,"Black"),(2,"Green"),(3,"Purple"),(4,"Red"),(5,"White"),(6,"Yellow")]当然,你也可以忘记Int key在列表中从1到6的事情,因为列表已经被Int索引了:
intToColor n = ["Black","Green","Purple","Red","White","Yellow"] !! n(注意,这个函数有点不同,因为intToColor 0现在是“黑色”,而不是intToColor 1,但考虑到你的目标,这并不是真的很重要,如果它真的让你震惊,你可以写"!!(n-1)“)
但由于您的颜色并不是真正的字符串,而更像是符号,因此您可能应该创建一个Color类型:
data Color = Black | Green | Purple | Red | White | Yellow deriving (Eq, Ord, Show, Read, Enum)所以现在黑色是一个颜色类型的值,你可以在你的程序中的任何地方使用它(如果你写了Blak,GHC会抗议),多亏了自动派生的魔力,你可以比较颜色值,或显示它们,或使用toEnum将Int转换为颜色!
所以现在你可以写:
randColorIO :: IO Color
randColorIO = do
n <- randomRIO (0,5)
return (toEnum n)对于第二个,您希望在数据结构中存储骰子值(颜色),并提供保持相同投掷的选项。因此,首先应该存储几次抛出的结果,考虑到同时抛出的最大数量(5)和数据的复杂性,一个简单的列表就足够了,并且考虑到在Haskell中处理列表的函数数量,它是一个很好的选择。
所以你想掷几个骰子:
nThrows :: Int -> IO [Color]
nThrows 0 = return []
nThrows n = do
c <- randColorIO
rest <- nThrows (n-1)
return (c : rest)这是一个很好的第一种方法,这就是你所做的,或多或少,除非你使用if而不是模式匹配,并且你有一个显式的累加器参数(你打算使用尾部递归吗?),除了严格的累加器(Int而不是lists),并不是更好。
当然,Haskell推广高阶函数,而不是直接递归,所以让我们看看组合符,用Hoogle搜索"Int -> IO a -> IO a“会给出:
replicateM :: Monad m => Int -> m a -> m [a]它做的正是你想要的:
nThrows n = replicateM n randColorIO(我甚至不确定我会把它写成一个函数,因为我发现显式表达式更清晰,而且几乎一样简短)
一旦你有了抛出的结果,你应该检查哪些是相同的,我建议你看看排序,分组,映射和长度来实现这个目标(将你的结果列表转换成相同结果的列表,不是最有效的数据结构,但在这种规模下,是最合适的选择)。然后,将你得到的颜色保留几次只需使用滤镜即可。
然后你应该写一些更多的函数来处理交互和评分:
type Score = Int
yahtzee :: IO Score
yahtzeeStep :: Int -> [[Color]] -> IO [[Color]] -- recursive
scoring :: [[Color]] -> Score因此,我建议保留并传输一个[Color],以跟踪被放在一边的内容。这应该足以满足您的需求。
发布于 2012-03-06 19:12:43
你在这里基本上问了两个不同的问题。第一个问题可以用getColor n = fst . head $ filter (\x -> snd x == n) diceColor这样的函数来回答。
然而,你的第二个问题要有趣得多。您不能替换元素。你需要一个可以递归调用自身的函数,这个函数将驱动你的游戏。它需要接受当前得分和保留的骰子列表作为参数。一旦进入,分数将为零,所保存的骰子列表将为空。然后,它将根据需要掷出尽可能多的骰子来填充列表(我不熟悉Yahtzee的规则),将其输出给用户,并要求选择。如果用户选择结束游戏,该函数将返回分数。如果他选择保留一些骰子,该函数将使用当前得分和保留的骰子列表调用自己。所以,总结一下,playGame :: Score -> [Dice] -> IO Score。
免责声明:我也是Haskell的初学者。
发布于 2012-03-06 18:31:48
首先想到的是:
rand :: Int -> IO [Int]
rand n = mapM id (take n (repeat (randomRIO (1::Int, 6))))尽管haskeller可以删除括号
https://stackoverflow.com/questions/9581521
复制相似问题