改下哥尼斯堡網頁程式
Re: 改下哥尼斯堡網頁程式
如果當前處於「自動走棋」的搜尋進程時,場上的class=man以及btn_history將不能被點擊,如果點g12155並彈出modal窗口,則「自動走棋」的搜尋進程中止。
當modal窗口打開時,點擊「開始搜尋」,按鈕將變為「停止搜尋」,按下「停止搜尋」或關閉窗口,都會使其停止。
只需給出所要修改的地方。
上次由 ejsoon 在 2026年 4月 12日 20:57,总共编辑 1 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
代码: 全选
為了實現您的需求,我們需要針對 `konigsberg20260412param7794.html` 進行以下幾處修改:
### 1. 定義狀態控制變數與 UI 鎖定函式
在 `<script>` 標籤內的全局變數區域(例如在 `let currState;` 附近)新增一個 flag,並定義一個控制點擊狀態的函式。
```javascript
// 新增:追蹤自動走棋狀態
let isAiRunning = false;
// 新增:切換 UI 互動狀態的函式
function setUIInteraction(disabled) {
const pointerValue = disabled ? 'none' : 'auto';
// 鎖定/解鎖所有 class 為 man 的元素
document.querySelectorAll('.man').forEach(el => {
el.style.pointerEvents = pointerValue;
});
// 鎖定/解鎖 btn_history
const btnHistory = document.getElementById('btn_history');
if (btnHistory) btnHistory.style.pointerEvents = pointerValue;
}
```
### 2. 修改「自動走棋」的啟動與結束邏輯
找到負責執行「自動走棋」的函式(通常是處理「自動走棋」按鈕點擊後的邏輯,或名為 `autoPlay`、`aiMove` 的函式)。
```javascript
// 假設自動走棋的進入點函式如下,請在其開始與結束處加入控制
async function startAutoPlay() { // 函式名稱依原代碼而定
isAiRunning = true;
setUIInteraction(true); // 禁用點擊
while (isAiRunning && !gameFinished) {
// ... 原有的 AI 搜尋與走棋邏輯 ...
// 在循環內部檢查,如果 isAiRunning 被設為 false,則中斷
if (!isAiRunning) break;
await new Promise(resolve => setTimeout(resolve, 500)); // 假設的延遲
}
isAiRunning = false;
setUIInteraction(false); // 恢復點擊
}
```
### 3. 修改 `g12155` 的點擊事件
找到 `#g12155` 的事件監聽器(這是開啟 Modal 的按鈕),在開啟窗口的同時強制中止搜尋。
```javascript
// 找到 g12155 的 click 監聽處進行修改
document.getElementById('g12155').addEventListener('click', function() {
if (isAiRunning) {
isAiRunning = false; // 中止搜尋進程
setUIInteraction(false); // 立即恢復 UI 互動
console.log("自動走棋已因開啟窗口而中止");
}
// ... 原有的彈出 modal 窗口代碼 ...
});
```
### 修改要點說明:
1. **CSS `pointer-events`**: 這是最簡單且有效的方法。當設為 `none` 時,該元素及其子元素將無法觸發任何鼠標事件(click, hover 等)。
2. **標誌位 (Flag) 控制**: 透過 `isAiRunning` 變數。當點擊 `g12155` 時將其設為 `false`,則自動走棋的循環(Loop)或遞迴邏輯在下一次檢查時會自動停止。
3. **範圍限制**: 此修改精確鎖定了 `.man` 和 `#btn_history`,符合您的特定需求。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
代码: 全选
這裡為您提供所需的程式碼修改。您可以直接找到對應的區塊並將其替換或加入新增的程式碼:
### 1. 新增中止搜尋用的全域變數
在 `autoPlayTimer` 和 `isMctsRunning` 宣告的下方,新增一個 `abortMcts` 變數。
```javascript
let autoPlayTimer = null; // 用於自動下棋的計時器
let isMctsRunning = false; // 用來追蹤 MCTS 是否正在執行
let abortMcts = false; // 新增:用來強制中止 MCTS 搜尋
```
### 2. 禁止在搜尋期間點擊棋子 (man)
在 `manOnClick` 函數的開頭加入防護。
```javascript
// man onclick
function manOnClick() {
if (isMctsRunning) return; // 新增:如果正在搜尋中,禁止點擊
if (game_status == 1 || game_status == 3) {
let clickmandot = parseInt(this.getAttribute("i"));
```
### 3. 禁止在搜尋期間點擊歷史記錄相關按鈕
在 `historyOnclick` 與設定鈕的事件中加入防護。
```javascript
// show and set history
setting_close.onclick = btn_history_set.onclick = function() {
if (isMctsRunning && this === btn_history_set) return; // 新增:搜尋中禁止點擊設定鈕
let game_history_parse = [];
```
```javascript
// history prev
btn_history_next.onclick = btn_history_prev.onclick = historyOnclick;
function historyOnclick() {
if (isMctsRunning) return; // 新增:搜尋中禁止點擊歷史上下頁
if ("g11048" == this.id) {
```
### 4. 開啟視窗時強制中止搜尋
在 `openMctsModal` 開頭加入 `abortMcts = true`。
```javascript
// 新增視窗開啟控制
function openMctsModal() {
abortMcts = true; // 新增:開啟視窗時立即中止背景正在運行的自動搜尋
document.getElementById('mcts_results').innerHTML = '';
currentMctsResults = [];
```
### 5. 關閉視窗時中止搜尋並處理重啟
修改 `closeMctsModal`,中止搜尋、復原按鈕文字,並拔除原本針對 `!isMctsRunning` 的限制,確保自動下棋能順利重啟。
```javascript
// 新增視窗關閉與觸發控制
function closeMctsModal() {
abortMcts = true; // 新增:關閉視窗時中止目前的搜尋
document.getElementById('mcts_start_btn').innerText = "開始搜尋"; // 新增:復原按鈕文字
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)) {
clearTimeout(autoPlayTimer);
autoPlayTimer = setTimeout(() => {
isMctsRunning = false; // 確保被中止的鎖定狀態強制解除
updateMctsParams();
runMCTS(true);
}, 500);
}
}
}
```
### 6. 更新「開始搜尋」按鈕的事件綁定
修改 `mcts_start_btn` 的點擊事件,加入切換「停止搜尋」的邏輯。
```javascript
document.getElementById("mcts_start_btn").addEventListener('click', function() {
// 新增:如果正在搜尋,則改為中止行為
if (isMctsRunning) {
abortMcts = true;
this.innerText = "開始搜尋";
return;
}
if (![1, 2, 3, 4].includes(game_status)) {
document.getElementById('mcts_results').innerHTML = "請在輪到玩家移動時搜尋。";
return;
}
this.innerText = "停止搜尋"; // 新增:將按鈕變成停止
updateMctsParams();
document.getElementById('mcts_results').innerHTML = "搜尋中,請稍候...";
setTimeout(() => runMCTS(false), 50);
});
```
### 7. 在核心 `runMCTS` 中加入中斷判斷與按鈕復原
在 `runMCTS` 內部進行幾處修改,確保每次進入時重置旗標,並在運算中檢查中斷:
**A. 函數開頭重置旗標:**
```javascript
function runMCTS(isAuto = false) {
if (isMctsRunning) return;
isMctsRunning = true;
abortMcts = false; // 新增:開始搜尋時重置中止旗標
```
**B. 在提早獲勝或無路可走時復原按鈕文字:**
```javascript
// (約莫在 if (canShootNow) 的區塊內)
if (canShootNow) {
// ... (保留原本邏輯)
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋"; // 新增
return; // 終止後續的 MCTS 展開
}
let isFirstGameTurn = game_hp <= 1;
let rootMoves = getLegalMoves(rootState, isFirstGameTurn);
if (rootMoves.length === 0) {
// ... (保留原本邏輯)
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋"; // 新增
return;
}
```
**C. 修改 `processNextChunk` 迴圈來接收中止訊號:**
```javascript
// 非同步分塊執行函數
function processNextChunk() {
// 新增:每次迴圈檢查是否收到中止訊號
if (abortMcts) {
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋";
document.getElementById('thinking_ui').style.display = 'none';
if (!isAuto) document.getElementById('mcts_results').innerHTML = "搜尋已中止。";
return;
}
if (moveIndex < totalMoves) {
// ... (保留中間的所有推演邏輯)
moveIndex++;
// 使用 setTimeout 讓出執行緒,允許瀏覽器重新渲染畫面
setTimeout(processNextChunk, 0);
} else {
// 搜尋全部結束,處理結果
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋"; // 新增:搜尋結束自動復原按鈕
// ... (保留原本剩餘的結算與 UI 更新邏輯)
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
增加停止搜尋功能,禁止svg選中。把「必殺搜尋」分成四段。
- 附件
-
konigsberg20260412shutdown7795.7z- (13.94 KiB) 已下载 4 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
小修改。
https://ejsoon.vip/wp-content/uploads/2 ... k7797.html
- 附件
-
konigsberg20260412stopthink7797.7z- (13.94 KiB) 已下载 6 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
一,把「參數設定」改為「展開」,點擊之後變為「收回」。不要使用details-summary,用js來控制。
二,在「展開」的右邊增加四個按鈕:「簡單、困難、專家、自定」。它們的「mcts_sims、mcts_depth、mcts_max_path、mcts_first_path、fcd_depth1、fcd_depth2、fcd_depth3、fcd_depth4」值分別為:
簡單:10、1、5、3、1、1、1、1。
困難:50、5、7、4、2、2、2、2。
專家:100、10、9、5、2、4、6、8。
「自定」則保持上一次的值。當這些值被修改時,如果改動之後跟前面三個模式都不相同,則程式會自動把模式切換為「自定」。
起初默認選擇的是「簡單」。
三,當在搜尋時,包括自動走棋時的搜尋和打開modal窗口時的搜尋,都要加上計時功能,實時展示用了多少秒。
只需給出所要修改的地方。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
「四」錯給為「三」。
代码: 全选
這裡為你整理了實現這三個改進需求的修改部分。請對照你的原始代碼進行相應的替換。
### 第一部分:CSS 樣式修改
在你的 `<style>` 區塊中(例如 `#mcts_modal h3` 的定義附近),加入模式按鈕的樣式:
```css
.mode_btn {
padding: 2px 6px;
font-size: 13px;
cursor: pointer;
border: 1px solid #ccc;
background: #fff;
border-radius: 4px;
outline: none;
}
.mode_btn.active {
background: #8278f5;
color: white;
border-color: #8278f5;
}
```
### 第二部分:HTML 結構修改
在 `<div id="mcts_modal">` 中,**移除原有的 `<details> ... </details>` 整個區塊**,並替換為以下包含按鈕與收合邏輯的代碼(注意輸入框加入了 `class="mcts_param_input"` 以便 JS 監聽):
```html
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
<span id="toggle_params" style="cursor: pointer; font-weight: bold; outline: none; color: #333;">展開</span>
<div id="mode_buttons" style="display: flex; gap: 4px;">
<button class="mode_btn" data-mode="easy">簡單</button>
<button class="mode_btn" data-mode="hard">困難</button>
<button class="mode_btn" data-mode="expert">專家</button>
<button class="mode_btn" data-mode="custom">自定</button>
</div>
</div>
<div id="params_container" style="display: none;">
<div class="mcts_row"><label>模擬次數:</label> <input type="number" id="mcts_sims" class="mcts_param_input"></div>
<div class="mcts_row"><label>搜尋深度:</label> <input type="number" id="mcts_depth" class="mcts_param_input"></div>
<div class="mcts_row"><label>最大步數:</label> <input type="number" id="mcts_max_path" max="9" min="1" class="mcts_param_input"></div>
<div class="mcts_row"><label>首回限步:</label> <input type="number" id="mcts_first_path" max="9" min="1" class="mcts_param_input"></div>
<div style="margin-top: 5px; margin-bottom: 5px;">
<div style="margin-bottom: 5px; font-size: 14px;">必勝搜尋 (橋數 ➔ 深度):</div>
<div class="mcts_row" style="padding-left: 10px;">
<label>7</label><input type="number" id="fcd_depth1" style="width: 40px;" class="mcts_param_input">
</div>
<div class="mcts_row" style="padding-left: 10px;">
<label>12</label><input type="number" id="fcd_depth2" style="width: 40px;" class="mcts_param_input">
</div>
<div class="mcts_row" style="padding-left: 10px;">
<label>16</label><input type="number" id="fcd_depth3" style="width: 40px;" class="mcts_param_input">
</div>
<div class="mcts_row" style="padding-left: 10px;">
<label>19</label><input type="number" id="fcd_depth4" style="width: 40px;" class="mcts_param_input">
</div>
</div>
</div>
```
### 第三部分:JavaScript 邏輯修改
**1. 新增全域變數與初始化邏輯**
將原本的 `window.onload` 替換並加入模式邏輯,同時宣告計時與預設參數用的變數:
```javascript
// 在 <script> 開頭或宣告變數區域加入以下預設值與計時變數
const PRESETS = {
easy: [10, 1, 5, 3, 1, 1, 1, 1],
hard: [50, 5, 7, 4, 2, 2, 2, 2],
expert: [100, 10, 9, 5, 2, 4, 6, 8]
};
let lastSearchTime = 0; // 記錄最後一次搜尋總耗時
// 替換原有的 window.onload 函數
window.onload = function() {
let wakeLock = null;
const requestWakeLock = async () => {
try {
wakeLock = await navigator.wakeLock.request('screen');
} catch (err) {
console.log(`${err.name}, ${err.message}`);
}
}
document.addEventListener('visibilitychange', async () => {
if (wakeLock !== null && document.visibilityState === 'visible') {
requestWakeLock()
}
});
requestWakeLock();
displayGame();
// 綁定模式按鈕事件
document.querySelectorAll('.mode_btn').forEach(btn => {
btn.addEventListener('click', (e) => setMode(e.target.getAttribute('data-mode')));
});
// 綁定輸入框變更事件以自動判斷是否切換為「自定」
document.querySelectorAll('.mcts_param_input').forEach(input => {
input.addEventListener('input', checkCustomMode);
});
// 綁定展開/收回按鈕
document.getElementById('toggle_params').addEventListener('click', function() {
const container = document.getElementById('params_container');
if (container.style.display === 'none') {
container.style.display = 'block';
this.innerText = '收回';
} else {
container.style.display = 'none';
this.innerText = '展開';
}
});
// 初始化為「簡單」模式 (會自動填入參數)
setMode('easy');
document.getElementById('mcts_auto_blue').checked = false;
document.getElementById('mcts_auto_green').checked = true;
openMctsModal();
}
// 模式切換邏輯
function setMode(mode) {
document.querySelectorAll('.mode_btn').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.mode_btn[data-mode="${mode}"]`).classList.add('active');
if (mode !== 'custom') {
const vals = PRESETS[mode];
const inputs = document.querySelectorAll('.mcts_param_input');
inputs.forEach((input, idx) => {
input.value = vals[idx];
});
updateMctsParams();
}
}
// 檢查自定模式邏輯
function checkCustomMode() {
let isMatch = false;
const currentVals = Array.from(document.querySelectorAll('.mcts_param_input')).map(input => parseInt(input.value) || 0);
for (const [mode, vals] of Object.entries(PRESETS)) {
if (vals.every((v, i) => v === currentVals[i])) {
document.querySelectorAll('.mode_btn').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.mode_btn[data-mode="${mode}"]`).classList.add('active');
isMatch = true;
break;
}
}
if (!isMatch) {
document.querySelectorAll('.mode_btn').forEach(btn => btn.classList.remove('active'));
document.querySelector(`.mode_btn[data-mode="custom"]`).classList.add('active');
}
}
```
**2. 在結果清單中顯示耗時**
修改 `renderMctsResults()` 函數,加上顯示時間的標籤:
```javascript
// 在 renderMctsResults() 中找到這行:
// let resultsHtml = `<b>搜尋完成!共 ${total} 條路徑:</b><br>`;
// 替換為:
let resultsHtml = `<b>搜尋完成!共 ${total} 條路徑:</b><br><span style="font-size:13px; color:#555;">⏱️ 總耗時: ${lastSearchTime} 秒</span><br>`;
```
**3. 計時功能實作**
修改 `runMCTS(isAuto = false)` 函數:
```javascript
function runMCTS(isAuto = false) {
if (isMctsRunning) return;
isMctsRunning = true;
abortMcts = false;
let searchStartTime = performance.now(); // 記錄開始時間
let rootState = {
p0: parseInt(men_bottom[0].getAttribute("i") || men_top[0].getAttribute("i")),
// ... 原本的 rootState 設定
```
接著往下找到直接勝負判斷 `if (canShootNow)` 和 `if (rootMoves.length === 0)` 的區塊,加入時間顯示:
```javascript
if (canShootNow) {
let elapsedSec = ((performance.now() - searchStartTime) / 1000).toFixed(1);
let msg = `🎯 <b>射殺對手!</b><br>⏱️ ${elapsedSec} 秒`;
// ... 保持原有邏輯
```
```javascript
if (rootMoves.length === 0) {
let elapsedSec = ((performance.now() - searchStartTime) / 1000).toFixed(1);
if (!isAuto) {
document.getElementById('mcts_results').innerHTML = `❌ 勝率0%,無路可走!<br>⏱️ ${elapsedSec} 秒`;
} else {
let thinkingUI = document.getElementById('thinking_ui');
thinkingUI.innerHTML = `❌ <b>勝率0%</b><br>無路可走!<br>⏱️ ${elapsedSec} 秒`;
// ... 保持原有邏輯
```
最後找到處理遞迴的 `processNextChunk()` 函數,並修改 UI 更新邏輯:
```javascript
function processNextChunk() {
if (abortMcts) {
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋";
document.getElementById('thinking_ui').style.display = 'none';
if (!isAuto) document.getElementById('mcts_results').innerHTML = "搜尋已中止。";
return;
}
if (moveIndex < totalMoves) {
let move = rootMoves[moveIndex];
// 實時更新 UI 狀態並計算經過時間
let elapsedSec = ((performance.now() - searchStartTime) / 1000).toFixed(1);
let statusText = `層數: ${PARAMS.MAX_DEPTH}<br>分支: ${moveIndex + 1} / ${totalMoves}<br>⏱️ 耗時: ${elapsedSec} 秒`;
if (isAuto) {
thinkingUI.innerHTML = `🤔 <b>思考中...</b><br>${statusText}`;
} else {
resultsUI.innerHTML = `<b>搜尋中...</b><br>${statusText}`;
}
// ... 保留中間原本的核心推演邏輯 ...
} else {
// 搜尋全部結束,處理結果
isMctsRunning = false;
document.getElementById('mcts_start_btn').innerText = "開始搜尋";
// 儲存最後總耗時,提供給 renderMctsResults 使用
lastSearchTime = ((performance.now() - searchStartTime) / 1000).toFixed(1);
moveStats.sort((a, b) => { /* 保留原本的排序 */ });
if (isAuto) {
let bestStat = moveStats[0];
if (bestStat.guaranteedWin) {
thinkingUI.innerHTML = `🎯 必殺!<br>⏱️ ${lastSearchTime} 秒`;
} else if (bestStat.immediateLoss) {
thinkingUI.innerHTML = `💀 告負<br>⏱️ ${lastSearchTime} 秒`;
} else if (bestStat.guaranteedLoss) {
thinkingUI.innerHTML = `⚠️ 必敗<br>⏱️ ${lastSearchTime} 秒`;
} else {
thinkingUI.innerHTML = `✅ <b>決定!</b><br>預估勝率: ${((bestStat.wins / bestStat.plays) * 100).toFixed(1)}%<br>⏱️ ${lastSearchTime} 秒`;
}
setTimeout(() => simulateMove(bestStat.move), 800);
} else {
currentMctsResults = moveStats;
currentMctsPage = 0;
renderMctsResults(); // 這裡現在會吃到更新好的 lastSearchTime
}
}
}
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
增加了「簡單、困難、專家、自定」四種模式。增加搜尋計時。
https://ejsoon.vip/wp-content/uploads/2 ... e7798.html
- 附件
-
konigsberg20260413fourthree7798.7z- (14.8 KiB) 已下载 3 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 改下哥尼斯堡網頁程式
小修改,當點擊play時去掉redline。
https://ejsoon.vip/wp-content/uploads/2 ... es781.html
- 附件
-
konigsberg20260413endyes781.7z- (14.8 KiB) 已下载 1 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: Bing [Bot] 和 1 访客
