將製作ejcees(中國象棋打譜程式)
Re: 將製作ejcees(中國象棋打譜程式)
一個小問題:如果打開的json輪到黑方,則第一行要改為「特定局面,輪到黑方」。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
// 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/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
https://ejsoon.vip/wp-content/uploads/2 ... ndo98.html
undo和redo的問題已解決。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
<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/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
<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/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
一,為#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/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
<!-- 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/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: 没有注册用户 和 2 访客
