diff --git a/src/game/board.ts b/src/game/board.ts index 900e05f..289fd31 100644 --- a/src/game/board.ts +++ b/src/game/board.ts @@ -1,52 +1,51 @@ import { Pawn } from "../pieces/pawn"; -import { Cell } from "./cell"; -import { Player } from "./player"; -import { Point } from "./point"; -const maps: Record = import.meta.glob("../maps/*.txt", { - query: "?raw", - eager: true, -}) +import type { Cell } from "./cell"; +import type { Player } from "./player"; +import type { Point } from "./point"; +const maps: Record = import.meta.glob( + "../maps/*.txt", + { + query: "?raw", + eager: true, + }, +); export default class Board { - #cells: Cell[][] = [] + #cells: Cell[][] = []; - get rows() { - return this.#cells - } + get rows() { + return this.#cells; + } - get allCells() { - return this.#cells.flat() - } + get allCells() { + return this.#cells.flat(); + } - get size() { - return this.#cells.length - } + get size() { + return this.#cells.length; + } - constructor( - mapName: string, - players: Player[] - ) { - const map = maps[`../maps/${mapName}.txt`].default - .split("\n"); - map.pop() + constructor(mapName: string, players: Player[]) { + const map = maps[`../maps/${mapName}.txt`].default.split("\n"); + map.pop(); map.forEach((row, y) => { this.#cells[y] = []; row.split("").forEach((symbol, x) => { const cell: Cell = { - owner: null, - building: null, - piece: null, - point: {x, y} - } + owner: null, + building: null, + piece: null, + point: { x, y }, + }; if (symbol === ".") { } else if (symbol === "1") { - cell.piece = new Pawn("white") - cell.building = "castle" - cell.owner = players[0] + cell.piece = new Pawn("white"); + cell.building = "castle"; + cell.owner = players[0]; } else if (symbol === "2") { - cell.piece = new Pawn("black") - cell.building = "castle" - cell.owner = players[1] + cell.piece = new Pawn("black"); + cell.building = "castle"; + cell.owner = players[1]; } else if (symbol === "w") { cell.building = "wall"; } else if (symbol === "c") { @@ -60,6 +59,6 @@ export default class Board { } cellAt(point: Point) { - return this.#cells[point.y][point.x] + return this.#cells[point.y][point.x]; } } diff --git a/src/game/cell.ts b/src/game/cell.ts index 624c3eb..2336cbf 100644 --- a/src/game/cell.ts +++ b/src/game/cell.ts @@ -1,10 +1,10 @@ -import { Piece } from "../pieces/piece" -import { Player } from "./player" -import { Point } from "./point" +import type { Piece } from "../pieces/piece"; +import type { Player } from "./player"; +import type { Point } from "./point"; export type Cell = { - owner: Player | null, - building: Building | null, - piece: Piece | null, - point: Point -} + owner: Player | null; + building: Building | null; + piece: Piece | null; + point: Point; +}; diff --git a/src/game/game.ts b/src/game/game.ts index 46b16f8..d17b734 100644 --- a/src/game/game.ts +++ b/src/game/game.ts @@ -1,137 +1,156 @@ -import { Piece } from "../pieces/piece"; +import type { Piece } from "../pieces/piece"; +import Board from "./board"; import getAllPieces from "./getAllPieces"; -import Board from "./board" import { Player } from "./player"; -import { Point } from "./point"; +import type { Point } from "./point"; export default class Game { - #board - #players = [new Player("white"), new Player("black")]; - #currentPlayerIndex = 0 - #selectedPoint: Point | null = null - - afterEndTurn: (winner: PlayerColor | null) => void = () => {} - - get currentPlayer() { - return this.#players[this.#currentPlayerIndex] - } - - get previousPlayer() { - return this.#currentPlayerIndex > 0 - ? this.#players[this.#currentPlayerIndex - 1] - : this.#players[this.#players.length - 1] - } - - get board() { - return this.#board - } - - get selectedCell() { - if (!this.#selectedPoint) { - return null - } - return this.board.cellAt(this.#selectedPoint) - } - - constructor( - mapName: string - ) { - this.#board = new Board(mapName, this.#players) - } - - getAvailableMoves(point: Point) { - const piece = this.board.cellAt(point).piece - if (!piece) { - throw new Error - } - return piece.getAvailableMoves(this.board, point) - } - - getPiecesToBuy(point: Point): { piece: Piece, available: boolean, calculatedPrice: number }[] { - const unlocked = getAllPieces(this.currentPlayer.color) - .filter(p => this.currentPlayer.hasUnlocked(p)) - if (this.board.cellAt(point).piece || !this.currentPlayer.canBuyPiece()) { - return unlocked.map(p => ({ piece: p, available: false, calculatedPrice: this.#calculatePrice(point, p.cost) })) - } - return unlocked.map(p => ({ piece: p, available: this.#calculatePrice(point, p.cost) <= this.currentPlayer.gold, calculatedPrice: this.#calculatePrice(point, p.cost) })) - } - - select(point: Point) { - this.#selectedPoint = point - } - - unselect() { - this.#selectedPoint = null - } - - moveTo(point: Point) { - if (!this.#selectedPoint) { - throw new Error - } - - this.board.cellAt(point).piece = this.board.cellAt(this.#selectedPoint).piece - this.board.cellAt(this.#selectedPoint).piece = null - - this.#endTurn() - } - - skipTurn() { - this.#endTurn() - } - - forfeit() { - this.afterEndTurn(this.previousPlayer.color) - } - - buyPiece(point: Point, piece: Piece) { - this.currentPlayer.gold -= this.#calculatePrice(point, piece.cost) - this.currentPlayer.boughtPieces.add(piece.name) - this.currentPlayer.pieces++; - this.board.cellAt(point).piece = piece - this.#endTurn() - } - - buyUpgrade(point: Point, upgrade: string) { - if (upgrade !== "barracks" && upgrade !== "factory" && upgrade !== "mine") { - throw new Error() - } - this.currentPlayer.handleBuildingAcquisitionOrLoss(upgrade, "acquisition") - this.currentPlayer.gold -= 3 - this.board.cellAt(point).building = upgrade - this.#endTurn() - } - - #endTurn() { - this.currentPlayer.gold += this.currentPlayer.goldPerTurn - - // PLAYER CHANGE - this.#currentPlayerIndex = (this.#currentPlayerIndex + 1) % 2; - - this.#selectedPoint = null - for (const cell of this.#board.allCells.filter( - (cell) => - cell.building && cell.piece?.color === this.currentPlayer.color && cell.owner !== this.currentPlayer - )) { - cell.owner = this.currentPlayer - this.currentPlayer.handleBuildingAcquisitionOrLoss(cell.building!, "acquisition") - this.previousPlayer.handleBuildingAcquisitionOrLoss(cell.building!, "loss") - } - - let winner: PlayerColor | null = null - - if (!this.#board.allCells.some((cell) => cell.owner?.color === "black")) { - winner = "white" - } - - if (!this.#board.allCells.some((cell) => cell.owner?.color === "white")) { - winner = "black" - } - - this.afterEndTurn(winner) - } - - #calculatePrice(point: Point, price: number) { - const isFactory = this.board.cellAt(point).building === "factory" - return (isFactory ? Math.round(price * 0.7) : price) - } + #board; + #players = [new Player("white"), new Player("black")]; + #currentPlayerIndex = 0; + #selectedPoint: Point | null = null; + + afterEndTurn: (winner: PlayerColor | null) => void = () => {}; + + get currentPlayer() { + return this.#players[this.#currentPlayerIndex]; + } + + get previousPlayer() { + return this.#currentPlayerIndex > 0 + ? this.#players[this.#currentPlayerIndex - 1] + : this.#players[this.#players.length - 1]; + } + + get board() { + return this.#board; + } + + get selectedCell() { + if (!this.#selectedPoint) { + return null; + } + return this.board.cellAt(this.#selectedPoint); + } + + constructor(mapName: string) { + this.#board = new Board(mapName, this.#players); + } + + getAvailableMoves(point: Point) { + const piece = this.board.cellAt(point).piece; + if (!piece) { + throw new Error(); + } + return piece.getAvailableMoves(this.board, point); + } + + getPiecesToBuy( + point: Point, + ): { piece: Piece; available: boolean; calculatedPrice: number }[] { + const unlocked = getAllPieces(this.currentPlayer.color).filter((p) => + this.currentPlayer.hasUnlocked(p), + ); + if (this.board.cellAt(point).piece || !this.currentPlayer.canBuyPiece()) { + return unlocked.map((p) => ({ + piece: p, + available: false, + calculatedPrice: this.#calculatePrice(point, p.cost), + })); + } + return unlocked.map((p) => ({ + piece: p, + available: this.#calculatePrice(point, p.cost) <= this.currentPlayer.gold, + calculatedPrice: this.#calculatePrice(point, p.cost), + })); + } + + select(point: Point) { + this.#selectedPoint = point; + } + + unselect() { + this.#selectedPoint = null; + } + + moveTo(point: Point) { + if (!this.#selectedPoint) { + throw new Error(); + } + + this.board.cellAt(point).piece = this.board.cellAt( + this.#selectedPoint, + ).piece; + this.board.cellAt(this.#selectedPoint).piece = null; + + this.#endTurn(); + } + + skipTurn() { + this.#endTurn(); + } + + forfeit() { + this.afterEndTurn(this.previousPlayer.color); + } + + buyPiece(point: Point, piece: Piece) { + this.currentPlayer.gold -= this.#calculatePrice(point, piece.cost); + this.currentPlayer.boughtPieces.add(piece.name); + this.currentPlayer.pieces++; + this.board.cellAt(point).piece = piece; + this.#endTurn(); + } + + buyUpgrade(point: Point, upgrade: string) { + if (upgrade !== "barracks" && upgrade !== "factory" && upgrade !== "mine") { + throw new Error(); + } + this.currentPlayer.handleBuildingAcquisitionOrLoss(upgrade, "acquisition"); + this.currentPlayer.gold -= 3; + this.board.cellAt(point).building = upgrade; + this.#endTurn(); + } + + #endTurn() { + this.currentPlayer.gold += this.currentPlayer.goldPerTurn; + + // PLAYER CHANGE + this.#currentPlayerIndex = (this.#currentPlayerIndex + 1) % 2; + + this.#selectedPoint = null; + for (const cell of this.#board.allCells.filter( + (cell) => + cell.building && + cell.piece?.color === this.currentPlayer.color && + cell.owner !== this.currentPlayer, + )) { + cell.owner = this.currentPlayer; + this.currentPlayer.handleBuildingAcquisitionOrLoss( + cell.building!, + "acquisition", + ); + this.previousPlayer.handleBuildingAcquisitionOrLoss( + cell.building!, + "loss", + ); + } + + let winner: PlayerColor | null = null; + + if (!this.#board.allCells.some((cell) => cell.owner?.color === "black")) { + winner = "white"; + } + + if (!this.#board.allCells.some((cell) => cell.owner?.color === "white")) { + winner = "black"; + } + + this.afterEndTurn(winner); + } + + #calculatePrice(point: Point, price: number) { + const isFactory = this.board.cellAt(point).building === "factory"; + return isFactory ? Math.round(price * 0.7) : price; + } } diff --git a/src/game/getAllPieces.ts b/src/game/getAllPieces.ts index e4884c5..4218634 100644 --- a/src/game/getAllPieces.ts +++ b/src/game/getAllPieces.ts @@ -8,7 +8,7 @@ import { Pawn } from "../pieces/pawn"; import { PawnBishop } from "../pieces/pawnBishop"; import { PawnKnight } from "../pieces/pawnKnight"; import { PawnRook } from "../pieces/pawnRook"; -import { Piece } from "../pieces/piece"; +import type { Piece } from "../pieces/piece"; import { Rook } from "../pieces/rook"; export default function getAllPieces(color: PlayerColor): Piece[] { diff --git a/src/game/player.ts b/src/game/player.ts index bd2f101..744f640 100644 --- a/src/game/player.ts +++ b/src/game/player.ts @@ -1,4 +1,4 @@ -import { Piece } from "../pieces/piece"; +import type { Piece } from "../pieces/piece"; export class Player { pieces = 1; @@ -8,7 +8,6 @@ export class Player { #color; boughtPieces = new Set(); - get color() { return this.#color; } @@ -31,18 +30,21 @@ export class Player { } canBuyUpgrade() { - return this.gold >= 3 + return this.gold >= 3; } - handleBuildingAcquisitionOrLoss(building: Building, action: "acquisition" | "loss") { - const x = action === "loss" ? -1 : 1 - if (building === "factory" || building === "castle") { - } else if (building === "barracks") { - this.maxPieces += x; - } else if (building === "mine") { - this.goldPerTurn += x; - } else { - throw new Error() - } + handleBuildingAcquisitionOrLoss( + building: Building, + action: "acquisition" | "loss", + ) { + const x = action === "loss" ? -1 : 1; + if (building === "factory" || building === "castle") { + } else if (building === "barracks") { + this.maxPieces += x; + } else if (building === "mine") { + this.goldPerTurn += x; + } else { + throw new Error(); + } } } diff --git a/src/game/point.ts b/src/game/point.ts index eef2b47..c0641b3 100644 --- a/src/game/point.ts +++ b/src/game/point.ts @@ -1,4 +1,4 @@ export type Point = { - x: number, - y: number -} + x: number; + y: number; +}; diff --git a/src/main.ts b/src/main.ts index f711ff0..f46cfb7 100644 --- a/src/main.ts +++ b/src/main.ts @@ -4,33 +4,30 @@ import Game from "./game/game.ts"; // TODO: warn when piece limit is hit let firstRender = true; -const game = new Game("canyon") +const game = new Game("canyon"); game.afterEndTurn = (winner) => { if (winner) { gameOverDialog.showModal(); gameOverDialog.children[0].textContent = `Game over! ${winner[0].toLocaleUpperCase() + winner.substring(1)} is the winner.`; } - renderGame() -} + renderGame(); +}; const table = q("#board") as HTMLTableElement; // new OldGame(board, new URLSearchParams(location.search).has("tutorial")); -table.style.setProperty( - "--cells-horizontaly", - game.board.size.toString() -); -const tableBody = table.createTBody() +table.style.setProperty("--cells-horizontaly", game.board.size.toString()); +const tableBody = table.createTBody(); for (let x = 0; x < game.board.size; x++) { - const tableRow = tableBody.insertRow() + const tableRow = tableBody.insertRow(); for (let y = 0; y < game.board.size; y++) { - const tableCell = tableRow.insertCell() - const cell = game.board.cellAt({ x, y }) - tableCell.classList.add("cell") + const tableCell = tableRow.insertCell(); + const cell = game.board.cellAt({ x, y }); + tableCell.classList.add("cell"); if (cell.building === "castle") { tableCell.classList.add("building"); const div = document.createElement("div"); - div.title = "Castle" + div.title = "Castle"; div.classList.add("cell-annotation"); - div.textContent = "c" + div.textContent = "c"; tableCell.appendChild(div); } } @@ -39,16 +36,20 @@ for (let x = 0; x < game.board.size; x++) { const castleMenu = q("#castle-menu") as HTMLDialogElement; const castleMenuPieces = q("#castle-menu-pieces") as HTMLUListElement; const castleMenuUpgrades = q("#castle-menu-upgrades") as HTMLUListElement; -const gameOverDialog = q("#game-over") as HTMLDialogElement +const gameOverDialog = q("#game-over") as HTMLDialogElement; q("#skip-turn").onclick = () => game.skipTurn(); q("#forfeit").onclick = () => game.forfeit(); -q(`#${game.currentPlayer.color} .pieces`).textContent = game.currentPlayer.pieces.toString(); -q(`#${game.currentPlayer.color} .gold`).textContent = game.currentPlayer.gold.toString(); -q(`#${game.currentPlayer.color} .gold-per-turn`).textContent = game.currentPlayer.goldPerTurn.toString(); -q(`#${game.currentPlayer.color} .max-pieces`).textContent = game.currentPlayer.maxPieces.toString(); +q(`#${game.currentPlayer.color} .pieces`).textContent = + game.currentPlayer.pieces.toString(); +q(`#${game.currentPlayer.color} .gold`).textContent = + game.currentPlayer.gold.toString(); +q(`#${game.currentPlayer.color} .gold-per-turn`).textContent = + game.currentPlayer.goldPerTurn.toString(); +q(`#${game.currentPlayer.color} .max-pieces`).textContent = + game.currentPlayer.maxPieces.toString(); -renderGame() +renderGame(); Panzoom(table, { disableZoom: true, @@ -61,59 +62,61 @@ function q(selector: string) { if (!element) { throw new Error(`It's a bug! No element matching '${selector}' found`); } - return element as HTMLElement + return element as HTMLElement; } function allTableCells() { - return [...table.rows].flatMap((row) => [...row.cells]) + return [...table.rows].flatMap((row) => [...row.cells]); } function renderGame() { - q(`#${game.previousPlayer.color} .pieces`).textContent = game.previousPlayer.pieces.toString(); - q(`#${game.previousPlayer.color} .gold`).textContent = game.previousPlayer.gold.toString(); - q(`#${game.previousPlayer.color} .gold-per-turn`).textContent = game.previousPlayer.goldPerTurn.toString(); - q(`#${game.previousPlayer.color} .max-pieces`).textContent = game.previousPlayer.maxPieces.toString(); + q(`#${game.previousPlayer.color} .pieces`).textContent = + game.previousPlayer.pieces.toString(); + q(`#${game.previousPlayer.color} .gold`).textContent = + game.previousPlayer.gold.toString(); + q(`#${game.previousPlayer.color} .gold-per-turn`).textContent = + game.previousPlayer.goldPerTurn.toString(); + q(`#${game.previousPlayer.color} .max-pieces`).textContent = + game.previousPlayer.maxPieces.toString(); - if(!firstRender) { - q("#player-buttons").classList.toggle("white") - q("#white").classList.toggle("active") + if (!firstRender) { + q("#player-buttons").classList.toggle("white"); + q("#white").classList.toggle("active"); - q("#player-buttons").classList.toggle("black") - q("#black").classList.toggle("active") + q("#player-buttons").classList.toggle("black"); + q("#black").classList.toggle("active"); } for (let x = 0; x < game.board.size; x++) { for (let y = 0; y < game.board.size; y++) { const point = { x, y }; - const cell = game.board.cellAt(point) - const tableCell = table.rows[y].cells[x] - tableCell.classList.remove("selected", "highlighted", "piece-to-move") - tableCell.style.setProperty( - "--outline", - "", - ); - tableCell.style.setProperty( - "--background-image-url", - "", - ); - tableCell.oncontextmenu = null + const cell = game.board.cellAt(point); + const tableCell = table.rows[y].cells[x]; + tableCell.classList.remove("selected", "highlighted", "piece-to-move"); + tableCell.style.setProperty("--outline", ""); + tableCell.style.setProperty("--background-image-url", ""); + tableCell.oncontextmenu = null; if (cell.building === "wall") { - tableCell.classList.add("wall") + tableCell.classList.add("wall"); } else if (cell.building) { tableCell.children[0].textContent = cell.building[0]; - (tableCell.children[0] as HTMLElement).title = cell.building + (tableCell.children[0] as HTMLElement).title = cell.building; if (cell.owner === game.currentPlayer) { tableCell.oncontextmenu = (event) => { - event.preventDefault() + event.preventDefault(); castleMenu.showModal(); castleMenuPieces.innerHTML = ""; - for (const { piece, available, calculatedPrice } of game.getPiecesToBuy(point)) { + for (const { + piece, + available, + calculatedPrice, + } of game.getPiecesToBuy(point)) { const li = document.createElement("li"); li.classList.add("cell"); li.style.backgroundImage = `url('/${piece.name}-${piece.color}.png')`; if (available) { li.onclick = () => { - game.buyPiece(point, piece) + game.buyPiece(point, piece); castleMenu.close(); }; } else { @@ -125,18 +128,20 @@ function renderGame() { li.appendChild(div); castleMenuPieces.appendChild(li); } - for (const button of castleMenuUpgrades.querySelectorAll("button")) { + for (const button of castleMenuUpgrades.querySelectorAll( + "button", + )) { if (!game.currentPlayer.canBuyUpgrade()) { button.disabled = true; } else { button.disabled = false; button.onclick = () => { - game.buyUpgrade(point, button.innerText.toLocaleLowerCase()) + game.buyUpgrade(point, button.innerText.toLocaleLowerCase()); castleMenu.close(); - } + }; } } - } + }; } } if (cell.piece) { @@ -154,22 +159,22 @@ function renderGame() { } tableCell.onclick = () => { if (cell.piece?.color === game.currentPlayer.color) { - tableCell.classList.add("selected") - game.select(point) + tableCell.classList.add("selected"); + game.select(point); for (const destination of game.getAvailableMoves(point)) { - const c = table.rows[destination.y].cells[destination.x] - c.classList.add("highlighted") + const c = table.rows[destination.y].cells[destination.x]; + c.classList.add("highlighted"); } } else if (tableCell.classList.contains("highlighted")) { - game.moveTo(point) + game.moveTo(point); } else { for (const c of allTableCells()) { - c.classList.remove("selected", "highlighted") + c.classList.remove("selected", "highlighted"); } } - } + }; } } - firstRender = false + firstRender = false; } diff --git a/src/pieces/amazon.ts b/src/pieces/amazon.ts index b84fd55..fd5a381 100644 --- a/src/pieces/amazon.ts +++ b/src/pieces/amazon.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Bishop } from "./bishop"; import { BishopKnight } from "./bishopKnight"; import { BishopRook } from "./bishopRook"; @@ -35,12 +35,11 @@ export class Amazon implements Piece { constructor(color: PlayerColor) { this.#color = color; } -getAvailableMoves(board: Board, point: Point): Point[] { - return [ - ...new Rook(this.#color).getAvailableMoves(board, point), - ...new Bishop(this.#color).getAvailableMoves(board, point), - ...new Knight(this.#color).getAvailableMoves(board, point) - ]; -} - + getAvailableMoves(board: Board, point: Point): Point[] { + return [ + ...new Rook(this.#color).getAvailableMoves(board, point), + ...new Bishop(this.#color).getAvailableMoves(board, point), + ...new Knight(this.#color).getAvailableMoves(board, point), + ]; + } } diff --git a/src/pieces/bishop.ts b/src/pieces/bishop.ts index 366e5e0..31ba226 100644 --- a/src/pieces/bishop.ts +++ b/src/pieces/bishop.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Pawn } from "./pawn"; import type { Piece } from "./piece"; @@ -27,14 +27,17 @@ export class Bishop implements Piece { this.#color = color; } - getAvailableMoves(board: Board, { x, y }: Point): Point[] { const points: Point[] = []; // Top-left diagonal (Northwest) for (let xi = x - 1, yi = y - 1; xi >= 0 && yi >= 0; xi--, yi--) { const cell = board.cellAt({ x: xi, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { break; } points.push({ x: xi, y: yi }); @@ -46,7 +49,11 @@ export class Bishop implements Piece { // Bottom-left diagonal (Southwest) for (let xi = x - 1, yi = y + 1; xi >= 0 && yi < board.size; xi--, yi++) { const cell = board.cellAt({ x: xi, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { break; } points.push({ x: xi, y: yi }); @@ -56,9 +63,17 @@ export class Bishop implements Piece { } // Bottom-right diagonal (Southeast) - for (let xi = x + 1, yi = y + 1; xi < board.size && yi < board.size; xi++, yi++) { + for ( + let xi = x + 1, yi = y + 1; + xi < board.size && yi < board.size; + xi++, yi++ + ) { const cell = board.cellAt({ x: xi, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { break; } points.push({ x: xi, y: yi }); @@ -70,7 +85,11 @@ export class Bishop implements Piece { // Top-right diagonal (Northeast) for (let xi = x + 1, yi = y - 1; xi < board.size && yi >= 0; xi++, yi--) { const cell = board.cellAt({ x: xi, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { break; } points.push({ x: xi, y: yi }); diff --git a/src/pieces/bishopKnight.ts b/src/pieces/bishopKnight.ts index a122731..cde3d4f 100644 --- a/src/pieces/bishopKnight.ts +++ b/src/pieces/bishopKnight.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Bishop } from "./bishop"; import { Knight } from "./knight"; import type { Piece } from "./piece"; @@ -27,11 +27,10 @@ export class BishopKnight implements Piece { constructor(color: PlayerColor) { this.#color = color; } -getAvailableMoves(board: Board, point: Point): Point[] { - return [ - ...new Bishop(this.#color).getAvailableMoves(board, point), - ...new Knight(this.#color).getAvailableMoves(board, point) - ]; -} - + getAvailableMoves(board: Board, point: Point): Point[] { + return [ + ...new Bishop(this.#color).getAvailableMoves(board, point), + ...new Knight(this.#color).getAvailableMoves(board, point), + ]; + } } diff --git a/src/pieces/bishopRook.ts b/src/pieces/bishopRook.ts index ce93165..470f40d 100644 --- a/src/pieces/bishopRook.ts +++ b/src/pieces/bishopRook.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Bishop } from "./bishop"; import type { Piece } from "./piece"; import { Rook } from "./rook"; @@ -28,10 +28,10 @@ export class BishopRook implements Piece { this.#color = color; } -getAvailableMoves(board: Board, point: Point): Point[] { - return [ - ...new Rook(this.#color).getAvailableMoves(board, point), - ...new Bishop(this.#color).getAvailableMoves(board, point) - ]; -} + getAvailableMoves(board: Board, point: Point): Point[] { + return [ + ...new Rook(this.#color).getAvailableMoves(board, point), + ...new Bishop(this.#color).getAvailableMoves(board, point), + ]; + } } diff --git a/src/pieces/knight.ts b/src/pieces/knight.ts index 8bbd318..8835999 100644 --- a/src/pieces/knight.ts +++ b/src/pieces/knight.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Pawn } from "./pawn"; import type { Piece } from "./piece"; @@ -29,18 +29,21 @@ export class Knight implements Piece { getAvailableMoves(board: Board, { x, y }: Point): Point[] { const potentialMoves = [ - { x: x - 2, y: y - 1 }, { x: x - 1, y: y - 2 }, - { x: x + 1, y: y - 2 }, { x: x + 2, y: y - 1 }, - { x: x + 2, y: y + 1 }, { x: x + 1, y: y + 2 }, - { x: x - 1, y: y + 2 }, { x: x - 2, y: y + 1 } + { x: x - 2, y: y - 1 }, + { x: x - 1, y: y - 2 }, + { x: x + 1, y: y - 2 }, + { x: x + 2, y: y - 1 }, + { x: x + 2, y: y + 1 }, + { x: x + 1, y: y + 2 }, + { x: x - 1, y: y + 2 }, + { x: x - 2, y: y + 1 }, ]; -const points = potentialMoves - .filter(p => board.cellAt(p) !== undefined) - .filter(p => board.cellAt(p).piece?.color !== this.#color) - .filter(p => board.cellAt(p).building !== "wall"); + const points = potentialMoves + .filter((p) => board.cellAt(p) !== undefined) + .filter((p) => board.cellAt(p).piece?.color !== this.#color) + .filter((p) => board.cellAt(p).building !== "wall"); return points; } - } diff --git a/src/pieces/knightRook.ts b/src/pieces/knightRook.ts index efd2ddf..3795edf 100644 --- a/src/pieces/knightRook.ts +++ b/src/pieces/knightRook.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Knight } from "./knight"; import type { Piece } from "./piece"; import { Rook } from "./rook"; @@ -29,10 +29,9 @@ export class KnightRook implements Piece { } getAvailableMoves(board: Board, point: Point): Point[] { - return [ - ...new Knight(this.#color).getAvailableMoves(board, point), - ...new Rook(this.#color).getAvailableMoves(board, point) - ]; -} - + return [ + ...new Knight(this.#color).getAvailableMoves(board, point), + ...new Rook(this.#color).getAvailableMoves(board, point), + ]; + } } diff --git a/src/pieces/pawn.ts b/src/pieces/pawn.ts index d9bd0b2..3dc504a 100644 --- a/src/pieces/pawn.ts +++ b/src/pieces/pawn.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import type { Piece } from "./piece"; export class Pawn implements Piece { @@ -27,17 +27,25 @@ export class Pawn implements Piece { } getAvailableMoves(board: Board, point: Point): Point[] { - const x = point.x - const y = point.y + const x = point.x; + const y = point.y; let points = [ - { x: x - 1, y: y - 1 }, { x: x, y: y - 1 }, { x: x + 1, y: y - 1 }, { x: x + 1, y: y }, { x: x - 1, y: y }, { x: x + 1, y: y + 1 }, { x: x, y: y + 1 }, { x: x - 1, y: y + 1 },]; + { x: x - 1, y: y - 1 }, + { x: x, y: y - 1 }, + { x: x + 1, y: y - 1 }, + { x: x + 1, y: y }, + { x: x - 1, y: y }, + { x: x + 1, y: y + 1 }, + { x: x, y: y + 1 }, + { x: x - 1, y: y + 1 }, + ]; points = points .filter((p) => board.cellAt(p) !== undefined) .filter((p) => board.cellAt(p).piece?.color !== this.#color) .filter((p) => board.cellAt(p).building !== "wall"); - return points + return points; } } diff --git a/src/pieces/pawnBishop.ts b/src/pieces/pawnBishop.ts index caad5b2..687feed 100644 --- a/src/pieces/pawnBishop.ts +++ b/src/pieces/pawnBishop.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Bishop } from "./bishop"; import { Pawn } from "./pawn"; import type { Piece } from "./piece"; @@ -27,23 +27,23 @@ export class PawnBishop implements Piece { constructor(color: PlayerColor) { this.#color = color; } -getAvailableMoves(board: Board, point: Point): Point[] { - // Get available moves from the Bishop - const bishopMoves = new Bishop(this.#color).getAvailableMoves(board, point); - - // Get available moves from the Pawn - const pawnMoves = new Pawn(this.#color).getAvailableMoves(board, point); - - // Filter out pawn moves that overlap with bishop moves - const filteredPawnMoves = pawnMoves.filter(pawnMove => - !bishopMoves.some(bishopMove => bishopMove.x === pawnMove.x && bishopMove.y === pawnMove.y) - ); - - // Combine the filtered pawn moves with bishop moves - return [ - ...filteredPawnMoves, - ...bishopMoves - ]; -} - + getAvailableMoves(board: Board, point: Point): Point[] { + // Get available moves from the Bishop + const bishopMoves = new Bishop(this.#color).getAvailableMoves(board, point); + + // Get available moves from the Pawn + const pawnMoves = new Pawn(this.#color).getAvailableMoves(board, point); + + // Filter out pawn moves that overlap with bishop moves + const filteredPawnMoves = pawnMoves.filter( + (pawnMove) => + !bishopMoves.some( + (bishopMove) => + bishopMove.x === pawnMove.x && bishopMove.y === pawnMove.y, + ), + ); + + // Combine the filtered pawn moves with bishop moves + return [...filteredPawnMoves, ...bishopMoves]; + } } diff --git a/src/pieces/pawnKnight.ts b/src/pieces/pawnKnight.ts index d6f714e..cb220f9 100644 --- a/src/pieces/pawnKnight.ts +++ b/src/pieces/pawnKnight.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Knight } from "./knight"; import { Pawn } from "./pawn"; import type { Piece } from "./piece"; @@ -28,10 +28,9 @@ export class PawnKnight implements Piece { this.#color = color; } getAvailableMoves(board: Board, point: Point): Point[] { - return [ - ...new Pawn(this.#color).getAvailableMoves(board, point), - ...new Knight(this.#color).getAvailableMoves(board, point) - ]; -} - + return [ + ...new Pawn(this.#color).getAvailableMoves(board, point), + ...new Knight(this.#color).getAvailableMoves(board, point), + ]; + } } diff --git a/src/pieces/pawnRook.ts b/src/pieces/pawnRook.ts index 9a0285a..ec398b3 100644 --- a/src/pieces/pawnRook.ts +++ b/src/pieces/pawnRook.ts @@ -1,6 +1,6 @@ import type { OldCell } from "../cell"; -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Pawn } from "./pawn"; import type { Piece } from "./piece"; import { Rook } from "./rook"; @@ -36,16 +36,14 @@ export class PawnRook implements Piece { const pawnMoves = new Pawn(this.#color).getAvailableMoves(board, point); // Filter out pawn moves that overlap with rook moves - const filteredPawnMoves = pawnMoves.filter(pawnMove => - !rookMoves.some(rookMove => rookMove.x === pawnMove.x && rookMove.y === pawnMove.y) + const filteredPawnMoves = pawnMoves.filter( + (pawnMove) => + !rookMoves.some( + (rookMove) => rookMove.x === pawnMove.x && rookMove.y === pawnMove.y, + ), ); // Combine the filtered pawn moves with rook moves - return [ - ...filteredPawnMoves, - ...rookMoves - ]; + return [...filteredPawnMoves, ...rookMoves]; } } - - diff --git a/src/pieces/piece.ts b/src/pieces/piece.ts index 2dd1a15..ca164b3 100644 --- a/src/pieces/piece.ts +++ b/src/pieces/piece.ts @@ -1,5 +1,5 @@ -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; export interface Piece { get color(): PlayerColor; diff --git a/src/pieces/rook.ts b/src/pieces/rook.ts index 412007a..e1e5715 100644 --- a/src/pieces/rook.ts +++ b/src/pieces/rook.ts @@ -1,5 +1,5 @@ -import Board from "../game/board"; -import { Point } from "../game/point"; +import type Board from "../game/board"; +import type { Point } from "../game/point"; import { Bishop } from "./bishop"; import { Knight } from "./knight"; import type { Piece } from "./piece"; @@ -26,59 +26,73 @@ export class Rook implements Piece { constructor(color: PlayerColor) { this.#color = color; } -getAvailableMoves(board: Board, { x, y }: Point): Point[] { - const points: Point[] = []; + getAvailableMoves(board: Board, { x, y }: Point): Point[] { + const points: Point[] = []; - // Upward movement (North) - for (let yi = y - 1; yi >= 0; yi--) { - const cell = board.cellAt({ x, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { - break; - } - points.push({ x, y: yi }); - if (cell.piece) { - break; - } - } + // Upward movement (North) + for (let yi = y - 1; yi >= 0; yi--) { + const cell = board.cellAt({ x, y: yi }); + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { + break; + } + points.push({ x, y: yi }); + if (cell.piece) { + break; + } + } - // Downward movement (South) - for (let yi = y + 1; yi < board.size; yi++) { - const cell = board.cellAt({ x, y: yi }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { - break; - } - points.push({ x, y: yi }); - if (cell.piece) { - break; - } - } + // Downward movement (South) + for (let yi = y + 1; yi < board.size; yi++) { + const cell = board.cellAt({ x, y: yi }); + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { + break; + } + points.push({ x, y: yi }); + if (cell.piece) { + break; + } + } - // Leftward movement (West) - for (let xi = x - 1; xi >= 0; xi--) { - const cell = board.cellAt({ x: xi, y }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { - break; - } - points.push({ x: xi, y }); - if (cell.piece) { - break; - } - } + // Leftward movement (West) + for (let xi = x - 1; xi >= 0; xi--) { + const cell = board.cellAt({ x: xi, y }); + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { + break; + } + points.push({ x: xi, y }); + if (cell.piece) { + break; + } + } - // Rightward movement (East) - for (let xi = x + 1; xi < board.size; xi++) { - const cell = board.cellAt({ x: xi, y }); - if (!cell || cell.building === "wall" || cell.piece?.color === this.#color) { - break; - } - points.push({ x: xi, y }); - if (cell.piece) { - break; - } - } + // Rightward movement (East) + for (let xi = x + 1; xi < board.size; xi++) { + const cell = board.cellAt({ x: xi, y }); + if ( + !cell || + cell.building === "wall" || + cell.piece?.color === this.#color + ) { + break; + } + points.push({ x: xi, y }); + if (cell.piece) { + break; + } + } - return points; -} - - + return points; + } }