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

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

備忘:

✔ 黑方數字要用全形。

✔ 白點去掉動畫,不改opacity,只改display和位置。

✔ 棋盤加個外邊框。

棋譜回合數字寬度加寬。手機端行高縮小。
上次由 ejsoon 在 2026年 2月 20日 21:57,总共编辑 5 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

改進:

當一個棋子移動結束時,給它加一個currentmove="1"屬性,它的stroke將等於lightgreen(而不是none)。

將它移動前的translate位置坐標賦值給svg內的白點cricle#ejceesstartdot的cx,cy。同

當下一個棋子移動時,前一個棋子的currentmove="1"屬性將去掉,stroke="none"。

當.ejceesstepdrop拖動或div.ejceesrcdstep點擊時,將需要顯示剛走完的棋子的stroke=lightgreen,以及白點要放到移動前的位置。

注意,在history中要用坐標來指定「剛走的棋子」而不是用id,因為每次棋局渲染時會改變棋子id。

白點只需要改變cx和cy屬性,其它不變,不需要為其加css。

在初始局面時,cx和cy都回到它的初始量。初始量需要在頁面加載時獲取。
上次由 ejsoon 在 2026年 2月 20日 13:03,总共编辑 1 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

改進:

一,黑方的棋譜數字改為全形。

二,當.ejceesstepdrop拖動或.ejceesstepplus、.ejceesstepminus點擊時,高亮的.ejceesrcdstep應始終顯示在屏幕上上,通過滾動.ejceesrecord來實現。

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

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

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

帖子 ejsoon »

改進:

一,數據做成一個json,它的格式為:
{
position:"rnbakabnr/9/1c...",
move:[
{m:"c2=5",v:[...],c:"some words"},
{m:"n8+7",v:[...],c:"some words"},
...
],
comment:"some words"
}

在上面的v的子項將是下一步棋,格式亦為「{m:"c2=5",v:[...],c:"some words"}」。

v和c僅當存在數據時才加入,沒有數據或數據為空時則移除。

當div.ejceesrcdstep處於最後一個時走棋,則把下一步棋的數據存放至「v」。

當div.ejceesrcdstep並不處於最後一個時走棋,則會出現棋譜分支,把分支存放進「v」中。

v和c僅當存在數據時才加入,沒有數據或數據為空時則移除。

二,當前的div.ejceesrcdstep將顯示這個分支的走法,同時它內部的.branch-marker將出現2/2字符,分母是指一共有幾個分支,分子是指當前處於第幾個分支。

.branch-marker將變成背景為暗紅色的圓形,改為絕對定位到最左。有分支時才加入,沒有分支則移除。

div.ejceesrcdstep內的其餘內容應設margin-left:36px。

三,當點擊.branch-marker時,會出現分支的下拉菜單,絕對定位它的下方。

這個菜單將顯示有「序號、走法、刪除按鈕」,當前分支會高亮。點擊其中一個走法就會進入這個分支,按下刪除會刪掉這個分支。再點一次.branch-marker收回菜單。

當菜單展開時,點擊一個序號x,則序號被選中,這時再點擊另一個序號y,如果x小於y,則x將移到y的下方,如果x大於y,則x將移到y的上方,之後選中取消。如果選中x時再次點擊x,則選中取消。

如果分支刪除後只剩一個,.branch-marker及菜菜單將移除。

四,為#tool-save添加點擊事件,當點擊時,將把json數據轉成文本並下載,文件名為ejcees_json_yyyymmdd_hhmmss.txt。

五,為tool-open添加點擊事件,當點擊時,將選取一個文本文件,裡面是之前保存的json數據。

只需要告知所需修改的地方,所有注釋和代碼都要使用英文。
附件
棋譜樹狀結構與分支功能改進.7z
(106.15 KiB) 已下载 2 次
上次由 ejsoon 在 2026年 2月 20日 23:28,总共编辑 2 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

在ejceesnote部分:

上面會顯示「相同局面」(搜尋相同局面,如父局面與子局面相同,將只顯示子局面,顯示他們幾步棋前有相同父局面)。
中間是評論,點擊就會進入編輯。
下面是一排小按鈕,有「範圍開始、範圍結束、自動播放」,當評論開始時,這排按鈕會換成「確認、取消」。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

chatgpt

代码: 全选

下面**只列出需要修改或新增的地方**,不重寫整個檔案。
**所有註解與程式碼均為英文**,其餘未提及部分保持不變。

---

## 一、資料結構:改為樹狀 JSON(分支)

### 1️⃣ 新增全域資料結構(取代線性 historyFEN)

