js1k2014年作品不完整还原-Wolfenstein

js1k.com是全球性的JavaScript比赛。

其要求是整个程序(JavaScript)部分必须在1024字节内,即我们需要用1024个英文单词(包含符号)来完成整个程序。

哇,听起来就好有难度的有木有!好刺激啊!


在我们解析前呢,先来了解一些JavaScript的压缩方法。

1.把长的变量及函数名改为1个字母或2个字母的简易名称。

2.系统函数保存为一个短名称变量。

3.删除空格、不必要的分号及其他符号。

4.采用压缩算法。



我们来看看本章的主角吧!

Wolfenstein

作者对此作品的简介: 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);
            }
        }
    }
}

由于代码计算量太大,另外,为了压缩体积这段代码中使用了大量的……连体用法……咳咳……

有空会把他全部还原的。

如果您有什么建议或意见,请评论!~~~~

js1k2014年作品不完整还原-Wolfenstein,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。