javascriptchess

Having issues with chess.js, valid moves are not being displayed via socket.io after reloading an in-progress game


I'm writing a multiplayer chess app using chess.js, react-chessboard, socket.io, and React that should allow users to play chess with each other and store the history of the games. I've gotten it to work up to a point, I'm able to start a game, play a few moves between 2 users, and send the position to the database but as soon as I leave to the menu and re-enter the game, it only allows 1 move to be made and it doesn't send that move to the other player. The socket seems to be firing because an error saying the move was invalid shows up on the other users console, which is strange because the move was allowed on the first users screen and they have the same chessboard positions on screen.

Here is my current code for the chess game component. There's not much going on server side just some simple sockets.

function ChessGame({socket}) {
  const dispatch = useDispatch();
  const user = useSelector(store => store.user); 
  const room = useSelector(store => store.room);
  let [position, setPosition] = useState('start');
  let [game, setGame] = useState(new Chess());
  let [turn, setTurn] = useState(game.turn());
  let [color, setColor] = useState('w')
  let [draggable, setDraggable] = useState(true);
  const { id } = useParams();
  let [pgn, setPgn] = useState();

  useEffect(() => {
    socket.emit('joinRoom', id);
    dispatch({type: 'FETCH_ROOM', payload: id});
  }, [id]);

  // Loads PGN once the pgn variable has been updated
  // function setUpBoard () {
  //   console.log(pgn)
  //   game.loadPgn(pgn)
  // };

  // useEffect(() => {
  //   if(pgn) {
  //     setUpBoard()
  //   }
  // }, [pgn])

  // Update variables once the room saga has loaded
  useEffect(() => {
    if(room.length === 1) {
    setPlayerColor();
    setPgn(room[0].pgn)
      if(room[0].position !== 'start') {
        setGame(new Chess(room[0].position));
        setPosition(room[0].position)
        console.log(game)
      }
    } 
    
  }, [room]);

  useEffect(() => {
    setTurn(game.turn())
  }, [game])

  // Sets player color from the database
  function setPlayerColor() {
    if(user.id === room[0].black) {
      setColor('b');
    } else if (user.id === room[0].white) {
      setColor('w');
    } else {
      setDraggable(false);
    }
  };

  // Updates game on player move
  const makeMove = (move) => {
      game.move(move, {sloppy: true});
      setGame(new Chess(game.fen()));
      setPgn(game.pgn());
    };

  // for onPieceDrop prop in chessboard, emits to makeMove socket
  function onDrop(sourceSquare, targetSquare) {
      const movePiece = makeMove({
          from: sourceSquare,
          to: targetSquare,
          promotion: "q",
        });
      const move = {
          from: sourceSquare,
          to: targetSquare,
          promotion: "q", 
      };
      setPosition(game.fen());
      putPosition()
      if (movePiece === null) {return false}
      else { 
          socket.emit('makeMove', move, id);
          return true;
      };
    }

  // Controls whether the pieces are draggable based on whos turn it is
  function areDraggable () {
    console.log(color, turn)
    if(color == turn) {
        setDraggable(true)
    } else {
        setDraggable(false)
    }
  };

  useEffect(() => {
      areDraggable();
  }, [turn, color]);

  socket.on('makeMove', (move) => {
    onDrop(move.from, move.to);
    setPosition(game.fen());
  });

  let gameObject = {
    position,
    pgn,
  }

  // Update database with new position and pgn
  function putPosition() {
    axios.put(`/api/game/position/${id}`, gameObject).then((response) => {

    }).catch(error => {
      console.log('Error in PUT /position', error);
    })
  };

I've tried .loadPgn to populate the game but that didn't change anything. It may be that I'm implementing it incorrectly. Any insight would be greatly appreciated! I'm pretty new to React and coding in general so any pointers would help a lot. Thank you!


Solution

  • Getting rid of the movePiece !== null and placing the makeMove and the variable changes inside of a try/catch worked!