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

Re: 研究提升三菱棋的AI棋力

帖子 ejsoon »

gemini 3.1 pro

代码: 全选

這裡為你整理了所有需要修復與改進的代碼塊。我們將依序解決撤銷重做 BUG、更新規則多語言與 HTML、修復結算面板多語言,以及全面優化 SVG 導出的動畫與數值精度。

### 1. 修改 `I18N` 字典與 `toggleLanguage` (解決第二點)

我們需要在中文和英文的 `rule` 屬性中加入第二段落的計分規則。為了讓換行符號 `<br><br>` 生效,還需要將切換語言時的 `innerText` 修改為 `innerHTML`。

**替換程式碼:** (大約在第 746 行)

```javascript
      // --- 多語言字典 ---
      const I18N = {
        zh: {
          title: '三菱棋',
          sub: '一個抽象策略遊戲,在二維與三維之間',
          ruleTitle: '規則簡介',
          rule: '雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動,分數高者獲勝。<br><br>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分。',
          startBtn: '開始遊戲',
// ... (保留中間其他翻譯) ...

```

**(大約在第 813 行)**

```javascript
        en: {
          title: 'Trirhombus',
          sub: 'An abstract strategy game between 2D and 3D',
          ruleTitle: 'Rules Overview',
          rule: 'Players take turns. The first player must place a blue piece first. The second player must place a red piece first. Play alternates thereafter. Highest score wins.<br><br>Scoring Rules: Players sit opposite each other, so your "up" is the opponent\'s "down". From each perspective, blue pieces are seen as the top face of a cube, while red and orange pieces are the side faces. Each perceived cube scores one point.',
          startBtn: 'Start Game',
// ... (保留中間其他翻譯) ...

```

**(大約在第 1358 行 - `toggleLanguage` 函數中)**

將原本的 `.innerText` 替換為 `.innerHTML`:

```javascript
        document.getElementById('text-title').innerText = getText('title');
        document.getElementById('text-sub').innerText = getText('sub');
        document.getElementById('text-rule-title').innerText = getText('ruleTitle');
        document.getElementById('rule-content').innerHTML = getText('rule'); // 這裡改用 innerHTML
        document.getElementById('text-start-btn').innerText = getText('startBtn');

```

---

### 2. 更新 HTML 中初始顯示的規則文字 (解決第二點)

請找到 `<div id="start-screen">` 內部的 `#rule-content` 元素,並同步更新它的初始 HTML:

**替換程式碼:** (大約在第 356 行)

```html
        <div class="rules-content" id="rule-content">
          雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動,分數高者獲勝。<br><br>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分。
        </div>

```

---

### 3. 修復後退(Undo)時棋子不消失的問題 (解決第一點)

由於你在盤面上新增了小白點 (`last-move-indicator`) 作為提示,它成為了 `etanidrop` 的 `lastChild`,導致原本依賴 `lastChild` 檢查 `.tiledropped` 的刪除邏輯失效。我們改為精準選取最後一個 `tiledropped` 元素。

**替換程式碼:** (在 `undoMove()` 函數中,大約第 1121 行)

```javascript
            let scores = gameLogic.undo();
            p1CurrentScore = scores.p1Score;
            p2CurrentScore = scores.p2Score;
            piecesLeft[move.player][move.pid]++;
            historyIndex--;

            let dropG = document.getElementById('etanidrop');
            let tiles = dropG.querySelectorAll('.tiledropped');
            if (tiles.length > 0) {
              dropG.removeChild(tiles[tiles.length - 1]);
            }

            isFirstMove = historyIndex < roundStart;

```

---

### 4. 修復結算視窗的語言顯示問題 (解決第三點)

把寫死的 `P1(我方)` 等字眼替換為動態獲取 `I18N` 的值。

**替換程式碼:** (在 `showRoundEnd()` 函數中,大約第 1419 行)

```javascript
        if (currentRound === 1) {
          p1Round1Score = s1;
          p2Round1Score = s2;
          p1TotalScore = s1;
          p2TotalScore = s2;
          title.innerText = getText('gameOver') + ' - Round 1';
          scoresDiv.innerHTML = `${getText('round1Score')}<br>${getText('p1You')}: ${s1} - ${getText('p2Opp')}: ${s2}`;

          actionsDiv.innerHTML = `
            <button class="btn-secondary" onclick="finalEnd()">${getText('endGameBtn')}</button>
            <button class="btn-primary" onclick="startRound2()">${getText('swapBtn')}</button>
          `;
        } else {
          p1TotalScore = p1Round1Score + s1;
          p2TotalScore = p2Round1Score + s2;
          title.innerText = getText('gameOver') + ' - Final';
          let winnerText =
            p1TotalScore > p2TotalScore
              ? getText('winnerMe')
              : p2TotalScore > p1TotalScore
                ? getText('winnerOpp')
                : getText('draw');

          scoresDiv.innerHTML = `
            ${getText('round2Score')} ${getText('p1You')}: ${s1} - ${getText('p2Opp')}: ${s2}<br>
            <hr style="margin:15px 0;">
            <strong>${getText('totalScore')} ${getText('p1You')}: ${p1TotalScore} - ${getText('p2Opp')}: ${p2TotalScore}</strong><br>
            <span style="color:var(--p2-color)">${winnerText}</span>
          `;
          actionsDiv.innerHTML = `<button class="btn-primary" onclick="restartGame()">${getText('restartBtn')}</button>`;
        }

```

---

### 5. 優化 SVG 動畫導出與數值修復 (解決第四點)

加入過濾多餘小數點的格式化函數 `fmt()`,動態計算文本動畫相對於當前視圖 `pan` 及 `scale` 的坐標,並為所有棋子加入專屬的初始退場動畫。

**替換程式碼:** (覆蓋整個 `updateDlPreview` 函數,大約第 1217 行)

