WWW.YOUINFO.SITE
标签聚合 战胜

/tag/战胜

LinuxDo 最新话题 · 2026-06-04 12:00:00+08:00 · tech

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <title>五子棋 AI 对战</title> <style> :root { --bg-color: #f5f6fa; --board-color: #e4b980; --line-color: #634d31; --primary-color: #4a90e2; } * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; -webkit-user-select: none; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; background-color: var(--bg-color); display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; padding: 10px; } .container { width: 100%; max-width: 500px; display: flex; flex-direction: column; align-items: center; gap: 15px; } h1 { font-size: 1.5rem; color: #333; font-weight: 600; } .status { font-size: 1.1rem; font-weight: bold; color: var(--primary-color); height: 24px; } .board-wrapper { width: 100%; aspect-ratio: 1 / 1; background-color: var(--board-color); border-radius: 8px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); padding: 12px; position: relative; } canvas { width: 100%; height: 100%; display: block; cursor: pointer; } .btn { background-color: var(--primary-color); color: white; border: none; padding: 10px 24px; font-size: 1rem; border-radius: 20px; cursor: pointer; box-shadow: 0 4px 12px rgba(74, 144, 226, 0.3); transition: all 0.2s ease; } .btn:active { transform: scale(0.95); box-shadow: 0 2px 6px rgba(74, 144, 226, 0.3); } </style> </head> <body> <div class="container"> <h1>五子棋 AI 对战</h1> <div class="status" id="status-text">你是黑棋,请落子</div> <div class="board-wrapper"> <canvas id="gobang"></canvas> </div> <button class="btn" onclick="restartGame()">重新开始</button> </div> <script> const canvas = document.getElementById('gobang'); const ctx = canvas.getContext('2d'); const statusText = document.getElementById('status-text'); const GRID_SIZE = 15; let cellSize = 0; // ===== 修复点 1:直接初始化为 15×15 的二维零矩阵 ===== let board = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0)); let gameOver = false; let isAiTurn = false; let lastMove = null; let haloAngle = 0; function initCanvas() { const rect = canvas.getBoundingClientRect(); const dpr = window.devicePixelRatio || 1; canvas.width = rect.width * dpr; canvas.height = rect.height * dpr; ctx.scale(dpr, dpr); cellSize = rect.width / (GRID_SIZE + 1); // ===== 修复点 2:移除这里的 render(),避免在 board 未就绪时渲染 ===== // 渲染工作交给 restartGame() 或动画循环 } function restartGame() { board = Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(0)); gameOver = false; isAiTurn = false; lastMove = null; statusText.innerText = "你是黑棋,请落子"; statusText.style.color = "#4a90e2"; render(); } // 每一帧动画都重绘整个棋盘和现有棋子,确保落子持续显示 function render() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 1. 绘制网格 ctx.strokeStyle = '#634d31'; ctx.lineWidth = 1; for (let i = 0; i < GRID_SIZE; i++) { ctx.beginPath(); ctx.moveTo(cellSize, cellSize * (i + 1)); ctx.lineTo(cellSize * GRID_SIZE, cellSize * (i + 1)); ctx.stroke(); ctx.beginPath(); ctx.moveTo(cellSize * (i + 1), cellSize); ctx.lineTo(cellSize * (i + 1), cellSize * GRID_SIZE); ctx.stroke(); } // 2. 绘制星位 const stars = [[3, 3], [11, 3], [7, 7], [3, 11], [11, 11]]; ctx.fillStyle = '#634d31'; stars.forEach(([x, y]) => { ctx.beginPath(); ctx.arc(cellSize * (x + 1), cellSize * (y + 1), 4, 0, Math.PI * 2); ctx.fill(); }); // 3. 稳固绘制所有棋子 for (let x = 0; x < GRID_SIZE; x++) { for (let y = 0; y < GRID_SIZE; y++) { if (board[x][y] !== 0) { drawPiece(x, y, board[x][y]); } } } // 4. 叠加最新的浮动光环 if (lastMove) { drawLastMoveHalo(lastMove.x, lastMove.y); } } function drawPiece(x, y, type) { const cx = cellSize * (x + 1); const cy = cellSize * (y + 1); const radius = cellSize * 0.43; ctx.save(); ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); const gradient = ctx.createRadialGradient(cx - radius*0.15, cy - radius*0.15, radius * 0.1, cx, cy, radius); if (type === 1) { gradient.addColorStop(0, '#666'); gradient.addColorStop(1, '#000'); } else { gradient.addColorStop(0, '#fff'); gradient.addColorStop(0.8, '#ddd'); gradient.addColorStop(1, '#bbb'); } ctx.fillStyle = gradient; ctx.shadowBlur = 4; ctx.shadowColor = "rgba(0, 0, 0, 0.3)"; ctx.shadowOffsetX = 1; ctx.shadowOffsetY = 2; ctx.fill(); ctx.restore(); } function drawLastMoveHalo(x, y) { const cx = cellSize * (x + 1); const cy = cellSize * (y + 1); const baseRadius = cellSize * 0.43; const pulse = Math.sin(haloAngle) * 3; const haloRadius = baseRadius + 3 + pulse; const opacity = 0.5 - (pulse + 3) * 0.04; ctx.save(); ctx.beginPath(); ctx.arc(cx, cy, haloRadius, 0, Math.PI * 2); ctx.strokeStyle = `rgba(74, 144, 226, ${Math.max(0.1, opacity)})`; ctx.lineWidth = 2; ctx.stroke(); ctx.restore(); } function animate() { haloAngle += 0.07; render(); requestAnimationFrame(animate); } canvas.addEventListener('click', function(e) { if (gameOver || isAiTurn) return; const rect = canvas.getBoundingClientRect(); const clientX = e.clientX - rect.left; const clientY = e.clientY - rect.top; const x = Math.round(clientX / cellSize) - 1; const y = Math.round(clientY / cellSize) - 1; if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE || board[x][y] !== 0) return; board[x][y] = 1; lastMove = { x, y }; render(); if (checkWin(x, y, 1)) { statusText.innerText = "恭喜,你赢了!🎉"; statusText.style.color = "#2ecc71"; gameOver = true; return; } isAiTurn = true; statusText.innerText = "AI 正在思考..."; statusText.style.color = "#e67e22"; setTimeout(aiMove, 300); }); function aiMove() { if (gameOver) return; let bestScore = -1; let bestPoints = []; for (let x = 0; x < GRID_SIZE; x++) { for (let y = 0; y < GRID_SIZE; y++) { if (board[x][y] === 0) { let aiScore = evaluatePoint(x, y, 2); let playerScore = evaluatePoint(x, y, 1); let totalScore = aiScore + playerScore * 0.9; if (totalScore > bestScore) { bestScore = totalScore; bestPoints = [{x, y}]; } else if (totalScore === bestScore) { bestPoints.push({x, y}); } } } } if (bestPoints.length === 0) { statusText.innerText = "平局!"; gameOver = true; return; } const move = bestPoints[Math.floor(Math.random() * bestPoints.length)]; board[move.x][move.y] = 2; lastMove = { x: move.x, y: move.y }; render(); if (checkWin(move.x, move.y, 2)) { statusText.innerText = "AI 赢了,再接再厉!"; statusText.style.color = "#e74c3c"; gameOver = true; return; } isAiTurn = false; statusText.innerText = "你是黑棋,请落子"; statusText.style.color = "#4a90e2"; } function evaluatePoint(x, y, type) { let score = 0; const directions = [[1,0], [0,1], [1,1], [1,-1]]; directions.forEach(([dx, dy]) => { let count = 1; let block1 = false; let block2 = false; let tx = x + dx, ty = y + dy; while(tx >= 0 && tx < GRID_SIZE && ty >= 0 && ty < GRID_SIZE) { if (board[tx][ty] === type) { count++; } else { if (board[tx][ty] !== 0) block1 = true; break; } tx += dx; ty += dy; } if (tx < 0 || tx >= GRID_SIZE || ty < 0 || ty >= GRID_SIZE) block1 = true; tx = x - dx; ty = y - dy; while(tx >= 0 && tx < GRID_SIZE && ty >= 0 && ty < GRID_SIZE) { if (board[tx][ty] === type) { count++; } else { if (board[tx][ty] !== 0) block2 = true; break; } tx -= dx; ty -= dy; } if (tx < 0 || tx >= GRID_SIZE || ty < 0 || ty >= GRID_SIZE) block2 = true; if (count >= 5) score += 100000; else if (count === 4) { if (!block1 && !block2) score += 10000; else if (!block1 || !block2) score += 1000; } else if (count === 3) { if (!block1 && !block2) score += 1000; else if (!block1 || !block2) score += 100; } else if (count === 2) { if (!block1 && !block2) score += 100; else if (!block1 || !block2) score += 10; } }); return score; } function checkWin(x, y, type) { const directions = [[1,0], [0,1], [1,1], [1,-1]]; for (let [dx, dy] of directions) { let count = 1; let tx = x + dx, ty = y + dy; while (tx >= 0 && tx < GRID_SIZE && ty >= 0 && ty < GRID_SIZE && board[tx][ty] === type) { count++; tx += dx; ty += dy; } tx = x - dx; ty = y - dy; while (tx >= 0 && tx < GRID_SIZE && ty >= 0 && ty < GRID_SIZE && board[tx][ty] === type) { count++; tx -= dx; ty -= dy; } if (count >= 5) return true; } return false; } window.addEventListener('resize', initCanvas); window.onload = () => { // 先初始化画布(计算 cellSize 等) initCanvas(); // 再重置游戏(初始化 board 并首次渲染) restartGame(); // 启动动画循环 animate(); }; </script> </body> </html> 改编自 @518 佬发的源码,想玩的佬友也可以试试哈 4 个帖子 - 4 位参与者 阅读完整话题

plink.anyfeeder.com · 2026-04-26 23:35:36+08:00 · tech

今天的2026斯诺克世锦赛1/8决赛上演巅峰中国德比, 卫冕冠军赵心童历经三阶段鏖战,以13-9战胜丁俊晖,职业生涯首次在世锦赛击败对手,强势晋级八强。 这是两人职业生涯首次25局13胜制长局对决,被视为中国斯诺克新老领军人物的传承之战。 首阶段8局战罢,双方势均力敌4-4平,丁俊晖第8局上演极限逆转(62:61),赵心童轰出单杆116分。 第二阶段赵心童状态飙升,长台命中率高达71%,打出单杆115分破百及3杆50+,9-7建立领先优势。 第三阶段丁俊晖顽强追至9-11,赵心童顶住压力轰出单杆108分锁定赛点,最终13-9取胜。 赵心童3杆破百、5杆50+;丁俊晖8杆50+,虽发挥稳定但关键球准度稍逊。 此役过后,赵心童成为中国斯诺克新一代核心,丁俊晖仍以39岁高龄展现顶级竞争力,两人共同撑起中国斯诺克黄金时代。 接下来1/4决赛,赵心童将迎战肖恩・墨菲,冲击世锦赛四强席位。 查看评论

www.ithome.com · 2026-04-11 21:21:19+08:00 · tech

IT之家 4 月 11 日消息,2026 年 KPL 王者荣耀职业联赛春季赛决赛于 4 月 11 日晚在海口五源河文化体育中心落幕。 苏州 KSG 以 4:0 的比分横扫重庆狼队,捧起队史首座冠军奖杯;中单选手流浪(张恒)斩获 FMVP。全新五人组(无言、句号、流浪、小屿、一笙)首个赛季即夺冠。 《王者荣耀》KPL 决赛采用七局四胜制,苏州 KSG 在四局比赛中均展现出强大的战术执行力和团队协作,以压倒性的表现零封对手,成为 KPL 历史上第九支获得联赛冠军的战队。 IT之家查询发现,此前在季后赛胜者组决赛中,重庆狼队曾以 4:0 战胜成都 AG 超玩会率先晋级,而苏州 KSG 则是在败者组完成“一穿三”的壮举,先后淘汰深圳 DYG、北京 WB 和成都 AG 超玩会后闯入总决赛,上演了从败者组逆袭夺冠的精彩剧本。 本届春决是 KSG 队史第二次闯入总决赛,此前他们曾在 2024 年 KPL 夏季赛中获得亚军。根据赛前信息,冠军战队将获得专属签名皮肤,苏州 KSG 选择了“西施-诗语江南”,4 月 16 日开放兑换。