New feature added: While in the match the user can go back it time

to analyse previous moves.
This commit is contained in:
Moon Patel
2023-07-04 03:11:46 +05:30
parent 5f450e92fe
commit d8d0c95779
7 changed files with 101 additions and 333 deletions
+10 -2
View File
@@ -21,6 +21,7 @@ import ChallengeFriend, { playFriendAction } from './pages/Play/ChallengeFriend'
import ChessGame from './pages/Chess/ChessGame'
import JoinChallenge from './components/JoinChallenge'
import ErrorBoundary from './components/ErrorBoundary'
import ChessGameContextProvider, { ChessGameContext } from './context/chess-game-context'
const router = createBrowserRouter([{
path: '/',
@@ -38,7 +39,14 @@ const router = createBrowserRouter([{
{ path: 'online', element: <div>Online</div> }
]
},
{ path: "game/friend/:roomID", element: <ChessGame /> },
{
path: "game/friend/:roomID", element:
<div>
<ChessGameContextProvider>
<ChessGame />
</ChessGameContextProvider>
</div>
},
{
path: 'settings', element: <Settings />, children: [
{ index: true, element: <Profile /> },
@@ -52,7 +60,7 @@ const router = createBrowserRouter([{
},
{ path: "/game/challenges/:challenger/:roomID", element: <JoinChallenge /> },
{
path: '/login', element: <AuthenticationPage isLogin={true} />,action: loginAction, loader: () => { if (getAuthToken()) return redirect('/home'); else return null; }
path: '/login', element: <AuthenticationPage isLogin={true} />, action: loginAction, loader: () => { if (getAuthToken()) return redirect('/home'); else return null; }
}, {
path: '/signup', element: <AuthenticationPage isLogin={false} />, action: signupAction, loader: () => { if (getAuthToken()) return redirect('/signup'); else return null; }
}, {
+32
View File
@@ -0,0 +1,32 @@
import React, { useContext } from 'react'
import { ChessGameContext } from '../context/chess-game-context'
import { Button, Flex, Text } from '@mantine/core';
const GameHistory = () => {
const { gameHistory, jumpTo } = useContext(ChessGameContext)
let gameHistoryJSX = [];
for (let i = 0; i < gameHistory.length;) {
let move1 = null, move2 = null;
let index = i;
move1 = <Button onClick={() => { jumpTo(index) }}>{gameHistory[i++].move}</Button>
if (i < gameHistory.length) {
let index = i;
move2 = <Button onClick={() => { jumpTo(index) }}>{gameHistory[i++].move}</Button>
}
gameHistoryJSX.push(
<Flex key={i} direction='row' gap='md'>
{move1}
{move2}
</Flex>
)
}
return (
<div>
{gameHistoryJSX}
</div>
)
}
export default GameHistory
+1
View File
@@ -13,4 +13,5 @@ export const DISPATCH_EVENTS = {
SELECT_PIECE: "SELECT_PIECE",
MOVE_PIECE: "MOVE_PIECE",
CAPTURE_PIECE: "CAPTURE_PIECE",
JUMP_TO: "JUMP_TO",
};
+44 -14
View File
@@ -1,7 +1,8 @@
import React, { createContext, useReducer, useRef } from 'react'
import { ChessModified, chessInit } from '../../utils/chess';
import { DISPATCH_EVENTS } from '../constants';
const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE } = DISPATCH_EVENTS
import ChessBoard from '../pages/Chess/ChessBoard';
const { CAPTURE_PIECE, MOVE_PIECE, SELECT_PIECE, JUMP_TO } = 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
@@ -11,22 +12,31 @@ const reducer = (state, action) => {
switch (action.type) {
case SELECT_PIECE:
{
console.log('SELECTING...', action.val)
console.log('SELECTING...', action.val);
return { ...state, moveHints: state.chess.getMoves(action.val), selected: action.val };
}
case MOVE_PIECE:
{
console.log('Moving', action.val, state.chess.turn());
let newChessObj = new ChessModified({ prop: state.chess.fen(), color: state.chess.myColor })
newChessObj.move(action.val);
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null };
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() });
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: -1 };
}
case CAPTURE_PIECE:
{
console.log('Capture', action.val, state.chess.turn())
let newChessObj = new ChessModified({ prop: state.chess.fen(), color: state.chess.myColor, selected: null });
newChessObj.move(action.val);
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [] };
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() });
return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(localStorage.getItem('myColor')), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: -1 };
}
case JUMP_TO:
{
let index = action.val;
return { ...state, currentIndex: index }
}
default:
return state;
@@ -37,17 +47,23 @@ function chessGameStateInit(myColor) {
let chess = chessInit(myColor);
let chessBoard = chess.getBoard(myColor);
let moveHints = [];
let gameHistory = [];
let selected = null;
let currentIndex = -1;
return { chess, chessBoard, moveHints, selected }
return { chess, chessBoard, moveHints, selected, gameHistory, currentIndex };
}
// the ChessGameContextProvider seperates the game logic from the ChessBoard component and exposes
// some functions to update game state.
const ChessGameContextProvider = ({ children }) => {
let myColor = localStorage.getItem('myColor');
const [{ chess, chessBoard, moveHints, selected }, dispatch] = useReducer(reducer, myColor, chessGameStateInit);
console.log('INSIDE CONTEXT PROVIDER');
const [{ chess, chessBoard, moveHints, selected, gameHistory, currentIndex }, dispatch] = useReducer(reducer, myColor, chessGameStateInit);
console.log(gameHistory)
console.log(gameHistory);
const moveAudioRef = useRef(null);
const captureAudioRef = useRef(null);
const gameEndAudioRef = useRef(null);
@@ -56,9 +72,9 @@ const ChessGameContextProvider = ({ children }) => {
// data received through socket
function handleOpponentMove(data) {
let { from, to } = data;
console.log(from + to)
console.log(from + to);
if (!chess.get(to)) {
console.log('Moving piece: ', data)
console.log('Moving piece: ', data);
dispatch({ type: MOVE_PIECE, val: { from, to } });
moveAudioRef.current.play();
return;
@@ -123,9 +139,23 @@ const ChessGameContextProvider = ({ children }) => {
return moveHints.includes(square);
}
function jumpTo(index) {
dispatch({ type: JUMP_TO, val: index })
}
function getChessBoard() {
console.log(gameHistory, currentIndex);
if (currentIndex === -1 || gameHistory.length === 0) {
return chessBoard;
} else {
let currentChessBoard = new ChessModified({ prop: gameHistory[currentIndex].fen, color: myColor }).getBoard(myColor);
return currentChessBoard;
}
}
return (
<ChessGameContext.Provider value={{
myColor, chess, chessBoard, moveHints, selected, dispatch, handleOpponentMove, handleSquareClick, getSquareColor, isSquareMarked, selectPiece, handleDrop
myColor, chessBoard, moveHints, selected, handleOpponentMove, handleSquareClick, getSquareColor, isSquareMarked, selectPiece, handleDrop, gameHistory, jumpTo, getChessBoard
}}>
{children}
<audio src='/src/assets/move-self.mp3' ref={moveAudioRef} />
+3 -2
View File
@@ -5,7 +5,7 @@ import { Flex, createStyles } from '@mantine/core';
import { DndContext } from '@dnd-kit/core'
import { ChessGameContext } from '../../context/chess-game-context';
import { SOCKET_EVENTS } from '../../constants';
const {CHESS_OPPONENT_MOVE,CHESS_MOVE} = SOCKET_EVENTS
const { CHESS_OPPONENT_MOVE, CHESS_MOVE } = SOCKET_EVENTS
const useStyles = createStyles((theme) => ({
chessboard: {
[theme.fn.largerThan('md')]: {
@@ -34,8 +34,9 @@ const useStyles = createStyles((theme) => ({
const ChessBoard = () => {
const { classes } = useStyles();
const { chessBoard, handleOpponentMove, handleDrop } = useContext(ChessGameContext)
const { getChessBoard, handleOpponentMove, handleDrop } = useContext(ChessGameContext)
let roomID = localStorage.getItem('roomID');
const chessBoard = getChessBoard();
useEffect(() => {
socket.on(CHESS_OPPONENT_MOVE, handleOpponentMove)
+11 -9
View File
@@ -1,12 +1,14 @@
import { Avatar, Button, Flex, Image, Loader, MediaQuery, NavLink, Text, Title } from '@mantine/core'
import React, { useEffect, useState } from 'react'
import React, { useContext, useEffect, useState } from 'react'
import ChessBoard from '../Chess/ChessBoard'
import { useNavigate, useParams } from 'react-router-dom'
import { socket } from '../../socket'
import { getUserData } from '../../../utils/auth'
import ChessGameContextProvider from '../../context/chess-game-context'
import { ChessGameContext } from '../../context/chess-game-context'
import GameHistory from '../../components/GameHistory'
const ChessGame = () => {
const { gameHistory } = useContext(ChessGameContext);
const user = getUserData();
let username = user.username;
let color = localStorage.getItem('myColor')
@@ -59,9 +61,9 @@ const ChessGame = () => {
}, []);
// if (!hasJoinedRoom) return (
// <Loader variant='bars' />
// )
if (!hasJoinedRoom) return (
<Loader variant='bars' />
)
return (
<Flex gap="xl" miw={360} justify='center' align='center' wrap='nowrap' mt={{ base: '50px', sm: '0px' }} direction={{ base: 'column', lg: 'row' }}>
@@ -72,9 +74,7 @@ const ChessGame = () => {
icon={<Avatar radius="3px" children={opponent[0].toUpperCase()} />}
description={"description"}
/>
<ChessGameContextProvider>
<ChessBoard />
</ChessGameContextProvider>
<ChessBoard />
<NavLink
p="2px"
label={username}
@@ -83,7 +83,6 @@ const ChessGame = () => {
/>
</Flex>
<MediaQuery smallerThan="lg" styles={{ display: 'none' }}>
<Flex maw={450} sx={{
width: '100%',
height: '600px',
@@ -91,6 +90,9 @@ const ChessGame = () => {
borderRadius: '10px'
}} bg='gray' p="10px" justify='start' align='center' direction='column' h="600px">
<Title>Game Data</Title>
<Flex direction='column'>
<GameHistory />
</Flex>
<Flex>
<Button onClick={exitGame} color='red'>Exit Game</Button>
</Flex>
-306
View File
@@ -1,309 +1,3 @@
// const pawn = "P",
// rook = "R",
// knight = "N",
// bishop = "B",
// queen = "Q",
// king = "K";
// export const pieces = {
// pawn,
// rook,
// knight,
// bishop,
// queen,
// king,
// };
// export const whiteColor = "W",
// blackColor = "B";
// export function chessBoardInit(myColor) {
// let opColor = myColor === whiteColor ? blackColor : whiteColor;
// const chessBoardMatrix = [
// [
// { color: opColor, type: rook },
// { color: opColor, type: knight },
// { color: opColor, type: bishop },
// { color: opColor, type: myColor === whiteColor ? queen : king },
// { color: opColor, type: myColor === whiteColor ? king : queen },
// { color: opColor, type: bishop },
// { color: opColor, type: knight },
// { color: opColor, type: rook },
// ],
// Array(8).fill({ color: opColor, type: pawn }),
// [null, null, null, null, null, null, null, null],
// [null, null, null, null, null, null, null, null],
// [null, null, null, null, null, null, null, null],
// [null, null, null, null, null, null, null, null],
// Array(8).fill({ color: myColor, type: pawn }),
// [
// { color: myColor, type: rook },
// { color: myColor, type: knight },
// { color: myColor, type: bishop },
// { color: myColor, type: myColor === whiteColor ? queen : king },
// { color: myColor, type: myColor === whiteColor ? king : queen },
// { color: myColor, type: bishop },
// { color: myColor, type: knight },
// { color: myColor, type: rook },
// ],
// ];
// return chessBoardMatrix;
// }
// function inBoard(i, j) {
// if (i >= 0 && i < 8 && j >= 0 && j < 8) return true;
// else return false;
// }
// function isBlocked(chessBoard, chessPiece, i, j) {
// if (chessBoard[i][j] === null) return false;
// else if (chessBoard[i][j].color === chessPiece.color) return true;
// else return false;
// }
// function isAttacking(chessBoard, chessPiece, i, j) {
// if (chessBoard[i][j] === null) return false;
// else if (chessBoard[i][j].color !== chessPiece.color) return true;
// else return false;
// }
// function getPawnHint(chessBoard, chessPiece, myColor) {
// const { row, col } = chessPiece;
// let movePos = [];
// if (chessPiece.color === myColor) {
// // for moving forward
// if (inBoard(row - 1, col) && chessBoard[row - 1][col] === null && movePos.push({ row: row - 1, col })) {
// chessPiece.row === 6 &&
// chessBoard[row - 2][col] === null &&
// inBoard(row - 2, col) &&
// !isBlocked(chessBoard, chessPiece, row - 1, col) &&
// movePos.push({ row: row - 2, col });
// }
// // for killing opponent piece
// if (
// inBoard(row - 1, col + 1) &&
// chessBoard[row - 1][col + 1]?.type &&
// chessBoard[row - 1][col + 1]?.color !== myColor
// )
// inBoard(row - 1, col + 1) && movePos.push({ row: row - 1, col: col + 1 });
// if (
// inBoard(row - 1, col - 1) &&
// chessBoard[row - 1][col - 1]?.type &&
// chessBoard[row - 1][col - 1]?.color !== myColor
// )
// inBoard(row - 1, col - 1) && movePos.push({ row: row - 1, col: col - 1 });
// } else {
// // for moving forward
// if (inBoard(row + 1, col) && chessBoard[row + 1][col] === null && movePos.push({ row: row + 1, col })) {
// chessPiece.row === 1 &&
// chessBoard[row + 2][col] === null &&
// inBoard(row + 2, col) &&
// movePos.push({ row: row + 2, col });
// }
// // for killing opponent piece
// if (
// inBoard(row + 1, col + 1) &&
// chessBoard[row + 1][col + 1]?.type &&
// chessBoard[row + 1][col + 1]?.color === myColor
// )
// inBoard(row + 1, col + 1) && movePos.push({ row: row + 1, col: col + 1 });
// if (
// inBoard(row + 1, col - 1) &&
// chessBoard[row + 1][col - 1]?.type &&
// chessBoard[row + 1][col - 1]?.color === myColor
// )
// inBoard(row + 1, col - 1) && movePos.push({ row: row + 1, col: col - 1 });
// }
// return { movePos };
// }
// function getRookHint(chessBoard, chessPiece, myColor) {
// const { row, col, color } = chessPiece;
// let movePos = [];
// let i = row,
// j = col;
// while (inBoard(++i, j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// console.log(movePos);
// return { movePos };
// }
// function getKnightHint(chessBoard, chessPiece, myColor) {
// const { row, col, color } = chessPiece;
// let movePos = [];
// if (inBoard(row + 2, col + 1) && !isBlocked(chessBoard, chessPiece, row + 2, col + 1))
// movePos.push({ row: row + 2, col: col + 1 });
// if (inBoard(row + 2, col - 1) && !isBlocked(chessBoard, chessPiece, row + 2, col - 1))
// movePos.push({ row: row + 2, col: col - 1 });
// if (inBoard(row - 2, col + 1) && !isBlocked(chessBoard, chessPiece, row - 2, col + 1))
// movePos.push({ row: row - 2, col: col + 1 });
// if (inBoard(row - 2, col - 1) && !isBlocked(chessBoard, chessPiece, row - 2, col - 1))
// movePos.push({ row: row - 2, col: col - 1 });
// if (inBoard(row + 1, col + 2) && !isBlocked(chessBoard, chessPiece, row + 1, col + 2))
// movePos.push({ row: row + 1, col: col + 2 });
// if (inBoard(row - 1, col + 2) && !isBlocked(chessBoard, chessPiece, row - 1, col + 2))
// movePos.push({ row: row - 1, col: col + 2 });
// if (inBoard(row + 1, col - 2) && !isBlocked(chessBoard, chessPiece, row + 1, col - 2))
// movePos.push({ row: row + 1, col: col - 2 });
// if (inBoard(row - 1, col - 2) && !isBlocked(chessBoard, chessPiece, row - 1, col - 2))
// movePos.push({ row: row - 1, col: col - 2 });
// return { movePos };
// }
// function getBishopHint(chessBoard, chessPiece, myColor) {
// const { row, col, color } = chessPiece;
// let movePos = [];
// let i = row,
// j = col;
// while (inBoard(++i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(++i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// return { movePos };
// }
// function getQueenHint(chessBoard, chessPiece, myColor) {
// const { row, col, color } = chessPiece;
// let movePos = [];
// let i = row,
// j = col;
// while (inBoard(++i, j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(++i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(++i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, ++j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// i = row;
// j = col;
// while (inBoard(--i, --j) && !isBlocked(chessBoard, chessPiece, i, j)) {
// movePos.push({ row: i, col: j });
// if (isAttacking(chessBoard, chessPiece, i, j)) break;
// }
// return { movePos };
// }
// function getKingHint(chessBoard, chessPiece, myColor) {
// const { row, col } = chessPiece;
// let movePos = [];
// if (inBoard(row, col + 1) && !isBlocked(chessBoard, chessPiece, row, col + 1))
// movePos.push({ row: row, col: col + 1 });
// if (inBoard(row, col - 1) && !isBlocked(chessBoard, chessPiece, row, col - 1))
// movePos.push({ row: row, col: col - 1 });
// if (inBoard(row + 1, col + 1) && !isBlocked(chessBoard, chessPiece, row + 1, col + 1))
// movePos.push({ row: row + 1, col: col + 1 });
// if (inBoard(row + 1, col) && !isBlocked(chessBoard, chessPiece, row + 1, col))
// movePos.push({ row: row + 1, col: col });
// if (inBoard(row + 1, col - 1) && !isBlocked(chessBoard, chessPiece, row + 1, col - 1))
// movePos.push({ row: row + 1, col: col - 1 });
// if (inBoard(row - 1, col + 1) && !isBlocked(chessBoard, chessPiece, row - 1, col + 1))
// movePos.push({ row: row - 1, col: col + 1 });
// if (inBoard(row - 1, col) && !isBlocked(chessBoard, chessPiece, row - 1, col))
// movePos.push({ row: row - 1, col: col });
// if (inBoard(row - 1, col - 1) && !isBlocked(chessBoard, chessPiece, row - 1, col - 1))
// movePos.push({ row: row - 1, col: col - 1 });
// return { movePos };
// }
// export function getPieceHint(chessBoard, chessPiece, myColor) {
// switch (chessPiece.type) {
// case pawn:
// return getPawnHint(chessBoard, chessPiece, myColor);
// case rook:
// return getRookHint(chessBoard, chessPiece, myColor);
// case knight:
// return getKnightHint(chessBoard, chessPiece, myColor);
// case bishop:
// return getBishopHint(chessBoard, chessPiece, myColor);
// case queen:
// return getQueenHint(chessBoard, chessPiece, myColor);
// case king:
// return getKingHint(chessBoard, chessPiece, myColor);
// }
// return [];
// }
import { Chess } from "chess.js";
export class ChessModified extends Chess {