分页: 4 / 5

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 15:45
ejsoon
首回合限制行走步數為5,然後跟7784下和了一盤:

代码: 全选

[[3,6],[-5,3,7,8],[8,6,7,3,8,7],[-5,6,9,8,5,4,1],[8,1,7,3,8,7,9,6,8,9,5,8,4,5,1,4],[-5,8,7,4,5],[5,1,7,3,7,8,9,6,8,9,5,8,5,4,1,4,4,7],[-5,1,2,5,9,6],[5,6,7,3,7,8,6,9,8,9,5,8,5,4,1,4,4,7,2,1,5,2,9,5],[-5,5,8,4,7],[7,6,7,3,7,8,6,9,8,9,8,5,5,4,1,4,7,4,2,1,5,2,9,5,4,8],[-5,6,2,1,0,3,4,8,9],[7,9,7,3,7,8,6,9,9,8,8,5,5,4,1,4,7,4,1,2,5,2,9,5,8,4,6,2,1,0,0,3,3,4],[-5,7,8,5,2],[2,9,7,3,8,7,6,9,9,8,5,8,5,4,1,4,7,4,1,2,2,5,9,5,8,4,6,2,1,0,0,3,3,4],[-5,9,5,8,7],[2,7,7,3,7,8,6,9,9,8,8,5,5,4,1,4,7,4,1,2,2,5,5,9,8,4,6,2,1,0,0,3,3,4],[-5,2,5,9],[9,7,7,3,7,8,6,9,9,8,8,5,5,4,1,4,7,4,1,2,5,2,9,5,8,4,6,2,1,0,0,3,3,4],[-5,7,8,5,2],[9,2,7,3,8,7,6,9,9,8,5,8,5,4,1,4,7,4,1,2,2,5,9,5,8,4,6,2,1,0,0,3,3,4],[-5,9,8,7],[7,2,7,3,7,8,6,9,8,9,5,8,5,4,1,4,7,4,1,2,2,5,9,5,8,4,6,2,1,0,0,3,3,4],[-4,2,5,8,9],[7,9,7,3,7,8,6,9,9,8,8,5,5,4,1,4,7,4,1,2,5,2,9,5,8,4,6,2,1,0,0,3,3,4]]
https://ejsoon.vip/wp-content/uploads/2 ... n7784.html

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 16:12
ejsoon
現在AI之間很容易就會和棋:

代码: 全选

[[3,6],[-5,3,7,8,9,6,2,5,1,0,4],[4,6,7,3,8,7,9,8,6,9,2,6,5,2,1,5,0,1,4,0],[-5,6,9,8,7,4,5,2],[4,2,7,3,7,8,8,9,9,6,2,6,2,5,1,5,0,1,4,0,4,7,5,4],[-5,4,1,5,8,9],[9,2,7,3,7,8,9,8,9,6,2,6,2,5,5,1,0,1,4,0,4,7,5,4,1,4,5,8],[-5,2,6,5,4,7],[9,7,7,3,7,8,9,8,9,6,6,2,2,5,5,1,0,1,4,0,7,4,4,5,1,4,5,8,6,5],[-5,9,6],[6,7,7,3,7,8,9,8,6,9,6,2,2,5,5,1,0,1,4,0,7,4,4,5,1,4,5,8,6,5],[-5,7,3,4,0],[6,0,3,7,7,8,9,8,6,9,6,2,2,5,5,1,0,1,0,4,7,4,4,5,1,4,5,8,6,5,3,4],[-5,6,9,8,4,5],[5,0,3,7,7,8,8,9,9,6,6,2,2,5,5,1,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4],[-5,0,3,7,8,9,5,1],[5,1,7,3,8,7,9,8,9,6,6,2,2,5,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5],[-5,5,8,7],[7,1,7,3,7,8,9,8,9,6,6,2,2,5,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5],[-5,1,2],[7,2,7,3,7,8,9,8,9,6,6,2,2,5,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5,1,2],[-5,7,3],[3,2,3,7,7,8,9,8,9,6,6,2,2,5,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5,1,2],[-5,2,5],[3,5,3,7,7,8,9,8,9,6,6,2,5,2,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5,1,2],[-5,3,7],[7,5,7,3,7,8,9,8,9,6,6,2,5,2,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5,1,2],[-4,5,2],[7,2,7,3,7,8,9,8,9,6,6,2,2,5,1,5,0,1,0,4,7,4,5,4,1,4,5,8,6,5,3,4,8,4,0,3,9,5,1,2]]

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 16:13
ejsoon
哥尼斯堡在很難和棋的同時,也提供了和棋的空間,以使本棋躋身紹對公平的弈棋行列。

