From cee1932f494114b03b32a14e26af3aa6f1c4989d Mon Sep 17 00:00:00 2001 From: Immortal Date: Sun, 29 Oct 2023 22:03:36 +0530 Subject: [PATCH 1/2] Fixed addFriend POST req --- frontend/src/pages/Settings/Friends.jsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/src/pages/Settings/Friends.jsx b/frontend/src/pages/Settings/Friends.jsx index 73eeb9e..b067e64 100644 --- a/frontend/src/pages/Settings/Friends.jsx +++ b/frontend/src/pages/Settings/Friends.jsx @@ -10,11 +10,14 @@ const Friends = () => { const form = useForm({ initialValues: { username: '' }, }) const addFriend = async () => { - console.log(form.values); - const response = await fetch(`${import.meta.env.VITE_BACKEND_HOST}/api/user/friends/${form.values.username}`, { + console.log("form values",form.values); + const response = await fetch(`${import.meta.env.VITE_BACKEND_HOST}/api/user/friends`, { method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, credentials: 'include', - body: JSON.stringify({ username: form.values.username }) + body: JSON.stringify({friendUsername: form.values.username}), }); if (!response.ok) { const resData = await response.json(); @@ -36,4 +39,4 @@ const Friends = () => { ) } -export default Friends \ No newline at end of file +export default Friends From e956e66427d3e46338ecbbaf6fe4d8199180b730 Mon Sep 17 00:00:00 2001 From: Immortal Date: Mon, 30 Oct 2023 21:08:11 +0530 Subject: [PATCH 2/2] Added premove feature --- frontend/src/constants.js | 2 + frontend/src/context/chess-game-context.jsx | 83 +++++++++++++++---- frontend/src/pages/Play/ChessGameComputer.jsx | 20 +++-- .../src/pages/Play/ChessGameMultiplayer.jsx | 14 +++- 4 files changed, 93 insertions(+), 26 deletions(-) diff --git a/frontend/src/constants.js b/frontend/src/constants.js index c74f704..f9d2b5d 100644 --- a/frontend/src/constants.js +++ b/frontend/src/constants.js @@ -20,4 +20,6 @@ export const DISPATCH_EVENTS = { JUMP_TO: "JUMP_TO", SET_GAME_HISTORY: "SET_GAME_HISTORY", END_GAME: "END_GAME", + ADD_PREMOVE: "ADD_PREMOVE", + DELETE_PREMOVES: "DELETE_PREMOVES", }; diff --git a/frontend/src/context/chess-game-context.jsx b/frontend/src/context/chess-game-context.jsx index 32f53b0..d0aa278 100644 --- a/frontend/src/context/chess-game-context.jsx +++ b/frontend/src/context/chess-game-context.jsx @@ -6,7 +6,7 @@ import { socket } from '../socket'; import { ChessModified, chessInit } from '../utils/chess'; import { DISPATCH_EVENTS, SOCKET_EVENTS } from '../constants'; -const { MOVE_PIECE, SELECT_PIECE, JUMP_TO, SET_GAME_HISTORY, END_GAME } = DISPATCH_EVENTS +const { MOVE_PIECE, SELECT_PIECE, JUMP_TO, SET_GAME_HISTORY, END_GAME, ADD_PREMOVE, DELETE_PREMOVES } = DISPATCH_EVENTS const { GAME_END } = SOCKET_EVENTS; export const ChessGameContext = createContext(); @@ -21,22 +21,32 @@ const reducer = (state, action) => { } case MOVE_PIECE: { - let newChessObj = new ChessModified(state.chess.fen()); + const { from ,to } = action.val; + const newChessCopyObj = new ChessModified(state.chessCopy.fen()); + let { san, after } = newChessCopyObj.move({from, to}); + const newChessObj = new ChessModified(newChessCopyObj.fen()); + + const preMoves = [ ...state.preMoves ]; + action.val.isPreMove && preMoves.shift(); + preMoves.forEach(({from, to}) => { + const piece = newChessObj.remove(from); + newChessObj.put(piece, to); + }) + let updatedGameHistory = state.gameHistory; - let { san, after } = newChessObj.move(action.val); updatedGameHistory.push({ move: san, fen: after }); let newState; if (newChessObj.isCheckmate()) { action.val.callback(); action.val.playAudioCallback("CHECKMATE"); - newState = { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'CHECKMATE' }; + newState = { ...state, chess: newChessObj, chessCopy: newChessCopyObj, chessBoard: newChessObj.getBoard(), preMoves, moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'CHECKMATE' }; } else if(newChessObj.isCheck() || newChessObj.inCheck()) { action.val.playAudioCallback("CHECK"); - newState = { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 }; + newState = { ...state, chess: newChessObj, chessCopy: newChessCopyObj, chessBoard: newChessObj.getBoard(), preMoves, moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 }; } else if (newChessObj.isStalemate()) { action.val.callback(); action.val.playAudioCallback("STALEMATE"); - newState = { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'STALEMATE' }; + newState = { ...state, chess: newChessObj, chessCopy: newChessCopyObj, chessBoard: newChessObj.getBoard(), preMoves, moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1, hasGameEnded: true, gameEndedReason: 'STALEMATE' }; } else { if(!state.chess.get(action.val.to)) { @@ -44,7 +54,7 @@ const reducer = (state, action) => { } else { action.val.playAudioCallback("CAPTURE"); } - newState = { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(), moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 }; + newState = { ...state, chess: newChessObj, chessCopy: newChessCopyObj, chessBoard: newChessObj.getBoard(), preMoves, moveHints: [], selected: null, gameHistory: updatedGameHistory, currentIndex: updatedGameHistory.length - 1 }; } return newState; } @@ -68,6 +78,20 @@ const reducer = (state, action) => { { return { ...state, hasGameEnded: true, gameEndedReason: action.val } } + case ADD_PREMOVE: + { + const updatedPreMoves = [ ...state.preMoves, action.val ]; + const newChessObj = new ChessModified(state.chessCopy.fen()); + updatedPreMoves.forEach(({from, to}) => { + const piece = newChessObj.remove(from); + newChessObj.put(piece, to); + }) + return { ...state, chess: newChessObj, chessBoard: newChessObj.getBoard(), preMoves: updatedPreMoves } + } + case DELETE_PREMOVES: + { + return { ...state, chess: state.chessCopy, chessBoard: state.chessCopy.getBoard(), preMoves: [] } + } default: return state; } @@ -79,7 +103,9 @@ const reducer = (state, action) => { function chessGameStateInit(myColor) { let chess = chessInit(myColor); + let chessCopy = chessInit(myColor); let chessBoard = chess.getBoard(); + let preMoves = []; let moveHints = []; let gameHistory = []; let selected = null; @@ -87,7 +113,7 @@ function chessGameStateInit(myColor) { let hasGameEnded = false; let gameEndedReason = ""; - return { chess, chessBoard, moveHints, selected, gameHistory, currentIndex, hasGameEnded, gameEndedReason }; + return { chess, chessCopy, chessBoard, preMoves, moveHints, selected, gameHistory, currentIndex, hasGameEnded, gameEndedReason }; } // the ChessGameContextProvider seperates the game logic from the ChessBoard component and exposes @@ -95,7 +121,7 @@ function chessGameStateInit(myColor) { const ChessGameContextProvider = ({ children }) => { let myColor = localStorage.getItem('myColor'); let roomID = localStorage.getItem('roomID'); - const [{ chess, chessBoard, moveHints, selected, gameHistory, currentIndex, hasGameEnded, gameEndedReason }, dispatch] = useReducer(reducer, myColor, chessGameStateInit); + const [{ chess, chessCopy, chessBoard, moveHints, selected, gameHistory, currentIndex, hasGameEnded, gameEndedReason, preMoves }, dispatch] = useReducer(reducer, myColor, chessGameStateInit); const [isTimerOn, setIsTimerOn] = useState(true); const chessRef = useRef(chess); @@ -142,37 +168,58 @@ const ChessGameContextProvider = ({ children }) => { function handleOpponentMove(data, callback) { let { from, to } = data; console.log("Opponent move:",from,to); - dispatch({type:MOVE_PIECE,val: { from, to, callback,playAudioCallback }}); + dispatch({type:MOVE_PIECE,val: { from, to, callback,playAudioCallback, isPreMove: false }}); } // called when user clicks a square function handleSquareClick(square, emitToSocketCallback, callback) { let { type, color } = chessRef.current.get(square); let marked = moveHintsRef.current.includes(square); - if (chessRef.current.turn() === myColor) { if (type && color === myColor) { selectPiece({square,color}); return; } else if(marked) { - dispatch({ type: MOVE_PIECE, val: { from: selectedRef.current, to: square, callback,playAudioCallback } }) + dispatch({ type: MOVE_PIECE, val: { from: selectedRef.current, to: square, callback,playAudioCallback, isPreMove: false } }) console.log("Move:",{ from: selectedRef.current, to: square }) emitToSocketCallback({ from: selectedRef.current, to: square }) } + } else { + if (selectedRef.current) { + dispatch({ type: ADD_PREMOVE, val: {from: selectedRef.current, to: square}}); + } } } function handleDrop(moveData, emitToSocketCallback, callback) { let { from, to } = moveData; + const isOpponentTurn = chessCopy.turn() !== myColor; + if (isOpponentTurn && from !== to && chess.get(from).color === myColor) { + dispatch({ type: ADD_PREMOVE, val: {from, to}}); + return; + } if (moveHintsRef.current.includes(to)) { - dispatch({ type: MOVE_PIECE, val: { from: from, to: to, callback,playAudioCallback } }); // capture piece + dispatch({ type: MOVE_PIECE, val: { from: from, to: to, callback,playAudioCallback, isPreMove: false } }); // capture piece console.log("Move:",{ from,to }) emitToSocketCallback(moveData); } } + function handlePreMove(callback, emitMoveToSocketCallback) { + const {from, to} = preMoves[0]; + const moveHints = chessCopy.getMoves(from); + if(moveHints.includes(to)) { + dispatch({ type: MOVE_PIECE, val: { from, to, isPreMove: true, callback, playAudioCallback }}) + console.log("Move:", { from, to }); + emitMoveToSocketCallback({ from, to }); + } + else{ + dispatch({ type: DELETE_PREMOVES }); + } + } + function selectPiece({ square, color: pieceColor }) { - if (pieceColor === myColor && myColor === chessRef.current.turn()) { + if (pieceColor === myColor) { dispatch({ type: SELECT_PIECE, val: square }); } } @@ -190,8 +237,8 @@ const ChessGameContextProvider = ({ children }) => { } function getChessBoard() { - if (currentIndexRef.current === -1 || gameHistoryRef.current.length === 0) { - return new ChessModified().getBoard(); + if (currentIndex === gameHistory.length - 1) { + return chessBoard; } else { // console.log(chess); let currentChessBoard = new ChessModified(gameHistoryRef.current[currentIndexRef.current].fen).getBoard(); @@ -227,7 +274,7 @@ const ChessGameContextProvider = ({ children }) => { return ( @@ -244,4 +291,4 @@ ChessGameContextProvider.propTypes = { children: PropTypes.object } -export default ChessGameContextProvider \ No newline at end of file +export default ChessGameContextProvider diff --git a/frontend/src/pages/Play/ChessGameComputer.jsx b/frontend/src/pages/Play/ChessGameComputer.jsx index a8644a1..5c5af41 100644 --- a/frontend/src/pages/Play/ChessGameComputer.jsx +++ b/frontend/src/pages/Play/ChessGameComputer.jsx @@ -11,7 +11,7 @@ import { SOCKET_EVENTS } from '../../constants'; const { CHESS_MOVE, GAME_END } = SOCKET_EVENTS const ChessGameComputer = () => { - const { hasGameEnded, gameEndedReason, handleOpponentMove } = useContext(ChessGameContext); + const { chessCopy, myColor, hasGameEnded, gameEndedReason, preMoves, handleOpponentMove, handlePreMove } = useContext(ChessGameContext); const [gameEndedModalOpen, modalFunctions] = useDisclosure(true); const navigate = useNavigate(); const user = getUserData(); @@ -23,15 +23,14 @@ const ChessGameComputer = () => { useEffect(() => { socket.connect(); socket.emit('INIT', {color}); - // socket.onAny(evt => { // console.log("event", evt); // }) socket.on("CHESS_BOT_MOVE", (data) => { - handleOpponentMove(data, () => { - socket.emit(GAME_END, roomID); - }) + handleOpponentMove(data, + () => socket.emit(GAME_END, roomID), + ); }); return () => { @@ -40,6 +39,15 @@ const ChessGameComputer = () => { } }, []); + useEffect(() => { + if(chessCopy.turn() === myColor && preMoves.length) { + handlePreMove( + () => socket.emit(GAME_END, roomID), + (moveData) => socket.emit(CHESS_MOVE, roomID, moveData) + ) + } + }, [chessCopy]) + const exitGame = () => { console.log("Ending game"); socket.disconnect(); @@ -132,4 +140,4 @@ const ChessGameComputer = () => { ) } -export default ChessGameComputer \ No newline at end of file +export default ChessGameComputer diff --git a/frontend/src/pages/Play/ChessGameMultiplayer.jsx b/frontend/src/pages/Play/ChessGameMultiplayer.jsx index 04f69dc..bd4087f 100644 --- a/frontend/src/pages/Play/ChessGameMultiplayer.jsx +++ b/frontend/src/pages/Play/ChessGameMultiplayer.jsx @@ -15,7 +15,7 @@ import Timer from '../Chess/Timer' const { CONNECT, DISCONNECT, CHESS_OPPONENT_MOVE, USER_RESIGNED, JOIN_ROOM, JOIN_ROOM_ERROR, JOIN_ROOM_SUCCESS, ROOM_FULL, USER_JOINED_ROOM, CHESS_MOVE } = SOCKET_EVENTS; const ChessGameMultiplayer = () => { - const { setGameHistory, hasGameEnded, gameEndedReason, endGame, handleOpponentMove, isTimerOn } = useContext(ChessGameContext); + const { chessCopy, myColor, preMoves, setGameHistory, hasGameEnded, gameEndedReason, endGame, handleOpponentMove, handlePreMove, isTimerOn } = useContext(ChessGameContext); const [gameEndedModalOpen, modalFunctions] = useDisclosure(true); const user = getUserData(); @@ -98,6 +98,16 @@ const ChessGameMultiplayer = () => { } }, []); + useEffect(() => { + if(chessCopy.turn() === myColor && preMoves.length) { + handlePreMove( + () => socket.emit(GAME_END, roomID), + (moveData) => socket.emit(CHESS_MOVE, roomID, moveData) + ) + } + }, [chessCopy]) + + if (!hasJoinedRoom) return ( ) @@ -171,4 +181,4 @@ const ChessGameMultiplayer = () => { ) } -export default ChessGameMultiplayer \ No newline at end of file +export default ChessGameMultiplayer