Restructured project from nested workspace pattern to flat single-repo layout. This eliminates redundant nesting and consolidates all project files under version control. ## Migration Summary **Before:** ``` alex/ (workspace, not versioned) ├── chess-game/ (git repo) │ ├── js/, css/, tests/ │ └── index.html └── docs/ (planning, not versioned) ``` **After:** ``` alex/ (git repo, everything versioned) ├── js/, css/, tests/ ├── index.html ├── docs/ (project documentation) ├── planning/ (historical planning docs) ├── .gitea/ (CI/CD) └── CLAUDE.md (configuration) ``` ## Changes Made ### Structure Consolidation - Moved all chess-game/ contents to root level - Removed redundant chess-game/ subdirectory - Flattened directory structure (eliminated one nesting level) ### Documentation Organization - Moved chess-game/docs/ → docs/ (project documentation) - Moved alex/docs/ → planning/ (historical planning documents) - Added CLAUDE.md (workspace configuration) - Added IMPLEMENTATION_PROMPT.md (original project prompt) ### Version Control Improvements - All project files now under version control - Planning documents preserved in planning/ folder - Merged .gitignore files (workspace + project) - Added .claude/ agent configurations ### File Updates - Updated .gitignore to include both workspace and project excludes - Moved README.md to root level - All import paths remain functional (relative paths unchanged) ## Benefits ✅ **Simpler Structure** - One level of nesting removed ✅ **Complete Versioning** - All documentation now in git ✅ **Standard Layout** - Matches open-source project conventions ✅ **Easier Navigation** - Direct access to all project files ✅ **CI/CD Compatible** - All workflows still functional ## Technical Validation - ✅ Node.js environment verified - ✅ Dependencies installed successfully - ✅ Dev server starts and responds - ✅ All core files present and accessible - ✅ Git repository functional ## Files Preserved **Implementation Files:** - js/ (3,517 lines of code) - css/ (4 stylesheets) - tests/ (87 test cases) - index.html - package.json **CI/CD Pipeline:** - .gitea/workflows/ci.yml - .gitea/workflows/release.yml **Documentation:** - docs/ (12+ documentation files) - planning/ (historical planning materials) - README.md **Configuration:** - jest.config.js, babel.config.cjs, playwright.config.js - .gitignore (merged) - CLAUDE.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
244 lines
6.0 KiB
JavaScript
244 lines
6.0 KiB
JavaScript
/**
|
|
* @file sliding-piece-pattern.js
|
|
* @description Pattern for implementing sliding pieces (Rook, Bishop, Queen)
|
|
* These pieces slide along lines until blocked
|
|
*/
|
|
|
|
import Piece from '../models/Piece.js';
|
|
import { DIRECTIONS } from '../utils/Constants.js';
|
|
import { isValidPosition } from '../utils/Helpers.js';
|
|
|
|
/**
|
|
* @class Rook
|
|
* @extends Piece
|
|
* @description Example of sliding piece implementation
|
|
*
|
|
* Pattern applies to:
|
|
* - Rook: DIRECTIONS.ORTHOGONAL (vertical and horizontal)
|
|
* - Bishop: DIRECTIONS.DIAGONAL
|
|
* - Queen: [...DIRECTIONS.ORTHOGONAL, ...DIRECTIONS.DIAGONAL]
|
|
*/
|
|
class Rook extends Piece {
|
|
constructor(color, position) {
|
|
super(color, position, 'rook');
|
|
}
|
|
|
|
/**
|
|
* Gets all valid moves for this rook
|
|
* Uses sliding piece pattern
|
|
*
|
|
* @param {Board} board - Current board state
|
|
* @returns {Array<Object>} Array of valid positions
|
|
*/
|
|
getValidMoves(board) {
|
|
const moves = [];
|
|
|
|
// Rook moves in 4 orthogonal directions
|
|
const directions = DIRECTIONS.ORTHOGONAL;
|
|
|
|
// For each direction, slide until blocked
|
|
for (const direction of directions) {
|
|
const directionMoves = this._getMovesInDirection(board, direction);
|
|
moves.push(...directionMoves);
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
/**
|
|
* Gets all moves in a specific direction
|
|
*
|
|
* @private
|
|
* @param {Board} board - Current board state
|
|
* @param {Object} direction - Direction vector {row, col}
|
|
* @returns {Array<Object>} Valid positions in this direction
|
|
*/
|
|
_getMovesInDirection(board, direction) {
|
|
const moves = [];
|
|
const { row, col } = this.position;
|
|
|
|
let currentRow = row + direction.row;
|
|
let currentCol = col + direction.col;
|
|
|
|
// Slide in direction until we hit edge or piece
|
|
while (isValidPosition(currentRow, currentCol)) {
|
|
const currentPos = { row: currentRow, col: currentCol };
|
|
const piece = board.getPieceAt(currentPos);
|
|
|
|
if (!piece) {
|
|
// Empty square - can move here and continue
|
|
moves.push(currentPos);
|
|
} else if (piece.color !== this.color) {
|
|
// Enemy piece - can capture but can't continue
|
|
moves.push(currentPos);
|
|
break;
|
|
} else {
|
|
// Friendly piece - can't move here, stop
|
|
break;
|
|
}
|
|
|
|
// Continue sliding
|
|
currentRow += direction.row;
|
|
currentCol += direction.col;
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
clone() {
|
|
const clone = new Rook(this.color, { ...this.position });
|
|
clone.hasMoved = this.hasMoved;
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @class Bishop
|
|
* @extends Piece
|
|
* @description Bishop using same sliding pattern with diagonal directions
|
|
*/
|
|
class Bishop extends Piece {
|
|
constructor(color, position) {
|
|
super(color, position, 'bishop');
|
|
}
|
|
|
|
getValidMoves(board) {
|
|
const moves = [];
|
|
const directions = DIRECTIONS.DIAGONAL; // Only difference from Rook!
|
|
|
|
for (const direction of directions) {
|
|
const directionMoves = this._getMovesInDirection(board, direction);
|
|
moves.push(...directionMoves);
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
_getMovesInDirection(board, direction) {
|
|
// Identical to Rook implementation
|
|
const moves = [];
|
|
const { row, col } = this.position;
|
|
|
|
let currentRow = row + direction.row;
|
|
let currentCol = col + direction.col;
|
|
|
|
while (isValidPosition(currentRow, currentCol)) {
|
|
const currentPos = { row: currentRow, col: currentCol };
|
|
const piece = board.getPieceAt(currentPos);
|
|
|
|
if (!piece) {
|
|
moves.push(currentPos);
|
|
} else if (piece.color !== this.color) {
|
|
moves.push(currentPos);
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
currentRow += direction.row;
|
|
currentCol += direction.col;
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
clone() {
|
|
const clone = new Bishop(this.color, { ...this.position });
|
|
clone.hasMoved = this.hasMoved;
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @class Queen
|
|
* @extends Piece
|
|
* @description Queen combines Rook + Bishop movements
|
|
*/
|
|
class Queen extends Piece {
|
|
constructor(color, position) {
|
|
super(color, position, 'queen');
|
|
}
|
|
|
|
getValidMoves(board) {
|
|
const moves = [];
|
|
|
|
// Queen moves in all 8 directions
|
|
const directions = [...DIRECTIONS.ORTHOGONAL, ...DIRECTIONS.DIAGONAL];
|
|
|
|
for (const direction of directions) {
|
|
const directionMoves = this._getMovesInDirection(board, direction);
|
|
moves.push(...directionMoves);
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
_getMovesInDirection(board, direction) {
|
|
// Identical to Rook/Bishop implementation
|
|
const moves = [];
|
|
const { row, col } = this.position;
|
|
|
|
let currentRow = row + direction.row;
|
|
let currentCol = col + direction.col;
|
|
|
|
while (isValidPosition(currentRow, currentCol)) {
|
|
const currentPos = { row: currentRow, col: currentCol };
|
|
const piece = board.getPieceAt(currentPos);
|
|
|
|
if (!piece) {
|
|
moves.push(currentPos);
|
|
} else if (piece.color !== this.color) {
|
|
moves.push(currentPos);
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
|
|
currentRow += direction.row;
|
|
currentCol += direction.col;
|
|
}
|
|
|
|
return moves;
|
|
}
|
|
|
|
clone() {
|
|
const clone = new Queen(this.color, { ...this.position });
|
|
clone.hasMoved = this.hasMoved;
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* PATTERN SUMMARY:
|
|
*
|
|
* All sliding pieces use the same algorithm:
|
|
* 1. Define direction vectors
|
|
* 2. For each direction:
|
|
* a. Start at piece position
|
|
* b. Step in direction
|
|
* c. Check if position is valid
|
|
* d. If empty: add move, continue
|
|
* e. If enemy: add move, stop
|
|
* f. If friendly: stop
|
|
*
|
|
* OPTIMIZATION TIP:
|
|
* Extract _getMovesInDirection to a shared utility function
|
|
* to avoid code duplication:
|
|
*
|
|
* // In a SlidingPieceHelper.js file:
|
|
* export function getSlidingMoves(piece, board, directions) {
|
|
* const moves = [];
|
|
* for (const direction of directions) {
|
|
* moves.push(...getMovesInDirection(piece, board, direction));
|
|
* }
|
|
* return moves;
|
|
* }
|
|
*
|
|
* // Then in pieces:
|
|
* getValidMoves(board) {
|
|
* return getSlidingMoves(this, board, DIRECTIONS.ORTHOGONAL);
|
|
* }
|
|
*/
|
|
|
|
export { Rook, Bishop, Queen };
|