使用Data.Map打印游戏板

时间:2018-04-26 23:17:10

标签: haskell

我有Data.Map (Int, Int) [String]代表游戏的棋盘(我假设在地图上的某个位置可以有多个棋子)。让我们说我有以下地图:

fromList [ ( (0,1) , ["piece1", "piece2"] )
         , ( (2,2) , ["piece3", "piece4"] ) ]

我要做的是打印表格,在这种情况下是一张3×3的桌子,地图的元素位于指定的位置,而其余的空格是空的或者有一个' x&# 39 ;.我曾尝试使用foldl和地图以及2的组合,但我不知道应该怎么做。我必须提到我对Haskell很新。任何帮助都会很棒!

输出应为:

x | piece1piece2 | x
x | x | x
x | x | piece3piece4

2 个答案:

答案 0 :(得分:1)

以下是一些可以帮助您入门的代码。它通过迭代板的(行,列)坐标来工作。在迭代中,它查找要为该位置打印的字符串,在失败时默认为“x”。最后,电路板一次打印一行。

最终的格式并不完全是你的想法,但它应该让你在那里大部分时间。

from_unixtime

答案 1 :(得分:0)

我将开始导入Data.Map.Strict。一般来说,这样做的方法是

import qualified Data.Map.Strict as M
import Data.Map.Strict (Map)

你有一个Map (Int, Int) String,你需要打印一个正方形的字符串数组。看来你需要做的第一件事就是计算数组的尺寸。我们可以用索引折叠来做到这一点。对于这份工作来说,它看起来很不错

foldlWithKey' :: (a -> k -> b -> a) -> a -> Map k b -> a

Hrmm ......那些类型变量不是很有用。让我重新评论一下:

foldlWithKey'
  :: (acc -> key -> elem -> acc)
  -> acc
  -> Map key elem
  -> acc

此函数获取累加器的初始值,以及指示如何为映射中的每个键和元素修改该累加器的函数。让我们做一个代表董事会维度的类型:

data Dim = Dim { rows :: !Int, cols :: !Int }

现在我们可以写

getDim :: Map (Int, Int) a -> Dim
getDim = M.foldlWithKey' update (Dim 0 0)
  where
    update (Dim rs cs) (r, c) _
      = Dim (max rs (r + 1)) (max cs (c + 1))

对于Map中的每个条目,我们会根据需要调整行数和列数。

现在我们知道了电路板的尺寸,让我们构建一个更适合打印的表示。最简单的方法是迭代行号和列号,查找映射中的对。让我们开始写一个函数来获得一行:

getRow :: Int -> Dim -> Map (Int, Int) a -> [Maybe a]
getRow r (Dim {cols = cs}) m =
  [ M.lookup (r, c) | c <- [0 .. cs - 1] ]

此处Nothing表示该密钥不在地图中,Just whatever表示该密钥。

现在我们可以用它来获取所有行:

getRows :: Dim -> Map (Int, Int) a -> [[Maybe a]]
getRows dim@(Dim {rows = rs}) m =
  [ getRow r dim m | r <- [0 .. rs - 1] ]

现在我们可以考虑展示了!我将把此留给您,但我建议您考虑使用Data.List.intercalatemap将每一行转换为字符串。