diff --git a/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/chessboard.js b/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/chessboard.js index 8256f5a..192a03f 100644 --- a/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/chessboard.js +++ b/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/chessboard.js @@ -6,6 +6,7 @@ import { buildOnSnapEnd, WHITE_ABBREVIATION, BLACK_ABBREVIATION, + findMove, } from "./defaultConfig.js"; /** @@ -47,6 +48,7 @@ function AnduinChessBoard(color) { this.socket = null; this.statusControl = null; this.roleControl = null; + this.lastMovePair = [null, null]; this.config = { orientation: this.color === BLACK_ABBREVIATION ? "black" : "white", @@ -58,6 +60,30 @@ function AnduinChessBoard(color) { onSnapEnd: null, }; + this.renderTrack = () => { + if (this.lastMovePair[0] !== null && this.lastMovePair[1] !== null) { + let allSquares = Array.from( + document.querySelectorAll(`#board [data-square]`) + ); + allSquares + .filter((square) => { + let sq = square.getAttribute("data-square"); + return sq !== this.lastMovePair[0] && sq !== this.lastMovePair[1]; + }) + .forEach((square) => (square.style.boxShadow = "")); + + allSquares + .filter((square) => { + let sq = square.getAttribute("data-square"); + return sq === this.lastMovePair[0] || sq === this.lastMovePair[1]; + }) + .forEach( + (square) => + (square.style.boxShadow = "inset .2px .2px 4px 4px #f9ff49") + ); + } + }; + this.run = (player, gameId) => { this.roleControl.innerHTML = `You are ${ this.color === WHITE_ABBREVIATION @@ -96,6 +122,12 @@ function AnduinChessBoard(color) { }; this.refresh = (newFEN) => { + if (this.game !== null) { + let [position1, position2] = findMove(this.game.fen(), newFEN); + this.lastMovePair = [position1, position2]; + this.renderTrack(); + } + this.game = new Chess(newFEN); this.board.position(newFEN); console.log(`Got fen ${newFEN}. refreshing board...`); diff --git a/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/defaultConfig.js b/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/defaultConfig.js index ad6b10b..635b1ff 100644 --- a/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/defaultConfig.js +++ b/src/Aiursoft.ChessServer/wwwroot/scripts/chessboard/defaultConfig.js @@ -65,7 +65,7 @@ function buildOnDragStart(globalParams) { * * # example: * ```js - * let onDrop = onDrop({game, socket}); + * let onDrop = onDrop({game, socket, lastMovePair, renderTrack}); * ``` * * @param {{game, socket}} globalParams @@ -75,6 +75,7 @@ function buildOnDrop(globalParams) { const realOnDrop = (source, target) => { let game = globalParams.game; let socket = globalParams.socket; + let renderTrack = globalParams.renderTrack; document.querySelectorAll("#board [data-square]").forEach((square) => { square.style.backgroundColor = ""; @@ -90,16 +91,15 @@ function buildOnDrop(globalParams) { return "snapback"; } - // if (source !== target) { - // lastMovePair = [source, target]; - // } + if (source !== target) { + globalParams.lastMovePair = [source, target]; + renderTrack(); + } const lastMove = game.history({ verbose: true }).pop().san; socket.send(lastMove); } catch (e) { return "snapback"; - } finally { - // renderTrack(); } }; @@ -128,6 +128,68 @@ function buildOnSnapEnd(globalParams) { return realOnSnapEnd; } +function trackFEN() {} + +function parseFEN(fen) { + const parts = fen.split(" ")[0].split("/"); + const board = []; + + for (const part of parts) { + const row = []; + for (const char of part) { + if (isNaN(char)) { + row.push(char); + } else { + for (let i = 0; i < parseInt(char); i++) { + row.push(""); + } + } + } + board.push(row); + } + + return board; +} + +/** + * find the move positions + * @param {oldFEN} fen1 old FEN + * @param {string} fen2 new FEN + * @returns two positions thay are move, e.g. ['e4', 'e6'] + */ +function findMove(fen1, fen2) { + const board1 = parseFEN(fen1); + const board2 = parseFEN(fen2); + + let position1 = null; + let position2 = null; + + for (let i = 0; i < 8; i++) { + for (let j = 0; j < 8; j++) { + if (board1[i][j] !== board2[i][j]) { + if (position1 === null) { + position1 = { row: i, col: j }; + } else { + position2 = { row: i, col: j }; + } + } + } + } + + if (position1 === null || position2 === null) { + return [position1, position2]; + } else { + let row = 8 - position1.row; + let col = String.fromCharCode("a".charCodeAt() + position1.col); + position1 = col + row; + + row = 8 - position2.row; + col = String.fromCharCode("a".charCodeAt() + position2.col); + position2 = col + row; + return [position1, position2]; + } +} + export { buildOnDragStart, buildOnDrop, @@ -136,4 +198,5 @@ export { BLACK_ABBREVIATION, WHITE_SQUARE_GREY, BLACK_SQUARE_GREY, + findMove, };