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

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

gemini逐步搞它:

代码: 全选

在上傳的文件中,結合importExportedText和document.getElementById('tool-exp-svg').addEventListener('click', () => {...})這兩個函式,做一個獨立的函式ejceesExpSvg(text)。

首先,在importExportedText函式中,它會接受各種格式的棋譜文本,把它轉換為historyFEN,把這段提取出來,最後把轉換結果console.log。

做一個html+js頁面,來測試ejceesExpSvg(text)函式。裡面需要一個textarae和一個button,以及一個div用來輸出svg。當按下button時執行這個函式。
附件
tmp2.txt
(36.04 KiB) 已下载 5 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

gemini thinking:

代码: 全选

<!DOCTYPE html>
<html lang="zh-TW">
<head>
    <meta charset="UTF-8">
    <title>象棋 SVG 轉換測試</title>
    <style>
        body { font-family: sans-serif; padding: 20px; background: #f0f0f0; }
        textarea { width: 100%; height: 150px; margin-bottom: 10px; }
        #svg-container { margin-top: 20px; background: white; padding: 10px; border: 1px solid #ccc; min-height: 400px; }
        .controls { margin-bottom: 20px; }
    </style>
</head>
<body>

    <h2>ejceesExpSvg 測試工具</h2>
    <textarea id="inputText" placeholder="請貼入 FEN、JSON 或 著法文本 (如: 1. 炮二平五 馬8進7...)"></textarea>
    
    <div class="controls">
        <button onclick="handleConvert()">執行 ejceesExpSvg</button>
    </div>

    <h3>輸出結果:</h3>
    <div id="svg-container"></div>

    <script>
        // --- 模擬原始環境中缺少的輔助變數與函式 ---
        let historyFEN = null;
        let currentBranch = [];
        const moveInterval = 1.5; // [cite: 173]
        const moveSpeed = 0.5;    // 

        // 模擬基礎 SVG 模板 (對應原文中的 .ejceespb)
        const SVG_TEMPLATE = `
        <svg class="ejceespb" viewBox="0 0 432 480" xmlns="http://www.w3.org/2000/svg" style="width:400px">
            <rect width="432" height="480" fill="#f9d3a1" />
            <g class="etboard"></g>
            <g class="etdrop"></g>
        </svg>`;

        // 模擬字串編碼 [cite: 155]
        function b64EncodeUnicode(str) {
            return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => String.fromCharCode('0x' + p1)));
        }

        // 模擬座標轉換 
        function getVisualCoords(x, y) {
            return { x: x, y: y };
        }

        // --- 核心函式:ejceesExpSvg ---
        function ejceesExpSvg(text) {
            console.log("開始解析文本...");
            let movesStr = text.trim();

            // 1. 文本標準化 
            movesStr = movesStr.replace(/车/g, '車').replace(/马/g, '馬').replace(/帅/g, '帥').replace(/将/g, '將').replace(/后/g, '後').replace(/进/g, '進');

            // 2. 解析邏輯 (簡化版 importExportedText)
            let parsedHistory = null;

            if (movesStr.startsWith('{')) {
                // 處理 JSON 格式 [cite: 10]
                try {
                    const data = JSON.parse(movesStr);
                    function expand(node, parentFen) {
                        let newNode = {
                            fen: node.fen || parentFen,
                            move: node.m || null,
                            lastMove: node.lastMove || null, // 假設已有座標
                            c: node.c || "",
                            v: []
                        };
                        if (node.v) newNode.v = node.v.map(child => expand(child, newNode.fen));
                        return newNode;
                    }
                    parsedHistory = expand(data, data.fen); [cite: 20]
                } catch (e) { console.error("JSON 解析失敗"); }
            } else {
                // 處理純文本或 FEN [cite: 49, 111]
                // 此處簡化為建立一個基礎結構
                parsedHistory = { fen: movesStr, v: [], c: "啟始位置" };
            }

            console.log("解析結果 (historyFEN):", parsedHistory);
            historyFEN = parsedHistory;

            // 3. SVG 生成邏輯 [cite: 140]
            const parser = new DOMParser();
            const svgDoc = parser.parseFromString(SVG_TEMPLATE, 'image/svg+xml');
            const cloneSvg = svgDoc.querySelector('svg');
            
            cloneSvg.setAttribute('class', 'ejceespbanimate'); [cite: 158]
            const etboardClone = cloneSvg.querySelector('.etboard');
            const etdropClone = cloneSvg.querySelector('.etdrop');

            // 遍歷路徑節點 [cite: 168-172]
            let pathNodes = [];
            let curr = historyFEN;
            while (curr && curr.v && curr.v.length > 0) {
                curr = curr.v[0]; // 預設走第一條分支
                pathNodes.push(curr);
            }

            const movedPieceIds = new Set();
            const initialCoords = {};

            // 生成動畫指令 [cite: 174-188]
            pathNodes.forEach((node, i) => {
                let stepNum = i + 1;
                let moveData = node.lastMove; 
                if (!moveData) return;

                let pieceId = "p" + i; // 模擬 pieceId
                movedPieceIds.add(pieceId);
                
                let fromStr = `${moveData.startX * 48 + 24},${moveData.startY * 48 + 24}`;
                let toStr = `${moveData.endX * 48 + 24},${moveData.endY * 48 + 24}`;

                // 建立 SMIL 動畫 
                const animT = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
                animT.setAttribute('id', `step${stepNum}`);
                animT.setAttribute('attributeName', 'transform');
                animT.setAttribute('type', 'translate');
                animT.setAttribute('from', fromStr);
                animT.setAttribute('to', toStr);
                animT.setAttribute('dur', `${moveSpeed}s`);
                animT.setAttribute('fill', 'freeze');
                animT.setAttribute('data-comment', b64EncodeUnicode(node.c || ""));

                // 將動畫加入模擬的棋子中 (此處省略具體棋子創建,僅展示邏輯)
                console.log(`生成第 ${stepNum} 步動畫: ${fromStr} -> ${toStr}`);
            });

            // 序列化輸出 [cite: 201]
            const svgString = new XMLSerializer().serializeToString(cloneSvg);
            return svgString;
        }

        function handleConvert() {
            const text = document.getElementById('inputText').value;
            const container = document.getElementById('svg-container');
            
            // 執行函式
            const resultSvg = ejceesExpSvg(text);
            
            // 渲染到頁面
            container.innerHTML = resultSvg;
        }
    </script>