AI這種頂尖棋手果然總是能找到和棋的辦法,當然不是盤盤都和。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 16:27
ejsoon
當無路可走時,應點一下棋子再點一下btn_finish。

代码: 全选

[[3,6],[-5,3,7,4,5,1],[1,6,7,3,4,7,5,4,1,5],[-5,6,9],[1,9,7,3,4,7,5,4,1,5,9,6],[-5,1,2,6,5,4],[4,9,7,3,4,7,4,5,1,5,9,6,2,1,6,2,5,6],[-5,9,8],[4,8,7,3,4,7,4,5,1,5,9,6,2,1,6,2,5,6,8,9],[-5,4,8,9],[9,8,7,3,4,7,4,5,1,5,9,6,2,1,6,2,5,6,9,8,8,4],[-5,8,4,0],[9,0,7,3,4,7,4,5,1,5,9,6,2,1,6,2,5,6,9,8,4,8,0,4],[-5,9,5,2,1,0,4,3],[3,0,7,3,4,7,4,5,1,5,9,6,1,2,6,2,5,6,9,8,4,8,4,0,5,9,5,2,1,0,4,3]]

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 16:30
ejsoon
當關閉窗口時,如果輪到的棋手打勾,則將開始自動走棋。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 18:38
ejsoon
改進:
一,當頁面加載完成時,彈出mcts_modal窗口。它的初始值將被js還原為初始值。

二,任何時候當mcts_modal窗口彈出時,包括頁面加載完成時,只要game_status==0或7,也就是btn_play顯示在頁面上時,它的「開始搜尋」以及下方的搜尋結果將隱藏,取而代之的是「開始遊戲」按鈕。當按下時,其作用跟按下btn_play一樣。

三,當按下關閉窗口mcts_close時,如果當前行動方的「自動checkbox」打勾的話,那它將開始搜尋並走棋。

四,「最大步數」下方新增一個「首回合限走步數」,用於限制AI在首回合的最大可走步數。默認值為6。

注意當搜尋時,不影響到後面回合的最大步數。比如我設其為7,那麼當它在搜尋時,搜到第二回合及往後,是可以走到8步甚至更多的。

五,當自動走棋無路可走時,應提示「勝率0%,無路可走!」,並按下本方棋子,再按下btn_finish以完成本次行動。

只需給出所要修改的地方。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 18:41
ejsoon
gemini pro:

代码: 全选

以下是針對您的需求所需要修改的地方。請按照指示替換或新增代碼:

### 第一部分:修改 HTML 介面 (`#mcts_modal` 區塊)
找到 `<div id="mcts_modal">` 的程式碼,並將其替換為以下內容。
主要修改了關閉按鈕的點擊事件、新增了「首回合限走步數」設定,以及「開始遊戲」按鈕:

