152 lines
5.7 KiB
React
152 lines
5.7 KiB
React
import React, { useEffect, useReducer, useRef } from 'react';
|
|
import { ChessModified, chess, chessInit } from '../../../utils/chess';
|
|
import Cell from '../../components/Cell';
|
|
import { socket } from '../../socket';
|
|
import { Flex, createStyles } from '@mantine/core';
|
|
import { DndContext } from '@dnd-kit/core'
|
|
import { useElementSize } from '@mantine/hooks';
|
|
|
|
const useStyles = createStyles((theme) => ({
|
|
chessboard: {
|
|
[theme.fn.largerThan('md')]: {
|
|
width: '600px'
|
|
},
|
|
|
|
[theme.fn.smallerThan('md')]: {
|
|
width: '560px'
|
|
},
|
|
[theme.fn.smallerThan('sm')]: {
|
|
width: '360px',
|
|
},
|
|
},
|
|
boardrow: {
|
|
[theme.fn.largerThan('md')]: {
|
|
height: '75px'
|
|
},
|
|
[theme.fn.smallerThan('md')]: {
|
|
height: '70px'
|
|
},
|
|
[theme.fn.smallerThan('sm')]: {
|
|
height: '45px'
|
|
},
|
|
}
|
|
}))
|
|
|
|
const reducer = (state, action) => {
|
|
console.log(state.chess.myColor)
|
|
switch (action.type) {
|
|
case 'SELECT_PIECE':
|
|
{
|
|
if (state.chess.turn() !== localStorage.getItem('myColor')) return state;
|
|
state.chess.select(action.val.square);
|
|
return { ...state, moveHints: state.chess.getMoves(state.chess.selected) };
|
|
}
|
|
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: [] };
|
|
}
|
|
case 'CAPTURE_PIECE':
|
|
{
|
|
console.log('Capture', 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: [] };
|
|
}
|
|
default:
|
|
return state;
|
|
}
|
|
}
|
|
|
|
const ChessBoard = ({ color }) => {
|
|
const ref = useRef()
|
|
const { height, width } = useElementSize(ref)
|
|
const { classes } = useStyles();
|
|
const moveAudioRef = useRef(null);
|
|
const captureAudioRef = useRef(null);
|
|
const gameEndAudioRef = useRef(null);
|
|
const checkAudioRef = useRef(null);
|
|
|
|
let roomID = localStorage.getItem('roomID');
|
|
|
|
const [gameState, dispatch] = useReducer(reducer, {
|
|
chess: chessInit(color), chessBoard: chess.getBoard(color), moveHints: []
|
|
});
|
|
|
|
const chessBoardRef = useRef(gameState.chessBoard);
|
|
chessBoardRef.current = gameState.chessBoard;
|
|
|
|
useEffect(() => {
|
|
function handleOpponentMove(data) {
|
|
let { from, to } = data;
|
|
console.log(from + to)
|
|
if (!gameState.chess.get(to)) {
|
|
console.log('Moving piece: ', data)
|
|
dispatch({ type: 'MOVE_PIECE', val: { from, to } });
|
|
moveAudioRef.current.play();
|
|
return;
|
|
} else {
|
|
console.log('Capturing piece');
|
|
dispatch({ type: 'CAPTURE_PIECE', val: { from, to } });
|
|
captureAudioRef.current.play();
|
|
return;
|
|
}
|
|
}
|
|
socket.on('opponent-move', handleOpponentMove)
|
|
|
|
return () => {
|
|
socket.off('move', handleOpponentMove);
|
|
}
|
|
}, []);
|
|
|
|
return (
|
|
<DndContext onDragEnd={evt => {
|
|
let srcSquare = evt.active.id;
|
|
let destSquare = evt.over.id;
|
|
|
|
if (gameState.moveHints.includes(destSquare)) {
|
|
console.log(gameState.chess.get(srcSquare))
|
|
if (gameState.chess.get(destSquare)) {
|
|
captureAudioRef.current.play();
|
|
dispatch({ type: 'CAPTURE_PIECE', val: { from: srcSquare, to: destSquare } }); // capture piece
|
|
socket.emit('move', roomID, { from: srcSquare, to: destSquare })
|
|
} else {
|
|
moveAudioRef.current.play();
|
|
dispatch({ type: 'MOVE_PIECE', val: { from: srcSquare, to: destSquare } }); // move piece
|
|
socket.emit('move', roomID, { from: srcSquare, to: destSquare })
|
|
}
|
|
}
|
|
}}>
|
|
<Flex ref={ref} className={
|
|
classes.chessboard
|
|
}>
|
|
<div>
|
|
{gameState.chessBoard.map((row, rowIndex) => {
|
|
return (
|
|
<Flex className={classes.boardrow} key={rowIndex * 2}>
|
|
{row.map((cell) => {
|
|
return (
|
|
<Cell
|
|
key={cell.square}
|
|
cell={cell}
|
|
chess={chess}
|
|
marked={gameState.moveHints.includes(cell.square)}
|
|
dispatch={dispatch}
|
|
/>)
|
|
})}
|
|
</Flex>
|
|
)
|
|
})}
|
|
</div>
|
|
</Flex>
|
|
<audio src='/src/assets/move-self.mp3' ref={moveAudioRef} />
|
|
<audio src='/src/assets/capture.mp3' ref={captureAudioRef} />
|
|
<audio src='/src/assets/game-end.webm.mp3' ref={gameEndAudioRef} />
|
|
<audio src='/src/assets/move-check.mp3' ref={checkAudioRef} />
|
|
</DndContext >
|
|
)
|
|
}
|
|
|
|
export default ChessBoard |