娱乐五子棋(附加源码)

一写在开头

上期代码主要实现瀑布流功能,本期就来实现五子棋小游戏,开发久了很多功能都是通过框架组件库来完成,但是如果组件满足不了开发需求,还需要开发人员手动封装组件,专门出这样一期文章,通过原生js实现一些特定功能,功能也比较简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript,在前端中的作用,另外也培养下我们的代码思维,那我们本次就通过由简单到复杂循序渐进,这份专栏中我们还会带领大家用前端实现读心术小游戏等等有趣的小功能,纯前端语言实现,都会陆续带给大家。

实现逻辑

1.棋盘的绘制

绘制棋盘,其实就是一个 14 行 x 14 列 的 table 表格。

每个 td 会记录当前的格子是第几行第几列,我们通过自定义属性来进行记录。

data-row 记录行,data-line 记录列。

2.确定落子的坐标

当用户在棋盘上点击鼠标时,我们需要落下一颗棋子,那么如何确定这颗棋子的坐标呢?首先,通过 e.target.dataset,能够获取到用户点击的是哪一个 td,通过 e.offsetX、e.offsetY,我们就可以获取到事件发生时鼠标相对于事件源元素的坐标,所谓事件源元素就是绑定事件的那个元素。首先计算出一个格子的宽高,然后用户点击的 e.offsetX 小于格子宽度的一半,e.offsetY 小于格子高度的一半,则是左上区域。 e.offsetX 小于格子宽度的一半但是 e.offsetY 大于格子高度的一半,则是左下,依此类推。

3.绘制棋子

4.胜负判定

5.游戏已经结束,需要询问是否要重新来一局

页面创建

javascript 复制代码
<!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>五子棋小游戏2</title>
    <link rel="stylesheet" href="../css/index.css">
</head>
<body>
    <!-- 最外层的容器 -->
    <div class="container">
        <!-- 棋盘 -->
        <table class="chessboard"></table>
    </div>
    <script src="../js/index.js"></script>
</body>
</html>

样式编写

javascript 复制代码
/* 整体容器的样式 */
.container{
    border: 1px solid rgb(207, 188, 188);
    width: 500px;
    height: 500px;
    margin: 50px auto;
    /* 是一个弹性盒子,我们这边的设置代表让里面的内容水平垂直居中 */
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgb(247, 230, 183);
}

/* 棋盘里面的格子的样式 */
.chessboard{
    width: 92%;
    height: 92%;
    /* 设置表格的行列之间没有间隙 */
    border-collapse: collapse;
}

.chessboard td{
    border: 1px solid black;
    position: relative;
}

/* 棋子的公共样式 */
.chess{
    border: 1px solid lightgrey;
    border-radius: 50%;
    position: absolute;
    left: -50%;
    top: -50%;
    width: 90%;
    height: 90%;
    color: lightgrey;
    font-size : 12px;
    font-weight: bold;
    /* 让文字居中 */
    display: flex;
    justify-content: center;
    align-items: center;
}

/* 白色棋子 */
.white {
    background-color: #fff;
}

/* 黑色棋子 */
.black {
    background-color: #000;
}


/* 获胜棋子 */
.win{
    border : 1px solid red;
    box-shadow: 0 0 3px 2px red; /* 红色阴影 */
}

逻辑实现

javascript 复制代码
// 首先还是封装两个 DOM 查询的方法
function $(selector){
    return document.querySelector(selector);
}

function $$(selector){
    return document.querySelectorAll(selector);
}

var chessboard = $('.chessboard'); // 获取棋盘的 table
var isGameOver = false; // 游戏是否结束
var whichOne = 'white'; // 一开始是白色的棋子
var chessArr = []; //  存储所有的棋子信息

// 初始化棋盘的方法
function initChessboard(){
    // 我们要绘制一个 14x14 的棋盘格子,并且我们要把下标放入到每一个格子
    var tableContent = "";
    // 循环生成行
    for(var i=0;i<14;i++){
        var row = '<tr>';
        // 循环生成列
        for(var j=0;j<14;j++){
            row += `<td data-row='${i}' data-line='${j}'></td>`;
        }
        row += '</tr>';
        tableContent += row;
    }
    chessboard.innerHTML = tableContent;
}

