Skip to content

Commit acc7e43

Browse files
authored
更新 script.js
1 parent 0d962c0 commit acc7e43

1 file changed

Lines changed: 33 additions & 13 deletions

File tree

script.js

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// =====================================================
2-
// 五子棋 Ultra V18.2 · 反卡死终极修复版
2+
// 五子棋 Ultra V18.2.1 · 强制落子兜底修复版
33
// =====================================================
44
document.addEventListener('DOMContentLoaded', () => {
55
// ---------- DOM 元素 ----------
@@ -54,6 +54,7 @@ document.addEventListener('DOMContentLoaded', () => {
5454
let soundEnabled = true;
5555
let isAIThinking = false;
5656
let aiTimeoutHandle = null;
57+
let forceMoveTimer = null;
5758

5859
const rankSystem = [
5960
{ name: "初学者", icon: "1", min: 0, max: 100, color: "#6c757d" },
@@ -94,7 +95,7 @@ document.addEventListener('DOMContentLoaded', () => {
9495
{ version: "17.2", description: "修复快速连点漏洞:AI思考期间锁定棋盘,防止玩家连下多步" },
9596
{ version: "18.0 Ultra", description: "极致攻防一体化:防守系数18.0,复合棋型权重翻倍,双评估通道,深度提升至16层" },
9697
{ version: "18.1 Ultra", description: "移除Worker方案,回归主线程+requestAnimationFrame时间切片,帧率恢复55+" },
97-
{ version: "18.2 Ultra", description: "修复AI卡死与深层卡顿,增加随机兜底与紧急制动机制" }
98+
{ version: "18.2 Ultra", description: "双保险强制落子,彻底杜绝AI卡死,超时自动从最佳候选落子" }
9899
];
99100

100101
let gameState = {
@@ -263,6 +264,7 @@ document.addEventListener('DOMContentLoaded', () => {
263264
if (gameState.mode !== 'pvp' && gameState.currentPlayer === AI) return;
264265
if (gameState.gameOver || gameState.board[row][col] !== EMPTY) return;
265266

267+
clearTimeout(forceMoveTimer);
266268
playSound(placeSound);
267269
const prev = JSON.parse(JSON.stringify(gameState.board));
268270
gameState.board[row][col] = gameState.currentPlayer;
@@ -288,7 +290,6 @@ document.addEventListener('DOMContentLoaded', () => {
288290
if (gameState.mode === 'ai' && gameState.currentPlayer === AI && !gameState.gameOver) {
289291
isAIThinking = true;
290292
updateGameStatus('ai');
291-
// 使用 requestAnimationFrame 确保 UI 更新后再计算
292293
requestAnimationFrame(() => {
293294
aiTimeoutHandle = setTimeout(makeAIMove, 10);
294295
});
@@ -298,7 +299,7 @@ document.addEventListener('DOMContentLoaded', () => {
298299
}
299300
}
300301

301-
// ===================== AI 算法 (主线程,极致时间检查) =====================
302+
// ===================== AI 算法 =====================
302303
function findWinningMove(player) {
303304
for (let r = 0; r < BOARD_SIZE; r++) {
304305
for (let c = 0; c < BOARD_SIZE; c++) {
@@ -443,12 +444,12 @@ document.addEventListener('DOMContentLoaded', () => {
443444
}
444445
depthCount.textContent = gameState.stats.maxDepth;
445446
winChance.textContent = '0.00%';
446-
return bestMove || moves[0]; // 保证至少返回一个着法
447+
return bestMove || moves[0];
447448
}
448449

449450
function minimax(depth, alpha, beta, isMax, start, limit) {
450451
if (performance.now() - start > limit) return evaluateBoard();
451-
// 检查终局
452+
// 终局检测
452453
for (let r = 0; r < BOARD_SIZE; r++) {
453454
for (let c = 0; c < BOARD_SIZE; c++) {
454455
if (gameState.board[r][c] !== EMPTY && checkWin(r, c)) {
@@ -496,26 +497,42 @@ document.addEventListener('DOMContentLoaded', () => {
496497
updateGameStatus('ai');
497498
status.innerHTML = '<i class="fas fa-robot"></i> AI思考中 <span class="thinking"><span>.</span><span>.</span><span>.</span></span>';
498499

499-
// 使用 requestAnimationFrame 确保 UI 更新后再计算
500+
// 外层强制超时:最多 5 秒必须落子
501+
forceMoveTimer = setTimeout(() => {
502+
if (!isAIThinking) return;
503+
// 强制从候选列表取第一个,或随机空位
504+
const moves = genMoves();
505+
if (moves.length) {
506+
makeMove(moves[0].row, moves[0].col);
507+
} else {
508+
const emptyCells = [];
509+
for (let r = 0; r < BOARD_SIZE; r++) for (let c = 0; c < BOARD_SIZE; c++) if (gameState.board[r][c] === EMPTY) emptyCells.push({row: r, col: c});
510+
if (emptyCells.length) {
511+
const rand = emptyCells[Math.floor(Math.random() * emptyCells.length)];
512+
makeMove(rand.row, rand.col);
513+
}
514+
}
515+
}, 5000);
516+
500517
requestAnimationFrame(() => {
501518
const winMove = findWinningMove(AI);
502-
if (winMove) { makeMove(winMove.row, winMove.col); return; }
519+
if (winMove) { clearTimeout(forceMoveTimer); makeMove(winMove.row, winMove.col); return; }
503520
const playerWin = findWinningMove(PLAYER);
504-
if (playerWin) { makeMove(playerWin.row, playerWin.col); return; }
521+
if (playerWin) { clearTimeout(forceMoveTimer); makeMove(playerWin.row, playerWin.col); return; }
505522
const move = getUltimateAIMove();
523+
clearTimeout(forceMoveTimer);
506524
if (move) {
507525
makeMove(move.row, move.col);
508526
} else {
509-
// 终极兜底:随机空位
527+
// 兜底随机空位
510528
const emptyCells = [];
511529
for (let r = 0; r < BOARD_SIZE; r++) for (let c = 0; c < BOARD_SIZE; c++) if (gameState.board[r][c] === EMPTY) emptyCells.push({row: r, col: c});
512530
if (emptyCells.length) {
513531
const rand = emptyCells[Math.floor(Math.random() * emptyCells.length)];
514532
makeMove(rand.row, rand.col);
515533
} else {
516-
// 棋盘满,平局
517534
gameState.gameOver = true;
518-
showWinner(0); // 平局
535+
showWinner(0);
519536
}
520537
}
521538
});
@@ -536,10 +553,11 @@ document.addEventListener('DOMContentLoaded', () => {
536553

537554
function showWinner(player) {
538555
isAIThinking = false;
556+
clearTimeout(forceMoveTimer);
539557
if (aiTimeoutHandle) { clearTimeout(aiTimeoutHandle); aiTimeoutHandle = null; }
540558
winMessage.classList.add('show');
541559
let name, egg;
542-
if (player === 0) { // 平局
560+
if (player === 0) {
543561
name = '平局';
544562
egg = '棋盘已满,不分胜负。';
545563
} else if (player === PLAYER) {
@@ -562,6 +580,7 @@ document.addEventListener('DOMContentLoaded', () => {
562580

563581
function restartGame() {
564582
if (isAIThinking) return;
583+
clearTimeout(forceMoveTimer);
565584
if (aiTimeoutHandle) { clearTimeout(aiTimeoutHandle); aiTimeoutHandle = null; }
566585
for (let r = 0; r < BOARD_SIZE; r++) for (let c = 0; c < BOARD_SIZE; c++) gameState.board[r][c] = EMPTY;
567586
gameState.currentPlayer = PLAYER; gameState.gameOver = false; gameState.moves = []; gameState.stats.moves = 0;
@@ -592,6 +611,7 @@ document.addEventListener('DOMContentLoaded', () => {
592611
function setMode(mode) {
593612
playSound(clickSound);
594613
isAIThinking = false;
614+
clearTimeout(forceMoveTimer);
595615
if (aiTimeoutHandle) { clearTimeout(aiTimeoutHandle); aiTimeoutHandle = null; }
596616
gameState.mode = mode;
597617
aiModeBtn.classList.toggle('active', mode === 'ai');

0 commit comments

Comments
 (0)