扫雷板标签(初级)

2024-04-18

我们得到了一份家庭作业,其中我们得到了一个类似扫雷的样本板,其中有空格而不是数字(板是[String]形式)并且已经放置了地雷。我们需要的是创建一个函数,用数字替换所有空格,数字等于相邻地雷的数量。

除了删除所有带零的空格之外,我无法取得任何真正的进展,这可能根本没有任何用处。我还遇到了 Char 类型的零的问题,这使我无法向其添加例如 +1 。如果可以在没有高级功能的情况下解决这个问题,那就太好了,这样我就可以理解它,但任何解决方案或至少解决方案的想法都可以。

这就是代码开头的样子。

import Data.Char

type Result = [String]

pp :: Result -> IO ()
pp x = putStr (concat (map (++"\n") x)) --prints strings in a column.


sampleInput = ["       ",
               " *     ",
               "    *  ",
               "   *   ",
               "      *",
               "***    ",
               "* *    ",
               "***    "]

minesweeper :: Result -> Result

结果应该是这样的

Prelude>pp(minesweeper sampleInput)
1110000
1*11110
1122*10
001*221
233211*
***2011
*8*3000
***2000

我非常高兴得到任何指导,因为我无法取得任何真正的进展。

更新:做了一些不同但相似的解决方案。您可以查看相关问题here https://stackoverflow.com/questions/58827023/how-to-make-my-function-move-through-two-lists-at-once/58836932#58836932


你在这里需要的叫做“模板卷积”。看这张图片:

111
1x1
111

这是你的模板。在游戏板上选择一个图块,然后将模板放在该图块的顶部。 多少1s 覆盖地雷,我们应该在此图块中显示该数字。例如:

       .....   .....
111    .*...   .....
1x1  + ..x*. = ..3..
111    ...*.   .....
       .....   .....

一旦我们将这个操作应用到整个板上,我们就基本上完成了。

有一些高级设备可以实现此目的,例如 comonad 和数组,但出于本文的目的 我会让事情变得简单,所以我们将以最简单的类型手工起草所有内容。我 我还将在代码中留下一些空白,以便读者不那么无聊。如果你 使能够-fdefer-typed-holes https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#typed-holes,你可以把类似的东西_wut代替... and ghc会告诉您它认为孔的类型应该是什么。


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

    charsToInts :: [[Char]] -> [[Int]]
    charsToInts = (fmap . fmap) charToInt
      where
        charToInt '*' = ...
        charToInt ... = ...
    
    intsToChars :: [[Int]] -> [[Char]]
    intsToChars = ...
    
  2. 嵌套列表不是一种使用起来很舒服的类型。我们将定义一些辅助函数 让事情变得更容易。我们肯定需要的操作是“索引”,即访问 元素按其索引 - 如果它首先存在。

    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 = ...
            | ...                     = ...
    
  3. 现在,介绍一些有趣的东西——模板应用。

    applyStencil :: [[Int]] -> (Int, Int) -> Int
    applyStencil u = sum . Data.Maybe.catMaybes . fmap (... u) . stencil
      where
        stencil :: (Int, Int) -> [(Int, Int)]
        stencil (i, j) = [ (i + di, ...) | di <- ..., dj <- ..., (di, dj) /= ... ]
    

    这有效吗?

    λ applyStencil (charsToInts sampleInput) (3, 5)
    2
    λ applyStencil (charsToInts sampleInput) (6, 1)
    8
    
  4. 剩下要做的就是"map"雷区周围都有模板。为此,我们 将生成一个板,其中每个点的坐标都被写入。我希望在某个地方 您将会明白原因的方式。

    indices :: [[a]] -> [[(Int, Int)]]
    indices u = [ [ ... | ... ] | ... ]
    

    这里的想法是,我们给它一个任何东西的板,它创建一个坐标板 相同的尺寸。

  5. 考虑一下我们目前拥有的类型:

    λ :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"]
    

    看起来不错,不是吗?

  6. 只剩下一些小事情要做:给定两块字符板,将它们重叠起来。这在对另一个问题的回答 https://stackoverflow.com/a/58685116关于列表的列表。(我们收到很多这样的问题 有点晚了。向 Stack Overflow Haskell 教师助理的教授问好 团队!)

  7. 最终解决方案!

    minesweeper x = overlay x (intsToChars . fill . charsToInts $ x)
    

    一点也不难!


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

  1. 为电路板创建专门的类型,以便只能构建正确的电路板。
  2. 为该类型定义一个comonad。
  3. 彻底删除类型并将代码概括为 Store comonad。
  4. 使用高效的数组处理。

但我们探索的想法是持久的。

一些进一步阅读:

  1. 模板卷积的基础知识。 https://jaspervdj.be/posts/2014-11-27-comonads-image-processing.html
  2. 使用标准 comonad 类型。 http://blog.ielliott.io/comonad-transformers-in-the-wild/
  3. 模板卷积的高级优化。 https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/Stencil.pdf

 

让我知道事情的后续!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

