Generate a Koch Snowflake
A Koch snowflake is a triangle that for each n, another equilateral point is added in the middle of each side: http://en.wikipedia.org/wiki/Koch_snowflake#Properties
We already had a kolmogrov-complexity Koch Snowflake challenge for n=4. The new challenge is to draw a Koch snowflake with any n between 1 and 10.
Rules
The snowflakes may not be hardcoded in the program or in files - they must be generated by your program.
Your program must support all sized
nbetween 1 and 10.The number of sides must be input by the user through std-in.
You must print a graphical representation of the snowflake to the screen.
Sample Koch Snowflakes with n equaling 1, 2, 3, and 4 (green lines for clarity only, do not reproduce them):
Koch Snowflakes
In the event of a tie-breaker, the program with the highest number of upvotes wins (pop-contest).
12 Answers 12
MATLAB, (削除) 119 (削除ここまで) 115
In an unusual turn of events, I found that this program actually worked better as I golfed it. First, it became much faster due to vectorization. Now, it displays a helpful prompt ~n:~ reminding the user of which quantity to enter!
Newlines are not part of the program.
x=exp(i*pi/3);
o='~n:~';
P=x.^o;
for l=2:input(o);
P=[kron(P(1:end-1),~~o)+kron(diff(P)/3,[0 1 1+1/x 2]) 1];
end;
plot(P)
n = 9: n=9
o is an arbitrary string which is equal to [0 2 4 0] modulo 6. eiπ/3 raised to these powers gives the vertices of an equilateral triangle in the complex plane. The first kron is used to make a copy of the list of points with each one duplicated 4 times. ~~o is the convenient way to get a vector of 4 ones. Secondly diff(P) finds the vector between each pair of consecutive points. Multiples of this vector (0, 1/3, (1 + e-iπ/3)/3, and 2/3) are added to each of the old points.
-
\$\begingroup\$ Uhm, could you explain somewhat more how this code works? I thought I knew some Matlab but this is ... insanity?? =) \$\endgroup\$flawr– flawr2015年04月24日 20:30:37 +00:00Commented Apr 24, 2015 at 20:30
-
\$\begingroup\$ @flawr I added a few notes, does that help any? \$\endgroup\$feersum– feersum2015年04月24日 22:09:17 +00:00Commented Apr 24, 2015 at 22:09
-
\$\begingroup\$ Thank you very much! I'm gonna keep that string-abuse trick in mind=) \$\endgroup\$flawr– flawr2015年04月25日 11:52:33 +00:00Commented Apr 25, 2015 at 11:52
T-SQL: 686 (excluding formatting)
For SQL Server 2012+.
Even though this will never be a contender, I had to see if I could get it done in T-SQL. Gone for the approach of starting with the three initial edges, then recursing through each edge and replacing them with 4 edges for each level. Finally unioning it all up into a single geometry for the level specified for @i
DECLARE @i INT=8,@ FLOAT=0,@l FLOAT=9;
WITH R AS(
SELECT sX,sY,eX,eY,@l l,B,1i
FROM(VALUES(@,@,@l,@,0),(@l,@,@l/2,SQRT(@l*@l-(@l/2)*(@l/2)),-120),(@l/2,SQRT(@l*@l-(@l/2)*(@l/2)),@,@,-240))a(sX,sY,eX,eY,B)
UNION ALL
SELECT a.sX,a.sY,a.eX,a.eY,l/3,a.B,i+1
FROM R
CROSS APPLY(VALUES(sX,sY,sX+(eX-sX)/3,sY+(eY-sY)/3,sX+((eX-sX)/3)*2,sY+((eY-sY)/3)*2))x(x1,y1,x2,y2,x3,y3)
CROSS APPLY(VALUES(x2+((l/3)*SIN(RADIANS(B-210.))),y2+((l/3)*COS(RADIANS(B-210.)))))n(x4,y4)
CROSS APPLY(VALUES(x1,y1,x2,y2,B),
(x3,y3,eX,eY,B),
(x2,y2,x4,y4,B+60),
(x4,y4,x3,y3,B-60)
)a(sX,sY,eX,eY,B)
WHERE @i>i)
SELECT Geometry::UnionAggregate(Geometry::Parse(CONCAT('LINESTRING(',sX,' ',sY,',',eX,' ',eY,')')))
FROM R
WHERE i=@i
enter image description here enter image description here
-
\$\begingroup\$ I had no idea such wizardry could be achieved with T-SQL! \$\endgroup\$Harry Mustoe-Playfair– Harry Mustoe-Playfair2015年05月11日 20:56:52 +00:00Commented May 11, 2015 at 20:56
LOGO: 95
to w:c ifelse:c=1[fd 2 lt 60][w:c-1 w:c-1 lt 180 w:c-1 w:c-1]end
to k:c repeat 3[w:c rt 180]end
Defines function k with a single level parameter.
Edit
In the this online editor http://www.calormen.com/jslogo/ you can add k readword to use prompt for input, but for some reason this command does not support the standard abbreviation rw.
The 102 characters solution below works in USBLogo with standard input as specified in the question. However the code needed slight changes as UCBLogo has some weird parser. It requires to and end to be in separate lines and space before : is required but on the other hand : are optional.
to w c
ifelse c=1[fd 2 lt 60][w c-1 w c-1 lt 180 w c-1 w c-1]
end
to k c
repeat 3[w c rt 180]
end
k rw
-
\$\begingroup\$ How do you run LOGO? \$\endgroup\$Beta Decay– Beta Decay2014年11月07日 20:44:20 +00:00Commented Nov 7, 2014 at 20:44
-
\$\begingroup\$ @BetaDecay I used this: logo.twentygototen.org but this was the first I found: calormen.com/jslogo You can also install USBLogo \$\endgroup\$nutki– nutki2014年11月07日 21:16:13 +00:00Commented Nov 7, 2014 at 21:16
Mathematica - 177
r[x_, y_] := Sequence[x, RotationTransform[π/3, x]@y, y]
Graphics@Polygon@Nest[
ReplaceList[#, {___, x_, y_, ___} Sequence[x,r[2 x/3 + y/3, 2 y/3 + x/3], y]
] &, {{0, 0}, {.5, √3/2}, {1, 0}, {0, 0}}, Input[]]
enter image description here
Bonus clip of varying the angle of middle piece
enter image description here
BBC BASIC, 179
REV 1
INPUTn
z=FNt(500,470,0,0,3^n/9)END
DEFFNt(x,y,i,j,a)
LINEx-36*a,y-21*a,x+36*a,y-a*21PLOT85,x,y+a*42IFa FORj=-1TO1FORi=-1TO1z=FNt(x+24*a*i,y+j*14*a*(i*i*3-2),i,j,-j*a/3)NEXTNEXT
=0
As before, but in black and white, in ungolfed (but streamlined) and golfed versions. Not a winner, despite the fact that doing it ths way avoids the need for a special treament for n=1.
INPUTn
REM call function and throw return value away to z
z=FNt(500,470,0,0,3^n/9)
END
REM x,y=centre of triangle. a=scale.
REM loop variables i,j are only passed in order to make them local, not global.
DEFFNt(x,y,i,j,a)
REM first draw a line at the bottom of the triangle. PLOT85 then draws a filled triangle,
REM using the specified point (top of the triangle) and the last two points visited (those used to draw the line.)
LINEx-36*a,y-21*a,x+36*a,y-21*a
PLOT85,x,y+42*a
REM if the absolute magnitude of a is sufficient to be truthy, recurse to the next level.
REM j determines if the triangle will be upright, inverted or (if j=0) infinitely small.
REM i loops through the three triangles of each orientation, from left to right.
IFa FORj=-1TO1 FORi=-1TO1:z=FNt(x+24*a*i,y+j*14*a*(i*i*3-2),i,j,-j*a/3):NEXT:NEXT
REM return 0
=0
enter image description here
REV 0
According to the OP's answer to @xnor, filled in snowflakes are OK. This answer was inspired by xnor's comment. The colours are just for fun and to show the way it is constructed. Take a triangle (magenta in this case) and overplot with 6 triangles 1/3 of the base.
INPUTn
z=FNt(500,470,n,1,0,0)
END
DEFFNt(x,y,n,o,i,a)
a=3^n/22
GCOLn
MOVEx-36*a,y-o*21*a
MOVEx+36*a,y-o*21*a
PLOT85,x,y+o*42*a
IFn>1FORi=-1TO1:z=FNt(x+24*a*i,y+14*a*(i*i*3-2),n-1,-1,i,a):z=FNt(x+24*a*i,y-14*a*(i*i*3-2),n-1,1,i,a)NEXT
=0
enter image description here
-
1\$\begingroup\$ I like how it looks like 7 of them merged together. \$\endgroup\$user10766– user107662014年11月06日 00:34:34 +00:00Commented Nov 6, 2014 at 0:34
-
\$\begingroup\$ @hosch250 Indeed, I seem to have "invented" a new fractal whose silhouette happens to be a Koch snowflake, and if you delete the magenta part you are left with 6 smaller Koch snowflakes. The golfed version will be just a plain black silhouette, but I will leave this image up, too. \$\endgroup\$Level River St– Level River St2014年11月06日 00:40:45 +00:00Commented Nov 6, 2014 at 0:40
-
\$\begingroup\$ Do you write it BBC Basic or BBC BASIC? I go for the latter but I don't know if it's correct... \$\endgroup\$Beta Decay– Beta Decay2014年11月07日 20:45:04 +00:00Commented Nov 7, 2014 at 20:45
-
2\$\begingroup\$ @BetaDecay BASIC is a backronym for Beginners' All-purpose Standard/Symbolic Instruction Code. The "Standard" bit is debatable as there are so many variants. en.wikipedia.org/wiki/BASIC. Most variants of BASIC prefer the capitalised version, but according to the Wikipedia page, Visual Basic prefers lowercase. I think BBC BASIC as shipped was uppercase. I'm using the version at bbcbasic.co.uk/bbcwin/bbcwin.html. It's uppercase in the website and IDE, So I'd say the uppercase version is more correct. But I don't think it matters much. \$\endgroup\$Level River St– Level River St2014年11月07日 21:19:48 +00:00Commented Nov 7, 2014 at 21:19
-
\$\begingroup\$ Ahh okay, I'll carry on with the uppercase version \$\endgroup\$Beta Decay– Beta Decay2014年11月07日 21:21:38 +00:00Commented Nov 7, 2014 at 21:21
Mathematica 72
Region@Line@AnglePath[Nest[Join@@({#,1,4,1}&/@#)&,{4,4,4},Input[]-1]π/3]
n=3
Thanks for alephalpha.
-
\$\begingroup\$ Nice job. Golf it by two characters, and you get the win! \$\endgroup\$user10766– user107662014年11月25日 16:24:44 +00:00Commented Nov 25, 2014 at 16:24
-
\$\begingroup\$ @Hosch250 Updated, Thank you. \$\endgroup\$chyanog– chyanog2015年04月22日 03:45:04 +00:00Commented Apr 22, 2015 at 3:45
-
\$\begingroup\$ You can use
AnglePathin Mathematica 10.1. \$\endgroup\$alephalpha– alephalpha2015年04月22日 03:45:06 +00:00Commented Apr 22, 2015 at 3:45 -
\$\begingroup\$ @chyaong
Graphics@Line@AnglePath[Nest[Join@@({-1,2,-1,#}&/@#)&,{2,2,2},Input[]-1]Pi/3]\$\endgroup\$alephalpha– alephalpha2015年04月22日 06:08:53 +00:00Commented Apr 22, 2015 at 6:08 -
1\$\begingroup\$ @alephalpha 73 chars:
ListLinePlot@AnglePath[Nest[Join@@({#,1,4,1}&/@#)&,{4,4,4},Input[]-1]π/3]\$\endgroup\$chyanog– chyanog2015年04月28日 07:32:15 +00:00Commented Apr 28, 2015 at 7:32
Python 3 - 139
Uses the turtle graphics library.
from turtle import*
b=int(input())
a=eval(("FR"*3)+".replace('F','FLFRFLF')"*~-b)
for j in a:fd(9/b*("G">j));rt(60*(2-3*("Q">j))*("K"<j))])
-
\$\begingroup\$ Cool. I like your string-based approach of finding the shape with no more than two lines of code! But can't you check for
"G">j,"Q"<jand usefd(9/b)to save 3 bytes? Furthermore you can avoid theifstatements multiplying, e.g.,("G">j)with the argument9/band put them all in one line behindfor. Oh! Then you can even combinertandltusing120*(...)-60*(...)\$\endgroup\$Falko– Falko2014年11月06日 05:19:58 +00:00Commented Nov 6, 2014 at 5:19 -
\$\begingroup\$ This appears to render the Koch snowflake input+1. An input of 1 should just be a triangle like the picture above shows. \$\endgroup\$user10766– user107662014年11月06日 05:33:57 +00:00Commented Nov 6, 2014 at 5:33
-
\$\begingroup\$ @hosch250 Edited \$\endgroup\$Beta Decay– Beta Decay2014年11月06日 07:07:12 +00:00Commented Nov 6, 2014 at 7:07
-
\$\begingroup\$ Now it doesn't draw anything, and an input of 1 creates a division by 0 error. \$\endgroup\$user10766– user107662014年11月06日 17:05:17 +00:00Commented Nov 6, 2014 at 17:05
-
\$\begingroup\$ instead of
(b-1)you can do*-~b\$\endgroup\$FryAmTheEggman– FryAmTheEggman2014年11月06日 20:38:23 +00:00Commented Nov 6, 2014 at 20:38
Python 3, 117 bytes
from turtle import*
ht();n=int(input())-1
for c in eval("'101'.join("*n+"'0'*4"+")"*n):rt(60+180*(c<'1'));fd(99/3**n)
Method:
- The solution uses Python's turtle graphics.
nisinput - 1- Starting from the string
0000we join its every character with101ntimes iteratively with the eval trick (thanks to @xnor for that). - For every character in the final string we turn 60 degrees right or 120 degrees left based on the character value (
1or0) and then move forward a length (99/3^n) which guarantees a similar size for alln's. - The last
0in the string will be useless but it just redraws the same line the first0draws.
Example output for input = 3:
koch
R: (削除) 240 (削除ここまで) 175
Because I trying to get my head around R, here's another version. There's likely to be lot better ways to do this and I'm happy to receive pointers. What I've done seems very convoluted.
n=readline();d=c(0,-120,-240);c=1;while(c<n){c=c+1;e=c();for(i in 1:length(d)){e=c(e,d[i],d[i]+60,d[i]-60,d[i])};d=e};f=pi/180;plot(cumsum(sin(d*f)),cumsum(cos(d*f)),type="l")
enter image description here
Wise fwom youw gwave...
I knew I'd want to try implementing this in Befunge-98 using TURT, but I couldn't figure out how to go about it and I sat on it for several months. Now, only recently, I figured out a way to do it without using self-modification! And so...
Befunge-98 with the TURT fingerprint, 103
;v;"TRUT"4(02-&:0\:01円P>:3+:4`!*;
>j$;space makes me cry;^
^>1-:01-\:0\:01-\:0
0>I@
^>6a*L
^>ca*R
^>fF
Let's get some implementation details out of the way first:
- I tested this using CCBI 2.1, whose implementation of TURT (the turtle graphics fingerprint) makes
I"print" the image to a SVG file. If you run this in CCBI without the command-argument--turt-line=PATH, it will come out as a file named CCBI_TURT.svg by default. This is the closest I could come to "print a graphical representation of the snowflake to the screen" with available Funge interpreters I could find. Maybe someday there will be a better interpreter out there that has a graphical display for the turtle, but for now... - There has to be a newline at the end for CCBI to run it without hanging (this is included with the character count). I know, right?
Basically, this works by using the stack as a sort of makeshift L-system and expanding it on the fly. On each pass, if the top number on the stack is:
- -2, then it prints and stops;
- -1, the turtle turns counterclockwise 60 degrees;
- 0, it turns clockwise 120 degrees;
- 1, it moves forward (by 15 pixels here, but you can change it by modifying the
fon the last line); - some number n that's 2 or greater, then it is expanded on the stack to
n-1, -1, n-1, 0, n-1, -1, n-1.
For n = 10, this process takes a very long time (a couple of minutes on my system), and the resulting SVG is ~10MB in size and invisible when viewed in the browser because you can't adjust the size of the brush using TURT. IrfanView seems to work decently if you have the right plugins. I'm not super familiar with SVG, so I don't know what the preferred method is for viewing those files (especially when they're really big).
Hey, at least it works - which, considering it's Befunge, is something to be thankful for on its own.
APL(Dyalog Extended), (削除) (削除ここまで)57 bytes SBCS
'A=↑1 +=⌽ ̄60 -=⌽60'⌂turtle'A' 'A-A++A-A'⌂lsys⍣⎕⊢'A++A++A'
APL has builtins for generation of fractal L-systems and drawing them using turtle graphics.
Requires Dyalog for Windows.
Python 2, 127 bytes
from turtle import *
def L(l,d=input()-1):
for x in[1,-2,1,0]:[L(l,d-1),rt(60*x)] if d>0 else fd(l)
for i in'lol':lt(120);L(9)
-
1\$\begingroup\$ Grats for having the 50,000th post on here. \$\endgroup\$AndrewTheCodegolfer– AndrewTheCodegolfer2019年12月30日 15:38:46 +00:00Commented Dec 30, 2019 at 15:38
n=7, you can't see the newly added triangles in the snowflake on a computer screen. Is any "best effort" here OK? Is there a minimum resolution for pixel-based solutions? \$\endgroup\$