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

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

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

帖子 ejsoon »

四個按鍵都要有切換功能,切換時變色。

當url切換時,如果加有?url=xxx,則以xxx為域名前綴,否則去掉#前面的字符。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

ejcees20260405importFenRotate99977747

改個小bug,在導入時如果把rotate寫到fen中,則rotate。
附件
ejcees20260405importFenRotate99977747.7z
(44.79 KiB) 已下载 6 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

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

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

帖子 ejsoon »

代码: 全选

<script>
        function handleConvert() {
            const text = document.getElementById('inputText').value;
            const moveInterval = document.getElementById('inputInterval').value;
            const moveSpeed = document.getElementById('inputSpeed').value;
            const container = document.getElementById('svg-container');
            const resultSvg = ejceesExpSvg(text, moveInterval, moveSpeed);
            container.innerHTML = resultSvg;
        }
    </script>
增加功能:在#svg-container的下方增加一個download鏈接,顯示為「download svg(size: byte)」,文件名為ejcees_svg_yyyymmdd_hhiiss.svg,其內容為resultSvg。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

gemini fast

代码: 全选

function handleConvert() {
    const text = document.getElementById('inputText').value;
    const moveInterval = document.getElementById('inputInterval').value;
    const moveSpeed = document.getElementById('inputSpeed').value;
    const container = document.getElementById('svg-container');
    
    // 1. 生成 SVG 內容
    const resultSvg = ejceesExpSvg(text, moveInterval, moveSpeed);
    container.innerHTML = resultSvg;

    // 2. 獲取或創建下載連結元素
    let downloadLink = document.getElementById('svg-download-link');
    if (!downloadLink) {
        downloadLink = document.createElement('a');
        downloadLink.id = 'svg-download-link';
        downloadLink.style.display = 'block';
        downloadLink.style.marginTop = '10px';
        container.parentNode.insertBefore(downloadLink, container.nextSibling);
    }

    // 3. 處理檔案內容與大小
    const blob = new Blob([resultSvg], { type: 'image/svg+xml' });
    const fileSize = blob.size;
    const url = URL.createObjectURL(blob);

    // 4. 生成檔名 (yyyymmdd_hhiiss)
    const now = new Date();
    const pad = (n) => n.toString().padStart(2, '0');
    const timestamp = `${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_` +
                      `${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}`;
    const fileName = `ejcees_svg_${timestamp}.svg`;

    // 5. 更新連結屬性
    downloadLink.href = url;
    downloadLink.download = fileName;
    downloadLink.innerText = `download svg (size: ${fileSize} bytes)`;
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

當#svg-container內出現svg時,設它的動畫開始時間為0。

代码: 全选

const svgElement = container.querySelector('svg');
    if (svgElement && typeof svgElement.setCurrentTime === 'function') {
        svgElement.setCurrentTime(0);
    }
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

改進:

一,當點擊tool-exp-txt時,進入「導出文本」狀態,右邊的四個按鈕,當其中一個處於active狀態時,再點擊一次都將能夠切換內容。

二,當切換內容時,它的背景色將變為橙色。再點擊則變回原來的顏色。程式將記住當前的狀態。

三,當第二個按鈕en在active狀態時被點擊時,它的表現跟cn一樣,即切換加評論的版本。

四,當第四個按鈕urlParameter在active狀態時被點擊時,它會切換為「url#...」。

url有三種來源:一是當頁面打開時如果有?url=value(value要經encodeURIComponent()編碼)則設為此值;二是當confirm時,如果文本中含有#且#後面沒有字符,則#前面的字符將成為url的值;三是當confirm時,如果文本中含有#且後面有字符,若#前面的字符跟當前的域名不同,則它將成為url的值。

五,當處於「導出文本」狀態時,在下方ejceestextbtn內的confirm和cancle中間新增兩個按鈕:複製和粘貼,分別加上合適的svg圖標。

複製和粘貼要用到clipboard API。這兩個按鈕在點擊後,退出「導出文本」狀態。複製就會把文本內容複製到剪貼板並cancle,粘貼就會把當前剪貼板的內容貼上並confirm。

六,在粘貼的右方,加上一個stick圖標。它在「導出文本」狀態時,是「固定」與「不固定」的切換。初始是不固定。

當點擊confirm、複製或粘貼時,如果它處於固定狀態,則當退出「導出文本」狀態時,ejceestextbtn內的五個button的最後兩個(moveInterval和moveSpeed)將消失,用「粘貼」和「取消固定」替代。

當點擊「取消固定」時,「粘貼」和「取消固定」消失,moveInterval和moveSpeed回復原來位置。

七,只需給出所要修改的地方,所有的代碼都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

gemini pro 又能複製了,是經歷了很大的整改吧。

代码: 全选

Here are the modifications required to fulfill your requests. Please apply these changes to the appropriate sections in your code.

### 1. Update CSS
Add the following CSS rule inside your `<style>` block to handle the orange background for the toggled state:

```css
    .exp-fmt-btn.active[data-odd="1"] {
        background: orange;
    }
```

### 2. Global Variables and URL Initialization
Add the new state variables at the beginning of your `<script>` tag, right after your existing variable declarations. Also, capture the initial URL parameter inside the `DOMContentLoaded` event:

```javascript
    let isEditMode = false;
    let editUndoStack = [];
    let editRedoStack = [];
    let selectedPalettePiece = null;
    let isTile0Selected = true;
    let editMiniBoardState = 0; 
    let preEditFEN = '';
    let editPickedPieceId = null;

    // --- NEW GLOBAL VARIABLES ---
    let baseUrl = "";
    let formatOddStates = { cn: 0, en: 0, engine: 0, url: 0 };
    let isExportPinned = false;
    // ----------------------------

    // AutoPlay & Range states
    // ... (Keep existing states)

    document.addEventListener('DOMContentLoaded', () => {
        // --- NEW INITIALIZATION ---
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has('url')) {
            baseUrl = decodeURIComponent(urlParams.get('url'));
        }
        // --------------------------

        const svgElement = document.querySelector('.ejceespb');
```

### 3. Replace the Notation Generator Function
Replace your old `generateCnTextWidthComment` function completely with this combined function that handles both Chinese and English notation with comments:

```javascript
        function generateTextWithComment(isEnglish = false) {
            const pathRoot = getGamePath();
            const fen = pathRoot.fen;
            let text = fen + '\n';

            if (pathRoot.c && pathRoot.c.trim() !== '') {
                text += pathRoot.c.trim() + '\n';
            }

            let isRedTurn = fen.split(' ')[1] === 'w';
            let moveNum = 1;
            let currentNode = pathRoot;
            let needsEllipsis = !isRedTurn;

            while (currentNode.v && currentNode.v.length > 0) {
                currentNode = currentNode.v[0];

                const moveStr = isEnglish ?
                    currentNode.move :
                    NotationConverter.toChinese(currentNode.move);

                if (isRedTurn) {
                    text += `${moveNum}. ${moveStr}`;
                    if (currentNode.c && currentNode.c.trim() !== '') {
                        text += `\n${currentNode.c.trim()}\n`;
                        needsEllipsis = true;
                    } else {
                        text += " ";
                        needsEllipsis = false;
                    }
                    isRedTurn = false;
                } else {
                    if (needsEllipsis) {
                        text += `${moveNum}. ... ${moveStr}\n`;
                    } else {
                        text += `${moveStr}\n`;
                    }
                    if (currentNode.c && currentNode.c.trim() !== '') {
                        text += `${currentNode.c.trim()}\n`;
                    }
                    moveNum++;
                    isRedTurn = true;
                    needsEllipsis = false;
                }
            }

            return text.trim();
        }
```

### 4. Update the `generateUrlHash` Function
Modify the existing `generateUrlHash` to accept an `isToggled` argument and use the `baseUrl`:

```javascript
        function generateUrlHash(isToggled = false) {
            let hashStr = encodeUrlParam(historyFEN, true);
            hashStr = hashStr.replace(/\$+$/, '');
            let currentDomain = window.location.origin + window.location.pathname;
            let prefix = currentDomain;
            
            if (isToggled) {
                prefix = baseUrl ? baseUrl : "url";
            }
            
            return prefix + "#" + hashStr;
        }
```

### 5. Update the `importExportedText` Function
Add the URL detection logic at the very beginning of the `importExportedText` function:

```javascript
        function importExportedText(text, importedFen = null) {
            text = text.trim();
            if (!text) {
                renderRecordUI();
                renderNoteUI();
                updateToolHighlights();
                return;
            }

            // --- NEW URL PARSING LOGIC ---
            if (text.includes('#')) {
                let parts = text.split('#');
                let beforeHash = parts[0].trim();
                let afterHash = parts.length > 1 ? parts[1].trim() : "";

                if (afterHash === "") {
                    baseUrl = beforeHash;
                } else {
                    let currentDomain = window.location.origin + window.location.pathname;
                    if (beforeHash !== "" && beforeHash !== currentDomain) {
                        baseUrl = beforeHash;
                    }
                }
            }
            // -----------------------------

            // Normalize Chinese notations
            text = text.replace(/车/g, '車').replace(/马/g, '馬').replace(/帅/g, '帥').replace(/将/g, '將').replace(/后/g, '後').replace(/进/g, '進');
            // ... (Keep the rest of the function the same)
```

### 6. Replace `renderExportTextUI`
Overwrite your entire `renderExportTextUI` function to include the new buttons, clipboards, pinning states, and toggle states:

```javascript
        function renderExportTextUI() {
            const recordContainer = document.querySelector('.ejceesrecord');
            const commentDiv = document.querySelector('.ejceescomment');
            const btnDiv = document.querySelector('.ejceestextbtn');

            const cnText = generateExportText(false);
            const cnTextWidthComment = generateTextWithComment(false);
            const enText = generateExportText(true);
            const enTextWidthComment = generateTextWithComment(true);
            const urlText = generateUrlHash(false);
            const urlTextToggled = generateUrlHash(true);

            // Generate UCCI Engine Format String
            let path = getGamePath();
            let engineText = "position fen " + path.fen;
            let currNode = path;
            if (currNode && currNode.v && currNode.v.length > 0) {
                engineText += " moves";
            }
            while (currNode && currNode.v && currNode.v.length > 0) {
                currNode = currNode.v[0];
                let dc = currNode.lastMove;
                if (dc) {
                    engineText += " " + String.fromCharCode(97 + dc.startX) + (9 - dc.startY) + String.fromCharCode(97 + dc.endX) + (9 - dc.endY);
                }
            }

            recordContainer.innerHTML = `<textarea class="ejceescomment-edit" id="export-textarea" style="width:100%; height:100%; resize:none; border:none; outline:none; background:#2a2a2a; color:#fff; padding:8px; font-family:monospace; font-size:14px; white-space:pre-wrap; overflow:auto;"></textarea>`;

            const textarea = document.getElementById('export-textarea');

            commentDiv.innerHTML = `<div class="exp-fmt-outer">
                <div class="exp-fmt-btn ${lastExportFormat === 'cn' ? 'active' : ''}" data-fmt="cn" data-odd="${formatOddStates['cn']}">Chinese Notation</div>
                <div class="exp-fmt-btn ${lastExportFormat === 'en' ? 'active' : ''}" data-fmt="en" data-odd="${formatOddStates['en']}">English Notation</div>
                <div class="exp-fmt-btn ${lastExportFormat === 'engine' ? 'active' : ''}" data-fmt="engine" data-odd="${formatOddStates['engine']}">Engine Format</div>
                <div class="exp-fmt-btn ${lastExportFormat === 'url' ? 'active' : ''}" data-fmt="url" data-odd="${formatOddStates['url']}">URL Parameter</div>
               </div>`;

            const formatBtns = commentDiv.querySelectorAll('.exp-fmt-btn');

            const updateTextarea = (fmt) => {
                if (fmt === 'cn') {
                    textarea.value = formatOddStates[fmt] === 1 ? cnTextWidthComment : cnText;
                } else if (fmt === 'en') {
                    textarea.value = formatOddStates[fmt] === 1 ? enTextWidthComment : enText;
                } else if (fmt === 'engine') {
                    if (formatOddStates[fmt] === 1) {
                        const isRed = currentTurn === 'w';
                        const moves = getAllLegalMoves(isRed, tileMap);
                        const searchMovesStr = moves.map(m => String.fromCharCode(97 + m.startX) + (9 - m.startY) + String.fromCharCode(97 + m.endX) + (9 - m.endY)).join(' ');
                        textarea.value = engineText + (searchMovesStr ? "\ngo searchmoves " + searchMovesStr : "");
                    } else {
                        textarea.value = engineText;
                    }
                } else if (fmt === 'url') {
                    textarea.value = formatOddStates[fmt] === 1 ? urlTextToggled : urlText;
                }
            };

            formatBtns.forEach(btn => {
                btn.addEventListener('click', () => {
                    const wasActive = btn.classList.contains('active');
                    const fmt = btn.getAttribute('data-fmt');
                    lastExportFormat = fmt;

                    formatBtns.forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');

                    if (wasActive) {
                        formatOddStates[fmt] = formatOddStates[fmt] === 1 ? 0 : 1;
                    }
                    btn.setAttribute('data-odd', formatOddStates[fmt]);

                    updateTextarea(fmt);

                    textarea.blur();
                    setTimeout(() => {
                        textarea.focus();
                        textarea.select();
                    }, 12);
                });
            });

            updateTextarea(lastExportFormat);
            setTimeout(() => textarea.select(), 10);

            btnDiv.innerHTML = `
                   <div class="ejceestextbtninner">
                       <div class="note-btn btn-confirm" id="exp-confirm" title="Confirm">
                           <svg viewBox="0 0 24 24"><path fill="#4CAF50" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
                       </div>
                       <div class="note-btn btn-copy" id="exp-copy" title="Copy">
                           <svg viewBox="0 0 24 24"><path fill="#fff" d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>
                       </div>
                       <div class="note-btn btn-paste" id="exp-paste" title="Paste">
                           <svg viewBox="0 0 24 24"><path fill="#fff" d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/></svg>
                       </div>
                       <div class="note-btn btn-pin" id="exp-pin" title="Pin" style="background-color: ${isExportPinned ? '#4CAF50' : '#555'};">
                           <svg viewBox="0 0 24 24"><path fill="#fff" d="M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z"/></svg>
                       </div>
                       <div class="note-btn btn-cancel" id="exp-cancel" title="Cancel">
                           <svg viewBox="0 0 24 24"><path fill="#F44336" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                       </div>
                   </div>
               `;

            document.getElementById('exp-cancel').addEventListener('click', () => {
                isExportTextMode = false;
                renderRecordUI();
                renderNoteUI();
                updateToolHighlights();
            });

            document.getElementById('exp-confirm').addEventListener('click', () => {
                const text = textarea.value;
                isExportTextMode = false;
                importExportedText(text);
            });

            document.getElementById('exp-copy').addEventListener('click', () => {
                navigator.clipboard.writeText(textarea.value).then(() => {
                    document.getElementById('exp-cancel').click();
                }).catch(err => {
                    console.error('Copy failed', err);
                    document.getElementById('exp-cancel').click();
                });
            });

            document.getElementById('exp-paste').addEventListener('click', () => {
                navigator.clipboard.readText().then(text => {
                    textarea.value = text;
                    document.getElementById('exp-confirm').click();
                }).catch(err => {
                    console.error('Paste failed', err);
                });
            });

            document.getElementById('exp-pin').addEventListener('click', (e) => {
                isExportPinned = !isExportPinned;
                e.currentTarget.style.backgroundColor = isExportPinned ? '#4CAF50' : '#555';
            });
        }
```

### 7. Modify `renderNoteUI`
Find the `} else {` block in your `renderNoteUI` function (where it generates the buttons like `btn-del-move`, `btn-range`, `btn-interval`, etc.). Replace that specific block with the following logic:

```javascript
            } else {
                commentDiv.innerHTML = '';
                commentDiv.textContent = node.c || '';

                let extraBtns = '';
                if (isExportPinned) {
                    extraBtns = `
                        <div class="note-btn" id="btn-pinned-paste" title="Paste">
                            <svg viewBox="0 0 24 24"><path fill="#fff" d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/></svg>
                        </div>
                        <div class="note-btn" id="btn-unpin" title="Unpin">
                            <svg viewBox="0 0 24 24"><path fill="#F44336" d="M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z"/></svg>
                        </div>
                    `;
                } else {
                    extraBtns = `
                        <div class="note-btn" id="btn-interval" title="Move Interval" style="width: auto; padding: 0 4px; font-weight: bold;">
                    ${moveInterval}s
                        </div>
                        <div class="note-btn" id="btn-speed" title="Move Speed" style="width: auto; padding: 0 4px; font-weight: bold;">
                    ${moveSpeed}s
                        </div>
                    `;
                }

                btnDiv.innerHTML = `
                        <div class="ejceestextbtninner">
                        <div class="note-btn" id="btn-del-move" title="Delete Move">
                        <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
                        </div>
                        <div class="note-btn" id="btn-range" title="Range Selection" style="${isRangeMode ? 'background-color:#4CAF50;' : ''}">
                        <svg viewBox="0 0 24 24"><path fill="${isRangeMode ? '#fff' : '#ccc'}" d="M7 6h4v2H9v8h2v2H7V6zm10 0h-4v2h2v8h-2v2h4V6z"/></svg>
                        </div>
                        <div class="note-btn" id="btn-autoplay" title="Auto Play">
                    ${isAutoPlaying
                            ? '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>'
                            : '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>'
                    }
                        </div>
                        ${extraBtns}
                        </div>
                    `;

                document.getElementById('btn-autoplay').addEventListener('click', () => {
                    if (isAutoPlaying) {
                        stopAutoPlay();
                    } else {
                        startAutoPlay();
                    }
                });

                document.getElementById('btn-del-move').addEventListener('click', deleteCurrentMoveAndAfter);

                document.getElementById('btn-range').addEventListener('click', () => {
                    isRangeMode = !isRangeMode;
                    if (!isRangeMode) {
                        rangeStart = null;
                        rangeEnd = null;
                        rangeClicks = 0;
                        clearRangeBorders();
                    } else {
                        rangeStart = null;
                        rangeEnd = null;
                        rangeClicks = 0;
                        clearRangeBorders();
                    }
                    renderNoteUI();
                });

                if (isExportPinned) {
                    document.getElementById('btn-pinned-paste').addEventListener('click', () => {
                        navigator.clipboard.readText().then(text => {
                            importExportedText(text);
                        }).catch(err => {
                            console.error('Paste failed', err);
                        });
                    });
                    document.getElementById('btn-unpin').addEventListener('click', () => {
                        isExportPinned = false;
                        renderNoteUI();
                    });
                } else {
                    document.getElementById('btn-interval').addEventListener('click', () => {
                        if (isAutoPlaying) return;
                        btnDiv.innerHTML = `
                                <div class="ejceestextbtninner" style="justify-content: flex-start; gap: 4px;">
                                <input type="text" id="interval-input" style="width: 36px; font-size: 12px; background: #222; color: #fff; border: 1px solid #555; text-align: center; outline: none;" value="${moveInterval}" maxlength="3">
                                <div class="note-btn interval-opt" data-val="1">1</div>
                                <div class="note-btn interval-opt" data-val="2">2</div>
                                <div class="note-btn interval-opt" data-val="3">3</div>
                                <div class="note-btn btn-confirm" id="interval-confirm" title="Confirm">
                                <svg viewBox="0 0 24 24"><path fill="#4CAF50" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
                                </div>
                                <div class="note-btn btn-cancel" id="interval-cancel" title="Cancel">
                                <svg viewBox="0 0 24 24"><path fill="#F44336" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                                </div>
                                </div>
                                                       `;

                        document.querySelectorAll('.interval-opt').forEach(btn => {
                            btn.addEventListener('click', (e) => {
                                moveInterval = parseFloat(e.target.getAttribute('data-val'));
                                renderNoteUI();
                                saveStateToUndo();
                                updateToolHighlights();
                            });
                        });

                        document.getElementById('interval-confirm').addEventListener('click', () => {
                            let val = parseFloat(document.getElementById('interval-input').value);
                            if (isNaN(val) || val < 0.2 || val > 9) {
                                val = moveInterval;
                            }
                            moveInterval = parseFloat(val.toFixed(1));
                            renderNoteUI();
                            saveStateToUndo();
                            updateToolHighlights();
                        });

                        document.getElementById('interval-cancel').addEventListener('click', () => {
                            renderNoteUI();
                        });
                    });

                    document.getElementById('btn-speed').addEventListener('click', () => {
                        if (isAutoPlaying) return;
                        btnDiv.innerHTML = `
                                <div class="ejceestextbtninner" style="justify-content: flex-start; gap: 4px;">
                                <input type="text" id="speed-input" style="width: 36px; font-size: 12px; background: #222; color: #fff; border: 1px solid #555; text-align: center; outline: none;" value="${moveSpeed}" maxlength="3">
                                <div class="note-btn speed-opt" data-val="0.2">0.2</div>
                                <div class="note-btn speed-opt" data-val="0.4">0.4</div>
                                <div class="note-btn speed-opt" data-val="0.6">0.6</div>
                                <div class="note-btn btn-confirm" id="speed-confirm" title="Confirm">
                                <svg viewBox="0 0 24 24"><path fill="#4CAF50" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
                                </div>
                                <div class="note-btn btn-cancel" id="speed-cancel" title="Cancel">
                                <svg viewBox="0 0 24 24"><path fill="#F44336" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                                </div>
                                </div>
                            `;

                        document.querySelectorAll('.speed-opt').forEach(btn => {
                            btn.addEventListener('click', (e) => {
                                moveSpeed = parseFloat(e.target.getAttribute('data-val'));
                                renderNoteUI();
                                saveStateToUndo();
                                updateToolHighlights();
                            });
                        });

                        document.getElementById('speed-confirm').addEventListener('click', () => {
                            let val = parseFloat(document.getElementById('speed-input').value);
                            if (isNaN(val) || val < 0.1 || val > moveInterval) {
                                val = moveSpeed;
                            }
                            moveSpeed = parseFloat(val.toFixed(1));
                            renderNoteUI();
                            saveStateToUndo();
                            updateToolHighlights();
                        });

                        document.getElementById('speed-cancel').addEventListener('click', () => {
                            renderNoteUI();
                        });
                    });
                }
            }
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

在前面改動的基礎上,當「固定」被選中時,退出「導出文本」狀態之後,「自動播放」按鈕會消失,取而代之的是「複製」按鈕。

當按複製時,它將複製所要導出的文本。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。

代码: 全选

Here is the updated modification for the `renderNoteUI` function. Replace the `} else {` block (the one generating the default UI buttons for deleting, range, etc.) with the following code. 

It conditionally replaces the Auto Play button with a Copy button when pinned, and dynamically generates the exact text string based on your currently saved export settings when clicked.

### Modify `renderNoteUI`

Replace the `} else {` block inside `renderNoteUI` with this:

```javascript
            } else {
                commentDiv.innerHTML = '';
                commentDiv.textContent = node.c || '';

                let extraBtns = '';
                let autoPlayOrCopyBtn = '';

                if (isExportPinned) {
                    autoPlayOrCopyBtn = `
                        <div class="note-btn" id="btn-pinned-copy" title="Copy">
                            <svg viewBox="0 0 24 24"><path fill="#fff" d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>
                        </div>
                    `;
                    extraBtns = `
                        <div class="note-btn" id="btn-pinned-paste" title="Paste">
                            <svg viewBox="0 0 24 24"><path fill="#fff" d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/></svg>
                        </div>
                        <div class="note-btn" id="btn-unpin" title="Unpin">
                            <svg viewBox="0 0 24 24"><path fill="#F44336" d="M16 12V4h1V2H7v2h1v8l-2 2v2h5.2v6h1.6v-6H18v-2l-2-2z"/></svg>
                        </div>
                    `;
                } else {
                    autoPlayOrCopyBtn = `
                        <div class="note-btn" id="btn-autoplay" title="Auto Play">
                    ${isAutoPlaying
                            ? '<svg viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>'
                            : '<svg viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>'
                    }
                        </div>
                    `;
                    extraBtns = `
                        <div class="note-btn" id="btn-interval" title="Move Interval" style="width: auto; padding: 0 4px; font-weight: bold;">
                    ${moveInterval}s
                        </div>
                        <div class="note-btn" id="btn-speed" title="Move Speed" style="width: auto; padding: 0 4px; font-weight: bold;">
                    ${moveSpeed}s
                        </div>
                    `;
                }

                btnDiv.innerHTML = `
                        <div class="ejceestextbtninner">
                        <div class="note-btn" id="btn-del-move" title="Delete Move">
                        <svg viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
                        </div>
                        <div class="note-btn" id="btn-range" title="Range Selection" style="${isRangeMode ? 'background-color:#4CAF50;' : ''}">
                        <svg viewBox="0 0 24 24"><path fill="${isRangeMode ? '#fff' : '#ccc'}" d="M7 6h4v2H9v8h2v2H7V6zm10 0h-4v2h2v8h-2v2h4V6z"/></svg>
                        </div>
                        ${autoPlayOrCopyBtn}
                        ${extraBtns}
                        </div>
                    `;

                document.getElementById('btn-del-move').addEventListener('click', deleteCurrentMoveAndAfter);

                document.getElementById('btn-range').addEventListener('click', () => {
                    isRangeMode = !isRangeMode;
                    if (!isRangeMode) {
                        rangeStart = null;
                        rangeEnd = null;
                        rangeClicks = 0;
                        clearRangeBorders();
                    } else {
                        rangeStart = null;
                        rangeEnd = null;
                        rangeClicks = 0;
                        clearRangeBorders();
                    }
                    renderNoteUI();
                });

                if (isExportPinned) {
                    document.getElementById('btn-pinned-copy').addEventListener('click', () => {
                        let textToCopy = "";
                        const fmt = lastExportFormat || 'cn'; 
                        const odd = formatOddStates[fmt] || 0;

                        if (fmt === 'cn') {
                            textToCopy = odd === 1 ? generateTextWithComment(false) : generateExportText(false);
                        } else if (fmt === 'en') {
                            textToCopy = odd === 1 ? generateTextWithComment(true) : generateExportText(true);
                        } else if (fmt === 'engine') {
                            let path = getGamePath();
                            let engineText = "position fen " + path.fen;
                            let currNode = path;
                            if (currNode && currNode.v && currNode.v.length > 0) {
                                engineText += " moves";
                            }
                            while (currNode && currNode.v && currNode.v.length > 0) {
                                currNode = currNode.v[0];
                                let dc = currNode.lastMove;
                                if (dc) {
                                    engineText += " " + String.fromCharCode(97 + dc.startX) + (9 - dc.startY) + String.fromCharCode(97 + dc.endX) + (9 - dc.endY);
                                }
                            }
                            if (odd === 1) {
                                const isRed = currentTurn === 'w';
                                const moves = getAllLegalMoves(isRed, tileMap);
                                const searchMovesStr = moves.map(m => String.fromCharCode(97 + m.startX) + (9 - m.startY) + String.fromCharCode(97 + m.endX) + (9 - m.endY)).join(' ');
                                textToCopy = engineText + (searchMovesStr ? "\ngo searchmoves " + searchMovesStr : "");
                            } else {
                                textToCopy = engineText;
                            }
                        } else if (fmt === 'url') {
                            textToCopy = generateUrlHash(odd === 1);
                        }

                        navigator.clipboard.writeText(textToCopy).catch(err => {
                            console.error('Copy failed', err);
                        });
                    });

                    document.getElementById('btn-pinned-paste').addEventListener('click', () => {
                        navigator.clipboard.readText().then(text => {
                            importExportedText(text);
                        }).catch(err => {
                            console.error('Paste failed', err);
                        });
                    });

                    document.getElementById('btn-unpin').addEventListener('click', () => {
                        isExportPinned = false;
                        renderNoteUI();
                    });

                } else {
                    document.getElementById('btn-autoplay').addEventListener('click', () => {
                        if (isAutoPlaying) {
                            stopAutoPlay();
                        } else {
                            startAutoPlay();
                        }
                    });

                    document.getElementById('btn-interval').addEventListener('click', () => {
                        if (isAutoPlaying) return;
                        btnDiv.innerHTML = `
                                <div class="ejceestextbtninner" style="justify-content: flex-start; gap: 4px;">
                                <input type="text" id="interval-input" style="width: 36px; font-size: 12px; background: #222; color: #fff; border: 1px solid #555; text-align: center; outline: none;" value="${moveInterval}" maxlength="3">
                                <div class="note-btn interval-opt" data-val="1">1</div>
                                <div class="note-btn interval-opt" data-val="2">2</div>
                                <div class="note-btn interval-opt" data-val="3">3</div>
                                <div class="note-btn btn-confirm" id="interval-confirm" title="Confirm">
                                <svg viewBox="0 0 24 24"><path fill="#4CAF50" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
                                </div>
                                <div class="note-btn btn-cancel" id="interval-cancel" title="Cancel">
                                <svg viewBox="0 0 24 24"><path fill="#F44336" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                                </div>
                                </div>
                                                       `;

                        document.querySelectorAll('.interval-opt').forEach(btn => {
                            btn.addEventListener('click', (e) => {
                                moveInterval = parseFloat(e.target.getAttribute('data-val'));
                                renderNoteUI();
                                saveStateToUndo();
                                updateToolHighlights();
                            });
                        });

                        document.getElementById('interval-confirm').addEventListener('click', () => {
                            let val = parseFloat(document.getElementById('interval-input').value);
                            if (isNaN(val) || val < 0.2 || val > 9) {
                                val = moveInterval;
                            }
                            moveInterval = parseFloat(val.toFixed(1));
                            renderNoteUI();
                            saveStateToUndo();
                            updateToolHighlights();
                        });

                        document.getElementById('interval-cancel').addEventListener('click', () => {
                            renderNoteUI();
                        });
                    });

                    document.getElementById('btn-speed').addEventListener('click', () => {
                        if (isAutoPlaying) return;
                        btnDiv.innerHTML = `
                                <div class="ejceestextbtninner" style="justify-content: flex-start; gap: 4px;">
                                <input type="text" id="speed-input" style="width: 36px; font-size: 12px; background: #222; color: #fff; border: 1px solid #555; text-align: center; outline: none;" value="${moveSpeed}" maxlength="3">
                                <div class="note-btn speed-opt" data-val="0.2">0.2</div>
                                <div class="note-btn speed-opt" data-val="0.4">0.4</div>
                                <div class="note-btn speed-opt" data-val="0.6">0.6</div>
                                <div class="note-btn btn-confirm" id="speed-confirm" title="Confirm">
                                <svg viewBox="0 0 24 24"><path fill="#4CAF50" d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
                                </div>
                                <div class="note-btn btn-cancel" id="speed-cancel" title="Cancel">
                                <svg viewBox="0 0 24 24"><path fill="#F44336" d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
                                </div>
                                </div>
                            `;

                        document.querySelectorAll('.speed-opt').forEach(btn => {
                            btn.addEventListener('click', (e) => {
                                moveSpeed = parseFloat(e.target.getAttribute('data-val'));
                                renderNoteUI();
                                saveStateToUndo();
                                updateToolHighlights();
                            });
                        });

                        document.getElementById('speed-confirm').addEventListener('click', () => {
                            let val = parseFloat(document.getElementById('speed-input').value);
                            if (isNaN(val) || val < 0.1 || val > moveInterval) {
                                val = moveSpeed;
                            }
                            moveSpeed = parseFloat(val.toFixed(1));
                            renderNoteUI();
                            saveStateToUndo();
                            updateToolHighlights();
                        });

                        document.getElementById('speed-cancel').addEventListener('click', () => {
                            renderNoteUI();
                        });
                    });
                }
            }
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

