Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#1] Implemented en passant logic #92

Merged
merged 9 commits into from
Dec 16, 2023
Merged
121 changes: 81 additions & 40 deletions development/src/logic/logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
King,
Square,
Position,
enPassantPosition,
resetEnPassantPosition,
} from './pieces';
import { Logger } from '../ui/logger';
import {
Expand Down Expand Up @@ -199,7 +201,7 @@ export function onFallOffTheBoard(draggedElement: HTMLElement, board: string) {
if (!draggedPiece) return;
if (!isAllowedToMove(draggedPiece)) return;

killPiece(draggedPiece);
permanentlyKillPiece(draggedPiece);
fellOffTheBoardPiece = draggedPiece;

endTurn();
Expand Down Expand Up @@ -235,19 +237,66 @@ function actOnTurn(
actOnTurnPieceToPiece(draggedPiece, targetPiece);
} else {
const targetSquare = target as Square;

actOnTurnPieceToSquare(draggedPiece, targetSquare);
}
}

function actOnTurnPieceToPiece(draggedPiece: Piece, targetPiece: Piece) {
export function actOnTurnPieceToPiece(
draggedPiece: Piece,
targetPiece: Piece,
) {
isFriendlyFire = targetPiece.player === draggedPiece.player;
draggedPiece.hasKilled = true;

deathCounter++;
isPieceKilled = true;
destroyPieceOnBoard(targetPiece);
killPiece(draggedPiece ,targetPiece);

const targetSquare: Square = { position: targetPiece.position };
move(draggedPiece, targetSquare);
}

function actOnTurnPieceToSquare(draggedPiece: Piece, targetSquare: Square) {
let isValidCastling = true;
if (isCastling) {
isValidCastling = castle(draggedPiece, targetSquare);
}

if (isValidCastling) {
if (draggedPiece instanceof Pawn && draggedPiece.enPassant){
if (!enPassantPosition) return;
const targetPiece = getPieceByPositionAndBoard(enPassantPosition);
if (!targetPiece) return;

killPiece(draggedPiece, targetPiece, targetSquare.position);
}
move(draggedPiece, targetSquare);
} else {
switchIsCastling();
}
}

function actOnTurnPieceToTrap(draggedPiece: Piece, targetItem: Item) {
permanentlyKillPiece(draggedPiece);
items = items.filter((item) => item !== targetItem);
destroyItemOnBoard(targetItem);

if (draggedPiece.position.board === OVERWORLD_BOARD_ID) {
draggedPiece.position = {...targetItem.position};
draggedPiece.position.board = draggedPiece.hasKilled
? HELL_BOARD_ID
: HEAVEN_BOARD_ID;
spawnPieceOnBoard(draggedPiece);
}

endTurn();
}

function killPieceProcess(
draggedPiece: Piece,
targetPiece: Piece,
targetPosition: Position,
) {
if (targetPiece.position.board === OVERWORLD_BOARD_ID) {
targetPiece.position = targetPosition;

Logger.logKill(`A ${targetPiece.player.color} ${targetPiece.name}
was killed by a ${draggedPiece.player.color} ${draggedPiece.name}.`);

Expand All @@ -272,7 +321,7 @@ function actOnTurnPieceToPiece(draggedPiece: Piece, targetPiece: Piece) {
const areTheSame = piece === targetPiece;

if (areOnTheSamePosition && !areTheSame) {
killPiece(piece);
permanentlyKillPiece(piece);
}
});

Expand All @@ -290,45 +339,26 @@ function actOnTurnPieceToPiece(draggedPiece: Piece, targetPiece: Piece) {
const areTheSame = piece === targetPiece;

if (areOnTheSamePosition && !areTheSame) {
killPiece(piece);
permanentlyKillPiece(piece);
}
});
}

const targetSquare: Square = { position: targetPiece.position };
move(draggedPiece, targetSquare);
}

function actOnTurnPieceToSquare(draggedPiece: Piece, targetSquare: Square) {
let isValidCastling = true;
if (isCastling) {
isValidCastling = castle(draggedPiece, targetSquare);
}

if (isValidCastling) {
move(draggedPiece, targetSquare);
} else {
switchIsCastling();
}
}

function actOnTurnPieceToTrap(draggedPiece: Piece, targetItem: Item) {
killPiece(draggedPiece);
items = items.filter((item) => item !== targetItem);
destroyItemOnBoard(targetItem);

if (draggedPiece.position.board === OVERWORLD_BOARD_ID) {
draggedPiece.position = {...targetItem.position};
draggedPiece.position.board = draggedPiece.hasKilled
? HELL_BOARD_ID
: HEAVEN_BOARD_ID;
spawnPieceOnBoard(draggedPiece);
}

endTurn();
function killPiece(
draggedPiece: Piece,
targetPiece: Piece,
targetPosition = targetPiece.position,
) {
draggedPiece.hasKilled = true;
deathCounter++;
isPieceKilled = true;
destroyPieceOnBoard(targetPiece);
killPieceProcess(draggedPiece, targetPiece, targetPosition);
}

function killPiece(targetPiece: Piece) {
function permanentlyKillPiece(targetPiece: Piece) {
pieces = pieces.filter((piece) => piece !== targetPiece);
deathCounter++;
isPieceKilled = true;
Expand Down Expand Up @@ -399,7 +429,6 @@ function endTurn() {
currentPlayerIndex =
currentPlayerIndex + 1 < players.length ? currentPlayerIndex + 1 : 0;
turnCounter++;

if (turnCounter % players.length === 0) {
turnCounter = 0;
roundCounter++;
Expand All @@ -413,4 +442,16 @@ function resetVariables() {
isFriendlyFire = false;
isPieceKilled = false;
fellOffTheBoardPiece = undefined;
pieces.forEach((piece) => {
if (piece.player !== getCurrentPlayer() && piece instanceof Pawn){
piece.enPassant = false;
}
});

if (
enPassantPosition &&
getCurrentPlayer() !== getPieceByPositionAndBoard(enPassantPosition)?.player
) {
resetEnPassantPosition();
}
}
18 changes: 16 additions & 2 deletions development/src/logic/pieces.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { OVERWORLD_BOARD_ID } from './constants';
import { Player, PlayerColors } from './players';
import { Position, Pawn, Bishop, Knight, Rook, Queen, King } from './pieces';
import { Position, Pawn, Bishop, Knight, Rook, Queen, King, setEnPassantPosition } from './pieces';

const whitePlayer = new Player(PlayerColors.WHITE);
const blackPlayer = new Player(PlayerColors.BLACK);
Expand Down Expand Up @@ -42,6 +42,20 @@ describe('Piece movements', () => {
});
expect(singleStepValidMove).toEqual(singleStepMove);

pawn.position = initialPosition;
setEnPassantPosition({
coordinates: [1,6],
board: OVERWORLD_BOARD_ID,
});
const enPassantMove: Position = {
coordinates: [1,5],
board: OVERWORLD_BOARD_ID,
};
const enPassantValidMove = pawn.validateMove({
position: enPassantMove,
});
expect(enPassantValidMove).toEqual(enPassantMove);

pawn.position = initialPosition;
const twoStepsInitialMove: Position = {
coordinates: [0, 4],
Expand All @@ -61,7 +75,7 @@ describe('Piece movements', () => {
);
const diagonalAttackValidMove = pawn.validateMove(diagonalAttackMove);
expect(diagonalAttackValidMove).toEqual(diagonalAttackMove.position);

pawn.position = initialPosition;
const invalidPosition: Position = {
coordinates: [0, 3],
Expand Down
38 changes: 31 additions & 7 deletions development/src/logic/pieces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ export type Position = {
coordinates: [number, number],
board: string,
}
export let enPassantPosition: Position | undefined;

export function resetEnPassantPosition() {
enPassantPosition = undefined;
}
export function setEnPassantPosition(position: Position) {
enPassantPosition = position;
}

interface PieceType {
position: Position;
Expand All @@ -38,7 +46,6 @@ export class Piece implements PieceType {
name: string;
hasMoved: boolean;
hasKilled: boolean;

constructor(
position: Position,
player: Player,
Expand Down Expand Up @@ -78,8 +85,12 @@ export type Square = {
};

export class Pawn extends Piece {

enPassant: boolean;

constructor(position: Position, player: Player) {
super(position, player, pawnResource, 'Pawn');
this.enPassant = false;
}

validateMove(target: Piece | Square) {
Expand All @@ -90,7 +101,6 @@ export class Pawn extends Piece {

const absDeltaX = Math.abs(deltaX);
const absDeltaY = Math.abs(deltaY);

const stepY =
target.position.coordinates[1] > this.position.coordinates[1]
? 1
Expand All @@ -106,26 +116,40 @@ export class Pawn extends Piece {
) {
return this.position;
}

// Pawns can attack diagonally.
const isDiagonalMovement = absDeltaY === 1 && absDeltaX === 1;
this.enPassant =
!!enPassantPosition &&
isDiagonalMovement &&
(targetCoordinates[0] === enPassantPosition.coordinates[0]) &&
Math.abs(targetCoordinates[1] - enPassantPosition.coordinates[1]) === 1;

// Pawns attack diagonally.
if ((target as Piece).name !== undefined) {
return absDeltaY === 1 && absDeltaX === 1
if (
(this.enPassant) ||
(target as Piece).name !== undefined
){
return isDiagonalMovement
? target.position
: this.position;
}

// Pawns can have an initial two-square move.
if (!this.hasMoved && absDeltaY === 2 && absDeltaX === 0) {
return simulateMove(
const validatedMove = simulateMove(
this.copyPosition(),
target.position,
0,
stepY,
2,
);
if (validatedMove === target.position) {
enPassantPosition = validatedMove;
}
return validatedMove;
}

// Pawns move one square forward.
// Pawns can move one square forward.
return absDeltaY === 1 && absDeltaX === 0
? target.position
: this.position;
Expand Down
Loading