/** * @file Helpers.js * @description Utility helper functions * @author Implementation Team */ import { BOARD_SIZE, FILES, RANKS, COLORS } from './Constants.js'; /** * Check if a position is within board boundaries * * @param {number} row - Row coordinate (0-7) * @param {number} col - Column coordinate (0-7) * @returns {boolean} True if position is valid */ export function isValidPosition(row, col) { return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE; } /** * Convert position to algebraic notation * * @param {number} row - Row coordinate (0-7) * @param {number} col - Column coordinate (0-7) * @returns {string} Algebraic notation (e.g., "e4") * * @example * positionToAlgebraic(7, 4); // "e1" * positionToAlgebraic(0, 0); // "a8" */ export function positionToAlgebraic(row, col) { return FILES[col] + RANKS[row]; } /** * Convert algebraic notation to position * * @param {string} notation - Algebraic notation (e.g., "e4") * @returns {{row: number, col: number}} Position object * * @example * algebraicToPosition("e4"); // {row: 4, col: 4} */ export function algebraicToPosition(notation) { const file = notation[0]; const rank = notation[1]; return { row: RANKS.indexOf(rank), col: FILES.indexOf(file) }; } /** * Get opposite color * * @param {string} color - 'white' or 'black' * @returns {string} Opposite color */ export function getOppositeColor(color) { return color === COLORS.WHITE ? COLORS.BLACK : COLORS.WHITE; } /** * Deep clone a 2D array * * @param {Array} arr - 2D array to clone * @returns {Array} Cloned array */ export function deepClone2DArray(arr) { return arr.map(row => row.map(cell => { if (cell && typeof cell === 'object' && cell.clone) { return cell.clone(); } return cell; })); } /** * Check if two positions are equal * * @param {{row: number, col: number}} pos1 - First position * @param {{row: number, col: number}} pos2 - Second position * @returns {boolean} True if positions are equal */ export function positionsEqual(pos1, pos2) { return pos1.row === pos2.row && pos1.col === pos2.col; } /** * Calculate distance between two positions * * @param {{row: number, col: number}} pos1 - First position * @param {{row: number, col: number}} pos2 - Second position * @returns {number} Distance (Chebyshev distance) */ export function getDistance(pos1, pos2) { return Math.max( Math.abs(pos1.row - pos2.row), Math.abs(pos1.col - pos2.col) ); } /** * Check if two positions are on the same diagonal * * @param {{row: number, col: number}} pos1 - First position * @param {{row: number, col: number}} pos2 - Second position * @returns {boolean} True if on same diagonal */ export function onSameDiagonal(pos1, pos2) { return Math.abs(pos1.row - pos2.row) === Math.abs(pos1.col - pos2.col); } /** * Check if two positions are on the same row or column * * @param {{row: number, col: number}} pos1 - First position * @param {{row: number, col: number}} pos2 - Second position * @returns {boolean} True if on same row or column */ export function onSameRowOrColumn(pos1, pos2) { return pos1.row === pos2.row || pos1.col === pos2.col; } /** * Get direction between two positions * * @param {{row: number, col: number}} from - Starting position * @param {{row: number, col: number}} to - Ending position * @returns {{row: number, col: number}|null} Direction vector or null */ export function getDirection(from, to) { const rowDiff = to.row - from.row; const colDiff = to.col - from.col; if (rowDiff === 0 && colDiff === 0) { return null; } return { row: rowDiff === 0 ? 0 : rowDiff / Math.abs(rowDiff), col: colDiff === 0 ? 0 : colDiff / Math.abs(colDiff) }; } /** * Debounce function to limit execution rate * * @param {Function} func - Function to debounce * @param {number} wait - Wait time in milliseconds * @returns {Function} Debounced function */ export function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } /** * Throttle function to limit execution frequency * * @param {Function} func - Function to throttle * @param {number} limit - Time limit in milliseconds * @returns {Function} Throttled function */ export function throttle(func, limit) { let inThrottle; return function executedFunction(...args) { if (!inThrottle) { func(...args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; } /** * Generate unique ID * * @returns {string} Unique identifier */ export function generateId() { return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; } export default { isValidPosition, positionToAlgebraic, algebraicToPosition, getOppositeColor, deepClone2DArray, positionsEqual, getDistance, onSameDiagonal, onSameRowOrColumn, getDirection, debounce, throttle, generateId };