在前面的基礎上,當處於「導出文本」狀態時,第一次點擊engine,它將在原來的字符加上「\ngo\n」。

當點擊confirm時,如果字符的最前面是「go 」,則記下後方的字符。則下回第一次點擊engine,它將在原來的字符加上「\ngo 記下的字符\n」。

比如當我輸入「go movetime 12000」,點擊confirm,則下回我進入導出文本狀態時,第一次點擊engine,出現的字符是「...\ngo movetime 12000\n」。

第二次點擊engine,之前它是加上了「\ngo searchmoves ...」,現在首先要改成加上「\ngo searchmoves ...\n」,其次當前面的「go 」後字符有值,則加到go的後面。比如「\ngo movetime 12000 searchmoves ...\n」

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

gemini pro 用完了:

代码: 全选

Here are the necessary modifications to implement the 3-state engine formatting and the `go ` command memory feature. Please update the corresponding sections in your code.

### 1. CSS Update
Update your CSS to apply the orange background for both toggled states (`data-odd="1"` and `data-odd="2"`).

```css
    .exp-fmt-btn.active[data-odd="1"],
    .exp-fmt-btn.active[data-odd="2"] {
        background: orange;
    }
```

### 2. Global Variable
Add `savedGoCommand` near the top of your `<script>` where your other new global variables are.

