Explosions on a chessboard

14

Atomic chess is a (very fun) variant of chess in which every capture causes an "explosion," destroying the captured piece, the piece doing the capturing, and all non-pawns in a 1-square radius. The goal of this challenge is not to play an entire game of atomic chess, but simply to simulate what happens when a certain move is made.

Disclaimer: Explosion sound effects not included.

Input

Board position will be given in Forsyth-Edwards Notation (commonly known as FEN), but with only the first field. For example, an input of:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR

represents the starting position:

Chess starting position.

This must be taken as a string or your language's equivalent. It is guaranteed to be valid; for example, you don't have to care if there are ten kings, or if there is no king at all.

You will also be given the move that you are to simulate, which is represented as two square names: the square on which the piece to be moved is, and the square it is moving to. For example, moving the king's pawn two spaces forwards on the above picture would be represented as:

e2e4

This must also be taken as a string. The move will always be valid, and you do not need to support castling. You do need to support en passant, which will be explained in further detail in the next section.

Output

The output of your program should be in the same partial-FEN notation as the input, with the specified move made (and any pieces exploded if necessary).

The exact rules for explosions are—when a piece is captured:

  • Remove the piece being captured (this will always be the piece on the second square named in the input, except for when the capture is an en passant).

  • Remove the piece that is doing the capturing (this will always be the piece on the first square named in the input).

  • Remove every piece that is:

    • located on one of the 8 squares surrounding the one where the capture took place (for en passant, this is the square that the capturing pawn would be on, if it didn't explode).

    • not a pawn.

Quick overview of en passant rules, for those who are unfamiliar: if a pawn moves two spaces forwards from its starting rank, and there is a pawn that could have captured it if it only moved one square forward, it may capture it anyway, but only on the subsequent move. This capture is said to be done "in passing" (or in French: "en passant").

Test cases

In the pictures, the green arrows represet the move about to be made, and the green circles represents pieces that are exploded.

Input: rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR, g1f3
Output: rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R
Test case 1.


Input: 3kBb1r/pp5p/3p4/4pn2/P7/1P2P1pP/2rP1P2/R1B3RK, f2g3
Output: 3kBb1r/pp5p/3p4/4pn2/P7/1P2P2P/2rP4/R1B3RK
Test case 2.
(stolen from http://en.lichess.org/ocoSfS5I/white#36)


Input: rnbqk1nr/1pp5/p2pp1pp/5p2/1bN5/2P1PQ1N/PP1P1PPP/R1B1KB1R, f3b7
Output: 3qk1nr/2p5/p2pp1pp/5p2/1bN5/2P1P2N/PP1P1PPP/R1B1KB1R
Test case 3.
(stolen from http://en.lichess.org/NCUnA6LV/white#14)


Input: rnbqk2r/pp2p2p/2p3pb/3pP3/5P2/2N5/PPPP2P1/R1BQKB1R, e5d6
Output: rnbqk2r/pp2p2p/2p3pb/8/5P2/2N5/PPPP2P1/R1BQKB1R
Test case 4.
(stolen from http://en.lichess.org/AvgU4Skq/white#16; this wasn't the actual move, but I couldn't be bothered to find an atomic game that actually had en passant :P)


Input: 5r2/2k5/p1B5/1pP1p3/1P4P1/3P4/P7/1K3R1q, c6h1
Output: 5r2/2k5/p7/1pP1p3/1P4P1/3P4/P7/1K3R2
Test case 5.
(stolen from http://en.lichess.org/l77efXEb/white#58)

Scoring

This is , so the shortest code in bytes wins.

Doorknob

Posted 2015-06-23T11:27:37.797

Reputation: 68 138

So... taking a piece with your king is a bad idea? – mbomb007 – 2015-06-23T18:26:39.287

@mbomb007 You are not allowed to take pieces with your king. :P – Doorknob – 2015-06-23T21:07:47.140

I might be mistaken, but how are we supposed to know if the en passant capture is possible? In your example the last move is denoted by the empty green square, so the black pawned can be captured en passant. But this information is not contained in the inputs we are given, so it is possible to have the exact same board but where the en passant capture is not possible, because the last move was not a two spaces forward move. – Fatalize – 2015-06-24T12:50:12.170

1@Fatalize "The move will always be valid" - from the "Input" section. – Doorknob – 2015-06-24T12:51:50.703

Complete program or function? – edc65 – 2015-06-24T13:39:06.133

@edc65 http://meta.codegolf.stackexchange.com/a/2422/3808

– Doorknob – 2015-06-24T22:24:34.043

As I submitted a function, happy to use the default. Asking because you explicitly said "your program..." – edc65 – 2015-06-24T22:29:34.117

+1 for "Explosion sound effects not included" – SuperJedi224 – 2015-11-14T02:34:45.243

Answers

5

JavaScript (ES6) 305 310 321

As a function with 2 real parameters (and a lot more with default values, used as a quick and dirty way to define locals)

Test running the snippet below (being EcmaScript 6, Firefox only)

F=(g,m,b=[...g.replace(/\d/g,c=>'0'.repeat(c))],P=p=>p=='p'|p=='P',n=parseInt(m,32),
  s=n>>5&31,u=n>>15,x=b[y=u+62-(n>>10&31)*9])=>(
  b[b[y]=0,z=s+62-(n&31)*9]<1&!(s!=u&P(x))?b[z]=x:
  [-1,1,8,9,10,-8,-9,-10].map(i=>b[i+=z]>'/'&&!P(b[i])?b[i]=0:0,b[b[z]<1?z>y?z-9:z+9:z]=0),
  b.join('').replace(/0+/g,x=>x.length)
)

//TEST
out=x=>O.innerHTML+=x+'\n'

test=[
 ['rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR', 'g1f3'
  ,'rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R']
,['3kBb1r/pp5p/3p4/4pn2/P7/1P2P1pP/2rP1P2/R1B3RK', 'f2g3'
  ,'3kBb1r/pp5p/3p4/4pn2/P7/1P2P2P/2rP4/R1B3RK']  
,['rnbqk1nr/1pp5/p2pp1pp/5p2/1bN5/2P1PQ1N/PP1P1PPP/R1B1KB1R', 'f3b7'
  ,'3qk1nr/2p5/p2pp1pp/5p2/1bN5/2P1P2N/PP1P1PPP/R1B1KB1R']
,['rnbqk2r/pp2p2p/2p3pb/3pP3/5P2/2N5/PPPP2P1/R1BQKB1R', 'e5d6'
  ,'rnbqk2r/pp2p2p/2p3pb/8/5P2/2N5/PPPP2P1/R1BQKB1R']
,['5r2/2k5/p1B5/1pP1p3/1P4P1/3P4/P7/1K3R1q', 'c6h1'
  ,'5r2/2k5/p7/1pP1p3/1P4P1/3P4/P7/1K3R2']
]

test.forEach(t=>( 
  r=F(t[0],t[1]), 
  out('Test '+(r==t[2]?'Ok':'Fail!')+'  '+t[0]+' move '+t[1]
     +'\nResult   '+r+'\nExpected '+t[2]+'\n')))
<pre id=O></pre>

Ungolfed

B=(b,m)=>{
  P=p=>p=='p'|p=='P'
  m=parseInt(m,32) 
  r=m&31 // arrival row
  s=(m/32&31)-10 // arrival column
  z=s+(8-r)*9 // arrival position
  t=m/32/32&31 // start row
  u=(m/32/32/32&31)-10 // start column
  y=u+(8-t)*9 // start position
  b=[...b.replace(/\d/g,c=>'0'.repeat(c))] // board to array, empty squares as 0
  x=b[y] // moving piece
  b[y]=0 
  C=s!=u&P(x) // pawn capture
  if (b[z]<1 && !C)
  {  // no capture
    b[z]=x
  }
  else
  {
    // capture and boom!
    if (b[z]<1) // arrival empty: en passant
      b[z>y?z-9:z+9]=0;
    else
      b[z]=0;
    // zero to nearest 8 squares
    [-1,1,8,9,10,-8,-9,-10].forEach(i=>b[i+=z]>'/'&&!P(b[i])?b[i]=0:0)
  }
  return b.join('').replace(/0+/g,x=>x.length)
}

edc65

Posted 2015-06-23T11:27:37.797

Reputation: 31 086

1Wow, that looks a lot simpler than my solution... Nice job! – cmxu – 2015-06-24T17:39:56.123

2

Java, (946 777 776 chars)

1 char thanks to @edc65

Note: Chars counted without test cases put in.

Code

class E{public static void main(String[]a){String i=a[0];char[]n=a[1].toCharArray();int j,k,z,w,y,u=56-n[3];char q,p,e ='e';char[][]b=new char[8][8];String[]r=i.split("/");for(j=0;j<8;j++){z=0;for(k=0;k<r[j].length();k++){p=r[j].charAt(k);if(Character.isDigit(p)){for(int l=k+z;l<k+z+p-48;l++)b[j][l]=e;z+=p-49;}else b[j][k+z]=p;}}z=n[0]-97;w=56-n[1];y=n[2]-97;p=b[w][z];q=b[u][y];b[w][z]=e;if(q!=e||((p|32)=='p'&&(w-u<0?u-w:w-u)==1&&(z-y<0?y-z:z-y)==1)){if(q!=e)b[u][y]=e;else b[w][y]=e;for(j=y-(y==0?0:1);j<y+(y==8?0:y==7?1:2);j++){for(k=u-(u==0?0:1);k<u+(u==8?0:u==7?1:2);k++)if((b[k][j]|32)!='p')b[k][j]=e;}}else b[u][y]=p;i="";for(j=0;j<8;j++){z=0;for(k=0;k<8;k++){if(b[j][k]==e)z++;else {if(z>0){i+=z;z=0;}i+=b[j][k];}}if(z>0)i+=z;i+=j!=7?"/":"";}System.out.print(i);}}

I'm not sure if this solution is optimal, but I'm working on golfing it more, any suggestions are welcome. I can comment all the code too if anyone would like, but I think it's mostly self explanatory, except for the confusing variable enumeration.

Explanation

  • Unpack the board string into a char matrix
  • Calculate the effect of the move
  • Repack the board into a string

Expanded

class ExplosionChess{
    public static void main(String[]a){
        String i=a[0];
        //"rnbqk1nr/1pp5/p2pp1pp/5p2/1bN5/2P1PQ1N/PP1P1PPP/R1B1KB1R";
        //"f3b7";
        char[]n=a[1].toCharArray();
        int j,k,z,w,y,u=56-n[3];
        char q,p,e ='e';
        char[][]b=new char[8][8];
        String[]r=i.split("/");
        for(j=0;j<8;j++){
            z=0;
            for(k=0;k<r[j].length();k++){
                p=r[j].charAt(k);
                if(Character.isDigit(p)){
                    for(int l=k+z;l<k+z+p-48;l++)
                        b[j][l]=e;
                    z+=p-49;
                }else 
                    b[j][k+z]=p;
            }
        }
        z=n[0]-97;
        w=56-n[1];
        y=n[2]-97;
        p=b[w][z];
        q=b[u][y];
        b[w][z]=e;
        if(q!=e||((p|32)=='p'&&(w-u<0?u-w:w-u)==1&&(z-y<0?y-z:z-y)==1)){
            if(q!=e)
                b[u][y]=e;
            else
                b[w][y]=e;
            for(j=y-(y==0?0:1);j<y+(y==8?0:y==7?1:2);j++){
                for(k=u-(u==0?0:1);k<u+(u==8?0:u==7?1:2);k++)
                    if((b[k][j]|32)!='p')
                        b[k][j]=e;
            }
        }else 
            b[u][y]=p;
        i="";
        for(j=0;j<8;j++){
            z=0;
            for(k=0;k<8;k++){
                if(b[j][k]==e)
                    z++;
                else {
                    if(z>0){
                        i+=z;
                        z=0;
                    }
                    i+=b[j][k];
                }
            }
            if(z>0)
                i+=z;
            i+=j!=7?"/":"";
        }
        System.out.print(i);
    }
}

Old

class E{public static void main(String[]a){String m,i="rnbqk1nr/1pp5/p2pp1pp/5p2/1bN5/2P1PQ1N/PP1P1PPP/R1B1KB1R";m="f3b7";char[]n=m.toCharArray();int z,w,y,u=56-n[3];z=n[0]-97;w=56-n[1];y=n[2]-97;char e='e';char[][]b=new char[8][8];String[]r=i.split("/");for(int j=0;j<8;j++){int o=0;for(int k=0;k<r[j].length();k++){char q=r[j].charAt(k);if(Character.isDigit(q)){for(int l=k+o;l<k+o+q-48;l++){b[j][l]=e;}o+=q-49;}else b[j][k+o]=q;}}char q,p=b[w][z];q=b[u][y];b[w][z]=e;if(q==e){if((p|32)=='p'&&(w-u<0?u-w:w-u)==1&&(z-y<0?y-z:z-y)==1){b[w][y]=e;for(int j=y-(y==0?0:1);j<y+(y==8?0:y==7?1:2);j++){for(int k=u-(u==0?0:1);k<u+(u==8?0:u==7?1:2);k++){if((b[k][j]|32)!='p')b[k][j]=e;}}}else{b[u][y]=p;}}else{b[u][y]=e;for(int j=y-(y==0?0:1);j<y+(y==8?0:y==7?1:2);j++){for(int k=u-(u==0?0:1);k<u+(u==8?0:u==7?1:2);k++){if((b[k][j]|32)!='p')b[k][j]=e;}}}i="";for(int j=0;j<8;j++){int x=0;for(int k=0;k<8;k++){if(b[j][k]==e)x++;else{if(x>0){i+=x;x=0;}i+=b[j][k];}}if(x>0)i+=x;i+=j!=7?"/":"";}System.out.println(i);}}

cmxu

Posted 2015-06-23T11:27:37.797

Reputation: 329

String m,i="";m="";char[]n=m.toCharArray() --> String i=a[0];char[]n=a[1].toCharArray() is shorter and so you get the parameters from outside (as you should anyway) – edc65 – 2015-06-24T17:41:10.390

Ahh, okay I'll change that, thanks! – cmxu – 2015-06-24T17:44:23.030