2012-12-08 15 views
5

Potrzebuję napisać program Haskell, który wygeneruje rekursywnie wyjście diamentowe. Oto przykładowe dane wyjściowe dla danego wejścia
Drukuj wzór diamentu za pomocą Haskella

wejściowy 1
Wydajność:

* 
* * 
* 

wejściowy 2
Wydajność:

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

wkład: 3
Wydajność:

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

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

napisałem następujące funkcje:

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 

co daje następujące wyjścia:

całkiem 1

* 
* 
* 

całkiem 2

* 
    * 
    * 
* 
* 
* 
    * 
    * 
    * 

Czy ktoś może mi pomóc z pozostałych połówek ? Z góry dziękuję.

+0

ten został poproszony w egzaminie w PUCSD. (Wydział informatyki uniwersytetu Pune). –

+0

To ja jestem Mistrzem. –

Odpowiedz

4

Dla n==0, next n opisuje cały obraz aż do dublowania. To już nie jest tak w przypadku większych n. Tak więc, w pierwszym etapie, możemy zmienić funkcję next do wyjścia symetrycznego obrazek:

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 

Teraz next n opisujący położenie wszystkich gwiazd. Aby je wydrukować, najpierw obliczamy względne odległości.

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' 

Stosowany do jednej linii, diffs zwraca listę liczbę miejsc musimy postawić przed każdą gwiazdę i lpad generuje obraz z tego. Wydrukuj jak poprzednio:

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

To jest dobre rozwiązanie problemu, o który go poproszono, i zasługuje na więcej awansów! – AndrewC

5

Podobało mi się to zadanie, więc napisałem alternatywne rozwiązanie.

Moglibyśmy go zbudować, trochę jak z ładną drukarką. Zajrzyj do pakietu pretty, aby wziąć te pomysły i właściwie je wykorzystać, ale trzymajmy się tego starego, [String].

Najpierw zróbmy pustej siatki

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

Następnie załóżmy zdefiniować diament.

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

Ale jak możemy dołączyć do tej macierzy [String] razem? Pierwszy uzyskać wszystkie String s, które powinny być łączone razem obok siebie, a nie pod sobą za pomocą transpose, potem concat nich wszystkich:

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

to zrobić na całej matrycy musimy dołączyć linie na w każdym wierszu, a następnie concat wszystkich linii w jeden wykaz linii:

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

funkcje pomocnicze dla druku

put = mapM_ putStrLn 
d n = put $ diamond n 

Można argumentować, że rozwiązanie numeryczne jest wydajniejsze i jest, ale jest ono największe, ale mieści się na moim ekranie i nie jest wolne. Można również argumentować, że to rozwiązanie jest bardziej przejrzyste.

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

(Działa na wyższy n też, ale oni zrobiliby tego posta niepotrzebnie długo na stronie.)

+0

Nie zapomnij zagłosować na cebewee's [dobra odpowiedź] (http://stackoverflow.com/questions/13778632/print-diamond-pattern-using-haskell/13779048#13779048)! – AndrewC

+0

Dzięki :) Bardzo podoba mi się, jak w swoim podejściu wystarczy zakodować diament tylko raz, podczas gdy w moim podejściu są dwa diamenty: Raz w 'następnym 0' i raz w' następnym n'. –

1

ten pochodzi z roztworu AndrewC użytkownika. Bloki przestrzenne są rekursywnie generowane i wolę używać operatorów, aby kod był bardziej przejrzysty:

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 (++) 

Uogólnienie. Jeśli chcielibyśmy mieć to:

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

następnie roztwór jest star 3 gdzie

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

Zgadzam się, infixes są tutaj świetne. Chociaż wielu programistów nie bardzo podobałoby się cieniowaniu '+ ', być może coś w stylu'% 'byłoby lepsze (domyślna stała konfiguracja' infixl 9' byłaby w tym przypadku równoważna + '' infixl 6' i redeclaring it 'infixr 6' (lub "infixr 4", jeśli o to chodzi) rzeczywiście sprawiłoby, że byłaby bardziej wydajna). – leftaroundabout

+0

'%' jest używane w 'Data.Ratio'. Nie mam nic przeciwko shadowingowi za takie małe przykłady. –

Powiązane problemy