// 绑定点击事件
function bindEvent(){
    chessboard.onclick = function(e){
        // 我们可以很轻松的知道用户点击的是哪一个 td
        if(!isGameOver){
            // 游戏没有结束,那么我们要做的事情就是落子
            var temp = Object.assign({}, e.target.dataset); // 获取到用户点击的 td 信息
            
            if(e.target.nodeName === 'TD'){
                // 我们首先计算出每个格子的边长
                var tdw = chessboard.clientWidth * 0.92 / 14;

                // 接下来我们就需要确认用户落子究竟是在四个角的哪一个角
                var positionX = e.offsetX > tdw / 2;
                var positionY = e.offsetY > tdw / 2;

                // 接下来我们来组装棋子的信息
                var chessPoint = {
                    x : positionX ? parseInt(temp.line) + 1 : parseInt(temp.line),
                    y : positionY ? parseInt(temp.row) + 1 : parseInt(temp.row),
                    c : whichOne
                }

                // 绘制棋子
                chessMove(chessPoint);
            }

        } else {
            // 游戏已经结束,需要询问是否要重新来一局
            if(window.confirm('是否要重新开始一局?')){
                // 进行一些初始化操作
                chessArr = []; // 重置棋子的数组
                initChessboard(); // 重新绘制棋盘
                isGameOver = false;
            }
        }
    }
}

// 绘制棋子,接收一个参数,就是棋子的信息的对象
function chessMove(chessPoint){
    // 我们在绘制之前,我们需要先判断一下,该位置有没有棋子,如果有棋子,那么就不需要再绘制
    if(exist(chessPoint) && !isGameOver){
        // 进入此 if,说明该位置能够绘制,并且没有游戏结束
        chessArr.push(chessPoint); // 将该棋子的信息推入到数组

        // 生成一个棋子,其实就是生成一个 div,然后将该 div 放入到对应的 td 里面
        var newChess = `<div class="chess ${chessPoint.c}" data-row="${chessPoint.y}" data-line="${chessPoint.x}"></div>`;

        // 接下来,我们需要根据不同的落子位置,调整棋子

        if(chessPoint.x < 14 && chessPoint.y < 14){
            var tdPos = $(`td[data-row='${chessPoint.y}'][data-line='${chessPoint.x}']`);
            tdPos.innerHTML += newChess;
        }

        // x 等于 14,说明是最右侧那条线
        if(chessPoint.x === 14 && chessPoint.y < 14){
            var tdPos = $(`td[data-row='${chessPoint.y}'][data-line='13']`);
            tdPos.innerHTML += newChess;
            tdPos.lastChild.style.left = '50%';
        }

        // y 等于 14,说明是最下侧那条线
        if(chessPoint.x < 14 && chessPoint.y === 14){
            var tdPos = $(`td[data-row='13'][data-line='${chessPoint.x}']`);
            tdPos.innerHTML += newChess;
            tdPos.lastChild.style.top = '50%';
        }

        // x 和 y 均等于 14,说明是最右下角的那个 td
        if(chessPoint.x === 14 && chessPoint.y === 14){
            var tdPos = $(`td[data-row='13'][data-line='13']`);
            tdPos.innerHTML += newChess;
            tdPos.lastChild.style.top = '50%';
            tdPos.lastChild.style.left = '50%';
        }

        whichOne = whichOne === 'white' ? 'black' : 'white'; // 切换棋子的颜色
    }

    check(); // 核对游戏是否结束
}

// 判断该棋子是否已经存在
function exist(chessPoint){
    var result = chessArr.find(function(item){
        return item.x === chessPoint.x && item.y === chessPoint.y;
    })
    return result === undefined ? true : false;
}

