import { Chess } from "../../../libs/chess.js";
import { Classification } from "../../classification/MoveClassifier.js";
export const IgnoredSuggestionTypes = [
Classification.BRILLIANT.type,
Classification.GREAT.type,
Classification.PERFECT.type,
Classification.THEORY.type,
Classification.FORCED.type
];
export class MoveInformation {
constructor() {}
/**
* Converts a UCI string to a SAN string.
* @param {string} uci - The UCI string to convert.
* @param {string} fen - The FEN string to use for the conversion.
* @returns {string} The SAN string.
*/
static convertUCIToSAN(uci, fen) {
const tempChess = new Chess(fen);
const from = uci.substring(0, 2);
const to = uci.substring(2, 4);
const promotion = uci.length > 4 ? uci.substring(4, 5) : undefined;
const moveObj = tempChess.move({ from, to, promotion });
return moveObj.san;
}
/**
* Updates the move information display.
* @param {Object} node - The current move node.
* @param {Object} prevNode - The previous move node.
*/
static updateMoveInfo(node, prevNode) {
const $moveInfo = $(".move-info").empty();
// Show placeholder when at the root node or have no move data
if (!node || node.id === 'root' || !node.move) {
$("
").addClass("move-info-placeholder")
.text("Select a move to see its classification.")
.appendTo($moveInfo);
return;
}
// Create container for move classification info
const $moveInfoContainer = $("
").addClass("move-classification-info");
// Add the current move classification if available
if (node.classification) {
const $moveInfoLine = $("
").addClass("classification-line");
// Left side - classification and move
const $moveLeftSide = $("
").addClass("move-left-side");
// Are the icons cached yet?
const trueClassification = Classification[node.classification.toUpperCase()];
if (trueClassification?.cachedImg) {
const originalImg = trueClassification.cachedImg;
const clone = originalImg.cloneNode(true);
$moveLeftSide.append(clone);
} else {
$("
![]()
").addClass("move-icon")
.attr("src", trueClassification.src)
.attr("alt", node.classification)
.appendTo($moveLeftSide);
}
$("
").addClass("move")
.addClass(trueClassification.class)
.text(node.move.san + " " + trueClassification.comment)
.appendTo($moveLeftSide);
$moveInfoLine.append($moveLeftSide);
// Right side - best move alternative
if (node.evaluatedMove?.lines?.length > 0 && !IgnoredSuggestionTypes.includes(node.classification)) {
// Get the previous position's best move
if (prevNode?.evaluatedMove?.lines) {
const bestLine = prevNode.evaluatedMove.lines.find(line => line.id === 1);
if (bestLine) {
// Get best move UCI string - either from uciMove or first element of pv array
const bestMoveUci = bestLine.uciMove || (bestLine.pv && bestLine.pv.length > 0 ? bestLine.pv[0] : null);
if (bestMoveUci) {
const san = MoveInformation.convertUCIToSAN(bestMoveUci, prevNode.fen);
$("").addClass("perfect-move-alternative")
.text("Best was " + san)
.appendTo($moveInfoLine);
}
}
}
}
$moveInfoContainer.append($moveInfoLine);
}
// Add the container to the move-info div
$moveInfo.append($moveInfoContainer);
}
}