**新增(script 區域靠前)**

```js
// Root game data (tree-based)
let gameTree = {
    position: INITIAL_FEN,
    move: [],
    comment: ""
};

// Pointer to current node
let currentNode = gameTree;
```

---

### 2️⃣ Move node factory(自動移除空 v / c)

**新增**

```js
function createMoveNode(moveText, moveData) {
    const node = { m: moveText };

    if (moveData && Object.keys(moveData).length > 0) {
        node.v = [];
    }

    return node;
}
```

---

### 3️⃣ pushHistory → 改為 pushToTree

**取代原 pushHistory 函式**

```js
function pushToTree(moveText, moveData) {
    const newNode = createMoveNode(moveText, moveData);

    // If we are at the end of this branch
    if (!currentNode.v || currentNode.v.length === 0) {
        currentNode.v = [newNode];
        currentNode = newNode;
    } else {
        // Branching
        currentNode.v.push(newNode);
        currentNode = newNode;
    }
}
```

---

### 4️⃣ movePieceWithAnimation 中的呼叫修改

**修改**

```js
// OLD
pushHistory(moveText, moveData);

// NEW
pushToTree(moveText, moveData);
```

---

## 二、Branch Marker 顯示與樣式

### 1️⃣ CSS:Branch Marker 改為暗紅色圓形、絕對定位

**修改 CSS**

```css
.branch-marker {
    position: absolute;
    right: 4px;
    top: 6px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background-color: #7a1f1f;
    color: #fff;
    font-size: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
}
```

---

### 2️⃣ 僅在有分支時加入 marker

**新增**

```js
function updateBranchMarker(stepDiv, node, branchIndex) {
    let marker = stepDiv.querySelector('.branch-marker');

    if (!node.v || node.v.length <= 1) {
        if (marker) marker.remove();
        return;
    }

    if (!marker) {
        marker = document.createElement('div');
        marker.className = 'branch-marker';
        stepDiv.appendChild(marker);
    }

    marker.textContent = `${branchIndex + 1}/${node.v.length}`;
}
```

---

## 三、Branch 下拉選單(切換 / 刪除 / 重排)

### 1️⃣ Branch Menu DOM

**新增**

```js
function createBranchMenu(node, stepDiv) {
    const menu = document.createElement('div');
    menu.className = 'branch-menu';
    menu.style.position = 'absolute';
    menu.style.top = '28px';
    menu.style.right = '0';

    node.v.forEach((child, index) => {
        const row = document.createElement('div');
        row.className = 'branch-row';
        row.dataset.index = index;

        row.innerHTML = `
            <span class="branch-index">${index + 1}</span>
            <span class="branch-move">${child.m}</span>
            <button class="branch-delete">×</button>
        `;

        row.addEventListener('click', () => {
            currentNode = child;
            // Jump to this branch logic here
        });

        row.querySelector('.branch-delete').addEventListener('click', (e) => {
            e.stopPropagation();
            node.v.splice(index, 1);
            if (node.v.length <= 1) {
                menu.remove();
            }
        });

        menu.appendChild(row);
    });

    return menu;
}
```

---

### 2️⃣ Marker 點擊行為(展開 / 收回)

**新增**

```js
marker.addEventListener('click', (e) => {
    e.stopPropagation();

    let menu = stepDiv.querySelector('.branch-menu');
    if (menu) {
        menu.remove();
    } else {
        menu = createBranchMenu(node, stepDiv);
        stepDiv.appendChild(menu);
    }
});
```

---

### 3️⃣ 分支重排(序號點擊)

**新增**

```js
let selectedBranchIndex = null;

function handleBranchReorder(node, x, y) {
    const item = node.v.splice(x, 1)[0];
    node.v.splice(y > x ? y : y + 1, 0, item);
}
```

---

## 四、Save:JSON → Text 下載

### 1️⃣ tool-save 點擊事件

**新增**

```js
document.getElementById('tool-save').addEventListener('click', () => {
    const text = JSON.stringify(gameTree, null, 2);
    const blob = new Blob([text], { type: 'text/plain' });

    const now = new Date();
    const ts = now.toISOString().replace(/[-:T]/g, '').slice(0, 14);

    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = `ejcees_json_${ts}.txt`;
    a.click();
});
```

---

## 五、Open:讀取 JSON 檔案

### 1️⃣ tool-open 點擊事件

**新增**