// 检查游戏是否结束,检查是否有符合要求的棋子
function check(){
    // 其实就是遍历数组里面的每一个棋子
    // 这里分为 4 种情况:横着、竖着、斜着(2 种)

    for(var i=0; i< chessArr.length; i++){
        var curChess = chessArr[i];
        var chess2, chess3, chess4, chess5;

        // 检查有没有横着的 5 个颜色一样的棋子
        chess2 = chessArr.find(function(item){
            return curChess.x === item.x + 1 && curChess.y === item.y && curChess.c === item.c;
        })
        chess3 = chessArr.find(function(item){
            return curChess.x === item.x + 2 && curChess.y === item.y && curChess.c === item.c;
        })
        chess4 = chessArr.find(function(item){
            return curChess.x === item.x + 3 && curChess.y === item.y && curChess.c === item.c;
        })
        chess5 = chessArr.find(function(item){
            return curChess.x === item.x + 4 && curChess.y === item.y && curChess.c === item.c;
        })
        if(chess2 && chess3 && chess4 && chess5){
            // 进入此 if,说明游戏结束
            end(curChess, chess2, chess3, chess4, chess5);
        }


        // 检查有没有竖着的 5 个颜色一样的棋子
        chess2 = chessArr.find(function(item){
            return curChess.x === item.x && curChess.y === item.y + 1 && curChess.c === item.c;
        })
        chess3 = chessArr.find(function(item){
            return curChess.x === item.x && curChess.y === item.y + 2 && curChess.c === item.c;
        })
        chess4 = chessArr.find(function(item){
            return curChess.x === item.x && curChess.y === item.y + 3 && curChess.c === item.c;
        })
        chess5 = chessArr.find(function(item){
            return curChess.x === item.x && curChess.y === item.y + 4 && curChess.c === item.c;
        })
        if(chess2 && chess3 && chess4 && chess5){
            // 进入此 if,说明游戏结束
            end(curChess, chess2, chess3, chess4, chess5);
        }

        // 检查有没有斜着的 5 个颜色一样的棋子
        chess2 = chessArr.find(function(item){
            return curChess.x === item.x + 1 && curChess.y === item.y + 1&& curChess.c === item.c;
        })
        chess3 = chessArr.find(function(item){
            return curChess.x === item.x + 2 && curChess.y === item.y + 2 && curChess.c === item.c;
        })
        chess4 = chessArr.find(function(item){
            return curChess.x === item.x + 3 && curChess.y === item.y + 3 && curChess.c === item.c;
        })
        chess5 = chessArr.find(function(item){
            return curChess.x === item.x + 4 && curChess.y === item.y + 4 && curChess.c === item.c;
        })
        if(chess2 && chess3 && chess4 && chess5){
            // 进入此 if,说明游戏结束
            end(curChess, chess2, chess3, chess4, chess5);
        }

        // 检查有没有斜着的 5 个颜色一样的棋子
        chess2 = chessArr.find(function(item){
            return curChess.x === item.x - 1 && curChess.y === item.y + 1&& curChess.c === item.c;
        })
        chess3 = chessArr.find(function(item){
            return curChess.x === item.x - 2 && curChess.y === item.y + 2 && curChess.c === item.c;
        })
        chess4 = chessArr.find(function(item){
            return curChess.x === item.x - 3 && curChess.y === item.y + 3 && curChess.c === item.c;
        })
        chess5 = chessArr.find(function(item){
            return curChess.x === item.x - 4 && curChess.y === item.y + 4 && curChess.c === item.c;
        })
        if(chess2 && chess3 && chess4 && chess5){
            // 进入此 if,说明游戏结束
            end(curChess, chess2, chess3, chess4, chess5);
        }
    }
}

function end(){
    if(!isGameOver){
        isGameOver = true; // 代表游戏结束

        // 1. 把所有的棋子标记出来
        for(var i=0;i<chessArr.length;i++){
            $(`div[data-row='${chessArr[i].y}'][data-line='${chessArr[i].x}']`).innerHTML = i + 1;
        }

        // 2. 把获胜的棋子加上一个红色阴影
        for(var i=0;i<arguments.length;i++){
            $(`div[data-row='${arguments[i].y}'][data-line='${arguments[i].x}']`).classList.add('win');
        }
    }
}


// 游戏的主方法,相当于程序的入口
function main(){
    // 1. 初始化棋盘
    initChessboard();

    // 2. 绑定对应的事件
    bindEvent();
}
main();

结果展示

相关推荐
candyTong12 小时前
一觉醒来,大模型就帮我排查完页面性能问题
前端·javascript·架构
玩嵌入式的菜鸡13 小时前
网页访问单片机设备---基于mqtt
前端·javascript·css
前端一小卒13 小时前
我用 Claude Code 的 Superpowers 技能链写了个服务,部署前差点把服务器搞炸
前端·javascript·后端
Dxy123931021614 小时前
HTML中的Canvas入门:从零开始绘制图形世界
html
滑雪的企鹅.15 小时前
HTML头部元信息避坑指南大纲
前端·html
浔川python社17 小时前
HTML头部元信息避坑指南技术文章大纲
前端·html
豹哥学前端18 小时前
用猜数字游戏,一口气掌握 JavaScript 核心知识点(附完整代码)
前端·javascript
忆往wu前18 小时前
从0到1一步步拆解搭建,梳理一个 Vue3 简易图书后台全开发流程
前端·javascript·vue.js
shao91851618 小时前
第3章(2)——使用Gradio JavaScript Client
javascript·node.js·cdn·gradio·job·events·playcode
光影少年18 小时前
大屏页面,一次多个请求,请求加密导致 点击 全局时间选择器 时出现卡顿咋解决(面板收起会延迟1~2秒)
前端·javascript·vue.js·学习·前端框架·echarts·reactjs