```html
            <div id="mcts_modal">
                <div class="mcts_close" onclick="closeMctsModal()">×</div>
                <h3>🤖 AI 搜尋設定</h3>
                <div class="mcts_row"><label>模擬次數:</label> <input type="number" id="mcts_sims" value="50"></div>
                <div class="mcts_row"><label>搜尋深度:</label> <input type="number" id="mcts_depth" value="8"></div>
                <div class="mcts_row"><label>最大步數:</label> <input type="number" id="mcts_max_path" value="10" max="10" min="2"></div>
                <div class="mcts_row"><label>首回限步:</label> <input type="number" id="mcts_first_path" value="6" max="10" min="1"></div>
                <hr>
                <div class="mcts_row">
                    <label><input type="checkbox" id="mcts_auto_blue"> 自動藍方</label>
                    <label><input type="checkbox" checked id="mcts_auto_green"> 自動綠方</label>
                </div>
                <button id="mcts_play_btn" style="width: 100%; padding: 8px; margin-top: 5px; cursor: pointer; display: none; background: #8278f5; color: white; border: none; border-radius: 4px; font-size: 16px;">開始遊戲</button>
                <button id="mcts_start_btn" style="width: 100%; padding: 8px; margin-top: 5px; cursor: pointer;">開始搜尋</button>
                <div id="mcts_results" style="margin-top: 10px; font-size: 14px;"></div>
            </div>
```

---

### 第二部分:新增全局參數與介面控制函數
找到 `const PARAMS = { ... };` 以及 `let autoPlayTimer = null;` 附近,將其替換並加入新函數:

```javascript
const PARAMS = {
    SIMULATIONS_PER_MOVE: 50, 
    MAX_DEPTH: 8,
    MAX_PATH_LENGTH: 10,
    FIRST_MAX_PATH: 6 // 新增首回合限走步數
};
let autoPlayTimer = null; 
let currentMctsResults = [];
let currentMctsPage = 0;

// 新增參數更新助手
function updateMctsParams() {
    PARAMS.SIMULATIONS_PER_MOVE = parseInt(document.getElementById('mcts_sims').value) || 50;
    PARAMS.MAX_DEPTH = parseInt(document.getElementById('mcts_depth').value) || 8;
    PARAMS.MAX_PATH_LENGTH = parseInt(document.getElementById('mcts_max_path').value) || 10;
    PARAMS.FIRST_MAX_PATH = parseInt(document.getElementById('mcts_first_path').value) || 6;
    let bridgesCount = arrows.length;
    if (bridgesCount <= 6) PARAMS.FORCE_CHECK_DEPTH = 2;
    else if (bridgesCount <= 9) PARAMS.FORCE_CHECK_DEPTH = 4;
    else if (bridgesCount <= 12) PARAMS.FORCE_CHECK_DEPTH = 6;
    else PARAMS.FORCE_CHECK_DEPTH = 8;
}

// 新增視窗開啟控制
function openMctsModal() {
    document.getElementById('mcts_sims').value = 50;
    document.getElementById('mcts_depth').value = 8;
    document.getElementById('mcts_max_path').value = 10;
    document.getElementById('mcts_first_path').value = 6;
    document.getElementById('mcts_results').innerHTML = '';
    currentMctsResults = [];
    currentMctsPage = 0;

    // 根據遊戲狀態顯示對應按鈕
    if (game_status === 0 || game_status === 7) {
        document.getElementById('mcts_start_btn').style.display = 'none';
        document.getElementById('mcts_results').style.display = 'none';
        document.getElementById('mcts_play_btn').style.display = 'block';
    } else {
        document.getElementById('mcts_start_btn').style.display = 'block';
        document.getElementById('mcts_results').style.display = 'block';
        document.getElementById('mcts_play_btn').style.display = 'none';
    }
    document.getElementById('mcts_modal').style.display = 'block';
}

// 新增視窗關閉與觸發控制
function closeMctsModal() {
    document.getElementById('mcts_modal').style.display = 'none';
    if (game_status == 1 || game_status == 3) {
        let autoBlue = document.getElementById('mcts_auto_blue') && document.getElementById('mcts_auto_blue').checked;
        let autoGreen = document.getElementById('mcts_auto_green') && document.getElementById('mcts_auto_green').checked;
        if ((current_man === 0 && autoBlue) || (current_man === 1 && autoGreen)) {
            clearTimeout(autoPlayTimer);
            autoPlayTimer = setTimeout(() => {
                updateMctsParams();
                runMCTS(true);
            }, 500);
        }
    }
}

// 綁定開始遊戲按鈕
document.getElementById("mcts_play_btn").addEventListener('click', () => {
    document.getElementById('mcts_modal').style.display = 'none';
    btn_play.onclick();
});
```

