分享和讨论Javascript相关的话题
回复
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

這段代碼是否需要修改?尤其是getMoveNotation已經不存在了。

代码: 全选

            if (moveStr.length >= 4) {
              let dc = null;
              let moveEn = '';
              let isRed = currentFen.includes(' w');

              if (/^[a-i][0-9][a-i][0-9]$/.test(moveStr)) {
                let startX = moveStr.charCodeAt(0) - 97;
                let startY = 9 - parseInt(moveStr.charAt(1), 10);
                let endX = moveStr.charCodeAt(2) - 97;
                let endY = 9 - parseInt(moveStr.charAt(3), 10);
                dc = {
                  startX,
                  startY,
                  endX,
                  endY
                };

                let pId = vMap.get(`${startX},${startY}`);
                if (!pId) {
                  hasError = true;
                  continue;
                }
                moveEn = this.getMoveNotation(pId, startX, startY, endX, endY, null, vMap);
              } else {
                let isEnglish = /^[a-zA-Z]/.test(moveStr) || /^[+\-=1-9][a-zA-Z0-9]/.test(moveStr);
                moveEn = isEnglish ? moveStr : this.NotationConverter.toEnglish(moveStr, isRed);
                console.log('moveEn', moveEn);
                if (/^[RNBAKCPrnbakcp+\-=1-9]{2}[+\-=][1-9]/.test(moveEn)) {
                  dc = this.deriveCoordsFromPgnMove(currentFen, moveEn, isRed);
                } else {
                  dc = moveEn;
                }
              }

              if (moveEn === dc) {
                if (!currentCommentNode.c) {
                  currentCommentNode.c = '';
                }
                // Append the token, separating with a space if a comment already exists
                currentCommentNode.c += (currentCommentNode.c ? ' ' : '') + token;
                continue; // Skip node creation and continue parsing
              }

              if (!dc) {
                const cleanInitial = this.INITIAL_FEN.replace(/ - - 0 1$/, '');
                if (importedFen !== cleanInitial && importedFen !== this.INITIAL_FEN) {
                  this.importExportedText(text, this.INITIAL_FEN);
                  return;
                } else {
                  alert('Parsed partially due to an invalid move notation.');
                  this.renderRecordUI();
                  this.renderNoteUI();
                  this.updateToolHighlights();
                  return;
                }
              }

              // Rule 4: The variation is attached to the parent of the move
              lastMoveParent = currNode;
              lastMoveParentFen = currentFen;

              let nextFen = this.simulateMove(currentFen, dc);
              let childIdx = currNode.v.findIndex(c => c.move === moveEn && c.fen === nextFen);

              if (childIdx === -1) {
                let newNode = {
                  fen: nextFen,
                  move: this.coordsToEngine(dc.startX, dc.startY, dc.endX, dc.endY),
                  c: '',
                  v: []
                };
                currNode.v.push(newNode);
                childIdx = currNode.v.length - 1;
              }

              // If this.this creates a fork on the main path, update this.currentBranch
              if (currNode.v.length > 1 && currNode === attachNode) {
                this.currentBranch[forkCount] = childIdx;
                forkCount++;
                attachNode = currNode.v[childIdx]; // Follow the first parsed line as the main path
              }

              currNode = currNode.v[childIdx];
              currentFen = nextFen;
              currentCommentNode = currNode;

              let pId = vMap.get(`${dc.startX},${dc.startY}`);
              vMap.delete(`${dc.startX},${dc.startY}`);
              if (pId) vMap.set(`${dc.endX},${dc.endY}`, pId);
            }

這段代碼是否需要修改?尤其是getMoveNotation已經不存在了。

找到所有getMoveNotation,並替換成正確的代碼。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

gemini pro夠強:

代码: 全选

Yes, the code needs to be modified. Since `getMoveNotation` no longer exists, and the `move` property expects the engine format (e.g., `"h2e2"`), you should replace all instances of `this.getMoveNotation(...)` with `this.coordsToEngine(startX, startY, endX, endY)`.

Here are all the places in the code that need to be updated, with all comments in English:

### 1. In `parseUrlHash` method
**Modify this part:**
```javascript
      let pId = vMap.get(`${startX},${startY}`);
      if (!pId) return null;

      // Replace getMoveNotation with coordsToEngine
      let moveNotation = this.coordsToEngine(startX, startY, endX, endY);

      return {
        fen: nextFen,
        move: moveNotation,
        lastMove: dc,
        c: '',
        v: []
      };
```

### 2. In `importExportedText` method (PGN Format Parsing)
**Modify this part:**
```javascript
          if (/^[a-i][0-9][a-i][0-9]$/i.test(word) || /^[A-I][0-9][A-I][0-9]$/i.test(word)) {
            word = word.toLowerCase();
            let startX = word.charCodeAt(0) - 97;
            let startY = 9 - parseInt(word.charAt(1), 10);
            let endX = word.charCodeAt(2) - 97;
            let endY = 9 - parseInt(word.charAt(3), 10);
            dc = { startX, startY, endX, endY };
            let vMap = this.buildVirtualMap(currentNode.fen);
            let pId = vMap.get(`${startX},${startY}`);
            if (pId) {
              // Replace getMoveNotation with coordsToEngine
              moveEn = this.coordsToEngine(startX, startY, endX, endY);
            } else {
              moveEn = word;
            }
          } else {
```

