我花了一夜用数据结构给女朋友写个H5走迷宫游戏

2023-11-12

先看效果图(在线电脑尝试地址http://biggsai.com/maze.html):
在这里插入图片描述

起因

在这里插入图片描述
又到深夜了,我按照以往在公众号写着数据结构!这占用了我大量的时间!我的超越妹妹严重缺乏陪伴而 怨气满满!
在这里插入图片描述
超越妹妹时常埋怨,认为数据结构这么抽象难懂的东西没啥作用,常会问道:天天写这玩意,有啥作用。而我答道:能干事情多了,比如写个小游戏啥的!
在这里插入图片描述
当我码完字准备睡觉时:写不好别睡觉!
在这里插入图片描述

分析

如果用数据结构与算法造出东西来呢?

  • 什么东西简单容易呢?我百度一下,我靠,这个鸟游戏原来不好搞啊,得接触一堆不熟悉的东西,搞不来搞不来。

有了(灵光一闪),写个猜数字游戏,问他加减乘除等于几。

  • 超越妹妹又不是小孩子,糊弄不过去。

经过一番折腾,终于在半夜12点确定写迷宫小游戏了。大概弄清楚其中的几个步骤。

大概是

  • 画线—>画迷宫(擦线)—>方块移动、移动约束(不出界不穿墙)—>完成游戏

画线(棋盘)

对于html+js(canvas)画的东西,之前学过javaswing应该有点映像。在html中有个canvas 的画布,可以在上面画一些东西和声明一些监听(键盘监听)。

对于迷宫来说,那些线条是没有属性的,只有位置x,y,你操作这个画布时候,可能和我们习惯的面相对象思维不一样。所以,在你设计的线或者点的时候,记得那个点、线在什么位置,在后续划线还是擦线还是移动的时候根据这个位置进行操作。

 <!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>	
  </head> 
  <body>
  <canvas id="mycanvas" width="600px" height="600px"></canvas>
    
  </body>
  <script type="text/javascript">

var aa=14;
    var chess = document.getElementById("mycanvas");
    var context = chess.getContext('2d');

    //  var context2 = chess.getContext('2d');
    //      context.strokeStyle = 'yellow';
    var tree = [];//存放是否联通
    var isling=[];//判断是否相连
    for(var i=0;i<aa;i++){
        tree[i]=[];
        for(var j=0;j<aa;j++){
            tree[i][j]=-1;//初始值为0
        }
    }  for(var i=0;i<aa*aa;i++){
        isling[i]=[];
        for(var j=0;j<aa*aa;j++){
            isling[i][j]=-1;//初始值为0
        }
    }
    
    function drawChessBoard(){//绘画
        for(var i=0;i<aa+1;i++){
            context.strokeStyle='gray';//可选区域
            context.moveTo(15+i*30,15);//垂直方向画15根线,相距30px;
            context.lineTo(15+i*30,15+30*aa);
            context.stroke();
            context.moveTo(15,15+i*30);//水平方向画15根线,相距30px;棋盘为14*14;
            context.lineTo(15+30*aa,15+i*30);
            context.stroke();
        }
    }
    drawChessBoard();//绘制棋盘
   
    //      var mymap=new Array(36);
    //      for(var i=0;i<36;i++)
    //     {mymap[i]=-1;}


  </script>
</html>

实现效果
在这里插入图片描述

画迷宫

随机迷宫怎么生成?怎么搞?一脸懵逼。

  • 因为我们想要迷宫,那么就需要这个迷宫出口和入口有连通路径,你可能压根不知道迷宫改怎么生成,用的什么算法。小声BB:并查集(不相交集合)

迷宫和不相交集合有什么联系呢?(规则)

  • 之前笔者在前面数据结构与算法系列中曾经介绍过并查集(不相交集合),它的主要功能是森林的合并,不联通的通过并查集能够快速将两个森林合并,并且能够快速查询两个节点是否在同一个森林中!

我们的随机迷宫:在每个方格都不联通的情况下,是一个棋盘方格,这也是它的初始状态。而这个节点可以跟邻居可能相连,也可能不相连。我们可以通过并查集实现。

具体思路为:(主要理解并查集)

  • 1:定义好不想交集合的基本类和方法(search,union等)
    2:数组初始化,每一个数组元素都是一个集合,值为-1
    3:随机查找一个格子(一维数据要转换成二维,有点麻烦),在随机找一面墙(也就是找这个格子的上下左右),还要判断找的格子出没出界。
    具体在格子中找个随机数m——>随机数m在二维中的位置[m/长,m%长]——>这个二维的上下左右随机找一个位置p[m/长+1,m%长][m/长-1,m%长][m/长,m%长+1][m/长,m%长-1]——>判断是否越界
    4:判断两个格子(一维数组编号)是否在一个集合(并查集查找)。如果在,则重新找,如果不在,那么把墙挖去
    5:把墙挖去有点繁琐,需要考虑奇偶判断它那种墙(上下还是左右,还要考虑位置),然后擦掉。(根据数组转换成真实距离)。具体为找一个节点,根据位置关系找到一维数组的号位用并查集判断是否在一个集合中。
    6:最终得到一个完整的迷宫。直到第一个(1,1)和(n,n)联通停止。虽然采用随机数找墙,但是效果并不是特别差。其中要搞清一维二维数组的关系。一维是真实数据,并查集操作。二维是位置。要搞懂转化!

注意:避免混淆,搞清数组的地址和逻辑矩阵位置。数组从0开始的,逻辑上你自己判断。别搞混淆!
在这里插入图片描述
主要逻辑为:

while(search(0)!=search(aa*aa-1))//主要思路
    {
        var num = parseInt(Math.random() * aa*aa );//产生一个小于196的随机数
        var neihbour=getnei(num);
        if(search(num)==search(neihbour)){continue;}
        else//不在一个上
        {
           isling[num][neihbour]=1;isling[neihbour][num]=1;
            drawline(num,neihbour);//划线
            union(num,neihbour);
         
        }
    }

那么在前面的代码为

<!DOCTYPE html>
<html>
  <head>
    <title>MyHtml.html</title>	
  </head> 
  <body>
  <canvas id="mycanvas" width="600px" height="600px"></canvas>
    
  </body>
  <script type="text/javascript">
//自行添加上面代码
    //      var mymap=new Array(36);
    //      for(var i=0;i<36;i++)
    //     {mymap[i]=-1;}
    function getnei(a)//获得邻居号  random
    {
        var x=parseInt(a/aa);//要精确成整数
        var y=a%aa;
        var mynei=new Array();//储存邻居
        if(x-1>=0){mynei.push((x-1)*aa+y);}//上节点
        if(x+1<14){mynei.push((x+1)*aa+y);}//下节点
        if(y+1<14){mynei.push(x*aa+y+1);}//有节点
        if(y-1>=0){mynei.push(x*aa+y-1);}//下节点
        var ran=parseInt(Math.random() * mynei.length );
        return mynei[ran];

    }
    function search(a)//找到根节点
    {
        if(tree[parseInt(a/aa)][a%aa]>0)//说明是子节点
        {
            return search(tree[parseInt(a/aa)][a%aa]);//不能压缩路径路径压缩
        }
        else
            return a;
    }
    function value(a)//找到树的大小
    {
        if(tree[parseInt(a/aa)][a%aa]>0)//说明是子节点
        {
            return tree[parseInt(a/aa)][a%aa]=value(tree[parseInt(a/aa)][a%aa]);//不能路径压缩
        }
        else
            return -tree[parseInt(a/aa)][a%aa];
    }
    function union(a,b)//合并
    {
        var a1=search(a);//a根
        var b1=search(b);//b根
        if(a1==b1){}
        else
        {
            if(tree[parseInt(a1/aa)][a1%aa]<tree[parseInt(b1/aa)][b1%aa])//这个是负数(),为了简单减少计算,不在调用value函数
            {
                tree[parseInt(a1/aa)][a1%aa]+=tree[parseInt(b1/aa)][b1%aa];//个数相加  注意是负数相加
                tree[parseInt(b1/aa)][b1%aa]=a1;       //b树成为a树的子树,b的根b1直接指向a;
            }
            else
            {
                tree[parseInt(b1/aa)][b1%aa]+=tree[parseInt(a1/aa)][a1%aa];
                tree[parseInt(a1/aa)][a1%aa]=b1;//a所在树成为b所在树的子树
            }
        }
    }

    function drawline(a,b)//划线,要判断是上下还是左右
    {

        var x1=parseInt(a/aa);
        var y1=a%aa;
        var x2=parseInt(b/aa);
        var y2=b%aa;        
        var x3=(x1+x2)/2;
        var y3=(y1+y2)/2;
        if(x1-x2==1||x1-x2==-1)//左右方向的点  需要上下划线
        {
            //alert(x1);
            //  context.beginPath();
            context.strokeStyle = 'white';
            //    context.moveTo(30+x3*30,y3*30+15);//
            //   context.lineTo(30+x3*30,y3*30+45);
            context.clearRect(29+x3*30, y3*30+16,2,28);
            //    context.stroke();
        }
        else
        {
            //   context.beginPath();
            context.strokeStyle = 'white';
            //  context.moveTo(x3*30+15,30+y3*30);//
            //    context.lineTo(45+x3*30,30+y3*30);
            context.clearRect(x3*30+16, 29+y3*30,28,2);
            //      context.stroke();
        }
    }
     
    while(search(0)!=search(aa*aa-1))//主要思路
    {
        var num = parseInt(Math.random() * aa*aa );//产生一个小于196的随机数
        var neihbour=getnei(num);
        if(search(num)==search(neihbour)){continue;}
        else//不在一个上
        {
           isling[num][neihbour]=1;isling[neihbour][num]=1;
            drawline(num,neihbour);//划线
            union(num,neihbour);
         
        }
    }
  </script>
</html>

实现效果:
在这里插入图片描述
在这里插入图片描述

方块移动

这部分我采用的方法不是动态真的移动,而是一格一格的跳跃。也就是当走到下一个格子将当前格子的方块擦掉,在移动的那个格子中再画一个方块。选择方块是因为方块更方便擦除,可以根据像素大小精准擦除。

另外,再移动中要注意不能穿墙、越界。那么怎么判断呢?很好办,我们再前面会判断两个格子是否联通,如果不连通我们将把这个墙拆开。再拆的时候把这个墙的时候记录这两点拆墙可走即可(数组)

另外,事件的监听上下左右查一查就可以得到,添加按钮对一些事件监听,这些不是最主要的。

为了丰富游戏可玩性,将方法封装,可以设置关卡(只需改变迷宫大小)。这样就可以实现通关了。另外,如果写成动态存库那就更好了。
在这里插入图片描述

结语

在线尝试地址,代码直接查看网页源代码即可!

笔者前端能力和算法能力有限,写的可能不是特别好,还请见谅!当然,笔者欢迎和一起热爱学习的人共同进步、学习!欢迎关注笔者公众号:bigsai,后台回复java、数据结构、爬虫、springboot等有精心准备资料一份。如果感觉不错,欢迎关注、点赞!蟹蟹!

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我花了一夜用数据结构给女朋友写个H5走迷宫游戏 的相关文章

  • 01背包问题变种:从长度为n的数组里选出m个数使和为固定值sum

    这个问题是我从leetcode上一道问题所想到的 原题 如果是从数组中选出2个数相加使之成为固定的数sum 这当然很简单 把数组中的数字遍历一遍 判断另一个数字是否也在数组中即可 代码如下 vector
  • Mysql 数据库

    数据库基础 1 什么是数据库 用来存储数据 数据库可在硬盘及内存中存储数据 数据库与文件存储数据的区别 数据库本质也是通过文件来存储数据 数据库的概念就是系统的管理存储数据的文件 数据库介绍 本质就是存储数据的C S架构的socket套接字
  • netty handler的执行顺序(3)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 今天解决2个问题 1 handler在pipeline当中究竟是如何存储的 2 在遍历handler的过程中 会根据event的不同 调用不同的handler 这一点是如何
  • 第二十八节、基于深度学习的目标检测算法的综述(附代码,并附有一些算法英文翻译文章链接))...

    在前面几节中 我们已经介绍了什么是目标检测 以及如何进行目标检测 还提及了滑动窗口 bounding box 以及IOU 非极大值抑制等概念 这里将会综述一下当前目标检测的研究成果 并对几个经典的目标检测算法进行概述 本文内容来自基于深度学
  • 链表和线性表的优缺点

    链表和线性表的优缺点 作为我们最先接触的两个数据结构 链表和线性表的优缺点都较为明显 并且二者互相补足 文章目录 链表和线性表的优缺点 线性表 线性表的组成 线性表的缺点 线性表的优点 链表 链表的组成 链表的优点 链表的缺点 总结 线性表
  • 用 Java 实现的八种常用排序算法

    八种排序算法可以按照如图分类 前置知识 1 算法稳定性 在一个序列中 能保证两个相等的数 经过排序之后 其在序列的前后位置顺序不变 A1 A2 排序前 A1 在 A2 前面 排序后 A1 还在 A2 前面 2 时间复杂度 时间复杂度是用于衡
  • 逆波兰表达式求值(C语言实现)

    实验项目 从文本文件输入任意一个语法正确的 中缀 表达式 显示并保存该表达式 利用栈结构 把上述 中缀 表达式转换成后缀表达式 并显示栈的状态变化过程和所得到的后缀表达式 利用栈结构 对上述后缀表达式进行求值 并显示栈的状态变化过程和最终结
  • 数据结构与算法学习总结(六)——字符串的模式匹配算法

    基本概念 字符串是一种特殊的线性表 即元素都是 字符 的线性表 字符是组成字符串的基本单位 字符的取值依赖于字符集 例如二进制的字符集为0 1 则取值只能为 0 1 再比如英语语言 则包括26个字母外加标点符号 例如 abcde 就是一个字
  • 【NOI 2015】程序自动分析

    题目 传送门 题目描述 在实现程序自动分析的过程中 常常需要判定一些约束条件是否能被同时满足 考虑一个约束满足问题的简化版本 假设 x 1 x 2
  • 数据结构小白之插入排序算法

    1 插入排序 1 1 思路 将n个需要排序的元素看成两个部分 一个是有序部分 一个是无序部分 开始的时候有序表只有一个元素 无序表有n 1个元素 排序过程中每次从无序表中取出元素 然后插入到有序表的适当位置 从而成为新的有序表 类似排队 如
  • 『Python基础-15』递归函数 Recursion Function

    什么是递归函数 一种计算过程 如果其中每一步都要用到前一步或前几步的结果 称为递归的 用递归过程定义的函数 称为递归函数 例如连加 连乘及阶乘等 凡是递归的函数 都是可计算的 即能行的 递归就是一个函数在它的函数体内调用它自身 编程语言中的
  • 算法系列15天速成——第八天 线性表【下】

    一 线性表的简单回顾 上一篇跟大家聊过 线性表 顺序存储 通过实验 大家也知道 如果我每次向 顺序表的头部插入元素 都会引起痉挛 效率比较低下 第二点我们用顺序存储时 容 易受到长度的限制 反之就会造成空间资源的浪费 二 链表 对于顺序表存
  • 字符串09--表示数值的字符串

    字符串09 表示数值的字符串 jz53 题目概述 解析 参考答案 注意事项 说明 题目概述 算法说明 请实现一个函数用来判断字符串是否表示数值 包括整数和小数 例如 字符串 100 5e2 123 3 1416 和 1E 16 都表示数值
  • JavaScript系列——数组元素左右移动N位算法实现

    引言 在自己刚刚毕业不久的时候 去了一家公司面试 面试官现场考了我这道题 我记忆深刻 当时没有想到思路 毫无疑问被面试官当成菜鸟了 最近刚好在研究数组的各种算法实现 就想到这道题 可以拿来实现一下 纪念自己逝去的青春 需求 假设有这样一个数
  • 数据结构与算法-列表(双向链表)设计及其排序算法

    0 概述 本文主要涵盖列表 双向链表 的设计及其排序算法的总结 列表是一种典型的动态存储结构 其中的数据 分散为一系列称作节点 node 的单位 节点之间通过指针相互索引和访问 为了引入新节点或删除原有节点 只需在局部调整少量相关节点之间的
  • Linux下进程退出的几种形式

    进程退出 Linux 下进程的退出分为正常退出和异常退出两种 1 正常退出 a 在main 函数中执行return b 调用exit 函数 c 调用 exit 函数 2 异常退出 a 调用about函数 b 进程收到某个信号 而该信号使程序
  • 索引优化之Explain 及慢查询日志

    索引 本质是数据结构 简单理解为 排好序的快速查找数据结构 以索引文件的形式存储在磁盘中 目的 提高数据查询的效率 优化查询性能 就像书的目录一样 优势 提高检索效率 降低IO成本 排好序的表 降低CPU的消耗劣势 索引实际也是一张表 该表
  • 浅谈归并排序:合并 K 个升序链表的归并解法

    在面试中遇到了这道题 如何实现多个升序链表的合并 这是 LeetCode 上的一道原题 题目具体如下 用归并实现合并 K 个升序链表 LeetCode 23 合并K个升序链表 给你一个链表数组 每个链表都已经按升序排列 请你将所有链表合并到
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤
  • 最大流-Dinic算法,原理详解,四大优化,详细代码

    文章目录 零 前言 一 概念回顾 可略过 1 1流网络 1 2流 1 3最大流 1 4残留网络 1 5增广路

