Drawing Diamonds
September 9, 2014
We begin with auxiliary functions that write an asterisk, a row of n blanks, a properly-spaced row of n asterisks, and an unfilled row of n asterisks:
(define (star) (display #\*))
(define (blanks n)
(do ((n n (- n 1))) ((zero? n)) (display #\space)))
(define (filled n)
(do ((n n (- n 1))) ((= n 1) (star)) (star) (blanks 1)))
(define (unfilled n)
(cond ((= n 1) (star))
(else (star) (blanks (+ n n -3)) (star))))
Note that the unfilled function writes two stars except for the case n = 1, when it writes only one star.
Then the function that draws a diamond is easy. It takes two parameters, the width of the diamond n and a boolean that is #t when the diamond is filled and #f when it is outlined:
(define (diamond n filled?)
(do ((i 1 (+ i 1))) ((< n i))
(blanks (- n i))
(if filled? (filled i) (unfilled i))
(newline))
(do ((i (- n 1) (- i 1))) ((zero? i))
(blanks (- n i))
(if filled? (filled i) (unfilled i))
(newline)))
Here are some examples:
> (diamond 5 #t)
*
* *
* * *
* * * *
* * * * *
* * * *
* * *
* *
*
> (diamond 5 #f)
*
* *
* *
* *
* *
* *
* *
* *
*
You can run the program at http://programmingpraxis.codepad.org/bvsiQ3LM.
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)); }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))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; } }(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, ...
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)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); }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)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); }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]))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) + starsvoid 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; }When run the output looks like this:
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *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 '*')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();
}
/* 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; }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](the previous one is wrong, cannot be deleted/edited?)
Haskell:
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); } }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
Hy, why print if using php programming te output number 2