Squished tetris

Geschrieben von am .

Nachtrag 2024: Zwischenzeitlich wurde die sigvec-API aus der Glibc entfernt. Die Originalversion lässt sich daher nicht mehr compilieren. Meine beiden Versionen hab ich auf die sigaction-API umgestellt.

Vor 20 Jahren gewann das Ofbuscated tetris von John Tromp den International Obfuscated C Code Contest in der Sparte Best Game. Ein komplettes Spiel (mit High-Score) auf einer halben A4-Seite: das hat mich damals sehr beeindruckt.

So sieht das Original aus:

long h[4];t(){h[3]-=h[3]/3000;setitimer(0,h,0);}c,d,l,v[]={(int)t,0,2},w,s,I,K
=0,i=276,j,k,q[276],Q[276],*n=q,*m,x=17,f[]={7,-13,-12,1,8,-11,-12,-1,9,-1,1,
12,3,-13,-12,-1,12,-1,11,1,15,-1,13,1,18,-1,1,2,0,-12,-1,11,1,-12,1,13,10,-12,
1,12,11,-12,-1,1,2,-12,-1,12,13,-12,12,13,14,-11,-1,1,4,-13,-12,12,16,-11,-12,
12,17,-13,1,-1,5,-12,12,11,6,-12,12,24};u(){for(i=11;++i<264;)if((k=q[i])-Q[i]
){Q[i]=k;if(i-++I||i%12<1)printf("\\033[%d;%dH",(I=i)/12,i%12*2+28);printf(
"\\033[%dm  "+(K-k?0:5),k);K=k;}Q[263]=c=getchar();}G(b){for(i=4;i--;)if(q[i?b+
n[i]:b])return 0;return 1;}g(b){for(i=4;i--;q[i?x+n[i]:x]=b);}main(C,V,a)char*
*V,*a;{h[3]=1000000/(l=C>1?atoi(V[1]):2);for(a=C>2?V[2]:"jkl pq";i;i--)*n++=i<
25||i%12<2?7:0;srand(getpid());system("stty cbreak -echo stop u");sigvec(14,v,
0);t();puts("\\033[H\\033[J");for(n=f+rand()%7*4;;g(7),u(),g(0)){if(c<0){if(G(x+
12))x+=12;else{g(7);++w;for(j=0;j<252;j=12*(j/12+1))for(;q[++j];)if(j%12==10){
for(;j%12;q[j--]=0);u();for(;--j;q[j+12]=q[j]);u();}n=f+rand()%7*4;G(x=17)||(c
=a[5]);}}if(c==*a)G(--x)||++x;if(c==a[1])n=f+4**(m=n),G(x)||(n=m);if(c==a[2])G
(++x)||--x;if(c==a[3])for(;G(x+12);++w)x+=12;if(c==a[4]||c==a[5]){s=sigblock(
8192);printf("\\033[H\\033[J\\033[0m%d\\n",w);if(c==a[5])break;for(j=264;j--;Q[j]=
0);while(getchar()-a[4]);puts("\\033[H\\033[J\\033[7m");sigsetmask(s);}}d=popen(
"stty -cbreak echo stop \\023;sort -mnr -o HI - HI;cat HI","w");fprintf(d,
"%4d from level %1d by %s\\n",w,l,getlogin());pclose(d);}

Download: ofbuscated_tetris.c (1467 byte)

Übersetzt (deaktivierte Warnungen) und gestartet wird es so:

> cc -w -o tetris ofbuscated_tetris.c
> ./tetris

Refurbished tetris:

Zum zwanzigsten Jahrestag habe ich mir das Programm noch einmal angeschaut.

Mindeststandard ist heute die Aktivierung der Warnungen des C-Compilers, doch ein Übersetzungsversuch mit

> cc -Wall -Werror -Wextra -o tetris ofbuscated_tetris.c

scheitert kläglich mit 56 Fehlermeldungen (gcc 4.6.3).

So hab ich mir den Spaß gemacht und das Original überarbeitet.

Die Includes und die struct-Typen lassen sich nicht einfach obfuszieren, der Rest aber sieht hoffentlich eben so grauslich aus wie beim Original. Und obwohl es größer geworden ist, passt es immer hoch auf eine halbe A4-Seite:

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
struct itimerval h;int c,l,w,s,I,K=0,i=276,j,k,q[276],Q[276],*n=q,*m,x=17,f[]={7
,-13,-12,1,8,-11,-12,-1,9,-1,1,12,3,-13,-12,-1,12,-1,11,1,15,-1,13,1,18,-1,1,2,0
,-12,-1,11,1,-12,1,13,10,-12,1,12,11,-12,-1,1,2,-12,-1,12,13,-12,12,13,14,-11,-1
,1,4,-13,-12,12,16,-11,-12,12,17,-13,1,-1,5,-12,12,11,6,-12,12,24};FILE*d;void t
(){h.it_value.tv_usec-=h.it_value.tv_usec/3000;setitimer(0,&h,0);}void u(){for(i
=11;++i<264;)if((k=q[i])-Q[i]){Q[i]=k;if(i-++I||i%12<1)printf("\033[%d;%dH",(I=i
)/12,i%12*2+28);printf(&"\033[%dm  "[K-k?0:5],k);K=k;}Q[263]=c=getchar();}int G(
int b){for(i=4;i--;)if(q[i?b+n[i]:b])return 0;;return 1;}void g(int b){for(i=4;i
--;q[i?x+n[i]:x]=b);}int main(int C,char**V){char*a=C>2?V[2]:"jkl pq";h.it_value
.tv_usec=1000000/(l=C>1?atoi(V[1]):2);system("stty cbreak -echo stop u");for(;i;
i--){*n++=i<25||i%12<2?7:0;}srand(getpid());struct sigaction v={0};v.sa_handler=
t;sigaction(SIGALRM,&v,0);puts("\033[H\033[J");t();for(n=f+rand()%7*4;;g(7),u(),
g(0)){if(c<0){if(G(x+12))x+=12;else{g(7);++w;for(j=0;j<252;j=12*(j/12+1))for(;q[
++j];)if(j%12==10){for(;j%12;q[j--]=0){}u();for(;--j;q[j+12]=q[j]);u();}n=f+rand
()%7*4;if(!G(x=17))c=a[5];}}if(c==*a&&!G(--x)){++x;}if(c==a[1])n=f+4**(m=n),(G(x
)||(n=m));if(c==a[2]&&!G(++x)){--x;}if(c==a[3])for(;G(x+12);++w)x+=12;if(c==a[4]
||c==a[5]){printf("\033[H\033[J\033[0m%d\n",w);if(c==a[5])break;for(j=264;j--;Q[
j]=0);while(a[4]!=getchar()){}puts("\033[H\033[J\033[7m");}}d=popen("touch HI;s"
"ort -mnr -o HI - HI;head HI","w");fprintf(d,"%4d from level %1d by %s\n",w,l,
getlogin());pclose(d);system("stty sane");return 0;}

Download: refurbished_tetris.c (1691 Bytes).

Übersetzt (mit aktivierten Warnungen) und gestartet wird es so:

> cc -Wall -Werror -Wextra -o tetris refurbished_tetris.c
> ./tetris

Außerdem gibt es die entobfuzierte und ein wenig kommentierte Version commented_tetris.c (6472 Bytes).