¿Qué programarías en 4096 caracteres de código en C?

Éste es el ¿absurdo? reto que propone cada año el International Obfuscated C Code Contest (IOCCC), en un intento de picar a programadores de todo el mundo hacia el extremo de la programación más enrevesada e imposible de entender. 

De entre los ganadores de 2013 me ha llamado mucho la atención una auténtica obra maestra: un emulador completo de 8086 capaz de ejecutar, sobre MSDOS, AutoCAD, Windows 3.0, etc. Mejor ver algunos screenshots:

AutoCAD

AutoCAD

screenshot_flightsim4

Flight Simulator

screenshot_lotus123

Lotus 123

Como dice su autor, “en tan sólo 4043 bytes (8086 nibbles, 28,301 bits), el código se las apaña para implementar casi todo el hardware de un IBM-PC de la era de 1980, usando unos pocos bits menos de código que transitores en la CPU 8086 original”.

screenshot_qbasic

QBASIC

screenshot_simcity

Simcity

Para los programadores más jóvenes, es necesario recordar qué era el 8086. Fue el primer procesador de Intel que realmente se popularizó, gracias al primer PC introducido por IBM en 1980/81. Su arquitectura interna era mucho más compleja e ineficaz que la del Motorola 68000, pero no siempre lo mejor acaba triunfando en el mercado…

La cuestión es que la microarquitectura del 8086 es una pesadilla, y mucho más para emularlo en tan poco código. La codificación de instrucciones es compleja e irregular en tamaño y estructura, con múltiples modos de direccionamiento y sin un posicionado consistente de operandos. Y por supuesto, el esperpéntico invento de la memoria segmentada. Además, el 8086 tiene una serie de bugs (por ejemplo, PUSH SP) y de características arcaicas que deben emularse para que los programas antiguos sigan funcionando.

screenshot_win3_on_macosx

Windows 3.0

En total se emulan todos estos dispositivos, que conforman un auténtico viaje al pasado: 

  • CPU Intel 8086/186
  • 1MB de RAM
  • 8072A 3.5″ floppy disk controller (1.44MB/720KB)
  • Contrlador de disco duro (hasta 528MB)
  • Tarjeta gráfica Hercules, gráficos 720×348 de 2 colores, 64KB de video RAM y suporte de modo texto CGA 80×25 a 16 colores.
  • 8253 programmable interval timer (PIT).
  • 8259 programmable interrupt controller (PIC).
  • Controlador de teclado 8042, con teclado de 83 teclas tipo XT.
  • Reloj de tiempo real MC146818.
  • PC speaker.

Como librería gráfica, el programa emplea SDL. Y aquí, el código fuente, por supuesto, ininteligible:

