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

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

問:undo和redo存在問題。

代码: 全选

            // Deep clone the entire game tree for undo/redo
            function cloneGameState() {
                return {
                    historyFEN: JSON.parse(JSON.stringify(historyFEN)),
                    currentBranch: [...currentBranch],
                    currentStepIndex: currentStepIndex
                };
            }

            function saveStateToUndo() {
                undoStack.push(cloneGameState());
                if (undoStack.length > 50) undoStack.shift(); // limit history size
                redoStack = []; // clear redo on new action
            }

            function restoreState(state) {
                historyFEN = state.historyFEN;
                currentBranch = state.currentBranch;
                currentStepIndex = state.currentStepIndex;
                renderRecordUI();
                renderNoteUI();
                jumpToStep(currentStepIndex);
            }

            function undo() {
                if (undoStack.length === 1) return;
                const previous = undoStack.pop();
                redoStack.push(previous);
                restoreState(undoStack[undoStack.length - 1]);
            }

            function redo() {
                if (redoStack.length === 0) return;
                const next = redoStack.pop();
                undoStack.push(next);
                restoreState(next);
            }

在以上代碼中,如果我走到第二步,之後走一下undo和redo,然後往後走到第四步或更多,當我undo回到第二步時,historyFEN跟當前最後一步是一樣的。

懷疑是深複製存在問題。

請查找問題原因,並說出如何修複。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

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

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

帖子 ejsoon »

上面的按鈕:

代码: 全选

<div class="ejceestool">
                <div class="tool-btn" id="tool-new" title="New">
                </div>
                <div class="tool-btn" id="tool-open" title="Open">
                </div>
                <div class="tool-btn" id="tool-edit" title="Edit">
                </div>
                <div class="tool-btn" id="tool-save" title="Save">
                </div>
                <div class="tool-btn" id="tool-undo" title="Undo">
                </div>
                <div class="tool-btn" id="tool-redo" title="Redo">
                </div>
                <div class="tool-btn" id="tool-rotate" title="Rotate">
                </div>
                <div class="tool-btn" id="tool-flip" title="Flip">
                </div>
                <div class="tool-btn" id="tool-exp-txt" title="Export Text">
                </div>
                <div class="tool-btn" id="tool-exp-svg" title="Export SVG">
                </div>
            </div>
下面的按鈕:

代码: 全选

                            <div class="note-btn" id="btn-del-move" title="Delete Move">
                            </div>
                            <div class="note-btn" id="btn-range" title="Range Selection">
                            </div>
                            <div class="note-btn" id="btn-autoplay" title="Auto Play">
                            </div>
                            <div class="note-btn" id="btn-speed" title="Move Speed" style="width: auto; padding: 0 4px; font-weight: bold;">
                                0.36s
                            </div>
                        
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

前面的html結構:

代码: 全选

            <div class="ejceesoutput">Click on the SVG area to get coordinates.</div>
            <div class="ejceesstep">
                <div class="ejceesstepminus">-</div>
                <input type="range" class="ejceesstepdrop" min="0" max="0" value="0">
                <div class="ejceesstepplus">+</div>
            </div>
下面的結構:

代码: 全选

<div class="ejceestext">
                <div class="ejceesrecord">
                    <div class="ejceesrcdstart" id="record-start">棋局開始,紅方先行</div>

<div class="ejceesrcdstep" id="step-record-1" data-index="1"><span class="ejceesrcdstepcontent">炮二平五</span></div>

                </div>
                <div class="ejceesnote">
                    <div class="ejceescomment"></div>
                    <div class="ejceestextbtn"></div>
                </div>
            </div>
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

改進:

一,為#tool-rotate和#tool-flip增加點擊功能,點擊之後高亮,再點擊取消高亮。

#tool-rotate使所有棋子位置中心旋轉,#tool-flip為所有棋子位置左右對稱。

這兩個功能都不會影響.ejceesrecord的文字描述即棋譜,也不會記錄到historyFEN中,亦不記錄到undo、redo中。

當點擊ejceesstep內的按鍵時,棋子位置也會因旋轉或對稱而發生變化。

二,tool-btn處於非高亮狀態時,把顏色調得更暗。

