/** * @file knight-king-pattern.js * @description Pattern for implementing non-sliding pieces (Knight, King) * These pieces jump to specific positions */ import Piece from '../models/Piece.js'; import { DIRECTIONS } from '../utils/Constants.js'; import { isValidPosition } from '../utils/Helpers.js'; /** * @class Knight * @extends Piece * @description Knight implementation using jump pattern * * Knight moves in L-shape: 2 squares in one direction, 1 square perpendicular * Can jump over other pieces */ class Knight extends Piece { constructor(color, position) { super(color, position, 'knight'); } /** * Gets all valid moves for this knight * * @param {Board} board - Current board state * @returns {Array} Array of valid positions */ getValidMoves(board) { const moves = []; const { row, col } = this.position; // Knight has 8 possible L-shaped moves const knightMoves = DIRECTIONS.KNIGHT; // Check each possible move for (const move of knightMoves) { const newPos = { row: row + move.row, col: col + move.col }; // Check if position is valid (on board) if (!isValidPosition(newPos.row, newPos.col)) { continue; } const piece = board.getPieceAt(newPos); // Can move to empty square or capture enemy if (!piece || piece.color !== this.color) { moves.push(newPos); } } return moves; } clone() { const clone = new Knight(this.color, { ...this.position }); clone.hasMoved = this.hasMoved; return clone; } } /** * @class King * @extends Piece * @description King implementation using adjacent square pattern * * King moves one square in any direction * Special move: Castling (handled separately) */ class King extends Piece { constructor(color, position) { super(color, position, 'king'); } /** * Gets all valid moves for this king * * @param {Board} board - Current board state * @returns {Array} Array of valid positions */ getValidMoves(board) { const moves = []; const { row, col } = this.position; // King can move one square in 8 directions const directions = [...DIRECTIONS.ORTHOGONAL, ...DIRECTIONS.DIAGONAL]; // Check each adjacent square for (const direction of directions) { const newPos = { row: row + direction.row, col: col + direction.col }; // Check if position is valid if (!isValidPosition(newPos.row, newPos.col)) { continue; } const piece = board.getPieceAt(newPos); // Can move to empty square or capture enemy if (!piece || piece.color !== this.color) { moves.push(newPos); } } // TODO: Add castling moves // Only if king hasn't moved // Only if rook hasn't moved // Only if squares between are empty // Only if king is not in check // Only if king doesn't pass through check // See castling example in special-moves.js return moves; } /** * Checks if king can castle kingside * * @param {Board} board - Current board state * @returns {boolean} True if kingside castling is legal */ canCastleKingside(board) { // TODO: Implement castling validation // This is complex and often handled in RuleEngine return false; } /** * Checks if king can castle queenside * * @param {Board} board - Current board state * @returns {boolean} True if queenside castling is legal */ canCastleQueenside(board) { // TODO: Implement castling validation return false; } clone() { const clone = new King(this.color, { ...this.position }); clone.hasMoved = this.hasMoved; return clone; } } /** * PATTERN SUMMARY - NON-SLIDING PIECES: * * Unlike sliding pieces, these pieces: * 1. Have a fixed set of possible moves (no sliding) * 2. Can't be blocked (Knight) or move only 1 square (King) * 3. Check each possible position directly * * Algorithm: * 1. Get all possible move offsets * 2. For each offset: * a. Calculate new position * b. Validate position is on board * c. Check if square is empty or has enemy * d. Add to moves if valid * * DIFFERENCE FROM SLIDING: * - Sliding: Loop until blocked * - Non-sliding: Check each position once * * KNIGHT SPECIAL: * - Only piece that can jump over others * - Don't need to check path, only destination * * KING SPECIAL: * - Must not move into check (validated elsewhere) * - Castling is complex special move * - Usually limited to 8 moves, but critical to protect */ export { Knight, King };