```javascript
      function updateDlPreview() {
        const originalSvg = document.getElementById('etani');
        let svgClone = originalSvg.cloneNode(true);
        svgClone.setAttribute('id', 'etani-preview');

        // 定義數字格式化,最多 3 位小數並自動去掉末尾多餘的 0
        const fmt = v => Number(v.toFixed(3));

        let gridOpt = document.getElementById('dl-opt-grid').checked;
        let numOpt = document.getElementById('dl-opt-num').checked;
        let animOpt = document.getElementById('dl-opt-anim').checked;

        // 1. 處理網格
        if (!gridOpt) {
          let etboard = svgClone.querySelector('.etboard');
          let gridPath = etboard.querySelector('path');
          if (gridPath) gridPath.remove();
        }

        // 2. 獲取當前局的所有合法移動
        let roundStart = currentRound === 2 ? 36 : 0;
        let activeMoves = moveHistory.slice(roundStart, historyIndex + 1);

        // 3. 處理數字與動畫:重構 etdrop 內的棋子,確保順序與 ID 正確
        let etdrop = svgClone.querySelector('.etdrop');
        // 保留 board (含網格與紫點)
        let etboard = etdrop.querySelector('.etboard');
        etdrop.innerHTML = '';
        etdrop.appendChild(etboard);

        // 加入自定義字體
        if (numOpt || animOpt) {
          let styleEl = document.createElement('style');
          styleEl.innerHTML = `
            @font-face {
              font-family: 'ZT Nature';
              src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2');
              font-weight: normal;
              font-style: normal;
              font-display: swap;
            }
          `;
          etboard.appendChild(styleEl);
        }

        // 準備全域動畫基底
        if (animOpt) {
          etdrop.setAttribute('opacity', '0');
          let baseAnim = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
          baseAnim.setAttribute('id', 'tr0');
          baseAnim.setAttribute('begin', '0;trend.end');
          baseAnim.setAttribute('attributeName', 'opacity');
          baseAnim.setAttribute('values', '0;0;1');
          baseAnim.setAttribute('fill', 'freeze');
          baseAnim.setAttribute('dur', '2s');
          etdrop.appendChild(baseAnim);
        }

        // 重繪所有目前局的棋子
        activeMoves.forEach((m, i) => {
          let px = fmt(m.px);
          let py = fmt(m.py);
          let useNode = document.createElementNS('http://www.w3.org/2000/svg', 'use');
          useNode.setAttribute('href', `#tile${m.pid}`);
          useNode.setAttribute('class', 'tiledropped');
          useNode.setAttribute('fill', TILE_COLORS[m.pid]);
          useNode.setAttribute('transform', `translate(${px}, ${py})`);

          if (animOpt) {
            let outY = fmt(m.player === 1 ? (480 - panY) / currentScale + 100 : -panY / currentScale - 100);

            // 加入初始動畫,讓棋子從目前的位置瞬間移出視窗(模擬退場的起始態)
            let initAnim = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
            initAnim.setAttribute('attributeName', 'transform');
            initAnim.setAttribute('attributeType', 'XML');
            initAnim.setAttribute('type', 'translate');
            initAnim.setAttribute('from', `${px},${py}`);
            initAnim.setAttribute('to', `${px},${outY}`);
            initAnim.setAttribute('dur', '1s');
            initAnim.setAttribute('fill', 'freeze');
            initAnim.setAttribute('begin', 'tr0.begin');
            useNode.appendChild(initAnim);

            let animNode = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
            animNode.setAttribute('id', `tr${i + 1}`);
            animNode.setAttribute('attributeName', 'transform');
            animNode.setAttribute('attributeType', 'XML');
            animNode.setAttribute('type', 'translate');
            animNode.setAttribute('from', `${px},${outY}`);
            animNode.setAttribute('to', `${px},${py}`);
            animNode.setAttribute('dur', '1s');
            animNode.setAttribute('fill', 'freeze');
            animNode.setAttribute('begin', `tr${i}.end`);
            useNode.appendChild(animNode);
          }
          etdrop.appendChild(useNode);

          // 處理數字
          if (numOpt) {
            let halfWidth = 31.1769;
            let cx1 = m.t1.isRight ? (m.t1.idx - 1) * halfWidth + 10.392 : (m.t1.idx - 1) * halfWidth + 20.784;
            let cy1 = m.t1.N * 18;

            let isRight2 = gameLogic.isRight(m.t2.idx, m.t2.N);
            let cx2 = isRight2 ? (m.t2.idx - 1) * halfWidth + 10.392 : (m.t2.idx - 1) * halfWidth + 20.784;
            let cy2 = m.t2.N * 18;

            let pieceCx = (cx1 + cx2) / 2;
            let pieceCy = (cy1 + cy2) / 2;

            let numStr = String(i + 1);
            let offsetX1 = -7,
              offsetY1 = 8;
            let offsetX2 = -14,
              offsetY2 = 8;
            let dx = numStr.length === 1 ? offsetX1 : offsetX2;
            let dy = numStr.length === 1 ? offsetY1 : offsetY2;

            let textNode = document.createElementNS('http://www.w3.org/2000/svg', 'text');
            textNode.setAttribute('x', fmt(pieceCx + dx).toString());
            textNode.setAttribute('y', fmt(pieceCy + dy).toString());
            textNode.setAttribute('stroke', 'none');
            textNode.setAttribute('fill', 'black');
            textNode.setAttribute('font-size', '24');
            textNode.setAttribute('font-family', 'ZT Nature');
            textNode.textContent = numStr;
            etdrop.appendChild(textNode);
          }
        });

        // 4. 動畫結算邏輯
        if (animOpt && activeMoves.length > 0) {
          let lastTrId = `tr${activeMoves.length}`;
          let trmeBase = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
          trmeBase.setAttribute('id', 'trme');
          trmeBase.setAttribute('begin', `${lastTrId}.end+1s`);
          trmeBase.setAttribute('dur', '4s');
          etdrop.appendChild(trmeBase);

          let trheBase = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
          trheBase.setAttribute('id', 'trhe');
          trheBase.setAttribute('begin', 'trme.end+1s');
          trheBase.setAttribute('dur', '4s');
          etdrop.appendChild(trheBase);

          let finalScores = gameLogic.calculateScores();
          let useElements = etdrop.querySelectorAll('.tiledropped');

          // 計算無用棋子 (拔掉後對應玩家分數不變)
          for (let i = 0; i < activeMoves.length; i++) {
            let testLogic = new HexGridGame();
            for (let j = 0; j < activeMoves.length; j++) {
              if (i === j) continue;
              let m = activeMoves[j];
              testLogic.tryPlacePiece(m.pid + 1, { x: m.t1.idx, y: m.t1.N }, { x: m.t2.idx, y: m.t2.N }, true);
            }
            let s = testLogic.calculateScores();

            let m = activeMoves[i];
            let px = fmt(m.px);
            let py = fmt(m.py);
            let len = Math.hypot(m.px, m.py) || 1;
            let outX = fmt(m.px + (m.px / len) * 400);
            let outY2 = fmt(m.py + (m.py / len) * 400);

            // 我方(P1)無用棋子
            if (s.p1Score === finalScores.p1Score) {
              let anim = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
              anim.setAttribute('attributeName', 'transform');
              anim.setAttribute('attributeType', 'XML');
              anim.setAttribute('type', 'translate');
              anim.setAttribute(
                'values',
                `${px},${py}; ${outX},${outY2}; ${outX},${outY2}; ${outX},${outY2}; ${px},${py}`
              );
              anim.setAttribute('dur', '4s');
              anim.setAttribute('fill', 'freeze');
              anim.setAttribute('begin', 'trme.begin');
              useElements[i].appendChild(anim);
            }
            // 對方(P2)無用棋子
            if (s.p2Score === finalScores.p2Score) {
              let anim = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
              anim.setAttribute('attributeName', 'transform');
              anim.setAttribute('attributeType', 'XML');
              anim.setAttribute('type', 'translate');
              anim.setAttribute(
                'values',
                `${px},${py}; ${outX},${outY2}; ${outX},${outY2}; ${outX},${outY2}; ${px},${py}`
              );
              anim.setAttribute('dur', '4s');
              anim.setAttribute('fill', 'freeze');
              anim.setAttribute('begin', 'trhe.begin');
              useElements[i].appendChild(anim);
            }
          }

          // 添加分數文字動畫:動態計算相對於縮放及平移的畫面坐標
          let p1TextX = fmt((480 - panX) / currentScale + 12 / currentScale);
          let p1TextY = fmt((480 - panY) / currentScale - 12 / currentScale);
          let p1SlideX = fmt(-144 / currentScale);

          let p1Text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
          p1Text.setAttribute('id', 'trmetxt');
          p1Text.setAttribute('x', p1TextX.toString());
          p1Text.setAttribute('y', p1TextY.toString());
          p1Text.setAttribute('stroke', 'none');
          p1Text.setAttribute('fill', 'black');
          p1Text.setAttribute('font-size', '60');
          p1Text.setAttribute('font-family', 'ZT Nature');
          p1Text.textContent = finalScores.p1Score.toString();

          let p1Anim = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
          p1Anim.setAttribute('attributeName', 'transform');
          p1Anim.setAttribute('attributeType', 'XML');
          p1Anim.setAttribute('type', 'translate');
          p1Anim.setAttribute('values', `0,0; ${p1SlideX},0; ${p1SlideX},0; ${p1SlideX},0; 0,0`);
          p1Anim.setAttribute('dur', '4s');
          p1Anim.setAttribute('fill', 'freeze');
          p1Anim.setAttribute('begin', 'trme.begin');
          p1Text.appendChild(p1Anim);
          etboard.appendChild(p1Text);

          let p2TextX = fmt(panX / currentScale + 12 / currentScale);
          let p2TextY = fmt(panY / currentScale - 12 / currentScale);
          let p2SlideX = fmt(-144 / currentScale);

          let p2Text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
          p2Text.setAttribute('id', 'trhetxt');
          p2Text.setAttribute('x', p2TextX.toString());
          p2Text.setAttribute('y', p2TextY.toString());
          p2Text.setAttribute('stroke', 'none');
          p2Text.setAttribute('fill', 'black');
          p2Text.setAttribute('font-size', '60');
          p2Text.setAttribute('font-family', 'ZT Nature');
          p2Text.setAttribute('transform', 'rotate(180)');
          p2Text.textContent = finalScores.p2Score.toString();

          let p2Anim = document.createElementNS('http://www.w3.org/2000/svg', 'animateTransform');
          p2Anim.setAttribute('attributeName', 'transform');
          p2Anim.setAttribute('attributeType', 'XML');
          p2Anim.setAttribute('type', 'translate');
          p2Anim.setAttribute('values', `0,0; ${p2SlideX},0; ${p2SlideX},0; ${p2SlideX},0; 0,0`);
          p2Anim.setAttribute('dur', '4s');
          p2Anim.setAttribute('fill', 'freeze');
          p2Anim.setAttribute('additive', 'sum'); // 疊加在 rotate(180) 上
          p2Anim.setAttribute('begin', 'trhe.begin');
          p2Text.appendChild(p2Anim);
          etboard.appendChild(p2Text);

          // 結尾漸隱
          let endAnim = document.createElementNS('http://www.w3.org/2000/svg', 'animate');
          endAnim.setAttribute('id', 'trend');
          endAnim.setAttribute('begin', 'trhe.end+1s');
          endAnim.setAttribute('attributeName', 'opacity');
          endAnim.setAttribute('values', '1;1;0');
          endAnim.setAttribute('fill', 'freeze');
          endAnim.setAttribute('dur', '2s');
          etdrop.appendChild(endAnim);
        }

        // 5. 序列化與渲染預覽
        let serializer = new XMLSerializer();
        currentDlSvgSource = serializer.serializeToString(svgClone);
        if (!currentDlSvgSource.match(/^<svg[^>]+xmlns="http\:\/\/www\.w3\.org\/2000\/svg"/)) {
          currentDlSvgSource = currentDlSvgSource.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
        }

        document.getElementById('dl-preview-container').innerHTML = '';
        document.getElementById('dl-preview-container').appendChild(svgClone);

        let sizeKb = new Blob([currentDlSvgSource]).size.toLocaleString();
        document.getElementById('dl-size').innerText = sizeKb + ' Bytes';
      }