```javascript
    // --- NEW GLOBAL VARIABLES ---
    let baseUrl = "";
    let formatOddStates = { cn: 0, en: 0, engine: 0, url: 0 };
    let isExportPinned = false;
    let savedGoCommand = ""; // NEW: Stores the saved 'go' arguments
    // ----------------------------
```

### 3. Update `renderExportTextUI`
Replace the `updateTextarea`, `formatBtns` loop, and the `exp-confirm` event listener inside `renderExportTextUI` with the following:

```javascript
            const updateTextarea = (fmt) => {
                if (fmt === 'cn') {
                    textarea.value = formatOddStates[fmt] === 1 ? cnTextWidthComment : cnText;
                } else if (fmt === 'en') {
                    textarea.value = formatOddStates[fmt] === 1 ? enTextWidthComment : enText;
                } else if (fmt === 'engine') {
                    let goCmdStr = savedGoCommand ? ` ${savedGoCommand}` : "";
                    if (formatOddStates[fmt] === 1) {
                        // State 1: Append '\ngo [saved_command]\n'
                        textarea.value = engineText + `\ngo${goCmdStr}\n`;
                    } else if (formatOddStates[fmt] === 2) {
                        // State 2: Append '\ngo [saved_command] searchmoves ...\n'
                        const isRed = currentTurn === 'w';
                        const moves = getAllLegalMoves(isRed, tileMap);
                        const searchMovesStr = moves.map(m => String.fromCharCode(97 + m.startX) + (9 - m.startY) + String.fromCharCode(97 + m.endX) + (9 - m.endY)).join(' ');
                        textarea.value = engineText + `\ngo${goCmdStr}` + (searchMovesStr ? ` searchmoves ${searchMovesStr}` : "") + "\n";
                    } else {
                        // State 0: Default
                        textarea.value = engineText;
                    }
                } else if (fmt === 'url') {
                    textarea.value = formatOddStates[fmt] === 1 ? urlTextToggled : urlText;
                }
            };

            formatBtns.forEach(btn => {
                btn.addEventListener('click', () => {
                    const wasActive = btn.classList.contains('active');
                    const fmt = btn.getAttribute('data-fmt');
                    lastExportFormat = fmt;

                    formatBtns.forEach(b => b.classList.remove('active'));
                    btn.classList.add('active');

                    if (wasActive) {
                        // Cycle states: engine goes 0 -> 1 -> 2 -> 0, others go 0 -> 1 -> 0
                        if (fmt === 'engine') {
                            formatOddStates[fmt] = (formatOddStates[fmt] + 1) % 3;
                        } else {
                            formatOddStates[fmt] = formatOddStates[fmt] === 1 ? 0 : 1;
                        }
                    }
                    btn.setAttribute('data-odd', formatOddStates[fmt]);

                    updateTextarea(fmt);

                    textarea.blur();
                    setTimeout(() => {
                        textarea.focus();
                        textarea.select();
                    }, 12);
                });
            });

            updateTextarea(lastExportFormat);
            setTimeout(() => textarea.select(), 10);
            
            // ... (Keep the btnDiv.innerHTML declaration exactly as it was) ...

            // ... (Keep exp-cancel as it was) ...

            document.getElementById('exp-confirm').addEventListener('click', () => {
                const text = textarea.value;
                // Capture the 'go' command arguments if it starts with 'go '
                if (text.startsWith('go ')) {
                    savedGoCommand = text.substring(3).trim();
                }
                isExportTextMode = false;
                importExportedText(text);
            });
```

