基于JS實(shí)現(xiàn)經(jīng)典的井字棋游戲
井字棋作為我們?cè)谏蠈W(xué)時(shí)代必玩的一款連珠游戲,你知道如何做到先手必然不會(huì)輸嗎?今天我們就用HTML、css、js來實(shí)現(xiàn)一款井字棋游戲。
先看成品
游戲初始化界面:

玩家獲勝

AI電腦獲勝

思路
生成棋盤
- 通過表格生成一個(gè)3*3的表格
- 然后通過css屬性隱藏部分邊框?qū)崿F(xiàn)井字棋盤
重新開始
- 清空文本數(shù)列刪除屬性
玩家落子
- 通過玩家點(diǎn)擊獲取id
- 通過id將點(diǎn)擊的表格塊設(shè)置為
O
電腦落子
- 通過算法來實(shí)現(xiàn)電腦最適合的塊id然后落子
代碼
HTML
<!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>CSS
* {
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;
}js
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";
//設(shè)置陣列點(diǎn) 創(chuàng)建9個(gè)數(shù)組元素,元素的鍵0到8
origBoard = Array.from(Array(9).keys());
// console.log(origBoard);
for (var i = 0; i < cells.length; i++) {
//把文本先設(shè)置為空
cells[i].innerHTML = "";
//刪除屬性知道已經(jīng)有人贏了
cells[i].style.removeProperty('background-color');
//點(diǎn)擊方塊
cells[i].addEventListener('click', turnClick, false);
}
}
function turnClick (square) {
//記住原來走過的方塊
if (typeof origBoard[square.target.id] == 'number') {
//人類玩家點(diǎn)擊
turn(square.target.id, huPlayer);
//由人類轉(zhuǎn)向AI玩家
if (!checkTie()) {
//電腦玩家將棋子放到最合適的地方
turn(bestStep(), aiPlayer);
}
}
}
function turn (squareId, player) {
//這些id給玩家
origBoard[squareId] = player;
document.getElementById(squareId).innerHTML = player;
//讓游戲進(jìn)行檢查
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)) {
//現(xiàn)在我們知道是哪一個(gè)組合勝利了
gameWin = { index: index, player: player };
break;
}
}
return gameWin;
}
/*游戲結(jié)束*/
function gameOver (gameWin) {
for (let index of winCombos[gameWin.index]) {
//人類獲勝則為藍(lán)色
document.getElementById(index).style.backgroundColor =
gameWin.player == huPlayer ? "blue" : "red";
}
/*事件偵聽器刪除單擊,已經(jīng)結(jié)束了,不能再點(diǎn)擊*/
for (var i = 0; i < cells.length; i++) {
cells[i].removeEventListener('click', turnClick, false);
}
declareWinner(gameWin.player == huPlayer ? "你贏了" : "你輸了");
}
function emptySquares () {
//過濾每一個(gè)元素,如果元素為number,返回所有方塊
return origBoard.filter(s => typeof s == 'number');
}
/*AI最優(yōu)步驟*/
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) {
//找到索引,空方塊功能設(shè)置為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 };
}
//之后進(jìn)行評(píng)估
var moves = [];
//收集每個(gè)動(dòng)作時(shí)的空白點(diǎn)
for (var i = 0; i < availSpots.length; i++) {
//然后設(shè)置空的索引號(hào)
var move = {};
move.index = newBoard[availSpots[i]];
newBoard[availSpots[i]] = player;
if (player == aiPlayer) {
//存儲(chǔ)對(duì)象,包括得分屬性
var result = minmax(newBoard, huPlayer);
move.score = result.score;
} else {
//存儲(chǔ)對(duì)象,包括得分屬性
var result = minmax(newBoard, aiPlayer);
move.score = result.score;
}
newBoard[availSpots[i]] = move.index;
moves.push(move);
}
var bestMove;
//如果是AI玩家,以非常低的數(shù)字和循環(huán)通過
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];
}以上就是基于JS實(shí)現(xiàn)經(jīng)典的井字棋游戲的詳細(xì)內(nèi)容,更多關(guān)于JS井字棋的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Javascript實(shí)現(xiàn)html轉(zhuǎn)pdf高清版(提高分辨率)
這篇文章主要介紹了Javascript將html轉(zhuǎn)成pdf高清版(提高分辨率),需要的朋友可以參考下2020-02-02
javascript仿百度輸入框提示自動(dòng)下拉補(bǔ)全
這篇文章主要介紹了javascript仿百度輸入框提示自動(dòng)下拉補(bǔ)全的相關(guān)資料,需要的朋友可以參考下2016-01-01
Bootstrap編寫一個(gè)兼容主流瀏覽器的受眾門戶式風(fēng)格頁面
這篇文章主要介紹了Bootstrap編寫一個(gè)兼容IE8、谷歌等主流瀏覽器的受眾門戶式風(fēng)格頁面,感興趣的小伙伴們可以參考一下2016-07-07
Axios?get?post請(qǐng)求傳遞參數(shù)的實(shí)現(xiàn)代碼
axios是基于promise用于瀏覽器和node.js的http客戶端,支持瀏覽器和node.js,能攔截請(qǐng)求和響應(yīng),這篇文章主要介紹了axios?get?post請(qǐng)求傳遞參數(shù)的操作代碼,需要的朋友可以參考下2022-11-11
javascript+html5實(shí)現(xiàn)繪制圓環(huán)的方法
這篇文章主要介紹了javascript+html5實(shí)現(xiàn)繪制圓環(huán)的方法,實(shí)例分析了javascript實(shí)現(xiàn)html5基于canvas繪制圓環(huán)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07