```

代码: 全选

好的,為你調整 **第 1 點(I18N 字典)** 與 **第 2 點(HTML 初始文字)** 的修改方案。我們將文字更新為包含「立方體可堆疊累加」,並將原本的 `<br><br>` 全部替換為更符合語意且結構乾淨的 `<p>` 標籤。

### 1. 修改 `I18N` 字典與 `toggleLanguage`

請將 JavaScript 中的 `I18N` 字典中關於 `rule` 的部分替換為以下程式碼(包含英文翻譯的更新):

**替換程式碼:** (大約在第 746 行起)

```javascript
      // --- 多語言字典 ---
      const I18N = {
        zh: {
          title: '三菱棋',
          sub: '一個抽象策略遊戲,在二維與三維之間',
          ruleTitle: '規則簡介',
          rule: '<p>雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動,分數高者獲勝。</p><p>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。</p>',
          startBtn: '開始遊戲',
// ... (保留中間其他中文翻譯) ...

```

**(大約在第 813 行起)**

```javascript
        en: {
          title: 'Trirhombus',
          sub: 'An abstract strategy game between 2D and 3D',
          ruleTitle: 'Rules Overview',
          rule: '<p>Players take turns. The first player must place a blue piece first. The second player must place a red piece first. Play alternates thereafter. Highest score wins.</p><p>Scoring Rules: Players sit opposite each other, so your "up" is the opponent\'s "down". From each perspective, blue pieces are seen as the top face of a cube, while red and orange pieces are the side faces. Each perceived cube scores one point, and cubes can be stacked and accumulated.</p>',
          startBtn: 'Start Game',
// ... (保留中間其他英文翻譯) ...

```

*註:請確保在 `toggleLanguage` 函數中,`document.getElementById('rule-content')` 依然是使用 `.innerHTML` 賦值(如前一次修改所示),這樣 `<p>` 標籤才能正確渲染。*

---

### 2. 更新 HTML 中初始顯示的規則文字

同步將 HTML 結構中初始顯示的文字改用 `<p>` 標籤包裹:

**替換程式碼:** (大約在第 356 行)

```html
        <div class="rules-content" id="rule-content">
          <p>雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動,分數高者獲勝。</p>
          <p>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。</p>
        </div>

```

*(提示:如果使用 `<p>` 標籤後發現段落上下的間距過大或過小,可以在 CSS 的 `#rule-content p` 中加入 `margin: 10px 0;` 進行微調。)*
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
帖子: 6318
注册时间: 2022年 11月 18日 17:36
联系:

Re: 研究提升三菱棋的AI棋力

帖子 ejsoon »

trirhombus2880.html

導出動畫以及標數字的功能已做好。

規則需要加上一句「除了第一個棋子之外,所落下的棋子必須跟場上已有棋子貼合。」
附件
trirhombus2880.html.7z
(35.5 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
帖子: 6318
注册时间: 2022年 11月 18日 17:36
联系:

Re: 研究提升三菱棋的AI棋力

帖子 ejsoon »

輸給expert,所以現在的AI已經足夠強了。

代码: 全选

[(0,0),(1,0)] [(0,-2),(0,-1)] [(0,1),(0,2)] [(1,-2),(1,-1)] [(1,1),(1,2)] [(1,3),(2,3)] [(2,4),(2,5)] [(0,4),(1,4)] [(0,5),(0,6)] [(2,-1),(2,0)] [(-1,-3),(0,-3)] [(-1,1),(-1,2)] [(-1,-2),(-1,-1)] [(-2,-2),(-2,-1)] [(1,5),(1,6)] [(-3,-1),(-3,0)] [(3,-1),(3,0)] [(3,-3),(3,-2)] [(2,-4),(3,-4)] [(3,1),(4,1)] [(4,0),(5,0)] [(-1,-5),(-1,-4)] [(0,-6),(0,-5)] [(3,4),(3,5)] [(2,-3),(2,-2)] [(5,-2),(5,-1)] [(3,-5),(4,-5)] [(2,1),(2,2)] [(6,-2),(6,-1)] [(-1,3),(0,3)] [(-1,4),(-1,5)] [(2,6),(3,6)] [(2,7),(2,8)] [(-2,0),(-1,0)] [(5,-3),(6,-3)] [(3,2),(3,3)] [(0,0),(1,0)] [(1,1),(1,2)] [(0,-2),(0,-1)] [(0,1),(0,2)] [(2,1),(2,2)] [(1,-1),(2,-1)] [(1,3),(2,3)] [(3,1),(3,2)] [(2,-3),(2,-2)] [(2,-4),(3,-4)] [(0,4),(1,4)] [(3,-3),(3,-2)] [(4,-3),(4,-2)] [(2,0),(3,0)] [(2,-6),(2,-5)] [(-1,-3),(0,-3)] [(-1,-1),(-1,0)] [(-2,-1),(-2,0)] [(4,-5),(4,-4)] [(-2,1),(-2,2)] [(-1,-5),(-1,-4)] [(-1,1),(-1,2)] [(3,-6),(3,-5)] [(-2,-2),(-1,-2)] [(0,-5),(0,-4)] [(-3,-2),(-3,-1)] [(-1,3),(0,3)] [(-3,0),(-3,1)] [(1,-3),(1,-2)] [(-3,-3),(-2,-3)] [(1,-5),(1,-4)] [(1,5),(1,6)] [(-1,5),(0,5)] [(-1,6),(-1,7)] [(3,-1),(4,-1)] [(0,6),(0,7)]
Screenshot from 2026-07-22 09-10-59.png
Screenshot from 2026-07-22 09-10-59.png (12.34 KiB) 查看 38 次

代码: 全选

<svg id="etani-preview" version="1.1" xmlns="http://www.w3.org/2000/svg" width="480" height="480" viewBox="0 0 480 480" preserveAspectRatio="xMidYMid meet">
          <defs>
            <g id="tile0"><path d="M 0,-18 L 31.177,0 L 0,18 L -31.177,0 Z"/></g>
            <g id="tile1"><path d="M 15.588,9 L -15.588,27 L -15.588,-9 L 15.588,-27 Z"/></g>
            <g id="tile2"><path d="M -15.588,9 L -15.588,-27 L 15.588,-9 L 15.588,27 Z"/></g>
          </defs>
          <g class="etdrop" stroke="#777" stroke-width="2" stroke-linejoin="round" transform="translate(206.000, 214.000) scale(1.240)" id="etanidrop"><g class="etboard"><path d="M -1496.491,-1200 L -1496.491,1200 M -1465.314,-1200 L -1465.314,1200 M -1434.137,-1200 L -1434.137,1200 M -1402.960,-1200 L -1402.960,1200 M -1371.784,-1200 L -1371.784,1200 M -1340.607,-1200 L -1340.607,1200 M -1309.430,-1200 L -1309.430,1200 M -1278.253,-1200 L -1278.253,1200 M -1247.076,-1200 L -1247.076,1200 M -1215.899,-1200 L -1215.899,1200 M -1184.722,-1200 L -1184.722,1200 M -1153.545,-1200 L -1153.545,1200 M -1122.368,-1200 L -1122.368,1200 M -1091.191,-1200 L -1091.191,1200 M -1060.015,-1200 L -1060.015,1200 M -1028.838,-1200 L -1028.838,1200 M -997.661,-1200 L -997.661,1200 M -966.484,-1200 L -966.484,1200 M -935.307,-1200 L -935.307,1200 M -904.130,-1200 L -904.130,1200 M -872.953,-1200 L -872.953,1200 M -841.776,-1200 L -841.776,1200 M -810.599,-1200 L -810.599,1200 M -779.423,-1200 L -779.423,1200 M -748.246,-1200 L -748.246,1200 M -717.069,-1200 L -717.069,1200 M -685.892,-1200 L -685.892,1200 M -654.715,-1200 L -654.715,1200 M -623.538,-1200 L -623.538,1200 M -592.361,-1200 L -592.361,1200 M -561.184,-1200 L -561.184,1200 M -530.007,-1200 L -530.007,1200 M -498.830,-1200 L -498.830,1200 M -467.654,-1200 L -467.654,1200 M -436.477,-1200 L -436.477,1200 M -405.300,-1200 L -405.300,1200 M -374.123,-1200 L -374.123,1200 M -342.946,-1200 L -342.946,1200 M -311.769,-1200 L -311.769,1200 M -280.592,-1200 L -280.592,1200 M -249.415,-1200 L -249.415,1200 M -218.238,-1200 L -218.238,1200 M -187.061,-1200 L -187.061,1200 M -155.885,-1200 L -155.885,1200 M -124.708,-1200 L -124.708,1200 M -93.531,-1200 L -93.531,1200 M -62.354,-1200 L -62.354,1200 M -31.177,-1200 L -31.177,1200 M 0.000,-1200 L 0.000,1200 M 31.177,-1200 L 31.177,1200 M 62.354,-1200 L 62.354,1200 M 93.531,-1200 L 93.531,1200 M 124.708,-1200 L 124.708,1200 M 155.885,-1200 L 155.885,1200 M 187.061,-1200 L 187.061,1200 M 218.238,-1200 L 218.238,1200 M 249.415,-1200 L 249.415,1200 M 280.592,-1200 L 280.592,1200 M 311.769,-1200 L 311.769,1200 M 342.946,-1200 L 342.946,1200 M 374.123,-1200 L 374.123,1200 M 405.300,-1200 L 405.300,1200 M 436.477,-1200 L 436.477,1200 M 467.654,-1200 L 467.654,1200 M 498.830,-1200 L 498.830,1200 M 530.007,-1200 L 530.007,1200 M 561.184,-1200 L 561.184,1200 M 592.361,-1200 L 592.361,1200 M 623.538,-1200 L 623.538,1200 M 654.715,-1200 L 654.715,1200 M 685.892,-1200 L 685.892,1200 M 717.069,-1200 L 717.069,1200 M 748.246,-1200 L 748.246,1200 M 779.423,-1200 L 779.423,1200 M 810.599,-1200 L 810.599,1200 M 841.776,-1200 L 841.776,1200 M 872.953,-1200 L 872.953,1200 M 904.130,-1200 L 904.130,1200 M 935.307,-1200 L 935.307,1200 M 966.484,-1200 L 966.484,1200 M 997.661,-1200 L 997.661,1200 M 1028.838,-1200 L 1028.838,1200 M 1060.015,-1200 L 1060.015,1200 M 1091.191,-1200 L 1091.191,1200 M 1122.368,-1200 L 1122.368,1200 M 1153.545,-1200 L 1153.545,1200 M 1184.722,-1200 L 1184.722,1200 M 1215.899,-1200 L 1215.899,1200 M 1247.076,-1200 L 1247.076,1200 M 1278.253,-1200 L 1278.253,1200 M 1309.430,-1200 L 1309.430,1200 M 1340.607,-1200 L 1340.607,1200 M 1371.784,-1200 L 1371.784,1200 M 1402.960,-1200 L 1402.960,1200 M 1434.137,-1200 L 1434.137,1200 M 1465.314,-1200 L 1465.314,1200 M 1496.491,-1200 L 1496.491,1200 M -1200,-1574.820 L 1200,-189.180 M -1200,-153.180 L 1200,-1538.820 M -1200,-1538.820 L 1200,-153.180 M -1200,-117.180 L 1200,-1502.820 M -1200,-1502.820 L 1200,-117.180 M -1200,-81.180 L 1200,-1466.820 M -1200,-1466.820 L 1200,-81.180 M -1200,-45.180 L 1200,-1430.820 M -1200,-1430.820 L 1200,-45.180 M -1200,-9.180 L 1200,-1394.820 M -1200,-1394.820 L 1200,-9.180 M -1200,26.820 L 1200,-1358.820 M -1200,-1358.820 L 1200,26.820 M -1200,62.820 L 1200,-1322.820 M -1200,-1322.820 L 1200,62.820 M -1200,98.820 L 1200,-1286.820 M -1200,-1286.820 L 1200,98.820 M -1200,134.820 L 1200,-1250.820 M -1200,-1250.820 L 1200,134.820 M -1200,170.820 L 1200,-1214.820 M -1200,-1214.820 L 1200,170.820 M -1200,206.820 L 1200,-1178.820 M -1200,-1178.820 L 1200,206.820 M -1200,242.820 L 1200,-1142.820 M -1200,-1142.820 L 1200,242.820 M -1200,278.820 L 1200,-1106.820 M -1200,-1106.820 L 1200,278.820 M -1200,314.820 L 1200,-1070.820 M -1200,-1070.820 L 1200,314.820 M -1200,350.820 L 1200,-1034.820 M -1200,-1034.820 L 1200,350.820 M -1200,386.820 L 1200,-998.820 M -1200,-998.820 L 1200,386.820 M -1200,422.820 L 1200,-962.820 M -1200,-962.820 L 1200,422.820 M -1200,458.820 L 1200,-926.820 M -1200,-926.820 L 1200,458.820 M -1200,494.820 L 1200,-890.820 M -1200,-890.820 L 1200,494.820 M -1200,530.820 L 1200,-854.820 M -1200,-854.820 L 1200,530.820 M -1200,566.820 L 1200,-818.820 M -1200,-818.820 L 1200,566.820 M -1200,602.820 L 1200,-782.820 M -1200,-782.820 L 1200,602.820 M -1200,638.820 L 1200,-746.820 M -1200,-746.820 L 1200,638.820 M -1200,674.820 L 1200,-710.820 M -1200,-710.820 L 1200,674.820 M -1200,710.820 L 1200,-674.820 M -1200,-674.820 L 1200,710.820 M -1200,746.820 L 1200,-638.820 M -1200,-638.820 L 1200,746.820 M -1200,782.820 L 1200,-602.820 M -1200,-602.820 L 1200,782.820 M -1200,818.820 L 1200,-566.820 M -1200,-566.820 L 1200,818.820 M -1200,854.820 L 1200,-530.820 M -1200,-530.820 L 1200,854.820 M -1200,890.820 L 1200,-494.820 M -1200,-494.820 L 1200,890.820 M -1200,926.820 L 1200,-458.820 M -1200,-458.820 L 1200,926.820 M -1200,962.820 L 1200,-422.820 M -1200,-422.820 L 1200,962.820 M -1200,998.820 L 1200,-386.820 M -1200,-386.820 L 1200,998.820 M -1200,1034.820 L 1200,-350.820 M -1200,-350.820 L 1200,1034.820 M -1200,1070.820 L 1200,-314.820 M -1200,-314.820 L 1200,1070.820 M -1200,1106.820 L 1200,-278.820 M -1200,-278.820 L 1200,1106.820 M -1200,1142.820 L 1200,-242.820 M -1200,-242.820 L 1200,1142.820 M -1200,1178.820 L 1200,-206.820 M -1200,-206.820 L 1200,1178.820 M -1200,1214.820 L 1200,-170.820 M -1200,-170.820 L 1200,1214.820 M -1200,1250.820 L 1200,-134.820 M -1200,-134.820 L 1200,1250.820 M -1200,1286.820 L 1200,-98.820 M -1200,-98.820 L 1200,1286.820 M -1200,1322.820 L 1200,-62.820 M -1200,-62.820 L 1200,1322.820 M -1200,1358.820 L 1200,-26.820 M -1200,-26.820 L 1200,1358.820 M -1200,1394.820 L 1200,9.180 M -1200,9.180 L 1200,1394.820 M -1200,1430.820 L 1200,45.180 M -1200,45.180 L 1200,1430.820 M -1200,1466.820 L 1200,81.180 M -1200,81.180 L 1200,1466.820 M -1200,1502.820 L 1200,117.180 M -1200,117.180 L 1200,1502.820 M -1200,1538.820 L 1200,153.180 " stroke="#b0b0b0" stroke-width="1" stroke-dasharray="5 5" fill="none"/><style xmlns="http://www.w3.org/1999/xhtml">
            @font-face {
              font-family: 'ZT Nature';
              src: url('data:font/woff2;charset=utf-8;base64,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') format('woff2');
              font-weight: normal;
              font-style: normal;
              font-display: swap;
            }
          </style></g><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(0, 0)"/><text x="-7" y="8" stroke="none" fill="black" font-size="24" font-family="ZT Nature">1</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(15.588, 27)"/><text x="8.588" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">2</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(-15.589, -27)"/><text x="-22.589" y="-19" stroke="none" fill="black" font-size="24" font-family="ZT Nature">3</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-15.589, 27)"/><text x="-22.589" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">4</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(46.765, 27)"/><text x="39.765" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">5</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(31.177, -18)"/><text x="24.176" y="-10" stroke="none" fill="black" font-size="24" font-family="ZT Nature">6</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(31.176, 54)"/><text x="24.176" y="62" stroke="none" fill="black" font-size="24" font-family="ZT Nature">7</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(77.942, 27)"/><text x="70.942" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">8</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(46.765, -45)"/><text x="39.765" y="-37" stroke="none" fill="black" font-size="24" font-family="ZT Nature">9</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(62.354, -72)"/><text x="48.353" y="-64" stroke="none" fill="black" font-size="24" font-family="ZT Nature">10</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-0.001, 72)"/><text x="-14" y="80" stroke="none" fill="black" font-size="24" font-family="ZT Nature">11</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(77.942, -45)"/><text x="63.942" y="-37" stroke="none" fill="black" font-size="24" font-family="ZT Nature">12</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(109.119, -45)"/><text x="95.119" y="-37" stroke="none" fill="black" font-size="24" font-family="ZT Nature">13</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(62.353, 0)"/><text x="48.353" y="8" stroke="none" fill="black" font-size="24" font-family="ZT Nature">14</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(46.765, -99)"/><text x="32.765" y="-91" stroke="none" fill="black" font-size="24" font-family="ZT Nature">15</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-31.178, -54)"/><text x="-45.177" y="-46" stroke="none" fill="black" font-size="24" font-family="ZT Nature">16</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(-46.766, -9)"/><text x="-60.766" y="-1" stroke="none" fill="black" font-size="24" font-family="ZT Nature">17</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-77.943, -9)"/><text x="-91.943" y="-1" stroke="none" fill="black" font-size="24" font-family="ZT Nature">18</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(109.119, -81)"/><text x="95.119" y="-73" stroke="none" fill="black" font-size="24" font-family="ZT Nature">19</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-77.943, 27)"/><text x="-91.943" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">20</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(-46.766, -81)"/><text x="-60.766" y="-73" stroke="none" fill="black" font-size="24" font-family="ZT Nature">21</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(-46.766, 27)"/><text x="-60.766" y="35" stroke="none" fill="black" font-size="24" font-family="ZT Nature">22</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(77.942, -99)"/><text x="63.942" y="-91" stroke="none" fill="black" font-size="24" font-family="ZT Nature">23</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-62.355, -36)"/><text x="-76.354" y="-28" stroke="none" fill="black" font-size="24" font-family="ZT Nature">24</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-15.589, -81)"/><text x="-29.589" y="-73" stroke="none" fill="black" font-size="24" font-family="ZT Nature">25</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-109.12, -27)"/><text x="-123.12" y="-19" stroke="none" fill="black" font-size="24" font-family="ZT Nature">26</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-31.178, 54)"/><text x="-45.177" y="62" stroke="none" fill="black" font-size="24" font-family="ZT Nature">27</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-109.12, 9)"/><text x="-123.12" y="17" stroke="none" fill="black" font-size="24" font-family="ZT Nature">28</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(15.588, -45)"/><text x="1.588" y="-37" stroke="none" fill="black" font-size="24" font-family="ZT Nature">29</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-93.531, -54)"/><text x="-107.531" y="-46" stroke="none" fill="black" font-size="24" font-family="ZT Nature">30</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(15.588, -81)"/><text x="1.588" y="-73" stroke="none" fill="black" font-size="24" font-family="ZT Nature">31</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(15.588, 99)"/><text x="1.588" y="107" stroke="none" fill="black" font-size="24" font-family="ZT Nature">32</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(-31.178, 90)"/><text x="-45.177" y="98" stroke="none" fill="black" font-size="24" font-family="ZT Nature">33</text><use href="#tile2" class="tiledropped" fill="#FF8C00" transform="translate(-46.766, 117)"/><text x="-60.766" y="125" stroke="none" fill="black" font-size="24" font-family="ZT Nature">34</text><use href="#tile0" class="tiledropped" fill="#00BFFF" transform="translate(93.53, -18)"/><text x="79.53" y="-10" stroke="none" fill="black" font-size="24" font-family="ZT Nature">35</text><use href="#tile1" class="tiledropped" fill="#FF0000" transform="translate(-15.589, 117)"/><text x="-29.589" y="125" stroke="none" fill="black" font-size="24" font-family="ZT Nature">36</text></g>
        </svg>
