2016-07-17 7 views
0

ハスケルのクイーンズ問題に取り組んできましたが、私はそれを大部分解決することができました。ハスケル:nクイーンズASCIIグラフィック

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]が[int]をdrawQueens関数に「与える」ように出力するクイーンズ関数を取得するにはどうすればよいですか?

2.コンパイラが['\ n']を解釈していませんか?希望の出力を得るためにコードを変更するにはどうすればよいですか?

これは当初は学期中の宿題に関する質問でしたが、今は自分のためにやっています。

My desired output for n = 8

This is what my output of drawQueens looks like currently

すべてのご協力いただきありがとうございます。

答えて

3

コンパイラは'\n'を正しく解釈します。改行は実際には「安全な文字」ではありません。ハスケルコードで改行を含む文字列リテラルを直接使用することはできません。そして、GHCiがデフォルトで使っている、よくあるものを出力するprintの出力は、常に有効なHaskellコードを生成しようとするので、これらの改行を再びエスケープします。それは端末にあるとして、あなただけの猫に文字列を、それを指示する場合、これはsurpressedすることができます。

*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_______ 

は、別の問題がまだあります:あなたはactuallチェス盤のように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" 

a b c d e f g h 
8▌♛▐█▌ ▐█▌ ▐█▌ ▐█▌ 
7▐█▌ ▐█▌ ▐♛▌ ▐█▌ 
6▌ ▐█▌ ▐█▌ ▐█▌ ▐♛▌ 
5▐█▌ ▐█▌ ▐█▌♛▐█▌ 
4▌ ▐█▌♛▐█▌ ▐█▌ ▐█▌ 
3▐█▌ ▐█▌ ▐█▌ ▐♛▌ 
2▌ ▐♛▌ ▐█▌ ▐█▌ ▐█▌ 
1▐█▌ ▐█▌♛▐█▌ ▐█▌ 
+0

ありがとう、私はすぐにそれを見てみましょう。 縦型の「1 2 3 4 5 6 7 8」を取得するにはどうすればよいですか? –

0

これは動作するはずのようになります。

import Control.Monad 

forM_ (map drawQueens (queens 8)) putStrLn 

forM_putStrLndrawQueens ...にそれぞれの結果 "を与えます"。

更新

putStrLnは、実際に新しい行を「解釈」することにより、コンソールに文字列を出力します。例えば

:GHCiのを与えるなど

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

は、あなたの迅速な答えをありがとう与えます!しかし、これは私が実際にControl.Monadで作業を始めていないので、私が探しているものではありません。私はその点で私の質問には仕様がないと思う。 –

+0

私の答えにいくつかのタイプミスが見つかりました - 訂正で更新されました。 – ErikR

1

は引用符を含め、バックその文字列を取得するために、GHCiのdrawQueens (head (queens 8))意志出力あなたがコードにコピー - ペーストできる文字列を手渡す、文字通りの\ nは

putStr (drawQueens (head (queens 8)))代わりになります\ nを改行に変換し、引用符を省略するなど、putStrの代わりにputStrLnの最後に改行が追加されます。

クイーンズから返されたリストが空の場合、これらの両方がクラッシュします。より安全なバリアントには、listToMaybe、大文字と小文字の一致、および/またはその他の回答のforM/traverseが含まれます。

+0

あなたの助けてくれてありがとう!しかし、私は本当に "print。drawQueens。head。queens :: Int - > IO()"と何をするべきかわからない。私はこれが関数の構成であると考えましたが、コードのどの部分にこれを追加するべきか分かりません。どんな助けもありがとう。 –

+0

ghci、いくつかのaのタイプIO aでない値が指定された場合、その値を印刷に差し込みます。あなたの "現在の出力"を読んで、私は私の答えを調整します。 – Gurkenglas