December 19, 2006
In 1992, Brad Grantham and I challenged each other to write the shortest ray tracer possible. The program should take a set of sphere coordinates and radii on the command line, and output an ASCII rendering of the scene:
% ray x1 y1 z1 r1 [x2 y2 z2 r2 ...]
For example:
% ray 0 0 0 15 -15 2 15 5 10 -10 10 5 ........................................................................... ........................................................................... ........................................................................... ........................................................................... ...............................#########====::............................. ............................@@@@########=====:::-.......................... ..........................@@@@@########======:::--.........##=............. .........................@@@@#########======::::---....#@@@@###==:......... ........................#############======:::::---..=##@@#####==::........ .......................############=======:::::----..=#######===::-........ .......................##########=======::::::----...=========:::-......... .......................#######=========::::::----....-::::::::--........... .......................=============:::::::-----........----............... .......................==========::::::::-----............................. ........................:====::::::::::-----............................... ......................###==:::::::::------................................. ....................@@###==:--.--------.................................... ...................#####==::-...---........................................ ...................=##==:::-............................................... ....................:::::--................................................ ......................--................................................... ...........................................................................
The program with the shortest source code,
measured in characters, would win. (Details: 80 characters
per line maximum; the only compile switch is -lm
for the
math library; use .-:=#@
for the brightness of a pixel.)
I spent an entire Wednesday on it, failing a
statistics mid-term as a result.
In the end, my version was one character shorter than Brad's. Luckily, he kept them in his vast email archives. Here's mine:
#define s atoi(*b++) float sqrt(),A,B,i,o,w=-22,_,h,r,d,e,f;main(L,c,b)char**c,**b;{for(;w<22;w+=2){ for(o=-39;++o<37;){b=c+1,h=0,i=9;while(*b)d=s,e=s,f=50-s,r=s,A=2500+o*o+w*w,B=f *50-e*w-d*o,(_=B*B-A*(f*f+d*d+e*e-r*r))>0&&(_=(B-sqrt(_))/A,_<i&&(h=(f-_*(50+o+ w)-d-e)/r,i=_));putchar("......-:=#@"[(int)(h*3)+5]);}puts("");}}
This was Brad's:
l;float*T,sqrt(),s[80],x,y=6,X,Y,Z,d,*S=s,A,B,C;main(c,v)char**v;{while(*++v)* S++=atoi(*v);for(;y>-6;y-=.6,puts(""))for(x=-8;x<8;x+=.22,putchar("...-:=#@"[l] ))for(d=9e9,l=0,T=s;T<S;T++)X=*T++,Y=*T++,Z=*T+++9,A=x*x+y*y+81,B=x*X+y*Y+9*Z,C =B*B-A*(X*X+Y*Y+Z*Z-*T**T),C>0&&(B-=sqrt(C),B<d?l=(X-Y+Z-(d=B)/A*(x-y+9))*2/ *T+4:0);}
(The original specs weren't precise on where the eyepoint should be, so Brad put his at the origin and I put mine recessed from the origin.) Brad has since found two characters to remove, so in these versions Brad's is one character shorter than mine (326 to 327).
It's a worthwhile exercise to try to write one of these. You learn a lot about C. Start with a normal program and keep shortening it. If you don't have that much time, then just try to shorten one of the above two programs. You'll probably find a lot of ideas that, when tried, either make the program longer or crash it.