Concurso internacional de código C ofuscado | |
---|---|
Estado | Activo |
Género | Concurso de codificación |
Frecuencia | Semestralmente |
Años de actividad | 1984–1996, 1998, 2000, 2001, 2004–2006, 2011–2015, 2018-2020 |
Inaugurado | 1984 ( 1984 ) |
Fundadores | Landon Curt Noll , Larry Bassel |
Lo más reciente | 2020 |
Sitio web | www.ioccc.org |
El Concurso Internacional de Código C Ofuscado (abreviado como IOCCC ) es un concurso de programación informática para el código C más creativamente ofuscado . Se lleva a cabo semestralmente y se describe como una "celebración de la opacidad sintáctica [de C]". [1] El código ganador del 27.º concurso, celebrado en 2020, se publicó en julio de 2020. [2] Los concursos anteriores se llevaron a cabo en los años 1984-1996, 1998, 2000, 2001, 2004-2006, 2011-2015 y 2018-2020.
Las inscripciones son evaluadas anónimamente por un panel de jueces. El proceso de evaluación está documentado en las pautas del concurso [3] y consiste en rondas eliminatorias. Por tradición, no se brinda información sobre el número total de inscripciones para cada concurso. Las inscripciones ganadoras son premiadas con una categoría, como "Peor abuso del preprocesador C " o "Comportamiento más errático", y luego se anuncian en el sitio web oficial del IOCCC. El concurso establece que el premio por ganar es ser anunciado en el sitio web del IOCCC.
El IOCCC fue fundado por Landon Curt Noll y Larry Bassel en 1984 mientras trabajaban en el grupo de adaptación de Genix de National Semiconductor. La idea del concurso surgió después de que compararan notas entre ellos sobre un código mal escrito que tenían que arreglar, en particular el shell Bourne , que usaba macros para emular la sintaxis de ALGOL 68 , y una versión defectuosa de finger para BSD. [4] El concurso en sí fue el tema de una pregunta de concurso en el Computer Bowl de 1993. [5] Después de una pausa de cinco años a partir de 2006, el concurso regresó en 2011. [6]
En comparación con otros concursos de programación, el IOCCC es descrito como "no tan serio" por Michael Swaine , editor del Dr. Dobb's Journal . [7]
Cada año, las reglas del concurso se publican en el sitio web del IOCCC. Todo el material se publica bajo la licencia Creative Commons BY-SA 3.0 Unported. [8] Las reglas varían de un año a otro y se publican con un conjunto de pautas que intentan transmitir el espíritu de las reglas.
Hackear las reglas de los concursos es una tradición. — Landon Curt Noll, 2011 [6]
Las reglas suelen estar redactadas deliberadamente con lagunas que se anima a los concursantes a encontrar y aprovechar. [3] Los participantes que se aprovechan de esas lagunas pueden provocar que se ajusten las reglas del concurso del año siguiente. [3]
Las entradas a menudo emplean trucos extraños o inusuales, como usar el preprocesador C para hacer cosas que no fue diseñado para hacer (en algunos casos "espectacularmente", según el Dr. Dobbs , [9] con una entrada que crea una ALU de 11 bits en el preprocesador C [10] ), o evitar construcciones comúnmente utilizadas en el lenguaje de programación C a favor de formas mucho más oscuras de lograr lo mismo.
Las contribuciones han incluido código fuente formateado para parecerse a imágenes, texto, etc., a la manera del arte ASCII , redefiniciones del preprocesador para hacer que el código sea más difícil de leer y código automodificable . En varios años se presentó una entrada que exigía una nueva definición de algunas de las reglas para el año siguiente, lo que se consideraba un gran honor. Un ejemplo es el programa autorreproductor más corto del mundo . La entrada era un programa diseñado para generar su propio código fuente y que tenía cero bytes de código fuente. Cuando el programa se ejecutaba, imprimía cero bytes, equivalentes a su código fuente. [11]
En un esfuerzo por llevar la ofuscación al extremo, los participantes han producido programas que bordean los estándares de C o que dan como resultado construcciones que activan combinaciones de rutas de código que rara vez se usan en los compiladores. Como resultado, es posible que varias de las entradas anteriores no se compilen directamente en un compilador moderno y algunas pueden provocar fallas.
Dentro del límite de tamaño del código de sólo unos pocos kilobytes, los concursantes han logrado hacer cosas complicadas: un ganador de 2004 presentó un sistema operativo. [12]
Toledo Nanochess es un motor de ajedrez creado por el desarrollador de software mexicano Oscar Toledo Gutiérrez, cinco veces ganador del IOCCC. De acuerdo con las reglas del IOCCC, tiene una longitud de 1255 caracteres. El autor afirma que es el programa de ajedrez más pequeño del mundo escrito en C.
El código fuente de Toledo Nanochess y otros motores está disponible. [13] Debido a que Toledo Nanochess se basa en la propuesta ganadora de Toledo del 18.º IOCCC (Mejor juego [14] ), está muy ofuscado . [15]
El 2 de febrero de 2014, el autor publicó el libro Toledo Nanochess: The commented source code , que contiene el código fuente completamente comentado. [16]
A fecha de 7 de febrero de 2010, parece ser uno de los dos únicos motores de ajedrez escritos en menos de 2 kilobytes de C que son capaces de ejecutar movimientos de ajedrez legales completos, junto con Micro-Max del físico holandés HG Muller. En 2014, la barrera de 1 kilobyte fue superada por Super Micro Chess [17] , un derivado de Micro-Max, con un total de 760 caracteres (espacios y nuevas líneas incluidos). [18] También existe una versión más pequeña del motor de Toledo, el Toledo Picochess , que consta de 944 caracteres que no son espacios en blanco.
Extracto del código fuente
B , i , y , u , b , I [ 411 ], * G = I , x = 10 , z = 15 , M = 1e4 ; X ( w , c , h , e , S , s ){ int t , o , L , E , d , O = e , N =- M * M , K = 78 - h << x , p , * g , n , * m , A , q , r , C , J , a = y ?- x : x ; y ^= 8 ; G ++ ; d = w || s && s >= h && v 0 , 0 ) > M ; hacer { _ o = I [ p = O ]){ q = o & z ^ y _ q < 7 ){ A = q --& 2 ? 8 : 4 ; C = o -9 y z ? q [ "& .$ " ] : 42 ; hacer { r = I [ p += C [ l ] -64 ] _ ! w | p == w ){ g = q | p + a - S ? 0 : I + S _ ! r & ( q | A < 3 || g ) || ( r + 1 & z ^ y ) > 9 && q | A > 2 ){ _ m =! ( r -2 & 7 )) PG [ 1 ] = O , K ; J = n = o & z ; E = I [ p - a ] & z ; t = q | E -7 ? n : ( n += 2 , 6 ^ y ) ; Z n <= t ){ L = r ? l [ r & 7 ] * 9-189 - h - q : 0 _ s ) L += ( 1 - q ? l [ p / x + 5 ] - l [ O / x + 5 ] + l [ p % x + 6 ] *-~! q - l [ O % x + 6 ] + o / 16 * 8 :!! m * 9 ) + ( q ? 0 :! ( I [ p -1 ] ^ n ) + ! ( I [ p + 1 ] ^ n ) + l [ n & 7 ] * 9-386 +!! g * 99 + ( A < 2 )) +! ( E ^ y ^ 9 ) _ s > h || 1 < s & s == h && L > z | d ){ p [ I ] = n , O [ I ] = m ?* g =* m , * m = 0 : g ?* g = 0 : 0 ; L -= X ( s > h | d ? 0 : p , L - N , h + 1 , G [ 1 ], J = q | A > 1 ? 0 : p , s ) _ ! ( h || s -1 | B - O | i - n | p - b | L <- M )) P y ^= 8 , u = J ; J = q -1 | A < 7 || m ||! s | d | r | o < z || v 0 , 0 ) > M ; O [ I ] = o ; p [ I ] = r ; m ? * m =* g , * g = 0 : g ?* g = 9 ^ y : 0 ;} _ L > N ){ * G = O _ s > 1 ){ _ h && c - L < 0 ) P L _ ! h ) i = n , B = O , b = p ;} N = L ;} n += J || ( g = I + p , m = p < O ? g -3 : g + 2 , * m < z | m [ O - p ] || I [ p += p - O ]);}}}} Z ! r & q > 2 || ( p = O , q | A > 2 | o > z & ! r &&++ C *-- A ));}}} Z ++ O > 98 ? O = 20 : e - O ); P N + M * M && N >- K + 1924 | d ? N : 0 ;} principal (){ Z ++ B < 121 ) * G ++= B / x % x < 2 | B % x < 2 ? 7 : B / x & 4 ? 0 :* l ++& 31 ; Z B = 19 ){ Z B ++< 99 ) putchar ( B % x ? l [ B [ I ] | 16 ] : x ) _ x - ( B = F )){ i = I [ B += ( x - F ) * x ] & z ; b = F ; b += ( x - F ) * x ; Z x - ( * G = F )) i =* G ^ 8 ^ y ;} de lo contrario v u , 5 ); v u , 1 );}}
A continuación se muestra una entrada de 1988 que calcula pi observando su propia área : [19]
#define _ -F<00||--F-OO--; entero F = 00 , OO = 00 ; principal (){ F_OO (); printf ( "%1.3f \n " , 4. * - F / OO / OO );} F_OO () { _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ - _ - _ - _ - _ _ - _ - _ - _ }
(Esta entrada fue escrita en K&R C ; no funciona correctamente en ANSI C sin algunos cambios. [20] )
Otro ejemplo es el siguiente simulador de vuelo, ganador del IOCCC de 1998, [21] tal como se enumera y describe en Calculated Bets: Computers, Gambling, and Mathematical Modeling to Win (2001) [22] y se muestra a continuación:
#include <math.h> #include <sys/time.h> #include <X11/Xlib.h> #include <X11/keysym.h> doble L , o , P , _ = dt , T , Z , D = 1 , d , s [ 999 ], E , h = 8 , I , J , K , w [ 999 ], M , m , O , n [ 999 ], j = 33e-3 , i = 1E3 , r , t , u , v , W , S = 74,5 , l = 221 , X = 7,26 , a , B , A = 32,2 , c , F , H ; int N , q , C , y , p , U ; Ventana z ; char f [ 52 ] ; GC k ; principal (){ Mostrar * e = XOpenDisplay ( 0 ); z = RootWindow ( e , 0 ); para ( XSetForeground ( e , k = XCreateGC ( e , z , 0 , 0 ), BlackPixel ( e , 0 )) ; scanf ( "%lf%lf%lf" , y + n , w + y , y + s ) + 1 ; y ++ ); XSelectInput ( e , z = XCreateSimpleWindow ( e , z , 0,0,400,400,0,0 , WhitePixel ( e , 0 ) ), KeyPressMask ) ; para ( XMapWindow ( e , z ) ; ; T = sin ( O ) ){ struct timeval G = { 0 , dt * 1e6 } ; K = cos ( j ) ; N = 1e4 ; M + = H * _ ; Z = D * K ; F + = _ * P ; r = E * K ; W = cos ( O ) ; m = K * W ; H = K * T ; O + = D * _ * F / K + d / K * E * _ ; B = sin ( j ) ; a = B * T * D - E * W ; XClearWindow ( e , z ) ; t = T * E + D * B * W ; j += d * _ * D - _ * F * E ; P = W * E * B - T * D ; para ( o += ( I = D * W + E * T * B , E * d / K * B + v + B / K * F * D ) * _ ; p < y ; ){ T = p [ s ] + i ; E = c - p [ w ]; D = n [ p ] - L ; K = D * m - B * T - H * E ; si ( p [ n ] + w [ p ] + p [ s ] == 0 | K < fabs ( W = T * r - I * E + D * P ) | fabs ( D = t * D + Z * T - a * E ) > K ) N = 1e4 ; de lo contrario { q = W / K * 4E2 + 2e2 ; C = 2E2 + 4e2 / K * D ; N -1E4 && XDrawLine ( e , z , k , N , U , q , C ); N = q ; U = C ; } ++ p ; } L += _ * ( X * t + P * M + m * l ); T = X * X + l * l + M * M ; CadenaXDraw ( e , z , k , 20 , 380 , f , 17 ); D = v / l * 15 ; i += ( B * l - M * r - X * Z ) * _ ; para (; XPending ( e ); u *= CS != N ){ XEvent z ; XNextEvent ( e , & z ); ++* (( N = XLookupKeysym ( & z . xkey , 0 )) - IT ? N - LT ? UP - N ?& E :& J : & u : & h ); --* ( DN - N ? N - DT ? N == RT ?& u : & W :& h :& J ); } m = 15 * F / l ; c += ( I = M / l , l * H + I * M + a * X ) * _ ; H = A * r + v * X - F * l + ( E = .1 + X * 4.9 / l , t = T * m / 32 - I * T / 24 ) / S ; K = F * M + ( h * 1e4 / l - ( T + E * 5 * T * E ) / 3e2 ) / S - X * d - B * A ; a = 2,63 / l * d ; X += ( d * l - T / S * ( .19 * E + a * .64 + J / 1e3 ) - M * v + A * Z ) * _ ; l += K * _ ; W = d ; sprintf ( f , "%5d %3d" "%7d" , p = l / 1,7 ,( C = 9E3 + O * 57,3 ) % 0550 ,( int ) i ); d += T * ( .45 -14 / l * X - a * 130 - J * .14 ) * _ / 125e2 + F * _ * v ; P = ( T * ( 47 * I - m * 52 + E * 94 * D - t * .38 + u * .21 * E ) / 1e2 + W * 179 * v ) / 2312 ; seleccione ( p = 0 , 0 , 0 , 0 y G ); v - = ( W * F - T * ( .63 * m - I * .086 + m * E * 19 - D * 25 -.11 * u ) / 107e2 ) * _ ; D = cos ( o ); E = sen ( o ); } }
Este programa necesita la siguiente línea de comando en un sistema Linux para ser compilado: [21]
cc bancos.c -o bancos -DIT=XK_Pág_Arriba -DDT=XK_Pág_Abajo \-DUP=XK_Arriba -DDN=XK_Abajo -DLT=XK_Izquierda -DRT=XK_Derecha \-DCS=XK_Return -Ddt=0.02 -lm -lX11 -L/usr/X11R6/lib
Para ejecutar el archivo binario ( banks
) se le debe suministrar un .sc
archivo de escenario mediante stdin
la entrada: [21]
gato pittsburgh.sc | ./bancos
A continuación se muestra una entrada de 2011 que reduce la resolución de imágenes PGM , PPM y arte ASCII de Don, Yang: [23]
/* + + + + [ >i>n[t */ # incluir < stdio . h > /*2w0,1m2,]_<n+a m+o>r>i>=>(['0n1'0)1; */ int /**/ main ( int /**/ n , char ** m ){ ARCHIVO * p , * q ; int A , k , a , r , i /* #uinndcelfu_dset<rsitcdti_oa.nhs>i/_*/ ; char * d = "P%" "d \n %d \40 %d" /**/ " \n %d \n\00 wb+" , b [ 1024 ], y [] = "yuriyurarararayuruyuri*daijiken**akkari~n**" "/y*u*k/riin<ty(uyr)g,aur,arr[a1r2a82*y2*/u*r{uyu}riOcyurhiyua**rrar+*arayra*=" "yuruyurwiyuriyurara'rariayuruyuriyuriyu>rarararayuruy9uriyu3riyurar_aBrMaPrOaWy^?" "*]/f]`;hvroai<dp/f*i*s/<ii(f)a{tpguat<cahfaurh(+uf)a;f}vivn+tf/g*`*w/jmaa+i`ni(" /** */ "i+k[>+b+i>++b++>l[rb" ; int /**/ u ; for ( i = 0 ; i < 101 ; i ++ ) y [ i * 2 ] ^= "~hktrvg~dmG*eoa+%squ#l2" ":(wn \" 1l))v?wM353{/Y;lgcGp`vedllwudvOK`cct~[|ju {stkjalor(stwvne \" gt \" yogYURUYURI" [ i ] ^ y [ i * 2 + 1 ] ^ 4 ; /*!*/ p = ( n > 1 && ( m [ 1 ][ 0 ] - '-' || m [ 1 ][ 1 ] != '\0' )) ? fopen ( m [ 1 ], y + 298 ) : entrada estándar ; /*y/riynrt~(^w^)],]c+h+a+r+*+*[n>)+{>f+o<r<(-m] =<2<5<64;} -]-(m+;yry[rm*])/[* */ q = ( n < 3 ||! ( m [ 2 ][ 0 ] - '-' || m [ 2 ][ 1 ])) ? salida estándar /*]{ }[*/ : fopen ( m [ 2 ], d + 14 ); si ( ! p || /* "]<<*-]>y++>u>>+r >+u++ +y>--u---r>++i+++" <)< ;[>-m-.>a-.-i.++n.>[(w)*/ ! q /**/ ) return + printf ( " No se puede " " abrir \40 %s \40 " "" "para \40 %sing \n " , m [ ! p ? 1 : 2 ], ! p ? /* o=82]5<<+(+3+1+&. (+ m +-+1.)<)<|<|.6>4>-+(> m- &-1.9-2-)-|-|.28>-w-?-m.:>( [28+ */ "leer" : "escribir" ); para ( a = k = u = 0 ; y [ u ]; u = 2 + u ){ y [ k ++ ] = y [ u ];} si (( a = fread ( b , 1 , 1024 /* , mY/R*Y"R*/ , p /*U*/ ) /* R*/ ) > /*U{ */ 2 && b /*Y */ [ 0 ] /*U*/ == 'P' && 4 == /*"y*r/y)r\} */ sscanf ( b ,d , y k , y A , y yo , & r ) && ! ( k -6 && k -5 ) && r == 255 ){ u = A ; si ( n > 3 ){ /* ]&<1<6<?<m.-+1>3> +:+ .1>3+++ . -m-) -;.u+=++.1<0< <; f<o<r<(.;<([m(=)/8*/ u ++ ; i ++ ;} fprintf ( q , d , k , u >> 1 , i >> 1 , r ); u = k -5 ? 8 : 4 ; k = 3 ;} de lo contrario /*]>*/ {( u ) = /*{ p> >u >t>-]s >++(.yryr*/ + ( n + 14 > 17 ) ? 8 / 4 : 8 * 5 / 4 ;} para ( r = i = 0 ; ;){ u *= 6 ; u += ( n > 3 ? 1 : 0 ); si ( y [ u ] & 01 ) fputc ( /* <ge<tc>ha r -(-).)8+<1. >;+i.(<)< <)+{+si>([180*/ 1 * ( r ),q ); si ( y [ u ] y 16 ) k = A ; si ( y [ u ] y 2 ) k -- ; si ( i /* ("^w^NAMORI; { I*/ == a /*" )*/ ){ /**/ i = a = ( u ) * 11 y 255 ; si ( 1 y& 0 >= ( a = fread ( b , 1 , 1024 , p )) && ")]i>(w)-;} { /si-(-m--M1-0.)<{" [ 8 ] == 59 /* */ ) romper ; i = 0 ;} r = b [ i ++ ] ; u += ( /**>> *..</<<<)<[[;]**/ + 8 &* ( y + u )) ? ( 10 - r ? 4 : 2 ) : ( y [ u ] & 4 ) ? ( k ? 2 : 4 ) : 2 ; u = y [ u /* 49;7i\(w)/;} y}ru\=*ri[ ,mc]o;n}trientuu ren ( */ ] - ( int ) '`' ;} fclose ( p ); k = + fclose ( q ); /*] <*.na/m*o{ri{ d;^w^;} }^_^}} " */ return k - -1 + /*\' '-`*/ ( - /* }/ */ 0x01 ); {;{ }} / *^w^*/ ;}
Si el programa se ejecuta utilizando su propia fuente como entrada, el resultado es:
[ raíz @ host ~ ] # . / akari akari . c int * w , m , _namori = ( 'n' ); #include <stdio.h> /*;hrd"% dnd4%"*/ /**/ int ( y ), u , r [ 128 * 2 /*{y}icuhya*rr*rya= */ ]; void /**/ i (){ putchar ( u );} int /**/ main ( /* "(n"l)?M5{YlcpvdluvKct[j skao(tve"t"oYRYR" */ int ( w ) , char ** n ){ para ( m = 256 ; -- m ; r [ m ] /* "<*]y+u>r>u+yu-r+i+" ) ;>mai+n>() /q*/ = 25 < ( 31 y ( m -1 )) || 64 - ( m y 192 ) || 2 > w ? m : ( 2 + m /*"*,/U// R/)/ U * & /Y/0/U/=P &=/"*/ ) \ & 16 ? m -13 : 13 + m ) ; u =+ 10 ; para (;( m = /* *>/()/{ pone +(yy*+ n1>7?/:*/ getchar ()) + 1 ; i () ){ si ( 10 /* "wNMR;{ yo/=/" )/{*/ == u * 1 ) i (); si ( m -10 ){ u = /*> *./<)[;*/ 8 * 4 ; i (); } u = r [ m ];} return ( * * n /*{i ;w; }_} ( -*/ * 00 ) ; } [ raíz @ host ~ ] # . / akari akari . c > . / akari . pequeño [ raíz @ host ~ ] # . / akari . / akari . pequeño wm_aoi ( n ) /*idad,,[2*/ {} char * y = ( ")M{lpduKtjsa(v""YY" "*yuruyuri" ) ; principal ( /* /",U/ R)U* Y0U= ="/\ */ ){ pone ( y + 17 /* "NR{I=" ){/=* =* */ ); /* **/ { ;;}} [ raíz @ host ~ ] # [ raíz @ host ~ ] # . / akari . / akari . pequeño > . / akari . más pequeño [ raíz @ host ~ ] # . / akari . / akari . menor principal (){ pone ( "Y" "U RU YU " \ "RI" ) /* */ ;} [ root @ host ~ ] #
gcc -traditional-cpp -o r r.c
o gcc -E r.c | sed 's/- -/--/g' > r2.c ; gcc -o r2 r2.c
(El archivo fuente es r.c
) [ ¿ investigación original? ]