【问题标题】:Haskell: n queens ASCII graphicHaskell:n 个皇后 ASCII 图形
【发布时间】:2016-07-18 06:45:00
【问题描述】:

我一直在研究 Haskell 上的 n 个皇后问题,并且我已经能够解决大部分问题。

queens :: Int -> [[Int]]
queens 0 = [[]]
queens n = [ x : y | y <- queens (n-1), x <- [1..8], safe x y 1]
     where
         safe x [] n = True
         safe x (y:ys) n = and [ x /= y , x /= y + n , x /= y - n , safe x ys (n+1)]
drawQueens :: [Int] -> String
drawQueens [] = ""
drawQueens x = "1 2 3 4 5 6 7 8" ++ ['\n'] ++ concatMap showRow x  ++       ['\n']
    where
        size = length x
        spaces = replicate size '_' ++  ""
        showRow n = take (n - 1) spaces ++ "D" ++ take (size - n) spaces   ++ ['\n']

我的第二个函数 drawQueens 应该理想地将皇后问题的一种解决方案转换为 ASCII 图形(见下图)。我的问题/疑问是:

  1. 如何获得输出 [[Int]] 的 Queens 函数以“给”一个 [Int] 给 drawQueens 函数?

2.为什么编译器不解释['\n']?如何修改我的代码以获得所需的输出?

这最初是学期中的家庭作业问题,但我现在只是为自己做。

My desired output for n = 8

This is what my output of drawQueens looks like currently

感谢您的所有帮助。

【问题讨论】:

    标签: haskell ascii n-queens


    【解决方案1】:

    编译器“解释”'\n' 就好了。只是,换行符并不是真正的“安全字符”,例如:您不能直接在 Haskell 代码中使用带有换行符的字符串文字。 print 的输出,GHCi 默认使用它来打印东西,总是试图生成有效的 Haskell 代码,因此它再次转义这些换行符。如果您只是指示它将字符串按原样发送到终端,这可能会令人感到惊讶:

    *Main> drawQueens [4,2,7,3,6,8,5,1]
    "1 2 3 4 5 6 7 8\n___D____\n_D______\n______D_\n__D_____\n_____D__\n_______D\n____D___\nD_______\n\n"
    *Main> putStrLn $ drawQueens [4,2,7,3,6,8,5,1]
    1 2 3 4 5 6 7 8
    ___D____
    _D______
    ______D_
    __D_____
    _____D__
    _______D
    ____D___
    D_______
    

    还有另一个问题:数字 ow 中的间距与实际棋盘中的间距不同。嗯,这也很容易解决。

    drawQueens :: [Int] -> String
    drawQueens [] = ""
    drawQueens x = "1 2 3 4 5 6 7 8" ++ "\n" ++ concatMap showRow x
        where
            size = length x
            spaces n = concat $ replicate n "□ "
            showRow n = spaces (n - 1) ++ "♛ " ++ spaces (size - n) ++ "\n"
    

    然后给出:

    *Main> putStrLn $ drawQueens [4,2,7,3,6,8,5,1]
    1 2 3 4 5 6 7 8
    □ □ □ ♛ □ □ □ □ 
    □ ♛ □ □ □ □ □ □ 
    □ □ □ □ □ □ ♛ □ 
    □ □ ♛ □ □ □ □ □ 
    □ □ □ □ □ ♛ □ □ 
    □ □ □ □ □ □ □ ♛ 
    □ □ □ □ ♛ □ □ □ 
    ♛ □ □ □ □ □ □ □ 
    

    花式版本:

    chessboardRow, chessboardRow' :: [Maybe Char] -> String
    chessboardRow' [] = "▌"
    chessboardRow' (Just c:cs) = '▌':c:chessboardRow cs
    chessboardRow' (Nothing:cs) = "▌ "++chessboardRow cs
    chessboardRow [] = " "
    chessboardRow (Just c:cs) = '▐':c:chessboardRow' cs
    chessboardRow (Nothing:cs) = "▐█"++chessboardRow' cs
    
    drawQueens :: [Int] -> String
    drawQueens [] = ""
    drawQueens x = "  a b c d e f g h" ++ "\n"
                     ++ concat (reverse $ 
                                 zipWith3 showRow
                                          ['1'..]
                                          (cycle [chessboardRow, chessboardRow'])
                                          x)
                     ++ "\n"
        where
            size = length x
            showRow i rsh n = i : rsh (replicate (n - 1) Nothing
                                          ++ [Just '♛']
                                          ++ replicate (size - n) Nothing)
                                  ++ "\n"
    

    给予

      a b c d e f g h
    8▌♛▐█▌ ▐█▌ ▐█▌ ▐█▌
    7▐█▌ ▐█▌ ▐♛▌ ▐█▌  
    6▌ ▐█▌ ▐█▌ ▐█▌ ▐♛▌
    5▐█▌ ▐█▌ ▐█▌♛▐█▌  
    4▌ ▐█▌♛▐█▌ ▐█▌ ▐█▌
    3▐█▌ ▐█▌ ▐█▌ ▐♛▌  
    2▌ ▐♛▌ ▐█▌ ▐█▌ ▐█▌
    1▐█▌ ▐█▌♛▐█▌ ▐█▌  
    

    【讨论】:

    • 谢谢,我马上去看看。以及如何获得垂直“1 2 3 4 5 6 7 8”?
    【解决方案2】:

    提供 ghci drawQueens (head (queens 8)) 将输出一个字符串,您可以将其复制粘贴到代码中以取回该字符串,包括引号、文字 \n 等。

    给出 ghci putStr (drawQueens (head (queens 8))) 将改为“解释”字符串,将 \n 转换为换行符,省略引号等。putStrLn 而不是 putStr 在末尾添加换行符。

    如果皇后返回的列表为空,这两个都会崩溃。更安全的变体包括 listToMaybe、大小写匹配和/或其他答案中的 forM/traverse 内容。

    【讨论】:

    • 感谢您的帮助!但是,我不太确定如何处理“print.drawQueens.head.queens :: Int -> IO ()”;我认为这是一个函数组合,但我不知道我应该将它添加到我的代码的哪一部分。任何帮助将不胜感激。
    • ghci,当给定任何非 IO a 类型的值时,会将其插入打印。阅读您的“当前输出”,我会调整我的答案。
    【解决方案3】:

    看起来应该可以:

    import Control.Monad
    
    forM_ (map drawQueens (queens 8)) putStrLn
    

    forM_drawQueens ... 中的每个结果“给出”到putStrLn

    更新

    putStrLn 实际上将一个字符串打印到控制台,从而“解释”新行。

    例如:

    ghci> "line 1\nline 2\n"
    "line 1\nline 2\n"
    ghci> putStrLn "line 1\nline 2\n"
    line 1
    line 2
    

    【讨论】:

    • 感谢您的快速答复!然而,这并不是我想要的,因为我还没有真正开始使用 Control.Monad。我想我的问题在这方面缺乏规范。
    • 在我的回答中发现了一些错别字 - 已更新并更正。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    • 2021-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多