SVG preview
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
帖子: 6318
注册时间: 2022年 11月 18日 17:36
联系:

Re: 研究提升三菱棋的AI棋力

帖子 ejsoon »

改進:
一,更改導入導出的記譜格式


在導入導出的文本格式中,首先把横坐標改為字母,0為a,-1為b,以此類推負數為小寫字母,1為A,2為B,以此類推正數為大寫字母。例如[(1,-2),(1,-1)]將改為[(A,-2),(A,-1)],[(-1,3),(0,3)]將改為[(b,3),(a,3)]。

在此基礎上,先手方第一手藍色棋子坐標為[(a,0),(A,0)],棋譜記作「0」。

如果有藍色棋子的横坐標為a和A,則如果其縱坐標為正數則為「A$」,負數則為「a$」,$代表無符號數字。比如[(a,6),(A,6)]記作「A6」,[(a,-2),(A,-2)]記作「a2」。

如果有藍色棋子不屬於以上情況,則記作「前字母$後字母」,$為無符號數字。當其縱坐標為正數時,前字母和後字母為字母順序,否則為倒序。比如[(d,-1),(c,-1)]記作「d1c」,[(B,7),(A,7)]記作「A7B」。

紅色或橙色棋子,記作「前$字母後$」,$代表無符號數字。如果其縱坐標存在正數,則前數字小於後數字,否則前數字大於後數字。比如[(B,8),(B,9)]記作「8B9」,[(c,-2),(c,-3)]記作「3c2」。

