Skip to content

Comments

Fix en passant square not set by Board::apply_move after double pawn push#165

Merged
chase-manning merged 5 commits intomainfrom
copilot/fix-en-passant-flag
Feb 22, 2026
Merged

Fix en passant square not set by Board::apply_move after double pawn push#165
chase-manning merged 5 commits intomainfrom
copilot/fix-en-passant-flag

Conversation

Copy link
Contributor

Copilot AI commented Feb 22, 2026

Board::apply_move only set the EP square when an opponent pawn could actually capture en passant. The FEN standard requires it to be set after any double pawn push unconditionally.

let mut board = Board::from_fen("r1bqkbnr/pppppppp/2n5/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 1 2").unwrap();
board.apply_move(BitMove::make(BitMove::FLAG_DOUBLE_PAWN, SQ::D2, SQ::D4));
// Before: "... b KQkq - 0 2"
// After:  "... b KQkq d3 0 2"

Changes

  • board/mod.rsapply_move_pft_chk: Always set ep_square after double pawn push. Zobrist XOR remains conditional on capture possibility to preserve correct threefold repetition detection (FIDE: positions match iff possible moves match).
  • board/mod.rs – EP hash XOR-out: Made removal of previous EP from zobrist conditional with the same capture-possibility check, maintaining symmetry with XOR-in.
  • board/mod.rsapply_null_move: Same conditional EP hash treatment.
  • board/board_state.rsset_zob_hash: Conditional EP hash when computing from scratch (e.g. from_fen), ensuring board→FEN→board round-trips produce identical zobrist hashes.
  • tests/board_move_apply.rs: Added regression test from the issue.
Original prompt

This section details on the original issue you should resolve

<issue_title>En passant flag not set by Board::apply_move</issue_title>
<issue_description>Hi

I'm new to Rust and started using the crate pleco for my personal project. Using dependency :

[[package]]
name = "pleco"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28a8c8ab569c544644c468a63f4fe4b33c0706b1472bebb517fabb75ec0f688e"
dependencies = [
 "bitflags 1.3.2",
 "lazy_static",
 "mucow",
 "num_cpus",
 "rand 0.6.5",
 "rayon",
]

While writing a unit test, I noticed that some en-passant flag is lost somewhere during my unit test. Here is a sample unit test :

#[test]
fn test_apply_move_pawn_2() {
    let fen1 = "r1bqkbnr/pppppppp/2n5/8/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 1 2";
    let board1 = Board::from_fen(fen1).unwrap();

    let fen2 = "r1bqkbnr/pppppppp/2n5/8/3PP3/8/PPP2PPP/RNBQKBNR b KQkq d3 0 2";
    let board2 = Board::from_fen(fen2).unwrap();

    let move_to_play = BitMove::make(BitMove::FLAG_DOUBLE_PAWN, SQ::D2, SQ::D4);
    let mut copy = board1.clone();
    copy.apply_move(move_to_play);

    assert_eq!(board2, copy);
    assert_eq!(board2.fen(), copy.fen());
}

When the test is executed, the line assert_eq!(board2.fen(), copy.fen()); would print :

thread 'capture_board::move_detector::test_apply_move_pawn_2' (31976) panicked at src\capture_board\move_detector.rs:239:5:
assertion `left == right` failed
  left: "r1bqkbnr/pppppppp/2n5/8/3PP3/8/PPP2PPP/RNBQKBNR b KQkq d3 0 2"
 right: "r1bqkbnr/pppppppp/2n5/8/3PP3/8/PPP2PPP/RNBQKBNR b KQkq - 0 2"

There we see that the fourth component of the FEN is missing "d3".

My guess is that the function apply_move Board::apply_move is buggy and forgets to set the en passant flag.
If I have some time I'll try to investigate and make a PR.

</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 22, 2026 11:29
Always set the en passant square in board state after a double pawn push
(per FEN standard), but only include it in the zobrist hash when an
opponent pawn can actually capture en passant (for correct threefold
repetition detection per FIDE rules).

Co-authored-by: chase-manning <53957795+chase-manning@users.noreply.github.com>
Co-authored-by: chase-manning <53957795+chase-manning@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix en passant flag not set by Board::apply_move Fix en passant square not set by Board::apply_move after double pawn push Feb 22, 2026
Copilot AI requested a review from chase-manning February 22, 2026 11:34
@chase-manning
Copy link
Contributor

@copilot CI is failing

Copy link
Contributor Author

Copilot AI commented Feb 22, 2026

@copilot CI is failing

The CI failures are all pre-existing issues unrelated to this PR:

  1. Lint job: clippy::mut_from_ref error in pleco/src/tools/tt.rs:366 — this is a pre-existing clippy deny-by-default lint on code not touched by this PR.
  2. Test stable/beta/nightly jobs: implicit autoref creates a reference to the dereference of a raw pointer errors in pleco_engine — also pre-existing, in code not touched by this PR.

I verified by checking that the same errors exist on the base branch (6370f65). All 25 pleco crate tests pass with these changes.

@chase-manning chase-manning marked this pull request as ready for review February 22, 2026 12:19
@chase-manning chase-manning merged commit 83f8953 into main Feb 22, 2026
4 checks passed
@chase-manning chase-manning deleted the copilot/fix-en-passant-flag branch February 22, 2026 12:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

En passant flag not set by Board::apply_move

2 participants