Yahoo! Logo ASCII Animation in 462 bytes of C
Last week I put together another obfuscated C program and have been urged by my coworkers to post it publicly. I've made some refinements since posting it to our internal list, so here is the final version (to those who had seen it already: it's one line shorter now, and the angles are less screwy, and the animation is 2 seconds instead of 3). Go ahead, try it:
$ cat >yanim.c
c,p,i,j,n,F=40,k,m;float a,x,y,S=0,V=0;main(){for(;F--;usleep(50000),F?puts(
"\x1b[25A"):0)for(S+=V+=(1-S)/10-V/4,j=0;j<72;j+=3,putchar(10))for(i=0;x=S*(
i-27),i++<73;putchar(c[" ''\".$u$"]))for(c=0,n=3;n--;)for(y=S*(j+n-36),k=0,c
^=(136*x*x+84*y*y<92033)<<n,p=6,m=0;m<8;k++["<[\\]O=IKNAL;KNRbF8EbGEROQ@BSX"
"XtG!#t3!^"]/1.16-68>x*cos(a)+y*sin(a)?k=p,p="<AFJPTX"[m++]-50:k==p?c^=1<<n,
m=8:0)a=(k["O:85!fI,wfO8!yZfO8!f*hXK3&fO;:O;#hP;\"i[by asloane"]-79)/14.64;}
^D
$ gcc -o yanim yanim.c -lm
[warnings which real programmers ignore]
$ ./yanim
[you'll see - show the animation]
...uuuu$$$$$uuuu... $$$$$$$uuuuuu
..u$$$$$$$$$$$$$$$$$$$$$$$u.. $$$$$$$$$$$$'
.u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u. $$$$$$$$$$$$
.$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$. $$$$$$$$$$$"
.$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$. $$$$$$$$$$$
u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u $$$$$$$$$$$
.$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$. $$$$$$$$$$'
$$$$$$$$$$$$$u. uu$$$$$''''''''''''''$$$$$$$ $$$$$$$$$$
$$$$$$$$$$$$$$$$. $$$$$$.. ..$$$$$$$$$ $$$$$$$$$"
$$$$$$$$$$$$$$$$$u "$$$$$$"' u$$$$$$$$$$$$$ $$$$$$$$$
u$$$$$$$$$$$$$$$$$$$ '$$$"' u$$$$$$$$$$$$$$$u $$$$$$$$$
$$$$$$$$$$$$$$$$$$$$$. '"' u$$$$$$$$$$$$$$$$$$ $$$$$$$$
$$$$$$$$$$$$$$$$$$$$$u .u$$$$$$$$$$$$$$$$$$$ $$$$$$$$
$$$$$$$$$$$$$$$$$$$$$$u u$$$$$$$$$$$$$$$$$$$$$ $$$$$$$"
'$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$' $$$$$$$
"$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$" ""$$$$$
'$$$$$$$$$$$$$$$""""" """""$$$$$$$$$$$$$$'
"$$$$$$$$$$$$$................$$$$$$$$$$$$" ..
'"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"' $$$$$$$u
'"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"' $$$$$$$'
'""$$$$$$$$$$$$$$$$$$$$$$$$$""' .$$$$$$$
''"""$$$$$$$$$$$$$"""'' '"""""$$
'''''
It's a 20fps, antialiased ASCII art animation of the Yahoo! logo. If you want to figure out how it works on your own, you're welcome to. Otherwise, read on.
I encourage you to play with the constants in the code: S+=V+=(1-S)/10-V/5 is the underdamped control system for the animation -- S is scale (=1/zoom), V is velocity, and 1/10 and 1/5 are the PD constants. S=0 corresponds to infinite zoom on the first frame. S<0 is funny. F is the frame counter. The 1.16 controls the scale of the polygon rendering (68 is an approximation of 79/1.16 so you have to adjust that too), and 136/84/92033 define the ellipse. The 14.64 is not a tunable parameter, though (it's 46/π, and for a good reason).
The antialiasing is simple: each character consists of three vertically-arranged samples and an 8-character lookup table for each arrangement of three on/off pixels. Each frame consists of 73x24 characters, or 73x72 pixels. The 73 horizontal choice was somewhat arbitrary; I suppose I could have gone up to 79.
The logo is rendered as an ellipse and eight convex polygons using a fairly neat method (I thought) with sub-pixel precision and no frame buffer. It required some design tradeoffs to fit into two printable-character arrays, but it's much less code than rendering triangles to a framebuffer, which is the typical way polygon rasterization is done.
To produce this, first I had to vectorize the "Y!" logo. I did this by taking some measurements of a reference image and writing coordinates down on graph paper. Then I wrote a utility program which takes the points and polygon definitions and turns them into angles and offsets as defined below. [I put the generator code on pastebin until I get can some code highlighting stuff set up for my blog].
The ellipse is fairly standard high-school math: x2/a2 + y2/b2 < 1. Each point is tested and if it's inside the ellipse, the pixel is plotted. (136x2 + 84y2 < 92033 was a trivial rearrangement of terms with a and b being the radii of the two axes of the ellipse measured from my source image, scaled to the pixel grid).
Each polygon is made up of a set of separating half-planes (a half-plane being all points on one side of an infinitely long line). If a given point is "inside" all of the half-planes, it's inside the polygon (which only works as long as the polygon is convex) and the pixel is toggled with the XOR operator ^ (thus it handles the "inverse" part inside the ellipse as well as the uninverted exclamation mark without any special cases). Each side of a polygon is defined by the equation ax + by > c. To represent both a and b I use an angle θ so that a = cos(θ) and b = sin(θ) and quantize the angle in π/46 increments — my angles are thus represented from -π to +π as ASCII 33 to 125 — '!' to '}' — with 'O' (ASCII 79) as zero. Then I solve for c, also quantized in scaled increments from -47 to +47, so that the midpoint of the side is considered inside the polygon.
Here's an extremely crude diagram: (I'm writing this on a plane and none of my drawing programs are working. Sorry.)

The shaded area is ax + by < c, implying it's outside the polygon, and the dashed line is ax + by = c.
(a,b) form a vector orthogonal to the line segment they represent pointing towards the inside of the polygon, so we can get them directly from the points defining the line segment by taking the vector defining the side — (x1 - x0, y1 - y0) — and rotating it 90 degrees, resulting in (a, b) = (y1 - y0, x0 - x1). Then we normalize (a, b) as the actual magnitude doesn't matter, but it will be 1 when we decode the angle and we can compensate with our choice of c later (if ax+by>c, then sax+sby>sc for some scale s>0). Then compute θ = atan2(a,b), quantize to one of our 94 angles, and get our new (a,b) = (cos(θ), sin(θ)).
c is easy to get by directly substituting any of the points making up the line on the side of the polygon into c = ax+by. I use the midpoint of the line segment on the side, (xt, yt) = ((x0 +x1)/2, (y0 + y1)/2), because the angle of the side can be slightly off after we quantize θ, and this evens the errors out across the length of the side.
You'll notice on the first couple frames (you can pause with ^S, resume with ^Q -- xon/xoff) that the bottom section of the 'Y' has little bites taken out of it due to the quantization error in the separating half-plane equations.
It could probably be made somewhat more efficient CPU-wise by careful reordering of the separating plane arrays so that most of the drawing area is rejected first. I didn't get to that in my generator code.
The animation is done by the <ESC>[25A sequence — it moves the cursor up 25 lines in just about any terminal emulation mode. I technically only need to move up 24 lines, but puts is shorter than printf and it implicitly adds a newline. If your terminal isn't at least 26 lines high, though, it does funky things to your scrollback. And usleep is there to limit it to 20fps, which is the only non-ANSI Cism about it.
And then I shrunk the code down by arranging it into clever for loops and taking unorthodox advantage of commas, conditionals, and globals being ints by default in C (which is all par for the course in obfuscated C code). And that pretty much reveals all the secrets as to how it was done.
It would be fairly easy to enhance this with a different movement sequence, or rotation (or any kind of 3D transform, as it's basically just ray-tracing the logo). I just animated the scale to prove the point that it was being rendered dynamically and not just a compressed logo, and kept the animation short and sweet.
I apologize in advance for the various sign errors I'm sure to have made when typing this up, but you get the idea.
Yahoo! Logo ASCII Animation in 462 bytes of C的更多相关文章
- booting logo & booting animation
開機第一張圖片: 圖片位置: linux_repo/vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo 因為 project 選用 ...
- 【C语言编程学习笔记】利用462字节代码实现雅虎logo ACSII 动画!
ACSII 动画演示: 不过本文介绍的是另一个作品:c 代码实现雅虎 logo ACSII 动图. 运行后,你将会看到: 它是一个 20fps.抗锯齿的 Yahoo! logo ASCII 动 ...
- 异常空格,ASCII (194,160)问题
今天运营的同学反映有一些店铺的名称后面带空格,我下意识的说不可能啊,我已经处理过了啊.然后就找出来看. 其中有个店铺的名称是“安踏 ”,第一眼看上去好像是带了个空格.然后我就仔细的看了下. pry(m ...
- 二进制;16进制; Byte , Python的bytes类; Base64数据编码; Bae64模块;
参考:中文维基 二进制 位操作(wiki) Byte字节 互联网数据处理:Base64数据编码 Python的模块Base64 16进制简介 python: bytes对象 字符集介绍:ascii 二 ...
- Python3中的bytes和str类型
Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示.Python 3不会以任意隐式的方式混用str和b ...
- Transact-SQL 数据类型转换
Syntax Syntax for CAST: CAST ( expression AS data_type [ ( length ) ] ) Syntax for CONVERT: CO ...
- python基础知识(四)
摘要:主要涉及lambda表达式.python内置函数(open文件重点).冒泡排序 一.lambda表达式 适用于创建简单函数,也叫匿名函数, 函数名 = lambda 参数 : 返回值 funct ...
- Python3使用urllib访问网页
介绍 改教程翻译自python官网的一篇文档. urllib.request是一个用于访问URL(统一资源定位符)的Python模块.它以urlopen函数的形式提供了一个非常简单的接口,可以访问使用 ...
- 初始python第三天(三)
全局变量与局部变量 1.什么是全局变量 在globals中的变量,都是全局变量,全局变量的作用域就是整个程序 NAME = 'alex' def global_test(): name = 'alex ...
随机推荐
- CSS3 过渡transition 认识
其实,我一直觉得自己对新知识是以一种抵触的情绪在学习的.因为我总是习惯于将事情想得很复杂,所以也错过了很多美好的东西. 以前觉得CSS3的知识应该是很难的,很难理解的.但是我发现我觉得知识点很难,是因 ...
- php的传值和传址
有些情况下,可能希望在函数体内对参数的修改在函数体外也能反映; 使用引用传递参数要在参数前加上&符号; 例子: <?php $a=5; function show(&$a){ ...
- 在Ubuntu Linux下安装Code::Blocks和Eclipse CDT
最近小白由于有工作学习的需要,要尝试在Linux下进行C++编程.所以特地花了一点时间研究一下Linux下的C++的IDE.最后我尝试了使用Code::Blocks和Eclipse两个著 ...
- 浅谈JAVA集合框架(转载)_常用的Vector和HashMap
原作者滴着:http://www.cnblogs.com/eflylab/archive/2007/01/20/625237.html Java提供了数种持有对象的方式,包括语言内置的Array,还有 ...
- sgu 101 domino
题意还算简洁明了,加上有道翻译凑过着读完了题.题意大体上是 给你 n 个多米诺骨牌, 给出每个骨牌两端的数字, 只有数字相同才可以推到, 比如 2-3和3-2.你可以旋转这些多米诺骨牌, 输出一个可以 ...
- thinkphp autoload 命名空间自定义 namespace
使用thinkPHP过程中,一些自定义的类库和第三方类库需要找一个合适的位置放置,放到系统默认的org文件夹感觉不太好,破坏了thinkPHP的原生目录. 就看了一下官方手册,可以在模块或者应用的配置 ...
- RX学习笔记:在FreeCodeCamp的学习
FreeCodeCamp https://www.freecodecamp.com 2016-07-03 前几日在Github浏览时,偶然看到一个叫FreeCodeCamp的开源项目,进去该网站之后感 ...
- Android开发系列之Android项目的目录结构
今天开始正式学习Android开发的种种细节,首先从最基本的概念和操作学起. 首先看一下Android项目的目录结构. 这是我随便建立的一个test项目,我们重点关注一下几个方面的内容: 1.src目 ...
- NHibernate多对多关联映射的实现
上次用EF演示了数据库多对多关系的操作,这次我们还是引用上次的案例,来演示如何在C#当中使用NHibernate. 首先介绍一下NHibernate框架的来源.熟悉Java编程的读者肯定知道Hiber ...
- .Net 中资源的使用方式
近期要在小丸工具箱中添加一个启动画面,画面中需要使用一个GIF动图.经过学习和实验,总结了几个读取资源的方式,罗列如下. 一.使用外部资源 Image img = Image.FromFile(&qu ...