Koch Snowflake - codegolf
Python, 650 612 594 574 characters
n='\n'
S='_a/G\F I\n'
A=dict(zip(S,('III',' ','__/',' G','\ ','F__',' ','III','')))
B=dict(zip(S,('III',' ','\ ',' aF','/a ',' G',' ','III','')))
C=dict(zip(S,('___','aaa','/ ','GII','II\\',' F',' ','III','')))
def T(s):
a=b=c=d=r=u''
for k in s:
a+=A[k];b+=B[k];c+=C[k]
if k=='I':a=a[:-3]+('II\\'if'a '==d[1:3]else'GII'if' a'==d[:2]else 3*k)
d=d[3:]
if k==n:d=c.replace('____','__/F').replace('aaaa','aa ').replace('/ a','/a ').replace('a F',' aF');r+=a+n+b+n+d+n;a=b=c=''
return r
print T(T(T('__\n\G\n'))).translate({97:95,71:47,73:32,70:92})
This works by expanding the triangle by a factor of 3 each time. To do that, we need to keep track of whether each symbol is a left or right boundary (e.g. how /
is expanded depends on which side of the /
is the inside). We use different symbols for the two possible cases, as follows:
_: _, outside on the top
a: _, outside on the bottom
/: /, outside on the left
G: /, outside on the right
\: \, outside on the left
F: \, outside on the right
<space>: inside
I: outside
The d
variable handles the special case where the expansion of an a
needs to extend into the 3x3 in the next row.
MS-DOS 16 bit machine code: 199 bytes
Decode using this site, save as 'koch.com' file and execute from WinXP command prompt.
sCAAxo7ajsKLz/OquF9fulwvvUoBM9u+BADoiQDodgDocwDogADobQDoagDodwCK8TLSs0+I98cHDQrGRwIktAnNIf7GOO5+7MNWAVwBYwFsAXoBgwGJB4DDAsOIN/7D6QQA/suIF/7P6R0A/suAPyB1AogH/suIB8OBw/8AiDfpBgD+x4gX/sM4734Ciu84z30Cis/Dg8UIg8UCgf1WAXLzg+0Mw07/dgB0GV/o9v/o5v/o8P/o3f/o2v/o5//o1//o4f9Gww==
Update
Here's an easy-to-read assembler version:
; L-System Description
;
; Alphabet : F
; Constants : +, -
; Axiom : F++F++F
; Production rules: F -> F-F++F-F
;
; Register usage:
; _ _
; bp = direction: 0 = ->, 1 = /|, 2 = |\, 3 = <-, 4 = |/_, 5 = _\|
; cl = min y, ch = max y
; bl = x (unsigned)
; bh = y (signed)
; si = max level
; clear data
mov al,20h
add dh,al
mov ds,dx
mov es,dx
mov cx,di
rep stosb
mov ax,'__'
mov dx,'/\'
; initialise variables
mov bp,Direction0
xor bx,bx
mov si,4
call MoveForward
call TurnRight
call TurnRight
call MoveForward
call TurnRight
call TurnRight
call MoveForward
mov dh,cl
xor dl,dl
mov bl,79
OutputLoop:
mov bh,dh
mov w [bx],0a0dh
mov b [bx+2],24h
mov ah,9
int 21h
inc dh
cmp dh,ch
jle OutputLoop
ret
Direction0:
dw MoveRight
dw MoveUpRight
dw MoveUpLeft
dw MoveLeft
dw MoveDownLeft
dw MoveDownRight
Direction6:
MoveRight:
mov w [bx],ax
add bl,2
ret
MoveUpRight:
mov b [bx],dh
inc bl
jmp DecBHCheckY
MoveUpLeft:
dec bl
mov b [bx],dl
DecBHCheckY:
dec bh
jmp CheckY
MoveLeft:
dec bl
cmp b [bx],20h
jne MoveLeftAgain
mov [bx],al
MoveLeftAgain:
dec bl
mov [bx],al
ret
MoveDownLeft:
add bx,255
mov b [bx],dh
jmp CheckY
MoveDownRight:
inc bh
mov b [bx],dl
inc bl
CheckY:
cmp bh,ch
jle NoMaxChange
mov ch,bh
NoMaxChange:
cmp bh,cl
jge NoMinChange
mov cl,bh
NoMinChange:
ret
TurnRight:
add bp,8
TurnLeft:
add bp,2
cmp bp,Direction6
jb ret
sub bp,12
ret
MoveForward:
dec si
push [bp]
jz DontRecurse
pop di
call MoveForward
call TurnLeft
call MoveForward
call TurnRight
call TurnRight
call MoveForward
call TurnLeft
call MoveForward
DontRecurse:
inc si
ret
Perl, 176 175 bytes
Posting this as a separate answer because it uses a binary source file, which is perhaps a bit cheaty. But considering that it’s still Perl source code, I think it’s remarkable that it beats the MS-DOS machine code solution!
Source as base64-encoded
JF89IsLApwag0dhnMmAmMEcGIAcGQNHYwsDRFLsQ0djCwKcGoNHYwsDRFDdbECYwcRUxe1DCwNEUuxDR2
CI7c14uXiR4PW9yZCQmOyQieCgkeD4+MykucXcoXCAvXyBfXy8gXC8gX18gX1wgLyBfXy9cX18pWyR4Jj
ddXmVnO3NeLnsyN31eJF89cmV2ZXJzZSQmO3l+L1xcflxcL347cHJpbnQkJi4kXy4kL15lZw==
Somewhat more readable
Replace all instances of /<[0-9a-f]+>/
with the relevant binary data:
# Raw data!
$_="<c2c0a706a0d1d86732602630470620070640d1d8c2c0d114bb10d1d8c2>".
"<c0a706a0d1d8c2c0d114375b1026307115317b50c2c0d114bb10d1d8>";
# Decode left half of the snowflake (without newlines)
s^.^$x=ord$&;$"x($x>>3).qw(\ /_ __/ \/ __ _\ / __/\__)[$x&7]^eg;
# Reconstruct the right half and the newlines
s^.{27}^$_=reverse$&;y~/\\~\\/~;print$&.$_.$/^eg
In this version, the snowflake is encoded in the following way:
The 8 bits in each byte are divided like this:
+---+---+---+---+---+---+---+---+ | 5 bits | 3 bits | +---+---+---+---+---+---+---+---+ R C
R
encodes a run of spaces. The longest run is 27 characters, so all runs fit into 5 bits.C
encodes a sequence of characters which are simply looked up in the literal array. (I used to have slightly crazier encodings here where the array contained only/ \ _
, but the Perl code necessary to decode it was longer...)I am lucky that the binary data does not contain any
"
/'
or\
that would need escaping. I didn’t plan for this. But even if it did, I probably could have just changed the order of the items in the array to fix that.It is amazing how simple this solution is compared to the tens of other solutions I went through before I came up with this. I experimented with many different bitwise encodings more complex than this one, and it never occurred to me that a simpler one might be worth it simply because the Perl code to decode it would be shorter. I also tried to compress repetitions in the data using variable interpolation (see the other answer), but with the newest version that doesn’t gain any characters anymore.