將製作ejcees(中國象棋打譜程式)

分享和讨论Javascript相关的话题
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4549
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

Re: 將製作ejcees(中國象棋打譜程式)

帖子 ejsoon »

根據盤面及走法,得到所移動的棋子起始和結束坐標:

代码: 全选

/**
 * Advanced: Derives coordinates from FEN and English notation (supports handling ambiguity for multiple pawns)
 * Supported formats: C2=5, +2=3, =P+1, 3P=9, etc.
 */
function deriveCoordsFromEN(fen, moveEN) {
    if (!moveEN) return null;

    // 1. Parse FEN to get the board array and the current turn
    const parts = fen.split(' ');
    const isRed = (parts[1] === 'w');
    const board = parseFENToBoard(parts[0]); // Convert to 10x9 array

    // 2. Parse English move string
    // Format parsing: [prefix?][piece/col?][action][target value]
    const match = moveEN.match(/^([+\-=1-9])?([a-zA-Z1-9])?([+\-=])(\d)$/);
    if (!match) return null;

    let prefix = match[1];      // +, -, =, 1-9 (representing front, back, middle, or ordinal number)
    let indicator = match[2];   // Piece code (e.g., P) or starting column (e.g., 2)
    const action = match[3];    // +, -, =
    const targetVal = parseInt(match[4], 10);

    // 3. Collect all pieces of the same type belonging to the current side on the board
    let searchChar = (indicator && /[a-zA-Z]/.test(indicator)) ? 
                     (isRed ? indicator.toUpperCase() : indicator.toLowerCase()) : 
                     (isRed ? 'P' : 'p'); // Default to pawn

    let candidates = [];
    for (let y = 0; y < 10; y++) {
        for (let x = 0; x < 9; x++) {
            if (board[y][x] === searchChar) {
                candidates.push({ x, y, col: isRed ? (9 - x) : (x + 1) });
            }
        }
    }

    // 4. Filter starting piece (startX, startY) based on ambiguity rules
    let piece = null;

    // Case A: Starting column specified (e.g., "2" in C2=5 or +2=3)
    if (indicator && /[1-9]/.test(indicator)) {
        const startCol = parseInt(indicator, 10);
        let colPieces = candidates.filter(p => p.col === startCol);

        if (prefix) {
            // Handle cases like "+2=3" (front-2-move-to-3)
            sortPiecesFrontToBack(colPieces, isRed);
            const idx = parsePrefixToIndex(prefix, colPieces.length);
            piece = colPieces[idx];
        } else {
            // Handle cases like "C2=5"
            piece = colPieces[0];
        }
    } 
    // Case B: Special prefix used (e.g., =P+1 or 3P=9)
    else if (prefix) {
        // First, identify columns with multiple pieces
        let multiCols = [];
        for(let c=1; c<=9; c++) {
            if (candidates.filter(p => p.col === c).length > 1) multiCols.push(c);
        }

        if (multiCols.length > 1 && prefix !== '=') {
            // This is the "two-column pawn" rule: prefix represents "front/back", indicator represents "which column"
            // If indicator is P, we need to search all candidates
            sortPiecesFrontToBack(candidates, isRed);
            const idx = parsePrefixToIndex(prefix, candidates.length); 
            piece = candidates[idx];
        } else {
            // Single-column, multiple-piece rule (front, middle, back)
            sortPiecesFrontToBack(candidates, isRed);
            const idx = parsePrefixToIndex(prefix, candidates.length);
            piece = candidates[idx];
        }
    }

    if (!piece) return null;

    // 5. Calculate target coordinates (endX, endY)
    const startX = piece.x;
    const startY = piece.y;
    let endX = startX, endY = startY;

    if (action === '=') {
        endX = isRed ? (9 - targetVal) : (targetVal - 1);
    } else {
        const direction = isRed ? -1 : 1; // Red moves decrease Y, Black moves increase Y
        const sign = (action === '+') ? 1 : -1;
        const isJumping = ['N','B','A'].includes(searchChar.toUpperCase());

        if (isJumping) {
            endX = isRed ? (9 - targetVal) : (targetVal - 1);
            const dx = Math.abs(endX - startX);
            const dy = (searchChar.toUpperCase() === 'N') ? (dx === 1 ? 2 : 1) : (dx === 2 ? 2 : 1);
            endY = startY + (direction * sign * dy);
        } else {
            endY = startY + (direction * sign * targetVal);
        }
    }

    return { startX, startY, endX, endY };
}

/** Helper: Parse FEN into an array */
function parseFENToBoard(fenPart) {
    return fenPart.split('/').map(row => {
        let line = [];
        for (let char of row) {
            if (/\d/.test(char)) line.push(...Array(parseInt(char)).fill(null));
            else line.push(char);
        }
        return line;
    });
}

/** Helper: Sort pieces based on Xiangqi rules (from front to back) */
function sortPiecesFrontToBack(pieces, isRed) {
    // Red: Smaller Y is closer to the front
    // Black: Larger Y is closer to the front
    if (isRed) pieces.sort((a, b) => a.y - b.y);
    else pieces.sort((a, b) => b.y - a.y);
}

/** Helper: Convert prefix symbol to array index */
function parsePrefixToIndex(prefix, total) {
    if (prefix === '+') return 0; // Front
    if (prefix === '-') return total - 1; // Back
    if (prefix === '=') return 1; // Middle (assuming 3 pieces)
    if (/[1-9]/.test(prefix)) return parseInt(prefix, 10) - 1; // 1-9 ordinal
    return 0;
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4549
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

Re: 將製作ejcees(中國象棋打譜程式)

帖子 ejsoon »

著法的添加應在棋子移動開始前,而不是移完之後。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4549
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

Re: 將製作ejcees(中國象棋打譜程式)

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4549
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

Re: 將製作ejcees(中國象棋打譜程式)

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

正浏览此版面之用户: 没有注册用户 和 12 访客