---

### 第三部分:修改原本的事件綁定與初始化邏輯

**1. 修改 `window.onload`,使其載入完畢即彈出視窗:**
```javascript
	window.onload = function () {
		let wakeLock = null;
		const requestWakeLock = async ()=>{
			try {
				wakeLock = await navigator.wakeLock.request('screen');
				console.log('Wake Lock is active!');
			} catch (err) {
				console.log(`${err.name}, ${err.message}`);
			}
		}
		document.addEventListener('visibilitychange', async () => {
			if (wakeLock !== null && document.visibilityState === 'visible') {
				requestWakeLock()
			}
		});
		requestWakeLock()
		displayGame();
		openMctsModal(); // 新增這一行
	}
```

**2. 修改圖標點擊與「開始搜尋」按鈕事件** (找到原本的 `g12155` 以及 `mcts_start_btn` 事件綁定並替換):
```javascript
// 點擊圖標顯示設定視窗
document.getElementById("g12155").addEventListener('click', () => {
    openMctsModal();
});

document.getElementById("mcts_start_btn").addEventListener('click', () => {
    if (![1, 2, 3, 4].includes(game_status)) {
        document.getElementById('mcts_results').innerHTML = "請在輪到玩家移動時搜尋。";
        return;
    }
    updateMctsParams(); // 使用新函數更新參數
    document.getElementById('mcts_results').innerHTML = "搜尋中,請稍候...";
    setTimeout(() => runMCTS(false), 50);
});
```

**3. 替換 `displayGame()` 裡的自動下棋定時器邏輯**:
找到 `// 自動下棋` 後的 `autoPlayTimer` 設定區塊替換為:
```javascript
	// 自動下棋
	clearTimeout(autoPlayTimer);
	if (game_status == 1 || game_status == 3) {
		let autoBlue = document.getElementById('mcts_auto_blue') && document.getElementById('mcts_auto_blue').checked;
		let autoGreen = document.getElementById('mcts_auto_green') && document.getElementById('mcts_auto_green').checked;
		if ((current_man === 0 && autoBlue) || (current_man === 1 && autoGreen)) {
			autoPlayTimer = setTimeout(() => {
				updateMctsParams(); // 精簡為直接呼叫函數
				runMCTS(true); 
			}, 500);
		}
	}
```

---

### 第四部分:修改核心 AI 搜尋邏輯

**1. 替換 `getLegalMoves()` 使其支持區分首回合與動態步數**:
```javascript
function getLegalMoves(state, isFirstTurn = false) {
    let start = state.turn === 0 ? state.p0 : state.p1;
    let opponent_pos = state.turn === 0 ? state.p1 : state.p0; 
    let moves = [];
    let bridges_count = state.stack_arrow.length / 2;
    // 依據是否為首回合應用不同的最大步數
    let current_max_path = isFirstTurn ? PARAMS.FIRST_MAX_PATH : PARAMS.MAX_PATH_LENGTH;

    function dfs(curr, path, has_new_bridge) {
        if (path.length > 1 && (has_new_bridge || bridges_count >= 12) && curr !== opponent_pos) {
            moves.push(path.slice());
        }
        if (path.length - 1 >= current_max_path) return; // 動態步數限制

        for (let nxt of state.empty_map[curr] || []) {
            if (path.indexOf(nxt) === -1) {
                path.push(nxt);
                dfs(nxt, path, true);
                path.pop();
            }
        }
        for (let nxt of state.arrow_map[curr] || []) {
            if (path.indexOf(nxt) === -1) {
                path.push(nxt);
                dfs(nxt, path, has_new_bridge);
                path.pop();
            }
        }
    }
    dfs(start, [start], false);
    return moves;
}
```

