ASCII Art of the Day #2 - Flow Snakes
Python 2, 428 411 388 bytes
This one was pretty tricky. The patterns don't retain their ratios after each step meaning its very difficult to procedurally produce an image from its predecessor. What this code does, though its pretty unreadable after some intense math golfing, is actually draw the line from start to finish using the recursively defined D
function.
The size was also an issue, and I ended up just starting in the middle of a 5*3**n
sided square and cropping things afterward, though if I can think of better way to calculate the size I might change it.
n=input();s=5*3**n
r=[s*[" "]for i in[0]*s]
def D(n,x,y,t=0):
if n<1:
x-=t%2<1;y+=t%3>1;r[y][x]='_/\\'[t/2]
if t<2:r[y][x+2*t-1]='_'
return[-1,2,0,1,0,1][t]+x,y-(2<t<5)
for c in[int(i)^t%2for i in"424050035512124224003"[t/2::3]][::(t^1)-t]:x,y=D(n-1,x,y,c)
return x,y
D(n,s/2,s/2)
S=[''.join(c).rstrip()for c in r]
for l in[c[min(c.find('\\')%s for c in S):]for c in S if c]:print l
JavaScript (ES6), 356 362 370
That's a difficult one ...
Each shape is stored as a path. There are 6 basic building blocks (3 + 3 backward)
0
diagonal up left to bottom right (4
backward)1
diagonal bottom left to up right (5
backward)2
horizontal left to right (6
backward)
For each one, there is a replacing step to be applied when increasing order:
0
-->0645001
(backward4
-->5441024
)1
-->2116501
(backward5
-->5412556
)2
-->2160224
(backward6
-->0664256
)
values prefilled in theh
array, even if the elements 4..6 can be obtained from 0..2 using
;[...h[n]].reverse().map(x=>x^4).join('')
To obtain the shape for the given order, the path is built in the p variable applying the substitutions repeatedly. Then the main loop iterates on the p variable and draw the shape inside the g[] array, where each element is a row.
Starting at position (0,0), each index can become negative (y index at high orders). I avoid negative y indexes shifting all the g array whenever I find a negative y value. I don't care if the x index becomes negative, as in JS negative indexes are allowed, just a little more difficult to manage.
In the last step, I scan the main array using .map, but for each row I need to use an explicit for(;;) loop using the b
variable that holds the least x index reached (that will be < 0).
In the console.log
version there is a handy leading newline, that can be easily made a trailing newline swapping 2 rows, as in the snippet version.
f=o=>{
g=[],x=y=b=0,
h='064500192116501921602249954410249541255690664256'.split(9);
for(p=h[2];--o;)p=p.replace(/./g,c=>h[c]);
for(t of p)
z='\\/_'[s=t&3],
d=s-(s<1),
t>3&&(x-=d,y+=s<2),
y<0&&(y++,g=[,...g]),r=g[y]=g[y]||[],
s?s>1?r[x]=r[x+1]=z:r[x]=z:r[x-1]=z,
t<3&&(x+=d,y-=s<2),
x<b?b=x:0;
g.map(r=>
{
o+='\n';
for(x=b;x<r.length;)o+=r[x++]||' '
},o='');
console.log(o)
}
Handy snippet to test (in Firefox) :
f=o=>{
g=[],x=y=b=0,
h='064500192116501921602249954410249541255690664256'.split(9);
for(p=h[2];--o;)p=p.replace(/./g,c=>h[c]);
for(t of p)
z='\\/_'[s=t&3],
d=s-(s<1),
t>3&&(x-=d,y+=s<2),
y<0&&(y++,g=[,...g]),r=g[y]=g[y]||[],
s?s>1?r[x]=r[x+1]=z:r[x]=z:r[x-1]=z,
t<3&&(x+=d,y-=s<2),
x<b?b=x:0;
g.map(r=>
{
for(x=b;x<r.length;)o+=r[x++]||' ';
o+='\n'
},o='');
return o
}
// TEST
fs=9;
O.style.fontSize=fs+'px'
function zoom(d) {
d += fs;
if (d > 1 && d < 40)
fs=d, O.style.fontSize=d+'px'
}
#O {
font-size: 9px;
line-height: 1em;
}
<input id=I value=3><button onclick='O.innerHTML=f(I.value)'>-></button>
<button onclick="zoom(2)">Zoom +</button><button onclick="zoom(-2)">Zoom -</button>
<br>
<pre id=O></pre>
Haskell, 265 bytes
(?)=div
(%)=mod
t[a,b]=[3*a+b,2*b-a]
_#[0,0]=0
0#_=3
n#p=[352,6497,2466,-1]!!((n-1)#t[(s+3)?7|s<-p])?(4^p!!0%7)%4
0&_=0
n&p=(n-1)&t p+maximum(abs<$>sum p:p)
n!b=n&[1,-b]
f n=putStr$unlines[["__ \\/ "!!(2*n#t[a?2,-b]+a%2)|a<-[b-n!2+1..b+n!2+0^n?3]]|b<-[-n!0..n!0]]
(Note: on GHC before 7.10, you will need to add import Control.Applicative
or replace abs<$>
with map abs$
.)
Run online at Ideone.com
f n :: Int -> IO ()
draws the level n
flowsnake. The drawing is computed in bitmap order rather than along the curve, which allows the algorithm to run in O(n) space (that is, logarithmic in the drawing size). Nearly half of my bytes are spent computing which rectangle to draw!