棋譜中的每一手棋都用空白隔開,則第一手為我方落子,第二手為對方,依次類推。

如「[(0,0),(1,0)] [(0,-2),(0,-1)] [(0,2),(0,1)] [(1,-2),(1,-1)] [(0,-3),(-1,-3)]」將記為「0 2a1 1a2 2A1 b3a」。

這個記譜格式將只用於導入和導出,不要改變原先程式中的數據格式。

二,導出svg顯示的數字調小一些

當導出svg時,如果勾選了「數字」,則把它的字體大小改小一些。

三,規則文字變動

落子規則:雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動。除了第一手棋之外,每一手棋都要跟場上已有棋子貼合。不可形成空洞。

計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。

四,中文時把P1和P2去掉,英文時則只顯示P1和P2

當一局結束時,中文應只顯示「我方」和「對方」,不必顯示「P1」和「P2」。

請明確給出所要修改的地方和所要替換的代碼。

代码: 全选

改進:
一,更改導入導出的記譜格式


在導入導出的文本格式中,首先把横坐標改為字母,0為a,-1為b,以此類推負數為小寫字母,1為A,2為B,以此類推正數為大寫字母。例如[(1,-2),(1,-1)]將改為[(A,-2),(A,-1)],[(-1,3),(0,3)]將改為[(b,3),(a,3)]。