#include "SDL.h"
#define $ for(O=9
#define CX M+=(T%3+2*!(!T*t-6))
#define x ,A=4*!T,O=t,W=h=T<3?u(Q?p:D(A+3),D(A),D(A+1)[i]+D(A+2)*g+):K(t),U=V=K(a),o?U=h,W=V:V,
#define C 8*-~L
#define Z short
#define y a(Z)Y[++O]
#define B ),a--||(
#define _ ),e--||(
#define V(I,D,E)(O=a(I)h[r])&&!(A=(D)(V=(1[E+L]<<16)+*i)/O,A-(I)A)?1[E+L]=V-O*(*E=A):H(0)
#define i(B,M)B(o){return M;}
#define R(O,M,_)(S=L?a(I Z)O:O,N=L?a(I Z)O M(f=a(I Z)_):(O M(f=a(I n)_)))
#define T(_)R(r[u(10,L=4,--)],=,_)
#define u(a,r,T)16*i[a]+(I Z)(T i[r])
#define a(_)*(_*)&
#define L(_)M(W,_,U)
#define M(S,F,T)R(r[S],F,r[T])
#define A(_)(i[L=4]+=2,R(_,=,r[u(10,4,-2+)]))
#define c(R,T)(1[u=19,L+T]=(N=a(R)h[r]*(R)*T)>>16,*i=N,G(F(N-(R)N)))
#define h(_)(1&(L?a(Z)_:_)>>C-1)
#define I unsigned
#define n char
#define e(_)v(F(40[L(_##=40[E]+),E]&N==S|_ N<_(int)S))
I n t,e,l[80186],*E,m,u,L,a,T,o,r[1<<21],X,*Y,b,Q=0,R=0;I Z*i,M,p,q=3;I*localtime(),f,S,kb=0,h,W,U,c,g,d,V,A;N,O,P=983040,j[5];SDL_Surface*k=0;i(K,P+(L?2*o:2*o+o/4&7))i(D,r[a(I)E[259+4*o]+O])i(w,i[o]+=~(-2*47[E])*~L)i(v,(z1)f^=S^N)&16),G(N-S&&1&(40[E]^f>>C-1))J(){V=61442;$;O--;)V+=40[E+O]<<D(25);}i(H,(46[u=76,J(),T(V),T(9[i]),T(M),M(P+18,=,4*o+2),R(M,=,r[4*o]),E]=0))s(o){$;O--;)40[E+O]=1&&1<<D(25)&o;}i(BP,(*i+=262*o*z(F2)*E&15)>9|42[E],*E&=15))i(SP,(w(7),R&&--1[i]&&o?R++,Q&&Q++,M--:0))DX(){$,O*=27840;O--;)O[(I*)k->pixels]=-!!(1<<7-O%8&r[O/2880*90+O%720/8+(88+952[l]/128*4+O/720%4<<13)]);SDL_Flip(k);}main(BX,nE)n**nE;{9[i=E=r+P]=P>>4;$;q;)j[--q]=*++nE?open(*nE,32898):0;read(2[a(I)*i=*j?lseek(*j,0,2)>>9:0,j],E+(M=256),P);$;Y=r+16*9[i]+M,Y-r;Q|R||kb&46[E]&&KB)--64[T=1[O=32[L=(X=*Y&7)&1,o=X/2&1,l]=0,t=(c=y)&7,a=c/8&7,Y]>>6,g=~-T?y:(n)y,d=BX=y,l],!T*t-6&&T-2?T-1?d=g:0:(d=y),Q&&Q--,R&&R--x(O=*Y,O=u=D(51),e=D(8),m=D(14)_ O=*Y/2&7,M+=(n)c*(L^(D(m)[E]|D(22)[E]|D(23)[E]^D(24)[E]))_ L=*Y&8,R(K(X)[r],=,c)_ L=e+=3,o=0,a=X x a=m _ T(X[i])_ A(X[i])_ a<2?M(U,+=1-2*a+,P+24),v(f=1),G(S+1-a==1<<C-1),u=u&4?19:57:a-6?CX+2,a-3||T(9[i]),a&2&&T(M),a&1&&M(P+18,=,U+2),R(M,=,U[r]),u=67:T(h[r])_(W=U B u=m,M-=~L,R(W[r],&,d)B 0 B L(=~)B L(=-),S=0,u=22,F(N>S)B L?c(I Z,i):c(I/**/n,E)B L?c(Z,i):c(n,E)B L?V(I Z,I,i):V(I n,I Z,E)B L?V(Z,int,i):V(n,Z,E))_++e,h=P,d=c,T=3,a=m,M--_++e,13[W=h,i]=(o|=!L)?(n)d:d,U=P+26,M-=~!o,u=17+(m=a)_(a=m B L(+=),F(N<S)B L(|=)B e(+)B e(-)B L(&=)B L(-=),F(N>S)B L(^=)B L(-),F(N>S)B L(=))_!L?L=a+=8 x L(=):!o?Q=1,R(r[p=m x V],=,h):A(h[r])_ T=a=0,t=6,g=c x M(U,=,W)_(A=h(h[r]),V=m?++M,(n)g:o?31&2[E]:1)&&(a<4?V%=a/2+C,R(A,=,h[r]):0,a&1?R(h[r],>>=,V):R(h[r],<<=,V),a>3?u=19:0,a<5?0:F(S>>V-1&1)B R(h[r],+=,A>>C-V),G(h(N)^F(N&1))B A&=(1<<V)-1,R(h[r],+=,A<<C-V),G(h(N*2)^F(h(N)))B R(h[r],+=(40[E]<<V-1)+,A>>1+C-V),G(h(N)^F(A&1<<C-V))B R(h[r],+=(40[E]<<C-V)+,A<<1+C-V),F(A&1<<V-1),G(h(N)^h(N*2))B G(h(N)^F(h(S<<V-1)))B G(h(S))B 0 B V<C||F(A),G(0),R(h[r],+=,A*=~3)1<<C)-1>>V)_(V=!!--1[a=X,i]B V&=!m[E]B V&=m[E]B 0 B V=!++1[i]),M+=V*(n)c _ M+=3-o,L?0:o?9[M=0,i]=BX:T(M),M+=o*L?(n)c:c _ M(U,&,W)_ L=e+=8,W=P,U=K(X)_!R||1[i]?M(m<2?u(8,7,):P,=,m&1?P:u(Q?p:11,6,)),m&1||w(6),m&2||SP(1):0 _!R||1[i]?M(m?P:u(Q?p:11,6,),-,u(8,7,)),43[u=92,E]=!N,F(N>S),m||w(6),SP(!N==b):0 _ o=L,A(M),m&&A(9[i]),m&2?s(A(V)):o||(4[i]+=c)_ R(U[r],=,d)_ 986[l]^=9,R(*E,=,l[m?2[i]:(n)c])_ R(l[m?2[i]:(n)c],=,*E)_ R=2,b=L,Q&&Q++_ W-U?L(^=),M(U,^=,W),L(^=):0 _ T(m[i])_ A(m[i])_ Q=2,p=m,R&&R++_ L=0,O=*E,F(D(m+=3*42[E]+6*40[E])),z(D(1+m)),N=*E=D(m-1)_ N=BP(m-1)_ 1[E]=-h(*E)_ 2[i]=-h(*i)_ 9[T(9[i]),T(M+5),i]=BX,M=c _ J(),T(V)_ s(A(V))_ J(),s4)V&~m)+1[E])_ J(),1[E]=V _ L=o=1 x L(=),M(P+m,=,h+2)_++M,H(3)_ M+=2,H(c&m)_++M,m[E]&&H(4)_(c&=m)?1[E]=*E/c,N=*E%=c:H(0)_*i=N=m&E[L=0]+c*1[E]_*E=-m[E]_*E=r[u(Q?p:m,3,*E+)]_ m[E]^=1 _ E[m/2]=m&1 _ R(*E,&,c)_(a=c B write(1,E,1)B time(j+3),memcpy(r+u(8,3,),localtime(j+3),m,a<2?*E=~lseek(O=4[E][j],a(I)5[i]<<9,0)?(a?write:read)(O,r+u(8,3,),*i):0:0),O=u,D(16)?v(0):D(17)&&G(F(0)),CX*D(20)+D(18)-D(19)*~!!L,D(15)?O=m=N,41[43[44[E]=h(N),E]=!N,E]=D(50):0,!++q?kb=1,*l?SDL_PumpEvents(),k=k?k:SDL_SetVideoMode(720,348,32,0),DX():k?SDL_Quit(),k=0:0:0;}i(F,40[E]=!!o)i(z,42[E]=!!o)i(G,48[E]=o)

