qwerty084 / vue3-chessboard

Vue 3 chessboard component, built with lichess chessground and chess.js
https://qwerty084.github.io/vue3-chessboard-docs/
GNU General Public License v3.0
70 stars 18 forks source link

Check highlight while viewing history when PGN starts with the king being in check does not work #251

Open YouSafe opened 7 months ago

YouSafe commented 7 months ago

Describe the bug Check highlight while viewing history when PGN starts with the king being in check does not work

Which version are you using 1.3.3

To Reproduce Steps to reproduce the behavior:

  1. Clone repository
  2. Add buttons for viewing history
  3. Load a pgn via loadPgn with a custom FEN where the king is initially in check
  4. Play a move
  5. Press the button to go back to the first move in history

Expected behavior Check should be highlighted like in all other cases.

Screenshots firefox_2FPNXlS4Pm

Additional context The issue comes from the fact that to determine whether or not the king is in check in any history position, the SAN of the previous move is examined and if it contains # or +, then the king must be in check after the move is performed.

This is the problematic line: https://github.com/qwerty084/vue3-chessboard/blob/77c704e2e018e2a4ce50869afa31ad013e99dda4/src/classes/BoardApi.ts#L706

gavin-lb commented 1 month ago

Unfortunately, to actually address this bug would require either a PR with chess.js or some rather large changes to the way history is handled in this project.

Currently the .history method of the underlying chess.js game is entirely responsible for handling the game history and sadly this method does not provide check/checkmate information even when called with the verbose option. Checking the SAN of the previous move was a lucky hack that allowed checking of check/checkmate information when implementing the history viewer feature, but obviously if the first move is a check/checkmate then this is not possible.

One change that could be made with the way chess.js handles move history would be to take advantage of the flag property of the Move objects returned in verbose mode. Currently it only has information about whether the move is a capture, a "big pawn" move (ie. the double push on its first move), an en passant, a promotion, a kingside castle or a queenside castle - but no check/checkmate information. So merely adding check/checkmate information to the flag property would be one change that could be made with chess.js to facilitate this bug fix.

The other approach would be to change the way history is handled in vue3-chessboard. For example, one change we could do is to view history by actually rewinding the game in the chess.js instance. Then we could call chess.js methods for the currently viewed position and this could be used to get check/checkmate information (of course, this would require keeping track of what we have rewound so that we could redo the moves when unviewing history). Alternatively we could keep track of the history internally and then we could store check/checkmate information for each move ourselves. However, neither of these changes are ideal as they would be more work and they kind of defeat the point of using chess.js for the underlying game logic.

So of the two approaches, I feel it would definitely be preferable to submit a PR with chess.js to return check/checkmate information about each move with the .history method. But given the relative inactivity of that repo and the author’s seeming reluctance to accept PRs (I have several open “under consideration” for more than a year, for instance), I wouldn't hold your breath with that one...


And apologies, but I must add one tiny bit of pedantry: your statement "to determine whether or not the king is in check in any history position, the SAN of the previous move is examined and if it contains # or +, then the king must be in check after the move is performed" is not strictly true. It actually checks whether the string '+#' contains the last character of the SAN, which is functionally equivalent to checking whether the last character of the SAN is either a + or a #. This is slightly more efficient than checking the whole SAN string and it won't return a false positive for a malformed SAN such as '+e4', but otherwise is almost the same as what you said.

gavin-lb commented 1 month ago

Actually, I suppose there is a third approach: a hacky edgecase check bugfix. When initialising a board, we could check whether the first move is a check/checkmate by creating a separate chess.js object with only the starting FEN. We can then throw away that chess.js instance and store this edgecase information to refer back to whenever viewing the first move. But this is extremely ugly, so I would be reluctant to do it. We would probably be better off just handling history internally instead.