Drawing Diamonds

September 9, 2014

Given a small positive integer n, write a function that draws a diamond, either filled or in outline as specified by the user. For instance, here are filled and outline diamonds for n = 5:

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

Note that there is a single space between asterisks in the filled version of the diamond.

Your task is to write a program that draws diamonds as described above. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

20 Responses to “Drawing Diamonds”

  1. use strict;
    use warnings;
    
    print diamond( @ARGV );
    
    ## Really a one-liner - but we'll make it easier to read
    sub diamond {
      my( $filled, $size ) = @_;
      return join q(), map {
        q( )x($size-$_),
        q(*),
        $filled ? q( *)x($_-1)
      : $_>1    ? q(  )x($_-2).q( *)
      : q(),
        "\n" } (1..$size, reverse 1..($size-1));
    }
    
  2. Paul said

    In Python.

    def diamond(n, filled=False):
        for i in range(1, n) + range(n, 0, -1):
            txt = ["*"] * i if filled else ["*"] + [" "] * (i-2) + ["*"] * (i > 1)
            print ("{:^" + str(n * 2  - 1) + "s}").format(" ".join(txt))
    
  3. Andras said

    In Java, another approach

    public class DrawingDiamonds {
    
        private static final String S = System.lineSeparator();
    
        public static String drawDiamond(int size, boolean filled) {
            String diamond = "";
            for (int y = 1 - size; y <= (size - 1); y++) {
                for (int x = 1 - size; x <= size - 1; x++) {
                    if (filled) {
                        if ((x + size - 1 >= -y) && (x + size - 1 >= y) && (x - size + 1 <= -y) && (x - size + 1 <= y)) {
                            diamond += "*";
                        } else {
                            diamond += " ";
                        }
                    } else {
                        if ((x + size - 1 == -y) || (x + size - 1 == y) || (x - size + 1 == -y) || (x - size + 1 == y)) {
                            diamond += "*";
                        } else {
                            diamond += " ";
                        }
                    }
                }
                diamond += S;
            }
            return diamond;
        }
    }
  4. Jussi Piitulainen said


    (define (<> n fill?)
      (let ((b (- 1 n)))
        (do ((r b (+ r 1))) ((>= r n))
          (do ((k b (+ k 1))) ((= k n) (newline))
            (write-char (if (fill? n r k) #\* #\space))))))

    (define (solid n r k) (and (< (+ (abs r) (abs k)) n) (odd? (+ r k n))))
    (define (hollow n r k) (= (+ (abs r) (abs k) 1) n))

    ; Usage: (<> n solid) or (<> n hollow) for n = 0, 1, 2, 3, ...

  5. Christophe said

    My solution in Scheme:

    (#%require srfi/1)
    (define (draw-diamond n fill?)
      ; Repeats a string n times.
      (define (string-repeat str n)
        (fold string-append "" (make-list n str)))
      ; Prints a string n times, centered in the given 
      ; width. Fill? determines if the string should be repeated.
      (define (print n width string stringwidth)
        (let* ((whitespace (/ (- width (* n stringwidth)) 2))
               (center-width (max 0 (- (* n stringwidth) (* 2 stringwidth))))
               (center-spaces (string-repeat " " center-width))
               (ws-string (string-repeat " " whitespace)))
          (if fill?
              (string-append ws-string (string-repeat string n) ws-string "\n")
              (if (> n 1)
                  (string-append ws-string string center-spaces string ws-string "\n")
                  (string-append ws-string string ws-string "\n")))))
      (let ((total-width (* n 2))
            (single-star "* ")
            (output ""))
        ; Print the top pyramid.
        (let top ((counter 1))
          (set! output (string-append output (print counter total-width "* " 2)))
          (if (> n counter)
              (top (+ 1 counter))))
        ; Print bottom half.
        
        (let bottom ((counter (- n 1)))
          (set! output (string-append output (print counter total-width "* " 2)))
          (if (> counter 1)
              (bottom (- counter 1))))
        (display output)))
    
    (draw-diamond 10 #t)
    
  6. matthew said

    Let’s use some old-style VT100 cursor movement commands to draw the diamond, instead of generating a bunch of strings (obviously, needs to be run in a suitable terminal window). Looks nicer with a small delay when drawing characters:

    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    
    timespec delay;
    
    void cls() { fprintf(stderr,"\x1b""[2J"); }
    void moveto(int x, int y) { fprintf(stderr,"\x1b""[%d;%dH",y,x); }
    
    void printat(int x, int y, const char *s)
    { 
      nanosleep(&delay,NULL);
      moveto(x,y);
      fprintf(stderr,"%s", s);
    }
    
    int main(int argc, char *argv[])
    {
      int N = atoi(argv[1]);
      delay.tv_nsec = 2000/(N*N)*1000000;
      int k = N, x = N+1, y = 0, xinc = -1, yinc = 1;
      cls();
      while (true) {
        for (int i = 0; i < k; i++) {
          x += xinc; y += yinc;
          printat(x,y,"*");
        }
        xinc = -xinc;
        k--; if (k == 0) break;
        for (int i = 0; i < k; i++) {
          x += xinc; y += yinc;
          printat(x,y,"*");
        }
        yinc = -yinc;
      }
      moveto(1,2*N);
    }
    
  7. matthew said

    And if we want to use strings, it’s easy to generate them recursively. We can extend a solution for n to a solution for n+1 by adding an extra ” ” at the start of each line and adding an extended duplicate of the last line. How we do the extension determines how the diamond is filled:

    -- Unfilled
    e1 1 s = "* " ++ s
    e1 _ (_:s) = "*  " ++ s -- skip previously inserted *
    -- Filled with alternate blanks
    e2 _ s = "* " ++ s
    -- Completely filled
    e3 _ s = "**" ++ s
    
    h _ 0 = ["*\n"]
    h e n = (e n (head s)): map (" "++) s where s = h e (n-1)
    d e n = concat (reverse (tail s) ++ s) where s = h e (n-1)
    main = do putStr (d e1 5) >> putStr (d e2 5) >> putStr (d e3 5)
    
  8. matthew said

    This is better for the main loop of my C++ solution – we don’t need to treat the two passes separately, just rotate by 90° at each corner:

    int main(int argc, char *argv[])
    {
      int N = atoi(argv[1]);
      int x = N+1, y = 0, xinc = -1, yinc = 1;
      delay.tv_nsec = 2000/(N*N)*1000000;
      cls();
      for (int k = 2*N; k > 1; k--) {
        for (int i = 0; i < k/2; i++) {
          x += xinc; y += yinc;
          printat(x,y,"*");
        }
        int t = xinc; xinc = yinc; yinc = -t;
      }
      moveto(1,2*N);
    }
    
  9. Mike said

    Python 3 version. Depends on print function to insert spaces between each argument.

    def foo(n, fill='*'):
        for i in it.chain(range(1,n), range(n,0,-1)):
            print(*(['']*(n-i) + ['*'] + [fill]*(i-2) + ['*'][:i-1]))
    
  10. R.Bravo said
    d = int( input() )
    double = d * 2
    offset = 0
    for i in xrange( 1 , double + 1 ) : 
    	if i > d :
    		stars = ' '.join('*' * (double - i) )
    		offset = i - d
    	else :
    		stars = ' '.join('*' * i)
    		offset = d - i
    	print ' ' * (offset) + stars
    
  11. novatech said
    void diamond(int n)
    {
            for (int i = n-1;i>-n;i--)
            {
                    int g=abs(i)+1;
                    printf("%*c%*c\n",g,'*',2*(n-g),g-n?'*':0);
            }
    }
    
    int main()
    {
           diamond(1);
           diamond(2);
           diamond(-5);
           diamond(5);
           diamond(8);
    
           return 0;
    }
    
  12. Globules said
    import Data.List (intercalate)
    
    mirror :: [a] -> [a]
    mirror xs = xs ++ tail (reverse xs)
    
    half :: Char -> Int -> Int -> String
    half fill n i = replicate (n-i-1) ' ' ++ "*" ++ take i (cycle [' ', fill])
    
    line :: Char -> Int -> Int -> String
    line fill n i = mirror $ half fill n i
    
    diamond :: Char -> Int -> [String]
    diamond fill n = mirror $ map (line fill n) [0..n-1]
    
    beside :: [String] -> [String] -> [String]
    left `beside` right = zipWith ((++) . (++ "    ")) left right
    
    printLines :: [String] -> IO ()
    printLines = putStrLn . intercalate "\n"
    
    main :: IO ()
    main = printLines $ diamond '*' 5 `beside` diamond ' ' 5
    

    When run the output looks like this:

        *            *    
       * *          * *   
      * * *        *   *  
     * * * *      *     * 
    * * * * *    *       *
     * * * *      *     * 
      * * *        *   *  
       * *          * *   
        *            *    
    
  13. svenningsson said

    My Haskell solution.

    import Data.List
    
    diamond :: Bool -> Int -> String
    diamond fill size = unlines [ replicate (size - stars) ' ' ++  dots fill stars | stars <- [1..size] ++ [size-1,size-2..1] ]
      where 
        dots False 1 = "*"
        dots False s = "*" ++ replicate (2 * s - 3) ' ' ++ "*"
        dots True  s = intersperse ' ' (replicate s '*')
    
  14. Naj said

    In C++
    #include
    #include
    int main()
    {
    int i,n;
    cout<>n;
    for( i=0;ii;j–)
    cout<<" ";
    for(int k=0;k<i;k++)
    cout<<" *";
    cout<0;i–)
    {
    for(int j=n;j>i;j–)
    cout<<" ";
    for(int k=0;k<i;k++)
    cout<<" *";
    cout<<"\n";
    }
    getch();
    }

  15. Jussi Piitulainen said
    /* gcc -std=c99 -Wall */
    #include <stdio.h>
    void draw(int n, int (*filled)(int, int, int)) {
      for (int r = 1 - n ; r < n ; ++ r) {
        for (int k = 1 - n ; k < n ; ++ k)
          putchar(filled(n, r, k) ? '*' : ' ');
        putchar('\n');
      }
    }
    int abs(int m) { return (m < 0) ? (-m) : m; }
    int odd(int m) { return m & 1; }
    int sol(int n, int r, int k) { return abs(r) + abs(k) < n && odd(r + k + n); }
    int hol(int n, int r, int k) { return abs(r) + abs(k) + 1 == n; }
    int main() { draw(4, sol); draw(4, hol); return 0; }
    
  16. Without string, formatting, … support and only basic operators (but comprehension lists):

    t n f=[[if c<=0 &&(f||c==0)&& mod x 2==mod y 2 then '*' else ' '
          |x<-w,let c=abs x+abs y-n+1]|y<-w]where w=[-n+1..n-1]
    
  17. (the previous one is wrong, cannot be deleted/edited?)
    Haskell:

    t n f=[[if c<=0&&(x+n).&.1/=y.&.1&&f||c==0 then '*'else ' '|x<-w,let c=abs x+abs y-n+1]|let w=[-n+1..n-1],y<-w]
    
  18. Another Java solution:

    import java.util.Arrays;
    
    public class DrawDiamond {
    
        public static void draw(int size, boolean filled) {
            int middle = (2 * size - 1) / 2;
            char[] line = new char[2 * size - 1];
            for (int i = 0; i <= middle; i++) {
                Arrays.fill(line, ' ');
                int l = middle - i;
                int r = middle + i;
                line[l] = '*';
                line[r] = '*';
                if (filled) {
                    for (int j = l + 2; j < r; j += 2) {
                        line[j] = '*';
                    }
                }
                println(line);
            }
            for (int i = middle - 1; i >= 0; i--) {
                Arrays.fill(line, ' ');
                int l = middle - i;
                int r = middle + i;
                line[l] = '*';
                line[r] = '*';
                if (filled) {
                    for (int j = l + 2; j < r; j += 2) {
                        line[j] = '*';
                    }
                }
                println(line);
            }
        }
    
        private static void println(char[] chars) {
            StringBuilder out = new StringBuilder();
            out.append(chars);
            System.out.println(out);
        }
    
        public static void main(String[] args) {
            draw(5, true);
        }
    }
    
  19. Sarthak Mehta said

    j = 7
    k = 7
    p = 1
    for i in range(8):
    print ” ” * k,” *” * i
    k -=1
    while j > 1:
    j -= 1
    print ” ” * p,” *” * j
    p +=1

  20. Rey Diamond said

    Hy, why print if using php programming te output number 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: