Skip to content

Commit

Permalink
Implements castling rights tracking.
Browse files Browse the repository at this point in the history
  • Loading branch information
aryann committed Oct 6, 2024
1 parent f2d7c16 commit a6534fc
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 5 deletions.
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"cSpell.words": ["aryann", "immer", "perft", "RNBQKBNR", "tanstack"],
"cSpell.words": [
"aryann",
"immer",
"Kiwipete",
"perft",
"RNBQKBNR",
"tanstack"
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[json]": {
Expand Down
111 changes: 110 additions & 1 deletion engine/src/board.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ describe("from fen", () => {
assert.isUndefined(board.get("h8"));
});

it("color", () => {
it("side to move", () => {
assert.equal(
new BoardState(
"8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - 40 40"
Expand All @@ -331,3 +331,112 @@ describe("from fen", () => {
);
});
});

describe("castling rights", () => {
it("K move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("e2", "e3");
board.move("a7", "a6");
board.move("f1", "e2");
board.move("b7", "b6");
board.move("g1", "f3");
board.move("c7", "c6");

assert.include(board.fen(), "KQkq");

board.move("e1", "f1");
assert.equal(
board.fen(),
"rnbqkbnr/3ppppp/ppp5/8/8/4PN2/PPPPBPPP/RNBQ1K1R b kq - 1 4"
);
});

it("k move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("a2", "a3");
board.move("e7", "e6");
board.move("b2", "b3");
board.move("f8", "e7");
board.move("c2", "c3");
board.move("g8", "f6");
board.move("d2", "d3");

assert.include(board.fen(), "KQkq");

board.move("e8", "f8");
assert.equal(
board.fen(),
"rnbq1k1r/ppppbppp/4pn2/8/8/PPPP4/4PPPP/RNBQKBNR w KQ - 1 5"
);
});

it("queen side R move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("b1", "c3");
board.move("a7", "a6");

assert.include(board.fen(), "KQkq");

board.move("a1", "b1");
assert.equal(
board.fen(),
"rnbqkbnr/1ppppppp/p7/8/8/2N5/PPPPPPPP/1RBQKBNR b Kkq - 1 2"
);
});

it("king side R move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("g1", "f3");
board.move("a7", "a6");

assert.include(board.fen(), "KQkq");

board.move("h1", "g1");
assert.equal(
board.fen(),
"rnbqkbnr/1ppppppp/p7/8/8/5N2/PPPPPPPP/RNBQKBR1 b Qkq - 1 2"
);
});

it("queen side r move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("a2", "a3");
board.move("b8", "c6");
board.move("b2", "b3");

assert.include(board.fen(), "KQkq");

board.move("a8", "b8");
assert.equal(
board.fen(),
"1rbqkbnr/pppppppp/2n5/8/8/PP6/2PPPPPP/RNBQKBNR w KQk - 1 3"
);
});

it("king side r move", () => {
const board = new BoardState();
assert.include(board.fen(), "KQkq");

board.move("a2", "a3");
board.move("g8", "f6");
board.move("b2", "b3");

assert.include(board.fen(), "KQkq");

board.move("h8", "g8");
assert.equal(
board.fen(),
"rnbqkbr1/pppppppp/5n2/8/8/PP6/2PPPPPP/RNBQKBNR w KQq - 1 3"
);
});
});
69 changes: 66 additions & 3 deletions engine/src/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ type State = {
isWhiteTurn: boolean;
halfMoves: number;
fullMoves: number;

castlingRights: {
white: {
kingSide: boolean;
queenSide: boolean;
};
black: {
kingSide: boolean;
queenSide: boolean;
};
};
};

export class BoardState {
Expand Down Expand Up @@ -49,6 +60,8 @@ export class BoardState {
this.state.halfMoves++;
}

this.updateCastlingRights(from);

this.state.board[toIndex] = this.state.board[fromIndex];
this.state.board[fromIndex] = 0;

Expand All @@ -58,6 +71,23 @@ export class BoardState {
this.state.isWhiteTurn = !this.state.isWhiteTurn;
}

// Updates the castling rights. This function assumes that the move has
// already been determined to be valid.
private updateCastlingRights(from: TSquare) {
if (from === "a1" || from === "e1") {
this.state.castlingRights.white.queenSide = false;
}
if (from === "h1" || from === "e1") {
this.state.castlingRights.white.kingSide = false;
}
if (from === "a8" || from === "e8") {
this.state.castlingRights.black.queenSide = false;
}
if (from === "h8" || from === "e8") {
this.state.castlingRights.black.kingSide = false;
}
}

isLegal(from: TSquare, to: TSquare): boolean {
const fromIndex = this.toIndex(from);
const piece = this.intToPiece(this.state.board[fromIndex]);
Expand Down Expand Up @@ -103,9 +133,30 @@ export class BoardState {
const turn = this.state.isWhiteTurn ? "w" : "b";

// TODO: Add support for castling rights, en passant, and move counters.
return `${ranks.join("/")} ${turn} KQkq - ${this.state.halfMoves} ${
this.state.fullMoves
}`;
return `${ranks.join("/")} ${turn} ${this.fenCastlingRights()} - ${
this.state.halfMoves
} ${this.state.fullMoves}`;
}

private fenCastlingRights(): string {
const castlingRights = [];
if (this.state.castlingRights.white.kingSide) {
castlingRights.push("K");
}
if (this.state.castlingRights.white.queenSide) {
castlingRights.push("Q");
}
if (this.state.castlingRights.black.kingSide) {
castlingRights.push("k");
}
if (this.state.castlingRights.black.queenSide) {
castlingRights.push("q");
}
if (castlingRights.length === 0) {
return "-";
}

return castlingRights.join("");
}

sideToMove(): TSide {
Expand Down Expand Up @@ -148,6 +199,8 @@ export class BoardState {
}
const isWhiteTurn = turn === "w";

const castlingRights = parts[2];

const halfMoves = parseInt(parts[4]);
if (Number.isNaN(halfMoves) || halfMoves < 0) {
throw `Forsyth–Edwards Notation (FEN) has invalid half moves: ${fen}`;
Expand Down Expand Up @@ -188,6 +241,16 @@ export class BoardState {
isWhiteTurn,
halfMoves,
fullMoves,
castlingRights: {
white: {
kingSide: castlingRights.includes("K"),
queenSide: castlingRights.includes("Q"),
},
black: {
kingSide: castlingRights.includes("k"),
queenSide: castlingRights.includes("q"),
},
},
};
}

Expand Down

0 comments on commit a6534fc

Please sign in to comment.