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 是:
- 如何获得输出 [[Int]] 到 "give" 一个 [Int] 到 drawQueens 函数的 queens 函数?
2.Why 编译器不是在解释 ['\n'] 吗?如何修改我的代码以获得所需的输出?
这最初是本学期的家庭作业问题,但我现在只为自己做。
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▐█▌ ▐█▌♛▐█▌ ▐█▌
我一直在研究 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 是:
- 如何获得输出 [[Int]] 到 "give" 一个 [Int] 到 drawQueens 函数的 queens 函数?
2.Why 编译器不是在解释 ['\n'] 吗?如何修改我的代码以获得所需的输出?
这最初是本学期的家庭作业问题,但我现在只为自己做。
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▐█▌ ▐█▌♛▐█▌ ▐█▌