tool-new:當有至少一步棋,或初始狀態與INITIAL_FEN不同時高亮。
tool-open:一直高亮。
tool-edit:當處於非編輯狀態時高亮。
tool-save:跟tool-new相同。
tool-undo:當undoStack.length>1時高亮。
tool-redo:當redoStack.length>0時高亮。
tool-rotate:當處於rotate狀態時高亮。
tool-flip:當處於flip狀態時高亮。
tool-exp-txt:一直高亮。
tool-exp-svg:一直高亮。

建立一個切換按鍵高亮的函式,在事件觸發的時候使用。

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

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

帖子 ejsoon »

grok:

代码: 全选

<!-- ONLY THE MODIFIED PARTS BELOW (all code/comments in English) -->
<!-- 1. CSS: Update .tool-btn rules for darker non-highlight state + explicit .enable support -->

        .tool-btn {
            width: 32px;
            height: 32px;
            border-radius: 50%;
            background-color: #333; /* darker default (non-highlighted state) */
            color: #aaa;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 11px;
            cursor: pointer;
            user-select: none;
        }

        .tool-btn.enable {
            background-color: #555;
            color: white;
        }

        .tool-btn.enable svg {
            fill: #4CAF50; /* Green for active/enabled */
        }

        .tool-btn:hover svg {
            fill: #fff;
        }

<!-- 2. JavaScript: Add these variables right after the existing "let" declarations (after line with isAutoPlaying) -->

        // View mode flags - rotate/flip only affect visual piece positions
        // They do NOT modify .ejceesrecord text, historyFEN, undoStack, or redoStack
        let isRotateEnabled = false;
        let isFlipEnabled = false;

<!-- 3. JavaScript: Add these helper functions just before the comment "// --- Boot the App ---" -->

        /**
         * Applies current rotate and/or flip transforms to piece positions only.
         * Called automatically after every loadFEN so step navigation also reflects the mode.
         * Updates DOM transforms, tileMap, and piecePos. Purely visual - no history impact.
         */
        function applyCurrentTransforms() {
            if (!isRotateEnabled && !isFlipEnabled) {
                return;
            }
            if (isRotateEnabled) {
                rotateBoard180();
            }
            if (isFlipEnabled) {
                flipBoardHorizontal();
            }
        }

        /**
         * Rotate all pieces 180 degrees around board center (newX = 8 - oldX, newY = 9 - oldY).
         * Updates DOM, tileMap, and piecePos. Does NOT touch historyFEN, record, undo, or redo.
         */
        function rotateBoard180() {
            const newTileMap = new Map();
            const newPiecePos = new Map();
            for (const [posStr, pieceId] of tileMap.entries()) {
                const [x, y] = posStr.split(',').map(Number);
                const newX = 8 - x;
                const newY = 9 - y;
                const newPosStr = `${newX},${newY}`;
                newTileMap.set(newPosStr, pieceId);
                newPiecePos.set(pieceId, { x: newX, y: newY });
                const el = document.getElementById(pieceId);
                if (el) {
                    const px = newX * 48 + 24;
                    const py = newY * 48 + 24;
                    el.setAttribute('transform', `translate(${px}, ${py})`);
                }
            }
            tileMap.clear();
            piecePos.clear();
            for (const [k, v] of newTileMap.entries()) tileMap.set(k, v);
            for (const [k, v] of newPiecePos.entries()) piecePos.set(k, v);
        }

        /**
         * Flip all pieces left-right (newX = 8 - oldX, newY = oldY).
         * Updates DOM, tileMap, and piecePos. Does NOT touch historyFEN, record, undo, or redo.
         */
        function flipBoardHorizontal() {
            const newTileMap = new Map();
            const newPiecePos = new Map();
            for (const [posStr, pieceId] of tileMap.entries()) {
                const [x, y] = posStr.split(',').map(Number);
                const newX = 8 - x;
                const newY = y;
                const newPosStr = `${newX},${newY}`;
                newTileMap.set(newPosStr, pieceId);
                newPiecePos.set(pieceId, { x: newX, y: newY });
                const el = document.getElementById(pieceId);
                if (el) {
                    const px = newX * 48 + 24;
                    const py = newY * 48 + 24;
                    el.setAttribute('transform', `translate(${px}, ${py})`);
                }
            }
            tileMap.clear();
            piecePos.clear();
            for (const [k, v] of newTileMap.entries()) tileMap.set(k, v);
            for (const [k, v] of newPiecePos.entries()) piecePos.set(k, v);
        }

        /**
         * Central function to toggle .enable class on all tool-btn elements based on current state.
         * Called on every relevant event (new, open, edit, undo, redo, step change, etc.).
         */
        function updateToolHighlights() {
            const isModified = currentStepIndex > 0 || historyFEN.fen !== INITIAL_FEN;
            const highlights = {
                'tool-new': isModified,
                'tool-open': true,
                'tool-edit': !isEditingComment,
                'tool-save': isModified,
                'tool-undo': undoStack.length > 1,
                'tool-redo': redoStack.length > 0,
                'tool-rotate': isRotateEnabled,
                'tool-flip': isFlipEnabled,
                'tool-exp-txt': true,
                'tool-exp-svg': true
            };
            for (const [id, shouldEnable] of Object.entries(highlights)) {
                const btn = document.getElementById(id);
                if (btn) {
                    if (shouldEnable) {
                        btn.classList.add('enable');
                    } else {
                        btn.classList.remove('enable');
                    }
                }
            }
        }

