Haskell: n 个皇后 ASCII 图形

Haskell: n queens ASCII graphic

我一直在研究 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 图形(见下图)。我的 problems/questions 是:

  1. 如何获得输出 [[Int]] 到 "give" 一个 [Int] 到 drawQueens 函数的 queens 函数?

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

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

My desired output for n = 8

This is what my output of drawQueens looks like currently

感谢您的帮助。

看起来应该可行:

import Control.Monad

forM_ (map drawQueens (queens 8)) putStrLn

forM_ "gives" 每个结果在 drawQueens ...putStrLn.

更新

putStrLn 实际上将字符串打印到控制台,从而 "interpreting" 新行。

例如:

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

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

给 ghci putStr (drawQueens (head (queens 8))) 将改为 "interpret" 字符串,将 \n 转换为换行符,省略引号等。 putStrLn 而不是 putStr 添加换行符结束。

如果 queens 返回的列表为空,这两个都会崩溃。更安全的变体包括 listToMaybe,大小写匹配 and/or 来自其他答案的 forM/traverse 内容。

编译器“解释”'\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_______

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

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▐█▌ ▐█▌♛▐█▌ ▐█▌