用JS写一个连连看小程序

思路

  1. 决定内容区域的大小和图片种类数量
    • 图片应该放多少行,多少列。必须是偶数
    • 整个区域应该是在图片外多围上一圈,也就是行数和列数都应该比图片的多1
    • 放多少对图片,一对两张。注意对数不能超过所有图片总数
  2. 根据行列数来创建两个必要的数组
    • 一个数组保存所有小格子的行数和列数
      • 应该使用一个二维数组
      • 一维代表当前行数
      • 二维当前当前列数
    • 一个数组保存按一对一对的形式来保存图片名
      • 图片名以1,2,3...来命名,容易使用
      • 数组中保存的值就是以[1,1,2,2....]这样保存图片名
  3. 开始渲染出整个游戏的页面
    • 打乱保存了图片名的数组
    • 遍历保存了所有小格子的数组,根据行数创建tr,根据列数创建td
    • 如果这个这个td不是第一行,最后一行,第一列,最后一列。因为最外围需要给后面连线留空位。
    • 根据打乱后的图片数组(以下称随机数组),往保存了小格子的数组(以下称为大数组)中添加图片名。
    • 创建图片对象,添加到td中,根据随机数组中的值来添加图片的src属性
    • 给图片对象中添加两个关键值。即对应的行数和列数。行数就是大数组的一维值,列数就是二维值。
    • 给所有的图片都注册一个点击事件
  4. 点击图片查找路径是否符合要求

    这是最里面最关键的部分,这里涉及到我们怎么来判断两张图是否能连通的问题。后面我们用一张图来看看连连看中怎样才能相连。

    • 点击的两张图片相邻,直接可消除。
    • 点击的两张图片不相邻。(以下简称两张图片分别为A点和B点)
      • 获取A点和B点的十字线上的点的行列数。
      • 遍历A点十字线上的点,当上面有一个点上面没有图片并且与A点之间没有任何一张图片,我们称这个点为有效点A(至于怎么判断有没有图片,只需要判断点的行列数在大数组中的值是否是0,非0即为有图片)
      • 当存在有效点A,我们再拿到B点十字线和A点行数相等或者列数相等的两个点的坐标。
      • 判断B点十字线上的获得到的两个点上是否有图片并且它们的坐标和B点之间是否有图片,没有图片的话我们称那个点为有效点B
      • 判断有效点A和有效点B之间有没有图片,没有图片即为连通。即这两张图片可以消除。
    注意这四个点非常有用 ,而且能够连通的路线并不只有一条。
  5. 根据路径来连线

这里需要配合CSS来连线,CSS中已经写好了线的类样式,后面只要找准方向,添加相应的类样式即可

  + 拿到所有能够连通的四个点。
  + 根据这四个点获取其中的最短路径的一个路线
      - 如果路线只有一条,那么这一条就是最短路径
      - 如果有一条路线中 有效点A和有效点B 重合了,那么这条路径就是最短路径。
      - 如果是四个不一样的点,那么根据 A点和有效点A的距离 + B点和有效点B的距离 + 有效点A和有效点B之间的距离的和的大小来判断,最小的那一个即为最短路径。
  + 判断有效点上画线的方向
      - 有效点A在A点右边,画线的方向就往左
      - 有效点A在有效点B的下面,有效点A画线的方向就往上,有效点B画线的方向就往下。
      - 有效点B在B点右边,画线的方向就往作
      - 最后把方向拼接起来,格式化之后得到 topLeft,topRight,bottomLeft,bottomRight四个值。
      - _这里注意下,如果4个点在一条线上就不用计算方向了_

  + 判断普通的路径是水平方向还是垂直方向连。
  + 得到 A点到有效点A之间的所有路径和方向,B点到有效点B之间的所有路径和方向,有效点A到有效点B之间的所有路径和方向
  + 根据得到的路径和方向,来画线。

我们用图片来看看怎样才算两张图连通

关于连连看中两张图片能否连通.png

这里标明了A点,有效点A,B点,有效点B,路径中有图片的地方表示路线不通。

