import { Classification } from '../../classification/MoveClassifier.js';
/**
* GameStats utility class for displaying player statistics comparison
*/
export class GameStats {
/**
* Renders the game statistics UI to the specified container
* @param {jQuery|string} container - The container element or selector
* @param {Object} analysis - The game analysis data
* @param {string} whiteName - White player name
* @param {string} blackName - Black player name
*/
static render(container = '.game-stats', analysis, whiteName = 'White', blackName = 'Black') {
if (!analysis) {
// Empty analysis
analysis = {
white: {
accuracy: 0,
counts: {},
elo: 0
},
black: {
accuracy: 0,
counts: {},
elo: 0
},
phaseClassifications: {
white: {
opening: Classification.GOOD,
middlegame: Classification.GOOD,
endgame: Classification.GOOD
},
black: {
opening: Classification.GOOD,
middlegame: Classification.GOOD,
endgame: Classification.GOOD
}
}
}
}
const $container = $(container);
$container.empty();
const statsContainer = $('
');
const phaseClassifications = analysis.phaseClassifications;
// Add all sections
statsContainer
.append(this.createPlayersHeader(whiteName, blackName))
.append('
')
.append(this.createStatsRow('Accuracy',
(analysis.white.accuracy * 100).toFixed(1),
(analysis.black.accuracy * 100).toFixed(1),
true))
.append('
')
.append(this.createMovesSection(analysis))
.append('
')
.append(this.createStatsRow('Estimated Elo',
analysis.white.elo ? Math.ceil(analysis.white.elo / 10) * 10 : 1400,
analysis.black.elo ? Math.ceil(analysis.black.elo / 10) * 10 : 1400,
true))
.append(this.createPhaseClassificationsRow('Opening', phaseClassifications?.white?.opening, phaseClassifications?.black?.opening, false))
.append(this.createPhaseClassificationsRow('Middlegame', phaseClassifications?.white?.middlegame, phaseClassifications?.black?.middlegame, false))
.append(this.createPhaseClassificationsRow('Endgame', phaseClassifications?.white?.endgame, phaseClassifications?.black?.endgame, false));
$container.append(statsContainer);
}
/**
* Creates the players header row
* @param {string} whiteName - White player name
* @param {string} blackName - Black player name
* @returns {jQuery} The players header element
*/
static createPlayersHeader(whiteName, blackName) {
return $(`
${whiteName}
${blackName}
`);
}
/**
* Creates a statistics row
* @param {string} label - The row label
* @param {string} whiteValue - White player value
* @param {string} blackValue - Black player value
* @param {boolean} useBoxes - Whether to use boxes for styling
* @returns {jQuery} The stats row element
*/
static createStatsRow(label, whiteValue, blackValue, useBoxes = false) {
const whiteEl = useBoxes
? `${whiteValue}
`
: `${whiteValue}
`;
const blackEl = useBoxes
? `${blackValue}
`
: ``;
return $(`
${label}
${whiteEl}
${blackEl}
`);
}
static createPhaseClassificationsRow(label, whiteClassification, blackClassification) {
const row = $(``);
let whiteIcon = $(`-
`);
let blackIcon = $(`-
`);
if (whiteClassification) whiteIcon = $(`
`);
if (blackClassification) blackIcon = $(`
`);
row.find('#white-icon').append(whiteIcon);
row.find('#black-icon').append(blackIcon);
return row;
}
/**
* Creates the moves section with classification counts
* @param {Object} analysis - The game analysis data
* @returns {jQuery} The moves section element
*/
static createMovesSection(analysis) {
const movesSection = $('');
const displayedClassifications = [
Classification.BRILLIANT,
Classification.GREAT,
Classification.PERFECT,
Classification.EXCELLENT,
Classification.GOOD,
Classification.MISTAKE,
Classification.BLUNDER
];
displayedClassifications.forEach(classif => {
const whiteCount = analysis.white.counts[classif.type] || 0;
const blackCount = analysis.black.counts[classif.type] || 0;
const label = classif.type.charAt(0).toUpperCase() + classif.type.slice(1);
const row = $(`
${label}
${whiteCount}
${blackCount}
`);
// Add classification icon if available
if (classif.cachedImg) {
row.find('.stats-icon').append(classif.cachedImg.cloneNode(true));
} else {
// Manually add the icon
const icon = $(`
`);
row.find('.stats-icon').append(icon);
}
movesSection.append(row);
});
return movesSection;
}
/**
* Updates an existing game stats display
* @param {jQuery|string} container - The container element or selector
* @param {Object} analysis - The updated game analysis data
* @param {string} whiteName - White player name
* @param {string} blackName - Black player name
*/
static update(container, analysis, whiteName = 'White', blackName = 'Black') {
this.render(container, analysis, whiteName, blackName);
}
}