我一直在研究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图形(见下图)。我的问题是:
2.为什么编译器不解释[&#39; \ n&#39;]?如何修改代码以实现所需的输出?
这最初是学期间的作业问题,但我现在正在为自己做这件事。
This is what my output of drawQueens looks like currently
感谢您的帮助。
答案 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