随机推荐

  • SQL笔记(一)

    1 初识MySQL JavaEE 企业级Java开发 Web 前端 页面 展示 数据 后台 连接点 连接数据库JDBC 链接前端 控制 控制视图跳转 和给前端传递数据 数据库 存数据 ITxt Excel word 只会写代码 学好数据库
  • sqli-labs (less-39)

    sqli labs less 39 输入id 1 http 127 0 0 1 sql1 Less 39 id 1 根据错误显示判断为数字型注入 这里我们就不讲使用union注入的方法 前面的关卡讲了很多union注入的方法 我们直接使用堆
  • word:表格中的文字居中

    如 操作 如下图 选择布局 点击2就可以把表格居中了 居中结果
  • 实时ETL解决方案总结

    问题导读1 实时ETL可以选择哪些架构部件 2 实时ETL有哪些实现方法 3 实时ETL有哪些难点 1 简述在架构实时ETL时的可以选择的架构部件 答 在建立数据仓库时 ETL通常都采用批处理的方式 一般来说是每天的夜间进行跑批 随着数据仓
  • 【MyBatis】一天之内快速掌握MyBatis的增删改查

    MyBatis 文章介绍 一共不到8000字 一天之内可以快速学会mybatis的增删改查 以及经常使用的操作 不讲废话 只将眼光聚焦到实操上 也可以搭配黑马的视频观看 看完之后 可以自己找个mybatis源码课继续学习 但是一般的业务代码
  • Eclipse的安装与基本操作(详解配图)

    不为失败找理由 只为成功找方法 所有的不甘 都是因为还心存梦想 在你放弃之前 好好拼一把 只怕心老 不怕路长 文章目录 一 简介 二 下载 三 使用Eclipse编写第一个Java程序 四 Eclipse的基本操作 1 背景 2 字体 五
  • Windows10系统MySQL服务器简单安装

    Windows10系统MySQL服务器简单安装 Mysql下载 安装 修改MySQL数据保存地址 修改服务 初始化数据库 修改root密码 新增用户 Mysql下载 MySql官网下载 下载地址 https dev mysql com do
  • 创建M32F103C8T6的工程文件之后编译为什么一堆错误?

    首先先看错误的提示是不是以下的显示 Rebuild started Project STM32F103C8T6 Using Compiler V6 15 folder F keil ARM ARMCLANG Bin Rebuild targ
  • 关于vxe-table全局引入的问题

    主要讲解一下vxe table全局引入然后使用碰到的问题 0 vxe table的官网地址 1 基本环境 1 vue版本为3 x以上 我的是3 2 13 2 依赖库 xe utils 注意 这篇博客的是vue3的脚手架搭建的 如果需要看低版
  • 毕业设计-机器视觉的疲劳驾驶检测系统-python-opencv

    目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 大四是整个大学期间最忙碌的时光 一边要忙着备考或实习为毕业后面临的就业升学做准备 一边要为毕业设计耗费大量精力 近几年各个学校要求的毕设项目越来越难 有不少课题是研究生级别难度
  • vue-admin-template,连接自己后台,二次开发必看

    第一步 找到 env development文件做如下修改 just a flag ENV development base api VUE APP BASE API api 第二步 找到 vue config js 配置跨域 关闭mock
  • Ubuntu 20版本将动态ip修改为静态ip时,ping 不通网络

    问题描述 在对Ubuntu 20版本将动态ip修改为静态ip时 ping www baidu com ping不通了 火狐浏览器没有了网路 下载不了东西 一直卡在这里不动 问题出在哪里还是配置ip dns 网关的问题 如果我们在当初安装ub
  • Spring:从零开始的Cloud生活(零)——Eureka 服务治理

    目录 Spring 从零开始的Cloud生活 零 Eureka 服务治理 1 Netfilx Eurake 2 搭建服务注册中心 3 服务提供者 4 高可用注册中心 5 服务发现和消费 之前对于SpringCloud都是一知半解的状态 现在
  • MySQL中的模糊查询

    1 表示任意0个或多个字符 可匹配任意类型和长度的字符 有些情况下若是中文 请使用两个百分号 表示 比如 SELECT FROM user WHERE u name LIKE 三 将会把u name为 张三 张猫三 三脚猫 唐三藏 等等有
  • python调用turtle(海龟画图),画一个正方形

    调用海龟画图 画一个正方形 方法一 调用海龟画图 import turtle bob turtle Turtle print bob 定义画图的方向 此处画了一个直角 bob fd 100 bob lt 90 加入以下步骤画了一个正方形 b
  • Linux Shell学习简单小结(更新中……)

    if fi bin bash 删除文件 和 新建文件 file readme function delFile if e file then rm f file echo del file fi function addFile if f
  • YOLO系列发展史

    YOLO You Only Look Once 是一种目标检测算法 由Joseph Redmon等人在2015年提出 它的主要思想是将目标检测任务看作是一个回归问题 并且可以在一个神经网络中同时预测目标的位置和类别 自2015年YOLO第一
  • ChatGPT会取代互联网程序员吗?

    ChatGPT会取代互联网程序员吗 ChatGPT是一个基于GPT 3模型的自然语言对话系统 它可以与用户进行自然 流畅 智能的对话交互 回答用户的问题 提供用户所需的信息 甚至生成一些有趣和创意的内容 ChatGPT最近火爆全网 一时间C
  • Linux系统启动分析

    文章目录 大体流程分析 一 BIOS 1 1 BIOS简介 1 2 POST 二 BootLoader GRUB 2 1 What s MBR 2 2 What s GRUB 2 3 boot img 2 4 core img lzma d
  • 我花了一夜用数据结构给女朋友写个H5走迷宫游戏

    文章目录 起因 分析 画线 棋盘 画迷宫 方块移动 结语 先看效果图 在线电脑尝试地址http biggsai com maze html 起因 又到深夜了 我按照以往在公众号写着数据结构 这占用了我大量的时间 我的超越妹妹严重缺乏陪伴而