前端技术搭建井字游戏(内含源码)

news2024/11/24 1:02:02

The sand accumulates to form a pagoda

  • ✨ 写在前面
  • ✨ 功能介绍
  • ✨ 页面搭建
  • ✨ 样式设置
  • ✨ 逻辑部分


✨ 写在前面

上周我们实通过前端基础实现了飞机大战游戏,今天还是继续按照我们原定的节奏来带领大家完成一个井字游戏游戏,功能也比较简单简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循序渐进从简单到复杂的过程,后续会带领大家用前端实现翻卡片、扫雷、贪吃蛇等有趣的小游戏,纯前端语言实现,都会陆续带给大家。欢迎大家订阅我们这份前端小游戏的专栏。订阅链接:https://blog.csdn.net/jhxl_/category_12261013.html


✨ 功能介绍

在这里插入图片描述

井字游戏是一款经典的策略性棋盘游戏,也被称为井字棋或三子棋。游戏通过在3x3的棋盘上轮流落子,目标是将自己的棋子以横、竖或对角线的形式连成一条线,先达成连线的一方获胜。这款游戏简单易学,但需要一定的思考和策略,是一款适合所有年龄段的休闲游戏。

游戏开始时,棋盘上显示一个3x3的网格,玩家扮演的是"X"棋子,计算机扮演的是"O"棋子。玩家和计算机轮流落子,每个回合可以在空白的格子中放置自己的棋子。玩家通过点击空白格子来放置"X"棋子,计算机会自动进行下棋。当任意一方的棋子以横、竖或对角线的形式连成一条线时,该方获得胜利。如果棋盘填满且没有任何一方获胜,则游戏为平局。挑战计算机,思考最佳策略,争取在井字游戏中获得胜利吧!


✨ 页面搭建

创建文件

首先呢我们创建我们的HTML文件,这里我就直接命名为 井字游戏.html 了,大家可以随意命名, 文件创建生成后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码结构,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 ! 我们敲击回车直接就会给我们生成基础版本的前端代码结构。

在这里插入图片描述

文档声明和编码设置: 在HTML文档的头部,使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。下面我就开始搭建我们的DOM结构了!

DOM结构搭建

这段HTML代码表示一个井字游戏的棋盘。让我为来看下每部分的含义吧!<div class="board">:这是游戏的棋盘容器,表示整个游戏区域。 <div class="cell">:这是每个格子,用于放置玩家和计算机的棋子。这里共有9个格子,按照3x3的形式排列,代表了井字游戏的九个位置。<div id="result"></div>:这是用于显示游戏结果的区域,初始时是空的。

在这个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,用于与上方元素保持一定的间距。

这些样式定义了游戏界面的布局、单元格的样式和游戏结果信息的样式,使界面看起来更加整齐、美观,并提供了互动性和可点击性。

<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>

在这里插入图片描述

✨ 逻辑部分

上面我们搭建了基本的样式,下面呢我们就通过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}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/526918.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

路径规划 | 图解快速随机扩展树RRT算法(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 什么是RRT算法&#xff1f;2 图解RRT算法原理3 算法仿真与实现3.1 ROS C实现3.2 Python实现3.3 Matlab实现 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全局规划(图搜索、采样法、…

〖Python网络爬虫实战㉕〗- Ajax数据爬取之Ajax 案例实战

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;目前专栏免费订阅&#xff0c;在转为付费专栏前订阅本专栏的&#xff0c;可以免费订阅付…

Gradle下载、安装、配置

1. Gradle下载 1.1 Gradle下载地址&#xff1a;https://docs.gradle.org/current/userguide/installation.html#installing_manually 1.2 点击Download 1.3 选择想要下载的版本&#xff0c;点击binary-only即可下载 2. Gradle安装&#xff08;注意&#xff1a;安装gradle之前…

【C语言】三子棋小游戏的思路及实现(内附代码)

简单不先于复杂&#xff0c;而是在复杂之后。 目录 1. 分文件实现 2.分步骤实现 2.1 游戏菜单 2.2 创建棋盘 2.3 初始化棋盘 2.4 打印棋盘 2.5 玩家下棋 2.6 电脑下棋 2.7 判断输赢 3. 附完整代码 3.1 test.c 3.2 game.h 3.2 game.c 1. 分文件实现 当我…

对称加密、非对称加密、数字签名、消息摘要的简单学习

对称加密、非对称加密、数字签名、消息摘要的简单学习 前言对称加密算法DES特点&#xff1a;为什么不使用&#xff1a; 3DES&#xff08;Triple DES 或者 DESede&#xff09;特点&#xff1a;使用场景&#xff1a;为什么不用&#xff1a; AES&#xff08;Advanced Encryption S…

聊一聊模板方法模式

统一抽取&#xff0c;制定规范&#xff1b; 一、概述 模板方法模式&#xff0c;又叫模板模式&#xff0c;属于23种设计模式中的行为型模式。在抽象类中公开定义了执行的方法&#xff0c;子类可以按需重写其方法&#xff0c;但是要以抽象类中定义的方式调用方法。总结起来就是&…

c语言实现栈(顺序栈,链栈)

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;推荐专栏: &#x1f354;&#x1f35f;&#x1f32f;C语言进阶 &#x1f511;个人信条: &#x1f335;知行合一 &#x1f349;本篇简介:>:讲解用c语言实现:“数据结构之"栈”,分别从"顺序栈…

区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测

区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRCNN-BiGRU卷积双向门控循环单元分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 1.Matlab实现基于QRCNN-BiGRU分位数回…

MySQL视图与联集

一、VIEW&#xff08;视图&#xff09; 1、 概念 可以被当作是虚拟表或存储查询 视图跟表格的不同是&#xff0c;表格中有实际储存资料&#xff0c;而视图是建立在表格之上的一个架构&#xff0c;它本身并不实际储存资料。 临时表在用户退出或同数据库的连接断开后就自动消…

DIY技巧:微星B760主板13600K降压教程 CPU温度暴降25℃

前段时间微星B600/700系主板更新了最新的BIOS&#xff0c;最新的BIOS更新&#xff1b;额105微码&#xff0c;让用户能直接在BIOS中对13代带K处理器进行降压&#xff0c;十分方便&#xff0c;今就带大家体验一下微星B760迫击炮主板的降压流程&#xff0c;其他微星B600/700系主板…

43岁,年薪200万的高管,被裁了!这4条职场潜规则,你越早知道越好

作者| Mr.K 编辑| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) 我的一位老朋友S总&#xff0c;是某世界500强外企中国区运营总监&#xff0c;光年薪就200万&#xff0c;还不包括福利、股票的部分&#xff0c;他比我略长一两岁&#xff0c;我们人生经历相似&#xf…

