The sand accumulates to form a pagoda
- ✨ 写在前面
- ✨ 功能介绍
- ✨ 页面搭建
- ✨ 样式设置
- ✨ 逻辑部分
✨ 写在前面
上周我们实通过前端基础实现了飞机大战游戏,今天还是继续按照我们原定的节奏来带领大家完成一个井字游戏游戏,功能也比较简单简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循序渐进从简单到复杂的过程,后续会带领大家用前端实现翻卡片、扫雷、贪吃蛇等有趣的小游戏,纯前端语言实现,都会陆续带给大家。欢迎大家订阅我们这份前端小游戏的专栏。订阅链接:https://blog.csdn.net/jhxl_/category_12261013.html
✨ 功能介绍
井字游戏是一款经典的策略性棋盘游戏,也被称为井字棋或三子棋。游戏通过在3×3的棋盘上轮流落子,目标是将自己的棋子以横、竖或对角线的形式连成一条线,先达成连线的一方获胜。这款游戏简单易学,但需要一定的思考和策略,是一款适合所有年龄段的休闲游戏。
游戏开始时,棋盘上显示一个3×3的网格,玩家扮演的是”X”棋子,计算机扮演的是”O”棋子。玩家和计算机轮流落子,每个回合可以在空白的格子中放置自己的棋子。玩家通过点击空白格子来放置”X”棋子,计算机会自动进行下棋。当任意一方的棋子以横、竖或对角线的形式连成一条线时,该方获得胜利。如果棋盘填满且没有任何一方获胜,则游戏为平局。挑战计算机,思考最佳策略,争取在井字游戏中获得胜利吧!
✨ 页面搭建
创建文件
首先呢我们创建我们的HTML文件,这里我就直接命名为 井字游戏.html
了,大家可以随意命名, 文件创建生成后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码结构,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 !
我们敲击回车直接就会给我们生成基础版本的前端代码结构。
文档声明和编码设置: 在HTML文档的头部,使用声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。下面我就开始搭建我们的DOM结构了!
DOM结构搭建
这段HTML代码表示一个井字游戏的棋盘。让我为来看下每部分的含义吧!:这是游戏的棋盘容器,表示整个游戏区域。
:这是每个格子,用于放置玩家和计算机的棋子。这里共有9个格子,按照3×3的形式排列,代表了井字游戏的九个位置。
:这是用于显示游戏结果的区域,初始时是空的。
在这个HTML结构中,通过使用CSS样式和JavaScript代码,可以实现井字游戏的显示、交互和结果展示。玩家可以点击格子,在空白的位置放置自己的棋子,然后计算机会根据规则进行下一步的落子,最终判断是否有玩家获胜或者平局。当然我们写上下面代码打开页面也是空白的,因为我们虽然写了标签,但是标签里面没有任何内容!
<div class="board"><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div></div><div id="result"></div>
✨ 样式设置
我们看到了上面的的DOM已经搭建好了,但是页面什么都看不出来,下面我们简单的来配置一下样式吧,其实我们本专栏也是想带领大家掌握一些逻辑所以样式方面我们就一切从简;
这段样式代码定义了游戏界面的外观和布局。让我为小白逐个解释每个样式的含义:
.board
:这是一个类选择器,用于选择游戏棋盘的容器元素。
display: grid;
:设置元素的布局方式为网格布局。grid-template-columns: repeat(3, 1fr);
:定义了网格的列数为 3,每列的宽度平均分配。grid-template-rows: repeat(3, 1fr);
:定义了网格的行数为 3,每行的高度平均分配。gap: 5px;
:设置了网格之间的间隔为 5px。width: 300px;
:设置了容器的宽度为 300px。height: 300px;
:设置了容器的高度为 300px。margin: 0 auto;
:使容器在水平方向上居中对齐。border: 1px solid #ccc;
:设置容器的边框为 1px 的实线边框,颜色为 #ccc。padding: 5px;
:设置容器的内边距为 5px。
.cell
:这是一个类选择器,用于选择游戏棋盘中的每个单元格元素。
display: flex;
:设置元素的布局方式为弹性布局。align-items: center;
:在交叉轴上居中对齐元素内容。justify-content: center;
:在主轴上居中对齐元素内容。font-size: 24px;
:设置字体大小为 24px。font-weight: bold;
:设置字体加粗。background-color: #f2f2f2;
:设置背景颜色为 #f2f2f2,即浅灰色。cursor: pointer;
:将鼠标光标设置为手型指示器,表示单元格可以点击。
#result
:这是一个 ID 选择器,用于选择游戏结果信息的元素。
text-align: center;
:将文本内容居中对齐。font-size: 24px;
:设置字体大小为 24px。margin-top: 20px;
:设置顶部外边距为 20px,用于与上方元素保持一定的间距。
这些样式定义了游戏界面的布局、单元格的样式和游戏结果信息的样式,使界面看起来更加整齐、美观,并提供了互动性和可点击性。
.board {display: grid;grid-template-columns: repeat(3, 1fr);grid-template-rows: repeat(3, 1fr);gap: 5px;width: 300px;height: 300px;margin: 0 auto;border: 1px solid #ccc;padding: 5px;}.cell {display: flex;align-items: center;justify-content: center;font-size: 24px;font-weight: bold;background-color: #f2f2f2;cursor: pointer;}#result {text-align: center;font-size: 24px;margin-top: 20px;}
✨ 逻辑部分
上面我们搭建了基本的样式,下面呢我们就通过js代码,实现我们游戏的功能吧首先我们定义了一些变量,来使用:
const board
:表示游戏棋盘的状态数组,存储每个格子的标记。const cells
:存储所有格子的元素,用于操作和监听每个格子。const resultElement
:用于显示游戏结果的元素。let currentPlayer
:表示当前玩家的标记,初始为 “X”。let gameEnded
:表示游戏是否结束的标志,初始为false
。
const board = ["", "", "", "", "", "", "", "", ""];const cells = document.querySelectorAll(".cell");const resultElement = document.getElementById("result");let currentPlayer = "X";let gameEnded = false;
同时我们编写了一些函数,下面就是每个函数的大致作用:
updateGameState(cellIndex)
:更新游戏状态,处理玩家的移动。checkWin(player)
:检查玩家是否获胜。checkDraw()
:检查游戏是否平局。endGame(message)
:结束游戏,显示最终结果。makeComputerMove()
:模拟电脑进行移动。renderBoard()
:渲染棋盘状态。resetGame()
:重置游戏为初始状态。
最后,通过监听格子的点击事件,调用 updateGameState
函数处理玩家的移动,并在页面加载完成后调用 resetGame
函数初始化游戏。
<script>function updateGameState(cellIndex) {if (!gameEnded && board[cellIndex] === "") {board[cellIndex] = currentPlayer;renderBoard();if (checkWin(currentPlayer)) {endGame("Player " + currentPlayer + " wins!");} else if (checkDraw()) {endGame("It's a draw!");} else {currentPlayer = currentPlayer === "X" " />"O" : "X";if (currentPlayer === "O") {setTimeout(makeComputerMove, 500);}}}}function checkWin(player) {const winningCombinations = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]];for (let i = 0; i < winningCombinations.length; i++) {const [a, b, c] = winningCombinations[i];if (board[a] === player && board[b] === player && board[c] === player) {return true;}}return false;}function checkDraw() {return board.every(cell => cell !== "");}function endGame(message) {gameEnded = true;resultElement.textContent = message;}function makeComputerMove() {const emptyCells = board.reduce((acc, cell, index) => {if (cell === "") {acc.push(index);}return acc}, []);if (emptyCells.length > 0) {const randomIndex = Math.floor(Math.random() * emptyCells.length);const computerMove = emptyCells[randomIndex];updateGameState(computerMove);}}function renderBoard() {for (let i = 0; i < cells.length; i++) {cells[i].textContent = board[i];}}function resetGame() {board.fill("");currentPlayer = "X";gameEnded = false;resultElement.textContent = "";renderBoard();}cells.forEach((cell, index) => {cell.addEventListener("click", () => updateGameState(index));});resetGame();</script>
完整代码
<!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>Document</title><style>.board {display: grid;grid-template-columns: repeat(3, 1fr);grid-template-rows: repeat(3, 1fr);gap: 5px;width: 300px;height: 300px;margin: 0 auto;border: 1px solid #ccc;padding: 5px;}.cell {display: flex;align-items: center;justify-content: center;font-size: 24px;font-weight: bold;background-color: #f2f2f2;cursor: pointer;}#result {text-align: center;font-size: 24px;margin-top: 20px;}</style></head><body><div class="board"><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div><div class="cell"></div></div><div id="result"></div></body><script>const board = ["", "", "", "", "", "", "", "", ""];const cells = document.querySelectorAll(".cell");const resultElement = document.getElementById("result");let currentPlayer = "X";let gameEnded = false;function updateGameState(cellIndex) {if (!gameEnded && board[cellIndex] === "") {board[cellIndex] = currentPlayer;renderBoard();if (checkWin(currentPlayer)) {endGame("Player " + currentPlayer + " wins!");} else if (checkDraw()) {endGame("It's a draw!");} else {currentPlayer = currentPlayer === "X" ? "O" : "X";if (currentPlayer === "O") {setTimeout(makeComputerMove, 500);}}}}function checkWin(player) {const winningCombinations = [[0, 1, 2],[3, 4, 5],[6, 7, 8],[0, 3, 6],[1, 4, 7],[2, 5, 8],[0, 4, 8],[2, 4, 6]];for (let i = 0; i < winningCombinations.length; i++) {const [a, b, c] = winningCombinations[i];if (board[a] === player && board[b] === player && board[c] === player) {return true;}}return false;}function checkDraw() {return board.every(cell => cell !== "");}function endGame(message) {gameEnded = true;resultElement.textContent = message;}function makeComputerMove() {const emptyCells = board.reduce((acc, cell, index) => {if (cell === "") {acc.push(index);}return acc}, []);if (emptyCells.length > 0) {const randomIndex = Math.floor(Math.random() * emptyCells.length);const computerMove = emptyCells[randomIndex];updateGameState(computerMove);}}function renderBoard() {for (let i = 0; i < cells.length; i++) {cells[i].textContent = board[i];}}function resetGame() {board.fill("");currentPlayer = "X";gameEnded = false;resultElement.textContent = "";renderBoard();}cells.forEach((cell, index) => {cell.addEventListener("click", () => updateGameState(index));});resetGame();</script></html>
本期推荐 点击此处购买
✨ 原创不易,还希望各位大佬支持一下\textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下
点赞,你的认可是我创作的动力!\textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!\textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!\textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!