Python 2.6, 886 - 1425 characters
My initial version (in the revisions) came in at 886 characters but did not satisfy the spec completely (it did not check for avoiding checkmate ; it didn't even consider the possible moves of the black pieces).
Now it does (and I've fixed several bugs in the original). Alas this comes with a cost in characters: 1425 for now, but there should still be little room for improvement. This version should be a lot more solid in handling edge cases then the previous one.
#-*-coding:utf8-*-
import sys;e=enumerate
B,W=["♟","♜","♞","♝","♛","♚"],["♙","♖","♘","♗","♕","♔"]
R={"♙":[11,42],"♖":[28],"♘":[31],"♗":[8],"♕":[8,28],"♔":[1,21]}
def F(w):return sum([[(i,j)for j,p in e(o)if p==w]for i,o in e(Z)],[])
def G(x,y):
P=Z[x][y];D=P in W;L=[]
for o in R[P]if D else R[unichr(ord(P.decode('utf8'))-6).encode('utf8')]:
r,k="%02d"%o
for g,h in[[(-1,-1),(1,1),(-1,1),(1,-1)],[[(1,-1),(1,1)],[(-1,-1),(-1,1)]][D],[(-1,0),(1,0),(0,-1),(0,1)],[(-2,-1),(-2,1),(-1,-2),(-1,2),(1,-2),(1,2),(2,-1),(2,1)],[(-1,0)]][int(r)]:
J=0
for i in range(int(k)):
T=x+(i+1)*g;U=y+(i+1)*h
if T<0 or T>7 or U<0 or U>7:break
M=Z[T][U]
if not J:L.append((T,U,P,M))
else:break
if r in"02"and(M in W+B):
J=1
if not((D and M in B)or(not D and M in W)):L.pop()
elif(r=="1"and not((D and M in B)or(not D and M in W)))or(r=="4"and((i==1 and x!=6)or M!="…")):L.pop()
return L
Z=[[y for y in l[5:].split()]for l in sys.stdin.readlines()[:-2]]
Q=[]
for p in R:
for i,j in F(p):
for M,L,c,_ in G(i,j):
O=Z[M][L];Z[i][j]="…";Z[M][L]=c;E=[];map(E.extend,map(F,B))
if not any(any(1 for _,_,_,I in G(v,h)if I==["♔","♚"][c in B])for v,h in E):Q.append((i,j,M,L,c))
Z[i][j]=c;Z[M][L]=O
(x,y,X,Y,p)=Q[0];Z[x][y]="…";Z[X][Y]=p
for i,h in e(Z):print`8-i`+' ║'+' '.join(h)
print"——╚"+"═"*16+"\n—— a b c d e f g h"
Example input and output:
# INPUT
8 ║♜ ♞ ♝ … ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… … … … ♟ … … …
4 ║… … … … … … ♙ ♛
3 ║… … … … … ♙ … …
2 ║♙ ♙ ♙ ♙ ♙ … ♙ …
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
——╚═══════════════
—— a b c d e f g h
# OUTPUT
8 ║♜ ♞ ♝ … ♚ ♝ ♞ ♜
7 ║♟ ♟ ♟ ♟ … ♟ ♟ ♟
6 ║… … … … … … … …
5 ║… … … … ♟ … … …
4 ║… … … … … … ♙ ♛
3 ║… … … … … ♙ ♙ …
2 ║♙ ♙ ♙ ♙ ♙ … … …
1 ║♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖
——╚════════════════
—— a b c d e f g h
@CMP, a triple repetition is irrelevant here, because it's legal to do the move that leads to it, and also legal to ignore it and keep playing (it's a draw only if a player calls it). – ugoren – 2012-02-05T08:48:29.597
though it's not mine, and it doesn't use stdin as input! but this is one of the best ones out there! it's a chess game with AI which can beat average human level just in 1023 bytes!
– Ali1S232 – 2012-01-23T07:56:53.710I mean a standard error message caused by failure of some built-in function of the language. So that's ok? — Is it mandatory that the program can do any legal move? Perhaps castling and pawn special moves should be made optional with some bonus? – ceased to turn counterclockwis – 2012-01-21T15:12:58.990
2@leftaroundabout: Whenever you can castle, you can just move the rook instead, so you can skip the logic for that at least. – hammar – 2012-01-21T15:15:17.153
2... and thinking about it some more, the "en passant" move requires information about what previous moves has been made, which cannot be inferred from just the positions of the pieces, so I guess it might be safe to drop that. However, whether the double first move is available can be inferred from the rank of the pawn, so you might want to include that. – hammar – 2012-01-21T18:41:09.123
@hammar: you're right, I hadn't thought about that. The double move is also not important, except for one case: when you can go two steps you can also go one, so it only becomes important when you're in check and the double-move is the only move that covers the king. Also, even when you don't need to be able to use every move, you still need to consider that black can answer with any possibility. – ceased to turn counterclockwis – 2012-01-21T19:14:06.583
@hammar "en passant" and castling have to be ignored, there is no such thing as double move in chess as far as I know. – Hristo Hristov – 2012-01-21T20:36:35.737
@HristoHristov: I meant the way you can move a pawn 2 steps the first time. Not sure what the proper term is. – hammar – 2012-01-21T20:46:40.430
@hammar Now I understand. These are two possible moves of the pawn which can be valid or not, so they have to be considered. – Hristo Hristov – 2012-01-21T20:52:27.737
9Is resigning counted as a legal move? :) – gnibbler – 2012-01-22T13:19:59.910
@gnibbler resigning is legal, but it's not a "move" :) – Hristo Hristov – 2012-01-22T15:24:15.387
Can we assume we're not in check (without testing for that)? And don't have to test whether a move would uncover check? – smci – 2012-01-23T11:51:33.420
@smci No, these assumes are not acceptable. – Hristo Hristov – 2012-01-23T12:25:49.037
If you give the move in a standard format like FEN, you have the en passant target encoded, as well as castling availability. The only thing it can't do is a draw if the same position is seen 3 times. You need full history for that. – captncraig – 2012-01-23T15:52:42.180