將製作ejcees(中國象棋打譜程式)
Re: 將製作ejcees(中國象棋打譜程式)
一個不小的改動,這回文本導出的不再是全部的棋譜,而是只到currentStep的棋譜。
https://ejsoon.vip/wp-content/uploads/2 ... 77752.html
- 附件
-
ejcees20260407arrange99977752.7z- (46.25 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
只需給出所要修改的地方 ,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
Here are the modifications to implement the requested feature. We will add a parameter to the `getGamePath` function to conditionally limit the end step, and then apply this parameter only when generating the Engine format.
### 1. Update the `getGamePath` function
Find the `getGamePath()` function definition and replace it completely with the following code. This adds the `limitToCurrentStep` parameter, defaulting to `false` for `cn`, `en`, and `url` formats to export the full depth, but allowing the Engine format to stop at `currentStepIndex`.
**Replace this block:**
```javascript
// Extract the linear path corresponding to the currently selected branch
function getGamePath() {
let newStart = 0;
// Modification: Default end is now currentStepIndex instead of full depth
let newEnd = currentStepIndex;
let newHistory = {
fen: historyFEN.fen,
move: null,
lastMove: null,
c: historyFEN.c,
v: []
};
if (isRangeMode) {
// Restore original full depth default if in range mode but end isn't picked yet
newEnd = getPathDepth(historyFEN, currentBranch) - 1;
// ... (rest of the function)
```
**With this:**
```javascript
// Extract the linear path corresponding to the currently selected branch
function getGamePath(limitToCurrentStep = false) {
let newStart = 0;
// Modification: Default to currentStepIndex only if explicitly requested (for engine format)
let newEnd = limitToCurrentStep ? currentStepIndex : getPathDepth(historyFEN, currentBranch) - 1;
let newHistory = {
fen: historyFEN.fen,
move: null,
lastMove: null,
c: historyFEN.c,
v: []
};
if (isRangeMode) {
if (rangeStart === null && rangeEnd === null) {
newStart = currentStepIndex;
newEnd = currentStepIndex;
} else if (rangeStart !== null && rangeEnd !== null && rangeStart === rangeEnd) {
newStart = rangeStart;
newEnd = rangeEnd;
} else if (rangeStart !== null && rangeEnd === null) {
newStart = rangeStart;
} else if (rangeStart !== null && rangeEnd !== null && rangeStart !== rangeEnd) {
newStart = Math.min(rangeStart, rangeEnd);
newEnd = Math.max(rangeStart, rangeEnd);
}
const startNode = getNodeAtStep(newStart);
newHistory = {
fen: startNode.fen,
move: null,
lastMove: null,
c: startNode.c,
v: []
};
}
let curr = newHistory;
for (let i = newStart + 1; i <= newEnd; i++) {
const node = getNodeAtStep(i);
let newNode = {
fen: node.fen,
move: node.move,
lastMove: node.lastMove,
c: node.c,
v: []
};
curr.v.push(newNode);
curr = newNode;
}
return newHistory;
}
```
### 2. Update `performCopy` to pass `true` for Engine format
Locate the global `performCopy()` function that you added in the previous step. Find the `else if (fmt === 'engine') {` block and update the `getGamePath` call.
**Replace this line:**
```javascript
} else if (fmt === 'engine') {
let path = getGamePath();
```
**With this:**
```javascript
} else if (fmt === 'engine') {
// Modification: Pass true to limit engine format to currentStepIndex
let path = getGamePath(true);
```
### 3. Update `renderExportTextUI` to pass `true` for Engine format
Locate the `renderExportTextUI()` function (around the area where the `urlTextToggled` is defined). Find the section where the Engine text is generated and update the `getGamePath` call.
**Replace this block:**
```javascript
const urlText = generateUrlHash(false);
const urlTextToggled = generateUrlHash(true);
// Generate UCCI Engine Format String
let path = getGamePath();
```
**With this:**
```javascript
const urlText = generateUrlHash(false);
const urlTextToggled = generateUrlHash(true);
// Generate UCCI Engine Format String
// Modification: Pass true to limit engine format to currentStepIndex
let path = getGamePath(true);
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
代码: 全选
Here is the modification to add the **Spacebar** as a shortcut for the **Auto Play** button.
### Update the `keydown` Event Listener
Locate the main keyboard event listener `document.addEventListener('keydown', (e) => {` (around line `1854`). Insert the logic for the Spacebar inside the main block, ensuring it only triggers when the specified states are inactive.
**Search for this section:**
```javascript
document.addEventListener('keydown', (e) => {
if (isExportTextMode || isEditingComment || isEditMode || isEditingSettings) return;
```
**Replace that specific check and add the Spacebar logic like this:**
```javascript
document.addEventListener('keydown', (e) => {
// Check if any modal or edit mode is active
const isExportModalOpen = document.querySelector('.ejcees-export-modal') !== null;
const isRestrictedMode = isExportTextMode || isEditingComment || isEditMode || isEditingSettings || isExportModalOpen;
// Feature: Spacebar for Auto Play
if (e.code === 'Space' || e.key === ' ') {
if (!isRestrictedMode) {
e.preventDefault(); // Prevent page scrolling
const autoPlayBtn = document.getElementById('btn-auto-play');
if (autoPlayBtn) {
autoPlayBtn.click();
}
return;
}
}
if (isRestrictedMode) return;
if (e.ctrlKey) {
// ... (existing Ctrl shortcut logic)
```
### Explanation of the change:
* **`e.code === 'Space'`**: This reliably detects the spacebar across different keyboard layouts.
* **`e.preventDefault()`**: This is crucial because the default browser behavior for the spacebar is to scroll the page down; this line prevents that.
* **State Check**: It uses the same logic as your other shortcuts to ensure you don't accidentally toggle auto-play while typing a comment or editing settings.https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
更改導出範圍,engine只到currentStep,而其它三個都是全部導出。space播放和停止動畫。
https://ejsoon.vip/wp-content/uploads/2 ... 77753.html
- 附件
-
ejcees20260407engineStep99977753.7z- (46.37 KiB) 已下载 1 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將製作ejcees(中國象棋打譜程式)
應該要怎麼做?是否要把js對象化?
代码: 全选
要將原本的 HTML/CSS/JS 程式轉換為一個可複用的組件,並支援多個實例(例如頁面上有多個 `.ejcees` 容器且互不干擾),**將 JS「對象化」(物件導向,Object-Oriented)是絕對必要的**。
以下是實現這個目標的建議架構與步驟:
### 1. 核心觀念:封裝與範圍限制
在目前的代碼中,許多變量是全域的(如 `historyFEN`, `currentStepIndex` 等),且 DOM 操作是使用 `document.querySelector`。要達成多個實例並存,必須:
* **使用 Class (類別)**:將所有邏輯封裝在一個 `class Ejcees` 中。
* **Scoped DOM**:不要用 `document` 查找,而是從實例傳入的 `container` 節點開始查找。
* **私有狀態**:每個實例擁有自己的一套 `undoStack`, `redoStack`。
### 2. 實作步驟建議
#### A. CSS 的處理
為了讓 CSS 隨 JS 自動載入,你可以將原本 `<style>` 標籤中的內容 存為一個 JS 字串。
```javascript
const EJCEES_CSS = `
.ejceesmain { display: flex; ... }
/* 將原本的所有 CSS 放進這裡 */
`;
function injectCSS() {
if (!document.getElementById('ejcees-styles')) {
const style = document.createElement('style');
style.id = 'ejcees-styles';
style.textContent = EJCEES_CSS;
document.head.appendChild(style);
}
}
```
#### B. 將 JS 對象化 (Class 結構)
你需要將 `DOMContentLoaded` 中的邏輯 搬移到 Class 的 `constructor` 或 `init` 方法中。
```javascript
class Ejcees {
constructor(element) {
this.container = element; // 這是對應的 .ejcees 元素
this.historyFEN = { fen: INITIAL_FEN, v: [] }; // 獨立的狀態
this.undoStack = []; // 獨立的撤銷棧
this.currentStepIndex = 0;
this.init();
}
init() {
// 1. 生成內部 HTML 結構 (原本 body 裡的 ejceesmain 內容)
this.container.innerHTML = `...原本的 HTML 結構...`;
// 2. 獲取內部元素(使用 this.container.querySelector)
this.svgElement = this.container.querySelector('.ejceespb');
this.outputElement = this.container.querySelector('.ejceesoutput');
// 3. 綁定事件
this.bindEvents();
// 4. 初始化棋盤狀態
this.loadFEN(this.historyFEN.fen);
}
bindEvents() {
// 使用箭頭函數確保 this 指向實例
this.svgElement.addEventListener('click', (e) => this.handleBoardClick(e));
this.container.querySelector('#tool-undo').addEventListener('click', () => this.undo());
// ...其他按鈕事件
}
undo() {
if (this.undoStack.length <= 1) return;
// 實作該實例專屬的 undo 邏輯
}
// 將原本的所有 function (如 loadFEN, renderRecordUI) 變成 class 的 method
loadFEN(fenStr) { ... }
}
```
#### C. 主控入口
在 JS 檔案的最下方,檢查頁面上是否存在目標元素並實例化:
```javascript
function initAllEjcees() {
const elements = document.querySelectorAll('.ejcees');
if (elements.length > 0) {
injectCSS(); // 載入 CSS
elements.forEach(el => new Ejcees(el));
}
}
// 頁面載入後執行
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initAllEjcees);
} else {
initAllEjcees();
}
```
### 3. 注意事項
1. **ID 衝突**:原本 HTML 中使用了許多 `id`(如 `id="tool-undo"`)。在多個實例中,`id` 必須唯一。建議將 HTML 中的 `id` 改為 `class`,並在 JS 中透過 `this.container.querySelector('.tool-undo')` 來選取。
2. **LocalStorage**:原本代碼會將狀態存入 `localStorage.setItem('ejcees_saved_state', ...)`。如果頁面有多個棋盤,它們會互相覆蓋。建議給每個實例一個唯一的 ID(例如 `data-id`),存儲時鍵名改為 `ejcees_state_${id}`。
3. **Global Event Listeners**:代碼中有對 `document` 綁定 `keydown` 事件。這需要小心處理,否則按下鍵盤時所有棋盤都會同時動作。建議檢查 `document.activeElement` 是否在 `this.container` 內部,才觸發該實例的邏輯。
透過這種「類別封裝」的方式,你可以輕鬆在同一個網頁中放入多個象棋編輯器,且彼此的棋譜、編輯模式與撤銷紀錄都會完全獨立。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: 没有注册用户 和 4 访客
