【问题标题】:Nim in Haskell : recursive function for creating boardHaskell 中的 Nim:创建板的递归函数
【发布时间】:2026-01-30 01:45:02
【问题描述】:

我正在使用 haskell 创建一个名为 nim 的游戏。总结一下游戏: 通过调用 nim 后跟一个最多为 9 的数字,我为游戏创建了棋盘:

>> nim 3
1 *
2 * *
3 * * *
  1 2 3

这是正常工作的。游戏进行如下:您可以从任意行移除任意数量的星星,但您必须至少移除 1 颗星。您不能在同一回合从第 1 行和第 2 行移除星星。删除最后一颗星的人获胜。

好的,游戏按原样进行,但是当我在每回合后打印棋盘时出现问题。

假设我有上面的板,并提供输入以删除 1 1(从第 1 行删除 1 颗星)

这是我得到的:

0 
2 * *
3 * * *
  1 2 3

0 应该还是 1。

这些是我负责打印电路板的功能 putRow 接受行号和星数。这两个参数是相同的,但我没有运气将函数更改为只接受 1。

putBoard 接收代表游戏棋盘的列表。 putBoard [1,2,3] 从上面的游戏中创建棋盘。我在第一个元素中运行 putStr,然后在列表的其余部分递归调用 putRow。

putRow :: Int -> Int -> IO ()
putRow row num = do putStr (show row)
                    putStr " "
                    putStrLn (concat (replicate num "* "))

putBoard :: Board -> IO ()
putBoard (x:xs) =    putRow x x >> putBoard xs
putBoard [] = putStr " 1 2 3"

putBoard [] 稍后将被替换以在板下创建列号,但那是以后的事了。目前它只是一个仅适用于棋盘大小为 3 的游戏的字符串。

这是在指定行数和星数时处理移动的函数

move :: Board -> Int -> Int -> Board
move board row num = [update r n | (r, n) <- zip [1..] board]
   where update r n = if r == row then (n - num) else n

【问题讨论】:

  • 我是 Haskell 的新手,目前正致力于创建与此类似的游戏。我已尝试运行您的代码,但如何运行移动功能?董事会的类型是什么?

标签: haskell recursion


【解决方案1】:

您的函数putRow 接受两个参数:行号row,以及该行中的星数num

当您从 putBoard 调用该函数时,您会为 rownum 传递相同的 x

putRow x x

所以难怪左边印的数字和星星的数量一致!

您需要做的是为num 传递x(即星数),但为row 传递行的实际索引:

putRow idx x

但是在哪里可以获得idx?好吧,让我们看看:你第一次调用putBoardidx 将是1。然后每次您递归调用putBoard - 这将打印下一行,因此idx 应该增加一。让我们把它写下来:

putBoard :: Int -> Board -> IO ()
putBoard idx (x:xs) = putRow idx x >> putBoard (idx+1) xs
putBoard idx [] = putStr " 1 2 3"

但是现在打电话给putBoard的人必须提供初始的1

putBoard 1 board

这有点不方便,所以你可以像这样将它封装在一个内部函数中:

putBoard :: Board -> IO ()
putBoard = go 1
  where
    go idx (x:xs) = putRow idx x >> go (idx+1) xs
    go idx [] = putStr " 1 2 3"

【讨论】: