时间:2022-07-01 09:48:11 | 栏目:JavaScript代码 | 点击:次
井字棋作为我们在上学时代必玩的一款连珠游戏,你知道如何做到先手必然不会输吗?今天我们就用HTML、css、js来实现一款井字棋游戏。
O
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>井字棋</title> <link rel="stylesheet" href="css.css" rel="external nofollow" /> </head> <body> <table> <tr> <td class="cell" id="0"></td> <td class="cell" id="1"></td> <td class="cell" id="2"></td> </tr> <tr> <td class="cell" id="3"></td> <td class="cell" id="4"></td> <td class="cell" id="5"></td> </tr> <tr> <td class="cell" id="6"></td> <td class="cell" id="7"></td> <td class="cell" id="8"></td> </tr> </table> <div class="endgame"> <div class="text"></div> </div> <button onclick="startGame()">重新开始</button> <script src="js.js"></script> </body> </html>
* { margin: 0; padding: 0; } button { position: absolute; position: absolute; left: 50%; margin-left: -65px; top: 50px; } td { border: 2px solid #333; width: 100px; height: 100px; text-align: center; vertical-align: middle; font-family: '微软雅黑'; font-style: italic; font-size: 70px; cursor: pointer; } table { /*margin: 30px auto;*/ position: absolute; left: 40%; top: 100px; border-collapse: collapse; } table tr:first-child td { border-top: 0; } table tr:last-child td { border-bottom: 0; } table tr td:first-child { border-left: 0; } table tr td:last-child { border-right: 0; } .endgame { display: none; width: 200px; height: 120px; background-color: rgba(205, 132, 65, 0.8); position: absolute; left: 40%; top: 180px; margin-left: 50px; text-align: center; border-radius: 5px; color: white; font-size: 2em; }
var origBoard; const huPlayer = 'O'; const aiPlayer = 'X'; const winCombos = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [6, 4, 2] ] /*获取元素*/ const cells = document.querySelectorAll(".cell"); startGame(); function startGame () { document.querySelector(".endgame").style.display = "none"; //设置阵列点 创建9个数组元素,元素的键0到8 origBoard = Array.from(Array(9).keys()); // console.log(origBoard); for (var i = 0; i < cells.length; i++) { //把文本先设置为空 cells[i].innerHTML = ""; //删除属性知道已经有人赢了 cells[i].style.removeProperty('background-color'); //点击方块 cells[i].addEventListener('click', turnClick, false); } } function turnClick (square) { //记住原来走过的方块 if (typeof origBoard[square.target.id] == 'number') { //人类玩家点击 turn(square.target.id, huPlayer); //由人类转向AI玩家 if (!checkTie()) { //电脑玩家将棋子放到最合适的地方 turn(bestStep(), aiPlayer); } } } function turn (squareId, player) { //这些id给玩家 origBoard[squareId] = player; document.getElementById(squareId).innerHTML = player; //让游戏进行检查 var gameWin = checkWin(origBoard, player); if (gameWin) { gameOver(gameWin); } } //判断胜利 function checkWin (board, player) { let plays = board.reduce((a, e, i) => (e === player) ? a.concat(i) : a, []) let gameWin = null; //如果是属于之前winCombos胜利组合 for (let [index, win] of winCombos.entries()) { if (win.every(Element => plays.indexOf(Element) > -1)) { //现在我们知道是哪一个组合胜利了 gameWin = { index: index, player: player }; break; } } return gameWin; } /*游戏结束*/ function gameOver (gameWin) { for (let index of winCombos[gameWin.index]) { //人类获胜则为蓝色 document.getElementById(index).style.backgroundColor = gameWin.player == huPlayer ? "blue" : "red"; } /*事件侦听器删除单击,已经结束了,不能再点击*/ for (var i = 0; i < cells.length; i++) { cells[i].removeEventListener('click', turnClick, false); } declareWinner(gameWin.player == huPlayer ? "你赢了" : "你输了"); } function emptySquares () { //过滤每一个元素,如果元素为number,返回所有方块 return origBoard.filter(s => typeof s == 'number'); } /*AI最优步骤*/ function bestStep () { //智能AI return minmax(origBoard, aiPlayer).index; } //检查是否是平局 function checkTie () { if (emptySquares().length == 0) { for (var i = 0; i < cells.length; i++) { cells[i].style.backgroundColor = "green"; cells[i].removeEventListener('click', turnClick, false); } //谁获胜了 // declareWinner("玩家获胜"); return true; } else { //平局 return false; } } function declareWinner (who) { document.querySelector(".endgame").style.display = 'block'; document.querySelector(".endgame .text").innerHTML = who; } function minmax (newBoard, player) { //找到索引,空方块功能设置为a var availSpots = emptySquares(newBoard); if (checkWin(newBoard, player)) { return { score: -10 }; } else if (checkWin(newBoard, aiPlayer)) { return { score: 20 }; } else if (availSpots.length === 0) { return { score: 0 }; } //之后进行评估 var moves = []; //收集每个动作时的空白点 for (var i = 0; i < availSpots.length; i++) { //然后设置空的索引号 var move = {}; move.index = newBoard[availSpots[i]]; newBoard[availSpots[i]] = player; if (player == aiPlayer) { //存储对象,包括得分属性 var result = minmax(newBoard, huPlayer); move.score = result.score; } else { //存储对象,包括得分属性 var result = minmax(newBoard, aiPlayer); move.score = result.score; } newBoard[availSpots[i]] = move.index; moves.push(move); } var bestMove; //如果是AI玩家,以非常低的数字和循环通过 if (player === aiPlayer) { var bestScore = -1000; for (var i = 0; i < moves.length; i++) { if (moves[i].score > bestScore) { bestScore = moves[i].score; bestMove = i; } } } else { var bestScore = 1000; for (var i = 0; i < moves.length; i++) { if (moves[i].score < bestScore) { bestScore = moves[i].score; bestMove = i; } } } return moves[bestMove]; }