Haskell:n皇后ASCII图形

时间:2016-07-17 21:14:09

标签: haskell ascii n-queens

我一直在研究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]]输出到&#34;给出&#34;的皇后功能一个[Int]到drawQueens函数?
  2. 2.为什么编译器不解释[&#39; \ n&#39;]?如何修改代码以实现所需的输出?

    这最初是学期间的作业问题,但我现在正在为自己做这件事。

    My desired output for n = 8

    This is what my output of drawQueens looks like currently

    感谢您的帮助。

3 个答案:

答案 0 :(得分:3)

编译器“解释”'\n'就好了。只是,换行不是真正的“安全字符”,例如:你不能在Haskell代码中直接使用带有换行符的字符串文字。 GHCi默认使用print的输出,打印东西,总是试图生成有效的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▐█▌ ▐█▌♛▐█▌ ▐█▌  

答案 1 :(得分:1)

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

给予ghci putStr (drawQueens (head (queens 8)))代替&#34;解释&#34;字符串,将\ n转换为换行符,省略引号等。putStrLn而不是putStr在最后添加换行符。

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

答案 2 :(得分:0)

看起来应该可行:

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