**2. 替換所有呼叫 `getLegalMoves()` 的地方:**
請在 `canForceWin` 以及 `playout` 內,將 `let moves = getLegalMoves(...)` 改為:
* `let moves = getLegalMoves(state, false);` (在 `canForceWin` 中)
* `let moves = getLegalMoves(currState, false);` (在 `playout` 中)

**3. 在 `runMCTS()` 內,支援首回合參數與處理無路可走的自裁邏輯:**
在 `runMCTS` 中找到 `let rootMoves = getLegalMoves(rootState);`,將包含它的條件判斷替換為:
```javascript
    let rootMoves = getLegalMoves(rootState, true); // 第一回合展開加上 true
    if (rootMoves.length === 0) {
        if (!isAuto) {
            document.getElementById('mcts_results').innerHTML = "❌ 勝率0%,無路可走!";
        } else {
            let thinkingUI = document.getElementById('thinking_ui');
            thinkingUI.innerHTML = "❌ <b>勝率0%,無路可走!</b>";
            thinkingUI.style.display = 'block';
            setTimeout(() => {
                thinkingUI.style.display = 'none';
                let manDotOnClick = manOnClick.bind(men_bottom[current_man]);
                manDotOnClick(); // 按下本方棋子
                setTimeout(() => {
                    btn_finish.onclick(); // 再按下完成以直接輸掉回合
                }, 500);
            }, 1500);
        }
        return;
    }
```

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 19:02
ejsoon

代码: 全选

	let wakeLock = null;
	const requestWakeLock = async ()=>{
		try {
			wakeLock = await navigator.wakeLock.request('screen');
			console.log('Wake Lock is active!');
		} catch (err) {
			console.log(`${err.name}, ${err.message}`);
		}
	}
	document.addEventListener('visibilitychange', async () => {
		if (wakeLock !== null && document.visibilityState === 'visible') {
			requestWakeLock()
		}
	});
	requestWakeLock()
這段代碼有什麼用?

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 19:25
ejsoon
當mcts_modal顯示時,它背後應有一個半透明擋板,其下面應該被覆蓋不可點擊。

代码: 全选

為了實現「彈窗背後有半透明遮罩且不可點擊」的效果,我們需要新增一個遮罩層(Overlay)的 HTML 元素,並修改相關的 CSS 與 JavaScript 控制邏輯。

以下是具體的修改建議:

### 一、 修改 HTML 結構
在 `<body>` 內(建議放在 `#mcts_modal` 的前方)新增一個 `mcts_overlay` 元素:

```html
<div id="mcts_overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 999;"></div>

<div id="mcts_modal" style="display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1000; background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 15px rgba(0,0,0,0.3); width: 280px;">
    </div>
```

---

### 二、 修改 CSS 樣式
請確保 `mcts_modal` 的樣式包含 `position: fixed` 以及適中的 `z-index`。如果原本是在 `<style>` 標籤中定義的,請更新如下:

```css
#mcts_modal {
    position: fixed; /* 確保在屏幕正中央 */
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: white;
    padding: 15px;
    border-radius: 10px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.4);
    z-index: 1000; /* 高於遮罩層 */
    display: none;
    width: 260px;
}

#mcts_overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5); /* 半透明黑色 */
    z-index: 999; /* 低於 modal 但高於其他頁面元素 */
}
```

---

### 三、 修改 JavaScript 函數
修改 `openMctsModal` 和 `closeMctsModal` 函數,以便在顯示視窗時同步顯示/隱藏遮罩層:

