# Chess conversion

There's quite a lot of work that's been done in the world of chess. For example, there is a standardized file format, .pgn, that describes a chess game, including the list of moves. Additionally, there's another file format .fen, that describes a board position. The challenge today is to convert a list of chess moves (in algebraic notation) to a board position.

# Definitions

• Position [a-h][1-8]: Given by appending the row (file) and the column (rank). Defines one of the 64 possible positions on the board.
• Piece[KQRBNP]?: Represents the King, Queen, Rook, Bishop, KNight, Pawn. In algebraic notation, P is not used. When used on a board, letters are uppercase if they are White, otherwise lowercase.
• Move [KQRBN]?[a-h]?[1-8]?x?[a-h][1-8](=[KQRBN])?(+*?)?|O-O(-O): A piece followed by the position it is moving to.
• If the piece is ambiguous, then the row, or the column, or both are given.
• If the piece is capturing a piece, then x is placed between the piece and the position.
• If the move is a castling, then O-O is given for king-side, otherwise O-O-O.
• If a pawn is being promoted, the move is appended with = followed by the piece it is being promoted to.
• If a move puts the king in check, it is appended with a +.
• If a move puts the king in checkmate, its appended with #.
• The color of the piece is determined by the turn number (White and black alternate turns, starting with black.)
• Board(([1-8]|[KQRBNPkqrbnp])*\/){8}: Rows are given by listing the pieces in row order. If there are empty squares, each run of empty square is given using the length of the run. Rows are separated using /

A board's initial position is rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR, which represents:

rnbqkbnr
pppppppp

PPPPPPPP
RNBQKBNR


You need to take a list of Moves and return a Board. You can assume that your input is valid.

# Examples

                     -> rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR
e4                   -> rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR
e4,c5                -> rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR
e4,d5,exd5,e5        -> rnbqkbnr/ppp2ppp/8/3Pp3/8/8/PPPP1PPP/RNBQKBNR
e4,d5,exd5,e5,dxe6   -> rnbqkbnr/ppp2ppp/4P3/8/8/8/PPPP1PPP/RNBQKBNR
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4 -> r1bqk2r/ppp2pp1/4Pn2/2P4p/6nP/8/PPP2PPN/RNBQKB1R
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4 -> r1bqk2r/ppp2pp1/4P3/2P4p/3Q2nP/6P1/PPP2n1N/RNB1KB1R
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4,O-O -> r1bq1rk1/ppp2pp1/4P3/2P4p/3Q1BnP/6P1/PPP2n1N/RN2KB1R
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4,O-O,Na3,Nxh1,O-O-O,Qg5,exf7+ -> r1b2rk1/ppp2Pp1/8/2P3qp/3Q1BnP/N5P1/PPP4N/2KR1B1n
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4,O-O,Na3,Nxh1,O-O-O,Qg5,exf7+,Kh7,Bxg5,Rd8,f8=Q -> r1br1Q2/ppp3pk/8/2P3Bp/3Q2nP/N5P1/PPP4N/2KR1B1n
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4,O-O,Na3,Nxh1,O-O-O,Qg5,exf7+,Kh7,Bxg5,Rd8,f8=Q,Ngf2,c6,Rd7,cxd7,b6,d8=Q,c6,Q4d6,Ba6,Qd8f6 -> r4Q2/p5pk/bppQ1Q2/6Bp/7P/N5P1/PPP2n1N/2KR1B1n
e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4,O-O,Na3,Nxh1,O-O-O,Qg5,exf7+,Kh7,Bxg5,Rd8,f8=Q,Ngf2,c6,Rd7,cxd7,b6,d8=Q,c6,Q4d6,Ba6,Qd8f6,Rb8,Qdd8,b5,Qc5,b4,Qxb8,bxa3,Rd3,Nxd3+,Kd1,axb2,Bh3,b1=Q+,Kd2,Qxa2,Qh6+,gxh6,Qcd6,Qa1,Qbc7+,Kh8,Qdd8# -> 3Q3k/p1Q5/b1p4p/6Bp/7P/3n2PB/2PK3N/q6n


This is a , so make your answers as short as possible!

• So no en passant :p? Aug 12, 2016 at 16:54
• @Adnan I believe that my test cases include an en passant. Aug 12, 2016 at 16:55
• Oh sorry, I didn't see that. I'm always used to notate en passant moves with e.p.. Aug 12, 2016 at 16:59
• May we take the moves separated by spaces instead?
– orlp
Aug 12, 2016 at 21:32
• Of course. Any list format is acceptable. Aug 12, 2016 at 21:32

## Javascript (ES6), 1024 995 bytes

This is an early and still bulky attempt. I just stopped optimizing it when the 1K limit was reached.

It's probably not bullet-proof and only considers promotions to a Queen. But it does pass the test case.

Edit: 995 bytes - a few obvious optimizations

Source

