Engine PR 8.3: en passant — capture generation + applyMove removal #70

Closed
opened 2026-05-16 16:04:14 +00:00 by root · 4 comments
root commented 2026-05-16 16:04:14 +00:00 (Migrated from gitlab.core-project.space)

Imported from GitHub amaurycoudr/chess-project#70, opened by @amaurycoudr on 2026-05-16 16:04 UTC.
Closed on GitHub on 2026-05-16 21:37 UTC as completed.


Parent

#67

What to build

Additive on slice 8.1: the en passant capture. Slice 8.1 already sets the en passant target square on a double push; this slice generates the capture that consumes it and applies the board change.

Implements step 8 (partial) of docs/adr/0004-engine-slice-plan-and-king-first-piece-ordering.md.

  • Extend pseudoLegalPawnMoves in movegen.ts: when a side-to-move pawn attacks position.ep, generate an en passant capture move to that square (even though it is empty).
  • Modify applyMove in rules.ts: detect the en passant capture structurally (a pawn mover moving diagonally onto the empty position.ep square) and remove the enemy pawn from the square behind the destination — not from the destination itself.
  • Extend rules-pawns.test.ts with en passant coverage: capture availability only on the ply after the enabling double push, correct captured-pawn removal, en passant unavailable when no enemy pawn is positioned to take, and the en-passant-discovered-check case (an en passant capture that exposes the mover's own king is rejected by the existing legality filter).

The en-passant-discovered-check case falls out for free once applyMove removes the correct pawn — removing the captured pawn can open a rank for an enemy rook/queen onto the mover's king. It should be covered by an explicit test.

Acceptance criteria

  • pseudoLegalPawnMoves generates an en passant capture when a side-to-move pawn attacks position.ep
  • No en passant capture is generated when position.ep is undefined or no pawn attacks it
  • Game.apply() of an en passant capture moves the capturing pawn to ep and removes the enemy pawn from the square behind the destination
  • The captured-pawn removal is correct for both colors
  • An en passant capture that leaves the mover's king in check (en-passant-discovered-check) is excluded from legalMoves
  • En passant is available only on the ply immediately after the enabling double push (target cleared by any other move — already handled in 8.1, verified here)
  • The halfmove clock resets on an en passant capture
  • Tests follow the rules-knights.test.ts / rules-pawns.test.ts style, written as vertical TDD slices
  • pnpm lint, pnpm typecheck, pnpm test, pnpm build all green from the repo root

Blocked by

  • Blocked by #68
> _Imported from GitHub [amaurycoudr/chess-project#70](https://github.com/amaurycoudr/chess-project/issues/70), opened by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 16:04 UTC._ > _Closed on GitHub on 2026-05-16 21:37 UTC as completed._ <!-- github-issue:70 --> --- ## Parent #67 ## What to build Additive on slice 8.1: the en passant capture. Slice 8.1 already sets the en passant *target* square on a double push; this slice generates the capture that *consumes* it and applies the board change. Implements step 8 (partial) of `docs/adr/0004-engine-slice-plan-and-king-first-piece-ordering.md`. - Extend `pseudoLegalPawnMoves` in `movegen.ts`: when a side-to-move pawn attacks `position.ep`, generate an en passant capture move to that square (even though it is empty). - Modify `applyMove` in `rules.ts`: detect the en passant capture structurally (a pawn mover moving diagonally onto the empty `position.ep` square) and remove the enemy pawn from the square *behind* the destination — not from the destination itself. - Extend `rules-pawns.test.ts` with en passant coverage: capture availability only on the ply after the enabling double push, correct captured-pawn removal, en passant unavailable when no enemy pawn is positioned to take, and the en-passant-discovered-check case (an en passant capture that exposes the mover's own king is rejected by the existing legality filter). The en-passant-discovered-check case falls out for free once `applyMove` removes the correct pawn — removing the captured pawn can open a rank for an enemy rook/queen onto the mover's king. It should be covered by an explicit test. ## Acceptance criteria - [ ] `pseudoLegalPawnMoves` generates an en passant capture when a side-to-move pawn attacks `position.ep` - [ ] No en passant capture is generated when `position.ep` is undefined or no pawn attacks it - [ ] `Game.apply()` of an en passant capture moves the capturing pawn to `ep` and removes the enemy pawn from the square behind the destination - [ ] The captured-pawn removal is correct for both colors - [ ] An en passant capture that leaves the mover's king in check (en-passant-discovered-check) is excluded from `legalMoves` - [ ] En passant is available only on the ply immediately after the enabling double push (target cleared by any other move — already handled in 8.1, verified here) - [ ] The halfmove clock resets on an en passant capture - [ ] Tests follow the `rules-knights.test.ts` / `rules-pawns.test.ts` style, written as vertical TDD slices - [ ] `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build` all green from the repo root ## Blocked by - Blocked by #68
root commented 2026-05-16 17:12:09 +00:00 (Migrated from gitlab.core-project.space)

Imported from a GitHub comment by @amaurycoudr on 2026-05-16 17:12 UTC.

Implemented by Sandcastle on branch sandcastle/sequential-reviewer/1778951121227 — awaiting review. Adds en passant capture generation in pseudoLegalPawnMoves and structural en passant detection in applyMove with correct captured-pawn removal.

> _Imported from a [GitHub comment](https://github.com/amaurycoudr/chess-project/issues/70#issuecomment-4467562226) by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 17:12 UTC._ <!-- github-comment:4467562226 --> Implemented by Sandcastle on branch `sandcastle/sequential-reviewer/1778951121227` — awaiting review. Adds en passant capture generation in pseudoLegalPawnMoves and structural en passant detection in applyMove with correct captured-pawn removal.
root commented 2026-05-16 17:26:55 +00:00 (Migrated from gitlab.core-project.space)

Imported from a GitHub comment by @amaurycoudr on 2026-05-16 17:26 UTC.

Promoted to branch feat/engine-pr-8-1-pawns-pushes-captures-attack-mask-legality-wiring-68 (PR #72), not yet merged to main. A dependent slice should git fetch origin feat/engine-pr-8-1-pawns-pushes-captures-attack-mask-legality-wiring-68 and branch off it.

> _Imported from a [GitHub comment](https://github.com/amaurycoudr/chess-project/issues/70#issuecomment-4467607556) by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 17:26 UTC._ <!-- github-comment:4467607556 --> Promoted to branch `feat/engine-pr-8-1-pawns-pushes-captures-attack-mask-legality-wiring-68` (PR #72), not yet merged to main. A dependent slice should `git fetch origin feat/engine-pr-8-1-pawns-pushes-captures-attack-mask-legality-wiring-68` and branch off it.
root (Migrated from gitlab.core-project.space) closed this issue 2026-05-16 21:37:08 +00:00
root commented 2026-10-13 08:38:30 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #71

mentioned in issue #71
root commented 2026-10-13 10:20:25 +00:00 (Migrated from gitlab.core-project.space)

mentioned in commit 89bdac7e03

mentioned in commit 89bdac7e03fd3bafb79b401b9ad21f28c82c59ac
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
amaurycoudr/chess-project#70
No description provided.