```javascript
// 修改後的開啟函數
function openMctsModal() {
    // ... 原有的初始值還原邏輯 (mcts_sims, mcts_depth 等) ...
    document.getElementById('mcts_sims').value = 50;
    document.getElementById('mcts_depth').value = 8;
    document.getElementById('mcts_max_path').value = 10;
    document.getElementById('mcts_first_path').value = 6;

    // 顯示遮罩與視窗
    document.getElementById('mcts_overlay').style.display = 'block';
    document.getElementById('mcts_modal').style.display = 'block';

    // ... 原有的按鈕顯示/隱藏邏輯 (game_status == 0 或 7) ...
    if (game_status === 0 || game_status === 7) {
        document.getElementById('mcts_start_btn').style.display = 'none';
        document.getElementById('mcts_play_btn').style.display = 'block';
    } else {
        document.getElementById('mcts_start_btn').style.display = 'block';
        document.getElementById('mcts_play_btn').style.display = 'none';
    }
}

// 修改後的關閉函數
function closeMctsModal() {
    // 隱藏遮罩與視窗
    document.getElementById('mcts_overlay').style.display = 'none';
    document.getElementById('mcts_modal').style.display = 'none';

    // ... 原有的自動走棋判斷邏輯 ...
    if (game_status == 1 || game_status == 3) {
        let autoBlue = document.getElementById('mcts_auto_blue')?.checked;
        let autoGreen = document.getElementById('mcts_auto_green')?.checked;
        if ((current_man === 0 && autoBlue) || (current_man === 1 && autoGreen)) {
            clearTimeout(autoPlayTimer);
            autoPlayTimer = setTimeout(() => {
                updateMctsParams();
                runMCTS(true);
            }, 500);
        }
    }
}
```

### 額外建議:
如果您希望點擊「遮罩區域」也能關閉窗口,可以為 `mcts_overlay` 增加一個點擊事件:
```javascript
document.getElementById('mcts_overlay').onclick = closeMctsModal;
gemini pro:

代码: 全选

以下是新增半透明擋板所需修改的地方:

### 第一部分:新增 HTML 擋板元素
請在 `<div id="mcts_modal">` 的**正上方**加入這個 `#mcts_overlay` 擋板,並確保 `#mcts_modal` 本身的 `z-index` 層級高於擋板(若原本沒有設定,請補上):

```html
<div id="mcts_overlay" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 999;"></div>

<div id="mcts_modal" style="z-index: 1000; /* 保留您其他的原有 inline 樣式... */">
    ```

---

### 第二部分:修改開啟與關閉視窗的 JavaScript 函數
在 `openMctsModal()` 與 `closeMctsModal()` 函數中,加入控制擋板顯示與隱藏的代碼:

**1. 修改 `openMctsModal()`:**
在函數底部找到控制 modal 顯示的代碼,將其替換為同步顯示擋板:
```javascript
    // 根據遊戲狀態顯示對應按鈕... (省略中間代碼)
    
    document.getElementById('mcts_overlay').style.display = 'block'; // 新增這行:顯示擋板
    document.getElementById('mcts_modal').style.display = 'block';
}
```

**2. 修改 `closeMctsModal()`:**
在函數開頭找到控制 modal 隱藏的代碼,將其替換為同步隱藏擋板:
```javascript
function closeMctsModal() {
    document.getElementById('mcts_overlay').style.display = 'none'; // 新增這行:隱藏擋板
    document.getElementById('mcts_modal').style.display = 'none';
    
    // 下方原本的自動下棋邏輯保持不變...
```

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 19:57
ejsoon
konigsberg20260411defaultvalue779

增加「開始遊戲」按鈕。

https://ejsoon.vip/wp-content/uploads/2 ... ue779.html

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 20:08
ejsoon
首回合限步出錯,限到每一回合去了。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 20:27
ejsoon
這個局面:

代码: 全选

