Task
Produce a graphical or ASCII-art representation of a [[wp:Sierpinski carpet|Sierpinski carpet]] of order '''N'''.
For example, the Sierpinski carpet of order '''3''' should look like this:
###########################
# ## ## ## ## ## ## ## ## #
###########################
### ###### ###### ###
# # # ## # # ## # # #
### ###### ###### ###
###########################
# ## ## ## ## ## ## ## ## #
###########################
######### #########
# ## ## # # ## ## #
######### #########
### ### ### ###
# # # # # # # #
### ### ### ###
######### #########
# ## ## # # ## ## #
######### #########
###########################
# ## ## ## ## ## ## ## ## #
###########################
### ###### ###### ###
# # # ## # # ## # # #
### ###### ###### ###
###########################
# ## ## ## ## ## ## ## ## #
###########################
The use of the # character is not rigidly required for ASCII art.
The important requirement is the placement of whitespace and non-whitespace characters.
Related tasks
- [[Sierpinski triangle]]
Ada
with Ada.Text_Io; use Ada.Text_Io;
procedure Sierpinski_Carpet is
subtype Index_Type is Integer range 1..81;
type Pattern_Array is array(Index_Type range <>, Index_Type range <>) of Boolean;
Pattern : Pattern_Array(1..81,1..81) := (Others =>(others => true));
procedure Clear_Center(P : in out Pattern_Array; X1 : Index_Type; X2 : Index_Type;
Y1 : Index_Type; Y2 : Index_Type) is
Xfirst : Index_Type;
Xlast : Index_Type;
Yfirst : Index_Type;
Ylast : Index_Type;
Diff : Integer;
begin
Xfirst :=(X2 - X1 + 1) / 3 + X1;
Diff := Xfirst - X1;
Xlast := Xfirst + Diff;
Yfirst := (Y2 - Y1) / 3 + Y1;
YLast := YFirst + Diff;
for I in XFirst..XLast loop
for J in YFirst..YLast loop
P(I, J) := False;
end loop;
end loop;
end Clear_Center;
procedure Print(P : Pattern_Array) is
begin
for I in P'range(1) loop
for J in P'range(2) loop
if P(I,J) then
Put('*');
else
Put(' ');
end if;
end loop;
New_Line;
end loop;
end Print;
procedure Divide_Square(P : in out Pattern_Array; Order : Positive) is
Factor : Natural := 0;
X1, X2 : Index_Type;
Y1, Y2 : Index_Type;
Division : Index_Type;
Num_Sections : Index_Type;
begin
while Factor < Order loop
Num_Sections := 3**Factor;
Factor := Factor + 1;
X1 := P'First;
Division := P'Last / Num_Sections;
X2 := Division;
Y1 := X1;
Y2 := X2;
loop
loop
Clear_Center(P, X1, X2, Y1, Y2);
exit when X2 = P'Last;
X1 := X2;
X2 := X2 + Division;
end loop;
exit when Y2 = P'Last;
Y1 := Y2;
Y2 := Y2 + Division;
X1 := P'First;
X2 := Division;
end loop;
end loop;
end Divide_Square;
begin
Divide_Square(Pattern, 3);
Print(Pattern);
end Sierpinski_Carpet;
ALGOL 68
PROC in carpet = (INT in x, in y)BOOL: (
INT x := in x, y := in y;
BOOL out;
DO
IF x = 0 OR y = 0 THEN
out := TRUE; GO TO stop iteration
ELIF x MOD 3 = 1 AND y MOD 3 = 1 THEN
out := FALSE; GO TO stop iteration
FI;
x %:= 3;
y %:= 3
OD;
stop iteration: out
);
PROC carpet = (INT n)VOID:
FOR i TO 3 ** n DO
FOR j TO 3 ** n DO
IF in carpet(i-1, j-1) THEN
print("* ")
ELSE
print(" ")
FI
OD;
print(new line)
OD;
carpet(3)
AppleScript
(ES5 Functional version)
-- CARPET MODEL --------------------------------------------------------------
-- sierpinskiCarpet :: Int -> [[Bool]]
on sierpinskiCarpet(n)
-- rowStates :: Int -> [Bool]
script rowStates
on |λ|(x, _, xs)
-- cellState :: Int -> Bool
script cellState
-- inCarpet :: Int -> Int -> Bool
on inCarpet(x, y)
if (x = 0 or y = 0) then
true
else
not ((x mod 3 = 1) and ¬
(y mod 3 = 1)) and ¬
inCarpet(x div 3, y div 3)
end if
end inCarpet
on |λ|(y)
inCarpet(x, y)
end |λ|
end script
map(cellState, xs)
end |λ|
end script
map(rowStates, enumFromTo(0, (3 ^ n) - 1))
end sierpinskiCarpet
-- TEST ----------------------------------------------------------------------
on run
-- Carpets of orders 1, 2, 3
set strCarpets to ¬
intercalate(linefeed & linefeed, ¬
map(showCarpet, enumFromTo(1, 3)))
set the clipboard to strCarpets
return strCarpets
end run
-- CARPET DISPLAY ------------------------------------------------------------
-- showCarpet :: Int -> String
on showCarpet(n)
-- showRow :: [Bool] -> String
script showRow
-- showBool :: Bool -> String
script showBool
on |λ|(bool)
if bool then
character id 9608
else
" "
end if
end |λ|
end script
on |λ|(xs)
intercalate("", map(my showBool, xs))
end |λ|
end script
intercalate(linefeed, map(showRow, sierpinskiCarpet(n)))
end showCarpet
-- GENERIC FUNCTIONS ---------------------------------------------------------
-- enumFromTo :: Int -> Int -> [Int]
on enumFromTo(m, n)
if m > n then
set d to -1
else
set d to 1
end if
set lst to {}
repeat with i from m to n by d
set end of lst to i
end repeat
return lst
end enumFromTo
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- intercalate :: Text -> [Text] -> Text
on intercalate(strText, lstText)
set {dlm, my text item delimiters} to {my text item delimiters, strText}
set strJoined to lstText as text
set my text item delimiters to dlm
return strJoined
end intercalate
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
███
█ █
███
█████████
█ ██ ██ █
█████████
███ ███
█ █ █ █
███ ███
█████████
█ ██ ██ █
█████████
███████████████████████████
█ ██ ██ ██ ██ ██ ██ ██ ██ █
███████████████████████████
███ ██████ ██████ ███
█ █ █ ██ █ █ ██ █ █ █
███ ██████ ██████ ███
███████████████████████████
█ ██ ██ ██ ██ ██ ██ ██ ██ █
███████████████████████████
█████████ █████████
█ ██ ██ █ █ ██ ██ █
█████████ █████████
███ ███ ███ ███
█ █ █ █ █ █ █ █
███ ███ ███ ███
█████████ █████████
█ ██ ██ █ █ ██ ██ █
█████████ █████████
███████████████████████████
█ ██ ██ ██ ██ ██ ██ ██ ██ █
███████████████████████████
███ ██████ ██████ ███
█ █ █ ██ █ █ ██ █ █ █
███ ██████ ██████ ███
███████████████████████████
█ ██ ██ ██ ██ ██ ██ ██ ██ █
███████████████████████████
Or, defining the Sierpinski carpet weave more simply in terms of generic abstractions like '''zipWith''' and '''concatMap''':
-- weave :: [String] -> [String]
on weave(xs)
script thread
property f : zipWith(my append)
on |λ|(x)
f's |λ|(f's |λ|(xs, x), xs)
end |λ|
end script
script blank
on |λ|(x)
replicate(length of x, space)
end |λ|
end script
concatMap(thread, {xs, map(blank, xs), xs})
end weave
-- TEST ---------------------------------------------------
on run
-- sierpinksi :: Int -> String
script sierpinski
on |λ|(n)
unlines(item n of take(n, ¬
iterate(weave, {character id 9608})))
end |λ|
end script
sierpinski's |λ|(3)
end run
-- GENERIC ABSTRACTIONS -----------------------------------
-- Append two lists.
-- append (++) :: [a] -> [a] -> [a]
-- append (++) :: String -> String -> String
on append(xs, ys)
xs & ys
end append
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lng to length of xs
set acc to {}
tell mReturn(f)
repeat with i from 1 to lng
set acc to acc & |λ|(item i of xs, i, xs)
end repeat
end tell
return acc
end concatMap
-- iterate :: (a -> a) -> a -> Gen [a]
on iterate(f, x)
script
property v : missing value
property g : mReturn(f)'s |λ|
on |λ|()
if missing value is v then
set v to x
else
set v to g(v)
end if
return v
end |λ|
end script
end iterate
-- length :: [a] -> Int
on |length|(xs)
set c to class of xs
if list is c or string is c then
length of xs
else
(2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
end if
end |length|
-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
if class of f is script then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min
-- replicate :: Int -> String -> String
on replicate(n, s)
set out to ""
if n < 1 then return out
set dbl to s
repeat while (n > 1)
if (n mod 2) > 0 then set out to out & dbl
set n to (n div 2)
set dbl to (dbl & dbl)
end repeat
return out & dbl
end replicate
-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
set c to class of xs
if list is c then
if 0 < n then
items 1 thru min(n, length of xs) of xs
else
{}
end if
else if string is c then
if 0 < n then
text 1 thru min(n, length of xs) of xs
else
""
end if
else if script is c then
set ys to {}
repeat with i from 1 to n
set v to xs's |λ|()
if missing value is v then
return ys
else
set end of ys to v
end if
end repeat
return ys
else
missing value
end if
end take
-- unlines :: [String] -> String
on unlines(xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set str to xs as text
set my text item delimiters to dlm
str
end unlines
-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f)
script
on |λ|(xs, ys)
set lng to min(|length|(xs), |length|(ys))
if 1 > lng then return {}
set xs_ to take(lng, xs) -- Allow for non-finite
set ys_ to take(lng, ys) -- generators like cycle etc
set lst to {}
tell mReturn(f)
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs_, item i of ys_)
end repeat
return lst
end tell
end |λ|
end script
end zipWith
█████████
█ ██ ██ █
█████████
███ ███
█ █ █ █
███ ███
█████████
█ ██ ██ █
█████████
Applesoft BASIC
100 HGR
110 POKE 49234,0
120 DEF FN M(X) = X - INT (D * 3) * INT (X / INT (D * 3))
130 DE = 4
140 DI = 3 ^ DE * 3
150 FOR I = 0 TO DI - 1
160 FOR J = 0 TO DI - 1
170 FOR D = DI / 3 TO 0 STEP 0
180 IF INT ( FN M(I) / D) = 1 AND INT ( FN M(J) / D) = 1 THEN 200BREAK
190 D = INT (D / 3): NEXT D
200 HCOLOR= 3 * (D = 0)
210 HPLOT J,I
220 NEXT J
230 NEXT I
Asymptote
path across(path p, real node) {
return
point(p, node + 1/3) + point(p, node - 1/3) - point(p, node);
}
path corner_subquad(path p, real node) {
return
point(p, node) --
point(p, node + 1/3) --
across(p, node) --
point(p, node - 1/3) --
cycle;
}
path noncorner_subquad(path p, real node1, real node2) {
return
point(p, node1 + 1/3) --
across(p, node1) --
across(p, node2) --
point(p, node2 - 1/3) --
cycle;
}
void carpet(path p, int order) {
if (order == 0)
fill(p);
else {
for (real node : sequence(0, 3)) {
carpet(corner_subquad(p, node), order - 1);
carpet(noncorner_subquad(p, node, node + 1), order - 1);
}
}
}
path q =
// A square
unitsquare
// An oblong rhombus
// (0, 0) -- (5, 3) -- (0, 6) -- (-5, 3) -- cycle
// A trapezoid
// (0, 0) -- (4, 2) -- (6, 2) -- (10, 0) -- cycle
// A less regular quadrilateral
// (0, 0) -- (4, 1) -- (9, -4) -- (1, -1) -- cycle
// A concave shape
// (0, 0) -- (5, 3) -- (10, 0) -- (5, 1) -- cycle
;
size(9 inches, 6 inches);
carpet(q, 5);
AutoHotkey
ahk [http://www.autohotkey.com/forum/topic44657-150.html discussion]
Loop 4
MsgBox % Carpet(A_Index)
Carpet(n) {
Loop % 3**n {
x := A_Index-1
Loop % 3**n
t .= Dot(x,A_Index-1)
t .= "`n"
}
Return t
}
Dot(x,y) {
While x>0 && y>0
If (mod(x,3)=1 && mod(y,3)=1)
Return " "
Else x //= 3, y //= 3
Return "."
}
AWK
# WSC.AWK - Waclaw Sierpinski's carpet contributed by Dan Nielsen
#
# syntax: GAWK -f WSC.AWK [-v o={a|A}{b|B}] [-v X=anychar] iterations
#
# -v o=ab default
# a|A loose weave | tight weave
# b|B don't show | show how the carpet is built
# -v X=? Carpet is built with X's. The character assigned to X replaces all X's.
#
# iterations
# The number of iterations. The default is 0 which produces one carpet.
#
# what is the difference between a loose weave and a tight weave:
# loose tight
# X X X X X X X X X XXXXXXXXX
# X X X X X X X XX XX X
# X X X X X X X X X XXXXXXXXX
# X X X X X X XXX XXX
# X X X X X X X X
# X X X X X X XXX XXX
# X X X X X X X X X XXXXXXXXX
# X X X X X X X XX XX X
# X X X X X X X X X XXXXXXXXX
#
# examples:
# GAWK -f WSC.AWK 2
# GAWK -f WSC.AWK -v o=Ab -v X=# 2
# GAWK -f WSC.AWK -v o=Ab -v X=\xDB 2
#
BEGIN {
optns = (o == "") ? "ab" : o
n = ARGV[1] + 0 # iterations
if (n !~ /^[0-9]+$/) { exit(1) }
seed = (optns ~ /A/) ? "XXX,X X,XXX" : "X X X ,X X ,X X X " # tight/loose weave
leng = row = split(seed,A,",") # seed the array
for (i=1; i<=n; i++) { # build carpet
for (a=1; a<=3; a++) {
row = 0
for (b=1; b<=3; b++) {
for (c=1; c<=leng; c++) {
row++
tmp = (a == 2 && b == 2) ? sprintf("%*s",length(A[c]),"") : A[c]
B[row] = B[row] tmp
}
if (optns ~ /B/) { # show how the carpet is built
if (max_row < row+0) { max_row = row }
for (r=1; r<=max_row; r++) {
printf("i=%d row=%02d a=%d b=%d '%s'\n",i,r,a,b,B[r])
}
print("")
}
}
}
leng = row
for (j=1; j<=row; j++) { A[j] = B[j] } # re-seed the array
for (j in B) { delete B[j] } # delete work array
}
for (j=1; j<=row; j++) { # print carpet
if (X != "") { gsub(/X/,substr(X,1,1),A[j]) }
sub(/ +$/,"",A[j])
printf("%s\n",A[j])
}
exit(0)
}
GAWK -f WSC.AWK 1
X X X X X X X X X
X X X X X X
X X X X X X X X X
X X X X X X
X X X X
X X X X X X
X X X X X X X X X
X X X X X X
X X X X X X X X X
GAWK -f WSC.AWK -v o=A 1
XXXXXXXXX
X XX XX X
XXXXXXXXX
XXX XXX
X X X X
XXX XXX
XXXXXXXXX
X XX XX X
XXXXXXXXX
BBC BASIC
Order% = 3
side% = 3^Order%
VDU 23,22,8*side%;8*side%;64,64,16,128
FOR Y% = 0 TO side%-1
FOR X% = 0 TO side%-1
IF FNincarpet(X%,Y%) PLOT X%*16,Y%*16+15
NEXT
NEXT Y%
REPEAT WAIT 1 : UNTIL FALSE
END
DEF FNincarpet(X%,Y%)
REPEAT
IF X% MOD 3 = 1 IF Y% MOD 3 = 1 THEN = FALSE
X% DIV= 3
Y% DIV= 3
UNTIL X%=0 AND Y%=0
= TRUE
[[File:sierpinski_carpet_bbc.gif]]
Befunge
The order, N, is specified by the first number on the stack. The upper limit is implementation dependent and is determined by the interpreter's cell size.
*#3\>#-:#1_$:00p00g-#@_010p0>:20p10g30v
>p>40p"#"30g40g*!#v_$48*30g3%1-v^ >$55+,1v>
0 ^p03/3g03/3g04$_v#!*!-1%3g04!<^_^#- g00 <
^3g01p02:0p01_@#-g>#0,#02#:0#+g#11#g+#0:#<^
C
If you write coordinates of any point on the carpet in base 3, the pixel if blank if and only if any matching pair of digits are (1, 1).
#include <stdio.h>
int main()
{
int i, j, dim, d;
int depth = 3;
for (i = 0, dim = 1; i < depth; i++, dim *= 3);
for (i = 0; i < dim; i++) {
for (j = 0; j < dim; j++) {
for (d = dim / 3; d; d /= 3)
if ((i % (d * 3)) / d == 1 && (j % (d * 3)) / d == 1)
break;
printf(d ? " " : "##");
}
printf("\n");
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sCarpet {
int dim; // dimension
char *data; // character data
char **rows; // pointers to data rows
} *Carpet;
/* Clones a tile into larger carpet, or blank if center */
void TileCarpet( Carpet d, int r, int c, Carpet tile )
{
int y0 = tile->dim*r;
int x0 = tile->dim*c;
int k,m;
if ((r==1) && (c==1)) {
for(k=0; k < tile->dim; k++) {
for (m=0; m < tile->dim; m++) {
d->rows[y0+k][x0+m] = ' ';
}
}
}
else {
for(k=0; k < tile->dim; k++) {
for (m=0; m < tile->dim; m++) {
d->rows[y0+k][x0+m] = tile->rows[k][m];
}
}
}
}
/* define a 1x1 starting carpet */
static char s1[]= "#";
static char *r1[] = {s1};
static struct sCarpet single = { 1, s1, r1};
Carpet Sierpinski( int n )
{
Carpet carpet;
Carpet subCarpet;
int row,col, rb;
int spc_rqrd;
subCarpet = (n > 1) ? Sierpinski(n-1) : &single;
carpet = malloc(sizeof(struct sCarpet));
carpet->dim = 3*subCarpet->dim;
spc_rqrd = (2*subCarpet->dim) * (carpet->dim);
carpet->data = malloc(spc_rqrd*sizeof(char));
carpet->rows = malloc( carpet->dim*sizeof(char *));
for (row=0; row<subCarpet->dim; row++) {
carpet->rows[row] = carpet->data + row*carpet->dim;
rb = row+subCarpet->dim;
carpet->rows[rb] = carpet->data + rb*carpet->dim;
rb = row+2*subCarpet->dim;
carpet->rows[rb] = carpet->data + row*carpet->dim;
}
for (col=0; col < 3; col++) {
/* 2 rows of tiles to copy - third group points to same data a first */
for (row=0; row < 2; row++)
TileCarpet( carpet, row, col, subCarpet );
}
if (subCarpet != &single ) {
free(subCarpet->rows);
free(subCarpet->data);
free(subCarpet);
}
return carpet;
}
void CarpetPrint( FILE *fout, Carpet carp)
{
char obuf[730];
int row;
for (row=0; row < carp->dim; row++) {
strncpy(obuf, carp->rows[row], carp->dim);
fprintf(fout, "%s\n", obuf);
}
fprintf(fout,"\n");
}
int main(int argc, char *argv[])
{
// FILE *f = fopen("sierp.txt","w");
CarpetPrint(stdout, Sierpinski(3));
// fclose(f);
return 0;
}
Recursive version:
#include <stdio.h>
#include <stdlib.h>
typedef struct _PartialGrid{
char** base;
int xbegin, xend, ybegin, yend; // yend strictly not used
} PartialGrid;
void sierpinski_hollow(PartialGrid G){
int len = G.xend - G.xbegin+1;
int unit = len/3;
for(int i = G.xbegin+unit; i <G.xbegin+2*unit;i++){
for(int j = G.ybegin+unit; j <G.ybegin+2*unit;j++){
G.base[j][i] = ' ';
}}
}
void sierpinski(PartialGrid G, int iterations){
if(iterations==0)
return;
if((iterations)==1){
sierpinski_hollow(G);
sierpinski(G,0);
}
sierpinski_hollow(G);
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
int length = G.xend-G.xbegin+1;
int unit = length/3;
PartialGrid q = {G.base, G.xbegin + i*unit, G.xbegin+(i+1)*unit-1,
G.ybegin+j*unit, G.ybegin+(j+1)*unit-1};
sierpinski(q, iterations-1);
}
}
}
int intpow(int base, int expo){
if(expo==0){
return 1;
}
return base*intpow(base,expo-1);
}
int allocate_grid(char*** g, int n, const char sep){
int size = intpow(3,n+1);
*g = (char**)calloc(size, sizeof(char*));
if(*g==NULL)
return -1;
for(int i = 0; i < size; ++i){
(*g)[i] = (char*)calloc(size, sizeof(char));
if((*g)[i] == NULL)
return -1;
for(int j = 0; j < size; j++){
(*g)[i][j] = sep;
}
}
return size;
}
void print_grid(char** b, int size){
for(int i = 0; i < size; i++){
printf("%s\n",b[i]);
}
}
int main(){
int n = 3;
char** basegrid;
int size = allocate_grid(&basegrid, n, '#');
if(size == -1)
return 1; //bad alloc
PartialGrid b = {basegrid, 0, size-1, 0, size-1};
sierpinski(b, n);
print_grid(basegrid, size);
free(basegrid);
return 0;
}
C++
[[File:sierpinski_cpp.png|300px]]
#include <windows.h>
#include <math.h>
//--------------------------------------------------------------------------------------------------
const int BMP_SIZE = 738;
//--------------------------------------------------------------------------------------------------
class Sierpinski
{
public:
void draw( HDC wdc, int wid, int hei, int ord )
{
_wdc = wdc;
_ord = wid / static_cast<int>( pow( 3.0, ord ) );
drawIt( 0, 0, wid, hei );
}
void setHWND( HWND hwnd ) { _hwnd = hwnd; }
private:
void drawIt( int x, int y, int wid, int hei )
{
if( wid < _ord || hei < _ord ) return;
int w = wid / 3, h = hei / 3;
RECT rc;
SetRect( &rc, x + w, y + h, x + w + w, y + h + h );
FillRect( _wdc, &rc, static_cast<HBRUSH>( GetStockObject( BLACK_BRUSH ) ) );
for( int a = 0; a < 3; a++ )
for( int b = 0; b < 3; b++ )
{
if( a == 1 && b == 1 ) continue;
drawIt( x + b * w, y + a * h, w, h );
}
}
HWND _hwnd;
HDC _wdc;
int _ord;
};
//--------------------------------------------------------------------------------------------------
class wnd
{
public:
wnd() { _inst = this; }
int wnd::Run( HINSTANCE hInst )
{
_hInst = hInst;
_hwnd = InitAll();
_carpet.setHWND( _hwnd );
ShowWindow( _hwnd, SW_SHOW );
UpdateWindow( _hwnd );
MSG msg;
ZeroMemory( &msg, sizeof( msg ) );
while( msg.message != WM_QUIT )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
return UnregisterClass( "_SIERPINSKI_", _hInst );
}
private:
void wnd::doPaint( HDC dc ) { _carpet.draw( dc, BMP_SIZE, BMP_SIZE, 5 ); }
static int WINAPI wnd::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_DESTROY: PostQuitMessage( 0 ); break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint( hWnd, &ps );
_inst->doPaint( dc );
EndPaint( hWnd, &ps );
}
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
HWND InitAll()
{
WNDCLASSEX wcex;
ZeroMemory( &wcex, sizeof( wcex ) );
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = ( WNDPROC )WndProc;
wcex.hInstance = _hInst;
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszClassName = "_SIERPINSKI_";
RegisterClassEx( &wcex );
RECT rc = { 0, 0, BMP_SIZE, BMP_SIZE };
AdjustWindowRect( &rc, WS_SYSMENU | WS_CAPTION, FALSE );
int w = rc.right - rc.left,
h = rc.bottom - rc.top;
return CreateWindow( "_SIERPINSKI_", ".: Sierpinski carpet -- PJorente :.", WS_SYSMENU, CW_USEDEFAULT, 0, w, h, NULL, NULL, _hInst, NULL );
}
static wnd* _inst;
HINSTANCE _hInst;
HWND _hwnd;
Sierpinski _carpet;
};
wnd* wnd::_inst = 0;
//--------------------------------------------------------------------------------------------------
int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow )
{
wnd myWnd;
return myWnd.Run( hInstance );
}
//--------------------------------------------------------------------------------------------------
C#
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static List<string> NextCarpet(List<string> carpet)
{
return carpet.Select(x => x + x + x)
.Concat(carpet.Select(x => x + x.Replace('#', ' ') + x))
.Concat(carpet.Select(x => x + x + x)).ToList();
}
static List<string> SierpinskiCarpet(int n)
{
return Enumerable.Range(1, n).Aggregate(new List<string> { "#" }, (carpet, _) => NextCarpet(carpet));
}
static void Main(string[] args)
{
foreach (string s in SierpinskiCarpet(3))
Console.WriteLine(s);
}
}
Clojure
(ns example
(:require [clojure.contrib.math :as math]))
(defn in-carpet? [x y]
(loop [x x, y y]
(cond
(or (zero? x) (zero? y)) true
(and (= 1 (mod x 3)) (= 1 (mod y 3))) false
:else (recur (quot x 3) (quot y 3)))))
(defn carpet [n]
(apply str
(interpose
\newline
(for [x (range (math/expt 3 n))]
(apply str
(for [y (range (math/expt 3 n))]
(if (in-carpet? x y) "*" " ")))))))
(println (carpet 3))
Common Lisp
This solution works by printing a square of # except where both of the coordinates of a cell contain a 1 in the same digit position in base 3. For example, the central empty square has a 1 in the highest base-3 digit of all its cells, and the smallest empty squares have 1s in the lowest base-3 digit.
(defun print-carpet (order)
(let ((size (expt 3 order)))
(flet ((trinary (x) (format nil "~3,vR" order x))
(ones (a b) (and (eql a #\1) (eql b #\1))))
(loop for i below size do
(fresh-line)
(loop for j below size do
(princ (if (some #'ones (trinary i) (trinary j))
" "
"#")))))))
Crystal
def sierpinski_carpet(n)
carpet = ["#"]
n.times do
carpet = carpet.map { |x| x + x + x } +
carpet.map { |x| x + x.tr("#"," ") + x } +
carpet.map { |x| x + x + x }
end
carpet
end
5.times{ |i| puts "\nN=#{i}"; sierpinski_carpet(i).each { |row| puts row } }
N=0 # N=1 ### # # ### N=2 ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### N=3 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### N=4 ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # # ### ### ### ### ### ### ### ### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ``` ## D ```d import std.stdio, std.string, std.algorithm, std.array; auto sierpinskiCarpet(in int n) pure nothrow @safe { auto r = ["#"]; foreach (immutable _; 0 .. n) { const p = r.map!q{a ~ a ~ a}.array; r = p ~ r.map!q{a ~ a.replace("#", " ") ~ a}.array ~ p; } return r.join('\n'); } void main() { 3.sierpinskiCarpet.writeln; } ``` More functional style: ```d import std.stdio, std.algorithm, std.range, std.functional; auto nextCarpet(in string[] c) pure nothrow { /*immutable*/ const b = c.map!q{a ~ a ~ a}.array; return b ~ c.map!q{a ~ a.replace("#", " ") ~ a}.array ~ b; } void main() { ["#"] .recurrence!((a, n) => a[n - 1].nextCarpet) .dropExactly(3) .front .binaryReverseArgs!writefln("%-(%s\n%)"); } ``` A more direct and efficient version: ```d import std.stdio, std.array; char[][] sierpinskiCarpet(in size_t n) pure nothrow @safe { auto mat = uninitializedArray!(typeof(return))(3 ^^ n, 3 ^^ n); foreach (immutable r, row; mat) { row[] = '#'; foreach (immutable c, ref cell; row) { size_t r2 = r, c2 = c; while (r2 && c2) { if (r2 % 3 == 1 && c2 % 3 == 1) { cell = ' '; break; } r2 /= 3; c2 /= 3; } } } return mat; } void main() { writefln("%-(%s\n%)", 3.sierpinskiCarpet); 7.sierpinskiCarpet.length.writeln; } ``` ## DWScript ```delphi function InCarpet(x, y : Integer) : Boolean; begin while (x<>0) and (y<>0) do begin if ((x mod 3)=1) and ((y mod 3)=1) then Exit(False); x := x div 3; y := y div 3; end; Result := True; end; procedure Carpet(n : Integer); var i, j, p : Integer; begin p := Round(IntPower(3, n)); for i:=0 to p-1 do begin for j:=0 to p-1 do begin if InCarpet(i, j) then Print('#') else Print(' '); end; PrintLn(''); end; end; Carpet(3); ``` ## E ```e def inCarpet(var x, var y) { while (x > 0 && y > 0) { if (x %% 3 <=> 1 && y %% 3 <=> 1) { return false } x //= 3 y //= 3 } return true } def carpet(order) { for y in 0..!(3**order) { for x in 0..!(3**order) { print(inCarpet(x, y).pick("#", " ")) } println() } } ``` ## Elixir ```elixir defmodule RC do def sierpinski_carpet(n), do: sierpinski_carpet(n, ["#"]) def sierpinski_carpet(0, carpet), do: carpet def sierpinski_carpet(n, carpet) do new_carpet = Enum.map(carpet, fn x -> x <> x <> x end) ++ Enum.map(carpet, fn x -> x <> String.replace(x, "#", " ") <> x end) ++ Enum.map(carpet, fn x -> x <> x <> x end) sierpinski_carpet(n-1, new_carpet) end end Enum.each(0..3, fn n -> IO.puts "\nN=#{n}" Enum.each(RC.sierpinski_carpet(n), fn line -> IO.puts line end) end) ```N=0 # N=1 ### # # ### N=2 ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### N=3 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## Erlang ```erlang % Implemented by Arjun Sunel -module(carpet). -export([main/0]). main() -> sierpinski_carpet(3). sierpinski_carpet(N) -> lists: foreach(fun(X) -> lists: foreach(fun(Y) -> carpet(X,Y) end,lists:seq(0,trunc(math:pow(3,N))-1)), io:format("\n") end, lists:seq(0,trunc(math:pow(3,N))-1)). carpet(X,Y) -> if X=:=0 ; Y=:=0 -> io:format("*"); (X rem 3)=:=1, (Y rem 3) =:=1 -> io:format(" "); true -> carpet(X div 3, Y div 3) end. ``` ```txt *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ********* ********* * ** ** * * ** ** * ********* ********* *** *** *** *** * * * * * * * * *** *** *** *** ********* ********* * ** ** * * ** ** * ********* ********* *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ok ``` ## ERRE ```ERRE PROGRAM SIERP_CARPET ! for rosettacode.org !$INTEGER BEGIN OPEN("O",1,"OUT.PRN") PRINT(CHR$(12);) !CLS DEPTH=3 DIMM=1 FOR I=0 TO DEPTH-1 DO DIMM=DIMM*3 END FOR FOR I=0 TO DIMM-1 DO FOR J=0 TO DIMM-1 DO D=DIMM DIV 3 REPEAT EXIT IF ((I MOD (D*3)) DIV D=1 AND (J MOD (D*3)) DIV D=1) D=D DIV 3 UNTIL NOT(D>0) IF D>0 THEN PRINT(#1," ";) ELSE PRINT(#1,"##";) END IF END FOR PRINT(#1,) END FOR ! PRINT(#1,CHR$(12);) for printer only! CLOSE(1) END PROGRAM ``` Output is redirected to file OUT.PRN: you can change this to SCRN: to screen or "LPTx:" for a parallel printer. Output taken from OUT.PRN file: ```txt ###################################################### ## #### #### #### #### #### #### #### #### ## ###################################################### ###### ############ ############ ###### ## ## ## #### ## ## #### ## ## ## ###### ############ ############ ###### ###################################################### ## #### #### #### #### #### #### #### #### ## ###################################################### ################## ################## ## #### #### ## ## #### #### ## ################## ################## ###### ###### ###### ###### ## ## ## ## ## ## ## ## ###### ###### ###### ###### ################## ################## ## #### #### ## ## #### #### ## ################## ################## ###################################################### ## #### #### #### #### #### #### #### #### ## ###################################################### ###### ############ ############ ###### ## ## ## #### ## ## #### ## ## ## ###### ############ ############ ###### ###################################################### ## #### #### #### #### #### #### #### #### ## ###################################################### ``` ## Euphoria ```euphoria include std/math.e integer order = 4 function InCarpet(atom x, atom y) while 1 do if x = 0 or y = 0 then return 1 elsif floor(mod(x,3)) = 1 and floor(mod(y,3)) = 1 then return 0 end if x /= 3 y /= 3 end while end function for i = 0 to power(3,order)-1 do for j = 0 to power(3,order)-1 do if InCarpet(i,j) = 1 then puts(1,"#") else puts(1," ") end if end for puts(1,'\n') end for ``` =={{header|F_Sharp|F#}}== ```fsharp open System let blank x = new String(' ', String.length x) let nextCarpet carpet = List.map (fun x -> x + x + x) carpet @ List.map (fun x -> x + (blank x) + x) carpet @ List.map (fun x -> x + x + x) carpet let rec sierpinskiCarpet n = let rec aux n carpet = if n = 0 then carpet else aux (n-1) (nextCarpet carpet) aux n ["#"] List.iter (printfn "%s") (sierpinskiCarpet 3) ``` ## Fan ```Fan ** ** Generates a square Sierpinski gasket ** class SierpinskiCarpet { public static Bool inCarpet(Int x, Int y){ while(x!=0 && y!=0){ if (x % 3 == 1 && y % 3 == 1) return false; x /= 3; y /= 3; } return true; } static Int pow(Int n, Int exp) { rslt := 1 exp.times { rslt *= n } return rslt } public static Void carpet(Int n){ for(i := 0; i < pow(3, n); i++){ buf := StrBuf() for(j := 0; j < pow(3, n); j++){ if( inCarpet(i, j)) buf.add("*"); else buf.add(" "); } echo(buf); } } Void main() { carpet(4) } } ``` ## Forth ```forth \ Generates a square Sierpinski gasket : 1? over 3 mod 1 = ; ( n1 n2 -- n1 n2 f) : 3/ 3 / swap ; ( n1 n2 -- n2/3 n1) \ is this cell in the carpet? : incarpet ( n1 n2 -- f) begin over over or while 1? 1? and if 2drop false exit then 3/ 3/ repeat 2drop true \ return true if in the carpet ; \ draw a carpet of n size : carpet ( n --) 1 swap 0 ?do 3 * loop dup \ calculate power of 3 0 ?do dup 0 ?do i j incarpet if [char] # else bl then emit loop cr loop drop \ evaluate every cell in the carpet ; cr 4 carpet ``` ## Fortran ```fortran program Sierpinski_carpet implicit none call carpet(4) contains function In_carpet(a, b) logical :: in_carpet integer, intent(in) :: a, b integer :: x, y x = a ; y = b do if(x == 0 .or. y == 0) then In_carpet = .true. return else if(mod(x, 3) == 1 .and. mod(y, 3) == 1) then In_carpet = .false. return end if x = x / 3 y = y / 3 end do end function subroutine Carpet(n) integer, intent(in) :: n integer :: i, j do i = 0, 3**n - 1 do j = 0, 3**n - 1 if(In_carpet(i, j)) then write(*, "(a)", advance="no") "#" else write(*, "(a)", advance="no") " " end if end do write(*,*) end do end subroutine Carpet end program Sierpinski_carpet ``` ## Gnuplot ### Version #1. ;Note: * Find '''plotff.gp''' file-function for load command here on RC [[Brownian_tree#gnuplot| Brownian tree page]]. * dat-files are PARI/GP generated output files. See [[Sierpinski_carpet#PARI.2FGP| this page]] below. [[File:SC5gp1.png|right|thumb|Output SC5gp1.png]] ```gnuplot ## SCff.gp 1/14/17 aev ## Plotting Sierpinski carpet fractal. ## dat-files are PARI/GP generated output files: ## http://rosettacode.org/wiki/Sierpinski_carpet#PARI.2FGP #cd 'C:\gnupData' ##SC5 clr = '"green"' filename = "SC5gp1" ttl = "Sierpinski carpet fractal, v.#1" load "plotff.gp" ``` ```txt 1. All SCff.gp commands. 2. All plotted png-files: SC5gp1.png (for now) ``` ### Plotting a Sierpinski carpet fractal: versions #2 and #3 '''plotscf.gp''' and '''plotscf1.gp''' file-functions for the load command are the only possible imitation of the fine functions in the '''gnuplot'''. [[File:SCF21gp.png|right|thumb|Output SCF21gp.png]] [[File:SCF22gp.png|right|thumb|Output SCF22gp.png]] [[File:SCF31gp.png|right|thumb|Output SCF31gp.png]] ;plotscf.gp: ```gnuplot ## plotscf.gp 12/7/16 aev ## Plotting a Sierpinski carpet fractal to the png-file. ## Note: assign variables: ord (order), clr (color), filename and ttl (before using load command). ## ord (order) # a.k.a. level - defines size of fractal (also number of dots). reset set terminal png font arial 12 size 640,640 ofn=filename.".png" set output ofn unset border; unset xtics; unset ytics; unset key; set title ttl font "Arial:Bold,12" set xrange [0:1]; set yrange [0:1]; sc(n, x, y, d) = n >= ord ? \ sprintf('set object rect from %f,%f to %f,%f fc rgb @clr fs solid;', x, y, x+d, y+d) : \ sc(n+1, x, y, d/3) . sc(n+1, x+d/3, y, d/3) . \ sc(n+1, x+2*d/3, y, d/3) . sc(n+1, x, y+d/3, d/3) . \ sc(n+1, x+2*d/3, y+d/3, d/3) . sc(n+1, x, y+2*d/3, d/3) . \ sc(n+1, x+d/3, y+2*d/3, d/3) . sc(n+1, x+2*d/3, y+2*d /3, d/3); eval(sc(0, 0.0, 0.0, 1.0)) plot -100 set output ``` ;plotscf1.gp: ```gnuplot ## plotscf1.gp 12/7/16 aev ## Plotting a Sierpinski carpet fractal to the png-file. ## Note: assign variables: ord (order, just for title), clr (color), filename and ttl (before using load command). ## In this version order is always 5. reset set terminal png font arial 12 size 640,640 ofn=filename.".png" set output ofn unset border; unset xtics; unset ytics; unset key; set title ttl font "Arial:Bold,12" o=3 sqr(x,y) = abs(x + y) + abs(x - y) - o f(x) = o*abs(x) - o c0(x,y) = abs(x + y) + abs(x - y) - 1 c1(x,y) = c0(o*x,f(y)) * c0(f(x),o*y) * c0(f(x),f(y)) c2(x,y) = c1(o*x,f(y)) * c1(f(x),o*y) * c1(f(x),f(y)) c3(x,y) = c2(o*x,f(y)) * c2(f(x),o*y) * c2(f(x),f(y)) c4(x,y) = c3(o*x,f(y)) * c3(f(x),o*y) * c3(f(x),f(y)) sc(x,y) = sqr(x,y)>0 || c0(x,y)*c1(x,y)*c2(x,y)*c3(x,y)*c4(x,y)<0 ? 0:1 set xrange [-1.5:1.5]; set yrange [-1.5:1.5]; set pm3d map; set palette model RGB defined (0 "white", 1 @clr); set size ratio -1 smp=640; set samples smp; set isosamples smp; unset colorbox splot sc(x,y) set output ``` ;Plotting v.#2 and v.#3: ```gnuplot ## pSCF.gp 12/7/16 aev ## Plotting Sierpinski carpet fractals. ## Note: assign variables: ord (order), clr (color), filename and ttl (before using load command). ## ord (order) # a.k.a. level - defines size of fractal (also number of dots). #cd 'C:\gnupData' ##SCF21 ord=3; clr = '"red"'; filename = "SCF21gp"; ttl = "Sierpinski carpet fractal #21, ord ".ord; load "plotscf.gp" ##SCF22 ord=5; clr = '"brown"'; filename = "SCF22gp"; ttl = "Sierpinski carpet fractal #22, ord ".ord; load "plotscf.gp" ##SCF31 ord=5; clr = '"navy"'; filename = "SCF31gp"; ttl = "Sierpinski carpet fractal #31, ord ".ord; load "plotscf1.gp" ``` ```txt 1. All pSCF.gp file commands. 2. 3 plotted png-files: SCF21gp, SCF22gp and SCF31gp ``` ## Go Variable "grain" shown set to "#" here, but it's fun to experiment with other values. "|", ". ", "[]", "___", "██", "░░"... ```go package main import ( "fmt" "strings" "unicode/utf8" ) var order = 3 var grain = "#" func main() { carpet := []string{grain} for ; order > 0; order-- { // repeat expression allows for multiple character // grain and for multi-byte UTF-8 characters. hole := strings.Repeat(" ", utf8.RuneCountInString(carpet[0])) middle := make([]string, len(carpet)) for i, s := range carpet { middle[i] = s + hole + s carpet[i] = strings.Repeat(s, 3) } carpet = append(append(carpet, middle...), carpet...) } for _, r := range carpet { fmt.Println(r) } } ``` ## Groovy Solution, uses list-indexing of base 3 string representation: ```groovy def base3 = { BigInteger i -> i.toString(3) } def sierpinskiCarpet = { int order -> StringBuffer sb = new StringBuffer() def positions = 0..<(3**order) def digits = 0..<([order,1].max()) positions.each { i -> String i3 = base3(i).padLeft(order, '0') positions.each { j -> String j3 = base3(j).padLeft(order, '0') sb << (digits.any{ i3[it] == '1' && j3[it] == '1' } ? ' ' : order.toString().padRight(2) ) } sb << '\n' } sb.toString() } ``` Test Program: ```groovy (0..4).each { println sierpinskiCarpet(it) } ```0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ``` ## Haskell ```haskell inCarpet :: Int -> Int -> Bool inCarpet 0 _ = True inCarpet _ 0 = True inCarpet x y = not ((xr == 1) && (yr == 1)) && inCarpet xq yq where ((xq, xr), (yq, yr)) = (x `divMod` 3, y `divMod` 3) carpet :: Int -> [String] carpet n = map (zipWith (\x y -> if inCarpet x y then '#' else ' ') [0..3^n-1] . repeat) [0..3^n-1] printCarpet :: Int -> IO () printCarpet = mapM_ putStrLn . carpet ``` ```haskell nextCarpet :: [String] -> [String] nextCarpet carpet = border ++ map f carpet ++ border where border = map (concat . replicate 3) carpet f x = x ++ map (const ' ') x ++ x sierpinskiCarpet :: Int -> [String] sierpinskiCarpet n = iterate nextCarpet ["#"] !! n main :: IO () main = mapM_ putStrLn $ sierpinskiCarpet 3 ``` Seems not very different from version above, ```haskell main :: IO () main = putStr . unlines . (!!3) $ iterate next ["#"] next :: [String] -> [String] next block = block ! block ! block ++ block ! center ! block ++ block ! block ! block where (!) = zipWith (++) center = map (map $ const ' ') block ``` which we could also read as: ```haskell carpet :: Int -> String carpet = unlines . (iterate weave ["██"] !!) weave :: [String] -> [String] weave xs = let f = zipWith (++) g = flip f in [xs, fmap (const ' ') <$> xs, xs] >>= g xs . f xs main :: IO () main = mapM_ (putStrLn . carpet) [0 .. 2] ``` ```txt ██ ██████ ██ ██ ██████ ██████████████████ ██ ████ ████ ██ ██████████████████ ██████ ██████ ██ ██ ██ ██ ██████ ██████ ██████████████████ ██ ████ ████ ██ ██████████████████ ``` ==={{{header|GUI variant}}}=== Via high-level vector graphics (diagrams -> cairo -> gtk), very slow. ```haskell {-# LANGUAGE DoRec #-} import Control.Monad.Trans (lift) import Data.Colour (Colour) import Diagrams.Prelude hiding (after) import Diagrams.Backend.Cairo (Cairo) import Diagrams.Backend.Cairo.Gtk (defaultRender) import Graphics.Rendering.Diagrams.Points () import Graphics.UI.Gtk import Graphics.UI.Gtk.Gdk.GC (gcNew) main :: IO () main = do _ <- initGUI window <- windowNew _ <- window `onDestroy` mainQuit window `windowSetResizable` False area <- drawingAreaNew _ <- area `on` sizeRequest $ return (Requisition 500 500) _ <- window `containerAdd` area widgetShowAll window rec con <- area `on` exposeEvent $ do lift $ signalDisconnect con lift $ area `defaultRender` carpet 5 switchToPixBuf area mainGUI -- just workaround for slow redrawing switchToPixBuf :: DrawingArea -> EventM EExpose Bool switchToPixBuf area = eventArea >>= \ea -> lift $ do dw <- widgetGetDrawWindow area (w,h) <- drawableGetSize dw Just pb <- pixbufGetFromDrawable dw ea gc <- gcNew dw _ <- area `on` exposeEvent $ lift $ False <$ drawPixbuf dw gc pb 0 0 0 0 w h RgbDitherNone 0 0 return False carpet :: Int -> Diagram Cairo R2 carpet = (iterate next (cell white) !!) -- of course, one can use hcat / vcat - combinators next :: Diagram Cairo R2 -> Diagram Cairo R2 next block = scale (1/3) . centerXY $ (block ||| block ||| block) === (block ||| centr ||| block) === (block ||| block ||| block) where centr = cell black cell :: Colour Float -> Diagram Cairo R2 cell color = square 1 # lineWidth 0 # fillColor color ``` =={{header|Icon}} and {{header|Unicon}}== The IsFilled procedure is a translation of Java and Python. ```Icon $define FILLER "*" # the filler character procedure main(A) width := 3 ^ ( order := (0 < \A[1]) | 3 ) write("Carpet order= ",order) every !(canvas := list(width)) := list(width," ") # prime the canvas every y := 1 to width & x := 1 to width do # traverse it if IsFilled(x-1,y-1) then canvas[x,y] := FILLER # fill every x := 1 to width & y := 1 to width do writes((y=1,"\n")|"",canvas[x,y]," ") # print end procedure IsFilled(x,y) # succeed if x,y should be filled while x ~= 0 & y ~= 0 do { if x % 3 = y %3 = 1 then fail x /:= 3 y /:=3 } return end ``` ```txt Carpet order= 2 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ``` ## Io Based on Python translation of Ruby. ```Io sierpinskiCarpet := method(n, carpet := list("@") n repeat( next := list() carpet foreach(s, next append(s .. s .. s)) carpet foreach(s, next append(s .. (s asMutable replaceSeq("@"," ")) .. s)) carpet foreach(s, next append(s .. s .. s)) carpet = next ) carpet join("\n") ) sierpinskiCarpet(3) println ``` ```txt @@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@ @@ @@ @@ @@ @@ @@ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@ @@@@@@ @@@@@@ @@@ @ @ @ @@ @ @ @@ @ @ @ @@@ @@@@@@ @@@@@@ @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@ @@ @@ @@ @@ @@ @@ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@ @@@@@@@@@ @ @@ @@ @ @ @@ @@ @ @@@@@@@@@ @@@@@@@@@ @@@ @@@ @@@ @@@ @ @ @ @ @ @ @ @ @@@ @@@ @@@ @@@ @@@@@@@@@ @@@@@@@@@ @ @@ @@ @ @ @@ @@ @ @@@@@@@@@ @@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@ @@ @@ @@ @@ @@ @@ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@ @@@@@@ @@@@@@ @@@ @ @ @ @@ @ @ @@ @ @ @ @@@ @@@@@@ @@@@@@ @@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@ @ @@ @@ @@ @@ @@ @@ @@ @@ @ @@@@@@@@@@@@@@@@@@@@@@@@@@@ ``` =={{header|IS-BASIC}}==100 PROGRAM "Carpet.bas" 110 SET VIDEO MODE 5:SET VIDEO COLOR 0:SET VIDEO X 32:SET VIDEO Y 27 120 OPEN #101:"video:" 130 DISPLAY #101:AT 1 FROM 1 TO 27 140 CALL CARPET(30,0,1000,970,4) 150 DEF CARPET(X1,Y1,X2,Y2,LEV) 160 NUMERIC XT,XY,KX1,KX2,KY1,KY2 170 IF LEV>0 THEN 180 LET XT=(X2-X1)/3:LET YT=(Y2-Y1)/3 190 LET KX1=X1+XT:LET KY1=Y1+YT 200 LET KX2=X2-XT:LET KY2=Y2-YT 210 CALL CARPET(X1,Y1,KX1,KY1,LEV-1) 220 CALL CARPET(KX1,Y1,KX2,KY1,LEV-1) 230 CALL CARPET(KX2,Y1,X2,KY1,LEV-1) 240 CALL CARPET(KX2,KY1,X2,KY2,LEV-1) 250 CALL CARPET(KX2,KY2,X2,Y2,LEV-1) 260 CALL CARPET(KX1,KY2,KX2,Y2,LEV-1) 270 CALL CARPET(X1,KY2,KX1,Y2,LEV-1) 280 CALL CARPET(X1,KY1,KX1,KY2,LEV-1) 290 ELSE 300 PLOT X1,Y1;X2,Y1;X2,Y2;X1,Y2;X1,Y1 310 PLOT X1+4,Y1+4,PAINT 320 END IF 330 END DEF ``` ## J Like the sierpinski triangle, the carpet is straightforward to produce in J. One approach is based on repeatedly putting a function's argument in a box, forming 9 copies of it into a 3 by 3 array, and then replacing the contents of the middle box with blanks: ```j N=:3 (a:(<1;1)}3 3$<)^:N' ' ``` But N=:3 is big, so let's use N=:2 ```j N=:2 (a:(<1;1)}3 3$<)^:N' ' ┌─────────────┬─────────────┬─────────────┐ │┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│ ├─────────────┼─────────────┼─────────────┤ │┌───┬───┬───┐│ │┌───┬───┬───┐│ ││ │ │ ││ ││ │ │ ││ │├───┼───┼───┤│ │├───┼───┼───┤│ ││ │ │ ││ ││ │ │ ││ │├───┼───┼───┤│ │├───┼───┼───┤│ ││ │ │ ││ ││ │ │ ││ │└───┴───┴───┘│ │└───┴───┴───┘│ ├─────────────┼─────────────┼─────────────┤ │┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│ └─────────────┴─────────────┴─────────────┘ ``` or another way of getting the same image starts with the boolean array ```J #:7 5 7 1 1 1 1 0 1 1 1 1 ``` and uses that to select either a blank box or a boxed copy if the function's argument: ```j N=:2 ((#:7 5 7){_2{.<)^:N' ' ┌─────────────┬─────────────┬─────────────┐ │┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│ ├─────────────┼─────────────┼─────────────┤ │┌───┬───┬───┐│ │┌───┬───┬───┐│ ││ │ │ ││ ││ │ │ ││ │├───┼───┼───┤│ │├───┼───┼───┤│ ││ │ │ ││ ││ │ │ ││ │├───┼───┼───┤│ │├───┼───┼───┤│ ││ │ │ ││ ││ │ │ ││ │└───┴───┴───┘│ │└───┴───┴───┘│ ├─────────────┼─────────────┼─────────────┤ │┌───┬───┬───┐│┌───┬───┬───┐│┌───┬───┬───┐│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │├───┼───┼───┤│├───┼───┼───┤│├───┼───┼───┤│ ││ │ │ │││ │ │ │││ │ │ ││ │└───┴───┴───┘│└───┴───┴───┘│└───┴───┴───┘│ └─────────────┴─────────────┴─────────────┘ ``` That said, using spaces and '#' characters takes a bit more work. One approach would be: ```j N=:2 ' #'{~(#:7 5 7) ,/@(1 3 ,/"2@|: */)^:N ,.1 ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### N=:3 ' #'{~(#:7 5 7) ,/@(1 3 ,/"2@|: */)^:N ,.1 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` Here, what we are doing is forming a tensor product of our #:7 5 7 boolean array with our argument and then collapsing two of the dimensions so they line up right. Our starting argument is the 1 by 1 array with the value 1. Once we have repeated this process enough times, we select spaces for our zeros and pound signs for our 1s. ## Java ```java public static boolean inCarpet(long x, long y) { while (x!=0 && y!=0) { if (x % 3 == 1 && y % 3 == 1) return false; x /= 3; y /= 3; } return true; } public static void carpet(final int n) { final double power = Math.pow(3,n); for(long i = 0; i < power; i++) { for(long j = 0; j < power; j++) { System.out.print(inCarpet(i, j) ? "*" : " "); } System.out.println(); } } ``` ### Animated version [[File:sierpinski_carpet_java.png|300px|thumb|right]] ```java import java.awt.*; import java.awt.event.ActionEvent; import javax.swing.*; public class SierpinskiCarpet extends JPanel { private final int dim = 513; private final int margin = 20; private int limit = dim; public SierpinskiCarpet() { setPreferredSize(new Dimension(dim + 2 * margin, dim + 2 * margin)); setBackground(Color.white); setForeground(Color.orange); new Timer(2000, (ActionEvent e) -> { limit /= 3; if (limit <= 3) limit = dim; repaint(); }).start(); } void drawCarpet(Graphics2D g, int x, int y, int size) { if (size < limit) return; size /= 3; for (int i = 0; i < 9; i++) { if (i == 4) { g.fillRect(x + size, y + size, size, size); } else { drawCarpet(g, x + (i % 3) * size, y + (i / 3) * size, size); } } } @Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.translate(margin, margin); drawCarpet(g, 0, 0, dim); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Sierpinski Carpet"); f.setResizable(false); f.add(new SierpinskiCarpet(), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); } } ``` ## JavaScript ### ES5 In-browser JavaScript (HTML output) This version also produces a "graphic" via HTML and CSS. ```html4strict Sierpinski Carpet ``` ``` [[File:Sierpinski carpet js.png]] Or, in a functional idiom, generating plain text, and suitable for use in any ES5 JavaScript, whether in a browser or some other environment. Creates an N by N array of boolean values, which are mapped to lines of characters for output. ```JavaScript // Orders 1, 2 and 3 of the Sierpinski Carpet // as lines of text. // Generic text output for use in any JavaScript environment // Browser JavaScripts may use console.log() to return textual output // others use print() or analogous functions. [1, 2, 3].map(function sierpinskiCarpetOrder(n) { // An (n * n) grid of (filled or empty) sub-rectangles // n --> [[s]] var carpet = function (n) { var lstN = range(0, Math.pow(3, n) - 1); // State of each cell in an N * N grid return lstN.map(function (x) { return lstN.map(function (y) { return inCarpet(x, y); }); }); }, // State of a given coordinate in the grid: // Filled or not ? // (See https://en.wikipedia.org/wiki/Sierpinski_carpet#Construction) // n --> n --> bool inCarpet = function (x, y) { return (!x || !y) ? true : !( (x % 3 === 1) && (y % 3 === 1) ) && inCarpet( x / 3 | 0, y / 3 | 0 ); }, // Sequence of integers from m to n // n --> n --> [n] range = function (m, n) { return Array.apply(null, Array(n - m + 1)).map( function (x, i) { return m + i; } ); }; // Grid of booleans mapped to lines of characters // [[bool]] --> s return carpet(n).map(function (line) { return line.map(function (bool) { return bool ? '\u2588' : ' '; }).join(''); }).join('\n'); }).join('\n\n'); ``` Output (orders 1, 2 and 3): ```txt ███ █ █ ███ █████████ █ ██ ██ █ █████████ ███ ███ █ █ █ █ ███ ███ █████████ █ ██ ██ █ █████████ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ███ ██████ ██████ ███ █ █ █ ██ █ █ ██ █ █ █ ███ ██████ ██████ ███ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ █████████ █████████ █ ██ ██ █ █ ██ ██ █ █████████ █████████ ███ ███ ███ ███ █ █ █ █ █ █ █ █ ███ ███ ███ ███ █████████ █████████ █ ██ ██ █ █ ██ ██ █ █████████ █████████ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ███ ██████ ██████ ███ █ █ █ ██ █ █ ██ █ █ █ ███ ██████ ██████ ███ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ``` ### ES6 ```JavaScript (() => { 'use strict'; // sierpinskiCarpet :: Int -> String let sierpinskiCarpet = n => { // carpet :: Int -> [[String]] let carpet = n => { let xs = range(0, Math.pow(3, n) - 1); return xs.map(x => xs.map(y => inCarpet(x, y))); }, // https://en.wikipedia.org/wiki/Sierpinski_carpet#Construction // inCarpet :: Int -> Int -> Bool inCarpet = (x, y) => (!x || !y) ? true : !( (x % 3 === 1) && (y % 3 === 1) ) && inCarpet( x / 3 | 0, y / 3 | 0 ); return carpet(n) .map(line => line.map(bool => bool ? '\u2588' : ' ') .join('')) .join('\n'); }; // GENERIC // range :: Int -> Int -> [Int] let range = (m, n) => Array.from({ length: Math.floor(n - m) + 1 }, (_, i) => m + i); // TEST return [1, 2, 3] .map(sierpinskiCarpet); })(); ``` ```txt ███ █ █ ███ █████████ █ ██ ██ █ █████████ ███ ███ █ █ █ █ ███ ███ █████████ █ ██ ██ █ █████████ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ███ ██████ ██████ ███ █ █ █ ██ █ █ ██ █ █ █ ███ ██████ ██████ ███ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ █████████ █████████ █ ██ ██ █ █ ██ ██ █ █████████ █████████ ███ ███ ███ ███ █ █ █ █ █ █ █ █ ███ ███ ███ ███ █████████ █████████ █ ██ ██ █ █ ██ ██ █ █████████ █████████ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ███ ██████ ██████ ███ █ █ █ ██ █ █ ██ █ █ █ ███ ██████ ██████ ███ ███████████████████████████ █ ██ ██ ██ ██ ██ ██ ██ ██ █ ███████████████████████████ ``` Or, defining the Sierpinksi carpet weave declaratively, in terms of '''zipWith''' and '''concatMap''': ```javascript (() => { 'use strict'; // weave :: [String] -> [String] const weave = xs => { const f = zipWith(append); return concatMap( x => f(f(xs)(x))(xs) )([ xs, map(x => replicate(length(x))(' '))( xs ), xs ]); }; // TEST ----------------------------------------------- const main = () => { const sierp = n => unlines( take(1 + n, iterate(weave, ['\u2588']))[n] ), carpet = sierp(2); return ( // console.log(carpet), carpet ); }; // GENERIC ABSTRACTIONS ------------------------------- // append (++) :: [a] -> [a] -> [a] // append (++) :: String -> String -> String const append = xs => ys => xs.concat(ys); // concatMap :: (a -> [b]) -> [a] -> [b] const concatMap = f => xs => xs.reduce((a, x) => a.concat(f(x)), []); // iterate :: (a -> a) -> a -> Gen [a] function* iterate(f, x) { let v = x; while (true) { yield(v); v = f(v); } } // Returns Infinity over objects without finite length // this enables zip and zipWith to choose the shorter // argument when one is non-finite, like cycle, repeat etc // length :: [a] -> Int const length = xs => xs.length || Infinity; // map :: (a -> b) -> [a] -> [b] const map = f => xs => xs.map(f); // replicate :: Int -> String -> String const replicate = n => s => s.repeat(n); // take :: Int -> [a] -> [a] // take :: Int -> String -> String const take = (n, xs) => xs.constructor.constructor.name !== 'GeneratorFunction' ? ( xs.slice(0, n) ) : [].concat.apply([], Array.from({ length: n }, () => { const x = xs.next(); return x.done ? [] : [x.value]; })); // unlines :: [String] -> String const unlines = xs => xs.join('\n'); // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] const zipWith = f => xs => ys => { const lng = Math.min(length(xs), length(ys)), as = take(lng, xs), bs = take(lng, ys); return Array.from({ length: lng }, (_, i) => f(as[i])(bs[i])); }; // MAIN ----------------------------------------------- return main(); })(); ``` ```txt █████████ █ ██ ██ █ █████████ ███ ███ █ █ █ █ ███ ███ █████████ █ ██ ██ █ █████████ ``` ## Kotlin ### ASCII Art Version ```scala // version 1.1.2 fun inCarpet(x: Int, y: Int): Boolean { var xx = x var yy = y while (xx != 0 && yy != 0) { if (xx % 3 == 1 && yy % 3 == 1) return false xx /= 3 yy /= 3 } return true } fun carpet(n: Int) { val power = Math.pow(3.0, n.toDouble()).toInt() for(i in 0 until power) { for(j in 0 until power) print(if (inCarpet(i, j)) "*" else " ") println() } } fun main(args: Array) = carpet(3) ``` ```txt *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ********* ********* * ** ** * * ** ** * ********* ********* *** *** *** *** * * * * * * * * *** *** *** *** ********* ********* * ** ** * * ** ** * ********* ********* *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ``` ### Graphical Animated Version ```scala // version 1.1.2 import java.awt.* import javax.swing.* public class SierpinskiCarpet : JPanel() { private val dim = 513 private val margin = 20 private var limit = dim init { val size = dim + 2 * margin preferredSize = Dimension(size, size) background = Color.blue foreground = Color.yellow Timer(2000) { limit /= 3 if (limit <= 3) limit = dim repaint() }.start() } private fun drawCarpet(g: Graphics2D, x: Int, y: Int, s: Int) { var size = s if (s < limit) return size /= 3 for (i in 0 until 9) { if (i == 4) { g.fillRect(x + size, y + size, size, size) } else { drawCarpet(g, x + (i % 3) * size, y + (i / 3) * size, size) } } } override fun paintComponent(gg: Graphics) { super.paintComponent(gg) val g = gg as Graphics2D g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) g.translate(margin, margin) drawCarpet(g, 0, 0, dim) } } fun main(args: Array ) { SwingUtilities.invokeLater { val f = JFrame() f.defaultCloseOperation = JFrame.EXIT_ON_CLOSE f.title = "Sierpinski Carpet" f.isResizable = false f.add(SierpinskiCarpet(), BorderLayout.CENTER) f.pack() f.setLocationRelativeTo(null) f.isVisible = true } } ``` ## jq jq does Cartesian products, so the heart of the matter is the line: inCarpet( range(0; $power) ; range(0; $power), -1 ) This is like a "for" loop within a "for" loop in C-like languages, because range(0;n) generates a stream of n integers beginning at 0. The -1 is used to signal that a newline character is required. ```jq def inCarpet(x; y): x as $x | y as $y | if $x == -1 or $y == -1 then "\n" elif $x == 0 or $y == 0 then "*" elif ($x % 3) == 1 and ($y % 3) == 1 then " " else inCarpet($x/3 | floor; $y/3 | floor) end; def ipow(n): . as $in | reduce range(0;n) as $i (1; . * $in); def carpet(n): (3|ipow(n)) as $power | [ inCarpet( range(0; $power) ; range(0; $power), -1 )] | join("") ; carpet(3) ``` The following command produces the required pattern, and so the output is not repeated here: ```sh jq -n -r -c -f sierpinski.jq ``` ## Julia ```julia function sierpinski(n::Integer, token::AbstractString="*") x = fill(token, 1, 1) for _ in 1:n t = fill(" ", size(x)) x = [x x x; x t x; x x x] end return x end function printsierpinski(m::Matrix) for r in 1:size(m, 1) println(join(m[r, :])) end end sierpinski(2, "#") |> printsierpinski ``` ## Liberty BASIC ```lb NoMainWin WindowWidth = 508 WindowHeight = 575 Open "Sierpinski Carpets" For Graphics_nsb_nf As #g #g "Down; TrapClose [halt]" 'labels #g "Place 90 15;\Order 0" #g "Place 340 15;\Order 1" #g "Place 90 286;\Order 2" #g "Place 340 286;\Order 3" 'carpets Call carpet 5, 20, 243, 0 Call carpet 253, 20, 243, 1 Call carpet 5, 293, 243, 2 Call carpet 253, 293, 243, 3 #g "Flush" Wait [halt] Close #g End Sub carpet x, y, size, order #g "Color 0 0 128; BackColor 0 0 128" #g "Place ";x;" ";y #g "BoxFilled ";x+size-1;" ";y+size-1 #g "Color white; BackColor white" side = Int(size/3) newX = x+side newY = y+side #g "Place ";newX;" ";newY #g "BoxFilled ";newX+side-1;" ";newY+side-1 order = order - 1 If order > -1 Then Call carpet newX-side, newY-side+1, side, order Call carpet newX, newY-side+1, side, order Call carpet newX+side, newY-side+1, side, order Call carpet newX+side, newY, side, order Call carpet newX+side, newY+side, side, order Call carpet newX, newY+side, side, order Call carpet newX-side, newY+side, side, order Call carpet newX-side, newY, side, order End If End Sub ``` ## Mathematica Replace a empty spot with a 3x3 empty matrix, and replace a full spot with an empty spot surrounded by 8 full spots: ```Mathematica full={{1,1,1},{1,0,1},{1,1,1}} empty={{0,0,0},{0,0,0},{0,0,0}} n=3; Grid[Nest[ArrayFlatten[#/.{0->empty,1->full}]&,{{1}},n]//.{0->" ",1->"#"}] ``` ## MATLAB ```MATLAB n = 3; c = string('#'); for k = 1 : n c = [c + c + c, c + c.replace('#', ' ') + c, c + c + c]; end disp(c.join(char(10))) ``` ```txt ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## NetRexx ```NetRexx /* NetRexx */ options replace format comments java crossref symbols nobinary numeric digits 1000 runSample(arg) return -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method runSample(arg) public static DARK_SHADE = '\u2593' parse arg ordr filr . if ordr = '' | ordr = '.' then ordr = 3 if filr = '' | filr = '.' then filler = DARK_SHADE else filler = filr drawSierpinskiCarpet(ordr, filler) return -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method drawSierpinskiCarpet(ordr, filler = Rexx '@') public static binary x = long y = long powr = 3 ** ordr loop x = 0 to powr - 1 loop y = 0 to powr - 1 if isSierpinskiCarpetCellFilled(x, y) then cell = filler else cell = ' ' say cell'\-' end y say end x return -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ method isSierpinskiCarpetCellFilled(x = long, y = long) public static binary returns boolean isTrue = boolean (1 == 1) isFalse = \isTrue isFilled = isTrue loop label edge while x \= 0 & y \= 0 if x // 3 = 1 & y // 3 = 1 then do isFilled = isFalse leave edge end x = x % 3 y = y % 3 end edge return isFilled ``` Sample shown with order "2". ```txt ▓▓▓▓▓▓▓▓▓ ▓ ▓▓ ▓▓ ▓ ▓▓▓▓▓▓▓▓▓ ▓▓▓ ▓▓▓ ▓ ▓ ▓ ▓ ▓▓▓ ▓▓▓ ▓▓▓▓▓▓▓▓▓ ▓ ▓▓ ▓▓ ▓ ▓▓▓▓▓▓▓▓▓ ``` ## Nim ```nim proc `^`*(base: int, exp: int): int = var (base, exp) = (base, exp) result = 1 while exp != 0: if (exp and 1) != 0: result *= base exp = exp shr 1 base *= base proc inCarpet(x, y): bool = var x = x var y = y while true: if x == 0 or y == 0: return true if x mod 3 == 1 and y mod 3 == 1: return false x = x div 3 y = y div 3 proc carpet(n) = for i in 0 .. <(3^n): for j in 0 .. <(3^n): if inCarpet(i, j): stdout.write "* " else: stdout.write " " echo "" carpet(3) ``` Output: ```txt * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ``` ## Objeck ```objeck class SierpinskiCarpet { function : Main(args : String[]) ~ Nil { Carpet(3); } function : InCarpet(x : Int, y : Int) ~ Bool { while(x<>0 & y<>0) { if(x % 3 = 1 & y % 3 = 1) { return false; }; x /= 3; y /= 3; }; return true; } function : Carpet(n : Int) ~ Nil { power := 3.0->Power(n->As(Float)); for(i := 0; i < power; i+=1;) { for(j := 0; j < power; j+=1;) { c := InCarpet(i, j) ? '*' : ' '; c->Print(); }; IO.Console->PrintLine(); }; } } ``` ## OCaml ```ocaml let rec in_carpet x y = if x = 0 || y = 0 then true else if x mod 3 = 1 && y mod 3 = 1 then false else in_carpet (x / 3) (y / 3) (* I define my own operator for integer exponentiation *) let rec (^:) a b = if b = 0 then 1 else if b mod 2 = 0 then let x = a ^: (b / 2) in x * x else a * (a ^: (b - 1)) let carpet n = for i = 0 to (3 ^: n) - 1 do for j = 0 to (3 ^: n) - 1 do print_char (if in_carpet i j then '*' else ' ') done; print_newline () done ``` ```ocaml let nextCarpet carpet = List.map (fun x -> x ^ x ^ x) carpet @ List.map (fun x -> x ^ String.make (String.length x) ' ' ^ x) carpet @ List.map (fun x -> x ^ x ^ x) carpet let rec sierpinskiCarpet n = let rec aux n carpet = if n = 0 then carpet else aux (n-1) (nextCarpet carpet) in aux n ["#"] let () = List.iter print_endline (sierpinskiCarpet 3) ``` ## Oforth ```Oforth : carpet(n) | dim i j k | 3 n pow ->dim 0 dim 1 - for: i [ 0 dim 1 - for: j [ dim 3 / ->k while(k) [ i k 3 * mod k / 1 == j k 3 * mod k / 1 == and ifTrue: [ break ] k 3 / ->k ] k ifTrue: [ " " ] else: [ "#" ] print ] printcr ] ; ``` ## Order Since the C Preprocessor cannot print newlines, this Order program produces a string for a simple C program to print: ```c #include #define ORDER_PP_DEF_8in_carpet ORDER_PP_FN( \ 8fn(8X, 8Y, \ 8if(8or(8is_0(8X), 8is_0(8Y)), \ 8true, \ 8let((8Q, 8quotient(8X, 3)) \ (8R, 8remainder(8X, 3)) \ (8S, 8quotient(8Y, 3)) \ (8T, 8remainder(8Y, 3)), \ 8and(8not(8and(8equal(8R, 1), 8equal(8T, 1))), \ 8in_carpet(8Q, 8S))))) ) #define ORDER_PP_DEF_8carpet ORDER_PP_FN( \ 8fn(8N, \ 8lets((8R, 8seq_iota(0, 8pow(3, 8N))) \ (8G, 8seq_map(8fn(8Y, 8seq_map(8fn(8X, 8pair(8X, 8Y)), \ 8R)), \ 8R)), \ 8seq_map(8fn(8S, 8seq_map(8fn(8P, 8apply(8in_carpet, 8P)), \ 8S)), \ 8G))) ) #define ORDER_PP_DEF_8carpet_to_string ORDER_PP_FN( \ 8fn(8C, \ 8seq_fold( \ 8fn(8R, 8S, \ 8adjoin(8R, \ 8seq_fold(8fn(8P, 8B, 8adjoin(8P, 8if(8B, 8("#"), 8(" ")))), \ 8nil, 8S), \ 8("\n"))), \ 8nil, 8C)) ) #include int main(void) { printf(ORDER_PP( 8carpet_to_string(8carpet(3)) )); return 0; } ``` (This example may take a long time to compile: change the 8carpet
parameter to 2 for a much quicker compile time and a smaller graphic.) The8carpet
function creates a 2-dimensional array of boolean values (i.e. an internal representation of the Sierpinski carpet), and the8carpet_to_string
function then converts this to a C string. Since the # and space characters are rather difficult for the C Preprocessor to handle (as a result Order can only print them, not concatenate them), this program takes advantage of the fact that two string literals side-by-side in C must be interpreted as a single string. An alternative method might be to pass the carpet to a print function, that prints the carpet string and returns nil, and then use a regular C macro to stringify the entire result of the Order program. ## Oz ```oz declare %% A carpet is a list of lines. fun {NextCarpet Carpet} {Flatten [{Map Carpet XXX} {Map Carpet X_X} {Map Carpet XXX} ]} end fun {XXX X} X#X#X end fun {X_X X} X#{Spaces {VirtualString.length X}}#X end fun {Spaces N} if N == 0 then nil else & |{Spaces N-1} end end fun lazy {Iterate F X} X|{Iterate F {F X}} end SierpinskiCarpets = {Iterate NextCarpet ["#"]} in %% print all lines of the Sierpinski carpet of order 3 {ForAll {Nth SierpinskiCarpets 4} System.showInfo} ``` ## PARI/GP [[File:SierpC5.png|right|thumb|Output SierpC5.png]] [[File:SierpC5a.png|right|thumb|Output SierpC5a.png]] ### Plotting helper functions Note: wrtmat() can be found here on RC [[Brownian_tree#PARI.2FGP| Brownian tree page]]. ```parigp \\ Improved simple plotting using matrix mat (color and scaling added). \\ Matrix should be filled with 0/1. 7/6/16 aev iPlotmat(mat,clr)={ my(xz=#mat[1,],yz=#mat[,1],vx=List(),vy=vx,xmin,xmax,ymin,ymax,c=0.625); for(i=1,yz, for(j=1,xz, if(mat[i,j]==0, next, listput(vx,i); listput(vy,j)))); xmin=listmin(vx); xmax=listmax(vx); ymin=listmin(vy); ymax=listmax(vy); plotinit(0); plotcolor(0,clr); plotscale(0, xmin,xmax,ymin,ymax); plotpoints(0, Vec(vx)*c,Vec(vy)); plotdraw([0,xmin,ymin]); print(" *** matrix: ",xz,"x",yz,", ",#vy," DOTS"); } \\ iPlotV2(): Improved plotting from a file written by the wrtmat(). (color added) \\ Saving possibly huge generation time if re-plotting needed. iPlotV2(fn, clr)={ my(F,nf,vx=List(),vy=vx,Vr,xmin,xmax,ymin,ymax,c=0.625); F=readstr(fn); nf=#F; print(" *** Plotting from: ", fn, " - ", nf, " DOTS"); for(i=1,nf, Vr=stok(F[i]," "); listput(vx,eval(Vr[1])); listput(vy,eval(Vr[2]))); xmin=listmin(vx); xmax=listmax(vx); ymin=listmin(vy); ymax=listmax(vy); plotinit(0); plotcolor(0,clr); plotscale(0, xmin,xmax,ymin,ymax); plotpoints(0, Vec(vx)*c,Vec(vy)); plotdraw([0,xmin,ymin]); } \\ Are x,y inside Sierpinski carpet? (1-yes, 0-no) 6/10/16 aev inSC(x,y)={ while(1, if(!x||!y,return(1)); if(x%3==1&&y%3==1, return(0)); x\=3; y\=3;);\\wend } ``` ### Sierpinski carpet fractal. ```parigp \\ Sierpinski carpet fractal (n - order, clr - color, dfn - data file name) \\ 6/10/16, upgraded 11/29/16 aev pSierpinskiC(n, clr=5, dfn="")={ my(n3=3^n-1,M,pf=n>=5); if(pf, M=matrix(n3+1,n3+1)); for(i=0,n3, for(j=0,n3, if(inSC(i,j), if(pf, M[i+1,j+1]=1, print1("* ")), if(!pf, print1(" "))); ); if(!pf, print("")); );\\fend i if(!pf, return(0)); if(dfn=="", c, wrtmat(M, dfn)); } {\\ Test: pSierpinskiC(3); pSierpinskiC(5,14); \\ SierpC5.png, color - navy } {pSierpinskiC(5,,"c:\\pariData\\SC5.dat"); iPlotV2("c:\\pariData\\SC5.dat",10);} \\ SierpC5a.png, color - dark-green ``` ```txt > pSierpinskiC(3); * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * > pSierpinskiC(5,14); \\ SierpC5.png, color navy *** matrix: 243x243, 32768 DOTS > {pSierpinskiC(5,,"c:\\pariData\\SC5.dat"); iPlotV2("c:\\pariData\\SC5.dat",10);} \\ SierpC5a.png, color - dark-green *** matrix(243x243) 32768 DOTS put in c:\pariData\SC5.dat *** Plotting from: c:\pariData\SC5.dat - 32768 DOTS ``` ## Pascal ```pascal Program SierpinskiCarpet; uses Math; function In_carpet(a, b: longint): boolean; var x, y: longint; begin x := a; y := b; while true do begin if (x = 0) or (y = 0) then begin In_carpet := true; break; end else if ( (x mod 3) = 1 ) and ((y mod 3) = 1) then begin In_carpet := false; break; end; x := x div 3; y := y div 3; end; end; procedure Carpet(n: integer); var i, j: longint; begin for i := 0 to 3**n - 1 do begin for j := 0 to 3**n - 1 do if In_carpet(i, j) then write('*') else write(' '); writeln; end; end; begin Carpet(3); end. ``` ```txt :> ./SierpinskiCarpet *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ********* ********* * ** ** * * ** ** * ********* ********* *** *** *** *** * * * * * * * * *** *** *** *** ********* ********* * ** ** * * ** ** * ********* ********* *************************** * ** ** ** ** ** ** ** ** * *************************** *** ****** ****** *** * * * ** * * ** * * * *** ****** ****** *** *************************** * ** ** ** ** ** ** ** ** * *************************** ``` ## Perl ```perl my @c = '##'; @c = (map($_ x 3, @c), map($_.(' ' x length).$_, @c), map($_ x 3, @c)) for 1 .. 3; print join("\n", @c), "\n"; ``` ## Perl 6 ```perl6 sub carpet { (['#'], -> @c { [ |@c.map({$_ x 3}), |@c.map({ $_ ~ $_.trans('#'=>' ') ~ $_}), |@c.map({$_ x 3}) ] } ... *).map: { .join("\n") }; } say carpet[3]; # Same as above, structured as an array bound to a sequence, with a separate sub for clarity. sub weave ( @c ) { [ |@c.map({ $_ x 3 }), |@c.map({ $_ ~ .trans( '#' => ' ' ) ~ $_ }), |@c.map({ $_ x 3 }) ] } my @carpet = ( ['#'], &weave ... * ).map: { .join: "\n" }; say @carpet[3]; # Output of both versions matches task example. ``` ## Phix ```Phix constant order = 4 function InCarpet(atom x, atom y) while x!=0 and y!=0 do if floor(mod(x,3))=1 and floor(mod(y,3))=1 then return ' ' end if x /= 3 y /= 3 end while return '#' end function for i=0 to power(3,order)-1 do for j=0 to power(3,order)-1 do puts(1,InCarpet(i,j)) end for puts(1,'\n') end for ```################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # # ### ### ### ### ### ### ### ### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ``` ## PicoLisp ```PicoLisp (de carpet (N) (let Carpet '("#") (do N (setq Carpet (conc (mapcar '((S) (pack S S S)) Carpet) (mapcar '((S) (pack S (replace (chop S) "#" " ") S)) Carpet ) (mapcar '((S) (pack S S S)) Carpet) ) ) ) ) ) (mapc prinl (carpet 3)) ``` ## PL/I ```PL/I /* Sierpinski carpet */ Sierpinski_carpet: procedure options (main); /* 28 January 2013 */ call carpet(3); In_carpet: procedure (a, b) returns (bit(1)); declare (a, b) fixed binary nonassignable; declare (x, y) fixed binary; declare (true value ('1'b), false value ('0'b)) bit (1); x = a ; y = b; do forever; if x = 0 | y = 0 then return (true); else if mod(x, 3) = 1 & mod(y, 3) = 1 then return (false); x = x / 3; y = y / 3; end; end in_carpet; Carpet: procedure (n); declare n fixed binary nonassignable; declare (i, j) fixed binary; do i = 0 to 3**n - 1; do j = 0 to 3**n - 1; if In_carpet(i, j) then put edit ('#') (a); else put edit (' ') (a); end; put skip; end; end Carpet; end Sierpinski_carpet; ``` The above is a translation of the Fortran version. Output for n=3: ```txt ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## PostScript ```PostScript %!PS-Adobe-3.0 %%BoundingBox 0 0 300 300 /r { moveto 0 -1 1 0 0 1 3 { rlineto } repeat closepath fill } def /serp { gsave 3 1 roll translate 1 3 div dup scale 1 1 r dup 1 sub dup 0 eq not { 0 0 0 1 0 2 1 0 1 2 2 0 2 1 2 2 17 -1 roll 8 { serp } repeat } if pop grestore } def 300 300 scale 0 0 r 1 setgray 0 0 5 serp pop showpage %%EOF ``` ## PowerShellText based solution
```PowerShell function Draw-SierpinskiCarpet ( [int]$N ) { $Carpet = @( '#' ) * [math]::Pow( 3, $N ) ForEach ( $i in 1..$N ) { $S = [math]::Pow( 3, $i - 1 ) ForEach ( $Row in 0..($S-1) ) { $Carpet[$Row+$S+$S] = $Carpet[$Row] * 3 $Carpet[$Row+$S] = $Carpet[$Row] + ( " " * $Carpet[$Row].Length ) + $Carpet[$Row] $Carpet[$Row] = $Carpet[$Row] * 3 } } $Carpet } Draw-SierpinskiCarpet 3 ``` ```txt ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ```Graphics based solution
```PowerShell Function Draw-SierpinskiCarpet ( [int]$N ) { # Define form $Form = [System.Windows.Forms.Form]@{ Size = '300, 300' } $Form.Controls.Add(( $PictureBox = [System.Windows.Forms.PictureBox]@{ Size = $Form.ClientSize; Anchor = 'Top, Bottom, Left, Right' } )) # Main code to draw Sierpinski carpet $Draw = { # Create graphics objects to use $PictureBox.Image = ( $Canvas = New-Object System.Drawing.Bitmap ( $PictureBox.Size.Width, $PictureBox.Size.Height ) ) $Graphics = [System.Drawing.Graphics]::FromImage( $Canvas ) # Draw single pixel $Graphics.FillRectangle( [System.Drawing.Brushes]::Black, 0, 0, 1, 1 ) # If N was not specified, use an N that will fill the form If ( -not $N ) { $N = [math]::Ceiling( [math]::Log( [math]::Max( $PictureBox.Size.Height, $PictureBox.Size.Width ) ) / [math]::Log( 3 ) ) } # Define the shape of the fractal $P = @( @( 0, 0 ), @( 0, 1 ), @( 0, 2 ) ) $P += @( @( 1, 0 ), @( 1, 2 ) ) $P += @( @( 2, 0 ), @( 2, 1 ), @( 2, 2 ) ) # For each iteration ForEach ( $i in 0..$N ) { # Copy the result of the previous iteration $Copy = New-Object System.Drawing.TextureBrush ( $Canvas ) # Calulate the size of the copy $S = [math]::Pow( 3, $i ) # For each position in the next layer of the fractal ForEach ( $i in 1..7 ) { # Adjust the copy for the new location $Copy.TranslateTransform( - $P[$i-1][0] * $S + $P[$i][0] * $S, - $P[$i-1][1] * $S + $P[$i][1] * $S ) # Paste the copy of the previous iteration into the new location $Graphics.FillRectangle( $Copy, $P[$i][0] * $S, $P[$i][1] * $S, $S, $S ) } } } # Add the main drawing code to the appropriate events to be drawn when the form is first shown and redrawn when the form size is changed $Form.Add_Shown( $Draw ) $Form.Add_Resize( $Draw ) # Launch the form $Null = $Form.ShowDialog() } Draw-SierpinskiCarpet 4 ``` ## PureBasic ```PureBasic Procedure in_carpet(x,y) While x>0 And y>0 If x%3=1 And y%3=1 ProcedureReturn #False EndIf y/3: x/3 Wend ProcedureReturn #True EndProcedure Procedure carpet(n) Define i, j, l=Pow(3,n)-1 For i=0 To l For j=0 To l If in_carpet(i,j) Print("#") Else Print(" ") EndIf Next PrintN("") Next EndProcedure ``` ## Python This inserts a space after every character; but this makes the spacing look better anyway. ```python def in_carpet(x, y): while True: if x == 0 or y == 0: return True elif x % 3 == 1 and y % 3 == 1: return False x /= 3 y /= 3 def carpet(n): for i in xrange(3 ** n): for j in xrange(3 ** n): if in_carpet(i, j): print '*', else: print ' ', print ``` This version is elegant: ```python def sierpinski_carpet(n): carpet = ["#"] for i in xrange(n): carpet = [x + x + x for x in carpet] + \ [x + x.replace("#"," ") + x for x in carpet] + \ [x + x + x for x in carpet] return "\n".join(carpet) print sierpinski_carpet(3) ``` We can also define a Sierpinski carpet weave declaratively, in terms of generic abstractions like '''zipWith''' and '''bind''': ```python '''Iterations of the Sierpinski carpet''' from itertools import chain, islice from inspect import signature from operator import add # sierpinskiCarpet :: Int -> [String] def sierpinskiCarpet(n): '''A string representing the nth iteration of a Sierpinski carpet. ''' f = zipWith(add) g = flip(f) # weave :: [String] -> [String] def weave(xs): return bind([ xs, [' ' * len(s) for s in xs], xs ])(compose(g(xs))(f(xs))) return index( iterate(weave)(['▓▓']) )(n) # TEST ---------------------------------------------------- def main(): '''Test iteration of the Sierpinski carpet''' levels = enumFromTo(0)(3) t = ' ' * ( len(' -> ') + max(map(compose(len)(str), levels)) ) print( fTable(__doc__ + ':')(lambda x: '\n' + str(x))( lambda xs: xs[0] + '\n' + ( unlines(map(lambda x: t + x, xs[1:]))) ) (sierpinskiCarpet)(levels) ) # GENERIC ------------------------------------------------- # bind (>>=) :: [a] -> (a -> [b]) -> [b] def bind(xs): '''List monad injection operator. Two computations sequentially composed, with any value produced by the first passed as an argument to the second.''' return lambda f: list(chain.from_iterable( map(f, xs) )) # compose (<<<) :: (b -> c) -> (a -> b) -> a -> c def compose(g): '''Right to left function composition.''' return lambda f: lambda x: g(f(x)) # enumFromTo :: (Int, Int) -> [Int] def enumFromTo(m): '''Integer enumeration from m to n.''' return lambda n: list(range(m, 1 + n)) # flip :: (a -> b -> c) -> b -> a -> c def flip(f): '''The (curried or uncurried) function f with its arguments reversed.''' if 1 < len(signature(f).parameters): return lambda a, b: f(b, a) else: return lambda a: lambda b: f(b)(a) # index (!!) :: [a] -> Int -> a def index(xs): '''Item at given (zero-based) index.''' return lambda n: None if 0 > n else ( xs[n] if ( hasattr(xs, "__getitem__") ) else next(islice(xs, n, None)) ) # iterate :: (a -> a) -> a -> Gen [a] def iterate(f): '''An infinite list of repeated applications of f to x. ''' def go(x): v = x while True: yield v v = f(v) return lambda x: go(x) # unlines :: [String] -> String def unlines(xs): '''A single string derived by the intercalation of a list of strings with the newline character.''' return '\n'.join(xs) # zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] def zipWith(f): '''A list constructed by zipping with a custom function, rather than with the default tuple constructor.''' return lambda xs: lambda ys: ( map(f, xs, ys) ) # OUTPUT FORMATTING --------------------------------------- # fTable :: String -> (a -> String) -> # (b -> String) -> (a -> b) -> [a] -> String def fTable(s): '''Heading -> x display function -> fx display function -> f -> xs -> tabular string. ''' def go(xShow, fxShow, f, xs): ys = [xShow(x) for x in xs] w = max(map(len, ys)) return s + '\n' + '\n'.join(map( lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)), xs, ys )) return lambda xShow: lambda fxShow: lambda f: lambda xs: go( xShow, fxShow, f, xs ) # MAIN --- if __name__ == '__main__': main() ``` ```txt Iterations of the Sierpinski carpet: 0 -> ▓▓ 1 -> ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ 2 -> ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 3 -> ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓▓▓ ▓▓ ▓▓ ▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓▓▓ ▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ``` ## R ### Version #1. Note: Find plotmat() here on RC [[User:AnatolV/Helper_Functions| R Helper Functions page]]. [[File:SierpCRo5.png|200px|right|thumb|Output SierpCRo5.png]] ```r ## Are x,y inside Sierpinski carpet (and where)? (1-yes, 0-no) inSC <- function(x, y) { while(TRUE) { if(!x||!y) {return(1)} if(x%%3==1&&y%%3==1) {return(0)} x=x%/%3; y=y%/%3; } return(0); } ## Plotting Sierpinski carpet fractal. aev 4/1/17 ## ord - order, fn - file name, ttl - plot title, clr - color pSierpinskiC <- function(ord, fn="", ttl="", clr="navy") { m=640; abbr="SCR"; dftt="Sierpinski carpet fractal"; n=3^ord-1; M <- matrix(c(0), ncol=n, nrow=n, byrow=TRUE); cat(" *** START", abbr, date(), "\n"); if(fn=="") {pf=paste0(abbr,"o", ord)} else {pf=paste0(fn, ".png")}; if(ttl!="") {dftt=ttl}; ttl=paste0(dftt,", order ", ord); cat(" *** Plot file:", pf,".png", "title:", ttl, "\n"); for(i in 0:n) { for(j in 0:n) {if(inSC(i,j)) {M[i,j]=1} }} plotmat(M, pf, clr, ttl); cat(" *** END", abbr, date(), "\n"); } ## Executing: pSierpinskiC(5); ``` ```txt > pSierpinskiC(5); *** START SCR Sun Apr 02 12:39:21 2017 *** Plot file: SCRo5 .png title: Sierpinski carpet fractal, order 5 *** Matrix( 242 x 242 ) 32283 DOTS *** END SCR Sun Apr 02 12:39:28 2017 ``` ### Version #2. Note: Find plotmat() here on RC [[User:AnatolV/Helper_Functions| R Helper Functions page]]. [[File:SierpCR2o5.png|200px|right|thumb|Output SierpCR2o5.png]] ```r ## Plotting Sierpinski carpet fractal v.2. aev 4/2/17 ## ord - order, fn - file name, ttl - plot title, clr - color pSierpinskiC2 <- function(ord, fn="", ttl="", clr="brown") { m=640; abbr="SCR2"; dftt="Sierpinski carpet fractal v.2"; cat(" *** START", abbr, date(), "\n"); if(fn=="") {pf=paste0(abbr,"o", ord)} else {pf=paste0(fn, ".png")}; if(ttl!="") {dftt=ttl}; ttl=paste0(dftt,", order ", ord); cat(" *** Plot file:", pf,".png", "title:", ttl, "\n"); S = matrix(1,1,1); for (i in 1:ord) { Q = cbind(S,S,S); R = cbind(S,0*S,S); S = rbind(Q,R,Q); } plotmat(S, pf, clr, ttl); cat(" *** END", abbr, date(), "\n"); } ## Executing: pSierpinskiC2(5); ``` ```txt > pSierpinskiC2(5); *** START SCR2 Sun Apr 02 14:44:17 2017 *** Plot file: SCR2o5 .png title: Sierpinski carpet fractal v.2, order 5 *** Matrix( 243 x 243 ) 32768 DOTS *** END SCR2 Sun Apr 02 14:44:24 2017 ``` ## REXX ```rexx /*REXX program draws any order Sierpinski carpet (order 20 would be ≈ 3.4Gx3.4G carpet).*/ parse arg N char . /*get the order of the carpet. */ if N=='' | N=="," then N= 3 /*if none specified, then assume 3. */ if char=='' then char= "*" /*use the default of an asterisk (*). */ if length(char)==2 then char= x2c(char) /*it was specified in hexadecimal char.*/ if length(char)==3 then char= d2c(char) /* " " " " decimal character*/ width= linesize() /*the width of the terminal screen. */ if N>18 then numeric digits 100 /*just in case the user went ka─razy. */ nnn= 3**N /* [↓] NNN is the cube of N. */ do j=0 for nnn; z= /*Z: will be the line to be displayed.*/ do k=0 for nnn; jj= j; kk= k; x= char do while jj\==0 & kk\==0 /*one symbol for a not (¬) is a \ */ if jj//3==1 then if kk//3==1 then do /*in REXX: // ≡ division remainder*/ x= ' ' /*use a blank for this display line. */ leave /*LEAVE terminates this DO WHILE. */ end jj= jj % 3; kk= kk % 3 /*in REXX: % ≡ integer division. */ end /*while*/ z= z || x /*X is either black or white. */ end /*k*/ /* [↑] " " " " blank. */ if length(z)N=0 # N=1 ### # # ### N=2 ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### N=3 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## Rust ```rust fn main() { for i in 0..4 { println!("\nN={}", i); println!("{}", sierpinski_carpet(i)); } } fn sierpinski_carpet(n: u32) -> String { let mut carpet = vec!["#".to_string()]; for _ in 0..n { let mut top: Vec<_> = carpet.iter().map(|x| x.repeat(3)).collect(); let middle: Vec<_> = carpet .iter() .map(|x| x.to_string() + &x.replace("#", " ") + x) .collect(); let bottom = top.clone(); top.extend(middle); top.extend(bottom); carpet = top; } carpet.join("\n") } ``` ## Scala ```scala def nextCarpet(carpet: List[String]): List[String] = ( carpet.map(x => x + x + x) ::: carpet.map(x => x + x.replace('#', ' ') + x) ::: carpet.map(x => x + x + x)) def sierpinskiCarpets(n: Int) = (Iterator.iterate(List("#"))(nextCarpet) drop n next) foreach println ``` ## Scheme ```scheme (define (carpet n) (define (in-carpet? x y) (cond ((or (zero? x) (zero? y)) #t) ((and (= 1 (remainder x 3)) (= 1 (remainder y 3))) #f) (else (in-carpet? (quotient x 3) (quotient y 3))))) (do ((i 0 (+ i 1))) ((not (< i (expt 3 n)))) (do ((j 0 (+ j 1))) ((not (< j (expt 3 n)))) (display (if (in-carpet? i j) #\* #\space))) (newline))) ``` ## Seed7 ```seed7 $ include "seed7_05.s7i"; const func boolean: inCarpet (in var integer: x, in var integer: y) is func result var boolean: result is TRUE; begin while result and x <> 0 and y <> 0 do if x rem 3 = 1 and y rem 3 = 1 then result := FALSE; else x := x div 3; y := y div 3; end if; end while; end func; const proc: carpet (in integer: n) is func local var integer: i is 0; var integer: j is 0; begin for i range 0 to pred(3 ** n) do for j range 0 to pred(3 ** n) do if inCarpet(i, j) then write("#"); else write(" "); end if; end for; writeln; end for; end func; const proc: main is func begin carpet(3); end func; ``` ## Sidef ```ruby var c = ['##'] 3.times { c = (c.map{|x| x * 3 } + c.map{|x| x + ' '*x.len + x } + c.map{|x| x * 3 }) } say c.join("\n") ``` ## Sinclair ZX81 BASIC Works with the unexpanded (1k RAM) ZX81. A screenshot of the output is [http://www.edmundgriffiths.com/zx81sierpcarpet.jpg here]. ```basic 10 LET O=3 20 LET S=3**O 30 FOR I=0 TO S-1 40 FOR J=0 TO S-1 50 LET X=J 60 LET Y=I 70 GOSUB 120 80 IF C THEN PLOT J,I 90 NEXT J 100 NEXT I 110 GOTO 190 120 LET C=0 130 IF X-INT (X/3)*3=1 AND Y-INT (Y/3)*3=1 THEN RETURN 140 LET X=INT (X/3) 150 LET Y=INT (Y/3) 160 IF X>0 OR Y>0 THEN GOTO 130 170 LET C=1 180 RETURN ``` ## Swift ```Swift import Foundation func sierpinski_carpet(n:Int) -> String { func middle(str:String) -> String { let spacer = str.stringByReplacingOccurrencesOfString("#", withString:" ", options:nil, range:nil) return str + spacer + str } var carpet = ["#"] for i in 1...n { let a = carpet.map{$0 + $0 + $0} let b = carpet.map(middle) carpet = a + b + a } return "\n".join(carpet) } println(sierpinski_carpet(3)) ``` ## Tcl ```tcl package require Tcl 8.5 proc map {lambda list} { foreach elem $list { lappend result [apply $lambda $elem] } return $result } proc sierpinski_carpet n { set carpet [list "#"] for {set i 1} {$i <= $n} {incr i} { set carpet [concat \ [map {x {subst {$x$x$x}}} $carpet] \ [map {x {subst {$x[string map {"#" " "} $x]$x}}} $carpet] \ [map {x {subst {$x$x$x}}} $carpet] \ ] } return [join $carpet \n] } puts [sierpinski_carpet 3] ``` ## uBasic/4tH Input "Carpet order: ";n l = (3^n) - 1 For i = 0 To l For j = 0 To l Push i,j Gosub 100 If Pop() Then Print "#"; Else Print " "; EndIf Next Print Next End 100 y = Pop(): x = Pop() : Push 1 Do While (x > 0) * (y > 0) If (x % 3 = 1) * (y % 3 = 1) Then Push (Pop() - 1) Break EndIf y = y / 3 x = x / 3 Loop Return ``` ## UNIX Shell Doesn't pretend to be efficient. Note that this code inserts a space between characters; some versions of [http://en.wikipedia.org/wiki/Paste_(Unix) paste(1)] (notably the one that ships with OS X) won't allow an empty delimiter. If yours does, you can replace the -d ' ' in the function body with -d ' ' for more compact output. ```bash #!/bin/bash sierpinski_carpet() { local -i n="${1:-3}" local carpet="${2:-#}" while (( n-- )); do local center="${carpet//#/ }" carpet="$(paste -d ' ' <(echo "$carpet"$'\n'"$carpet"$'\n'"$carpet") <(echo "$carpet"$'\n'"$center"$'\n'"$carpet") <(echo "$carpet"$'\n'"$carpet"$'\n'"$carpet"))" done echo "$carpet" } ``` Sample run: ```txt $ sierpinski_carpet 3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ``` ## Ursala The carpet function works for any natural number n and is tested on 0,1,2, and 3. The carpet is stored as a list of lists of booleans but converted to characters for display. ```Ursala #import std #import nat carpet = ~&a^?\<<&>>! (-*<7,5,7>; *=DS ~&K7+ ~&B**DS*=rlDS)^|R/~& predecessor #show+ test = mat0 ~&?(`#!,` !)*** carpet* <0,1,2,3> ``` # ### # # ### ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## VBA ```vb Const Order = 4 Function InCarpet(ByVal x As Integer, ByVal y As Integer) Do While x <> 0 And y <> 0 If x Mod 3 = 1 And y Mod 3 = 1 Then InCarpet = " " Exit Function End If x = x \ 3 y = y \ 3 Loop InCarpet = "#" End Function Public Sub sierpinski_carpet() Dim i As Integer, j As Integer For i = 0 To 3 ^ Order - 1 For j = 0 To 3 ^ Order - 1 Debug.Print InCarpet(i, j); Next j Debug.Print Next i End Sub ``` ```txt ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ### ### ### ### ### ### ### ### # # # # # # # # # # # # # # # # ### ### ### ### ### ### ### ### ######### ######### ######### ######### # ## ## # # ## ## # # ## ## # # ## ## # ######### ######### ######### ######### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ### ###### ###### ### ### ###### ###### ### # # # ## # # ## # # # # # # ## # # ## # # # ### ###### ###### ### ### ###### ###### ### ########################### ########################### # ## ## ## ## ## ## ## ## # # ## ## ## ## ## ## ## ## # ########################### ########################### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ### ### ### ###### ### ### ###### ### ### ### # # # # # # # ## # # # # # # ## # # # # # # # ### ### ### ###### ### ### ###### ### ### ### ######### ################## ################## ######### # ## ## # # ## ## ## ## ## # # ## ## ## ## ## # # ## ## # ######### ################## ################## ######### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ### ###### ###### ###### ###### ###### ###### ###### ###### ### # # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # ## # # # ### ###### ###### ###### ###### ###### ###### ###### ###### ### ################################################################################# # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # ################################################################################# ``` ## VBScript ```VBScript Function InCarpet(i,j) If i > 0 And j > 0 Then Do While i > 0 And j > 0 If i Mod 3 = 1 And j Mod 3 = 1 Then InCarpet = " " Exit Do Else InCarpet = "#" End If i = Int(i / 3) j = Int(j / 3) Loop Else InCarpet = "#" End If End Function Function Carpet(n) k = 3^n - 1 x2 = 0 y2 = 0 For y = 0 To k For x = 0 To k x2 = x y2 = y WScript.StdOut.Write InCarpet(x2,y2) Next WScript.StdOut.WriteBlankLines(1) Next End Function Carpet(WScript.Arguments(0)) ``` ```txt F:\VBScript>cscript /nologo RosettaCode-Sierpinski_Carpet.vbs 3 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## X86 Assembly Uses magic number division to avoid repeatedly using the div instruction in a loop. ```asm ;x86-64 assembly code for Microsoft Windows ;Tested in windows 7 Enterprise Service Pack 1 64 bit ;With the AMD FX(tm)-6300 processor ;Assembled with NASM version 2.11.06 ;Linked to C library with gcc version 4.9.2 (x86_64-win32-seh-rev1, Built by MinGW-W64 project) ;Assembled and linked with the following commands: ;nasm -f win64.asm -o .obj ;gcc .obj -o ;Takes magnitude of Sierpinski Carpet as command line argument. extern atoi,puts,putchar,exit section .data errmsg_noarg: db "Magnitude of Sierpinski Carpet was not specified.",0 errmsg_argnumber: db "There should be no more than one argument.",0 section .bss section .text global main main: ;check for argument cmp rcx,1 jle err_noarg ;ensure that only one argument was entered cmp rcx,2 jg err_argnumber ;column in rsi ;row in rdi ;x in r8 ;y in r9 ;width in r13 ;magic number in r14 mov r14,2863311531 ;get magnitude in rbx from first arg mov rcx,[rdx + 8] call atoi mov rbx,rax cmp rbx,0 jz magnitude_zero ;determine dimensions of square mov rax,1 find_width: lea rax,[rax * 3] dec rbx jg find_width sub rax,1 mov r13,rax mov rdi,rax next_row: mov rsi,r13 fill_row: ;x in r8, y in r9 mov r8,rsi mov r9,rdi is_filled: ;if(x%3==1 && y%3==1) ;x%3 in rbx mov rax,r8 mov rbx,r8 mul r14 shr rax,33 mov r8,rax lea rax,[rax * 3] sub rbx,rax ;y%3 in rcx mov rax,r9 mov rcx,r9 mul r14 shr rax,33 mov r9,rax lea rax,[rax * 3] sub rcx,rax ;x%3==1 && y%3==1 xor rbx,1 xor rcx,1 or rbx,rcx mov rcx,' ' cmp rbx,0 jz dont_fill ;x>0 || y>0 mov rax,r8 or rax,r9 cmp rax,0 jg is_filled mov rcx,'#' dont_fill: call putchar dec rsi jge fill_row ;put newline at the end of each row mov rcx,0xa call putchar dec rdi jge next_row xor rcx,rcx call exit magnitude_zero: mov rcx,'#' call putchar mov rcx,0xa call putchar xor rcx,rcx call exit ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;error message err_noarg: mov rcx,errmsg_noarg call puts mov rcx,1 call exit err_argnumber: mov rcx,errmsg_argnumber call puts mov rcx,1 call exit ``` ```txt F:\>asciisierpinski.exe Magnitude of Sierpinski Carpet was not specified. F:\>asciisierpinski.exe 1 1 1 There should be no more than one arguement. F:\>asciisierpinski.exe 0 # F:\>asciisierpinski.exe 1 ### # # ### F:\>asciisierpinski.exe 2 ######### # ## ## # ######### ### ### # # # # ### ### ######### # ## ## # ######### F:\>asciisierpinski.exe 3 ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ######### ######### # ## ## # # ## ## # ######### ######### ### ### ### ### # # # # # # # # ### ### ### ### ######### ######### # ## ## # # ## ## # ######### ######### ########################### # ## ## ## ## ## ## ## ## # ########################### ### ###### ###### ### # # # ## # # ## # # # ### ###### ###### ### ########################### # ## ## ## ## ## ## ## ## # ########################### ``` ## XPL0 [[File:CarpetXPL0.gif|right]] ```XPL0 include c:\cxpl\codes; \intrinsic 'code' declarations proc DrawPat(X0, Y0, S); \Draw 3x3 pattern with hole in middle int X0, Y0, S; \coordinate of upper-left corner, size int X, Y; [for Y:= 0 to 2 do for X:= 0 to 2 do if X#1 or Y#1 then \don't draw middle pattern [if S>1 then \recurse DrawPat(X*S+X0, Y*S+Y0, S/3) else Point(X+X0, Y+Y0, 4\red\); ]; ]; [SetVid($13); \set 320x200 graphic video mode DrawPat(0, 0, 3*3*3); \draw Sierpinski carpet if ChIn(1) then []; \wait for keystroke SetVid($3); \restore normal text mode ] ``` ## Yabasic ```Yabasic sub sp$(n) local i, s$ for i = 1 to n s$ = s$ + " " next i return s$ end sub sub replace$(s$, cf$, cr$) local i, p do i = instr(s$, cf$, p) if not i break mid$(s$, i, 1) = cr$ p = i loop return s$ end sub sub foreach$(carpet$, p$, m) local n, i, t$(1) n = token(carpet$, t$(), ",") for i = 1 to n switch(m) case 0: p$ = p$ + "," + t$(i) + t$(i) + t$(i) : break case 1: p$ = p$ + "," + t$(i) + sp$(len(t$(i))) + t$(i) : break default: error "Method not found!" : break end switch next i return p$ end sub sub sierpinskiCarpet$(n) local carpet$, next$, i carpet$ = "@" for i = 1 to n next$ = foreach$(carpet$, "") next$ = foreach$(carpet$, next$, 1) carpet$ = foreach$(carpet$, next$) next i return carpet$ end sub print replace$(sierpinskiCarpet$(3), ",", "\n") ``` ## zkl [[File:Sierpinski carpet.zkl.gif|250px|thumb|right]] Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl ```zkl fcn drawPat(x0,y0,s,img){ // Draw 3x3 pattern with hole in middle foreach y,x in (3,3){ if(x.isEven or y.isEven){ // don't draw middle pattern if(s>1) self.fcn(x*s + x0, y*s + y0, s/3, img); // recurse else img[x + x0, y + y0]=0xff0000; // red } } } ``` ```zkl img:=PPM(800,800); drawPat(0,0,(3).pow(5),img); img.write(File("foo.ppm","wb")); ```