### 4. Update `renderNoteUI` (Pinned Copy & Paste logic)
Find the `btn-pinned-copy` and `btn-pinned-paste` event listeners inside the `if (isExportPinned)` block of your `renderNoteUI` function and replace them to support the 3 states and capture the pasted `go ` string:

```javascript
                if (isExportPinned) {
                    document.getElementById('btn-pinned-copy').addEventListener('click', () => {
                        let textToCopy = "";
                        const fmt = lastExportFormat || 'cn'; 
                        const odd = formatOddStates[fmt] || 0;

                        if (fmt === 'cn') {
                            textToCopy = odd === 1 ? generateTextWithComment(false) : generateExportText(false);
                        } else if (fmt === 'en') {
                            textToCopy = odd === 1 ? generateTextWithComment(true) : generateExportText(true);
                        } else if (fmt === 'engine') {
                            let path = getGamePath();
                            let engineText = "position fen " + path.fen;
                            let currNode = path;
                            if (currNode && currNode.v && currNode.v.length > 0) {
                                engineText += " moves";
                            }
                            while (currNode && currNode.v && currNode.v.length > 0) {
                                currNode = currNode.v[0];
                                let dc = currNode.lastMove;
                                if (dc) {
                                    engineText += " " + String.fromCharCode(97 + dc.startX) + (9 - dc.startY) + String.fromCharCode(97 + dc.endX) + (9 - dc.endY);
                                }
                            }
                            
                            let goCmdStr = savedGoCommand ? ` ${savedGoCommand}` : "";
                            if (odd === 1) {
                                textToCopy = engineText + `\ngo${goCmdStr}\n`;
                            } else if (odd === 2) {
                                const isRed = currentTurn === 'w';
                                const moves = getAllLegalMoves(isRed, tileMap);
                                const searchMovesStr = moves.map(m => String.fromCharCode(97 + m.startX) + (9 - m.startY) + String.fromCharCode(97 + m.endX) + (9 - m.endY)).join(' ');
                                textToCopy = engineText + `\ngo${goCmdStr}` + (searchMovesStr ? ` searchmoves ${searchMovesStr}` : "") + "\n";
                            } else {
                                textToCopy = engineText;
                            }
                        } else if (fmt === 'url') {
                            textToCopy = generateUrlHash(odd === 1);
                        }

                        navigator.clipboard.writeText(textToCopy).catch(err => {
                            console.error('Copy failed', err);
                        });
                    });

                    document.getElementById('btn-pinned-paste').addEventListener('click', () => {
                        navigator.clipboard.readText().then(text => {
                            // Capture the 'go' command arguments if it starts with 'go '
                            if (text.startsWith('go ')) {
                                savedGoCommand = text.substring(3).trim();
                            }
                            importExportedText(text);
                        }).catch(err => {
                            console.error('Paste failed', err);
                        });
                    });
```