在此基礎上,先手方第一手藍色棋子坐標為[(a,0),(A,0)],棋譜記作「0」。

如果有藍色棋子的横坐標為a和A,則如果其縱坐標為正數則為「A$」,負數則為「a$」,$代表無符號數字。比如[(a,6),(A,6)]記作「A6」,[(a,-2),(A,-2)]記作「a2」。

如果有藍色棋子不屬於以上情況,則記作「前字母$後字母」,$為無符號數字。當其縱坐標為正數時,前字母和後字母為字母順序,否則為倒序。比如[(d,-1),(c,-1)]記作「d1c」,[(B,7),(A,7)]記作「A7B」。

紅色或橙色棋子,記作「前$字母後$」,$代表無符號數字。如果其縱坐標存在正數,則前數字小於後數字,否則前數字大於後數字。比如[(B,8),(B,9)]記作「8B9」,[(c,-2),(c,-3)]記作「3c2」。

棋譜中的每一手棋都用空白隔開,則第一手為我方落子,第二手為對方,依次類推。

如「[(0,0),(1,0)] [(0,-2),(0,-1)] [(0,2),(0,1)] [(1,-2),(1,-1)] [(0,-3),(-1,-3)]」將記為「0 2a1 1a2 2A1 b3a」。

這個記譜格式將只用於導入和導出,不要改變原先程式中的數據格式。