<!-- 4. JavaScript: Modify loadFEN - add call to applyCurrentTransforms at the very end (just before the closing } of loadFEN) -->

                // Apply rotate/flip transforms if enabled (purely visual; does not affect record, historyFEN, undo or redo)
                applyCurrentTransforms();
            }

<!-- 5. JavaScript: Add updateToolHighlights() at the end of renderRecordUI() and renderNoteUI() -->

            // (inside renderRecordUI, after highlightActiveStep)
            updateToolHighlights();

            // (inside renderNoteUI, after the if/else block that sets btnDiv)
            updateToolHighlights();

<!-- 6. JavaScript: Add the rotate and flip click listeners right after the existing tool listener block (after the tool-redo listener) -->

            // New: Rotate tool - click to toggle 180° rotation of all piece positions (highlight when active)
            // Clicking step controls (-, +, slider) will also reflect the rotation because loadFEN re-applies it.
            // Does NOT affect .ejceesrecord text, historyFEN, undoStack or redoStack.
            document.getElementById('tool-rotate').addEventListener('click', () => {
                isRotateEnabled = !isRotateEnabled;
                const currentNode = getNodeAtStep(currentStepIndex);
                if (currentNode) {
                    loadFEN(currentNode.fen);
                    applyLastMoveVisuals(currentNode.lastMove);
                } else {
                    applyCurrentTransforms();
                }
                updateToolHighlights();
            });

            // New: Flip tool - click to toggle left-right symmetry of all piece positions (highlight when active)
            // Clicking step controls (-, +, slider) will also reflect the flip because loadFEN re-applies it.
            // Does NOT affect .ejceesrecord text, historyFEN, undoStack or redoStack.
            document.getElementById('tool-flip').addEventListener('click', () => {
                isFlipEnabled = !isFlipEnabled;
                const currentNode = getNodeAtStep(currentStepIndex);
                if (currentNode) {
                    loadFEN(currentNode.fen);
                    applyLastMoveVisuals(currentNode.lastMove);
                } else {
                    applyCurrentTransforms();
                }
                updateToolHighlights();
            });

<!-- 7. JavaScript: Add initial call at the very end of DOMContentLoaded (right before the closing }); of the big script) -->

            // Initial highlight update after boot
            updateToolHighlights();
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

新問題:刪分支後盤面沒更新。

應補上loadFEN()。
上次由 ejsoon 在 2026年 3月 10日 23:26,总共编辑 1 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

出現問題:

棋譜不應因#tool-rotate和#tool-flip而發生變化。

例如:一個棋子從1,9移至2,7,棋譜記為N8+7(馬八進七)。#tool-rotate旋轉之後,它的坐標將變為從7,0移至6,2,但是棋譜仍應為N8+7(馬八進七)。

請修復。

代码: 全选

<!-- ONLY THE MODIFIED PARTS BELOW (all code/comments in English) -->

<!-- 1. CSS: unchanged from previous improvement (darker non-highlight + .enable support) -->

