分页: 16 / 34
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 17:55
由 ejsoon
加不進:
代码: 全选
h0h6 b9c7 b0c2 c6c5 e3e4 b7b6 h6h4 c9e7 g2e3 b6c6 g3g4 a9b9 g4g5 h7i7 h4h9 g7h9 a0b0 d9e8 b2b7 e7g5 b7i7 h9i7
position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w 1 - 0 1 moves h2e2 h9g7 h0g2 i9h9 i0h0 g6g5
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:03
由 ejsoon
下面這段代碼: const fenMatch = text.match(/(?:position fen )?([a-zA-Z0-9/]+ [wb](?: -| \d+)*)/);
是為了匹配中國象棋局面的字符串,如:
「position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w 1 - 0 1」,或者「rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w 1 - 0 1」,但是它不夠精確。現在改進為:必須包含九個「/」,前面一串含有/的字母只包含「rnbakcpRNBAKCP」,後面一個只能是「 w」或「 b」。
不用管position fen或其它可能的字符,只需要用空格分隔之後去檢查。
寫出改進的結果。
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:08
由 ejsoon
代码: 全选
const text = "position fen rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w 1 - 0 1";
// 1. 如果只是想提取核心的局面和走子方
const match = text.match(/(?:[rnbakcpRNBAKCP1-9]+\/){9}[rnbakcpRNBAKCP1-9]+ [wb]/);
if (match) {
console.log("匹配到的局勢:", match[0]);
}
// 2. 如果要檢查一個字串是否為合法的象棋 FEN (嚴格模式)
function isValidXiangqiFen(str) {
// 這裡加上了結尾的後續參數匹配 (步數等,可選)
const strictRegex = /^(?:[rnbakcpRNBAKCP1-9]+\/){9}[rnbakcpRNBAKCP1-9]+ [wb](?: -| \d+)*$/;
return strictRegex.test(str.trim());
}
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:22
由 ejsoon
代码: 全选
const fenRegex = /\b(?:[rnbakcpRNBAKCP1-9]{1,9}\/){9}[rnbakcpRNBAKCP1-9]{1,9} [wb](?:(?: -| \d+){4})?\b/;
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:36
由 ejsoon
代码: 全选
movesStr = movesStr.replace(/position fen /, '').replace(fenRegex, '').replace(/ moves /, '');
如何改進這段代碼?
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:39
由 ejsoon
代码: 全选
// 假設 fenRegex 已經定義好了
const cleanRegex = new RegExp(`position fen | moves |${fenRegex.source}`, 'g');
movesStr = movesStr.replace(cleanRegex, '').trim();
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 25日 21:48
由 ejsoon
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 00:45
由 ejsoon
評論顯示不全:
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 00:56
由 ejsoon
播放停止時應去掉「Auto-playing: 」。
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 08:41
由 ejsoon
ejcees20260326comment99973
去掉comment錯誤的css,提示文字加上了step/total:
https://ejsoon.vip/wp-content/uploads/2 ... 99973.html
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 08:54
由 ejsoon
改進:
增加「home,end,pgup,pgdn,del,insert,up,down,left,right」按鍵功能。
home:回到棋局起始位置。
end:回到棋局結束位置。
pgup:往前五個回合。
pgdn:往後五個回合。
del:刪除後續走法(等同於btn-del-move)。
insert:導出/導入文本(等同於tool-exp-txt)。
up:往前一回合。
down:往後一回合。
left:往前一步。
right:往後一步。
所有按鍵功能在「自動播放、編輯局面、導出文本、範圍選取、改動移動及間隔時間」狀態下都將失效。
不過insert和del可以在「選圍選取」狀態下使用。
只需給出所要修改的地方,所有的代碼和注釋都應使用英文。
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 08:59
由 ejsoon
對gemini pro來說非常簡單:
代码: 全选
// Add keyboard support at the end of DOMContentLoaded
document.addEventListener('keydown', (e) => {
// Check if user is currently changing move speed or interval
const isEditingSettings = document.getElementById('interval-input') !== null || document.getElementById('speed-input') !== null;
// Determine if the key pressed is allowed during Range Selection mode
const allowedInRangeMode = e.key === 'Insert' || e.key === 'Delete';
// Global block condition for shortcuts based on the application's current state
if (isExportTextMode || isAutoPlaying || isEditingComment || isEditingSettings || (isRangeMode && !allowedInRangeMode)) {
return;
}
// Undo / Redo logic (works in both Normal and Edit modes)
if (e.ctrlKey && e.key === 'z') {
e.preventDefault();
isEditMode ? undoEdit() : undo();
return;
}
if (e.ctrlKey && e.key === 'y') {
e.preventDefault();
isEditMode ? redoEdit() : redo();
return;
}
// All subsequent navigation and action shortcuts are disabled in Edit Mode
if (isEditMode) return;
// Get max step bounds from the slider for navigation limits
const maxStep = parseInt(stepSlider.max, 10) || 0;
switch (e.key) {
case 'Home':
e.preventDefault();
jumpToStep(0);
saveStateToUndo();
updateToolHighlights();
break;
case 'End':
e.preventDefault();
jumpToStep(maxStep);
saveStateToUndo();
updateToolHighlights();
break;
case 'PageUp':
e.preventDefault();
// Move backward 5 turns (10 steps/ply)
jumpToStep(Math.max(0, currentStepIndex - 10));
saveStateToUndo();
updateToolHighlights();
break;
case 'PageDown':
e.preventDefault();
// Move forward 5 turns (10 steps/ply)
jumpToStep(Math.min(maxStep, currentStepIndex + 10));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowUp':
case 'Up': // Handles legacy Edge/IE names
e.preventDefault();
// Move backward 1 turn (2 steps/ply)
jumpToStep(Math.max(0, currentStepIndex - 2));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowDown':
case 'Down':
e.preventDefault();
// Move forward 1 turn (2 steps/ply)
jumpToStep(Math.min(maxStep, currentStepIndex + 2));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowLeft':
case 'Left':
e.preventDefault();
// Move backward 1 step
jumpToStep(Math.max(0, currentStepIndex - 1));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowRight':
case 'Right':
e.preventDefault();
// Move forward 1 step
jumpToStep(Math.min(maxStep, currentStepIndex + 1));
saveStateToUndo();
updateToolHighlights();
break;
case 'Delete':
case 'Del':
e.preventDefault();
// Triggers the deletion of the current move and the branch after it
deleteCurrentMoveAndAfter();
break;
case 'Insert':
case 'Ins':
e.preventDefault();
// Triggers the text export/import tool
document.getElementById('tool-exp-txt').click();
break;
}
});
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 09:13
由 ejsoon
ejcees20260326autoplay99974
去掉提示文字中的坐標,因為沒有太大意義。增加鍵盤事件,上下左右翻頁home,end,del,insert:
https://ejsoon.vip/wp-content/uploads/2 ... 99974.html
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 09:47
由 ejsoon
增加功能:
在「編輯局面、導出文本、範圍選取、改動移動及間隔時間、導出svg」狀態時,按下esc,則退出該狀態。
ctrl+left:回到上一個分支所在。
ctrl+right:回到下一個分支所在。
ctrl+up:前面最近一個分支,切換到上一個分支。
ctrl+up:前面最近一個分支,切換到下一個分支。
只需給出所要修改的地方,所有的代碼和注釋都應使用英文。
Re: 將製作ejcees(中國象棋打譜程式)
发表于 : 2026年 3月 26日 09:49
由 ejsoon
gemini pro
代码: 全选
// Add keyboard support at the end of DOMContentLoaded
document.addEventListener('keydown', (e) => {
const isEditingSettings = document.getElementById('interval-input') !== null || document.getElementById('speed-input') !== null;
// --- Feature: ESC key to exit various active states ---
if (e.key === 'Escape' || e.key === 'Esc') {
e.preventDefault();
// 1. Export SVG Modal
const exportModal = document.querySelector('.ejcees-export-modal');
if (exportModal) {
const closeBtn = exportModal.querySelector('.close-btn');
if (closeBtn) closeBtn.click();
return;
}
// 2. Edit Mode
if (isEditMode) {
const editCancelBtn = document.getElementById('edit-cancel');
if (editCancelBtn) editCancelBtn.click();
return;
}
// 3. Export Text Mode
if (isExportTextMode) {
const expCancelBtn = document.getElementById('exp-cancel');
if (expCancelBtn) expCancelBtn.click();
return;
}
// 4. Range Selection Mode
if (isRangeMode) {
const rangeBtn = document.getElementById('btn-range');
if (rangeBtn) rangeBtn.click();
return;
}
// 5. Interval / Speed Settings
if (isEditingSettings) {
const intervalCancel = document.getElementById('interval-cancel');
const speedCancel = document.getElementById('speed-cancel');
if (intervalCancel) intervalCancel.click();
if (speedCancel) speedCancel.click();
return;
}
// 6. Editing Comment
if (isEditingComment) {
const commentCancel = document.querySelector('.btn-cancel');
if (commentCancel) commentCancel.click();
return;
}
return;
}
// --- Feature: Ctrl + Arrow keys for branch navigation ---
if (e.ctrlKey) {
if (e.key === 'ArrowLeft' || e.key === 'Left') {
e.preventDefault();
// Jump to the previous fork point
for (let i = currentStepIndex - 1; i >= 0; i--) {
let node = getNodeAtStep(i);
if (node && node.v && node.v.length > 1) {
jumpToStep(i);
saveStateToUndo();
updateToolHighlights();
break;
}
}
return;
}
if (e.key === 'ArrowRight' || e.key === 'Right') {
e.preventDefault();
// Jump to the next fork point
const totalDepth = getPathDepth(historyFEN, currentBranch);
for (let i = currentStepIndex + 1; i < totalDepth; i++) {
let node = getNodeAtStep(i);
if (node && node.v && node.v.length > 1) {
jumpToStep(i);
saveStateToUndo();
updateToolHighlights();
break;
}
}
return;
}
if (e.key === 'ArrowUp' || e.key === 'Up' || e.key === 'ArrowDown' || e.key === 'Down') {
e.preventDefault();
const isUp = (e.key === 'ArrowUp' || e.key === 'Up');
// Find the nearest previous fork and its respective index
let forkIndex = -1;
let tempNode = historyFEN;
let currentForks = [];
for (let i = 0; i <= currentStepIndex; i++) {
if (tempNode && tempNode.v && tempNode.v.length > 1) {
forkIndex++;
currentForks.push({ step: i, forkIdx: forkIndex, node: tempNode });
}
const choice = (tempNode && tempNode.v && tempNode.v.length > 1) ? (currentBranch[forkIndex] || 0) : 0;
if (tempNode && tempNode.v && tempNode.v.length > 0) {
tempNode = tempNode.v[choice];
} else {
break;
}
}
if (currentForks.length > 0) {
let lastFork = currentForks[currentForks.length - 1];
let choicesCount = lastFork.node.v.length;
let currentChoice = currentBranch[lastFork.forkIdx] !== undefined ? currentBranch[lastFork.forkIdx] : 0;
let newChoice;
if (isUp) {
// Switch to previous branch
newChoice = (currentChoice - 1 + choicesCount) % choicesCount;
} else {
// Switch to next branch
newChoice = (currentChoice + 1) % choicesCount;
}
// Apply branch change and rerender
updateBranchPath(lastFork.forkIdx, newChoice);
renderRecordUI();
// Stay at the current depth if possible, or cap at the new branch's maximum depth
const newDepth = getPathDepth(historyFEN, currentBranch);
jumpToStep(Math.min(currentStepIndex, newDepth - 1));
saveStateToUndo();
updateToolHighlights();
}
return;
}
}
// Determine if the key pressed is allowed during Range Selection mode
const allowedInRangeMode = e.key === 'Insert' || e.key === 'Delete';
// Global block condition for shortcuts based on the application's current state
if (isExportTextMode || isAutoPlaying || isEditingComment || isEditingSettings || (isRangeMode && !allowedInRangeMode)) {
return;
}
// Undo / Redo logic
if (e.ctrlKey && e.key === 'z') {
e.preventDefault();
isEditMode ? undoEdit() : undo();
return;
}
if (e.ctrlKey && e.key === 'y') {
e.preventDefault();
isEditMode ? redoEdit() : redo();
return;
}
// Navigation and action shortcuts are disabled in Edit Mode
if (isEditMode) return;
// Get max step bounds from the slider for navigation limits
const maxStep = parseInt(stepSlider.max, 10) || 0;
switch (e.key) {
case 'Home':
e.preventDefault();
jumpToStep(0);
saveStateToUndo();
updateToolHighlights();
break;
case 'End':
e.preventDefault();
jumpToStep(maxStep);
saveStateToUndo();
updateToolHighlights();
break;
case 'PageUp':
e.preventDefault();
// Move backward 5 turns (10 steps/ply)
jumpToStep(Math.max(0, currentStepIndex - 10));
saveStateToUndo();
updateToolHighlights();
break;
case 'PageDown':
e.preventDefault();
// Move forward 5 turns (10 steps/ply)
jumpToStep(Math.min(maxStep, currentStepIndex + 10));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowUp':
case 'Up': // Handles legacy Edge/IE names
e.preventDefault();
// Move backward 1 turn (2 steps/ply)
jumpToStep(Math.max(0, currentStepIndex - 2));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowDown':
case 'Down':
e.preventDefault();
// Move forward 1 turn (2 steps/ply)
jumpToStep(Math.min(maxStep, currentStepIndex + 2));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowLeft':
case 'Left':
e.preventDefault();
// Move backward 1 step
jumpToStep(Math.max(0, currentStepIndex - 1));
saveStateToUndo();
updateToolHighlights();
break;
case 'ArrowRight':
case 'Right':
e.preventDefault();
// Move forward 1 step
jumpToStep(Math.min(maxStep, currentStepIndex + 1));
saveStateToUndo();
updateToolHighlights();
break;
case 'Delete':
case 'Del':
e.preventDefault();
// Triggers the deletion of the current move and the branch after it
deleteCurrentMoveAndAfter();
break;
case 'Insert':
case 'Ins':
e.preventDefault();
// Triggers the text export/import tool
document.getElementById('tool-exp-txt').click();
break;
}
});