2012-12-08 6 views
5

Ich muss ein Haskell-Programm schreiben, das eine Raute-Ausgabe rekursiv generiert. hier einige Beispielausgabe für gegebene Eingangs
Drucken Rautenmuster mit Haskell

input: 1
Ausgang:

* 
* * 
* 

input: 2
Ausgang:

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

Eingang: 3
output:

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

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

Ich schrieb folgende Funktionen:

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 

die folgenden Ausgaben ergibt:

recht 1

* 
* 
* 

ziemlich 2

* 
    * 
    * 
* 
* 
* 
    * 
    * 
    * 

jemand mit den verbleibenden Hälften kann mir helfen ? Danke im Voraus.

+0

Dies wurde in einer Prüfung in PUCSD gefragt. (Pune Universität Informatikabteilung). –

+0

Es ist mir Meister. –

Antwort

4

Für n==0 beschreibt next n das gesamte Bild bis zur Spiegelung. Dies ist bei größeren n nicht mehr der Fall. So wird in einem ersten Schritt, ändern wir die next Funktion zur Ausgabe ein symmetrisches Bild:

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 

Nun beschreibt next n die Positionen aller Sterne. Um sie zu drucken, berechnen wir zuerst die relativen Abstände.

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' 

einer Zeile angewendet, diffs die Liste der Anzahl der Räume zurück wir müssen vor jedem Stern setzen und lpad erzeugt das Bild aus, dass. Drucken Sie es nach wie vor:

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

Dies ist eine gute Lösung für das Problem und verdient mehr Upvotes! – AndrewC

5

ich die Aufgabe mochte, so schrieb ich eine alternative Lösung.

Wir könnten es aufbauen, ein bisschen wie Sie mit einem hübschen Drucker würden. Schauen Sie in das Paket pretty, um diese Ideen zu nehmen und sie richtig zu verwenden, aber lassen Sie uns einfach auf dem alten [String] für diesen bleiben.

Lassen Sie uns zunächst ein leeres Gitter machen

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

Dann ist ein Diamant definieren lassen.

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]] 

Aber wie können wir diese Matrix von [String] miteinander zu verbinden? Zunächst erhalten alle String s, die zusammen nebeneinander verkettet werden sollten, anstatt untereinander transpose verwenden, dann concat sie alle:

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

Um das zu tun eine ganze Matrix müssen wir die Linien verbinden jede Zeile, concat dann alle Zeilen zusammen in eine Liste von Zeilen:

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

Helferfunktionen für den Druck:

put = mapM_ putStrLn 
d n = put $ diamond n 

Sie könnten argumentieren, dass die numerische Lösung effizienter ist, und es ist, aber d 4 ist die größte, die auf meinem Bildschirm passt und nicht langsam ist. Sie könnten auch argumentieren, dass diese Lösung klarer ist.

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

(Es funktioniert für höhere n auch, aber sie würde diesen Beitrag unnötig lange auf der Seite machen.)

+0

Vergessen Sie nicht, für Cebewee [gute Antwort] zu stimmen (http://stackoverflow.com/questions/13778632/print-diamond-pattern-using-haskell/13779048#13779048)! – AndrewC

+0

Danke :) Ich mag es sehr, wie du in deinem Ansatz den Diamanten nur einmal kodieren musst, während in meinem Ansatz zwei Diamanten sind: Einmal in 'next 0' und einmal in' next n'. –

1

Dies ist abgeleitet von AndrewC Lösung. Die Leerzeichen werden rekursiv erzeugt, und ich bevorzuge es, Operatoren zu verwenden, um den Code klarer zu machen:

Eine Verallgemeinerung. Wenn wir möchten, dies haben:

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

dann die Lösung star 3 wo

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

Ich stimme zu, Infixe sind hier super. Obwohl viele Programmierer das Shadowing von '+' nicht mögen würden, wäre vielleicht etwas wie '%' besser (die Standardfixierung 'infixl 9' würde in diesem Fall äquivalent zu 's' infixl 6 'sein und die Definition' infixr ') 6 '(oder 'Infix 4', tatsächlich) würde es tatsächlich ein bisschen effizienter machen). – leftaroundabout

+0

'%' wird in 'Data.Ratio' verwendet. Es macht mir nichts aus, für kleine Beispiele wie dieses zu schattieren. –