[[3,6],[-5,3,4,5,1,2,6,9,8],[8,6,4,3,5,4,1,5,2,1,6,2,9,6,8,9],[-5,6,2,5,4,8,7],[8,7,4,3,4,5,1,5,2,1,2,6,9,6,8,9,5,2,8,4,7,8],[-5,8,5,2],[2,7,4,3,4,5,1,5,2,1,2,6,9,6,8,9,2,5,8,4,7,8,5,8],[-5,7,4,5,8,9],[2,9,4,3,5,4,1,5,2,1,2,6,9,6,9,8,2,5,8,4,7,8,8,5,4,7],[-5,2,5,9,8],[8,9,4,3,5,4,1,5,2,1,2,6,9,6,8,9,5,2,8,4,7,8,8,5,4,7,5,9],[-5,9,6,5,2],[8,2,4,3,5,4,1,5,2,1,2,6,6,9,8,9,2,5,8,4,7,8,8,5,4,7,5,9,6,5],[-5,8,4,7],[7,2,4,3,5,4,1,5,2,1,2,6,6,9,8,9,2,5,4,8,7,8,8,5,7,4,5,9,6,5],[-5,2,6],[7,6,4,3,5,4,1,5,2,1,6,2,6,9,8,9,2,5,4,8,7,8,8,5,7,4,5,9,6,5],[-5,7,4,3],[3,6,3,4,5,4,1,5,2,1,6,2,6,9,8,9,2,5,4,8,7,8,8,5,4,7,5,9,6,5],[-5,6,2],[3,2,3,4,5,4,1,5,2,1,2,6,6,9,8,9,2,5,4,8,7,8,8,5,4,7,5,9,6,5]]
藍方搜尋出的一步棋是敗著。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 21:14
ejsoon
gemini pro:

代码: 全选

這是一個非常典型的 MCTS(蒙地卡羅樹搜尋)實作時容易忽略的問題。

### 問題所在

在你的程式碼中,`runMCTS` 函數在取得根節點(也就是 AI 當下要決定的這步棋)的合法步數時,**把 `isFirstTurn` 參數寫死了為 `true`**。

這導致 AI 在**每一回合**搜尋自己的下一步時,都會誤以為現在是「第一回合」,從而永遠受到 `FIRST_MAX_PATH`(首回限步)的限制,而不是只有在遊戲真正的開局時才受限。

**原方程式碼位置 (大約在 `runMCTS` 函數中段):**
```javascript
        if (canShootNow) {
            // ... 略過上方射殺邏輯
            return; // 終止後續的 MCTS 展開
        }

        let rootMoves = getLegalMoves(rootState, true); // <--- 問題在這裡,永遠傳入 true
        if (rootMoves.length === 0) {
```

### 修改方法

我們需要引入遊戲的實際回合狀態。在你的系統中,全域變數 `game_hp` 紀錄了當前的歷史進度(半回合數)。
* 當 `game_hp == 0` 時,是藍方(Blue)的整場第一回合。
* 當 `game_hp == 1` 時,是綠方(Green)的整場第一回合。
* 往後 `game_hp >= 2` 時,就不再是雙方的第一回合。

因此,只要將寫死的 `true` 改為透過 `game_hp` 來動態判斷即可。

**請將該行程式碼替換為以下內容:**

```javascript
        if (canShootNow) {
            // ... 略過上方射殺邏輯
            return; // 終止後續的 MCTS 展開
        }

        // 修改:透過 game_hp 判斷是否為藍方或綠方的遊戲第一回合 (game_hp 為 0 或 1)
        let isFirstGameTurn = game_hp <= 1; 
        let rootMoves = getLegalMoves(rootState, isFirstGameTurn);

        if (rootMoves.length === 0) {
```

### 為什麼這樣改有效?
這樣修改後,`getLegalMoves` 才會在 `game_hp <= 1`(開局前兩步)時套用 `PARAMS.FIRST_MAX_PATH` (預設 6 步)。等到了第二回合 (`game_hp >= 2`),就會傳入 `false`,並正確切換為套用 `PARAMS.MAX_PATH_LENGTH` (預設 10 步),讓 AI 在後續回合能夠走更長的步數。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 21:43
ejsoon
在執行closeMctsModal時,如果當前正在執行runMcts(),則避免再重覆執行。給出修改方法。

代码: 全选

這是一個非常實際的問題。因為你的 `runMCTS()` 內部使用了非同步分塊(`setTimeout(processNextChunk, 0)`)來避免阻塞主執行緒,如果在這段期間又觸發了一次 `runMCTS()`,兩個 MCTS 會同時在背景運算,不但會拖垮效能,還可能導致 UI 狀態錯亂。

