Engine PR 8.1: pawns — pushes, captures, attack mask, legality wiring #68

Closed
opened 2026-05-16 16:03:48 +00:00 by root · 5 comments
root commented 2026-05-16 16:03:48 +00:00 (Migrated from gitlab.core-project.space)

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


Parent

#67

What to build

Make pawns a playable piece end-to-end through the public Game API, for all positions where no pawn reaches the last rank. This is the base pawn tracer bullet: attack mask → pseudo-legal generation (non-capturing pushes + diagonal captures) → applyMove en-passant-target lifecycle → legality wiring.

Promotion (slice 8.2) and en passant capture (slice 8.3) are deliberately out of scope and additive. To avoid leaking illegal moves, this slice does not generate pawn moves onto the last rank — a last-rank pawn move with no promotion field is illegal, so omitting it (an absent legal move) is correct here; 8.2 adds it back as a promotion expansion.

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

  • Add pawnAttacks(square, color) to attacks.ts — the (up to two) diagonal squares a pawn of the given color attacks. Color-dependent, unlike kingAttacks/knightAttacks. Models attacks only; non-capturing pushes are not attacks.
  • Add pseudoLegalPawnMoves(position) to movegen.ts — single push (square ahead empty), double push (from the starting rank, both intermediate and destination squares empty), and diagonal captures (pawnAttacks intersected with enemy pieces). Excludes any move landing on the last rank.
  • Modify applyMove in rules.ts: on a double push set the next position's ep to the skipped-over square; on every other move keep ep cleared.
  • Add the pawn clause to the superpiece isAttacked in rules.ts — pawnAttacks(target, byColor) intersected with the enemy pawn set.
  • legalMoves aggregates king + knight + slider + pawn candidates, then runs the existing legality filter unchanged.
  • Add rules-pawns.test.ts (pawn geometry, push blocking, double-push rules, captures, pinned-pawn legality, pawn-delivered mate, applyMove ep-target and halfmove-clock effects), following the rules-knights.test.ts style.

makePosition in test-fixtures.ts already accepts whitePawns/blackPawns/ep — no fixture change needed.

Acceptance criteria

  • pawnAttacks returns the correct diagonal targets for white (toward rank 8) and black (toward rank 1), truncated at the a/h files
  • Game.legalMoves() includes pawn single pushes when the square ahead is empty
  • A pawn on its starting rank offers a double push only when both the intermediate and destination squares are empty; a pawn off its starting rank never offers a double push
  • A pawn push is excluded when the square ahead is occupied by any piece (no forward capture)
  • Pawn diagonal captures onto enemy-occupied squares are generated; diagonals onto empty or friendly-occupied squares are excluded
  • No pawn move onto the last rank is generated (deferred to 8.2)
  • Game.apply() of a double push sets ep to the skipped-over square; every other move clears ep
  • The halfmove clock resets on every pawn move and increments on quiet non-pawn moves
  • isAttacked returns true when an enemy pawn attacks the square along its diagonal; a king cannot move onto a pawn-attacked square
  • Pawn moves leaving the mover's king in check (absolutely pinned pawns) are excluded
  • Game.status() returns checkmate on a pawn-delivered mate, ongoing whenever a legal pawn move exists
  • Pawn moves carry no promotion field; from is the pawn's origin
  • Tests follow the rules-knights.test.ts style (behavioural assertions, algebraicTargets), written as vertical TDD slices
  • pnpm lint, pnpm typecheck, pnpm test, pnpm build all green from the repo root
