chess/planning/implementation/examples/sliding-piece-pattern.js
Christoph Wagner 5ad0700b41 refactor: Consolidate repository structure - flatten from workspace pattern
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>
2025-11-23 10:05:26 +01:00

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 };