Haskell:n queens ASCII图形

Haskell:n queens ASCII图形,haskell,ascii,n-queens,Haskell,Ascii,N Queens,我一直在研究Haskell上的n queens问题,我已经解决了大部分问题 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 /

我一直在研究Haskell上的n queens问题,我已经解决了大部分问题

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']
queens::Int->[[Int]]
皇后区0=[]]

queens n=[x:y | y看起来应该可以这样做:

import Control.Monad

forM_ (map drawQueens (queens 8)) putStrLn
表单
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

看起来这样应该行得通:

import Control.Monad

forM_ (map drawQueens (queens 8)) putStrLn
表单
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

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

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


如果queens返回的列表为空,这两个选项都将崩溃。更安全的变体包括
listToMaybe
、大小写匹配和/或
表单
/
遍历另一个答案中的内容。

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

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


如果queens返回的列表为空,这两种方法都会崩溃。更安全的变体包括
listToMaybe
、大小写匹配和/或
表单
/
遍历另一个答案中的
内容。

编译器“解释”
'\n'
很好。只是,换行符不是真正的“安全字符”,如中所示:不能在Haskell代码中直接使用包含换行符的字符串文字。
print
(GHCi在默认情况下用于打印内容)的输出总是尝试生成有效的Haskell代码,因此它会再次转义这些换行符。如果您只是指示它按字符串的原样对其进行搜索,则会出现这种情况l:

*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"
给予


编译器“解释”
“\n”
很好。只是换行符不是真正的“安全字符”,如中所示:不能在Haskell代码中直接使用包含换行符的字符串文字。
print
(GHCi在默认情况下用于打印内容)的输出总是尝试生成有效的Haskell代码,因此它会再次转义这些换行符。如果您只是指示它按字符串的原样对其进行搜索,则会出现这种情况l:

*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"
给予


谢谢你的快速回答!但是这不是我想要的,因为我还没有真正开始使用Control.Monad。我想我的问题在这方面缺乏规范。在我的回答中发现了一些拼写错误-更新了更正。谢谢你的快速回答!但是这不是我想要的,因为我没有真的开始使用Control.Monad了。我想我的问题在这方面缺乏规范。在我的答案中发现了一些拼写错误-进行了更正。谢谢你的帮助!但是,我不确定如何处理“print.drawQueens.head.queens::Int->IO()”;我认为这是一个函数组合,但我不知道我应该将其添加到代码的哪一部分。任何帮助都将不胜感激。当为某些a提供任何非IO a类型的值时,ghci会将其插入打印。阅读您的“当前输出”,我会调整我的答案。谢谢您的帮助!但是,我不确定如何处理“print.drawQueens.head.queens::Int->IO()”,我认为这是一个函数组合,但我不知道应该将其添加到代码的哪一部分。任何帮助都将不胜感激。当为某些a提供任何不是IO a类型的值时,ghci会将其插入打印。读取“当前输出”,我会调整我的答案。谢谢,我会马上看一看。我怎么得到垂直的“12345678”?谢谢,我会马上看一看。我怎么得到垂直的“12345678”?