Skip to content

Commit ea27f93

Browse files
committed
implemented a method to make moves
1 parent c72dc84 commit ea27f93

File tree

4 files changed

+170
-5
lines changed

4 files changed

+170
-5
lines changed

src/chess.js

+94-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1-
import { GAME_ONGOING, WHITE, DEFAULT_FEN } from './constants';
1+
import {
2+
GAME_ONGOING,
3+
WHITE,
4+
DEFAULT_FEN,
5+
CASTLE_QUEENSIDE,
6+
CASTLE_KINGSIDE,
7+
PAWN,
8+
BLACK
9+
} from './constants';
210
import FenParser from './fen-parser';
311
import Board from './board/board';
4-
import { getPieceColor } from './utils';
12+
import {
13+
getPieceColor,
14+
parseBoardPosition,
15+
buildPieceString,
16+
getBoardPieceAt,
17+
updatePiecePosition,
18+
stringifyBoardPosition
19+
} from './utils';
520

621
class Chess {
722
constructor(fen = null) {
@@ -21,6 +36,8 @@ class Chess {
2136
this.halfMoves = 0;
2237
this.fullMoves = 1;
2338

39+
this.deadPieces = [];
40+
2441
this.loadFen(fen || DEFAULT_FEN);
2542
}
2643

@@ -80,11 +97,85 @@ class Chess {
8097
);
8198
}
8299

83-
move() {}
100+
move(piece, to) {
101+
const color = getPieceColor(piece);
102+
if (color !== this.activeColor) {
103+
throw new Error(`Not ${color} turn`);
104+
}
105+
106+
const board = this.getBoard();
107+
const legalMove = this.board
108+
.getLegalMovesForPiece(piece, board, this.enPassantTarget, this.castling)
109+
.find(move => move.to === to);
110+
111+
if (!legalMove) {
112+
throw new Error('Move not legal');
113+
}
114+
115+
// Move the piece
116+
const fromPos = parseBoardPosition(legalMove.from);
117+
const toPos = parseBoardPosition(legalMove.to);
118+
board[fromPos.y][fromPos.x] = null;
119+
board[toPos.y][toPos.x] = buildPieceString(legalMove.piece, color, legalMove.to);
120+
121+
if (legalMove.capture) {
122+
this.deadPieces.push(legalMove.capturedPiece);
123+
}
124+
125+
// Move castling rook
126+
if (legalMove.castle) {
127+
const castleRookY = color === WHITE ? 7 : 0;
128+
129+
if (legalMove.castle === CASTLE_QUEENSIDE) {
130+
const castleRookX = 0;
131+
const castleRook = getBoardPieceAt(board, castleRookX, castleRookY);
132+
const newRookPosition = stringifyBoardPosition(castleRookX + 3, castleRookY);
133+
board[castleRookY][castleRookX] = null;
134+
board[castleRookY][castleRookX + 3] = updatePiecePosition(castleRook, newRookPosition);
135+
} else if (legalMove.castle === CASTLE_KINGSIDE) {
136+
const castleRookX = 7;
137+
const castleRook = getBoardPieceAt(board, 7, castleRookY);
138+
const newRookPosition = stringifyBoardPosition(castleRookX - 2, castleRookY);
139+
board[castleRookY][castleRookX] = null;
140+
board[castleRookY][castleRookX - 2] = updatePiecePosition(castleRook, newRookPosition);
141+
}
142+
}
143+
144+
// En passant target (if a pawn does a 2 step move)
145+
if (legalMove.piece === PAWN && Math.abs(fromPos.y - toPos.y) === 2) {
146+
const enPassantTargetY = color === WHITE ? fromPos.y - 1 : fromPos.y + 1;
147+
this.enPassantTarget = stringifyBoardPosition(fromPos.x, enPassantTargetY);
148+
} else {
149+
this.enPassantTarget = null;
150+
}
151+
152+
this.board = new Board(board);
153+
this.fullMoves += 1;
154+
this.halfMoves = Math.floor((this.fullMoves + 1) / 2);
155+
this.activeColor = color === WHITE ? BLACK : WHITE;
156+
}
84157

85158
isCheck() {}
86159

87160
isCheckmate() {}
161+
162+
isDone() {
163+
const board = this.getBoard();
164+
const legalMoves = this.board.getAllLegalMoves(
165+
board,
166+
this.activeColor,
167+
this.enPassantTarget,
168+
this.castling
169+
);
170+
if (legalMoves.length === 0) {
171+
return true;
172+
}
173+
return false;
174+
}
175+
176+
getBoard() {
177+
return this.board.getBoard();
178+
}
88179
}
89180