### 3. In `importExportedText` method (Complex Format Parsing - The snippet you provided)
**Modify this part:**
```javascript
              if (/^[a-i][0-9][a-i][0-9]$/.test(moveStr)) {
                let startX = moveStr.charCodeAt(0) - 97;
                let startY = 9 - parseInt(moveStr.charAt(1), 10);
                let endX = moveStr.charCodeAt(2) - 97;
                let endY = 9 - parseInt(moveStr.charAt(3), 10);
                dc = {
                  startX,
                  startY,
                  endX,
                  endY
                };

                let pId = vMap.get(`${startX},${startY}`);
                if (!pId) {
                  hasError = true;
                  continue;
                }
                // Replace getMoveNotation with coordsToEngine
                moveEn = this.coordsToEngine(startX, startY, endX, endY);
              } else {
```

### 4. In `importExportedSVG` method
**Modify this part:**
```javascript
      const startX = startPt.x;
      const startY = startPt.y;
      const endX = endPt.x;
      const endY = endPt.y;

      const capturedId = this.tileMap.get(`${endX},${endY}`) || null;
      
      // Replace getMoveNotation with coordsToEngine
      const moveNotation = this.coordsToEngine(startX, startY, endX, endY);
      
      const dc = {
        startX,
        startY,
        endX,
        endY
      };
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

問題:當導入PGN時,中文又轉換失敗,且rotate=true沒有生效。

代码: 全选

[Game "Chinese Chess"]
[Rotate "true"]
[Format "Chinese"]

{吳可欣贏網友一盤棋}
1. 炮八平五 馬2進3
2. 兵七進一 車1平2
3. 馬八進七 卒7進1
4. 車九平八 馬8進7
5. 馬二進一 車9進1
6. 炮二平四{估計是這步棋使局勢急轉直下,因為它導致紅方右車完全出不來}
馬7進8
7. 炮四進三 卒7進1
8. 兵三進一 馬8進6
9. 馬七進六 車9平4
{吳姐說希望他踩中兵}
10. 馬六進五 馬3進5
11. 炮五進四 車4進3
12. 兵三進一 車4平5
{吳姐說差點走馬6進8}
13. 車一平二 砲8進4
14. 炮五平四 車5進2
15. 仕四進五 馬6進4
16. 車八進六 馬4進3
17. 帥五平四 砲8平6
18. 前炮平六 砲6退1
19. 炮六退五 車5平6
20. 帥四平五 車6平4
21. 帥五平四 車4進2
22. 車二進四 車4退2
23. 車二平四 砲2平6
24. 車八進三 砲6進3
{紅方認負}
*
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

上面問題已解決,現在的小問題是,PGN導出會產生兩個[Rotate "true"]。

TODO:URI導出如何放進rotate。

還有mini的剛走完的棋子的綠邊和白點又沒有了…
附件
ejceesobj202604302037.js
(299.29 KiB) 已下载 45 次
上次由 ejsoon 在 2026年 4月 30日 22:15,总共编辑 1 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

解決綠邊和白點小問題
engineToCoords(engineMove) {
coordsToEngine(startX, startY, endX, endY) {
機器碼和坐標相互轉。
附件
ejceesobj202604302047.js
(299.33 KiB) 已下载 49 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

東萍導入分支時仍然存在問題:

代码: 全选

寡人對戰網友
1. 炮二平五 馬8進7
2. 馬二進三 卒7進1
3. 車一進一 馬2進1 ①
邊馬會使中路薄弱
4. 車一平六
開局横車略虧
4. ………… 士6進5 ②
5. 馬八進七 砲2平4
6. 車九平八 車1平2
7. 炮八進四 ③ 象7進5
8. 兵七進一 車9平6
9. 兵五進一 ④ 馬7進6 ⑤
10. 車六進二 ⑥ 砲8平7 ⑦
11. 炮五進四 馬6進7
12. 兵五進一 車6進7
13. 馬七進五 卒1進1 ⑧
14. 仕四進五 ⑨ 車6退1
15. 車六進一 車2進2
16. 車八進二 卒9進1
17. 車六平二 將5平6 ⑩
18. 車二進五 砲7退2
19. 炮五平一 將6平5
20. 兵七進一 砲4進1 ⑪
21. 兵七進一 砲4平2
22. 兵七平八 車2平3
23. 兵八進一 車3進7
24. 兵八平九 象3進1
25. 炮一進三 士5退6
26. 炮一平三 象5退7
27. 車二平三 車3退7
28. 車三退四 卒9進1
29. 馬五進六 車3平6
30. 車八進二 卒9進1
31. 馬三進一 馬7進9
32. 馬一進二 前車平8
33. 相三進一
黑方認負

①
3. ………… 馬2進3
4. 兵七進一 象3進5
5. 馬八進七 馬7進8 ⑫
6. 馬七進六 車9進1
7. 馬六進五 馬3進5
8. 炮五進四 士4進5
9. 炮八平九 車9平7
10. 相三進五 馬8進7
11. 炮五平九 車1平4
12. 車九平八 卒7進1
13. 前炮進三 車4進6
14. 兵九進一

②
4. ………… 象7進5
34層23分
5. 馬八進七 士6進5
6. 兵七進一 砲2平3
7. 馬七進八 車9平6
8. 車六進三 馬7進6
9. 車六進一 馬1退3
10. 車九進一 砲3平4
11. 車九平四 砲8進2
12. 車六退四 馬3進4
13. 車六平七 砲4平3
14. 兵七進一 卒3進1
15. 車七進四 砲3平2
16. 炮八進五 馬4退2
17. 車七退一 馬2進3
18. 仕六進五 馬6進7
19. 車四進八 士5退6

③
7. 炮八進五
18層-24
7. ………… 象7進5
8. 車六平二 馬7進6
9. 兵七進一 車9平7
10. 車二進三 馬6進7
11. 炮五進四 車7進3
12. 馬七進六 卒7進1
13. 車二進一 卒7平6
14. 車二退二 卒1進1

④
9. 車六平二
20層-24
9. ………… 砲8進2
10. 馬七進六 車6進7
11. 馬六進五 馬7進5
12. 炮五進四 砲8退2
13. 馬三退一 車6退4
14. 車八進一 馬1退3
15. 相三進五 砲8平6
16. 仕四進五 砲6退2
17. 兵五進一 馬3進2
18. 車八進五 車2進3
19. 炮五平八 卒3進1

⑤
9. ………… 車6進7
19層52
10. 車六平二 砲8進2
11. 馬七進五 車2進2
12. 仕四進五 車6退1
13. 車二進三 卒1進1
14. 車八進二 車6平7
15. 兵一進一 砲4進1
16. 炮八退三 砲4進3
17. 炮八進三 車7平6
18. 相七進九 砲4退3
19. 炮八退三 車6退6
20. 炮五平四 砲4進2

⑥
10. 炮五進四
75
10. ………… 馬6退7
11. 兵五進一 車6進7
12. 馬七進五 馬7進5
13. 兵五進一 砲8進4
14. 仕四進五 車6退1
15. 相三進五 卒7進1
16. 兵三進一 砲8平5
17. 車六進二 車6進1
18. 車六平五 車6平7
19. 兵五平六 馬1退3
20. 炮八進一 砲4進7
21. 仕五退六 馬3進4
22. 車五進三 馬4進3
23. 相五進七 車7進2
24. 帥五進一

⑦
10. ………… 馬1退3
107分。妙著,下一步連環馬炮打車
11. 炮八進一 馬3進4
12. 車六平四 砲4進7
13. 車八進五 車2進2
14. 車八平四 車6進4
15. 車四進二 卒5進1
16. 車四退四 卒5進1
17. 馬七退六 車2進4
18. 車四平二 砲8平7
19. 炮五平七 馬4進3
20. 仕四進五 馬3進2
21. 車二進八 士5退6
22. 車二退五 車2平7

⑧
13. ………… 馬1退3
紅175
14. 仕四進五 車6退1
15. 炮八進一 將5平6
16. 車六進一 砲4進7
17. 車六退四 車2進2
18. 車八進七 砲7平2
19. 車六進八 馬3進1
20. 炮五平六 砲2平4
21. 炮六退三 車6退1
22. 兵五進一 車6平5
23. 兵五進一 馬7退6
24. 兵五平六 馬6進5
25. 馬三進五 車5進1
26. 兵六平七 車5退4
27. 車六退三 車5平3
28. 車六平三 車3平4
29. 車三進四 將6進1

⑨
14. 車六進一
262
14. ………… 車2進2
15. 仕四進五 車6退5
16. 車六平二 砲7退2
17. 車二進五 砲7平6
18. 車八進三 車6平8
19. 車二平一 砲4進1
20. 炮八退二 車2進2
21. 馬五進六 馬7退8

⑩
17. ………… 砲7退2
18. 馬五進六 砲4退1
19. 車二進五 砲7平6
20. 車八進二 車2平4
21. 馬三進五 砲4平2
22. 炮八平九 砲2平3
23. 炮五平一 車6退4
24. 炮一進三 馬7退5
25. 車八退一 車6平7
26. 車二退五 車7退2

⑪
20. ………… 砲4平3
-389分
21. 馬五進六 砲3退1
22. 相七進五 砲3進3
23. 兵五進一 車6進2
24. 相五退七 砲7平6
25. 馬三進五 車6退6
26. 炮一進三 馬7退5
27. 車八進二 馬5進3
28. 相三進五 馬3退4
29. 馬五進六 車6平7
30. 馬六進四 砲3平2
31. 兵五進一 象3進5
32. 車二退一 象5退7
33. 馬四進三 車7退1
34. 車二平三 砲6平9
35. 車三進一 士5退6

⑫
5. ………… 車9進1
6. 車一平二 砲8進2
7. 車二進三 砲2退1
8. 炮五平六 砲2平8
9. 車二平四 車1平2
10. 車九平八 卒3進1
11. 兵七進一 前砲平3
12. 馬七進八 砲3平2
13. 炮八進三 車2進4
14. 車四平七 馬3進4
15. 車七平六 馬4進2
16. 車八進四
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

改進:
一,當下載JSON格式時,如果根節點的fen等同於INITIAL_FEN,則不必加入。如果r和f屬性是0,則不必加入。

二,在更改了history的move為engine格式之後,去掉了lastMove,然而代碼中還是有不少地方用到lastMove。把它們全部替換為engineToCoords(move) 。

三,文本導入dp format格式時有誤,是否是上面的原因,如果不是,則查找原因並修復。

四,當rotate === truw時,導出pgn格式,它會出現兩個相同的[Rotate]標籤,應該只出現一個,查明原因。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。

gemini pro:

代码: 全选

Because the provided source code is truncated and only includes the constructor, initial state configurations, and CSS definitions[cite: 1], I cannot provide the exact line numbers for the rest of your file. However, here are the specific modifications you need to implement in your methods to fulfill your requirements.

All code and comments are provided in English.

### 1. Modifying JSON Export Logic
When serializing your history nodes (which are based on the `historyFEN` structure[cite: 1]) for JSON download, add conditionals to delete the properties if they match the default values.

```javascript
// Locate your JSON export/serialization function and modify the node formatting:
function formatNodeForJSON(node) {
    // Create a shallow copy to avoid mutating the actual game history
    let exportNode = { ...node };

    // Remove 'fen' if it equals INITIAL_FEN
    if (exportNode.fen === this.INITIAL_FEN) { //[cite: 1]
        delete exportNode.fen;
    }

    // Remove 'r' and 'f' if they are 0
    if (exportNode.r === 0) { //[cite: 1]
        delete exportNode.r;
    }
    if (exportNode.f === 0) { //[cite: 1]
        delete exportNode.f;
    }

    // Continue recursively for variations (exportNode.v)[cite: 1]
    if (exportNode.v && exportNode.v.length > 0) {
        exportNode.v = exportNode.v.map(child => formatNodeForJSON(child));
    }

    return exportNode;
}
```

### 2. Replacing `lastMove`
Since you updated `historyFEN.move` to use the engine format and removed `lastMove`[cite: 1], you must search your entire class methods (like piece drawing, move arrows, or animation logic) for references to `lastMove`.

```javascript
// Search for all occurrences of 'lastMove' in your codebase.
// Replace reads like this:
// let coords = node.lastMove;

