js1k2014年作品不完整还原-Wolfenstein
js1k.com是全球性的JavaScript比赛。
其要求是整个程序(JavaScript)部分必须在1024字节内,即我们需要用1024个英文单词(包含符号)来完成整个程序。
哇,听起来就好有难度的有木有!好刺激啊!
在我们解析前呢,先来了解一些JavaScript的压缩方法。
1.把长的变量及函数名改为1个字母或2个字母的简易名称。
2.系统函数保存为一个短名称变量。
3.删除空格、不必要的分号及其他符号。
4.采用压缩算法。
我们来看看本章的主角吧!
作者对此作品的简介: 2K的德军总部2D演示。您可以使用方向键来行走。该演示展现了如何用程序来生成纹理及地图,还有碰撞检测和门的动画。
东西挺多的嘛~(哎!?不对!!!2K?唔~我想起来了,js1k今年认为放大一倍大小限制可能会有更多优秀作品来的)
哇哦,是不是很酷!
我们来看看作者"Reinder Nijhoff"提供的源代码吧!
for(_=‘&&Cn[@-t$=[#h,`2,_-1^),Z,57,_._^]ZYImageData(X],WW[Vh=UI(T)*n+(eS++)R)ZQ=function(e,t,n){returnPP A[e.which]=O[f,oVN(N3_30W4737096=0;for(var ;s25664*(Math.abs(,D(min(vZmQ);if(s==[s])},0,.516random())/@4])[1][0] n-F(e $ ,e$)),@l++]=B(>s;sR&255(A[h+2]-A[h])*qM(M(2928815,.9+.*sin((3+o/)/(f/80^.3)^/4QQ,E([(v-m)*y,(m+v)*yVe=a.widt`t=a.height,n=(k=c.createXe,t)).data,r#Wi#WA#WK#36,36Wu=L=1,BP(t>>S>>)1-n)<<|(t*S*)1-n)*|(tS)1-nI=onkeydownO1,1>e?e>0?e:0:1},D=onkeyupOTn-e+1)*Te$+1EP D(e ,t ,n )*D(e,t,nFP sqrt(e*e+t*tGP T4JP T1^*MP e,e,2*T+*@5]@6]T(t -n -T(@2]$ )-@6]T(t-n-T(@3]$))QE(t,n,[@2W@3]])qP e,e,1+.2t $)/F(3$ ,3$QG(t,[3,3W1.)setInterval(function(){q=-u+(u=new Date//2ZU37,L+=,h++,ci=sin(LZco=cos(L)2K-=i[K -(1-s)*ci*|(K-s*co*)<<8]>1?0:(ci-s*ci+s*co)*;o#Wae>a;aR{f=2*a/e^,f#f*co/4+ci/4,co/4-f*ci/4Wl=255,UF(f ,fZd2>d;dR{var v=f[dWm=K[d]-~~K[dWg=1/v;0<v?m=1-m:g=-g;y=g*m,s2o=K+f*y;for(0>vCo[d]--;y<l;){if((H=i[o |o<<8])>1){s3i[o |o^+s<<8]==1CdC(H=4);l=y,p=(o +o)&63)+*d+128*H)}H==1C(w=F(x=(o -K +)/f *f,o -K +)/h)Cw<lC(j=x-T3-F(o -K ,o-K))+K-~~o)>0C(l=w,p=*j|0+128))2o+=f*g;y+=g}}var b=l/e,f=$*b/_l=4*a,d=4*e-4tM=1<f)?0>f?3684408:73688:r[321+f)|0+pWf+=bM>>M>>8M255,l+=d}c.putXk,032)*A=x=s,y=s>>8,l=.9<?3:_i=xCy?x%8?.7<C4!=y%8?l:0:4==y%8?1:l:l6b2>b;bRo>o;oRf>f;fR{l=o+1&15,p=f+1+(o+1>>4<<4)&31,U125006759873,l/+.1*);if(2>p||2>l)U;v=f-3_m=o-3UM(`[p,lV1,1,31,15,_.3_1]3)p#13,min(9-pow(5f/-Z2Z9)Wl=sin(.4*f+2.7Zd#51,55+lWy=->v?-.7:.7,U``.2ZE([f-_o-2Wp,dQ328987,777215_4Q3,3Q777215,G12QJ11QJ9^,^V1,4]-4._4.2V1,6.]^,^V4,1]4._^V6.,4.2]Q.8+.2*lZE([f,oWp,d)4)l#32-vZoWUl,[^,^,28,,_.4,^]Zl,[6,6,23YE(N29,0V35,]QUq(`[l %2_l%28]Z`E(l,[6,6V24,57])1)UN^,,66,_.4,^]ZN6,6,57YUq(`[f%8,o%8]Z`E(N6,6V57,57]));r[*f+o+*b+2*s)]=`b/3)}‘;g=/[-N-Z^-`#$@C]/.exec(_);)with(_.split(g))_=join(shift());eval(_)Oh my god! 这是什么鬼东西!?
别着急……我们来慢慢分析一下……
由于Js1k比赛中已经提供了一些内置内容。
我们先来看看比赛中都提供了哪些内容呢:
<!-- 哦,我们需要的是一个全屏应用程序,吼吼 --> <style> html, body { margin: 0; padding: 0; border: 0; width: 100%; height: 100%; overflow:hidden;} #c { display: block; } /* kill scrollbars from hell */ </style> <!-- 嗯,提供了一个名为c的画布 --> <canvas id="c"></canvas> <!-- 哇哦,No bad!好多兼容代码呢。 --> <script> var a = document.getElementsByTagName(‘canvas‘)[0]; var b = document.body; var d = function (e) { return function () { e.parentNode.removeChild(e); }; }(a); // unprefix some popular vendor prefixed things (but stick to their original name) var AudioContext = window.AudioContext || window.webkitAudioContext; var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || function (f) { setTimeout(f, 1000 / 30); }; // fix bug in safari: http://qfox.nl/weblog/218 document.body.clientWidth; // auto resize (original) canvas. call `onresize(w,h) to limit the size of the canvas (window.onorientationchange = window.onresize = function (a) { var mw = Infinity; var mh = Infinity; var min = Math.min; return function (w, h) { if (arguments.length === 2) { mw = w; mh = h; } a.style.width = (a.width = min(mw, innerWidth)) + ‘px‘; a.style.height = (a.height = min(mh, innerHeight)) + ‘px‘; }; }(a))(); var c = a.getContext(‘2d‘); </script>嗯,比赛内置的东西就只有上面这些了。
还是比较好理解的(最重要的是这些代码没有被混淆压缩……)。
嗯……以上那些……嗯……都不是重点……咳咳……
我们来解压一下本章主角的代码吧!
解压方法:用Chrome浏览器在任何页面中按下F12,转到控制台。把前面的压缩代码复制一下,然后把最后的eval改写成console.log。按下回车。
嘿嘿,解压了吧。但是这个时候的代码还是很乱的,没关系!我们百度一个在线JavaScript美化工具,放进去美化一下。结果如下:
e = a.width, t = a.height, n = (k = c.createImageData(e, t)).data, r = [], i = [], A = [], K = [36, 36.5], u = L = 1, B = function (e, t, n) { return (t >> 16) * n + (e >> 16) * (1 - n) << 16 | (t & 255 * 256) * n + (e & 255 * 256) * (1 - n) & 255 * 256 | (t & 255) * n + (e & 255) * (1 - n) }, I = onkeydown = function (e, t, n) { return A[e.which] = 1, 1 > e ? e > 0 ? e : 0 : 1 }, D = onkeyup = function (e, t, n) { return A[e.which] = 0, I(n - e + 1) * I(e - t + 1) }, E = function (e, t, n) { return D(e[0], t[0], n[0]) * D(e[1], t[1], n[1]) }, F = function (e, t, n) { return Math.sqrt(e * e + t * t) }, G = function (e, t, n) { return I(4 * (n - F(e[0] - t[0], e[1] - t[1]))) }, J = function (e, t, n) { return I(1 - 1.5 * Math.abs(n - F(e[0] - t[0], e[1] - t[1]))) }, M = function (e, t, n) { return B(e, B(0, e, 2 * I(.5 + .5 * n[5] * (n[6] * (I((t[0] - n[0]) / n[4]) - I((n[2] - t[0]) / n[4])) - n[6] * (I((t[1] - n[1]) / n[4]) - I((n[3] - t[1]) / n[4]))))), E(t, n, [n[2], n[3]])) }, q = function (e, t, n) { return B(e, B(0, e, 1 + .2 * (t[0] - t[1]) / F(3.5 - t[0], 3.5 - t[1])), G(t, [3.5, 3.5], 1.64)) }, setInterval(function () { q = -u + (u = new Date / 256 / 2), h = 37, L += (A[h + 2] - A[h]) * q, h++, ci = Math.sin(L), co = Math.cos(L); for (var s = 0; 2 > s; s++) K[s] -= i[K[0] - (1 - s) * ci * (A[h + 2] - A[h]) * q & 255 | (K[1] - s * co * (A[h + 2] - A[h]) * q & 255) << 8] > 1 ? 0 : (ci - s * ci + s * co) * (A[h + 2] - A[h]) * q; for (var o = [], a = 0; e > a; a++) { for (var f = 2 * a / e - 1, f = [f * co / 4 + ci / 4, co / 4 - f * ci / 4], l = 255, h = F(f[0], f[1]), d = 0; 2 > d; d++) { var v = f[d], m = K[d] - ~~K[d], g = 1 / v; 0 < v ? m = 1 - m : g = -g; for (var y = g * m, s = 0; 2 > s; s++) o[s] = K[s] + f[s] * y; for (0 > v && o[d]--; y < l;) { if ((H = i[o[0] | o[1] << 8]) > 1) { for (var s = 0; 3 > s; s++) i[o[0] | o[1] - 1 + s << 8] == 1 && d && (H = 4); l = y, p = 64 * ((64 * (o[0] + o[1]) & 63) + 64 * d + 128 * H) } H == 1 && (w = F(x = (o[0] - K[0] + .5) / f[0] * f[1], o[0] - K[0] + .5) / h) && w < l && (j = x - I(3 - F(o[0] - K[0], o[1] - K[1])) + K[1] - ~~o[1]) > 0 && (l = w, p = 64 * (64 * j | 0 + 128)); for (var s = 0; 2 > s; s++) o[s] += f[s] * g; y += g } } var b = l / e, f = -t * b / 2, l = 4 * a, d = 4 * e - 4; for (var s = 0; t > s; s++) M = 1 < Math.abs(f) ? 0 > f ? 3684408 : 7368816 : r[32 * (1 + f) | 0 + p], f += b, n[l++] = M >> 16 & 255, n[l++] = M >> 8 & 255, n[l++] = M & 255, n[l++] = 255, l += d } c.putImageData(k, 0, 0) }, 32); for (var s = 0; 256 * 256 > s; s++) A[s] = 0, x = s & 255, y = s >> 8, l = .9 < Math.random() ? 3 : 2, i[s] = x & 255 && y & 255 ? x % 8 ? .7 < Math.random() && 4 != y % 8 ? l : 0 : 4 == y % 8 ? 1 : l : l; for (var s = 0; 6 > s; s++) for (var b = 0; 2 > b; b++) for (var o = 0; 64 > o; o++) for (var f = 0; 64 > f; f++) { l = o + 1 & 15, p = f + 1 + (o + 1 >> 4 << 4) & 31, h = B(12500670, 5987163, l / 16 + .1 * Math.random()); if (2 > p || 2 > l) h = 4737096; v = f - 32, m = o - 30, h = M(h, [p, l], [1, 1, 31.5, 15, 2, .32, 1]); if (s == 3) p = [13, Math.min(9 - Math.pow(5 * (f / 64 - .5), 2), 9)], l = Math.sin(.4 * f + 2.7), d = [51, 55 + l], y = -.5 > v ? -.7 : .7, h = B(B(h, B(h, 0, .2), E([f - 2, o - 2], p, d)), B(0, B(B(B(B(B(B(B(B(B(16328987, 16777215, D(Math.min(Math.abs(v), Math.abs(m)), 2, 4)), 4737096, D(Math.min(Math.abs(v), Math.abs(m)), 3, 3)), 16777215, G([f, o], [32, 30], 12.5)), 0, J([f, o], [32, 30], 11)), 0, J([f, o], [32, 30], 9)), 4737096, E([(v - m) * y, (m + v) * y], [-1, -1], [1, 4])), 4737096, E([(v - m) * y, (m + v) * y], [-4.2, 4.2], [1, 6.16])), 4737096, E([(v - m) * y, (m + v) * y], [-1, -1], [4, 1])), 4737096, E([(v - m) * y, (m + v) * y], [4.2, -1], [6.16, 4.2])), .8 + .2 * l), E([f, o], p, d)); if (s == 4) l = [32 - Math.abs(v), o], h = B(M(M(B(0, 2928815, .9 + .16 * Math.sin((3.5 + o / 16) / (f / 80 - 1.3) - 1 / 4)), l, [-1, -1, 28, 64, 2, .4, -1]), l, [6, 6, 23, 57, 2, .2, -1]), 0, E([f, o], [29, 0], [35, 64])), h = B(q(h, [l[0] % 22, l[1] % 28]), h, E(l, [6, 6], [24, 57])); if (s == 1) h = M(M(B(0, 2928815, .9 + .16 * Math.sin((3.5 + o / 16) / (f / 80 - 1.3) - 1 / 4)), [f, o], [-1, 0, 64, 66, 2, .4, -1]), [f, o], [6, 6, 57, 57, 2, .2, -1]), h = B(q(h, [f % 8, o % 8]), h, E([f, o], [6, 6], [57, 57])); r[64 * f + o + 16 * 256 * (b + 2 * s)] = B(h, 0, b / 3) }根据本文最前面所说的压缩方法,你可以意识到这段代码是经过压缩的。下面我们根据程序的意思来翻译成最原始的代码吧!
额……还原过程中发现了作者有一个地方没有压缩呢。。。他用了很多次Math.random(),其实可以这样来进一步压缩:
r=Math.random; r();咳咳,这里仅仅是吐槽。
下面直接发还原后的代码咯。
// 画布宽度 var canvasWidth = a.width; // 画布高度 var canvasHeight = a.height; // 图像数据对象 var imageData = c.createImageData(canvasWidth, canvasHeight); // 像素数组 var pixs = imageData.data; // 颜色列表 var colors = { // 天空 sky: 0x383838, // 地板 floor: 0x707070, // 墙面基色 metopeBase: 0x484848, // 墙面深色 metopeDark: 0x5B5B5B, // 墙面浅色 metopeLight: 0xBEBEBE, // 门基色 doorBase: 0x2CB0AF, // 旗帜基色 flagBase: 0xF9291B, // 旗帜白 flagWhite: 0xFFFFFF, // 旗帜灰 flagGray: 0x484848 }; r = []; i = []; A = []; K = [36, 36.5]; u = L = 1; function B(e, t, n) { return (t >> 16) * n + (e >> 16) * (1 - n) << 16 | (t & 255 * 256) * n + (e & 255 * 256) * (1 - n) & 255 * 256 | (t & 255) * n + (e & 255) * (1 - n) } function I(e, t, n) { return A[e.which] = 1, 1 > e ? e > 0 ? e : 0 : 1 } window.onkeydown = I; function D(e, t, n) { return A[e.which] = 0, I(n - e + 1) * I(e - t + 1) } window.onkeyup = D; function E(e, t, n) { return D(e[0], t[0], n[0]) * D(e[1], t[1], n[1]); } function F(e, t, n) { return Math.sqrt(e * e + t * t); } function G(e, t, n) { return I(4 * (n - F(e[0] - t[0], e[1] - t[1]))); } function J(e, t, n) { return I(1 - 1.5 * Math.abs(n - F(e[0] - t[0], e[1] - t[1]))); } function M(e, t, n) { return B(e, B(0, e, 2 * I(.5 + .5 * n[5] * (n[6] * (I((t[0] - n[0]) / n[4]) - I((n[2] - t[0]) / n[4])) - n[6] * (I((t[1] - n[1]) / n[4]) - I((n[3] - t[1]) / n[4]))))), E(t, n, [n[2], n[3]])); } function q(e, t, n) { return B(e, B(0, e, 1 + .2 * (t[0] - t[1]) / F(3.5 - t[0], 3.5 - t[1])), G(t, [3.5, 3.5], 1.64)); } setInterval(function () { q = -u + (u = new Date / 256 / 2), h = 37, L += (A[h + 2] - A[h]) * q, h++, ci = Math.sin(L), co = Math.cos(L); for (var s = 0; 2 > s; s++) { K[s] -= i[K[0] - (1 - s) * ci * (A[h + 2] - A[h]) * q & 255 | (K[1] - s * co * (A[h + 2] - A[h]) * q & 255) << 8] > 1 ? 0 : (ci - s * ci + s * co) * (A[h + 2] - A[h]) * q; } for (var o = [], a = 0; canvasWidth > a; a++) { for (var f = 2 * a / canvasWidth - 1, f = [f * co / 4 + ci / 4, co / 4 - f * ci / 4], l = 255, h = F(f[0], f[1]), d = 0; 2 > d; d++) { var v = f[d], m = K[d] - ~~K[d], g = 1 / v; 0 < v ? m = 1 - m : g = -g; for (var y = g * m, s = 0; 2 > s; s++) { o[s] = K[s] + f[s] * y; } for (0 > v && o[d]--; y < l;) { if ((H = i[o[0] | o[1] << 8]) > 1) { for (var s = 0; 3 > s; s++) { i[o[0] | o[1] - 1 + s << 8] == 1 && d && (H = 4); } l = y, p = 64 * ((64 * (o[0] + o[1]) & 63) + 64 * d + 128 * H) } H == 1 && (w = F(x = (o[0] - K[0] + .5) / f[0] * f[1], o[0] - K[0] + .5) / h) && w < l && (j = x - I(3 - F(o[0] - K[0], o[1] - K[1])) + K[1] - ~~o[1]) > 0 && (l = w, p = 64 * (64 * j | 0 + 128)); for (var s = 0; 2 > s; s++) { o[s] += f[s] * g; } y += g } } var b = l / canvasWidth, f = -canvasHeight * b / 2, l = 4 * a, d = 4 * canvasWidth - 4; // 颜色的十进制值 var colorNum; for (var s = canvasHeight; s--;) { if (Math.abs(f) > 1) { if (0 > f) { // 设置颜色为天空 colorNum = colors.sky; } else { // 设置颜色为地板 colorNum = colors.floor; } } else { colorNum = r[32 * (1 + f) | 0 + p]; } // Red pixs[l++] = colorNum >> 16 & 255; // Green pixs[l++] = colorNum >> 8 & 255; // Blue pixs[l++] = colorNum & 255; // Alpha pixs[l++] = 255; f += b; l += d; } } c.putImageData(imageData, 0, 0); }, 32); for (var s = 0; 256 * 256 > s; s++) { // 设置可以动范围 A[s] = 0; x = s & 255; y = s >> 8; l = .9 < Math.random() ? 3 : 2; i[s] = x & 255 && y & 255 ? x % 8 ? .7 < Math.random() && 4 != y % 8 ? l : 0 : 4 == y % 8 ? 1 : l : l; } for (var s = 0; 6 > s; s++) { for (var b = 0; 2 > b; b++) { for (var o = 0; 64 > o; o++) { for (var f = 0; 64 > f; f++) { l = o + 1 & 15; p = f + 1 + (o + 1 >> 4 << 4) & 31; // 使用墙面样式 h = B(colors.metopeLight, colors.metopeDark, l / 16 + .1 * Math.random()); if (2 > p || 2 > l) { // 设置颜色为墙面基色 h = colors.metopeBase; } v = f - 32, m = o - 30, h = M(h, [p, l], [1, 1, 31.5, 15, 2, .32, 1]); if (s == 3) { // 使用旗帜样式 p = [13, Math.min(9 - Math.pow(5 * (f / 64 - .5), 2), 9)]; l = Math.sin(.4 * f + 2.7); d = [51, 55 + l]; y = -.5 > v ? -.7 : .7; h = B(B(h, B(h, 0, .2), E([f - 2, o - 2], p, d)), B(0, B(B(B(B(B(B(B(B(B(colors.flagBase, colors.flagWhite, D(Math.min(Math.abs(v), Math.abs(m)), 2, 4)), colors.flagGray, D(Math.min(Math.abs(v), Math.abs(m)), 3, 3)), colors.flagWhite, G([f, o], [32, 30], 12.5)), 0, J([f, o], [32, 30], 11)), 0, J([f, o], [32, 30], 9)), colors.flagGray, E([(v - m) * y, (m + v) * y], [-1, -1], [1, 4])), colors.flagGray, E([(v - m) * y, (m + v) * y], [-4.2, 4.2], [1, 6.16])), colors.flagGray, E([(v - m) * y, (m + v) * y], [-1, -1], [4, 1])), colors.flagGray, E([(v - m) * y, (m + v) * y], [4.2, -1], [6.16, 4.2])), .8 + .2 * l), E([f, o], p, d)); } if (s == 4) { // 使用门边栏样式 l = [32 - Math.abs(v), o]; h = B(M(M(B(0, colors.doorBase, .9 + .16 * Math.sin((3.5 + o / 16) / (f / 80 - 1.3) - 1 / 4)), l, [-1, -1, 28, 64, 2, .4, -1]), l, [6, 6, 23, 57, 2, .2, -1]), 0, E([f, o], [29, 0], [35, 64])); h = B(q(h, [l[0] % 22, l[1] % 28]), h, E(l, [6, 6], [24, 57])); } if (s == 1) { // 使用门样式 h = M(M(B(0, colors.doorBase, .9 + .16 * Math.sin((3.5 + o / 16) / (f / 80 - 1.3) - 1 / 4)), [f, o], [-1, 0, 64, 66, 2, .4, -1]), [f, o], [6, 6, 57, 57, 2, .2, -1]); h = B(q(h, [f % 8, o % 8]), h, E([f, o], [6, 6], [57, 57])); } r[64 * f + o + 16 * 256 * (b + 2 * s)] = B(h, 0, b / 3); } } } }
由于代码计算量太大,另外,为了压缩体积这段代码中使用了大量的……连体用法……咳咳……
有空会把他全部还原的。
如果您有什么建议或意见,请评论!~~~~
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。