Smallest chess program Inspired by this recent article telling of a French programmer who wrote a 487 byte 2-player (human vs. human) chess program in Assembly, I wondered how small chess programs could be in other languages.

Details


The program must only accept legal chess moves.
Declaration of check/checkmate is not necessary (just desirable), although the first rule applies in cases of check.
As per the article, castling is not a necessary implementation.
Also, you do not have to implement en passant.
You do however, have to permit pawn promotion upon reaching eighth rank (you may opt to simply force conversion to queen).
It is up to you how the board is displayed - terminal ASCII, GUI, etc.
You must display whose turn it is.


The rules of chess can be found here - ignore specified tournament rules (e.g. timing, touching), and remember castling and en passant are not necessary implementations.
C, 650 600

n=8,t=65,s,f,x,y,p,e,u=10,w=32,z=95;char a[95],b[95]=&quot;RNBKQBNR&quot;;v(){p=a[s]&amp;z;y=f/u-s/u;x=f-s-y*u;e=x*x+y*y;n=s%u/8|f%u/8|a[s]/w-t/w|a[f]/w==t/w|!(p==75&amp;e&lt;3|p&gt;80&amp;x*y==0|p%5==1&amp;x*x==y*y|p==78&amp;e==5|p==80&amp;x*(z-t)&gt;0&amp;(a[f]-w?e==2:e==1|e==4&amp;s%5==1));if(!n&amp;&amp;p-78)for(e=(f-s)/abs(x*x&gt;y*y?x:y),x=s;(x+=e)-f;)n|=a[x]-w;}main(){for(a[93]=40;n--;a[92]=47)sprintf(a,&quot;%s%cP    p%c \n&quot;,a,b[n],b[n]+w);for(;1;){puts(a);for(n=1;n;){putchar(t);scanf(&quot;%d%d&quot;,&amp;s,&amp;f);v();memcpy(b,a,z);if(!n){a[f]=p-80|f%u%7?a[s]:t+16;a[s]=w;a[f]&amp;z^75||(a[z-t/w]=f);f=a[z-t/w];t^=w;for(n=1,s=80;n&amp;&amp;s--;)v();if(n=!n)memcpy(a,b,z),t^=32;}}}}

To reduce the code for initializing the board, the display has White (uppercase) playing from left to right and Black (lowercase) playing from right to left. Input is in the form of two 2-digit decimal numbers (start position and finish position), giving file(0-7) and rank(0-7). For a bit of extra code (subtract 11 from each input), input could be made to comply with http://en.wikipedia.org/wiki/ICCF_numeric_notation (digits 1-8)
Here's a sample screenshot where Black has just advanced his Rook's Pawn. White tries various illegal moves with his queen, before finally capturing the pawn. Turn indicators are a for Black and A for White.

An interesting feature of my validation is the use of the square of the Euclidean distance. For the knight this is always 1^2+2^2=5, but I also use it for the King and the pawn.
Test for Check is done by backing up the board, carrying out the players move, and scanning all 64 possible opponent's moves.
The program has to be ended with Ctrl-C. I cant think of a more gracious way of doing it, other than putting in a special move to end the program. A game of chess actually ends when one player is unable to move on his turn (checkmate or stalemate) and that requires a lot of tests that arent required by the spec.
Commented code
n=8,t=65,s,f,x,y,p,e,u=10,w=32,z=95;                 // 8,10 height and width of board. w=ASCII space, also difference between ucase and lcase
                                                     // 95 is bitmask for conversion lowercase to uppercase, but also used as length of array, etc.
char a[95],b[95]=&quot;RNBKQBNR&quot;;                         // a is main board, b is backup board (but used at start to hold 1st row data.)
 
v(){                                                 // validate move in all aspects except check
  p=a[s]&amp;z;                                          // p=uppercase(character on start square)
  y=f/u-s/u;                                         // signed distance in y direction
  x=f-s-y*u;                                         // and x direction
  e=x*x+y*y;                                         // square of Euclidean distance
  n=s%u/8|f%u/8|                                     // n=true if 2nd digit of input out of bounds OR
  a[s]/w-t/w|a[f]/w==t/w|                            // start sq not friendly piece OR finish sq is friendly piece (also eliminates case where start=finish)
  !(                                                 // OR NOT geometry valid
    p==75&amp;e&lt;3|                                       // 'K'(ASCII75) AND euclidean distance squared =1 or 2 OR
    p&gt;80&amp;x*y==0|                                     // 'Q'or'R' AND x or y = 0 OR
    p%5==1&amp;x*x==y*y|                                 // 'Q'or'B' AND abs(x)=abs(y)
    p==78&amp;e==5|                                      // 'N' AND euclidean distance squared = 5
    p==80&amp;x*(z-t)&gt;0&amp;(a[f]-w?e==2:e==1|e==4&amp;s%5==1)   // 'P'(ASCII80):x direction must correspond with case of player (z-t)
  );                                                 // if capturing e=2. Otherwise e=1 (except on start rows 1 and 6, e can be 4)
  if(!n&amp;&amp;p-78)                                       // if not yet invalid and piece not 'N'(ASCII78) 
    for(e=(f-s)/abs(x*x&gt;y*y?x:y),x=s;(x+=e)-f;)      // Set e to the numeric difference to travel 1 square in right direction. Set x to start square
       n|=a[x]-w;                                    // and iterate x through all intervening squares, checking they are blank
}



main(){

  for(a[93]=40;n--;a[92]=47)                         // iterate n through 8 rows of board. vacant spaces in bracket are use to assign start positions of kings to a[92&amp;93] 
    sprintf(a,&quot;%s%cP    p%c \n&quot;,a,b[n],b[n]+w);      // build up start position, each row 10 squares wide, including filler space the end and newline
  
  for(;1;){                                          // loop forever   
    puts(a);                                         // display board
    for(n=1;n;){                                     // loop while move invalid
      putchar(t);                                    // display prompt 'A' for white 'a' for black
      scanf(&quot;%d%d&quot;,&amp;s,&amp;f);                           // get input
      v();                                           // validate move
      memcpy(b,a,z);                                 // backup board (and king position metadata)  
      if(!n){                                        // if move not yet invalid
        a[f]=p-80|f%u%7?a[s]:t+16;                   // if not a pawn on last row, content of finish square = start square, ELSE queen of correct case (t+16) 
        a[s]=w;                                      // start square becomes blank (ASCII32)
        a[f]&amp;z^75||(a[z-t/w]=f);                     // if finish square king, update king position metadata
        f=a[z-t/w];                                  // to begin scanning to see if king in check, set f to current king position
        t^=w;                                        // and change colour
        for(n=1,s=80;n&amp;&amp;s--;)v();                    // for s=79..0 search for valid opponent move to capture king (stops with n=0)
        if(n=!n)memcpy(a,b,z),t^=32;                 // valid opponent threat on king means invalid player move. Invert n, recover board from backup and change colour back.
      }
    }    
  }
}