ChessNut/engine/core/movement/moves.js
2025-10-20 13:23:22 +02:00

178 lines
4.9 KiB
JavaScript

import { generateLinearMoves } from './generateMoves.js';
// basic moves
class RookMove {
/**
* Return possible moves for a rook-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece, allowRing }
*/
static moves(ctx) {
const orthogonals = [
[1, 0],
[-1, 0],
[0, 1],
[0, -1],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: orthogonals,
allowRing: ctx.allowRing
});
}
}
class BishopMove {
/**
* Return possible moves for a bishop-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const diagonals = [
[1, 1],
[1, -1],
[-1, 1],
[-1, -1],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: diagonals,
allowRing: ctx.allowRing
});
}
}
class KnightMove {
/**
* Return possible moves for a knight-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const knightMoves = [
[2, 1], [2, -1], [-2, 1], [-2, -1],
[1, 2], [1, -2], [-1, 2], [-1, -2],
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: knightMoves,
maxSteps: 1,
allowEmpty: true,
allowCapture: true,
allowRing: ctx.allowRing
});
}
}
class QueenMove {
/**
* Return possible moves for a queen-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const directions = [
[1, 0], [-1, 0], [0, 1], [0, -1], // orthogonals
[1, 1], [1, -1], [-1, 1], [-1, -1], // diagonals
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: directions,
allowRing: ctx.allowRing
});
}
}
class KingMove {
/**
* Return possible moves for a king-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const directions = [
[1, 0], [-1, 0], [0, 1], [0, -1], // orthogonals
[1, 1], [1, -1], [-1, 1], [-1, -1], // diagonals
];
return generateLinearMoves({
board: ctx.board,
from: ctx.from,
piece: ctx.piece,
directions: directions,
maxSteps: 1,
allowRing: ctx.allowRing
});
}
}
class PawnMove {
/**
* Return possible moves for a pawn-like piece from `from` on the given `board`.
* The move format is { x, y, capture: boolean }
*
* ctx: { board, from: {x,y}, piece }
*/
static moves(ctx) {
const color = ctx.piece.getColor();
const forward = (color === 'white') ? -1 : 1; // assuming y=0 is top
const moves = [];
const w = ctx.board.getWidth();
const h = ctx.board.getHeight();
const x = ctx.from.x;
const y = ctx.from.y;
// Forward move
if (y + forward >= 0 && y + forward < h) {
const forwardCell = ctx.board.getCell(x, y + forward);
if (forwardCell?.piece == null) {
moves.push({ x: x, y: y + forward, capture: false });
// Double step from starting position
const startingRow = (color === 'white') ? h - 2 : 1;
if (!ctx.piece.hasMoved) {
const doubleForwardCell = ctx.board.getCell(x, y + 2 * forward);
if (doubleForwardCell?.piece == null) {
moves.push({ x: x, y: y + 2 * forward, capture: false });
}
}
}
}
// Captures
for (const dx of [-1, 1]) {
if (x + dx >= 0 && x + dx < w && y + forward >= 0 && y + forward < h) {
const diagCell = ctx.board.getCell(x + dx, y + forward);
const target = diagCell?.piece ?? null;
if (target != null && target.getColor() !== color) {
moves.push({ x: x + dx, y: y + forward, capture: true });
}
}
}
return moves;
}
}
export { RookMove, BishopMove, KnightMove, QueenMove, KingMove, PawnMove };