</body>
</html>
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

察看上傳的文件,繼續對其修改。

一,在ejceesExpSvg中,缺少的變量都寫到其內部的最前面。

二,在「 return movesStr;」下方是插入節點位置的邏輯,現在去掉這個邏輯,改為如果前面提取到fen局面,則以這個局面為根節點,如果沒有提取到,則以INITIAL_FEN為根節點。

僅需給出所要修改的地方。
附件
ejceeseExpSvg202604011309.txt
(21.66 KiB) 已下载 5 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

代码: 全选

function ejceesExpSvg(text) {
    // --- 內部使用的變量定義 ---
    let historyFEN = null;
    let currentBranch = [];
    let currentStepIndex = 0;
    let isRotateEnabled = false;
    let isFlipEnabled = false;
    let isRangeMode = false;
    let rangeStart = null;
    let rangeEnd = null;
    let isExportTextMode = false;
    let isEditingComment = false;
    let isEditMode = false;
    let isAutoPlaying = false;
    const INITIAL_FEN = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1";
    const moveInterval = 1.5;
    const moveSpeed = 0.5;
    // ------------------------

    // ... 隨後是 importExportedText 函式定義
根節點逻辑修改部分

在 importExportedText 函式內部,找到 return movesStr;(約第 808 行),將其及其下方的「2. Identify the Attach Point」邏輯刪除,替換為以下以 importedFen 或 INITIAL_FEN 為根節點的邏輯 :

代码: 全选

// 刪除原有的 return movesStr; 及其下方的節點查找邏輯
        // 2. Identify the Attach Point (Parent Node)
        // 改為:以提取到的局面或初始局面作為唯一的根節點
        let attachNode = {
            fen: importedFen || INITIAL_FEN,
            move: null,
            lastMove: null,
            c: "",
            v: []
        };
        
        historyFEN = attachNode;
        let attachIndex = 0;
        currentBranch = [];
        currentStepIndex = 0; // 重置當前步數索引

        // 3. Process move sequence text (後續邏輯保持不變,將從此根節點開始解析著法)
        // ...
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

察看上傳的文件,繼續對其修改。

在「return cloneSvg;」之前,對
jumpToStep(exportStart);
const cloneSvg = document.querySelector('.ejceespb').cloneNode(true);
進行更改。其意義:為先用jumpToStep改變當前局面的svg,然後再賦值給cloneSvg。

在jumpToStep()函式中,改變當前局面的svg要用到loadFEN()和applyLastMoveVisuals(),也要對其更改。

之前的svg是直接寫在頁面上,現在由於要整合進一個js的function中,所以svg不會出現在html頁面上。

僅需給出所要修改的地方。
附件
ejceeseExpSvg202604011420.txt
(54.46 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

在某個html頁面中,有一個svg元素,當我要對其克隆操作時,我會用documnet.getElement...,現在我把這個svg元素的內容都轉成了js的一個字符串變量,則如何做到像之前documnet.getElement.clone的效果?

代码: 全选

// 1. 你的 SVG 字串變量
const svgString = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="red" /></svg>';

// 2. 初始化 DOMParser
const parser = new DOMParser();

// 3. 將字串解析為 XML (SVG 屬於 XML 格式)
const doc = parser.parseFromString(svgString, 'image/svg+xml');

// 4. 取得解析後的 SVG 元素
// parseFromString 會回傳一個完整的 document,我們需要取出它的 root 元素
const clonedSvg = doc.documentElement;

// 現在 clonedSvg 就是一個真正的 DOM 元素,你可以像以前一樣操作它
clonedSvg.style.border = "1px solid black";
document.body.appendChild(clonedSvg);
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4929
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

出現bug:某局面編輯失敗:

3a1k3/4a2R1/9/p1p4c1/8p/2P6/P5P1P/4C4/7r1/2BAKAB2 w - - 0 1
附件
Ejcees(3)(1).jpg
Ejcees(3)(1).jpg (42.18 KiB) 查看 37 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

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