要解決這個問題,最穩妥的方法是引入一個**全域狀態標記 (flag)**,用來追蹤 MCTS 是否正在執行中。

以下是具體的修改步驟:

### 第一步:新增全域變數
在程式碼大約第 575 行附近(宣告 `autoPlayTimer` 的地方),新增一個 `isMctsRunning` 變數:

```javascript
    const PARAMS = {
        SIMULATIONS_PER_MOVE: 50,
        MAX_DEPTH: 8,
        MAX_PATH_LENGTH: 10,
        FIRST_MAX_PATH: 6
    };
    let autoPlayTimer = null; // 用於自動下棋的計時器
    let isMctsRunning = false; // 🟢 新增:用來追蹤 MCTS 是否正在執行
    let currentMctsResults = [];
    let currentMctsPage = 0;
```

### 第二步:修改 `closeMctsModal` 函數
在判斷是否要啟動自動下棋的條件中,加入 `!isMctsRunning` 的檢查,確保只有在 AI 沒有思考時才觸發:

```javascript
    // 新增視窗關閉與觸發控制
    function closeMctsModal() {
        document.getElementById('mcts_modal').style.display = 'none';
        if (game_status == 1 || game_status == 3) {
            let autoBlue = document.getElementById('mcts_auto_blue') && document.getElementById('mcts_auto_blue').checked;
            let autoGreen = document.getElementById('mcts_auto_green') && document.getElementById('mcts_auto_green').checked;
            
            // 🟢 修改此行:加入 && !isMctsRunning 條件
            if (((current_man === 0 && autoBlue) || (current_man === 1 && autoGreen)) && !autoPlayTimer && !isMctsRunning) {
                clearTimeout(autoPlayTimer);
                autoPlayTimer = setTimeout(() => {
                    updateMctsParams();
                    runMCTS(true);
                }, 500);
            }
        }
    }
```

### 第三步:在 `runMCTS` 中嚴格控制標記的開關
為了確保萬無一失(例如使用者狂點「開始搜尋」按鈕),我們也要在 `runMCTS` 內部做好防呆,並在搜尋結束的各個出口把標記改回 `false`:

```javascript
    function runMCTS(isAuto = false) {
        // 🟢 新增防呆:如果已經在執行,直接阻擋
        if (isMctsRunning) return; 
        isMctsRunning = true;

        let rootState = {
            // ... (維持原樣)
        };

        // --- 檢查直接射殺邏輯 ---
        // ... (維持原樣)

        if (canShootNow) {
            // ... (維持原樣)
            isMctsRunning = false; // 🟢 新增:結束執行時釋放標記
            return; // 終止後續的 MCTS 展開
        }

        let isFirstGameTurn = game_hp <= 1; 
        let rootMoves = getLegalMoves(rootState, isFirstGameTurn);
        
        if (rootMoves.length === 0) {
            // ... (維持原樣)
            isMctsRunning = false; // 🟢 新增:無路可走結束執行時釋放標記
            return;
        }

        // ... (維持原樣)

        // 非同步分塊執行函數
        function processNextChunk() {
            if (moveIndex < totalMoves) {
                // ... (維持原樣,推演邏輯不變)
                
                moveIndex++;
                setTimeout(processNextChunk, 0);
            } else {
                // 搜尋全部結束,處理結果
                isMctsRunning = false; // 🟢 新增:所有路線搜尋完畢,釋放標記
                
                moveStats.sort((a, b) => {
                    // ... (維持原樣)
```

透過加上這道鎖,無論你是關閉視窗、還是連續點擊搜尋按鈕,程式都只會允許一個 MCTS 實例在背景執行,避免重複運算造成的卡頓與邏輯衝突。

Re: 改下哥尼斯堡網頁程式

发表于 : 2026年 4月 11日 22:01
ejsoon
konigsberg20260411onceMcts7792

避免重覆調用Mcts。

https://ejsoon.vip/wp-content/uploads/2 ... s7792.html