> _Imported from GitHub [amaurycoudr/chess-project#68](https://github.com/amaurycoudr/chess-project/issues/68), opened by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 16:03 UTC._ > _Closed on GitHub on 2026-05-16 21:37 UTC as completed._ <!-- github-issue:68 --> --- ## Parent #67 ## What to build Make pawns a playable piece end-to-end through the public `Game` API, for all positions where no pawn reaches the last rank. This is the base pawn tracer bullet: attack mask → pseudo-legal generation (non-capturing pushes + diagonal captures) → `applyMove` en-passant-target lifecycle → legality wiring. Promotion (slice 8.2) and en passant *capture* (slice 8.3) are deliberately out of scope and additive. To avoid leaking illegal moves, this slice does **not** generate pawn moves onto the last rank — a last-rank pawn move with no `promotion` field is illegal, so omitting it (an absent legal move) is correct here; 8.2 adds it back as a promotion expansion. Implements step 8 (partial) of `docs/adr/0004-engine-slice-plan-and-king-first-piece-ordering.md`. - Add `pawnAttacks(square, color)` to `attacks.ts` — the (up to two) diagonal squares a pawn of the given color attacks. Color-dependent, unlike `kingAttacks`/`knightAttacks`. Models *attacks* only; non-capturing pushes are not attacks. - Add `pseudoLegalPawnMoves(position)` to `movegen.ts` — single push (square ahead empty), double push (from the starting rank, both intermediate and destination squares empty), and diagonal captures (`pawnAttacks` intersected with enemy pieces). Excludes any move landing on the last rank. - Modify `applyMove` in `rules.ts`: on a double push set the next position's `ep` to the skipped-over square; on every other move keep `ep` cleared. - Add the pawn clause to the superpiece `isAttacked` in `rules.ts` — `pawnAttacks(target, byColor)` intersected with the enemy pawn set. - `legalMoves` aggregates king + knight + slider + pawn candidates, then runs the existing legality filter unchanged. - Add `rules-pawns.test.ts` (pawn geometry, push blocking, double-push rules, captures, pinned-pawn legality, pawn-delivered mate, `applyMove` ep-target and halfmove-clock effects), following the `rules-knights.test.ts` style. `makePosition` in `test-fixtures.ts` already accepts `whitePawns`/`blackPawns`/`ep` — no fixture change needed. ## Acceptance criteria - [ ] `pawnAttacks` returns the correct diagonal targets for white (toward rank 8) and black (toward rank 1), truncated at the a/h files - [ ] `Game.legalMoves()` includes pawn single pushes when the square ahead is empty - [ ] A pawn on its starting rank offers a double push only when both the intermediate and destination squares are empty; a pawn off its starting rank never offers a double push - [ ] A pawn push is excluded when the square ahead is occupied by any piece (no forward capture) - [ ] Pawn diagonal captures onto enemy-occupied squares are generated; diagonals onto empty or friendly-occupied squares are excluded - [ ] No pawn move onto the last rank is generated (deferred to 8.2) - [ ] `Game.apply()` of a double push sets `ep` to the skipped-over square; every other move clears `ep` - [ ] The halfmove clock resets on every pawn move and increments on quiet non-pawn moves - [ ] `isAttacked` returns true when an enemy pawn attacks the square along its diagonal; a king cannot move onto a pawn-attacked square - [ ] Pawn moves leaving the mover's king in check (absolutely pinned pawns) are excluded - [ ] `Game.status()` returns `checkmate` on a pawn-delivered mate, `ongoing` whenever a legal pawn move exists - [ ] Pawn moves carry no `promotion` field; `from` is the pawn's origin - [ ] Tests follow the `rules-knights.test.ts` style (behavioural assertions, `algebraicTargets`), written as vertical TDD slices - [ ] `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build` all green from the repo root
root commented 2026-05-16 16:42:22 +00:00 (Migrated from gitlab.core-project.space)

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

Implemented by Sandcastle on branch sandcastle/sequential-reviewer/1778948706723 — awaiting review. Adds pawnAttacks, pseudoLegalPawnMoves, ep-target lifecycle in applyMove, and pawn clause in isAttacked.

> _Imported from a [GitHub comment](https://github.com/amaurycoudr/chess-project/issues/68#issuecomment-4467473569) by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 16:42 UTC._ <!-- github-comment:4467473569 --> Implemented by Sandcastle on branch `sandcastle/sequential-reviewer/1778948706723` — awaiting review. Adds pawnAttacks, pseudoLegalPawnMoves, ep-target lifecycle in applyMove, and pawn clause in isAttacked.
root commented 2026-05-16 17:26:52 +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/68#issuecomment-4467607447) by [@amaurycoudr](https://github.com/amaurycoudr) on 2026-05-16 17:26 UTC._ <!-- github-comment:4467607447 --> 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:29 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #69

mentioned in issue #69
root commented 2026-10-13 08:38:29 +00:00 (Migrated from gitlab.core-project.space)

mentioned in issue #70

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

mentioned in commit a6d484cae5

mentioned in commit a6d484cae544d6b6b2f1ed72198c804ff9c7121c
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#68
No description provided.