fix: promotion dialog only fires for genuine pawn promotions
The "Promote pawn" dialog popped for any pawn "moved" toward the last rank: the commit paths checked piece type + destination rank but never the pawn's SOURCE rank. With the phantom layer now filling ranks 7-8 with tappable phantom pieces, tapping one (which falls through to the real-move handler) while a real pawn was armed triggered the dialog for a move no pawn could make — and for any phantom type, not just pawns. Root cause: incomplete promotion detection, duplicated in Game.svelte `onCommit` and the server's `isPromotionRequired`. Replaced with one shared `isPromotionMove(piece, from, to)` — pawn, from the rank adjacent to promotion, to the promotion rank, at most one file over — used by both. 7 unit tests in packages/shared. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,3 +3,4 @@ export * from './moderator.js';
|
||||
export * from './protocol.js';
|
||||
export * from './geometric.js';
|
||||
export * from './phantoms.js';
|
||||
export * from './promotion.js';
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { fileIndex, type Piece, type Square } from './types.js';
|
||||
|
||||
/**
|
||||
* True iff moving `piece` from→to is a pawn promotion.
|
||||
*
|
||||
* A promotion is a pawn advancing from the rank adjacent to its promotion rank
|
||||
* onto the promotion rank (7→8 for White, 2→1 for Black), at most one file
|
||||
* over — a straight push or a diagonal capture.
|
||||
*
|
||||
* Checking only the piece type and the destination rank — as the move-commit
|
||||
* paths previously did — wrongly flags e.g. a pawn on the 2nd rank "moved" to
|
||||
* the 8th, popping the promotion dialog for a move no pawn could ever make.
|
||||
*/
|
||||
export function isPromotionMove(
|
||||
piece: Piece | undefined,
|
||||
from: Square,
|
||||
to: Square,
|
||||
): boolean {
|
||||
if (!piece || piece.type !== 'p') return false;
|
||||
if (Math.abs(fileIndex(from) - fileIndex(to)) > 1) return false;
|
||||
if (piece.color === 'w') return from[1] === '7' && to[1] === '8';
|
||||
return from[1] === '2' && to[1] === '1';
|
||||
}
|
||||
Reference in New Issue
Block a user