90181
export default Chess;

src/chess.test.js

+74
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,78 @@ describe('Chess class instance', () => {
1010
chess.loadFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
1111
expect(chess.castling).toEqual({ K: true, Q: true, k: true, q: true });
1212
});
13+
14+
describe('chess moves', () => {
15+
it('should prevent black from making a first move', () => {
16+
expect(() => chess.move('p@D7', 'D5')).toThrowError();
17+
});
18+
it('should allow white to make only 1 move', () => {
19+
expect(() => chess.move('P@D2', 'D4')).not.toThrowError();
20+
expect(() => chess.move('P@E2', 'E3')).toThrowError('Not w turn');
21+
});
22+
it('should record en passant target when 2 step pawn move', () => {
23+
chess.move('P@D2', 'D4');
24+
expect(chess.enPassantTarget).toBe('D3');
25+
chess.move('p@D7', 'D5');
26+
expect(chess.enPassantTarget).toBe('D6');
27+
chess.move('P@C2', 'C3');
28+
expect(chess.enPassantTarget).toBe(null);
29+
});
30+
it('should move rooks when castling queen side', () => {
31+
chess.move('P@D2', 'D4');
32+
chess.move('p@D7', 'D5');
33+
chess.move('P@B2', 'B3');
34+
chess.move('p@B7', 'B6');
35+
chess.move('B@C1', 'B2');
36+
chess.move('b@C8', 'B7');
37+
chess.move('N@B1', 'C3');
38+
chess.move('n@B8', 'C6');
39+
chess.move('Q@D1', 'D2');
40+
chess.move('q@D8', 'D7');
41+
42+
// white queen side castle
43+
chess.move('K@E1', 'C1');
44+
let board = chess.getBoard();
45+
expect(board[7][0]).toBe(null);
46+
expect(board[7][3]).toBe('R@D1');
47+
48+
// black queen side castle
49+
chess.move('k@E8', 'C8');
50+
board = chess.getBoard();
51+
expect(board[0][0]).toBe(null);
52+
expect(board[0][3]).toBe('r@D8');
53+
});
54+
it('should move rooks when castling king side', () => {
55+
chess.move('P@E2', 'E4');
56+
chess.move('p@E7', 'E5');
57+
chess.move('P@G2', 'G3');
58+
chess.move('p@G7', 'G6');
59+
chess.move('B@F1', 'G2');
60+
chess.move('b@F8', 'G7');
61+
chess.move('N@G1', 'F3');
62+
chess.move('n@G8', 'F6');
63+
64+
// white king side castle
65+
chess.move('K@E1', 'G1');
66+
let board = chess.getBoard();
67+
expect(board[7][7]).toBe(null);
68+
expect(board[7][5]).toBe('R@F1');
69+
70+
// black king side castle
71+
chess.move('k@E8', 'G8');
72+
board = chess.getBoard();
73+
expect(board[0][7]).toBe(null);
74+
expect(board[0][5]).toBe('r@F8');
75+
});
76+
it('should mark game as done if checkmate', () => {
77+
chess.move('P@E2', 'E4');
78+
chess.move('p@E7', 'E5');
79+
chess.move('B@F1', 'C4');
80+
chess.move('p@D7', 'D6');
81+
chess.move('Q@D1', 'F3');
82+
chess.move('n@B8', 'C6');
83+
chess.move('Q@F3', 'F7');
84+
expect(chess.isDone()).toBe(true);
85+
});
86+
});
1387
});

src/pieces/piece.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class Piece {
9999
piece: this.type,
100100
color: this.color,
101101
capture: isCapture,
102-
capturePiece: isCapture ? occupiedPiece : null,
102+
capturedPiece: isCapture ? occupiedPiece : null,
103103
enPassant: isEnPassant,
104104
castle: isCastle ? move.type : null
105105
};

src/pieces/piece.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('Chess piece class', () => {
6363
expect(setPieceColor(null)).toThrowError();
6464
});
6565

66-
it('should should validate piece position', () => {
66+
it('should validate piece position', () => {
6767
expect(setPiecePosition('A4')).not.toThrowError();
6868
expect(setPiecePosition('H8')).not.toThrowError();
6969
expect(setPiecePosition('F7')).not.toThrowError();

0 commit comments

Comments
 (0)