我们来看看关键代码

  1. 获取十字线。
     getPaths:function(element){  //获取点击图片的行数和列数
     //定义一个数组来存放十字线
     var paths = [];
     //遍历一共的行数
     for(var i=0;i<this.imgRow;i++){
         //列数不变,行数从0到最大
         paths.push({x:i,y:element.y});
     }
     //遍历一共的列数
     for(var j=0;j<this.imgCol;j++){
         //行数不变,列数从0到最大
         paths.push({x:element.x,y:j});
     }
    
     return paths;
    
}
     ```
  1. 判断两个点的连线上是否有图片
  ```
    checkTwoPath:function(target,current){
    //如果是同一列
    if(current.y == target.y){
        //遍历一行上不为点击的图片的行的所有十字线上的点
        for(var i=target.x;i<current.x?i<current.x:i>current.x;i<current.x?i++:i--){
            //如果含有图片 就返回false
            if(this.dimenArr[i][current.y]){
                return false;
            }
        }

    }else{
        //如果是同一行
        if(current.x == target.x){
            //遍历一列上不为点击的图片的列的所有十字线上的点
            for(var j=target.y;j<current.y?j<current.y:j>current.y;j<current.y?j++:j--){
                //如果含有图片 就返回false
                if(this.dimenArr[current.x][j]){
                    return false;
                }
            }
        }
    }
    return true;
}
  ```
  1. 获取B点和有效点A同行同列的两个点。
      getSamePostions:function(target,current){
      //定义一个数组存放同行同列的两个点的位置
      var paths = [{x:0,y:0},{x:0,y:0}]
      //遍历目标位置的十字线
      for(var i=0;i<target.length;i++){
          //如果在同一行
          if(current.x == target[i].x){
              paths[0].x = target[i].x;
              paths[0].y = target[i].y;
          }
    
          //如果在同一列
          if(current.y == target[i].y){
              paths[1].x = target[i].x;
              paths[1].y = target[i].y;
          }
      }
      return paths;
    
}
  ```
  1. 获取最短路径。
      getShortPath:function(nearPath){
      var flag = true;
    
      // 定义一个数组用来存放路径的长度
      var pathLength = [];
    
      // 定义一个最短路径 
      var shortPath = null;
    
      // 如果只有一条路径
      if(nearPath.length==1){
          // console.log(nearPath);
          shortPath = nearPath[0];
          // this.direction(nearPath[0]);
      }else{
          // 遍历这个对象
          for (var i = 0; i < nearPath.length; i++) {
              // 如果两个交点重合的话,此时就是最短路径
              if(nearPath[i].crossA.x == nearPath[i].crossB.x && nearPath[i].crossA.y==nearPath[i].crossB.y){
                  flag = false;
                  shortPath = nearPath[i];
                  break;
              }
          }
    
          if(flag){
              for (var i = 0; i < nearPath.length; i++) {
                  pathLength.push({'index':i,"value":this.getPathLength(nearPath[i].crossA,nearPath[i].A)+this.getPathLength(nearPath[i].crossB,nearPath[i].B)+this.getPathLength(nearPath[i].crossA,nearPath[i].crossB)});                   
              }
              
              // 升序排序得到最小值,拿到的值就是最短路径的索引
              pathLength.sort(function(obj1,obj2){
                  return obj1.value>obj2.value ? 1 : -1;
              })
              // 获得到最短路径
              console.log("这是算出来的最短路径");
              shortPath = nearPath[pathLength[0].index];
          }
      
      }
    
      return shortPath;
    
}
  ```
  1. 获取路径的长度值,以便比较出最短路径。
      getPathLength:function(currentCoords,targetCoords){
    
      // 如果x值坐标相等就获取y值的差值的绝对值,如果y值相等就获取x值差值的绝对值
      if(currentCoords.x==targetCoords.x){
          return Math.abs(currentCoords.y-targetCoords.y-1);
      }else if(currentCoords.y == targetCoords.y){
          return Math.abs(currentCoords.x-targetCoords.x-1);
      }
    
}
  ```

关于代码中运行时控制台的值所代表的含义

关于控制台中打印的值到底是什么.gif
  1. 第一个console.log()打印出的数组代表中共有多少种连通方式,当前只有一种,存入的对象是 A点,有效点A,B点和有效点B
  2. 第二个console.log()打印出的对象中存入的是最短路径的四个点的坐标对象
  3. 第三个console.log()打印出的是存入的四个点的坐标对象和有效点A和有效点B的绘制线的方向
  4. 后面打印的就是路径坐标了。

有兴趣的朋友可以自行下载看看代码,可能命名上由于词穷想不到比较好的名字,但是注释写的还比较全。
代码保存在了<a href="https://github.com/MagicianShiro/gamePractice" target = "_blank" >github</a>上,点击github跳转后下载即可。

总结

  • 首先代码还有缺陷,没有判断所有的点都不能连通的情况。·

    • 不过写起来的应该不难,我能想到的办法就是在每次开始之前,复制一份大数组,然后从中取出一个值,再获取到这个数组中和取出的值想同的这个值,然后让这两个值试着连通,当不能连通的时候,从这个数组中去除掉这两个元素。然后接着取值比较。最后赋值出的数组为空即代表所有的点不能连通。
  • 其实连线部分我总觉得做的复杂了,本来做到一半的时候想用canvas来画线,毕竟点的行列数都知道,计算坐标也比较容易。不过既然做了,就硬着头皮做下去了。

  • 最后希望不要嫌弃我太啰嗦。。个人水平比较差。。各位看官将就着看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • 《ilua》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 1...
    叶染柒丶阅读 10,490评论 0 11
  • 《ijs》速成开发手册3.0 官方用户交流:iApp开发交流(1) 239547050iApp开发交流(2) 10...
    叶染柒丶阅读 5,064评论 0 7
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 最初分手的时候还是很难过的,但是总觉得有下一个人在等着我去遇见。所以不急不忙的走着、等待着。 初中毕业中考成绩并...
    狐狸姑娘阅读 234评论 0 0