### 5. Update Keyboard Shortcuts (Ctrl + Enter)
In the `document.addEventListener('keydown', (e) => {` section, locate the `if (isExportTextMode)` block under `e.ctrlKey && e.key === 'Enter'` and modify it to also capture the string:

```javascript
                    // 2. Check if in Export Text Mode
                    if (isExportTextMode) {
                        const confirmBtn = document.getElementById('exp-confirm');
                        if (confirmBtn) {
                            const textarea = document.getElementById('export-textarea');
                            const text = textarea.value;
                            // Capture the 'go' command arguments if it starts with 'go '
                            if (text.startsWith('go ')) {
                                savedGoCommand = text.substring(3).trim();
                            }
                            isExportTextMode = false;
                            importExportedText(text);
                            return;
                        }
                    }
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

還要再加上當點擊ctrl+c,ctrl+v時,也要有相應效果。點擊複製或粘貼時,範圍選擇要取消。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

file:///不應變成null。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

不知道為何評論會變成兩倍。
附件
ejcees_json_20260406113612評論變為兩倍.txt
(5.23 KiB) 尚未被下载
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4982
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 173 次
被圈友点赞: 202 次
联系:

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

帖子 ejsoon »

附件
ejcees20260405importFenRotate99977748.7z
(45.58 KiB) 尚未被下载
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

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