这个程序能不能断网运行 <html><head> <meta charset="utf-8"...
बनाया गया: 9 फ़रवरी 2025
का उपयोग करके उत्तर दिया गया O3 Mini High द्वारा Chat01
बनाया गया: 9 फ़रवरी 2025
का उपयोग करके उत्तर दिया गया O3 Mini High द्वारा Chat01
这个程序能不能断网运行
<html><head> <meta charset="utf-8"> <title>ValueAIV2</title> <style> body { font-family: sans-serif; text-align: center; } #boardCanvas { background-color: #f0d9b5; margin-top: 10px; cursor: pointer; } #controls { margin-bottom: 10px; } </style> </head> <body> <h1>ValueAIV2</h1> <div id="controls"> 难度(最大搜索深度):<input type="range" id="difficulty" min="1" max="5" value="3"> <span id="difficultyValue">3</span> <br> 先手: <label><input type="radio" name="first" id="firstHuman" value="human" checked=""> 人类</label> <label><input type="radio" name="first" id="firstAI" value="ai"> AI</label> <br> <button id="restartBtn">重新开始</button> </div> <canvas id="boardCanvas" width="600" height="600"></canvas> <script> // ---------------------- 常量与全局变量 ---------------------- const BOARD_SIZE = 15; // 棋盘尺寸 15x15 const CELL_SIZE = 40; // 单元格像素大小 const EMPTY = 0; // 空 const BLACK = 1; // 黑棋 const WHITE = 2; // 白棋 var humanColor, aiColor; var currentPlayer; var gameOver = false; var maxDepth = 4; // 最大搜索深度(slider 值 + 1) var board = []; // 棋盘状态数组 var transpositionTable = {}; // 置换表缓存 const canvas = document.getElementById("boardCanvas"); const ctx = canvas.getContext("2d"); // ---------------------- 初始化棋盘及界面 ---------------------- function initBoard() { board = []; for (let i = 0; i < BOARD_SIZE; i++) { board[i] = []; for (let j = 0; j < BOARD_SIZE; j++) { board[i][j] = EMPTY; } } gameOver = false; transpositionTable = {}; // 根据滑块设定搜索深度(深度 = slider值 + 1) let diff = document.getElementById("difficulty").value; maxDepth = parseInt(diff) + 1; // 根据先手选择决定双方棋色(约定:黑棋先走) if (document.getElementById("firstHuman").checked) { humanColor = BLACK; aiColor = WHITE; currentPlayer = humanColor; } else { humanColor = WHITE; aiColor = BLACK; currentPlayer = aiColor; } drawBoard(); // 若 AI 先手,立即调用 AI 落子 if (currentPlayer === aiColor) { setTimeout(aiMove, 100); } } document.getElementById("difficulty").addEventListener("input", function() { document.getElementById("difficultyValue").innerText = this.value; }); document.getElementById("restartBtn").addEventListener("click", initBoard); canvas.addEventListener("click", handleClick); // ---------------------- 绘制棋盘与棋子 ---------------------- function drawBoard() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = "#333"; ctx.lineWidth = 1; // 绘制横线 for (let i = 0; i < BOARD_SIZE; i++) { ctx.beginPath(); ctx.moveTo(CELL_SIZE / 2, CELL_SIZE / 2 + i * CELL_SIZE); ctx.lineTo(canvas.width - CELL_SIZE / 2, CELL_SIZE / 2 + i * CELL_SIZE); ctx.stroke(); } // 绘制竖线 for (let j = 0; j < BOARD_SIZE; j++) { ctx.beginPath(); ctx.moveTo(CELL_SIZE / 2 + j * CELL_SIZE, CELL_SIZE / 2); ctx.lineTo(CELL_SIZE / 2 + j * CELL_SIZE, canvas.height - CELL_SIZE / 2); ctx.stroke(); } // 绘制棋子 for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (board[i][j] !== EMPTY) { let cx = CELL_SIZE / 2 + j * CELL_SIZE; let cy = CELL_SIZE / 2 + i * CELL_SIZE; ctx.beginPath(); ctx.arc(cx, cy, CELL_SIZE * 0.4, 0, 2 * Math.PI); ctx.fillStyle = board[i][j] === BLACK ? "black" : "white"; ctx.fill(); ctx.stroke(); } } } } // ---------------------- 人类落子处理 ---------------------- function handleClick(event) { if (gameOver || currentPlayer !== humanColor) return; let rect = canvas.getBoundingClientRect(); let x = event.clientX - rect.left; let y = event.clientY - rect.top; let j = Math.floor(x / CELL_SIZE); let i = Math.floor(y / CELL_SIZE); if (i < 0 || i >= BOARD_SIZE || j < 0 || j >= BOARD_SIZE) return; if (board[i][j] !== EMPTY) return; board[i][j] = humanColor; drawBoard(); if (isWinningMove(i, j, humanColor)) { gameOver = true; setTimeout(() => alert("你赢了!"), 10); return; } currentPlayer = aiColor; setTimeout(aiMove, 100); } // ---------------------- 判断胜利(检测四个方向) ---------------------- function isWinningMove(x, y, player) { const directions = [ [1, 0], [0, 1], [1, 1], [1, -1] ]; for (let d = 0; d < directions.length; d++) { let dx = directions[d][0], dy = directions[d][1]; let count = 1; // 正向计数 let i = 1; while (true) { let nx = x + i * dx, ny = y + i * dy; if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] === player) { count++; i++; } else break; } // 反向计数 i = 1; while (true) { let nx = x - i * dx, ny = y - i * dy; if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] === player) { count++; i++; } else break; } if (count >= 5) return true; } return false; } // ---------------------- AI 落子 ---------------------- function aiMove() { if (gameOver) return; let candidateMoves = getCandidateMoves(); // 检查 AI 是否有直接获胜的走法 for (let move of candidateMoves) { board[move.x][move.y] = aiColor; if (isWinningMove(move.x, move.y, aiColor)) { board[move.x][move.y] = EMPTY; board[move.x][move.y] = aiColor; drawBoard(); gameOver = true; setTimeout(() => alert("AI 赢了!"), 10); return; } board[move.x][move.y] = EMPTY; } // 检查对手是否有必胜走法,优先堵截 for (let move of candidateMoves) { board[move.x][move.y] = humanColor; if (isWinningMove(move.x, move.y, humanColor)) { board[move.x][move.y] = EMPTY; board[move.x][move.y] = aiColor; // 阻挡对手必胜 drawBoard(); currentPlayer = humanColor; return; } board[move.x][move.y] = EMPTY; } // 否则采用迭代加深搜索获得最佳走法 let bestMove = iterativeDeepening(maxDepth); if (bestMove) { board[bestMove.x][bestMove.y] = aiColor; drawBoard(); if (isWinningMove(bestMove.x, bestMove.y, aiColor)) { gameOver = true; setTimeout(() => alert("AI 赢了!"), 10); return; } } currentPlayer = humanColor; } // ---------------------- 候选落子点生成 ---------------------- // 仅在所有落子点的外包区域内(外延 margin 个单位)生成候选点 function getCandidateMoves() { let moves = []; let minX = BOARD_SIZE, minY = BOARD_SIZE, maxX = 0, maxY = 0; let found = false; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (board[i][j] !== EMPTY) { found = true; if (i < minX) minX = i; if (i > maxX) maxX = i; if (j < minY) minY = j; if (j > maxY) maxY = j; } } } if (!found) { moves.push({ x: Math.floor(BOARD_SIZE / 2), y: Math.floor(BOARD_SIZE / 2) }); return moves; } let margin = 2; minX = Math.max(minX - margin, 0); minY = Math.max(minY - margin, 0); maxX = Math.min(maxX + margin, BOARD_SIZE - 1); maxY = Math.min(maxY + margin, BOARD_SIZE - 1); for (let i = minX; i <= maxX; i++) { for (let j = minY; j <= maxY; j++) { if (board[i][j] === EMPTY) { moves.push({ x: i, y: j }); } } } return moves; } // 辅助函数:根据候选点周围相邻棋子数计算邻近得分(用于排序) function getAdjacencyScore(move) { let score = 0; for (let dx = -1; dx <= 1; dx++) { for (let dy = -1; dy <= 1; dy++) { let nx = move.x + dx, ny = move.y + dy; if (nx >= 0 && nx < BOARD_SIZE && ny >= 0 && ny < BOARD_SIZE && board[nx][ny] !== EMPTY) { score++; } } } return score; } // ---------------------- 迭代加深与 Negamax 搜索 ---------------------- function iterativeDeepening(maxDepth) { let bestMove = null; for (let depth = 1; depth <= maxDepth; depth++) { transpositionTable = {}; // 可选择跨迭代保留缓存,本例中每层重新清空 let result = negamax(depth, -Infinity, Infinity, aiColor); if (result.move) { bestMove = result.move; } } return bestMove; } // Negamax 搜索(返回 { score, move }) function negamax(depth, alpha, beta, player) { let boardKey = getBoardKey(); if (transpositionTable[boardKey] && transpositionTable[boardKey].depth >= depth) { return transpositionTable[boardKey].result; } if (depth === 0) { let evalScore = (player === aiColor) ? staticEvaluation() : -staticEvaluation(); return { score: evalScore, move: null }; } let best = { score: -Infinity, move: null }; let moves = getCandidateMoves(); if (moves.length === 0) { let evalScore = (player === aiColor) ? staticEvaluation() : -staticEvaluation(); return { score: evalScore, move: null }; } // 使用邻近得分对候选走法排序 moves.sort((a, b) => getAdjacencyScore(b) - getAdjacencyScore(a)); for (let move of moves) { board[move.x][move.y] = player; if (isWinningMove(move.x, move.y, player)) { board[move.x][move.y] = EMPTY; let winningScore = 1000000 + depth; // 越早获胜分数越高 let res = { score: winningScore, move: move }; transpositionTable[boardKey] = { depth: depth, result: res }; return res; } let nextPlayer = (player === aiColor) ? humanColor : aiColor; let result = negamax(depth - 1, -beta, -alpha, nextPlayer); let score = -result.score; board[move.x][move.y] = EMPTY; if (score > best.score) { best.score = score; best.move = move; } alpha = Math.max(alpha, score); if (alpha >= beta) break; } transpositionTable[boardKey] = { depth: depth, result: best }; return best; } function getBoardKey() { let key = ""; for (let i = 0; i < BOARD_SIZE; i++) { key += board[i].join(""); } return key; } // ---------------------- 评估函数 ---------------------- // 通过计算双方棋型得分(采用较高防御系数)返回局面静态评价 function staticEvaluation() { let defenseFactor = 0.82; // 对对手威胁赋予更高权重 let aiScore = evaluateFor(aiColor); let oppScore = evaluateFor(humanColor); return aiScore - defenseFactor * oppScore; } // 计算指定 color 棋子的局部得分(仅统计每个方向上的连续棋子及开放端) function evaluateFor(color) { let score = 0; for (let i = 0; i < BOARD_SIZE; i++) { for (let j = 0; j < BOARD_SIZE; j++) { if (board[i][j] === color) { for (let d = 0; d < 4; d++) { let dx = [1, 0, 1, 1][d]; let dy = [0, 1, 1, -1][d]; let prevX = i - dx, prevY = j - dy; if (prevX >= 0 && prevX < BOARD_SIZE && prevY >= 0 && prevY < BOARD_SIZE && board[prevX][prevY] === color) continue; let count = 0; let openEnds = 0; let x = i, y = j; while (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] === color) { count++; x += dx; y += dy; } if (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] === EMPTY) openEnds++; x = i - dx; y = j - dy; if (x >= 0 && x < BOARD_SIZE && y >= 0 && y < BOARD_SIZE && board[x][y] === EMPTY) openEnds++; score += scoreLine(count, openEnds); } } } } return score; } // 根据连续子数及开放端数量给予分值 function scoreLine(count, openEnds) { if (count >= 5) return 100000; if (count === 4) { if (openEnds === 2) return 10000; else if (openEnds === 1) return 1000; } if (count === 3) { if (openEnds === 2) return 1000; else if (openEnds === 1) return 100; } if (count === 2) { if (openEnds === 2) return 100; else if (openEnds === 1) return 10; } if (count === 1) return 1; return 0; } // ---------------------- 启动 ---------------------- initBoard(); </script> </body></html>这个程序是一个基于 JavaScript 的浏览器游戏实现。它的核心功能都是通过 JavaScript 在浏览器中运行的,因此它依赖于浏览器的 JavaScript 引擎。根据你的问题,程序是否能在断网的情况下运行,答案是:可以的。
解释如下:
只要你打开该 HTML 文件在浏览器中,就能在没有网络连接的情况下运行该程序。
本身不是依赖CDN的脚本什么的吗
这段代码中的所有脚本都是直接嵌入在 HTML 文件内的,没有通过外部 CDN 或其他外部资源加载任何脚本库。因此,它本身不依赖 CDN,可以在断网的情况下正常运行,只要浏览器支持 HTML5 和 JavaScript。