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

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

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

帖子 ejsoon »

你對currentBranch的理解有誤,currentBranch是一系列的數字,對應的是在當前線路的每一個分岔口(node.v.length>1)所選的分支。

比如currentBranch=[1,2],說明在第一個分岔口上,選擇了第二個分支,在遇到第二個分岔時選擇了第三個分支。

請修改你給的importExportedText()以及其它包含currentBranch的代碼。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4779
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

gemini:

You are absolutely right. I apologize for the misunderstanding. currentBranch only records choices at forks (where node.v.length > 1), not at every single step along the path.

Because of this, we need to track how many forks we have encountered up to the attach point (attachIndex), truncate currentBranch to that length, and then only append to currentBranch when a node actually has more than one child.

Here is the corrected importExportedText() function. You can replace the entire function with this updated version:

代码: 全选

function importExportedText(text) {
            text = text.trim();
            if (!text) {
                renderRecordUI();
                renderNoteUI();
                updateToolHighlights();
                return;
            }

            // Normalize Chinese notations
            text = text.replace(/车/g, '車').replace(/马/g, '馬').replace(/帅/g, '帥').replace(/将/g, '將').replace(/后/g, '後').replace(/进/g, '進');
            text = text.replace(/ r(\n|\s|$)/g, ' w$1');

            // Handle Direct JSON structure
            if (text.startsWith('{')) {
                try {
                    const data = JSON.parse(text);
                    function expand(node, parentFen) {
                        let dc, simfen, newNode;
                        if (node.m) {
                            dc = deriveCoordsFromMove(parentFen, node.m);
                            simfen = simulateMove(parentFen, dc);
                            newNode = { fen: simfen, move: node.m, lastMove: dc, c: node.c || "", v: [] };
                        } else {
                            newNode = { fen: parentFen, c: node.c || "", v: [] };
                        }
                        if (node.v) { newNode.v = node.v.map(child => expand(child, newNode.fen)); }
                        return newNode;
                    }
                    historyFEN = expand(data, data.fen);
                    initBranch(); // initBranch correctly builds currentBranch based on forks
                    currentStepIndex = 0;
                    renderRecordUI();
                    renderNoteUI();
                    jumpToStep(0);
                    saveStateToUndo();
                    updateToolHighlights();
                    return;
                } catch (e) {
                    console.log("JSON parse failed, processing as text notation.");
                }
            }

            // 1. Locate explicitly provided FEN if present
            let importedFen = null;
            const fenMatch = text.match(/(?:position fen )?([a-zA-Z0-9/]+ [wb])/);
            let movesStr = text;

            if (fenMatch) {
                importedFen = fenMatch[1];
                // Strip the FEN string declaration so it isn't parsed as moves later
                movesStr = movesStr.replace(/position fen [a-zA-Z0-9/]+ [wb](\s+moves)?/, '');
                if (movesStr === text) {
                    movesStr = movesStr.replace(fenMatch[1], '');
                }
            }

            // 2. Identify the Attach Point (Parent Node)
            let attachIndex = currentStepIndex;
            let attachNode = null;

            if (importedFen) {
                // If FEN exists, trace backwards to find a matching state
                for (let i = currentStepIndex; i >= 0; i--) {
                    const node = getNodeAtStep(i);
                    if (node && node.fen === importedFen) {
                        attachIndex = i;
                        attachNode = node;
                        break;
                    }
                }
                // No match down to root -> Overwrite everything
                if (!attachNode) {
                    attachIndex = 0;
                    attachNode = { fen: importedFen, move: null, lastMove: null, c: "", v: [] };
                    historyFEN = attachNode;
                    currentBranch = [];
                }
            } else {
                // No FEN -> Default attach point is the current active step
                attachNode = getNodeAtStep(attachIndex);
                importedFen = attachNode.fen;
            }

            // 3. Process move sequence text
            movesStr = movesStr.replace(/^\d+\.\s*/gm, ' ').replace(/\s\d+\.\s/g, ' ').replace(/\.\.\./g, ' ');
            let tokens = movesStr.split(/\s+/).filter(t => t.length > 0 && t !== 'moves');

            let currentFen = importedFen;
            let vMap = buildVirtualMap(currentFen);
            let currNode = attachNode;

            // Calculate how many forks exist from root up to attachIndex
            let forkCount = 0;
            let tempNode = historyFEN;
            for (let i = 0; i < attachIndex; i++) {
                if (tempNode.v && tempNode.v.length > 1) {
                    forkCount++;
                }
                const choice = (tempNode.v && tempNode.v.length > 1) ? (currentBranch[forkCount - 1] || 0) : 0;
                tempNode = tempNode.v[choice];
            }

            // Truncate currentBranch to discard choices beyond the attach point
            currentBranch = currentBranch.slice(0, forkCount);

            let hasError = false;

            for (let i = 0; i < tokens.length; i++) {
                let token = tokens[i];
                let dc = null;
                let moveEn = "";
                let isRed = currentFen.includes(' w');

                // Check for UCCI Engine Coordinate Format (e.g., "a0b0" or "h7e7")
                if (/^[a-i][0-9][a-i][0-9]$/.test(token)) {
                    let startX = token.charCodeAt(0) - 97;
                    let startY = 9 - parseInt(token.charAt(1), 10);
                    let endX = token.charCodeAt(2) - 97;
                    let endY = 9 - parseInt(token.charAt(3), 10);
                    dc = { startX, startY, endX, endY };

                    let pId = vMap.get(`${startX},${startY}`);
                    if (!pId) { hasError = true; break; }

                    moveEn = getMoveNotation(pId, startX, startY, endX, endY, null, vMap);
                } else {
                    let isEnglish = /^[a-zA-Z]/.test(token) || /^[+\-=1-9][a-zA-Z0-9]/.test(token);
                    moveEn = isEnglish ? token : NotationConverter.toEnglish(token, isRed);
                    dc = deriveCoordsFromMove(currentFen, moveEn, isRed);
                    if (!dc) { hasError = true; break; }
                }

                let nextFen = simulateMove(currentFen, dc);

                // Check if this move already exists as a branch from the current node
                let childIdx = currNode.v.findIndex(c => c.move === moveEn && c.fen === nextFen);
                if (childIdx === -1) {
                    let newNode = { fen: nextFen, move: moveEn, lastMove: dc, c: "", v: [] };
                    currNode.v.push(newNode);
                    childIdx = currNode.v.length - 1;
                }

                // If this node is a fork (either it was already, or we just added a new branch), record the choice
                if (currNode.v.length > 1) {
                    currentBranch[forkCount] = childIdx;
                    forkCount++;
                }

                currNode = currNode.v[childIdx];
                currentFen = nextFen;

                let pId = vMap.get(`${dc.startX},${dc.startY}`);
                vMap.delete(`${dc.startX},${dc.startY}`);
                if (pId) vMap.set(`${dc.endX},${dc.endY}`, pId);
            }

            if (hasError && tokens.length > 0) {
                alert("Parsed partially due to an invalid move notation.");
            }
            
            // If the final node we landed on (or existing path we merged into) has further branches, default to 0
            while (currNode && currNode.v && currNode.v.length > 0) {
                if (currNode.v.length > 1) {
                    currentBranch.push(0);
                }
                currNode = currNode.v[0];
            }

            currentStepIndex = attachIndex;
            renderRecordUI();
            renderNoteUI();
            jumpToStep(currentStepIndex);
            
            saveStateToUndo();
            updateToolHighlights();
        }
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4779
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

附件
ejcees20260322aabran99946.7z
(36.43 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4779
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

附件
ejcees20260323dpxq9995.7z
(36.56 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

正浏览此版面之用户: Semrush [Bot] 和 3 访客