// With this:
let coords = this.engineToCoords(node.move); 

// Note: Ensure that 'this.engineToCoords()' returns the exact same array/object structure 
// that 'lastMove' previously held (e.g., [startX, startY, endX, endY]).
```

### 3. Fixing the DP Format Import Bug
The DP import error is almost certainly caused by the removal of `lastMove`. If your DP import logic reads coordinates and still tries to assign or read `lastMove` to process the turn, it will fail because the rest of the codebase now expects `node.move` to hold the engine format[cite: 1].

```javascript
// Locate your DP format import/parsing function.
// Ensure that instead of assigning coordinates to 'lastMove', you convert them 
// to the engine format and assign them to the 'move' property.

// BEFORE (Incorrect):
// parsedNode.lastMove = [startX, startY, endX, endY];

// AFTER (Correct Fix):
// Convert the DP coordinates to the engine string format (e.g., "h2e2")
parsedNode.move = this.coordsToEngine(startX, startY, endX, endY); 

// If the DP parser needs to calculate paths based on the previous move, 
// make sure it uses this.engineToCoords(previousNode.move) to get the coordinates.
```

### 4. Fixing the Duplicate `[Rotate]` Tag in PGN Export
The duplicate tag occurs because `this.pgnMetadata`[cite: 1] might already contain a "Rotate" object from an imported file, while your PGN export function is manually hardcoding a second `[Rotate "1"]` string at the end of the headers when `rotate === true`.

```javascript
// Locate your PGN text generation logic. 
// You likely iterate through this.pgnMetadata[cite: 1] to build the header.
// Add a flag to track if the Rotate tag was already injected by the metadata array.