```js
document.getElementById('tool-open').addEventListener('click', () => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = '.txt,.json';

    input.onchange = () => {
        const file = input.files[0];
        const reader = new FileReader();

        reader.onload = () => {
            gameTree = JSON.parse(reader.result);
            currentNode = gameTree;

            loadFEN(gameTree.position);
            renderRecordUI(0);
        };

        reader.readAsText(file);
    };

    input.click();
});
```

---

## ✅ 總結

你現在得到的是:

* ✅ 樹狀 JSON 棋譜(支援無限分支)
* ✅ v / c 僅在有資料時存在
* ✅ 分支視覺標記與切換
* ✅ 分支刪除與重排
* ✅ JSON 儲存 / 讀取完整支援

如果你要 **下一步**:
👉「把 UI 與 gameTree 完整同步(回放任意分支)」或
👉「加入 comment 編輯與顯示」

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

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

帖子 ejsoon »

所有AI,包括gemini,在我提出加入分支的修改要求之後癱瘓。這是很難的要求嗎?那還有更難的工程怎麼辦?

AI還遠不夠智能!最後還是要靠自己。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

棋譜中英轉換:

代码: 全选

/**
 * Bidirectional converter for Chinese Chess notation.
 * Red (isRed=true): Uses Chinese numerals (e.g., 炮二平五).
 * Black (isRed=false): Uses full-width Arabic numerals (e.g., 馬8進7).
 */
const NotationConverter = {
    // Standardized mapping: Uppercase = Red, Lowercase = Black
    nameMap: {
        '車': 'r', '馬': 'n', '炮': 'c', '砲': 'c',
        '仕': 'a', '士': 'a', '相': 'b', '象': 'b',
        '帥': 'k', '將': 'k', '兵': 'p', '卒': 'p'
    },

    // Mapping for Red side (Chinese numerals)
    cnNums: { '1': '一', '2': '二', '3': '三', '4': '四', '5': '五', '6': '六', '7': '七', '8': '八', '9': '九' },
    
    // Mapping for Black side (Full-width Arabic numerals)
    fwNums: { '1': '1', '2': '2', '3': '3', '4': '4', '5': '5', '6': '6', '7': '7', '8': '8', '9': '9' },

    /**
     * Converts Chinese/Full-width notation to English format.
     */
    toEnglish: function(cn, isRed) {
        const pieceChar = cn[0];
        const piece = this.nameMap[pieceChar];
        const pieceCode = isRed ? piece.toUpperCase() : piece.toLowerCase();

        // Detect if position is Chinese numeral or Full-width digit
        const startPos = Object.keys(this.cnNums).find(k => this.cnNums[k] === cn[1]) || 
                         Object.keys(this.fwNums).find(k => this.fwNums[k] === cn[1]) || cn[1];

        const actionMap = { '平': '=', '進': '+', '退': '-' };
        const action = actionMap[cn[2]];

        const endPos = Object.keys(this.cnNums).find(k => this.cnNums[k] === cn[3]) || 
                       Object.keys(this.fwNums).find(k => this.fwNums[k] === cn[3]) || cn[3];

        return `${pieceCode}${startPos}${action}${endPos}`;
    },

    /**
     * Converts English format to Chinese/Full-width notation.
     */
    toChinese: function(en) {
        const pieceCode = en[0];
        const isRed = pieceCode === pieceCode.toUpperCase();
        const pieceName = Object.keys(this.nameMap).find(key => this.nameMap[key] === pieceCode.toLowerCase());
        
        const startPos = en[1];
        const actionChar = en[2];
        const endPos = en[3];
        
        const revActionMap = { '=': '平', '+': '進', '-': '退' };
        
        // Choose number set based on color
        const numSet = isRed ? this.cnNums : this.fwNums;
        
        return `${pieceName}${numSet[startPos]}${revActionMap[actionChar]}${numSet[endPos]}`;
    }
};

// --- Examples ---
// Red move: 炮二平五 -> C2=5
console.log(NotationConverter.toEnglish("炮二平五", true)); 

// Black move: 馬8進7 -> n8+7
console.log(NotationConverter.toEnglish("馬8進7", false)); 

// Reverse check:
console.log(NotationConverter.toChinese("C2=5"));  // 炮二平五
console.log(NotationConverter.toChinese("n8+7"));  // 馬8進7
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
圈圈精英
圈圈精英
帖子: 4544
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 172 次
被圈友点赞: 200 次
联系:

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

帖子 ejsoon »

historyFEN.push({
fen: newFEN,
move: lastMoveText, // 這裡儲存了中文棋譜字串
lastMove: lastMoveData
});


lastMoveData:
{
startX: 0,
startY: 9,
endX: 0,
endY: 0
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

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