扫雷板标签(初级) 的相关文章

  • 在 Haskell 中增长数组

    我想在 Haskell 中实现以下 命令式 算法 给定一个序列对 e0 s0 e1 s1 e2 s2 en sn 其中 e 和 s 部分不一定是自然数不同的是 在每个时间步都会随机选择该序列的一个元素 例如 ei si 并根据 ei si
  • 在Python中创建N*N*N列表时出现问题

    我正在尝试创建一个 3 维 NNPython 中的 N 列表 如下所示 n 3 l 0 n n n 不幸的是 这似乎没有正确地 克隆 列表 正如我所想的那样 gt gt gt l 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
  • 省略号列表[...]并将列表连接到自身[重复]

    这个问题在这里已经有答案了 EDIT 我在最初的例子中很粗心 当我添加列表时不会发生该行为A本身 而是当我添加一个列表时含有 list A to A本身 请参阅下面更正的示例 我试图理解省略号如何列出 那些显示为 当你有一个列表引用本身时发
  • 无点镜头创建不进行类型检查

    在函数中test 我遍历一个列表 从它的成员生成镜头 然后打印一些数据 当我使用有针对性的呼叫风格时 这会起作用 当我使其成为无点时 它无法进行类型检查 为什么会出现这种情况 我该如何解决这个问题 在我看来 GHC 并没有保留排名较高的信息
  • 如何在 LINQ 中执行 String.Replace?

    这是我正在尝试做的事情 但没有成功 我想打电话from x in list1 and join y in list2 where regex Match x Value Success 完成这些步骤后我需要打电话String Replace
  • 如何在 Python 中连接两个列表?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 如何在 Python 中连接两个列表 Example listone 1 2 3 lis
  • 在依赖类型的函数式编程语言中,扁平化列表是否更容易?

    在 haskell 中寻找一个可以展平任意深度嵌套列表的函数时 即应用的函数concat递归并在最后一次迭代时停止 使用非嵌套列表 我注意到这需要有一个更灵活的类型系统 因为随着列表深度的变化 输入类型也会变化 确实 有几个 stackov
  • 当我尝试从列表中删除元素时,如何忽略 ValueError?

    如果我打电话 如何忽略 不在列表中 错误消息a remove x when x不在列表中a 这是我的情况 gt gt gt a range 10 gt gt gt a 0 1 2 3 4 5 6 7 8 9 gt gt gt a remov
  • 将两个 Int 值相除以获得 Float 的正确方法是什么?

    我想分两份IntHaskell 中的值并获得结果Float 我尝试这样做 foo Int gt Int gt Float foo a b fromRational a b 但 GHC 版本 6 12 1 告诉我 无法将预期类型 Intege
  • Haskell 中的分类结构

    Hask通常被认为是一个范畴 其对象是类型 态射是函数 然而 我看到 Conor McBride pigworker 警告不要使用Hask多次 1 https stackoverflow com a 45905082 474311 2 ht
  • 规范化且不可变的数据模型

    Haskell如何解决 规范化不可变数据结构 问题 例如 让我们考虑一个表示前女友 男友的数据结构 data Man Man name String exes Woman data Woman Woman name String exes
  • 如何在 Java 中获得列表的反向列表视图?

    我想在列表上有一个反向列表视图 与List sublist提供列表上的子列表视图 是否有一些函数可以提供此功能 我不想复制该列表 也不想修改该列表 在这种情况下 如果我能在列表上至少获得一个反向迭代器就足够了 另外 我知道如何自己实现这一点
  • “Eta减少”并不总是在Haskell中举行?

    我发现我可以说 LANGUAGE RankNTypes f1 forall b b gt b gt forall c c gt c f1 f id f HLint 告诉我我可以在这里做 Eta 减少 但是 f2 forall b b gt
  • 以下两个 lambda 函数的空间复杂度

    我正在阅读以下内容 https en wikibooks org wiki Haskell Graph reduction https en wikibooks org wiki Haskell Graph reduction 其内容如下
  • Haskell 中列表列表的笛卡尔积

    给定一个长度列表的列表x所有子列表的长度都相同y 输出y x长度列表x包含每个子列表中的一项 例子 x 3 y 2 1 2 3 4 5 6 Output 2 3 8不同的输出 1 3 5 1 4 5 1 3 6 1 4 6 2 3 5 2
  • Haskell 中的中缀运算符优先级

    对于以下 Haskell 表达式 返回 a gt gt f 应该读作 返回a gt gt f or 返回 a gt gt f 这里的相关规则是什么 规则始终是函数应用程序的优先级高于任何运算符 因此 return a gt gt f 被解析
  • 属性错误:“列表”对象没有属性“拆分”

    我正在尝试读取一个文件并用逗号分隔每行中的一个单元格 然后仅显示第一个和第二个单元格 其中包含有关纬度和经度的信息 这是文件 time 纬度 经度 类型2015 03 20T10 20 35 890Z 38 8221664 122 7649
  • Python 将列表追加到列表中

    我正在尝试编写一个通过矩阵的函数 当满足条件时 它会记住该位置 我从一个空列表开始 locations 当函数遍历行时 我使用以下方法附加坐标 locations append x locations append y 函数末尾的列表如下所
  • 查找列表中项目的索引

    给定一个列表 foo bar baz 和列表中的一个项目 bar 如何获取它的索引1 gt gt gt foo bar baz index bar 1 See 文档 https docs python org tutorial datast
  • Collections.sort(list) 和 list.sort(Comparator) 之间的区别

    有什么理由让我应该选择Collections sort list 方法而不是简单地调用list sort 内部Collections sort只是调用sort的方法List无论如何 上课 令人惊讶的是几乎每个人都告诉我使用Collectio

随机推荐