chessboardjs icon indicating copy to clipboard operation
chessboardjs copied to clipboard

Temporarily duplicated pieces due to racing updates to currentPosition.

Open LMMilewski opened this issue 2 years ago • 2 comments

Consider the "Play Random Computer" example from https://www.chessboardjs.com/examples#5001

First, the following bug can be easily reproduced locally by exaggerating the effect with the following changes:

  • reduce the makeRandomMove delay to 1 (window.setTimeout(makeRandomMove, 1)
  • increase the move speed to 1000 (in the board config, set moveSpeed: 1000)

As a result of the above, you'll see duplicated pieces (for the duration of the animation) whenever the computer makes a move.

This happens because of these racing currentPosition reads/writes:

  • The player makes a move (drops the piece) which calls onDrop and schedules the "snap" animation to run after config.snapSpeed (30ms by default). That is, after 30ms, Chessboard will drawPositionInstant() with currentPosition. Usually currentPosition is whatever was on the board when the player dropped the piece and everything is correct in that case.
  • However, in the example above (or whenever one attempts to implement a computer opponent), when the player drops a piece, onDrop is called which: calculates the new move (can be faster than 30ms), calls board.position() (potentially queued with setTimeout), and starts an animation for the computer move. Note that board.position() updates the currentPosition immediately.

As a result, if board.position() is called in the 30ms snapSpeed time window after player's move, the player gets to see two versions of the piece moved by the computer:

  • one because of the animation moving the piece (this is expected)
  • one because when snap animation finishes, it sees the new position that happens only after the computer move but the snap animation callback intended to only draw the position that happened after the player's move (i.e. before the computer gets to move their piece).

I attached a screenshot. I played 1.d4 and the computer from your example replied 2...,g4 and now the black g-pawn is duplicated: one is on g4 and the other one is moving from g2 to g4). duplicates

As mentioned at the start of this post, you can easily reproduce it locally by changing makeRandomMove delay to 1 and config.moveSpeed to 1000 in your example at https://www.chessboardjs.com/examples#5001

One workaround is to set config.snapSpeed to 0 and disallowing dragging pieces while computer move is being animated.

LMMilewski avatar Jul 25 '22 17:07 LMMilewski

I have the same problem

JuliaHorokhovatska avatar Jan 08 '24 15:01 JuliaHorokhovatska

I added delay whenever the computer makes a move, it is fix duplicated pieces.

JuliaHorokhovatska avatar Jan 09 '24 07:01 JuliaHorokhovatska