F=i=>{B=[];b=0;X=[8,2,4,12,16,4,2,8,1];for(n=120;n--;B[n]=n<8?X[n]|32:n<24?33:n>111?X[n-112]
:n>95|0);Y=j=>(M[j]?M[j].charCodeAt(0)-97:8)|(M[++j]?(8-M[j])*16:128);G=_=>(F&8||!(F&7^f&7))
&&(F&128||!(F&112^f&112))&&B[f]==p;Z=d=>{for(k=f,u=1;(k+=d)!=T;)u&=!B[k]};Q=(j,...D)=>D.some
(d=>(j&2?!((f-T)%d)&&(Z(f<T?d:-d),u):T-f==d||(j&&f-T==d))&&(S=f));i.split(',').forEach(m=>{
if(m[0]=='O'){S=b?4:116;m[4]?(T=S-2,B[S-1]=B[S-4],B[S-4]=0):(T=S+2,B[S+1]=B[S+3],B[S+3]=0)}
else{M=m.match(/([B-R])?([a-h])?(\d)?x?([a-h])?(\d)?(=Q)?/);p=X["QKBNRP".indexOf(M[1]||'P')+
3]|b;F=Y(2);M[4]?T=Y(4):(T=F,F=136);for(f=120,S=0;f--;)G()&&(p&4&&Q(2,15,17),p&8&&Q(2,1,16),
p&2&&Q(1,14,18,31,33),p&16&&Q(1,1,15,16,17),p&1&&Q(0,b-16,2*b-32));for(f=120;p&1&&!S&&f--;)
G()&&Q(0,b-15,b-17);B[S]&1&&(S-T)%16&&!B[T]&&(B[T+16-b]=0)}B[T]=B[S];B[S]=0;M[6]&&(B[T]^=13)
;b^=32});for(r='',y=0;y<8;y++){for(x=z=0;x<8;x++)(b=B[y*16+x])?(p=".PN.B...R...Q...K"[b&31],
r+=(z||'')+(b&32?p.toLowerCase():p),z=0):z++;r+=(z||'')+(y<7?'/':'')}return r}


Full executable snippet

F=i=>{B=[];b=0;X=[8,2,4,12,16,4,2,8,1];for(n=120;n--;B[n]=n<8?X[n]|32:n<24?33:n>111?X[n-112]:n>95|0);Y=j=>(M[j]?M[j].charCodeAt(0)-97:8)|(M[++j]?(8-M[j])*16:128);G=_=>(F&8||!(F&7^f&7))&&(F&128||!(F&112^f&112))&&B[f]==p;Z=d=>{for(k=f,u=1;(k+=d)!=T;)u&=!B[k]};Q=(j,...D)=>D.some(d=>(j&2?!((f-T)%d)&&(Z(f<T?d:-d),u):T-f==d||(j&&f-T==d))&&(S=f));i.split(',').forEach(m=>{if(m[0]=='O'){S=b?4:116;m[4]?(T=S-2,B[S-1]=B[S-4],B[S-4]=0):(T=S+2,B[S+1]=B[S+3],B[S+3]=0)}else{M=m.match(/([B-R])?([a-h])?(\d)?x?([a-h])?(\d)?(=Q)?/);p=X["QKBNRP".indexOf(M[1]||'P')+3]|b;F=Y(2);M[4]?T=Y(4):(T=F,F=136);for(f=120,S=0;f--;)G()&&(p&4&&Q(2,15,17),p&8&&Q(2,1,16),p&2&&Q(1,14,18,31,33),p&16&&Q(1,1,15,16,17),p&1&&Q(0,b-16,2*b-32));for(f=120;p&1&&!S&&f--;)G()&&Q(0,b-15,b-17);B[S]&1&&(S-T)%16&&!B[T]&&(B[T+16-b]=0)}B[T]=B[S];B[S]=0;M[6]&&(B[T]^=13);b^=32});for(r='',y=0;y<8;y++){for(x=z=0;x<8;x++)(b=B[y*16+x])?(p=".PN.B...R...Q...K"[b&31],r+=(z||'')+(b&32?p.toLowerCase():p),z=0):z++;r+=(z||'')+(y<7?'/':'')}return r}

console.log(F(
"e4,d5,exd5,e5,dxe6,Bc5,Nf3,Nf6,d4,Nc6,dxc5,Ne5,h4,h5,Nh2,Neg4,g3,Nxf2,Qd4,N6g4,Bf4," +
"O-O,Na3,Nxh1,O-O-O,Qg5,exf7+,Kh7,Bxg5,Rd8,f8=Q,Ngf2,c6,Rd7,cxd7,b6,d8=Q,c6,Q4d6,Ba6," +
"Qd8f6,Rb8,Qdd8,b5,Qc5,b4,Qxb8,bxa3,Rd3,Nxd3+,Kd1,axb2,Bh3,b1=Q+,Kd2,Qxa2,Qh6+,gxh6," +
"Qcd6,Qa1,Qbc7+,Kh8,Qdd8#"
));