Files
lara-schach-live/pgn-parser.js

138 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* PGN Parser - Parses PGN files and extracts game data
*/
function parsePGN(pgnText) {
const games = [];
// Split by game boundaries - each game starts with [Event
const gameBlocks = pgnText.split(/\[\s*Event\s*"/);
for (let i = 1; i < gameBlocks.length; i++) {
const game = parseGameBlock(gameBlocks[i]);
if (game) games.push(game);
}
return games;
}
function parseGameBlock(block) {
try {
const headers = {};
// Der Event-Header fehlt, weil wir danach splitten extrahiere ihn aus dem Blockanfang
const eventEnd = block.indexOf('"]');
if (eventEnd > 1) {
headers.Event = block.substring(1, eventEnd);
}
const headerRegex = /^\s*\[(\w+)\s+"([^"]*)"\]/gm;
let match;
// Extract all headers
let tempBlock = block;
while ((match = headerRegex.exec(tempBlock)) !== null) {
headers[match[1]] = match[2];
}
// Extract moves - everything after the last header
const lastHeaderEnd = block.lastIndexOf('"]');
let movesText = lastHeaderEnd > -1 ? block.substring(lastHeaderEnd + 2).trim() : '';
// Remove comments from moves for cleaner parsing
const moves = parseMoves(movesText);
return {
event: headers.Event || '',
site: headers.Site || '',
date: headers.Date || '',
round: headers.Round || '',
white: headers.White || '',
black: headers.Black || '',
result: headers.Result || '',
termination: headers.Termination || '',
whiteElo: headers.WhiteElo || '',
blackElo: headers.BlackElo || '',
whiteClock: headers.WhiteClock || '',
blackClock: headers.BlackClock || '',
moves: moves,
isLive: headers.Termination === 'unterminated' || headers.Result === '*'
};
} catch (e) {
console.error('Error parsing game:', e);
return null;
}
}
function parseMoves(movesText) {
const moves = [];
let clockWhite = null;
let clockBlack = null;
let color = 'w';
const tokenRegex = /\d+\.\s*|\{[^}]*\}|\S+/g;
const tokens = movesText.match(tokenRegex) || [];
for (let i = 0; i < tokens.length; i++) {
let token = tokens[i].trim();
if (['1-0', '0-1', '1/2-1/2', '*'].includes(token)) {
moves.push({ san: token, isResult: true, whiteClock: clockWhite, blackClock: clockBlack });
continue;
}
if (/^\d+\.$/.test(token)) continue;
if (token.startsWith('{')) {
const clkMatch = token.match(/\[%clk\s+([\d:]+)\]/);
if (clkMatch && moves.length > 0) {
const lastMove = moves[moves.length - 1];
if (!lastMove.isResult && lastMove.color) {
if (lastMove.color === 'w') {
clockWhite = clkMatch[1];
} else {
clockBlack = clkMatch[1];
}
lastMove.whiteClock = clockWhite;
lastMove.blackClock = clockBlack;
}
}
continue;
}
const move = { san: token, isResult: false, whiteClock: clockWhite, blackClock: clockBlack, color };
moves.push(move);
color = color === 'w' ? 'b' : 'w';
}
return moves;
}
function filterLaraGames(games) {
return games.filter(game =>
game.white.toLowerCase().includes('kiesewetter') ||
game.black.toLowerCase().includes('kiesewetter')
);
}
function getLiveGame(laraGames) {
// Return the game that is still in progress
return laraGames.find(game => game.isLive) || null;
}
function getLatestGame(laraGames) {
if (laraGames.length === 0) return null;
// Sort by round number, return the highest round
const sorted = [...laraGames].sort((a, b) => {
const roundA = parseInt(a.round) || 0;
const roundB = parseInt(b.round) || 0;
return roundB - roundA;
});
return sorted[0];
}
window.parsePGN = parsePGN;
window.filterLaraGames = filterLaraGames;
window.getLiveGame = getLiveGame;
window.getLatestGame = getLatestGame;