I left out en passant last time. After trying for some time, I came up with a rather ugly way of implementing it(look here). Nevertheless, here is it. We modify the chessboard and move classes as follows:

class move {
public:
    ...
    bool do_enpassant;

    ...
    
    move(bool do_enpassant, std::pair<int, int&gt; init_pos,
         std::pair<int, int&gt; final_pos, int captured_piece) {
        this-&gt;do_enpassant = true;
        this-&gt;init_pos = init_pos;
        this-&gt;final_pos = final_pos;
        this-&gt;captured_piece = captured_piece;
        this-&gt;promoted_piece = BL;
        this-&gt;castle_code = NO_CASTLE;
    } 
};

...

class chessboard {
private:
    ...
    
    bool is_en_passant_allowed, prev_is_en_passant_allowed;
    std::pair<int, int&gt; en_passant_square, prev_en_passant_square;

    ...
};

The do_enpassant boolean in the move class is like the castling enum. Only here it tells us whether the move is an enpassant move or not. The board class carries the enpassant square and whether an enpassant move is allowed in a particular position(both these are determined by whether a pawn moved 2 squares in the previous position or not).

Generating the move is pretty bland:

var_i = i + increment_sign;
var_j = j + 1;
if(is_en_passant_allowed && en_passant_square.first == i
             && en_passant_square.second == var_j) {
    movelist.push_back(move(true, {i, j}, {var_i, var_j}, board[i][var_j]));
}

var_i = i + increment_sign;
var_j = j - 1;
if(is_en_passant_allowed && en_passant_square.first == i 
             && en_passant_square.second == var_j) {
    movelist.push_back(move(true, {i, j}, {var_i, var_j}, board[i][var_j]));
}

We pass the current and final squares along with the pawn that will disappear(that will be captured). Note how this thing is color/side agnostic.

Finally, playing the move, we simply add this line after moving our pawn.

if(m.do_enpassant) {
            board[en_passant_square.first][en_passant_square.second] = BL;
}

This makes the en passant pawn disappear. Note that we have stored in the captured_piece variable to restore it, and this is how we do so:

 if(m.do_enpassant) {
    board[m.final_pos.first][m.final_pos.second] = BL;
    board[en_passant_square.first][en_passant_square.second] = m.captured_piece;
}

That’s pretty self-explanatory. But where are setting the en_passant permissions and square for the game itself. We do so in the make_move function only. If the piece to move is a pawn and has moved 2 squares, we store the final position of the piece as the en passant and square and active the flag as well. Note that unlike castling, we don’t need seperate white and black en passant squares since there can only be 1 such place per turn.

// Set the permissions for en_passant
if((curr_piece == WP || curr_piece == BP) 
        && abs(m.init_pos.first-m.final_pos.first) == 2) {
    is_en_passant_allowed = true;
    en_passant_square = {m.final_pos.first, m.final_pos.second};
}

Take a look at the output here. The sample position contains only 2 pawns for simplicity. Plus to demonstrate the en passant, we play 2 plies deep(a ply is a half move in chess – i.e. white played, black played is a move but only white playing is a ply).

That’s it for today! Next, we’ll see how to filter out moves(I have been saying this for a couple of articles….but we really ARE gonna do that I swear). Well, then..bye 🙂

Advertisements

About the Author Pranav Deshpande

Software Developer interested in AI, Reinforcement Learning and game programming.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s