Building a Web-based Chess Game with React and Chess.js
In this article, we’ll walk through the step-by-step process of creating a Chess game using Chess.js, ReactJS, ExpressJS, and NodeJS. This application will provide users with a platform for users to play chess. It will be a single player game, where the opponent will be played by the application itself.
Output Preview: Let us have a look at how the final output will look like.
Pre-requisites
Approach to Create Chess Game using Reactjs and Chess.js:
- Set up a new React project with create-react-app. Initialize a Git repository. Define the project structure.
- Create a folder called “chess-game” within the project directory.
- Within the “chess-game” folder, create the following files and directories:
- src/index.js: Entry point of the application. Renders the <App /> component.
- src/styles/App.css: CSS styles specific to the <App /> component.
- src/styles/index.css: Global CSS styles.
- src/components/App.js: Main component of the application. Contains the chess game logic.
- Inside the “chess-game” folder, run the command npm install react react-dom chess.js to install the React library.
Steps to Create Chess Game using Reactjs and Chess.js:
Step 1: Set up React project using the command
npx create-react-app chess-game
Step 2: Navigate to the project folder using
cd chess-game
Step 3: Installing the required packages:
npm install react react-dom chess.js@0.13.3 react-chessboard@1.2.5
Project Structure:
The updated Dependencies in package.json file of frontend will look like:
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"chess.js": "^0.13.3",
"react": "^18.2.0",
"react-chessboard": "^1.2.5",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}
Example: Create the required files and write the following code.
/* App.css */
.app {
color: white;
display: flex;
flex-direction: column;
align-items: center;
}
.header {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
}
.game-image {
width: 150px; /* Adjust the width as needed */
height: auto; /* Maintain aspect ratio */
margin-right: 20px;
}
.game-info {
display: flex;
flex-direction: column;
}
.chessboard-container {
position: relative;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.7);
padding: 20px;
border-radius: 5px;
text-align: center;
}
.game-over p {
margin: 5px 0;
}
/* index.css */
body {
margin: 0;
background-color: #222;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
// App.js
import '../styles/App.css';
import { useState, useEffect } from 'react';
import { Chessboard } from 'react-chessboard';
import { Chess } from 'chess.js';
function App() {
const [game, setGame] = useState(new Chess());
const [winner, setWinner] = useState(null);
const [gameOver, setGameOver] = useState(false);
// Let's perform a function on the game state
function safeGameMutate(modify) {
setGame((g) => {
const update = { ...g };
modify(update);
return update;
});
}
// Movement of computer
function makeRandomMove() {
const possibleMove = game.moves();
// exit if the game is over
if (game.game_over() || game.in_draw() || possibleMove.length === 0) {
setGameOver(true);
const winner = game.turn() === 'w' ? 'Black' : 'White';
setWinner(winner);
return;
}
// select random move
const randomIndex = Math.floor(Math.random() * possibleMove.length);
// play random move
safeGameMutate((game) => {
game.move(possibleMove[randomIndex]);
});
}
// Perform an action when a piece is dropped by a user
function onDrop(source, target) {
if (gameOver) return false;
let move = null;
safeGameMutate((game) => {
move = game.move({
from: source,
to: target,
promotion: 'q',
});
});
// illegal move
if (move === null) return false;
// valid move
setTimeout(makeRandomMove, 200);
return true;
}
// Reset the game
function restartGame() {
setGame(new Chess());
setGameOver(false);
setWinner(null);
}
// Listen for Enter key press to restart the game
useEffect(() => {
function handleKeyPress(event) {
if (event.key === 'Enter') {
restartGame();
}
}
window.addEventListener('keydown', handleKeyPress);
return () => {
window.removeEventListener('keydown', handleKeyPress);
};
}, []);
return (
<div className="app">
<div className="header">
<img src=
"https://media.w3wiki.net/wp-content/cdn-uploads/20210420155809/gfg-new-logo.png"
alt="Game Image" className="game-image" />
<div className="game-info">
<h1>w3wiki Chess Game</h1>
</div>
</div>
<div className="chessboard-container">
<Chessboard position={game.fen()} onPieceDrop={onDrop} />
{gameOver && (
<div className="game-over">
<p>Game Over</p>
<p>Winner: {winner}</p>
<p>Press Enter to restart</p>
</div>
)}
</div>
</div>
);
}
export default App;
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './styles/index.css';
import App from './components/App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
Start your application using the following command.
npm start
Output:
Contact Us