<!-- 2. JavaScript: Keep the two flag variables (after existing let declarations) -->

        // View mode flags - rotate/flip are PURELY VISUAL
        // They NEVER change internal coordinates, tileMap, piecePos, FEN, lastMove,
        // getMoveNotation(), historyFEN, .ejceesrecord text, undoStack or redoStack
        let isRotateEnabled = false;
        let isFlipEnabled = false;

<!-- 3. JavaScript: REPLACE the old three functions (applyCurrentTransforms + rotateBoard180 + flipBoardHorizontal)
     with this single new function (place it where the old functions were, just before "// --- Boot the App ---") -->

        /**
         * Applies rotate 180° and/or horizontal flip as a single SVG group transform on .etdrop.
         * This is 100% visual only. Mouse clicks, move validation, notation generation,
         * historyFEN, record UI text and undo/redo remain completely unaffected.
         * The transform is applied to the existing <g class="etdrop"> so the whole board
         * (grid + pieces + start dot) appears rotated/flipped while logical coordinates
         * (used by getMoveNotation, lastMove, etc.) stay original.
         */
        function applyVisualTransform() {
            const etdrop = document.querySelector('.etdrop');
            if (!etdrop) return;

            let transformStr = '';
            if (isRotateEnabled) {
                transformStr += 'rotate(180 216 240) ';
            }
            if (isFlipEnabled) {
                transformStr += 'translate(432,0) scale(-1,1) ';
            }
            etdrop.setAttribute('transform', transformStr.trim() || 'translate(0,0) scale(1,1)');
        }

<!-- 4. JavaScript: Remove the old applyCurrentTransforms() call from loadFEN
     (delete the line that was added in the previous improvement) -->

                // (the following line is REMOVED - no longer needed)
                // applyCurrentTransforms();

<!-- 5. JavaScript: REPLACE the two tool listener blocks (the old rotate/flip listeners)
     with these new simple listeners (place them right after the existing tool-redo listener) -->

            // New: Rotate tool - toggles 180° visual rotation only (highlight when active)
            // Chess record text, FEN, move notation and history remain 100% unchanged.
            // Clicking step controls (-, +, slider) instantly reflects the current visual mode
            // because the transform is always active on .etdrop.
            document.getElementById('tool-rotate').addEventListener('click', () => {
                isRotateEnabled = !isRotateEnabled;
                applyVisualTransform();
                updateToolHighlights();
            });

            // New: Flip tool - toggles left-right visual symmetry only (highlight when active)
            // Chess record text, FEN, move notation and history remain 100% unchanged.
            document.getElementById('tool-flip').addEventListener('click', () => {
                isFlipEnabled = !isFlipEnabled;
                applyVisualTransform();
                updateToolHighlights();
            });

<!-- 6. JavaScript: Add initial call at the very end of DOMContentLoaded
     (right before the closing }); of the big script block) -->

            // Apply initial visual transform (defaults to identity) and update highlights
            applyVisualTransform();
            updateToolHighlights();
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4647
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 201 次
联系:

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

帖子 ejsoon »

出現問題:

棋譜不應因#tool-rotate和#tool-flip而發生變化。

例如:一個棋子從1,9移至2,7,棋譜記為N8+7(馬八進七)。#tool-rotate旋轉之後,它的坐標將變為從7,0移至6,2,但是棋譜仍應為N8+7(馬八進七)。

不能用transform的方式對svg旋轉或鏡像,應改變棋子的放置邏輯。

請修復。

代码: 全选

<!-- ONLY THE MODIFIED PARTS BELOW (all code/comments in English) -->
<!-- This completely replaces the previous rotate/flip implementation. -->
<!-- We now keep ALL game data (tileMap, piecePos, FEN, historyFEN, moves) in STANDARD LOGICAL coordinates. -->
<!-- Only the visual placement (translate) of each piece uses the current view mode. -->
<!-- Click coordinates are inverse-mapped back to logical before any game logic or notation generation. -->
<!-- This guarantees that the record text (棋譜) and all stored moves NEVER change due to rotate/flip. -->
<!-- Notation is always generated from logical coordinates (e.g. N8+7 stays N8+7). -->
<!-- Piece graphics stay upright (no group transform on SVG). -->
<!-- Step navigation (-, +, slider) automatically shows the rotated/flipped view. -->