let pgnHeader = '';
let hasRotateTag = false;

for (let meta of this.pgnMetadata) { //[cite: 1]
    if (meta.value) {
        pgnHeader += `[${meta.name} "${meta.value}"]\n`;
        // Check if the metadata already included the Rotate tag
        if (meta.name === 'Rotate') {
            hasRotateTag = true;
        }
    }
}

// Only append the manual Rotate tag if it wasn't found in the metadata loop
if (rotate === true && !hasRotateTag) {
    pgnHeader += `[Rotate "1"]\n`;
}
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

看看各種格式能否正常導出導入。

json:

代码: 全选

{"c":"看看東萍格式和PGN格式的兵能否正常導出導入。","v":[{"m":"g7g8","v":[{"m":"d9d8","c":"唯一的一步","v":[{"m":"f6f7","v":[{"m":"d8d7","v":[{"m":"g5g6","c":"玩玩","v":[{"m":"d7d8","v":[{"m":"g6f6"}]}]}]}]},{"m":"f5e5","c":"是五兵還是前四更好?"}]}]}],"fen":"3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1","r":1}
pgn1:

代码: 全选

[Game "Chinese Chess"]
[Rotate "true"]
[FEN "3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1"]
[Format "Chinese"]

{看看東萍格式和PGN格式的兵能否正常導出導入。}
1. 一兵進一 將4進1
{唯一的一步}
2. 四兵進一 (2. 五兵平五
{是五兵還是前四更好?})
將4進1
3. 二兵進一{玩玩}
將4退1
4. 二兵平四
*
pgn2:

代码: 全选

[Game "Chinese Chess"]
[Rotate "true"]
[FEN "3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1"]
[Format "ICCS"]

{看看東萍格式和PGN格式的兵能否正常導出導入。}
1. G7-g8 D9-d8
{唯一的一步}
2. F6-f7 (2. F5-e5
{是五兵還是前四更好?})
D8-d7
3. G5-g6{玩玩}
D7-d8
4. G6-f6
*
pgn3:

代码: 全选

[Game "Chinese Chess"]
[Rotate "true"]
[FEN "3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1"]
[Format "WXF"]

{看看東萍格式和PGN格式的兵能否正常導出導入。}
1. Pa+1 K4+1
{唯一的一步}
2. Pd+1 (2. Pe.5
{是五兵還是前四更好?})
K4+1
3. Pb+1{玩玩}
K4-1
4. Pb.4
*
DP1:

代码: 全选

3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1
1. 前三進一 將4進1
2. 後四平五
DP2:

代码: 全选

3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1
看看東萍格式和PGN格式的兵能否正常導出導入。
1. 前三進一 將4進1
唯一的一步
2. 後四平五
是五兵還是前四更好?
DP3:

代码: 全选

3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1
看看東萍格式和PGN格式的兵能否正常導出導入。
1. 前三進一 將4進1
唯一的一步
2. 前四進一 ① 將4進1
3. 中兵進一
玩玩
3. ………… 將4退1
4. 中兵平四

①
2. 後四平五
是五兵還是前四更好?
engine:

代码: 全选

position fen 3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4 w - - 0 1 moves g7g8 d9d8 f5e5
go
URL:

代码: 全选

#3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4,w,-,-,0,1;%E7%9C%8B%E7%9C%8B%E6%9D%B1%E8%90%8D%E6%A0%BC%E5%BC%8F%E5%92%8CPGN%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%85%B5%E8%83%BD%E5%90%A6%E6%AD%A3%E5%B8%B8%E5%B0%8E%E5%87%BA%E5%B0%8E%E5%85%A5%E3%80%82+g7g8+d9d8;%E5%94%AF%E4%B8%80%E7%9A%84%E4%B8%80%E6%AD%A5@f6f7+d8d7+g5g6;%E7%8E%A9%E7%8E%A9+d7d8+g6f6&f5e5;%E6%98%AF%E4%BA%94%E5%85%B5%E9%82%84%E6%98%AF%E5%89%8D%E5%9B%9B%E6%9B%B4%E5%A5%BD%EF%BC%9F
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Ejcees Object</title>
  </head>
  <body>
    <div class="ejcees" mode="main"></div>
    <script src="ejceesobj.js"></script>
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const containers = document.querySelectorAll('.ejcees');
        containers.forEach(container => {
          const mode = container.getAttribute('mode');
          new Ejcees(container, mode);
        });
      });
    </script>
  </body>
</html>


在wordpress中,拿到某attachmentId,替換<script src="ejceesobj.js"></script>。然後在新窗口打開這個html。順帶加上手機端適配。

整個代碼用js來寫,php代碼可直接用<?php>嵌入。



gemini fast:

代码: 全选

這是一個有趣的技術需求。要在 WordPress 中動態生成一個包含特定附件路徑的 HTML 頁面並在新窗口打開,最優雅的方式是利用 JavaScript 構建一個 **Blob URL**。這樣你就不需要真的在服務器上創建一個實體 `.html` 文件。

以下是結合 PHP 和 JavaScript 的解決方案:

### 核心實現代碼

你可以將這段代碼放在你的主題文件(如 `single.php` 或 `footer.php`)中,或者掛載到自定義按鈕的點擊事件上。

```javascript
/**
 * 使用 JavaScript 動態生成並在新窗口打開 Ejcees 頁面
 * @param {number} attachmentId - WordPress 的附件 ID
 */
function openEjceesWindow(attachmentId) {
    // 1. 使用 PHP 獲取附件的完整 URL
    // 我們將路徑存入 JS 變量
    const scriptUrl = "<?php echo wp_get_attachment_url('" + attachmentId + "'); ?>";
    
    if (!scriptUrl) {
        console.error("無法獲取附件 URL");
        return;
    }

    // 2. 定義 HTML 模板,加入手機端適配 (Viewport)
    const htmlContent = `
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>Ejcees Object</title>
    <style>
      body, html { 
        margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; 
        background: #000; /* 根據需要調整背景色 */
      }
      .ejcees { width: 100vw; height: 100vh; }
    </style>
  </head>
  <body>
    <div class="ejcees" mode="main"></div>
    <script src="${scriptUrl}"></script>
    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const containers = document.querySelectorAll('.ejcees');
        containers.forEach(container => {
          const mode = container.getAttribute('mode');
          if (typeof Ejcees !== 'undefined') {
            new Ejcees(container, mode);
          } else {
            console.error('Ejcees 庫加載失敗');
          }
        });
      });
    </script>
  </body>
