2012-12-08 45 views
5

我需要編寫一個將以遞歸方式生成鑽石輸出的Haskell程序。 這裏是給定的輸入輸出示例
使用Haskell打印鑽石圖案

輸入:1
輸出:

* 
* * 
* 

輸入:2
輸出:

* 
    * * 
    * 
*  * 
* * * * 
*  * 
    * 
    * * 
    * 

輸入:3
輸出:

   *    
      * *    
      *    
      *  *   
     * * * *   
      *  *   
      *    
      * *    
      *    

    *     *  
    * *    * * 
    *     *  
*  *   *  * 
* * * *   * * * * 
*  *   *  * 
    *     *  
    * *    * * 
    *     *  
      *    
      * *    
      *    
      *  *   
     * * * *   
      *  *   
      *    
      * *    
      *  

我寫了以下功能:

next 0 = [1,0,1] 
next n = map (+3^n) (next (n-1)) ++ next (n-1) ++ map (+3^n) (next (n-1)) 
lpad n = map (++"*") (zipWith ($) (map (take)(next (n-1))) ((repeat(repeat ' ')))) 
pretty n = putStrLn $ intercalate "\n" $ lpad n 

這給下面的輸出:

漂亮1

* 
* 
* 

漂亮的2

* 
    * 
    * 
* 
* 
* 
    * 
    * 
    * 

誰能幫助我的另一半?提前致謝。

+0

這被要求在PUCSD考試。 (浦那大學計算機科學系)。 – 2012-12-10 18:33:43

+0

它是我的主人。 – 2012-12-10 18:36:59

回答

4

對於n==0,next n描述了整個圖片直到鏡像。對於更大的n,情況並非如此。因此,在第一步中,我們改變了next功能輸出對稱圖片:

mmap = map . map 

next :: Int -> [[Int]] 
next 0 = [[1],[0,2],[1]] 
next n = sn ++ map (\a -> a ++ map (+2*3^n) a) nn ++ sn 
    where 
    nn = next (n - 1) 
    sn = mmap (+3^n) nn 

現在,next n描述了所有明星的位置。爲了打印它們,我們首先計算相對距離。

diffs :: [Int] -> [Int] 
diffs (x:xs) = x: diffs' x (xs) 
    where 
    diffs' x (y:ys) = y - x - 1 : diffs' y ys 
    diffs' _ [] = [] 
diffs [] = [] 

lpad :: Int -> [[Char]] 
lpad = map (concatMap $ \n -> replicate n ' ' ++ "*") . map diffs . next' 

適用於一條線,diffs返回的,我們需要各路明星之前付諸表決,並lpad從生成畫面的空格數的列表。像以前一樣打印:

pretty :: Int -> IO() 
pretty n = putStrLn $ unlines $ lpad n 
+0

這是一個很好的解決問題的方法,值得讚賞! – AndrewC

5

我喜歡這個任務,所以我寫了一個替代解決方案。

我們可以建立它,有點像使用漂亮的打印機。看看pretty包,以採取這些想法並正確使用它們,但讓我們堅持原來的[String]爲此。

首先,讓我們做一個空的網格

blank :: Int -> [String] 
blank n = replicate (3^n) $ replicate (3^n) ' ' 

然後讓我們定義的鑽石。

diamond :: Int -> [String] 
diamond 0 = ["*"] 
diamond n = let 
     o = diamond (n-1) 
     x = blank (n-1) in 
    joinMatrix [[x,o,x] 
       ,[o,x,o] 
       ,[x,o,x]] 

但是我們怎樣才能將[String]這個矩陣加在一起呢? 首先獲得所有String s表示,應彼此相鄰,而不是在對方使用transpose串聯在一起,然後concat他們都:

joinLine :: [[String]] -> [String] 
joinLine = map concat.transpose 

要做到這一點給整個矩陣,我們需要在加入行每一行,然後Concat的所有的線連成線中的一個列表:

joinMatrix :: [[[String]]] -> [String] 
joinMatrix = concat.map joinLine 

打印輔助功能:

put = mapM_ putStrLn 
d n = put $ diamond n 

你可能會爭辯說,數值解決方案更高效,而且它是,但是d 4是適合我的屏幕並且速度不是很慢的。你也可以爭辯說這個解決方案更清晰。

*Main> d 0 
* 
*Main> d 1 
* 
* * 
* 
*Main> d 2 
    *  
    * * 
    *  
*  * 
* * * * 
*  * 
    *  
    * * 
    *  

(它適用於高N過,但他們會做這個職位不必要的長時間在頁面上。)

+0

不要忘記投票cebewee的[好回答](http://stackoverflow.com/questions/13778632/print-diamond-pattern-using-haskell/13779048#13779048)! – AndrewC

+0

謝謝:)我非常喜歡你的方法,你只需要編碼一次鑽石,而在我的方法中,有兩顆鑽石:一次在'下一個0',一次在'下一個n'。 –

1

這是從AndrewC的解決方案的。空間塊是遞歸生成的,我更願意使用運算符來使代碼更清晰:

diamond 
    = putStr 
    . unlines 
    . fst 
    . (iterate f (["*"], [" "]) !!) 
    where 
    f (d, e) 
     = ( e + d + e 
     ++ d + e + d 
     ++ e + d + e 
      , e + e + e 
     ++ e + e + e 
     ++ e + e + e 
     ) 

    (+) = zipWith (++) 

泛化。 如果我們想有這樣的:

   +    
      - -    
      +    
      -  -   
     + + + +   
      -  -   
      +    
      - -    
      +    
    -     -  
    + +    + + 
    -     -  
+  +   +  + 
- - - -   - - - - 
+  +   +  + 
    -     -  
    + +    + + 
    -     -  
      +    
      - -    
      +    
      -  -   
     + + + +   
      -  -   
      +    
      - -    
      +    

那麼解決的辦法是star 3其中

star 
    = putStr 
    . unlines 
    . (\(d, p, e) -> d) 
    . (iterate f (["-"], ["+"], [" "]) !!) 
    where 
    f (d, p, e) 
     = ( e + p + e 
     ++ d + e + d 
     ++ e + p + e 
      , e + d + e 
     ++ p + e + p 
     ++ e + d + e 
      , e + e + e 
     ++ e + e + e 
     ++ e + e + e 
     ) 

    (+) = zipWith (++) 
+0

我同意,中綴在這裏很棒。雖然很多程序員不太喜歡'+'的陰影,但是''''也許會更好一些(默認固定'infixl 9'在這種情況下等於+'infixl 6';並且將它重新聲明爲'infixr 6'(或'infixr 4',就此而言)實際上會使它更高效一些)。 – leftaroundabout

+0

在'Data.Ratio'中使用'%'。我不介意這樣的小例子的陰影。 –