Creating a chess board in JavaScript is straightforward once you have knowledge of the Forsyth–Edwards Notation (FEN), a string of characters carrying information about the position of a chess board. For instance, the FEN of the starting position is as follows:
rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
Forsyth-Edwards Notation (FEN)
To draw the board, you only need the string of characters at the beginning of the FEN. To begin, you can create a function that turns this string into an array of length 64. Here is an example of how to do this in JavaScript:
function fenToArray(fen) {
const piecesString = fen.split(' ')[0].replace(/\//g, '');
const piecesArrayNums = piecesString.split('');
const piecesArray = piecesArrayNums.map(piece => {
if (parseInt(piece)) {
return [...Array(parseInt(piece)).fill(null)];
};
return piece;
}).flat();
return piecesArray;
}
Additionally, you will need images of pieces to render on the board, as well as two variables for the color of the light and dark squares. Here is an example of how to set up these objects and variables:
const lightSquare = '#c4c4c4';
const darkSquare = selectedColor;
const piecePngObj = {
'b': blackBishop,
'n': blackKnight,
'k': blackKing,
'p': blackPawn,
'q': blackQueen,
'r': blackRook,
'B': whiteBishop,
'N': whiteKnight,
'K': whiteKing,
'P': whitePawn,
'Q': whiteQueen,
'R': whiteRook,
}
Here, the values of the piecePngObj object reference the path to the 12 piece images.
Finally, you can create the board itself. Here is an example of how to do this in React with Material UI, though the logic will be similar in other implementations:
First, create the board of 64 squares.
function Board() {
const fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
const fenArray = fenToArray(fen);
const squares = [];
// Create board squares and pieces
for (let i = 0; i < 64; i++) {
const row = Math.floor(i / 8);
const color = (row % 2 === 0 && i % 2 === 0) ||
(row % 2 === 1 && i % 2 === 1)
? lightSquare : darkSquare;
squares.push(
<Box
key={i}
bgcolor={color}
sx={{
width: "100%",
height: "100%",
backgroundColor: color,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
</Box>
);
};
return (
<Box
className='board-container'
sx={{
height: length,
width: length,
display: 'grid',
gridTemplateColumns: 'repeat(8, 1fr)',
gridTemplateRows: 'repeat(8, 1fr)',
position: 'relative',
}}
>
{squares}
</Box>
);
}
To determine the color of the i-th square, it is necessary to consider if the row is odd or even; the first color in each row alternates, and the colors also alternate through each row. We store the 64 squares in a variable called squares
, which is then returned wrapped in a Material UI <Box/>
component. To make the 64 squares render in an 8x8 grid, use the gridTemplateColumns
and gridTemplateRows
CSS properties. For non-React and non-MUI implementations, this part may look different.
To add the piece images to the board, use the fenArray
variable defined earlier.
import Draggable from 'react-draggable';
function Board() {
const fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
const fenArray = fenToArray(fen);
const squares = [];
// Create board squares and pieces
for (let i = 0; i < 64; i++) {
const row = Math.floor(i / 8);
const color = (row % 2 === 0 && i % 2 === 0) ||
(row % 2 === 1 && i % 2 === 1)
? lightSquare : darkSquare;
const pieceImg = (
<Box
draggable='false'
component='img'
src={piecePngObj[`${fenArray[i]}`]}
alt=''
sx={{ maxWidth: "100%", maxHeight: "100%" }}
/>
);
squares.push(
<Box
key={i}
bgcolor={color}
sx={{
width: "100%",
height: "100%",
backgroundColor: color,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{staticBoard ? pieceImg :
<Draggable>
{pieceImg}
</Draggable>
}
</Box>
);
};
return (
<Box
className='board-container'
sx={{
height: length,
width: length,
display: 'grid',
gridTemplateColumns: 'repeat(8, 1fr)',
gridTemplateRows: 'repeat(8, 1fr)',
position: 'relative',
}}
>
{squares}
</Box>
);
}
The pieceImg
variable is an <img/>
component that displays the corresponding image for each non-empty square, or an empty square if the square is empty. The image source is determined by referencing the piecePngObj
object containing the links to the various piece images.
If using React, it's possible to make the pieces draggable using the react-draggable
npm package. However, additional work is required to ensure that the pieces behave correctly within the board, such as staying inside the board boundaries and snapping back to their original positions upon release.
Full code:
import Draggable from 'react-draggable';
import Box from '@mui/material/Box';
const lightSquare = '#c4c4c4';
const darkSquare = selectedColor;
const piecePngObj = {
'b': blackBishop,
'n': blackKnight,
'k': blackKing,
'p': blackPawn,
'q': blackQueen,
'r': blackRook,
'B': whiteBishop,
'N': whiteKnight,
'K': whiteKing,
'P': whitePawn,
'Q': whiteQueen,
'R': whiteRook,
}
function fenToArray(fen) {
const piecesString = fen.split(' ')[0].replace(/\//g, '');
const piecesArrayNums = piecesString.split('');
const piecesArray = piecesArrayNums.map(piece => {
if (parseInt(piece)) {
return [...Array(parseInt(piece)).fill(null)];
};
return piece;
}).flat();
return piecesArray;
}
function Board() {
const fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
const fenArray = fenToArray(fen);
const squares = [];
// Create board squares and pieces
for (let i = 0; i < 64; i++) {
const row = Math.floor(i / 8);
const color = (row % 2 === 0 && i % 2 === 0) ||
(row % 2 === 1 && i % 2 === 1)
? lightSquare : darkSquare;
const pieceImg = (
<Box
draggable='false'
component='img'
src={piecePngObj[`${fenArray[i]}`]}
alt=''
sx={{ maxWidth: "100%", maxHeight: "100%" }}
/>
);
squares.push(
<Box
key={i}
bgcolor={color}
sx={{
width: "100%",
height: "100%",
backgroundColor: color,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{staticBoard ? pieceImg :
<Draggable
bounds='.board-container'
onStart={onStart}
onStop={() => onStop(i)}
onDrag={(e, ui) => handleDrag(e, ui, i)}
position={positions[i]}
>
{pieceImg}
</Draggable>
}
</Box>
);
};
return (
<Box
className='board-container'
sx={{
height: length,
width: length,
display: 'grid',
gridTemplateColumns: 'repeat(8, 1fr)',
gridTemplateRows: 'repeat(8, 1fr)',
position: 'relative',
}}
>
{squares}
</Box>
);
}
export default Board;
Top comments (0)