</html>`;

    // 3. 創建 Blob 並生成 URL
    const blob = new Blob([htmlContent], { type: 'text/html' });
    const url = URL.createObjectURL(blob);

    // 4. 在新窗口打開
    const newWin = window.open(url, '_blank');
    
    // 5. 釋放內存(在窗口關閉或稍後執行)
    if (newWin) {
        newWin.onload = () => URL.revokeObjectURL(url);
    } else {
        alert('請允許彈窗以查看內容');
    }
}
```

---

### 代碼關鍵點說明:

* **手機端適配 (Responsive Design)**:
    * 添加了 `<meta name="viewport" ...>` 標籤,這是移動端適配的靈魂,確保頁面不會被縮小。
    * CSS 部分使用了 `100vw` 和 `100vh` 確保容器撐滿全屏,並移除了默認的邊距。
* **動態腳本路徑**:
    * 通過 `wp_get_attachment_url()` 直接從數據庫獲取該 ID 對應的 `ejceesobj.js` 真實路徑。
* **Blob URL 技術**:
    * `window.open(url, '_blank')` 打開的是一個虛擬路徑(類似 `blob:http://yoursite.com/...`)。這避免了跨域問題,且加載速度極快。
* **安全性與容錯**:
    * 腳本中加入了 `if (typeof Ejcees !== 'undefined')` 檢查,防止因腳本加載失敗導致的 JS 報錯。

### 如何使用?

如果你在 WordPress 後台想通過一個按鈕觸發:

```html
<button onclick="openEjceesWindow(123)">查看 Ejcees 對象</button>
```

**小提醒**:如果你的 `ejceesobj.js` 依賴於其他相對路徑的資源(例如加載同目錄下的 .bin 或 .json 文件),使用 Blob 方法可能會導致路徑偏移。如果出現這種情況,建議直接重定向到一個固定的 `.php` 模板頁面。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

htmlContent內的所有元素都要用document.createElement創建。
<button onclick="openEjceesWindow(19088)">打開Ejcees單頁面</button>

代码: 全选

/**
 * 使用 DOM API 動態構建完整的 HTML 並在新窗口打開
 * @param {number} attachmentId - WordPress 附件 ID
 */
function openEjceesWindow(attachmentId) {
    // 1. 獲取附件 URL (PHP 注入)
    const scriptUrl = "<?php echo wp_get_attachment_url('" + attachmentId + "'); ?>";

    // 2. 創建一個虛擬的 Document
    const doc = document.implementation.createHTMLDocument("Ejcees Object");

    // --- 設定 Head 部分 ---
    const metaCharset = doc.createElement('meta');
    metaCharset.setAttribute('charset', 'UTF-8');
    doc.head.appendChild(metaCharset);

    // 手機端適配 Viewport
    const metaViewport = doc.createElement('meta');
    metaViewport.name = "viewport";
    metaViewport.content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no";
    doc.head.appendChild(metaViewport);

    // 樣式表
    const style = doc.createElement('style');
    style.textContent = `
        body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #000; }
        .ejcees { width: 100vw; height: 100vh; }
    `;
    doc.head.appendChild(style);

    // --- 設定 Body 部分 ---
    const container = doc.createElement('div');
    container.className = 'ejcees';
    container.setAttribute('mode', 'main');
    doc.body.appendChild(container);

    // 引入外部 JS 附件
    const externalScript = doc.createElement('script');
    externalScript.src = scriptUrl;
    doc.body.appendChild(externalScript);

    // 寫入初始化逻辑 JS
    const initScript = doc.createElement('script');
    // 使用 textContent 注入代碼,無需擔心轉義問題
    initScript.textContent = `
        document.addEventListener('DOMContentLoaded', () => {
            const containers = document.querySelectorAll('.ejcees');
            containers.forEach(container => {
                const mode = container.getAttribute('mode');
                if (typeof Ejcees !== 'undefined') {
                    new Ejcees(container, mode);
                } else {
                    console.error('Ejcees Library load failed.');
                }
            });
        });
    `;
    doc.body.appendChild(initScript);

    // 3. 將 Document 轉化為字符串並創建 Blob
    const serializer = new XMLSerializer();
    const htmlString = '<!DOCTYPE html>\n' + serializer.serializeToString(doc);
    
    const blob = new Blob([htmlString], { type: 'text/html' });
    const url = URL.createObjectURL(blob);

    // 4. 打開新窗口
    const newWin = window.open(url, '_blank');
    
    // 5. 清理(可選)
    if (newWin) {
        newWin.onload = () => URL.revokeObjectURL(url);
    }
}

調試:

代码: 全选

/**
 * 強化調試版:使用 DOM API 構建頁面
 */