El mismo autor reconoce que casi le cuesta un divorcio dedicar tantas horas a encajar ese puzle en tan restringido espacio.

No es el único programa en 4096 caracteres. Otro que me ha llamado la atención es este render 3D iterativo (raytracer):

Render

Render en 4Kb de código (fuente)

Aquí está el código fuente.

Y para terminar esta friki-entrada os dejo con otras proezas, en este caso musicales, que se pueden crear con tan sólo una línea de código C:

 

 

Si te gustó, ¡compártelo!

Referencias   [ + ]

1. f^=S^N)&16),G(N-S&&1&(40[E]^f>>C-1
2. *E&15)>9|42[E]
3. 1<<C)-1>>V
4. V&~m)+1[E])_ J(),1[E]=V _ L=o=1 x L(=),M(P+m,=,h+2)_++M,H(3)_ M+=2,H(c&m)_++M,m[E]&&H(4)_(c&=m)?1[E]=*E/c,N=*E%=c:H(0)_*i=N=m&E[L=0]+c*1[E]_*E=-m[E]_*E=r[u(Q?p:m,3,*E+)]_ m[E]^=1 _ E[m/2]=m&1 _ R(*E,&,c)_(a=c B write(1,E,1)B time(j+3),memcpy(r+u(8,3,),localtime(j+3),m
Publicado en Curiosidades, Programación