List 扫雷艇板标签(初级)

List 扫雷艇板标签(初级),list,haskell,minesweeper,List,Haskell,Minesweeper,我们得到了一份家庭作业,在那里我们得到了一个类似扫雷艇的板样,用空格代替数字,板是[字符串]形式,并且已经放置了地雷。我们需要的是创建一个函数,用数字替换所有空格,这些数字等于相邻矿山的数量 我无法取得任何真正的进展,除了删除所有带零的空格,这可能在任何方面都没有用处。我也有一个问题,零是字符类型,这使我无法添加例如+1到它。如果没有高级功能就可以解决这个问题,那就太好了,所以我可以理解它,但任何解决方案或至少解决方案的想法都可以 这就是代码的开头应该是什么样子 导入数据.Char 类型结果=[

我们得到了一份家庭作业,在那里我们得到了一个类似扫雷艇的板样,用空格代替数字,板是[字符串]形式,并且已经放置了地雷。我们需要的是创建一个函数,用数字替换所有空格,这些数字等于相邻矿山的数量

我无法取得任何真正的进展,除了删除所有带零的空格,这可能在任何方面都没有用处。我也有一个问题,零是字符类型,这使我无法添加例如+1到它。如果没有高级功能就可以解决这个问题,那就太好了,所以我可以理解它,但任何解决方案或至少解决方案的想法都可以

这就是代码的开头应该是什么样子

导入数据.Char 类型结果=[字符串] pp::结果->IO pp x=putStr concat map++\n x-在列中打印字符串。 sampleInput=[,, * , * , * , *, *** , * * , *** ] 扫雷舰::结果->结果 结果应该是这样

Prelude>pp(minesweeper sampleInput)
1110000
1*11110
1122*10
001*221
233211*
***2011
*8*3000
***2000
我非常高兴得到任何指导,因为我无法取得任何真正的进展


更新:做了一些不同但相似的解决方案。您可以查看相关问题

这里需要的是模板卷积。请看这张图片:

111
1x1
111
这是你的模板。在游戏板上选择一块瓷砖,并将模板放在该瓷砖的顶部。 多少个1s叠加地雷,这个数字我们应该显示在这个瓷砖上。例如:

       .....   .....
111    .*...   .....
1x1  + ..x*. = ..3..
111    ...*.   .....
       .....   .....
一旦我们把这个操作应用到整个电路板上,我们基本上就完成了

有一些先进的设备可以实现这一点,比如comonads和array,但就本文而言 我会保持简单,所以我们将用最简单的类型手工起草所有内容。我 我还要在代码中留下一些空白,这样对读者来说就不那么无聊了。如果你 启用后,您可以将_wut等内容替换为。。。和ghc 将告诉你它认为应该是什么类型的洞

我想处理数字,而不是字符:正如你所指出的,字符 不适合算法工作。转换应该是双向的,这样我们就可以显示我们的 结果也是如此

charsToInts :: [[Char]] -> [[Int]]
charsToInts = (fmap . fmap) charToInt
  where
    charToInt '*' = ...
    charToInt ... = ...

intsToChars :: [[Int]] -> [[Char]]
intsToChars = ...
嵌套列表不是很适合使用的类型。我们将定义一些辅助函数 让它更容易。我们肯定需要的操作是索引,即访问 元素的索引-如果它首先存在

lookup2DMaybe :: [[a]] -> (Int, Int) -> Maybe a
lookup2DMaybe u (i, j) = do
    xs' <- lookupMaybe xs  i
    x   <- ...
    return x
  where
    lookupMaybe :: [a] -> Int -> Maybe a
    lookupMaybe xs i
        | 0 <= i && i < length xs = ...
        | ...                     = ...
剩下要做的就是绘制雷区周围的模板。为此,我们正在努力 将生成一个电路板,其中每个点的坐标都被写入。我希望有个地方 你会明白为什么

indices :: [[a]] -> [[(Int, Int)]]
indices u = [ [ ... | ... ] | ... ]
这里的想法是,我们给它一个任何东西的棋盘,它创建一个坐标的棋盘 同样大小

考虑到目前为止我们拥有的类型:

λ :type applyStencil (charsToInts sampleInput) 
applyStencil (charsToInts sampleInput) :: (Int, Int) -> Int
这是一个函数,它把坐标转换成周围地雷的数量 协调。如果我们把它映射到坐标板上会发生什么

fill :: [[Int]] -> [[Int]]
fill u = (fmap.fmap) (... u) (... u)

λ intsToChars (fill (charsToInts sampleInput))
["1110000","1011110","1122110","0011221","2332110","2422011","4843000","2422000"]
看起来不错,不是吗

只剩下一些小事情要做:给定两块字符板,覆盖它们。这一点在 关于列表的列表。这方面我们有很多问题 有点晚了。从哈斯克尔的助教那里向你的教授问好 团队

最终解决方案

minesweeper x = overlay x (intsToChars . fill . charsToInts $ x)
一点也不难

有一些方法可以改进此代码:

为电路板创建专用类型,以便只能构造正确的电路板。 为该类型定义一个comonad。 完全划掉类型,并将代码泛化到storecomonad。 使用高效的数组处理。 但我们所探索的想法是持久的

进一步阅读:


让我知道进展如何

这里需要的是模板卷积。请看这张图片:

111
1x1
111
这是你的模板。在游戏板上选择一块瓷砖,并将模板放在该瓷砖的顶部。 多少个1s叠加地雷,这个数字我们应该显示在这个瓷砖上。例如:

       .....   .....
111    .*...   .....
1x1  + ..x*. = ..3..
111    ...*.   .....
       .....   .....
一旦我们把这个操作应用到整个电路板上,我们基本上就完成了

有一些先进的设备可以实现这一点,比如comonads和array,但就本文而言 我会保持简单,所以我们将用最简单的类型手工起草所有内容。我 我还要在代码中留下一些空白,这样对读者来说就不那么无聊了。如果你 启用后,您可以将_wut等内容替换为。。。和ghc 将告诉你它认为应该是什么类型的洞

我想处理数字,而不是字符:正如你所指出的,字符 不适合算法工作。转换应该是双向的,这样我们就可以显示我们的 结果也是如此

charsToInts :: [[Char]] -> [[Int]]
charsToInts = (fmap . fmap) charToInt
  where
    charToInt '*' = ...
    charToInt ... = ...

intsToChars :: [[Int]] -> [[Char]]
intsToChars = ...
嵌套列表不是很适合使用的类型。我们将定义一些辅助函数 让它更容易。我们肯定需要的操作是索引,即 t是,访问 元素的索引-如果它首先存在

lookup2DMaybe :: [[a]] -> (Int, Int) -> Maybe a
lookup2DMaybe u (i, j) = do
    xs' <- lookupMaybe xs  i
    x   <- ...
    return x
  where
    lookupMaybe :: [a] -> Int -> Maybe a
    lookupMaybe xs i
        | 0 <= i && i < length xs = ...
        | ...                     = ...
剩下要做的就是绘制雷区周围的模板。为此,我们正在努力 将生成一个电路板,其中每个点的坐标都被写入。我希望有个地方 你会明白为什么

indices :: [[a]] -> [[(Int, Int)]]
indices u = [ [ ... | ... ] | ... ]
这里的想法是,我们给它一个任何东西的棋盘,它创建一个坐标的棋盘 同样大小

考虑到目前为止我们拥有的类型:

λ :type applyStencil (charsToInts sampleInput) 
applyStencil (charsToInts sampleInput) :: (Int, Int) -> Int
这是一个函数,它把坐标转换成周围地雷的数量 协调。如果我们把它映射到坐标板上会发生什么

fill :: [[Int]] -> [[Int]]
fill u = (fmap.fmap) (... u) (... u)

λ intsToChars (fill (charsToInts sampleInput))
["1110000","1011110","1122110","0011221","2332110","2422011","4843000","2422000"]
看起来不错,不是吗

只剩下一些小事情要做:给定两块字符板,覆盖它们。这一点在 关于列表的列表。这方面我们有很多问题 有点晚了。从哈斯克尔的助教那里向你的教授问好 团队

最终解决方案

minesweeper x = overlay x (intsToChars . fill . charsToInts $ x)
一点也不难

有一些方法可以改进此代码:

为电路板创建专用类型,以便只能构造正确的电路板。 为该类型定义一个comonad。 完全划掉类型,并将代码泛化到storecomonad。 使用高效的数组处理。 但我们所探索的想法是持久的

进一步阅读:


让我知道进展如何

我想这个问题已经发布了。我不认为我可以把这个作为一个重复来结束,因为这个问题和那个问题都还没有答案。但我会在这里重复我对这个问题的评论:这里有一些提示:1尝试创建一个函数,给定一个坐标,返回给定结果中该坐标周围的所有点;2然后尝试创建一个函数,该函数在给定结果的情况下返回其中所有坐标的嵌套列表,例如,[ab,cd]变为[[0,0,0,1],[1,0,1,1];3试着用这两个函数来解决你的问题。我想这个问题已经发布了。我不认为我可以把这个作为一个重复来结束,因为这个问题和那个问题都还没有答案。但我会在这里重复我对这个问题的评论:这里有一些提示:1尝试创建一个函数,给定一个坐标,返回给定结果中该坐标周围的所有点;2然后尝试创建一个函数,该函数在给定结果的情况下返回其中所有坐标的嵌套列表,例如,[ab,cd]变为[[0,0,0,1],[1,0,1,1];3试着用这两个函数来解决你的问题。好的,这看起来很有希望。然而,我想我需要先解释几件事,以便尝试使用它。我没有遇到过。操作员和我不确定什么功能适用于什么。有没有可能把它改写成没有点的?我也不知道如何打开fdefer类型的孔,也不太明白你附加的链接中有什么。而且,你不需要留下洞。这不是关于它是否无聊,而是关于我能够理解我应该做什么。另外,如果我想避免使用模具,我还可以采取哪些其他方法?谢谢你help@JakubKudlej点运算符是简单的函数组合。我认为在哈斯克尔避免这样做是没有意义的。可以将-fdefer类型的孔作为命令行参数提供给ghc,也可以说:在ghci中设置-fdefer类型的孔。您无法真正避免使用模具,因为这正是问题的定义。总的来说,我不认为它会变得比这更简单。我给了你结构,把问题分成小块。如果你发现任何子问题太难,你可以问一个精确的问题。我真的很想帮助你,但你也必须学习Haskell。那应该是applyStencil行末尾的stencil I,j吗?看起来你好像把它缩小了,但只在一边。嵌套列表上的模板卷积,这很激烈@Jakub Kudlej,准备好第四个优化步骤后,您可以从这里开始:这里有一些关于如何创建自己的模具并将其应用于实际阵列的示例。Haskell中的数组比列表稍微复杂一些,所以我建议首先理解这个答案。@Potato44谢谢你捕捉到这个。好的,这看起来很有希望。然而,我想我需要先解释几件事,以便尝试使用它。我没有遇到过。操作员和我不确定什么功能适用于什么。有没有可能把它改写成没有点的?我也不知道如何打开fdefer类型的孔,也不太明白你附加的链接中有什么。而且,你不需要留下洞。这不是关于它是否无聊,而是关于我能够理解我应该做什么。另外,如果我想避免使用模具,我还可以采取哪些其他方法?谢谢你help@JakubKudlej点运算符是简单的函数组合。我认为在哈斯克尔避免这样做是没有意义的。可以将-fdefer类型的孔作为命令行参数提供给ghc,也可以说:在ghci中设置-fdefer类型的孔。你不可能
切忌使用模版,因为这正是问题的定义。总的来说,我不认为它会变得比这更简单。我给了你结构,把问题分成小块。如果你发现任何子问题太难,你可以问一个精确的问题。我真的很想帮助你,但你也必须学习Haskell。那应该是applyStencil行末尾的stencil I,j吗?看起来你好像把它缩小了,但只在一边。嵌套列表上的模板卷积,这很激烈@Jakub Kudlej,准备好第四个优化步骤后,您可以从这里开始:这里有一些关于如何创建自己的模具并将其应用于实际阵列的示例。Haskell中的数组比列表稍微复杂一些,所以我建议您先理解这个答案。@Potato44谢谢您的理解。