二,導出svg顯示的數字調小一些

當導出svg時,如果勾選了「數字」,則把它的字體大小改小一些。

三,規則文字變動

落子規則:雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動。除了第一手棋之外,每一手棋都要跟場上已有棋子貼合。不可形成空洞。

計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。 

四,中文時把P1和P2去掉,英文時則只顯示P1和P2

當一局結束時,中文應只顯示「我方」和「對方」,不必顯示「P1」和「P2」。

請明確給出所要修改的地方和所要替換的代碼。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
帖子: 6318
注册时间: 2022年 11月 18日 17:36
联系:

Re: 研究提升三菱棋的AI棋力

帖子 ejsoon »

gemini 3.1 pro

代码: 全选

以下為您所要求的修改,請在原有的 HTML 檔案中找到對應的部分並進行替換:

### 1. 新增棋譜轉換輔助函數

請在 `<script>` 標籤的最上方(`let gameLogic = null;` 的上方)加入以下三個函數:

```javascript
      function indexToLetter(x) {
        if (x === 0) return 'a';
        if (x > 0) return String.fromCharCode(64 + x);
        return String.fromCharCode(97 - x);
      }

      function letterToIndex(char) {
        if (char === 'a') return 0;
        let code = char.charCodeAt(0);
        if (code >= 65 && code <= 90) return code - 64;
        if (code >= 98 && code <= 122) return 97 - code;
        return 0;
      }

      function getNewNotation(pid, x1, y1, x2, y2) {
        if (x1 > x2 || (x1 === x2 && y1 > y2)) {
          let tx = x1, ty = y1;
          x1 = x2; y1 = y2;
          x2 = tx; y2 = ty;
        }
        if (pid === 0) {
          if (x1 === 0 && x2 === 1 && y1 === 0 && y2 === 0) return "0";
          let y = Math.abs(y1);
          if (x1 === 0 && x2 === 1) return y1 > 0 ? "A" + y : "a" + y;
          let l1 = indexToLetter(x1);
          let l2 = indexToLetter(x2);
          let isAsc = l1.toLowerCase().localeCompare(l2.toLowerCase()) < 0;
          if (y1 > 0) {
            return isAsc ? (l1 + y + l2) : (l2 + y + l1);
          } else {
            return isAsc ? (l2 + y + l1) : (l1 + y + l2);
          }
        } else {
          let L = indexToLetter(x1);
          let n1 = Math.abs(y1), n2 = Math.abs(y2);
          if (y1 > 0 || y2 > 0) {
            return Math.min(n1, n2) + L + Math.max(n1, n2);
          } else {
            return Math.max(n1, n2) + L + Math.min(n1, n2);
          }
        }
      }

      let gameLogic = null;
      let p1CurrentScore = 0;

```

### 2. 替換多國語言與規則字串

找到 `const I18N = {` 中的這部分:

**原代碼:**

```javascript
          ruleTitle: '規則簡介',
          rule: '<p>雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動,分數高者獲勝。</p><p>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。</p>',
// ...略...
          p1You: 'P1(我方)',
          p2Opp: 'P2(對方)',

```

與英文中的:

```javascript
          p1You: 'P1 (You)',
          p2Opp: 'P2 (Opp)',

```

**替換為:**

