Ajedrez modo texto. 18º IOCCC. Best Game.
Este es el programa que dio inicio a todo, lo escribí con
el fin de ganar el
18º IOCCC
(International Obfuscated C Code Contest), un concurso que premia los programas
más complicados escritos en lenguaje C, tiene un límite de tamaño y personas
muy brillantes emplean sus mentes para realizar trucos nunca antes vistos.
Algunas de las participaciones ganadoras son clásicas y valiosos objetos de
estudio.
Mi objetivo fue encajar un programa completo de ajedrez en
los límites del concurso y darle una forma elegante.
Este es el código fuente, escrito en lenguaje C:
#define F getchar())
#define H(z)*n++=z;
#include <setjmp.h>
#define v main(0,0,0
#define Z while(
#define _ if(
#define o(d)(S=63,u[l]=0,l[d]=6^e,q=1e4>v,0),l[d]=0,u[l]=e^6,S=b,q)
#define I(H,n) { _ r=l[x=H],!r|(r^e)<-1){ _ j=u[l],-7==r|6==r\
){ n; e=~e; return 1e5-443*f; } u[l]=0,t=j+1,i=j-1; _!i&89<\
x)i=j,t=6; _-1==t&30>x)t=j,i=-7; Z++i<t){ d =0; S&= 63; \
a=((j^e)!=1?6!=(j^e)?O[32+x/10]-O[u/10+32]-q:(S|=6!=j?8\
:1,2==u-x)*9+9*(x-u==2):(d=1==j?x-u:u-x)/8+!(!((x-u)%\
10)|r)*99+(j==1?90<x:29>x)*(9*O[28+i]-288))+O[r+28\
]*9-288+O[x%10+33]-f-O[33+u%10]; x[l]=i; S|=(21=\
=u|21==x)*2+(u==28|28==x)*4+(91==u|x==91)*16+32\
*(u==98|x==98)+(20==d)*64*x; a-=k>f?main(a,f+1\
,M,k):0; _ i==c&u==h&!f&N&a>-1e4&x==y)longjm\
p(z,1); S=b; _!N|f&&(a>M||!f&a==M&&1&rand()\
)){ _!f){ _ k){ c=i; h=u; y=x; } } else _ \
L-a<N){ n; e=~e; u[l]=j; x[l]=r; return\
a; } M=a; } } x[l]=r; u[l]=j; n; } }
typedef int G; char J [ 78 ], O [ ]
= "HRQAMS#-smaqrh[UTZYTU[|TBA("
"$#(ABT|ba`gg`ab8>GK[_`fFDZXEYR" "L\t####"
"##B#A#@#G#F#E#D#K\t\3Zlv#tjm" "\3J#tjm\3Pwb"
"ofnbwf\3Joofdbo\3)&`&`.&`&`" "#+&g*\t"; G y,
c,h,e,S,*s,l[149]; jmp_buf z ; G main(G L,G f,
G N,G k){ G u=99,p,q,r,j,i,x ,t,a,b=S,d,M=-1e9
; char *n; if( *l){ e=~e; Z u >21){ q= l[--u]^e;
_!-- q){ _!l[p=e?u-10:u+10]){ I(p,)_ e?u>80 & !l[p
-=10]:u<39&!l[p+=10])I(p,)} _ l[p=e?u-11:9+u] )I(p,)
else _ u-1==S>>6){ l[u-1]=0; I(p,l[u-1]=-2^e); } _ l[
p=e?u-9:11+u])I(p,)else _ S>>6==1+u){ l[1+u]=0; I(p,l
[1+u]=e^-2); } } _!--q){ n=O+41; Z++n<50+O)I(u+80-*n,
)} _ 0<q&4>q){ n=q==2?53+O:O+49; Z++n<O+(q!=1)*4+54
){ p=u; do I(p-=*n-80,)Z!p[l]); } } _ 4==q){ n=49+O
; Z++n<O+58)I(u-*n+80,)_ e&!(S&24)|!e&!(S&3) &&
!l[u-2]&!l[u-1]&!l[u-3]&&o(u)&&o(u-1)){ l[u-1]=4
^e; l[u-4]=0; I(u-2,l[u-1]=0; l[u-4]=e^4); } _
e&!(S&40)|!e&!(S&5) &&!l[u+1]&!l[2+u]&&o(u)&&
o(1+u)){ l[u+1]=e^4; l[3+u]=0; I(u+2,l[1+u
]=0; l[u+3]=4^e); } } } e=~e; return M; }
Z h<130){l[h]=-(21>h|98<h|2 >(h+1 )%
10); O[h++]^=3; } n=O +14; s=20+l; Z
++s<29+l){ 10[s]=1; 70[s]=~ ( * s = *
n++ -+84); 60 [ s] =-2; } Z n=J){ puts
(58+O); u=19; Z++u<100){ H(32)_!( u%10
))H(32)H(O[7+l[u]])_(9+u)%10>7){ H(58
-u/10)H(32)_ u&1)puts(n=J); } } puts
(O+58); _-1e4 >v , 1)){ e=~e; puts
(O+(v,0)> 1e4?e?90:82:96)); break
; } _ 1<L&e) { d=v,2+L); printf
(O+114,h%10+64,58-h/10,y%10+64
,58 -y/10,d); } else{ putchar
(62+e); h= (95 & F-44; c=l[h
+=(56-F *10]; y=(95&F-44; y
+=(56-F*10; Z 10!=(u=(95
&F)){ c=5; Z--c>1&&u!=c
[O]); c=e^c-7; } } _!
setjmp(z)){ v+1,1);
puts( 106+
O); } } Z
10!=
F; }
Como compilarlo
Primero, descargue el código fuente desde
aquí.
Sugiero con franqueza que compile este programa de ajedrez
con la máxima optimización permitida por su compilador, en GCC puede
utilizar:
gcc -O3 -fexpensive-optimizations toledo.c -o toledo
Por constante petición del amable público también es posible
compilarlo con el antiquísimo Turbo C o como C++, vea las
instrucciones en el
FAQ.
Como utilizarlo
Este programa de ajedrez pueden funcionar en dos modos:
dos jugadores, o un jugador (siempre blancas) contra la máquina. Para el
primer modo, ejecute el programa sin argumentos:
toledo
El otro modo es accesible ejecutando el programa con un
argumento (análisis a nivel 5):
toledo a
Dos argumentos para análisis a nivel 6:
toledo a b
Y cada argumento sucesivo analizará un nivel más. No hay
límite de nivel, pero más allá de 7 niveles puede ser lento, pruébelo bajo
su propio riesgo y tiempo de computación.
Introduciendo movimientos
Cuando sea su turno, usted puede introducir su movimiento,
por ejemplo, como D2D4 y oprimir la tecla Enter, la computadora
verificará que el movimiento sea legal y le advertirá de movimientos ilegales.
Todos los movimientos legales del ajedrez están permitidos.
Un caso especial es cuando se realiza coronación, debe
introducir el movimiento junto con una letra extra que indica la pieza
deseada. El programa requiere la letra de la pieza, y no seleccionará
automáticamente una reina, así que no se sorprenda si no acepta su
movimiento.
Por ejemplo F7F8N (suponiendo que tiene un peón en
F7), lo coronará a un caballo, substituya N por la pieza deseada
(N=Caballo, Q=Reina, R=Torre, B=Alfil).
Estado del juego
La computadora detectará jaquemate y mate ahogado, y después
de cada movimiento suyo mostrará la puntuación de la posición, un número alto
es mejor para la computadora, idem. peor para usted.
Operación del programa
Este es un buen ejemplo de un programa de ajedrez reducido
a lo esencial. Para mantenerlo dentro de los límites del concurso, utilicé
algoritmos cortos pero de difícil comprensión.
La interface ocupa solo una fracción del codigo, el núcleo
realiza múltiples funciones, es llamado recursivamente para analizar y evaluar
cada nivel, realiza corte alfa-beta, generación de movimientos, movimiento
de la computadora, detección de jaque, verificación de movimientos ilegales
y realiza los movimientos después de verificarlos.
También pone una norma para ultra-mini-programas de ajedrez,
el jugador y la computadora pueden realizar todos los movimientos legales,
otras características son:
- Verificación de movimiento ilegal.
- Detección de jaquemate.
- Detección de mate ahogado.
- Incluso en nivel 5 puede darle una sorpresa a jugadores aficionados.
Trucos de confusión
- Solo una función C, muy modular.
- Uso extensivo de los operadores trinario y coma. Salve un disco duro
hoy.
- Uso extensivo de la precedencia de los operadores C, todos los buenos
programadores de C la recuerdan... Yo no puedo.
- Operandos intercambiados en todos los lugares posibles, algún día alguien
lo entenderá.
- Expresiones mezcladas y multifunción en sentencias, el buen estilo del
viejo BASIC.
- Se usan macros para ocultar la sintaxis del C, busque parentesis
desbalanceados y ¡llamadas con argumentos vacíos!
- Solo incluye los encabezados normativos necesarios, el enlazador toma
cuidado, y compila más rápido... pero no he notado la diferencia.
- Utiliza solo una cadena de texto, muy fácil de
internacionalizar. ;)
Revisiones anteriores
El programa anterior enviado al IOCCC tenía dos defectos,
uno de ellos convertía un peón del jugador a un peón de la computadora, al
estilo del lado obscuro de la fuerza :), y el otro permitía enrocar
estando en jaque y sobre cuadros atacados, y sí, a la computadora le
«encantaba» romper esa regla cada vez que podía.
Corregí silenciosamente el primer bug, de hecho nadie lo
detectó, o eso era lo que yo pensaba, recientemente vino a mi conocimiento
que el programador alemán Valentin Hilbig
lo descubrió el
12 de julio del 2007.
El otro defecto fue reportado por Andreas, probablemente
estaba muy avergonzado de probar código ofuscado, por eso no dijo su
apellido.
Y aquí está el código:
- toledo_rev0.c, el programa original con
los dos defectos. 19 de mayo del 2005.
- toledo_rev1.c, el programa con el
error del peón corregido. 1º de enero del 2006.
- toledo.c, el programa con ambos defectos
corregidos. 28 de marzo del 2006.
Hechos curiosos
Algunas personas no distinguen la figura del
caballo en el código fuente, ¡de verdad!, pruébelo con sus amigos, puede
servir como un tipo de lectura de la mente o prueba de Rorschach.
El programa juega relativamente rápido, algunas
personas se sienten forzadas a responder rápido, ¡y pierden el juego!
Ligas relacionadas
Última modificación: 10-mar-2013