打印所有可能的世界配置

时间:2011-02-09 20:54:49

标签: haskell

刚开始使用Haskell!作为练习,我正在尝试实现的当前问题如下:

我们有n个正方形,打印所有可能的世界配置:

  • (1)每个方格可以有一个“P”(坑)或不是(2 ^ n种可能性)。
  • (2)在所有n个方格(n + 1种可能性)中最多只能有一个“W”(wumpus)。

将两个正方形表示为两个字符串,这是n = 2的输出示例。我们有(2 ^ n)·(n + 1)=(2 ^ 2)·(2 + 1)= 12个配置。

[[" W"," "],[" "," W"],[" "," "],
 [" W","P"],[" ","PW"],[" ","P"],
 ["PW"," "],["P"," W"],["P"," "],
 ["PW","P"],["P","PW"],["P","P"]]

条件(1)易于实施。环顾四周,我找到了一些方法来表达它:

p 0 = [[]]
p n = [x:xs | x <- [" ","P"], xs <- p (n-1)]

p n = mapM (\x -> [" ","P"]) [1..n]

p n = replicateM n [" ","P"]

我不能声称理解最后两个,但这里是为了完整。

问题:如何添加条件(2)?可以使用列表理解吗? 我不那么好看的新手解决方案涉及这些功能:

insertw :: Int -> [String] -> [String]
insertw n xs 
    | n < 0     = xs
    | n >= lgth = xs
    | otherwise = (take (n) xs) ++ [xs!!n++"W"] ++ (drop (n+1) xs)
    where lgth  = length xs

duplicate :: Int -> [String] -> [[String]]
duplicate i squares 
    | i > lgth   = []
    | otherwise  = (insertw i squares) : duplicate (i+1) squares
    where lgth   = length squares

worlds :: Int -> [[String]]
worlds n = concat . map (duplicate 0) . p $ n

2 个答案:

答案 0 :(得分:3)

条件2不是列表理解的明显候选者,但是您已经编写的工作代码可以被清理。

0lgthduplicate的迭代可以使用map代替显式递归来完成:

duplicate squares = map (\i -> insertw i squares) [0 .. length squares]

duplicate不再使用索引参数,concat . mapconcatMap相同:

worlds = concatMap duplicate . p

如果同时执行droptake,则splitAt通常是更好的操作。

insertw n xs =
    case splitAt n xs of
        (as, []) -> as
        (as, b : bs) -> as ++ ((b ++ "W") : bs)

请注意,我们也删除了length xsxs !! n操作。

作为练习,可以通过压缩duplicate列表的initstails来编写另一个简短的squares函数。

答案 1 :(得分:0)

对我来说似乎很明显:)。在列表推导中,后面的列表可以依赖于先前列表中生成的值。第二个函数通过在添加wumpus时调用第一个函数来生成集合。

p 0 = [[]]
p n = [[x,' ']:xs | x <- [' ','P'], xs <- p (n-1)]

pw 0 = [[]]
pw n = [[x,w]:xs | w <- [' ','W'], x <- [' ','P'], xs <- if w == 'W' then p (n-1) else pw (n-1)]

它不尽可能干净,但我总是发现列表理解为问题带来了优雅:)。完全值得。