一文搞懂Go错误链

0. Go错误处理简要回顾 Go是一种非常强调错误处理的编程语言。在Go中&#xff0c;错误被表示为实现了error接口的类型的值&#xff0c;error接口只有一个方法&#xff1a; type error interface {Error() string } 这个接口的引入使得Go程序可以以一致和符合惯用法的方式进行错…

Python实现哈里斯鹰优化算法(HHO)优化LightGBM回归模型(LGBMRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 2019年Heidari等人提出哈里斯鹰优化算法(Harris Hawk Optimization, HHO)&#xff0c;该算法有较强的全…

有主题的图文内容创作 | AIGC实践

话说&#xff0c;昨天我发布了第一篇&#xff0c;内容由ChatGPT和Midjourney协助完成的文章&#xff1a;胡同与侏罗纪公园的时空交错 | 胡同幻想 在这篇文章中&#xff0c;大约70%图文内容由ChatGPT和Midjourney输出。我个人参与的部分&#xff0c;主要是提出指令&#xff08;P…

Monaco Editor编辑器教程(三一):在编辑器中实现模拟调试的交互

前言 最近有小伙伴咨询如何在编辑中实现 像vscode调试代码那样,可以打断点,可以高亮当前运行的一行。这样的需求并不多见,如果要做,那肯定是对编辑器做一个深层次的定制。一般很少很少会实现这种在浏览器中调试。 目前我还没见过,如果有遇到过的朋友可以指点一下。我去学…

Cesium AI GPT 文档 源码 ChatGPT问答

我用Cesium104.0的 源码 | 文档 | 3DTiles标准 作为上下文语料定制了一个智能Cesium专家问答助手 语料: 3D Tiles Specificationhttps://cesium.com/downloads/cesiumjs/releases/1.104/Build/CesiumUnminified/Cesium.jshttps://github1s.com/CesiumGS/cesium/blob/HEAD/Doc…

redis中的管道

Redis 管道 文章目录 1. 前言2. Redis 管道3. 小总结 1. 前言 通过一个问题引出 我们接下来要学习的 Redis 管道 : 提问 : 如何优化频繁命令往返造成的性能瓶颈 ? 另外 &#xff1a; 关于上面这个问题的由来 也可以简单的说一说 上面所说的思路 其实就是管道的概念 &#xff0…

读俞敏洪的书

没有认真写过一篇关于书籍的读后感文章&#xff0c;但在读完俞敏洪老师这本书后&#xff0c;想推荐给大家&#xff0c;也想分享下我的想法。 几周前&#xff0c;我在微信读书首页看到了俞敏洪老师的读书推荐 《在绝望中寻找希望》——俞敏洪写给迷茫不安的年轻人 有好几个晚上&…

电池只能充电500次?别太荒谬!收下这份真正的充电秘籍

我们的生活已经离不开电子设备了&#xff0c;而电子设备嘛&#xff0c;又离不开给它们提供能源的电池。在网上有许许多多的“延长电池寿命小技巧”&#xff0c;比如“新买的电子设备&#xff0c;第一次充电之前要把电都放完”“笔记本电脑一直插着电源可以保护电池”“长期不用…

区分COCO数据集的coco minival和coco test-dev、conda常用命令和python -m 的作用

1、COCO数据集的测试集coco minival和coco test-dev: 两个数据集在官方网站对应的内容如下所示&#xff1a; COCO数据集官网&#xff1a;https://cocodataset.org/#download 两个数据集的区分参考网址&#xff1a;https://zhuanlan.zhihu.com/p/533676547 2、conda常用命令…