Sierpinski triangle

From Rosetta Code
Revision as of 12:35, 28 August 2008 by rosettacode>Fogus
Task
Sierpinski triangle
You are encouraged to solve this task according to the task description, using any language you may know.

Produce an ASCII representation of a Sierpinski triangle of order N. For example, the Sierpinski triangle of order 4 should look like this:


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

See also Sierpinski carpet

Ada

This Ada example creates a string of the binary value for each line, converting the '0' values to spaces. <ada>with Ada.Text_Io; use Ada.Text_Io; with Ada.Strings.Fixed; with Interfaces; use Interfaces;

procedure Sieteri_Triangles is

  subtype Practical_Order is Unsigned_32 range 0..4;
  
  
  function Pow(X : Unsigned_32; N : Unsigned_32) return Unsigned_32 is
  begin
     if N = 0 then
        return 1;
     else
        return X * Pow(X, N - 1);
     end if;
  end Pow;
  
  procedure Print(Item : Unsigned_32) is
     use Ada.Strings.Fixed;
     package Ord_Io is new Ada.Text_Io.Modular_Io(Unsigned_32);
     use Ord_Io;
     Temp : String(1..36) := (others => ' ');
     First : Positive;
     Last  : Positive;
  begin
     Put(To => Temp, Item => Item, Base => 2);
     First := Index(Temp, "#") + 1;
     Last  := Index(Temp(First..Temp'Last), "#") - 1;
     for I in reverse First..Last loop
        if Temp(I) = '0' then
           Put(' ');
        else
           Put(Temp(I));
        end if;
     end loop;
     New_Line;
  end Print;
  
  procedure Sierpinski (N : Practical_Order) is
     Size : Unsigned_32 := Pow(2, N);
     V : Unsigned_32 := Pow(2, Size);
  begin
     for I in 0..Size - 1 loop
        Print(V);
        V := Shift_Left(V, 1) xor Shift_Right(V,1);
     end loop;
  end Sierpinski;
  

begin

  for N in Practical_Order loop
     Sierpinski(N);
  end loop;

end Sieteri_Triangles;</ada>

Common Lisp

(defun print-sierpinski (order)
  (loop with size = (expt 2 order)
        repeat size
        for v = (expt 2 (1- size)) then (logxor (ash v -1) (ash v 1))
        do (fresh-line)
           (loop for i below (integer-length v)
                 do (princ (if (logbitp i v) "*" " ")))))

Printing each row could also be done by printing the integer in base 2 and replacing zeroes with spaces: (princ (substitute #\Space #\0 (format nil "~%~2,vR" (1- (* 2 size)) v)))

Replacing the iteration with for v = 1 then (logxor v (ash v 1)) produces a "right" triangle instead of an "equilateral" one.

D

Adapted from Java version (this version is slower than the Python one). <d>import std.stdio, std.string;

string[] sierpinski(int n) {

   string[] parts = ["*"];
   string space = " ";
   for (int i; i < n; i++) {
       string[] parts2;
       foreach (x; parts)
           parts2 ~= space ~ x ~ space;
       foreach (x; parts)
           parts2 ~= x ~ " " ~ x;
       parts = parts2;
       space ~= space;
   }
   return parts;

}

void main() {

   writefln(sierpinski(4).join("\n"));

}</d>

That sierpinski() function can run at compile time too, so with a compile-time join it can compute the whole result at compile-time:

<d> string[] sierpinski(int n) {

   string[] parts = ["*"];
   string space = " ";
   for (int i; i < n; i++) {
       string[] parts2;
       foreach (x; parts)
           parts2 ~= space ~ x ~ space;
       foreach (x; parts)
           parts2 ~= x ~ " " ~ x;
       parts = parts2;
       space ~= space;
   }
   return parts;

}

string joinCT(string[] parts, char sep) {

   string result;
   if (parts.length) {
       foreach (part; parts[0 .. $-1]) {
           result ~= part;
           result ~= sep;
       }
       result ~= parts[$-1];
   }
   return result;

}

pragma(msg, sierpinski(4).joinCT('\n'));

void main() {} </d>

Forth

: stars ( mask -- )
  begin
    dup 1 and if [char] * else bl then emit
    1 rshift  dup
  while space repeat drop ;

: triangle ( order -- )
  1 swap lshift   ( 2^order )
  1 over 0 do
    cr  over i - spaces  dup stars
    dup 2* xor
  loop 2drop ;
 
5 triangle

Haskell

sierpinski 0     = ["*"]
sierpinski (n+1) =    map ((space ++) . (++ space)) down 
                   ++ map (unwords . replicate 2)   down
  where down = sierpinski n
        space = replicate (2^n) ' '

printSierpinski = mapM_ putStrLn . sierpinski

IDL

The only 'special' thing here is that the math is done in a byte array, filled with the numbers 32 and 42 and then output through a "string(array)" which prints the ascii representation of each individual element in the array.

pro sierp,n
  s = (t = bytarr(3+2^(n+1))+32b)
  t[2^n+1] = 42b  
  for lines = 1,2^n do begin
        print,string( (s = t) )
        for i=1,n_elements(t)-2 do if s[i-1] eq s[i+1] then t[i]=32b else t[i]=42b
  end
end

J

There are any number of succinct ways to produce this in J. Here's one that exploits self-similarity:

   |._31]\,(,.~,])^:4,:'* '

Here's one that leverages the relationship between Sierpinski's and Pascal's triangles:

   ' *'{~'1'=(-|."_1[:":2|!/~)i.-16

Java

Translation of: JavaScript

<java>public static void triangle(int n){

       n= 1 << n;
       StringBuilder line= new StringBuilder(); //use a "mutable String"
       char t= 0;
       char u= 0; // avoid warnings
       for(int i= 0;i <= 2 * n;++i)
               line.append(" "); //start empty
       line.setCharAt(n, '*'); //with the top point of the triangle
       for(int i= 0;i < n;++i){
               System.out.println(line);
               u= '*';
               for(int j= n - i;j < n + i + 1;++j){
                       t= (line.charAt(j - 1) == line.charAt(j + 1) ? ' ' : '*');
                       line.setCharAt(j - 1, u);
                       u= t;
               }
               line.setCharAt(n + i, t);
               line.setCharAt(n + i + 1, '*');
       }

}</java>

Translation of: Haskell

<java> import java.util.*;

public class Sierpinski {

   public static List<String> sierpinski(int n)
   {
       List<String> down = Arrays.asList("*");
       String space = " ";
       for (int i = 0; i < n; i++) {
           List<String> newDown = new ArrayList<String>();
           for (String x : down)
               newDown.add(space + x + space);
           for (String x : down)
               newDown.add(x + " " + x);
           down = newDown;
           space += space;
       }
       return down;
   }
   public static void main(String[] args)
   {
       for (String x : sierpinski(4))
           System.out.println(x);
   }

} </java>

JavaScript

<javascript>

function triangle(o) {
  var n = 1<<o, line = new Array(2*n), i,j,t,u;
  for (i=0; i<line.length; ++i) line[i] = ' ';
  line[n] = '*';
  for (i=0; i<n; ++i) {
    document.write(line.join()+"\n");
    u ='*';
    for(j=n-i; j<n+i+1; ++j) {
      t = (line[j-1] == line[j+1] ? ' ' : '*');
      line[j-1] = u;
      u = t;
    }
    line[n+i] = t;
    line[n+i+1] = '*';
  }
}

document.write("

\n");
 triangle(6);
 document.write("

");

</javascript>

This will draw a graphical Sierpinski gasket using turtle graphics.

to sierpinski :n :length
  if :n = 0 [stop]
  repeat 3 [sierpinski :n-1 :length/2  fd :length rt 120]
end
seth 30 sierpinski 5 200

OCaml

<ocaml> let sierpinski n =

 let rec loop down space n =
   if n = 0 then
     down
   else
     loop (List.map (fun x -> space ^ x ^ space) down @
             List.map (fun x -> x ^ " " ^ x) down)
       (space ^ space)
       (n - 1)
 in loop ["*"] " " n

let () =

 List.iter print_endline (sierpinski 4)

</ocaml>

Perl

<perl> sub sierpinski {

   my ($n) = @_;
   my @down = '*';
   my $space = ' ';
   foreach (1..$n) {
       @down = (map("$space$_$space", @down), map("$_ $_", @down));
       $space = "$space$space";
   }
   return @down;

}

print "$_\n" foreach sierpinski 4; </perl>

Pop11

Solution using line buffer in an integer array oline, 0 represents ' ' (space), 1 represents '*' (star).

define triangle(n);
    lvars k = 2**n, j, l, oline, nline;
    initv(2*k+3) -> oline;
    initv(2*k+3) -> nline;
    for l from 1 to 2*k+3 do 0 -> oline(l) ; endfor;
    1 -> oline(k+2);
    0 -> nline(1);
    0 -> nline(2*k+3);
    for j from 1 to k do
        for l from 1 to 2*k+3 do
            printf(if oline(l) = 0 then ' ' else '*' endif);
        endfor;
        printf('\n');
        for l from 2 to 2*k+2 do
            (oline(l-1) + oline(l+1)) rem 2 -> nline(l);
        endfor;
        (oline, nline) -> (nline, oline);
    endfor;
enddefine;

triangle(4);

Alternative solution, keeping all triangle as list of strings

define triangle2(n);
    lvars acc = ['*'], spaces = ' ', j;
    for j from 1 to n do
        maplist(acc, procedure(x); spaces >< x >< spaces ; endprocedure)
         <> maplist(acc, procedure(x); x >< ' ' >< x ; endprocedure) -> acc;
        spaces >< spaces -> spaces;
    endfor;
    applist(acc, procedure(x); printf(x, '%p\n'); endprocedure);
enddefine;

triangle2(4);

Python

<python> def sierpinski(n):

   d = ["*"]
   for i in xrange(n):
       sp = " " * (2 ** i)
       d = [sp+x+sp for x in d] + [x+" "+x for x in d]
   return d

print "\n".join(sierpinski(4)) </python>

Ruby

From the command line: <bash> ruby -le'32.times{|y|print" "*(31-y),(0..y).map{|x|~y&x>0?" .":" A"}}' </bash>


Scheme

As the Haskell. <scheme> (define (sierpinski n)

 (for-each
  (lambda (x) (display (list->string x)) (newline))
  (let loop ((acc (list (list #\*))) (spaces (list #\ )) (n n))
    (if (zero? n)
        acc
        (loop
         (append
          (map (lambda (x) (append spaces x spaces)) acc)
          (map (lambda (x) (append x (list #\ ) x)) acc))
         (append spaces spaces)
         (- n 1))))))

</scheme>