function openEjceesWindow(attachmentId) {
    console.group('Ejcees Window Debugger');
    
    // 1. 檢查 PHP 傳入的 URL
    const scriptUrl = "<?php echo wp_get_attachment_url('" + attachmentId + "'); ?>";
    console.log('1. 附件 ID:', attachmentId);
    console.log('2. 解析出的 Script URL:', scriptUrl);

    if (!scriptUrl || scriptUrl.trim() === "") {
        console.error('錯誤: 無法獲取 WordPress 附件 URL,請檢查 attachmentId 是否正確。');
        console.groupEnd();
        return;
    }

    try {
        // 2. 構建文檔
        const doc = document.implementation.createHTMLDocument("Ejcees Object");
        
        // Mobile Viewport
        const meta = doc.createElement('meta');
        meta.name = "viewport";
        meta.content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no";
        doc.head.appendChild(meta);

        const style = doc.createElement('style');
        style.textContent = `
            body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #222; color: white; }
            .ejcees { width: 100vw; height: 100vh; display: block; }
            #debug-overlay { position: fixed; top: 10px; left: 10px; background: rgba(0,0,0,0.5); font-size: 12px; z-index: 9999; pointer-events: none; }
        `;
        doc.head.appendChild(style);

        // 3. 容器與調試面板
        const container = doc.createElement('div');
        container.className = 'ejcees';
        container.setAttribute('mode', 'main');
        doc.body.appendChild(container);

        // 在新窗口內增加一個可見的調試層
        const debugDiv = doc.createElement('div');
        debugDiv.id = 'debug-overlay';
        debugDiv.textContent = 'Ejcees Loading...';
        doc.body.appendChild(debugDiv);

        // 4. 外部腳本 (添加載入監控)
        const extScript = doc.createElement('script');
        extScript.src = scriptUrl;
        extScript.onload = () => console.log('新窗口: 外部 JS 載入成功');
        extScript.onerror = () => console.error('新窗口: 外部 JS 載入失敗,路徑可能錯誤');
        doc.body.appendChild(extScript);

        // 5. 初始化腳本 (增加 try-catch)
        const initScript = doc.createElement('script');
        initScript.textContent = `
            console.log('新窗口: 初始化腳本開始執行');
            const debug = document.getElementById('debug-overlay');
            
            window.addEventListener('load', () => {
                debug.textContent += ' | Window Loaded';
                try {
                    const el = document.querySelector('.ejcees');
                    const mode = el.getAttribute('mode');
                    console.log('新窗口: 正在初始化 Ejcees, Mode:', mode);
                    
                    if (typeof Ejcees !== 'undefined') {
                        new Ejcees(el, mode);
                        debug.textContent = 'Ejcees Initialized';
                        console.log('新窗口: Ejcees 實例化完成');
                    } else {
                        throw new Error('找不到 Ejcees 構造函數,請檢查 JS 是否正確導出');
                    }
                } catch (err) {
                    console.error('新窗口運行報錯:', err);
                    debug.style.color = 'red';
                    debug.textContent = 'Error: ' + err.message;
                }
            });
        `;
        doc.body.appendChild(initScript);

        // 6. 序列化並打開
        // 使用 XMLSerializer 時要確保 meta 閉合,或者改用 innerHTML 構建字符串
        const htmlString = `<!DOCTYPE html><html>${doc.documentElement.innerHTML}</html>`;
        console.log('3. 生成的 HTML 字符串長度:', htmlString.length);

        const blob = new Blob([htmlString], { type: 'text/html' });
        const url = URL.createObjectURL(blob);
        
        console.log('4. Blob URL 已生成:', url);
        const newWin = window.open(url, '_blank');
        
        if (!newWin) {
            console.warn('警告: 彈窗被瀏覽器攔截');
        }

    } catch (globalErr) {
        console.error('構建過程出錯:', globalErr);
    }
    
    console.groupEnd();
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

ejceesobj202605011144

解決mini模式下分支顯示出錯。
附件
ejceesobj202605011144.js
(300.76 KiB) 已下载 44 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

改寫importExportedText()中的「// TODO: first convert to engine, then convert to cn word and dc」部分。

應先把word轉成engine格式(如h2e2),然後再轉成中文以及dc。

代码: 全选

改寫importExportedText()中的「// TODO: first convert to engine, then convert to cn word and dc」部分。

應先把word轉成engine格式(如h2e2),然後再轉成中文以及dc。

engine格式轉成PGN格式的方法是this.generatePGNFormat(),參照這個來做。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。
附件
ejceesobj202605011245.js
(301.11 KiB) 已下载 47 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

gemini pro:

代码: 全选

Here is the modified part of the `importExportedText()` method. 

```javascript
          // 1. First convert the input word to engine format (e.g., h2e2)
          let dc = null;
          let moveEn = '';
          let cnWord = '';
          let normalizedWord = word.toLowerCase().replace('-', '');

          if (/^[a-i][0-9][a-i][0-9]$/.test(normalizedWord)) {
            // The word is already in ICCS/engine format
            moveEn = normalizedWord;
          } else {
            // The word is in standard PGN notation, convert it to English notation first
            let isEnglish = /^[a-zA-Z]/.test(word) || /^[+\-=1-9][a-zA-Z0-9]/.test(word);
            let pgnEn = isEnglish ? word : this.NotationConverter.toEnglish(word, isRedTurn);
            
            // Derive temporary coordinates from the PGN notation
            let tempDc = this.deriveCoordsFromPgnMove(currentNode.fen, pgnEn, isRedTurn);
            if (tempDc) {
              // Construct the engine format string
              moveEn = this.coordsToEngine(tempDc.startX, tempDc.startY, tempDc.endX, tempDc.endY);
            }
          }

          // 2. Then convert the engine format to Chinese notation and extract derived coordinates (dc)
          if (moveEn && moveEn.length === 4) {
            // Convert to Chinese PGN notation using the engine format (referenced from this.generatePGNFormat)
            cnWord = this.getNotation(currentNode.fen, moveEn, 'cn');
            
            // Extract the final derived coordinates (dc) from the engine format string
            dc = this.deriveCoordsFromMove(moveEn);
          }
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

為deriveCoordsFromPgnMove增加如「Pb+1」這樣的描述。

代码: 全选

為deriveCoordsFromPgnMove增加如「Pb+1」這樣的描述。

P後面如果加abcde,則說明存在三個及以上的兵在同一列,或者有兩列上有不止一個兵。

如果只有一列,則從前往後數,a為第一個,b為第二個,依次類推。

如果有兩列兵,則從最右列開始,a為第一個,b為第二個,數完之後再到左列的最前面的兵。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。


gemini pro:

代码: 全选

Here is the modified part of the `deriveCoordsFromPgnMove()` method. 

You need to add a new `else if` block (Case 4) to handle the alphabetical prefix logic for pawns immediately after Case 3.

```javascript
    } else if (/[\+\-\=12345]/.test(char1) && /[0-9]/.test(char2)) {
      // Case 3: Prefix + Column Notation specifically for Pawns (e.g., "+3=4", "25+1")
      pieceType = isRed ? 'P' : 'p';
      const startCol = parseInt(char2, 10);
      startX = isRed ? 9 - startCol : startCol - 1;

      // Extract all pawns located on this specific column
      const targetGroup = myPieces.filter(p => p.char === pieceType && p.x === startX);
      if (targetGroup.length > 1) {
        // Sort Front to Back
        targetGroup.sort((a, b) => (isRed ? a.y - b.y : b.y - a.y));
        const candidate = getPieceFromPrefix(targetGroup, char1);
        if (candidate) {
          startY = candidate.y;
        }
      }
    } else if (/[pP]/.test(char1) && /[a-eA-E]/.test(char2)) {
      // Case 4: WXF Pawn Alphabetical Prefix (e.g., "Pa+1", "Pb=2")
      pieceType = isRed ? 'P' : 'p';
      
      const typePieces = myPieces.filter(p => p.char === pieceType);
      const colCounts = {};
      typePieces.forEach(p => {
        colCounts[p.x] = (colCounts[p.x] || 0) + 1;
      });
      
      // Collect all pawns located in columns with more than one pawn
      let multiPawns = typePieces.filter(p => colCounts[p.x] > 1);
      
      // Sort: Rightmost column first, then frontmost to backmost within the column
      multiPawns.sort((a, b) => {
        if (isRed) {
          if (b.x !== a.x) return b.x - a.x; // Rightmost first (highest X)
          return a.y - b.y; // Frontmost first (lowest Y)
        } else {
          if (a.x !== b.x) return a.x - b.x; // Rightmost first (lowest X)
          return b.y - a.y; // Frontmost first (highest Y)
        }
      });
      
      const targetIndex = char2.toLowerCase().charCodeAt(0) - 97; // 'a' -> 0, 'b' -> 1, etc.
      if (targetIndex >= 0 && targetIndex < multiPawns.length) {
        startX = multiPawns[targetIndex].x;
        startY = multiPawns[targetIndex].y;
      }
    }

    // Safety check if notation parsing failed
    if (startX === -1 || startY === -1) {
```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 6009
注册时间: 2022年 11月 18日 17:36
联系:

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

帖子 ejsoon »

如果isRotateEnabled===true,則把fen的第一個-改為r。如果isFlipEnabled===true,則把fen的第二個-改為f。

如果fen等於INITIAL_FEN,則會是if、ir,或irf、ifr。

代码: 全选

改進generateUrlHash(),以及importExportedText()方法下的這段邏輯:
    if (
      text.includes('#') ||
      text.startsWith('i;') ||
      text.startsWith('i+') ||
      text.startsWith('i@') ||
      /^([a-zA-Z0-9]+,)+[wb]/.test(text)
    ) {}

首先,包含「#」是必要條件。

一個fen都會存在兩個-,比如「3k5/9/6P2/5P3/5PP2/6P2/9/9/9/4K4,w,-,-,0,1」。

如果isRotateEnabled===true,則把fen的第一個-改為r。如果isFlipEnabled===true,則把fen的第二個-改為f。

如果fen等於INITIAL_FEN,則會是if、ir,或irf、ifr。

當導入的時候,在更改完isRotateEnabled和isFlipEnabled的值後,仍把fen中的f和r改回-。
附件
ejceesobj202605011341.js
(302.16 KiB) 已下载 45 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复
  • 相似主题
    回复总数
    阅读次数
    最新帖子

在线用户

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