<!-- 1. CSS: No change needed (previous darker non-highlight state is kept) -->

<!-- 2. JavaScript: Replace the old rotate/flip variables and helpers with the new logical/visual system -->
<!-- Put this right after: let isAutoPlaying = false; -->

        // View mode flags - rotate/flip only affect visual placement.
        // All game data, FEN, historyFEN, move notation, undo/redo remain in standard logical coordinates.
        let isRotateEnabled = false;
        let isFlipEnabled = false;

<!-- 3. JavaScript: Add these NEW helper functions just before the comment "// --- Boot the App ---" -->

        /**
         * Convert logical coordinates (standard FEN / history) to visual screen coordinates
         * according to current rotate/flip mode.
         * @returns {{x: number, y: number}}
         */
        function getVisualCoords(logX, logY) {
            let vX = logX;
            let vY = logY;
            if (isFlipEnabled) vX = 8 - vX;
            if (isRotateEnabled) {
                vX = 8 - vX;
                vY = 9 - vY;
            }
            return { x: vX, y: vY };
        }

        /**
         * Convert visual screen coordinates back to logical coordinates.
         * Used for click detection so all game logic and notation stay in standard coordinates.
         * @returns {{x: number, y: number}}
         */
        function getLogicalCoords(visX, visY) {
            let lX = visX;
            let lY = visY;
            if (isRotateEnabled) {
                lX = 8 - lX;
                lY = 9 - lY;
            }
            if (isFlipEnabled) lX = 8 - lX;
            return { x: lX, y: lY };
        }

        /**
         * Re-apply visual positions to all pieces without touching any game data.
         * Called when toggling rotate/flip or after step navigation.
         */
        function reapplyVisualPositions() {
            for (const [logPosStr, pieceId] of tileMap.entries()) {
                const [logX, logY] = logPosStr.split(',').map(Number);
                const vis = getVisualCoords(logX, logY);
                const px = vis.x * 48 + 24;
                const py = vis.y * 48 + 24;
                const el = document.getElementById(pieceId);
                if (el) {
                    el.setAttribute('transform', `translate(${px}, ${py})`);
                }
            }
            // Refresh the "from" dot for the current move
            const currentNode = getNodeAtStep(currentStepIndex);
            applyLastMoveVisuals(currentNode ? currentNode.lastMove : null);
        }

<!-- 4. JavaScript: Modify loadFEN - change piece placement to use visual coordinates (logical data unchanged) -->
<!-- Replace the placement block inside the FEN parsing loop (the part that sets px/py and appends useEl) -->

                            // Logical coords from FEN stay standard (for notation, history, validation)
                            const vis = getVisualCoords(x, y);
                            const px = vis.x * 48 + 24;
                            const py = vis.y * 48 + 24;

                            useEl.setAttribute('transform', `translate(${px}, ${py})`);

                            etboard.appendChild(useEl);
                            tileMap.set(`${x},${y}`, pieceId);   // key = logical
                            piecePos.set(pieceId, { x, y });     // logical
                            x++;

