-
-
Save williame/263bf661f0d0ba173c44 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
versions = [version.strip() for version in ( | |
""" | |
def t(b): | |
L=len;w,n=L(b[0])+3,-1;b=list("@"*w+"@@".join(b)+"@"*w);w+=n;I=b.index | |
for i in range(L(b)): | |
c=b[i];d={"^":-w,"<":n,">":1,"v":w}.get(c) | |
if d: | |
while c!='@': | |
i+=d;c=b[i] | |
if c=='*':b[i]='.' | |
elif c in "123456789":i+=I(c)-i or I(c,i+1)-i | |
elif c in '/\\':d={-w:n,w:1,1:w,n:-w}[d]*(-1 if c=='/' else 1) | |
return "*" not in b | |
""", | |
""" | |
def t(b): | |
L=len;w=L(b[0])+3;b=list("@"*w+"@@".join(b)+"@"*w);w-=1;I=b.index | |
for i in range(L(b)): | |
c=b[i];d={"^":-w,"<":-1,">":1,"v":w}.get(c) | |
if d: | |
while c!='@': | |
i+=d;c=b[i] | |
if c=='*':b[i]='.' | |
elif c in "123456789":i+=I(c)-i or I(c,i+1)-i | |
elif c in '/\\':d={-w:-1,w:1,1:w,-1:-w}[d]*(-1 if c=='/' else 1) | |
return "*" not in b | |
""", | |
""" | |
def t(b): | |
L=len;w=L(b[0])+3;b=list("@"*w+"@@".join(b)+"@"*w);w-=1;I=b.index | |
for i in range(L(b)): | |
c=b[i];d={"^":-w,"<":-1,">":1,"v":w}.get(c) | |
if d: | |
while c!='@': | |
i+=d;c=b[i] | |
if c=='*':b[i]='.' | |
elif c in '/\\':d={-w:-1,w:1,1:w,-1:-w}[d]*(-1 if c=='/' else 1) | |
elif c>'0':i+=I(c)-i or I(c,i+1)-i | |
return "*" not in b | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+2;B=list('@'*w+'@@'.join(b)+'@'*w);l=len(B);C="<>v^";D=[-1,1,w,-w];i=0 | |
while i<l: | |
d=C.find(B[i]) | |
if-1<d: | |
j=i;n=l*4 | |
while('@'!=B[j])*n: | |
c=B[j] | |
if'+'>c:B[j]='' | |
if'/'==c:d=(d+2)%4 | |
if'\\'==c:d=3-d | |
if c.isdigit():j=(B*2).index(c,j+1)%l | |
j+=D[d];n-=1 | |
i+=1 | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+2;B=list('@'*w+'@@'.join(b)+'@'*w);l=len(B);i=0 | |
while i<l: | |
d="<>v^".find(B[i]) | |
if-1<d: | |
j=i;n=l*4 | |
while(B[j]!='@')*n: | |
c=B[j] | |
if'+'>c:B[j]='' | |
if'/'==c:d=(d+2)%4 | |
if'\\'==c:d=3-d | |
if c.isdigit():j=(B*2).index(c,j+1)%l | |
j+=[-1,1,w,-w][d];n-=1 | |
i+=1 | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+2;B=list('@'*w+'@@'.join(b)+'@'*w);l=len(B);i=0 | |
while i<l: | |
d="<>v^".find(B[i]) | |
if-1<d: | |
j=i;c='.' | |
while c not in"@<>v^": | |
if'+'>c:B[j]='' | |
if'/'==c:d^=2 | |
if'\\'==c:d^=3 | |
elif'0'<c:j=(B*2).index(c,j+1)%l | |
j+=[-1,1,w,-w][d];c=B[j] | |
i+=1 | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+2;B=list('@'*w+'@@'.join(b)+'@'*w);l=len(B);i=0 | |
while i<l: | |
d="<>v^".find(B[i]);j=i;c='.' | |
while c not in"@<>v^": | |
if'+'>c:B[j]='' | |
if'/'==c:d^=2 | |
if'\\'==c:d^=3 | |
elif'0'<c:j=(B*2).index(c,j+1)%l | |
j+=[-1,1,w,-w,-i][d];c=B[j] | |
i+=1 | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+1;B=list('@'*w+'@'.join(b)+'@'*w);l=len(B);i=0 | |
while i<l: | |
d="<>v^".find(B[i]);j=i;c='.' | |
while c not in"@<>v^": | |
if'+'>c:B[j]='' | |
if'/'==c:d^=2 | |
if'\\'==c:d^=3 | |
elif'0'<c:j=(B*2).index(c,j+1)%l | |
j+=[-1,1,w,-w,-j][d];c=B[j] | |
i+=1 | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+1;B=list('@'*w+'@'.join(b));i=l=len(B);C="<>^v@" | |
while i: | |
j=l-i;i-=1;d=C.find(B[j]);c='.' | |
while c not in C: | |
if'+'>c:B[j]='.' | |
if'0'<c<C:j=(B*2).index(c,j+1)%l | |
elif'.'<c:d^=2+(c<C) | |
j-=[1,-1,w,-w,j][d];c=B[j%l] | |
return'*'not in B | |
""", | |
""" | |
def t(b): | |
w=len(b[0])+1;B=list('@'*w+'@'.join(b));i=l=len(B);C="<>^v@" | |
while i: | |
i-=1;d,j,c=C.find(B[i]),i,'.' | |
while(c in C)-1: | |
if'+'>c:B[j]='.' | |
if'0'<c<C:j=(B*2).index(c,j+1)%l | |
elif'.'<c:d^=2+(c<C) | |
j-=[1,-1,w,-w,j][d];c=B[j%l] | |
return('*'in B)-1 | |
""")] | |
width = max(len(line) for version in versions for line in version.split("\n")) | |
height = max(len(version.split("\n")) for version in versions) | |
import difflib | |
from PIL import Image, ImageFont, ImageDraw, ImageChops, GifImagePlugin | |
font = ImageFont.truetype("/Library/Fonts/Courier New.ttf", 15) | |
em, lineheight = 9, 14 | |
anim_frames = 1 | |
def render(text, ofs, diff, diff_ch, frames): | |
for frame in range(anim_frames if ofs is not None else 1): | |
image = Image.new("RGB", (width * em + int(em * 1.5), height * lineheight + int(lineheight/2)), "white") | |
frames.append(image) | |
draw = ImageDraw.Draw(image) | |
x, y = 0, 0 | |
for i, ch in enumerate(text): | |
if ch == '\n': | |
x = 0 | |
y += lineheight | |
else: | |
if i == ofs: | |
draw.rectangle((x, y, x + em, y + lineheight), | |
fill='red' if diff=='+' else 'blue') | |
scale = 1.0 / 3 * frame | |
if diff == '-': | |
scale = 1.0 - scale | |
draw.text((x, y), ch, font=font, | |
fill='yellow') | |
draw.rectangle((x + em, y, x + em + em, y + lineheight), | |
fill='white') | |
x += int(round(float(em) * scale)) | |
draw.text((x, y), ch, font=font, fill=0) | |
x += em | |
del draw | |
frames = [] | |
render(versions[0], None, None, None, frames) | |
prev = versions[0] | |
for i in range(3, len(versions)): | |
curr = versions[i] | |
print "==== %d (%d %d) ====" % (i, len(curr), len(prev)-len(curr)) | |
adjust = 0 | |
for ofs, diff in enumerate(difflib.ndiff(prev, curr)): | |
diff, ch = diff[0], diff[-1] | |
if diff in "+-": | |
render(prev, ofs-adjust, diff, ch, frames) | |
if diff == "+": | |
prev = prev[:ofs-adjust] + ch + prev[ofs-adjust:] | |
else: | |
assert prev[ofs-adjust] == ch, (ofs, prev[:ofs+1], ch) | |
prev = prev[:ofs-adjust] + prev[ofs-adjust+1:] | |
adjust += 1 | |
assert prev == curr | |
render(versions[-1], None, None, None, frames) | |
with open("anim.gif", "wb") as f: | |
prev = None | |
for frame in frames: | |
frame = frame.convert('P', palette=Image.WEB) | |
if not prev: | |
for s in GifImagePlugin.getheader(frame)[0]: | |
f.write(s) | |
prev = frame.copy() | |
frame = GifImagePlugin.getdata(frame) | |
else: | |
delta = ImageChops.subtract_modulo(frame, prev) | |
prev = frame.copy() | |
bbox = delta.getbbox() | |
if bbox: | |
frame = GifImagePlugin.getdata(frame.crop(bbox), offset = bbox[:2]) | |
else: | |
continue | |
for s in frame: | |
f.write(s) | |
f.write(";") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment