diff --git a/backend/package-lock.json b/backend/package-lock.json
index 67d84dc..e88a6f1 100644
--- a/backend/package-lock.json
+++ b/backend/package-lock.json
@@ -11,6 +11,7 @@
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
+ "chess.js": "^1.0.0-beta.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
@@ -144,6 +145,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/chess.js": {
+ "version": "1.0.0-beta.6",
+ "resolved": "https://registry.npmjs.org/chess.js/-/chess.js-1.0.0-beta.6.tgz",
+ "integrity": "sha512-sqBfX1VL3csSyqVM5ogbKA+aRlZyWDh276ruWXphwI0lDUMs7iYjZs29BOi49f7mXeunJE7cdfnIZhihsyLnsA=="
+ },
"node_modules/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
diff --git a/backend/package.json b/backend/package.json
index 10a5959..9c4282f 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -13,6 +13,7 @@
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.20.2",
+ "chess.js": "^1.0.0-beta.6",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
diff --git a/backend/socket.js b/backend/socket.js
index ff9d18d..c67ac5d 100644
--- a/backend/socket.js
+++ b/backend/socket.js
@@ -2,15 +2,19 @@ const socket = require("socket.io");
const { SOCKET_EVENTS } = require("./constants");
const { CHESS_MOVE, CHESS_OPPONENT_MOVE, CONNECTION, JOIN_ROOM, JOIN_ROOM_ERROR, JOIN_ROOM_SUCCESS, ROOM_FULL } =
SOCKET_EVENTS;
-// roomID => { timeLimit, players:[{username: {color}}] }
+// roomID => { timeLimit,gameHistory , players:[{username: {color}}] }
let activeRooms = new Map();
function createRoom(roomID, timeLimit) {
console.log(roomID, "created");
- activeRooms.set(roomID, { timeLimit, players: {} });
+ activeRooms.set(roomID, { timeLimit, players: {}, gameHistory: [] });
console.log("Currently active rooms", activeRooms.size);
}
+function getRoom(roomID) {
+ return activeRooms.get(roomID);
+}
+
// structure of userDetails: {username,color}
function addUserToRoom(roomID, userDetails) {
console.log(userDetails);
@@ -57,7 +61,9 @@ function socketIOServerInit(server) {
if (result === JOIN_ROOM_SUCCESS) {
socket.join(roomID);
io.to(roomID).emit("new user joined the room");
- socket.emit(result); // room joined successfully
+ console.log(data, "joined");
+ let room = getRoom(roomID);
+ socket.emit(result, room.gameHistory); // room joined successfully
} else {
socket.emit(result); // room is full
}
@@ -68,6 +74,8 @@ function socketIOServerInit(server) {
socket.on(CHESS_MOVE, (roomID, moveData) => {
console.log(moveData);
+ let room = activeRooms.get(roomID);
+ room.gameHistory.push(moveData);
socket.to(roomID).emit(CHESS_OPPONENT_MOVE, moveData);
});
});
diff --git a/frontend/src/components/Cell.jsx b/frontend/src/components/Cell.jsx
index 3d436c9..a05cf01 100644
--- a/frontend/src/components/Cell.jsx
+++ b/frontend/src/components/Cell.jsx
@@ -1,11 +1,14 @@
import React, { useContext, useState } from 'react'
import Piece from './Piece';
import { socket } from '../socket';
-import { Box, Flex } from '@mantine/core';
+import { Box, Flex, Modal } from '@mantine/core';
import { useDroppable } from '@dnd-kit/core'
import { ChessGameContext } from '../context/chess-game-context';
+import { SOCKET_EVENTS } from '../constants';
+const { CHESS_MOVE } = SOCKET_EVENTS
const Cell = ({ cell }) => {
+ let roomID = localStorage.getItem('roomID');
let { square, type, color } = cell;
const { getSquareColor, isSquareMarked, handleSquareClick } = useContext(ChessGameContext)
const [isDropped, setIsDropped] = useState(false);
@@ -14,7 +17,10 @@ const Cell = ({ cell }) => {
let marked = isSquareMarked(square);
const handleClick = () => {
- handleSquareClick(square);
+ handleSquareClick(square, (moveData) => {
+ // moveData contains fen string, from, to squares of the move
+ socket.emit(CHESS_MOVE, roomID, moveData);
+ });
}
let content = marked ? : ;
diff --git a/frontend/src/constants.js b/frontend/src/constants.js
index c85cdaf..c9548bc 100644
--- a/frontend/src/constants.js
+++ b/frontend/src/constants.js
@@ -14,4 +14,5 @@ export const DISPATCH_EVENTS = {
MOVE_PIECE: "MOVE_PIECE",
CAPTURE_PIECE: "CAPTURE_PIECE",
JUMP_TO: "JUMP_TO",
+ SET_GAME_HISTORY: "SET_GAME_HISTORY",
};
diff --git a/frontend/src/context/chess-game-context.jsx b/frontend/src/context/chess-game-context.jsx
index 94f8f37..1bf9732 100644
--- a/frontend/src/context/chess-game-context.jsx
+++ b/frontend/src/context/chess-game-context.jsx
@@ -2,7 +2,7 @@ import React, { createContext, useReducer, useRef } from 'react'
import { ChessModified, chessInit } from '../../utils/chess';
import { DISPATCH_EVENTS } from '../constants';
import ChessBoard from '../pages/Chess/ChessBoard';
-const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE, JUMP_TO } = DISPATCH_EVENTS
+const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE, JUMP_TO, SET_GAME_HISTORY } = DISPATCH_EVENTS
export const ChessGameContext = createContext();
// myColor: null, chess: null, chessBoard: null, moveHints: null, selected: null, dispatch: null, handleOpponentMove: null, handleSquareClick: null, getSquareColor: null, isSquareMarked: null, selectPiece: null, handleDrop: null
@@ -20,8 +20,8 @@ const reducer = (state, action) => {
console.log('Moving', action.val, state.chess.turn());
let newChessObj = new ChessModified({ prop: state.chess.fen(), color: state.chess.myColor });
let updatedGameHistory = state.gameHistory;
- let move = newChessObj.move(action.val);
- updatedGameHistory.push({ move: move.san, fen: newChessObj.fen() });
+ let { san, after } = newChessObj.move(action.val);
+ updatedGameHistory.push({ move: san, fen: after });
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 };
}
case CAPTURE_PIECE:
@@ -29,8 +29,8 @@ const reducer = (state, action) => {
console.log('Capture', action.val, state.chess.turn());
let newChessObj = new ChessModified({ prop: state.chess.fen(), color: state.chess.myColor });
let updatedGameHistory = state.gameHistory;
- let move = newChessObj.move(action.val);
- updatedGameHistory.push({ move: move.san, fen: newChessObj.fen() });
+ let { san, after } = newChessObj.move(action.val);
+ updatedGameHistory.push({ move: san, fen: after });
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 };
}
case JUMP_TO:
@@ -38,6 +38,17 @@ const reducer = (state, action) => {
let index = action.val;
return { ...state, currentIndex: index }
}
+ case SET_GAME_HISTORY:
+ {
+ let fetchedGameHistory = action.val;
+ let newChessObj = new ChessModified({ color: state.chess.myColor });
+ let updatedGameHistory = [];
+ for (let i = 0; i < fetchedGameHistory.length; i++) {
+ let { san, after } = newChessObj.move(fetchedGameHistory[i]);
+ updatedGameHistory.push({ fen: after, move: san })
+ }
+ return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(state.chess.myColor), gameHistory: updatedGameHistory }
+ }
default:
return state;
}
@@ -60,7 +71,7 @@ const ChessGameContextProvider = ({ children }) => {
let myColor = localStorage.getItem('myColor');
console.log('INSIDE CONTEXT PROVIDER');
const [{ chess, chessBoard, moveHints, selected, gameHistory, currentIndex }, dispatch] = useReducer(reducer, myColor, chessGameStateInit);
- console.log(gameHistory)
+ console.log(gameHistory);
console.log(gameHistory);
@@ -71,7 +82,7 @@ const ChessGameContextProvider = ({ children }) => {
// data received through socket
function handleOpponentMove(data) {
- let { from, to } = data;
+ let { from, to, fen } = data;
console.log(from + to);
if (!chess.get(to)) {
console.log('Moving piece: ', data);
@@ -87,7 +98,7 @@ const ChessGameContextProvider = ({ children }) => {
}
// called when user clicks a square
- function handleSquareClick(square) {
+ function handleSquareClick(square, emitToSocketCallback) {
let { type, color } = chess.get(square);
let marked = moveHints.includes(square);
console.log('handleSquareClick', square)
@@ -99,9 +110,13 @@ const ChessGameContextProvider = ({ children }) => {
}
if (!type && selected && marked) {
dispatch({ type: MOVE_PIECE, val: { from: selected, to: square } })
+ emitToSocketCallback({ from: selected, to: square })
+ captureAudioRef.current.play();
}
if (type && marked) {
dispatch({ type: CAPTURE_PIECE, val: { from: selected, to: square } })
+ emitToSocketCallback({ from: selected, to: square })
+ moveAudioRef.current.play();
}
} else {
return;
@@ -165,9 +180,14 @@ const ChessGameContextProvider = ({ children }) => {
}
}
+ // fetchedGameHistory is an array of objects of the form {from,to}
+ function setGameHistory(fetchedGameHistory) {
+ dispatch({ type: SET_GAME_HISTORY, val: fetchedGameHistory })
+ }
+
return (
{children}
diff --git a/frontend/src/pages/Chess/ChessGame.jsx b/frontend/src/pages/Chess/ChessGame.jsx
index 9127505..3607af8 100644
--- a/frontend/src/pages/Chess/ChessGame.jsx
+++ b/frontend/src/pages/Chess/ChessGame.jsx
@@ -8,7 +8,7 @@ import { ChessGameContext } from '../../context/chess-game-context'
import GameHistory from '../../components/GameHistory'
const ChessGame = () => {
- const { gameHistory } = useContext(ChessGameContext);
+ const { gameHistory,setGameHistory } = useContext(ChessGameContext);
const user = getUserData();
let username = user.username;
let color = localStorage.getItem('myColor')
@@ -35,8 +35,9 @@ const ChessGame = () => {
console.log('Connected');
});
- socket.on('join-room-success', () => {
+ socket.on('join-room-success', (fetchedGameHistory) => {
console.log('Room joined:', roomID);
+ setGameHistory(fetchedGameHistory);
setHasJoinedRoom(true);
});