<!-- 5. JavaScript: Modify the click handler - map visual click back to logical coordinates -->
<!-- Replace the grid calculation part in svgElement.addEventListener('click' ... -->

                const gridX_vis = Math.floor(clickX / 48);
                const gridY_vis = Math.floor(clickY / 48);
                const logicalPt = getLogicalCoords(gridX_vis, gridY_vis);
                const gridX = logicalPt.x;
                const gridY = logicalPt.y;

<!-- 6. JavaScript: Modify movePieceWithAnimation - use visual start/end for animation but keep logical data -->
<!-- Replace the entire movePieceWithAnimation function -->

            function movePieceWithAnimation(pieceId, targetLogicalX, targetLogicalY, eatenId) {
                if (isAnimating) return;
                isAnimating = true;

                const pieceEl = document.getElementById(pieceId);
                etdrop.appendChild(pieceEl);

                const startLogical = piecePos.get(pieceId);
                const startVis = getVisualCoords(startLogical.x, startLogical.y);
                const endVis = getVisualCoords(targetLogicalX, targetLogicalY);

                const startXpx = startVis.x * 48 + 24;
                const startYpx = startVis.y * 48 + 24;
                const endXpx = endVis.x * 48 + 24;
                const endYpx = endVis.y * 48 + 24;

                let startTime = null;
                const duration = 360;

                function animate(time) {
                    if (!startTime) startTime = time;
                    let progress = (time - startTime) / duration;
                    if (progress > 1) progress = 1;

                    const currX = startXpx + (endXpx - startXpx) * progress;
                    const currY = startYpx + (endYpx - startYpx) * progress;
                    pieceEl.setAttribute('transform', `translate(${currX}, ${currY})`);

                    if (progress < 1) {
                        requestAnimationFrame(animate);
                    } else {
                        etboard.appendChild(pieceEl);

                        if (eatenId) {
                            const eatenEl = document.getElementById(eatenId);
                            const href = eatenEl.getAttribute('href') || eatenEl.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
                            if (/^#(tile([2-9]|1[0-5]))$/.test(href)) {
                                eatenEl.setAttribute('rm', '1');
                                eatenEl.setAttribute('display', 'none');
                                piecePos.delete(eatenId);
                            }
                        }

                        // Update logical data only
                        const moveText = getMoveNotation(pieceId, startLogical.x, startLogical.y, targetLogicalX, targetLogicalY, eatenId);
                        const moveData = {
                            startX: startLogical.x,
                            startY: startLogical.y,
                            endX: targetLogicalX,
                            endY: targetLogicalY
                        };

                        tileMap.delete(`${startLogical.x},${startLogical.y}`);
                        tileMap.set(`${targetLogicalX},${targetLogicalY}`, pieceId);
                        piecePos.set(pieceId, { x: targetLogicalX, y: targetLogicalY });

                        // Final visual position
                        pieceEl.setAttribute('transform', `translate(${endXpx}, ${endYpx})`);

                        setPickup(pieceId, false);
                        isAnimating = false;

                        currentTurn = currentTurn === 'w' ? 'b' : 'w';
                        pushHistory(moveText, moveData);
                        applyLastMoveVisuals(moveData);
                    }
                }

                requestAnimationFrame(animate);
            }

<!-- 7. JavaScript: Modify applyLastMoveVisuals - dot uses visual coordinates -->
<!-- Replace the dot positioning part -->

                if (dot) {
                    if (!lastMove) {
                        dot.setAttribute('cx', initialDotCx);
                        dot.setAttribute('cy', initialDotCy);
                    } else {
                        const visStart = getVisualCoords(lastMove.startX, lastMove.startY);
                        dot.setAttribute('cx', visStart.x * 48 + 24);
                        dot.setAttribute('cy', visStart.y * 48 + 24);
                    }
                }

<!-- 8. JavaScript: Remove the old applyCurrentTransforms, rotateBoard180, flipBoardHorizontal functions entirely -->
<!-- (They are no longer needed - delete the whole block that was added in the previous version) -->

<!-- 9. JavaScript: Replace the tool-rotate and tool-flip click listeners (right after the existing tool-redo listener) -->

            // Rotate tool - toggles 180° view. Only changes visual placement; notation, historyFEN, record text unchanged.
            document.getElementById('tool-rotate').addEventListener('click', () => {
                isRotateEnabled = !isRotateEnabled;
                reapplyVisualPositions();
                updateToolHighlights();
            });

            // Flip tool - toggles horizontal mirror. Only changes visual placement; notation, historyFEN, record text unchanged.
            document.getElementById('tool-flip').addEventListener('click', () => {
                isFlipEnabled = !isFlipEnabled;
                reapplyVisualPositions();
                updateToolHighlights();
            });

<!-- 10. JavaScript: Remove the old applyCurrentTransforms() call that was inside loadFEN (no longer needed) -->

<!-- 11. JavaScript: Initial call remains the same (updateToolHighlights at the end of DOMContentLoaded) -->
<!-- No other changes required. The record text, getMoveNotation, FEN saving/loading, undo/redo, and all validation stay exactly as before. -->

<!-- End of modifications. This fixes the issue: chess record (e.g. N8+7) never changes due to rotate/flip, even after step navigation or new moves. -->
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

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