```javascript
          ruleTitle: '規則簡介',
          rule: '<p>雙方輪流落子,先手方第一手必須下藍色棋子,後手方第一手必須下紅色棋子,此後雙方輪流行動。除了第一手棋之外,每一手棋都要跟場上已有棋子貼合。不可形成空洞。</p><p>計分規則:雙方相對而坐,則我方的上面是對方的下面。從各方視角望去,藍色棋子視為一個立方體的頂面,紅色和橙色棋子視為側面,一個立方體記一分,立方體可堆疊累加。</p>',
// ...(中間保留原樣)...
          p1You: '我方',
          p2Opp: '對方',

```

英文替換為:

```javascript
          p1You: 'P1',
          p2Opp: 'P2',

```

### 3. 將原先產生棋譜字串的地方改用新格式

找到 `commitMove` 函數內部的字串組合:

**原代碼:**

```javascript
        // 確保坐標從小到大排序
        let sortedC1, sortedC2;
        if (t1.idx < t2.idx || (t1.idx === t2.idx && t1.N < t2.N)) {
          sortedC1 = t1;
          sortedC2 = t2;
        } else {
          sortedC1 = t2;
          sortedC2 = t1;
        }
        let notation = `[(${sortedC1.idx},${sortedC1.N}),(${sortedC2.idx},${sortedC2.N})]`;

```

**替換為:**

```javascript
        let notation = getNewNotation(pid, t1.idx, t1.N, t2.idx, t2.N);

```

找到 `autoPlayFirstBlue` 函數內部的字串組合:

**原代碼:**

```javascript
            if (result.success) {
              p1CurrentScore = result.scores.p1Score;
              p2CurrentScore = result.scores.p2Score;
            }
            let notation = `[(${t1.idx},${t1.N}),(${t2.idx},${t2.N})]`;

```

**替換為:**

```javascript
            if (result.success) {
              p1CurrentScore = result.scores.p1Score;
              p2CurrentScore = result.scores.p2Score;
            }
            let notation = getNewNotation(0, t1.idx, t1.N, t2.idx, t2.N);

```

找到 `buildMinimaxNodeDOM` 函數內部的字串組合:

**原代碼:**

```javascript
        let pieceName = pid === 0 ? '🔵藍' : pid === 1 ? '🔴紅' : '🟠橙';
        let notation = `[(${c1.x},${c1.y}),(${c2.x},${c2.y})]`;

```

**替換為:**

```javascript
        let pieceName = pid === 0 ? '🔵藍' : pid === 1 ? '🔴紅' : '🟠橙';
        let notation = getNewNotation(pid, c1.x, c1.y, c2.x, c2.y);

```

找到 `buildTreeNodeDOM` 函數內部的字串組合:

**原代碼:**

```javascript
        let pieceName = pid === 0 ? '🔵藍' : pid === 1 ? '🔴紅' : '🟠橙';
        let notation = `[(${c1.x},${c1.y}),(${c2.x},${c2.y})]`;

```

**替換為:**

```javascript
        let pieceName = pid === 0 ? '🔵藍' : pid === 1 ? '🔴紅' : '🟠橙';
        let notation = getNewNotation(pid, c1.x, c1.y, c2.x, c2.y);

```

### 4. 修改導入解析邏輯 (`submitImport`)

找到 `submitImport` 函數內部解析 tokens 的迴圈:

**原代碼:**

```javascript
          for (let i = 0; i < tokens.length; i++) {
            let match = tokens[i].match(/\[\((-?\d+),(-?\d+)\),\((-?\d+),(-?\d+)\)\]/);
            if (!match) throw new Error('格式錯誤');
            let t1_idx = parseInt(match[1]),
              t1_N = parseInt(match[2]);
            let t2_idx = parseInt(match[3]),
              t2_N = parseInt(match[4]);

            // 推導棋子種類 (0: 藍, 1: 紅, 2: 橙)
            let pid = 0;
            if (t1_N !== t2_N) {
              let isRight = gameLogic.isRight(t1_idx, t1_N);
              let dn = t2_N - t1_N;
              pid = isRight ? (dn === -1 ? 1 : 2) : dn === 1 ? 1 : 2;
            }

            let isRight1 = gameLogic.isRight(t1_idx, t1_N);

```

**替換為:**

```javascript
          for (let i = 0; i < tokens.length; i++) {
            let token = tokens[i];
            let t1_idx, t1_N, t2_idx, t2_N, pid;

            if (token === "0") {
              t1_idx = 0; t1_N = 0;
              t2_idx = 1; t2_N = 0;
              pid = 0;
            } else {
              let match1 = token.match(/^([aA])(\d+)$/);
              let match2 = token.match(/^([A-Za-z])(\d+)([A-Za-z])$/);
              let match3 = token.match(/^(\d+)([A-Za-z])(\d+)$/);

              if (match1) {
                pid = 0;
                t1_idx = 0;
                t2_idx = 1;
                t1_N = t2_N = match1[1] === 'A' ? parseInt(match1[2]) : -parseInt(match1[2]);
              } else if (match2) {
                pid = 0;
                let L1 = match2[1], L2 = match2[3];
                t1_idx = letterToIndex(L1);
                t2_idx = letterToIndex(L2);
                let isAsc = L1.toLowerCase().localeCompare(L2.toLowerCase()) < 0;
                t1_N = t2_N = isAsc ? parseInt(match2[2]) : -parseInt(match2[2]);
              } else if (match3) {
                let n1 = parseInt(match3[1]), n2 = parseInt(match3[3]);
                t1_idx = t2_idx = letterToIndex(match3[2]);
                if (n1 < n2) {
                  t1_N = n1; t2_N = n2;
                } else {
                  t1_N = -n1; t2_N = -n2;
                }
                let isRight = gameLogic.isRight(t1_idx, t1_N);
                let dn = t2_N - t1_N;
                pid = isRight ? (dn === -1 ? 1 : 2) : (dn === 1 ? 1 : 2);
              } else {
                throw new Error('格式錯誤');
              }
            }

            let isRight1 = gameLogic.isRight(t1_idx, t1_N);

```

### 5. 導出 SVG 時的數字字體調小

找到 `updateDlPreview` 函數處理數字 SVG 節點的部分:

**原代碼:**

```javascript
            textNode.setAttribute('stroke', 'none');
            textNode.setAttribute('fill', 'black');
            textNode.setAttribute('font-size', '24');
            textNode.setAttribute('font-family', 'ZT Nature');

```

**替換為:**

```javascript
            textNode.setAttribute('stroke', 'none');
            textNode.setAttribute('fill', 'black');
            textNode.setAttribute('font-size', '16');
            textNode.setAttribute('font-family', 'ZT Nature');

```
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复
  • 相似主题
    回复总数
    阅读次数
    最新帖子

在线用户

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