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

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4643
注册时间: 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
圈圈精英
圈圈精英
帖子: 4643
注册时间: 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
圈圈精英
圈圈精英
帖子: 4643
注册时间: 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
圈圈精英
圈圈精英
帖子: 4643
注册时间: 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/
弈趣極光:享受思維樂趣
回复

在线用户

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