
一個你打不贏的井字遊戲
繼之前的雙手互博版本的井字遊戲,這文章提供與電腦對戰版本
井字遊戲
原始碼:
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>井字棋遊戲</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
gap: 5px;
margin: 20px auto;
width: 320px;
}
.cell {
width: 100px;
height: 100px;
font-size: 36px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid black;
cursor: pointer;
background-color: #f0f0f0;
}
.cell.x {
color: blue;
}
.cell.o {
color: red;
}
#reset {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>井字棋遊戲</h1>
<p id="status">載入中...</p>
<div id="board">
<div class="cell" data-index="0"></div>
<div class="cell" data-index="1"></div>
<div class="cell" data-index="2"></div>
<div class="cell" data-index="3"></div>
<div class="cell" data-index="4"></div>
<div class="cell" data-index="5"></div>
<div class="cell" data-index="6"></div>
<div class="cell" data-index="7"></div>
<div class="cell" data-index="8"></div>
</div>
<button id="reset">重新開始</button>
<script>
const board = document.getElementById("board");
const statusText = document.getElementById("status");
const resetButton = document.getElementById("reset");
const cells = document.querySelectorAll(".cell");
let playerSymbol, computerSymbol;
let currentPlayer;
let boardState = ["", "", "", "", "", "", "", "", ""];
let gameActive = true;
let isPlayerTurn;
const winPatterns = [
[0, 1, 2], [3, 4, 5], [6, 7, 8], // 橫排
[0, 3, 6], [1, 4, 7], [2, 5, 8], // 直排
[0, 4, 8], [2, 4, 6] // 斜線
];
// 監聽玩家點擊格子
cells.forEach(cell => {
cell.addEventListener("click", handleCellClick);
});
// 處理玩家點擊事件
function handleCellClick(event) {
if (!isPlayerTurn || !gameActive) return;
const index = event.target.dataset.index;
if (boardState[index] !== "") return;
placeMove(index, currentPlayer);
if (!gameActive) return;
isPlayerTurn = false;
setTimeout(computerMove, 500); // 電腦稍作延遲再行動
}
// 電腦行動(強化 AI)
function computerMove() {
if (!gameActive) return;
let bestMove = getBestMove();
placeMove(bestMove, currentPlayer);
isPlayerTurn = true;
}
// AI 最佳選擇
function getBestMove() {
let emptyCells = boardState
.map((value, index) => (value === "" ? index : null))
.filter(index => index !== null);
// 1. **檢查是否能直接獲勝**
for (let index of emptyCells) {
boardState[index] = currentPlayer;
if (checkWin(currentPlayer)) {
boardState[index] = "";
return index;
}
boardState[index] = "";
}
// 2. **阻止玩家獲勝**
let opponent = currentPlayer === playerSymbol ? computerSymbol : playerSymbol;
for (let index of emptyCells) {
boardState[index] = opponent;
if (checkWin(opponent)) {
boardState[index] = "";
return index;
}
boardState[index] = "";
}
// 3. **優先選擇中心**
if (boardState[4] === "") return 4;
// 4. **優先選擇角落**
let corners = [0, 2, 6, 8].filter(i => boardState[i] === "");
if (corners.length > 0) return corners[Math.floor(Math.random() * corners.length)];
// 5. **選擇邊緣**
let edges = [1, 3, 5, 7].filter(i => boardState[i] === "");
if (edges.length > 0) return edges[Math.floor(Math.random() * edges.length)];
// 6. **最後隨機選擇**
return emptyCells[Math.floor(Math.random() * emptyCells.length)];
}
// 放置棋子並檢查勝負
function placeMove(index, player) {
boardState[index] = player;
cells[index].textContent = player;
cells[index].classList.add(player === "X" ? "x" : "o");
if (checkWin(player)) {
statusText.textContent = `${player === playerSymbol ? "玩家" : "電腦"} (${player}) 獲勝!`;
gameActive = false;
return;
}
if (boardState.every(cell => cell !== "")) {
statusText.textContent = "平局!";
gameActive = false;
return;
}
currentPlayer = currentPlayer === "X" ? "O" : "X";
statusText.textContent = `${currentPlayer === playerSymbol ? "玩家" : "電腦"} (${currentPlayer}) 的回合`;
}
// 檢查是否勝利
function checkWin(player) {
return winPatterns.some(pattern =>
pattern.every(index => boardState[index] === player)
);
}
// 重新開始遊戲
resetButton.addEventListener("click", startGame);
function startGame() {
boardState = ["", "", "", "", "", "", "", "", ""];
gameActive = true;
cells.forEach(cell => {
cell.textContent = "";
cell.classList.remove("x", "o");
});
// 隨機決定玩家與電腦的符號
if (Math.random() < 0.5) {
playerSymbol = "X";
computerSymbol = "O";
} else {
playerSymbol = "O";
computerSymbol = "X";
}
currentPlayer = "X"; // 遊戲固定從 X 開始
isPlayerTurn = (currentPlayer === playerSymbol);
statusText.textContent = `${isPlayerTurn ? "玩家" : "電腦"} (${currentPlayer}) 先手`;
if (!isPlayerTurn) {
setTimeout(computerMove, 500);
}
}
// 初始化遊戲
startGame();
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>井字棋遊戲</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
}
#board {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
gap: 5px;
margin: 20px auto;
width: 320px;
}
.cell {
width: 100px;
height: 100px;
font-size: 36px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
border: 2px solid black;
cursor: pointer;
background-color: #f0f0f0;
}
.cell.x {
color: blue;
}
.cell.o {
color: red;
}
#reset {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>井字棋遊戲</h1>
<p id="status">載入中...</p>
<div id="board">
<div class="cell" data-index="0"></div>
<div class="cell" data-index="1"></div>
<div class="cell" data-index="2"></div>
<div class="cell" data-index="3"></div>
<div class="cell" data-index="4"></div>
<div class="cell" data-index="5"></div>
<div class="cell" data-index="6"></div>
<div class="cell" data-index="7"></div>
<div class="cell" data-index="8"></div>
</div>
<button id="reset">重新開始</button>
<script>
const board = document.getElementById("board");
const statusText = document.getElementById("status");
const resetButton = document.getElementById("reset");
const cells = document.querySelectorAll(".cell");
let playerSymbol, computerSymbol;
let currentPlayer;
let boardState = ["", "", "", "", "", "", "", "", ""];
let gameActive = true;
let isPlayerTurn;
const winPatterns = [
[0, 1, 2], [3, 4, 5], [6, 7, 8], // 橫排
[0, 3, 6], [1, 4, 7], [2, 5, 8], // 直排
[0, 4, 8], [2, 4, 6] // 斜線
];
// 監聽玩家點擊格子
cells.forEach(cell => {
cell.addEventListener("click", handleCellClick);
});
// 處理玩家點擊事件
function handleCellClick(event) {
if (!isPlayerTurn || !gameActive) return;
const index = event.target.dataset.index;
if (boardState[index] !== "") return;
placeMove(index, currentPlayer);
if (!gameActive) return;
isPlayerTurn = false;
setTimeout(computerMove, 500); // 電腦稍作延遲再行動
}
// 電腦行動(強化 AI)
function computerMove() {
if (!gameActive) return;
let bestMove = getBestMove();
placeMove(bestMove, currentPlayer);
isPlayerTurn = true;
}
// AI 最佳選擇
function getBestMove() {
let emptyCells = boardState
.map((value, index) => (value === "" ? index : null))
.filter(index => index !== null);
// 1. **檢查是否能直接獲勝**
for (let index of emptyCells) {
boardState[index] = currentPlayer;
if (checkWin(currentPlayer)) {
boardState[index] = "";
return index;
}
boardState[index] = "";
}
// 2. **阻止玩家獲勝**
let opponent = currentPlayer === playerSymbol ? computerSymbol : playerSymbol;
for (let index of emptyCells) {
boardState[index] = opponent;
if (checkWin(opponent)) {
boardState[index] = "";
return index;
}
boardState[index] = "";
}
// 3. **優先選擇中心**
if (boardState[4] === "") return 4;
// 4. **優先選擇角落**
let corners = [0, 2, 6, 8].filter(i => boardState[i] === "");
if (corners.length > 0) return corners[Math.floor(Math.random() * corners.length)];
// 5. **選擇邊緣**
let edges = [1, 3, 5, 7].filter(i => boardState[i] === "");
if (edges.length > 0) return edges[Math.floor(Math.random() * edges.length)];
// 6. **最後隨機選擇**
return emptyCells[Math.floor(Math.random() * emptyCells.length)];
}
// 放置棋子並檢查勝負
function placeMove(index, player) {
boardState[index] = player;
cells[index].textContent = player;
cells[index].classList.add(player === "X" ? "x" : "o");
if (checkWin(player)) {
statusText.textContent = `${player === playerSymbol ? "玩家" : "電腦"} (${player}) 獲勝!`;
gameActive = false;
return;
}
if (boardState.every(cell => cell !== "")) {
statusText.textContent = "平局!";
gameActive = false;
return;
}
currentPlayer = currentPlayer === "X" ? "O" : "X";
statusText.textContent = `${currentPlayer === playerSymbol ? "玩家" : "電腦"} (${currentPlayer}) 的回合`;
}
// 檢查是否勝利
function checkWin(player) {
return winPatterns.some(pattern =>
pattern.every(index => boardState[index] === player)
);
}
// 重新開始遊戲
resetButton.addEventListener("click", startGame);
function startGame() {
boardState = ["", "", "", "", "", "", "", "", ""];
gameActive = true;
cells.forEach(cell => {
cell.textContent = "";
cell.classList.remove("x", "o");
});
// 隨機決定玩家與電腦的符號
if (Math.random() < 0.5) {
playerSymbol = "X";
computerSymbol = "O";
} else {
playerSymbol = "O";
computerSymbol = "X";
}
currentPlayer = "X"; // 遊戲固定從 X 開始
isPlayerTurn = (currentPlayer === playerSymbol);
statusText.textContent = `${isPlayerTurn ? "玩家" : "電腦"} (${currentPlayer}) 先手`;
if (!isPlayerTurn) {
setTimeout(computerMove, 500);
}
}
// 初始化遊戲
startGame();
</script>
</body>
</html>
<!DOCTYPE html> <html lang="zh-TW"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>井字棋遊戲</title> <style> body { font-family: Arial, sans-serif; text-align: center; } #board { display: grid; grid-template-columns: repeat(3, 100px); grid-template-rows: repeat(3, 100px); gap: 5px; margin: 20px auto; width: 320px; } .cell { width: 100px; height: 100px; font-size: 36px; font-weight: bold; display: flex; align-items: center; justify-content: center; border: 2px solid black; cursor: pointer; background-color: #f0f0f0; } .cell.x { color: blue; } .cell.o { color: red; } #reset { padding: 10px 20px; font-size: 16px; cursor: pointer; } </style> </head> <body> <h1>井字棋遊戲</h1> <p id="status">載入中...</p> <div id="board"> <div class="cell" data-index="0"></div> <div class="cell" data-index="1"></div> <div class="cell" data-index="2"></div> <div class="cell" data-index="3"></div> <div class="cell" data-index="4"></div> <div class="cell" data-index="5"></div> <div class="cell" data-index="6"></div> <div class="cell" data-index="7"></div> <div class="cell" data-index="8"></div> </div> <button id="reset">重新開始</button> <script> const board = document.getElementById("board"); const statusText = document.getElementById("status"); const resetButton = document.getElementById("reset"); const cells = document.querySelectorAll(".cell"); let playerSymbol, computerSymbol; let currentPlayer; let boardState = ["", "", "", "", "", "", "", "", ""]; let gameActive = true; let isPlayerTurn; const winPatterns = [ [0, 1, 2], [3, 4, 5], [6, 7, 8], // 橫排 [0, 3, 6], [1, 4, 7], [2, 5, 8], // 直排 [0, 4, 8], [2, 4, 6] // 斜線 ]; // 監聽玩家點擊格子 cells.forEach(cell => { cell.addEventListener("click", handleCellClick); }); // 處理玩家點擊事件 function handleCellClick(event) { if (!isPlayerTurn || !gameActive) return; const index = event.target.dataset.index; if (boardState[index] !== "") return; placeMove(index, currentPlayer); if (!gameActive) return; isPlayerTurn = false; setTimeout(computerMove, 500); // 電腦稍作延遲再行動 } // 電腦行動(強化 AI) function computerMove() { if (!gameActive) return; let bestMove = getBestMove(); placeMove(bestMove, currentPlayer); isPlayerTurn = true; } // AI 最佳選擇 function getBestMove() { let emptyCells = boardState .map((value, index) => (value === "" ? index : null)) .filter(index => index !== null); // 1. **檢查是否能直接獲勝** for (let index of emptyCells) { boardState[index] = currentPlayer; if (checkWin(currentPlayer)) { boardState[index] = ""; return index; } boardState[index] = ""; } // 2. **阻止玩家獲勝** let opponent = currentPlayer === playerSymbol ? computerSymbol : playerSymbol; for (let index of emptyCells) { boardState[index] = opponent; if (checkWin(opponent)) { boardState[index] = ""; return index; } boardState[index] = ""; } // 3. **優先選擇中心** if (boardState[4] === "") return 4; // 4. **優先選擇角落** let corners = [0, 2, 6, 8].filter(i => boardState[i] === ""); if (corners.length > 0) return corners[Math.floor(Math.random() * corners.length)]; // 5. **選擇邊緣** let edges = [1, 3, 5, 7].filter(i => boardState[i] === ""); if (edges.length > 0) return edges[Math.floor(Math.random() * edges.length)]; // 6. **最後隨機選擇** return emptyCells[Math.floor(Math.random() * emptyCells.length)]; } // 放置棋子並檢查勝負 function placeMove(index, player) { boardState[index] = player; cells[index].textContent = player; cells[index].classList.add(player === "X" ? "x" : "o"); if (checkWin(player)) { statusText.textContent = `${player === playerSymbol ? "玩家" : "電腦"} (${player}) 獲勝!`; gameActive = false; return; } if (boardState.every(cell => cell !== "")) { statusText.textContent = "平局!"; gameActive = false; return; } currentPlayer = currentPlayer === "X" ? "O" : "X"; statusText.textContent = `${currentPlayer === playerSymbol ? "玩家" : "電腦"} (${currentPlayer}) 的回合`; } // 檢查是否勝利 function checkWin(player) { return winPatterns.some(pattern => pattern.every(index => boardState[index] === player) ); } // 重新開始遊戲 resetButton.addEventListener("click", startGame); function startGame() { boardState = ["", "", "", "", "", "", "", "", ""]; gameActive = true; cells.forEach(cell => { cell.textContent = ""; cell.classList.remove("x", "o"); }); // 隨機決定玩家與電腦的符號 if (Math.random() < 0.5) { playerSymbol = "X"; computerSymbol = "O"; } else { playerSymbol = "O"; computerSymbol = "X"; } currentPlayer = "X"; // 遊戲固定從 X 開始 isPlayerTurn = (currentPlayer === playerSymbol); statusText.textContent = `${isPlayerTurn ? "玩家" : "電腦"} (${currentPlayer}) 先手`; if (!isPlayerTurn) { setTimeout(computerMove, 500); } } // 初始化遊戲 startGame(); </script> </body> </html>
