@real_one_chess_king/game-logic
Version:
R.O.C.K. chess game logic
137 lines • 5.02 kB
JavaScript
import { Cell } from "../cell";
import { handleKillAffect, handleMoveAffect, handleSpawnAffect, handleTransformAffect, reverseAffects, } from "../affect/affect";
import { buildPieceByMeta } from "../piece/piece-builder";
import { RulesEngine } from "../rules-engine";
/**
* Board keeps data about current game position and pieces on the array of cells
* It provides methods for manipulation by affects, but not dirrect access to pieces
* Always should be filled in by metadata
*/
export class Board {
size = 8;
squares;
rulesEngine = new RulesEngine();
/**
* Metastorage is needed for saving initial data about pieces
* It can be used for transformation of pieces
*/
meta;
constructor() {
this.squares = this.buildCells();
}
buildCells() {
return Array.from({ length: this.size }, () => Array.from({ length: this.size }, () => new Cell()));
}
isIndexValid = (index) => index >= 0 && index < this.size;
getMeta() {
if (!this.meta) {
throw new Error("Board meta is not defined yet");
}
return this.meta;
}
fillBoardByMeta(meta) {
this.meta = meta;
const { cellsMeta: cells, postMovementRules, movementRules } = meta;
this.rulesEngine.addMovementRules(movementRules);
this.rulesEngine.addPostMovementRules(postMovementRules);
for (let row = 0; row < this.size; row++) {
for (let col = 0; col < this.size; col++) {
const pieceMetaId = cells[row][col];
if (pieceMetaId) {
const cell = this.getCell(col, row);
const pieceMeta = meta.pieceMeta.find(({ id }) => id === pieceMetaId);
if (!pieceMeta) {
throw new Error("Piece meta not found");
}
cell.putPiece(buildPieceByMeta(pieceMeta));
}
}
}
}
getPiece = (x, y) => {
return this.squares[y][x].getPiece();
};
getPieceByCoordinate = (xy) => {
return this.squares[xy[1]][xy[0]].getPiece();
};
getCell(x, y) {
return this.squares[y][x];
}
forEachPiece(color, callback) {
this.squares.forEach((row, y) => {
row.forEach((cell, x) => {
const piece = cell.getPiece();
if (piece && piece.color === color) {
callback(piece, x, y);
}
});
});
}
// now [x, y, affects]
// to action: affects[]. Affects with user choice marked with field and will be used for tree building
//
getPieceAvailableMoves(x, y, turns) {
const availableMoves = [];
const piece = this.getPiece(x, y);
if (!piece) {
throw new Error("Can not get moves for invalid piece coordinates");
}
const { movementRules, postMovementRules } = piece;
movementRules.forEach((ruleId) => {
const ruleMoves = this.rulesEngine.getAvailableMoves(ruleId, x, y, this.getPiece, turns, this.size);
availableMoves.push(...ruleMoves);
});
let updatedMoves = availableMoves;
postMovementRules?.forEach((ruleId) => {
updatedMoves = this.rulesEngine.addPostMovementCorrections(ruleId, updatedMoves, piece.type);
});
return updatedMoves;
}
/**
* We keep all killed and removed from the board pieces here.
* Transformations are not included.
*/
killed = [];
updateCellsOnMove(affects) {
if (!this.meta) {
throw new Error("Board meta is not defined yet");
}
affects.forEach((affect) => {
handleKillAffect(affect, this.squares, this.killed);
handleMoveAffect(affect, this.squares);
handleTransformAffect(affect, this.squares, this.meta);
handleSpawnAffect(affect, this.squares, this.killed);
});
}
revertMove(affects) {
const reversedAffects = reverseAffects(affects);
this.updateCellsOnMove(reversedAffects);
}
duplicatePosition(cells) {
this.squares.forEach((row, y) => {
row.forEach((cell, x) => {
const piece = cell.getPiece();
if (piece) {
cells[y][x].putPiece(piece);
}
else {
cells[y][x].popPiece();
}
});
});
return cells;
}
findUniqPiece(color, pieceType) {
for (let i = 0; i < this.squares.length; i++) {
for (let j = 0; j < this.squares[i].length; j++) {
const cell = this.squares[i][j];
const piece = cell.getPiece();
if (piece && piece.color === color && piece.type === pieceType) {
return [j, i];
}
}
}
throw new Error(`${pieceType} not found`);
}
}
//# sourceMappingURL=board.js.map