最近在看 JavaScript, 想着上网找一个连连看游戏写一写, 看别人的代码很乱, 于是结合了思路好的, 自己模仿着写, 记录一下
页面如下:
实现的其实是 6*6 的连连看, 为什么会多一个框框一会会解释, 但是确实是做的没有那么好看的完善, 可能还有很多 bug , 欢迎大家找 bug .
html 文件, 也就是页面, 很简单, 写成 8*8的表格就可以了
代码参考:
<html>
<head>
<title>连连看title>
<meta charset="UTF-8">
<style type="text/css">
#container{
width:620px;
height:620px;
position:relative;
}
.row{
display:flex;
}
.row div{
width:100px;
height:100px;
border:solid 1px gray;
flex:1;
text-align: center;
line-height: 100px;
}
#handles{
width: 300px;
height: 800px;
position: absolute;
left:700px;
top: 0px;
}
.handleBtn{
width:150px;
height: 30px;
margin-left: 25% ;
margin-top: 20px;
text-align: center;
}
style>
head>
<body>
<div id="container">
<div id="row1" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row2" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row3" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row4" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row5" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row6" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row7" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
<div id="row8" class="row">
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
<div class="col">div>
div>
div>
<div id="handles">
<button id="btn" class="handleBtn">重新开始button>
<div id="showInfo">div>
div>
<script type="text/javascript" src="game_test.js">script>
<script type="text/javascript">
script>
body>
html>
JS 文件: (分为几个部分来写, 但是都是同一个 JS 文件)
// 获取表格元素
var container=document.getElementById('container');
// 获取行元素
var rows=document.getElementsByClassName('row');
// 获取列元素
var cols=document.getElementsByClassName('col');
// 获取按钮
var btn=document.getElementById('btn');
// 创建空数组
var targetArr=[];
// container 的子元素的长度, 也就是一共有几个同等级的子元素
var len=container.children.length;
// container 的第一个子元素包含几个同等级子元素
var childLen=container.firstElementChild.children.length;
// 此处定义了连连看的元素
var fruit=[['葡萄','橘子','香蕉','苹果','桃子','石榴','柚子','甘蔗'],
['芒果','榴莲','草莓','菠萝','西瓜','柠檬','荔枝','樱桃'],
['葡萄','橘子','香蕉','苹果','桃子','石榴','柚子','甘蔗'],
['芒果','榴莲','草莓','菠萝','西瓜','柠檬','荔枝','樱桃']];
定义点击重新开始按钮时的事件
// 对按钮元素添加事件句柄, 第一个参数代表事件名, 第二个参数代表事件触发时执行的函数
btn.addEventListener('click',reStart);
// 重新开始的函数
var reStart= function (){
// 生成数据函数
setData(fruit);
// 生成数据后, 给表格添加数据
for(var i=0;i<len;i++){
for(var j=0;j<childLen;j++){
container.children[i].children[j].innerText=container.children[i].children[j].getAttribute('info');
}
}
}
生成数据数组, 当然也可以不这么写, 但是前面综合找到的就用了这个, 如果后续真的有需要找更简单的, 会尝试更新
//生成数据数组
var setData=function( arr ){
var arrLen=arr.length;
var data=new Array();
var index,value;
var at=[];
//二维数组转一维数组, 当前一共有32个数据,生成36个数据还需要4个,当然也可以一开始就指定36个数据,当时找到的是后面在随机抽取两个数据, 大家喜欢咋地就咋地
arr=[].concat.apply([],arr);
// 随机取出两个数据凑数
for(var i=0;i<(36-arr.length)/2;i++){
at[i]=arr[Math.floor(Math.random()*(arr.length))];
}
// 将36个数据放在arr中
var a=arr.concat(at,at);
// 这里创建的是 8*8 的表格, 而我的需求只有36个数据,并且将边缘都空出来
for(var i=0;i<8;i++){
for(var j=0;j<8;j++){
//如果是边缘,则空出来,不填充数据
if (i==0 || i==7||j==0||j==7){
value = "";
}else {
// 生成一个随机下标
r=Math.floor(Math.random()*(a.length));
// 拿出值
value=a[r];
// 该方法其实是将value值删除,确保了每一个a里面的数据只出现一次
a.splice(r,1)
}
// 添加属性,增加x,y值,以及是否被选择,和数据具体值
// 这个表格敲重点!!!!!!!!!后面要考!!!!!!!
cols[i*8+j].setAttribute('x',i);
cols[i*8+j].setAttribute('y',j);
//console.log("生成 data x "+i,",y "+j);
cols[i*8+j].setAttribute('isSelected',false);
cols[i*8+j].setAttribute('info',value);
}
}
}
关于表格, 重点看坐标分布!!!和传统的不一样, 后续的函数会用到的
点击事件: 这部分还没有修改过, 只注释是啥意思, 复杂是复杂了, 未来看看会不会修改一下
container.onclick=function(e){
// 获取选中的部分
var tag=e.target;
var aTag;
var arr;
var x0,y0,x1,y1;
// 遍历
for(var i=0;i<len;i++){
for(var j=0;j<childLen;j++){
// 获取值
aTag=container.children[i].children[j]
// 如果值相等
if(aTag==tag){
// 将该值放入targetArr中
targetArr.push(aTag);
// 设置选中框的背景.
targetArr[0].style.backgroundColor='lightblue';
// 如果 targetArr 数组中有两个数据, 则可以开始比较了
if(targetArr.length==2){
// 该方法会获取到整个表格的内容
arr=getCellCondition();
// 将选中的格子的背景变为空白
targetArr[0].style.backgroundColor=null;
targetArr[1].style.backgroundColor=null;
// 获取两个选中数据的坐标
x0=targetArr[0].getAttribute('x');
y0=targetArr[0].getAttribute('y');
x1=targetArr[1].getAttribute('x');
y1=targetArr[1].getAttribute('y');
// 确保选中的数据是值相等的并且不是选中了同一个元素
if(targetArr[0].innerText===targetArr[1].innerText && targetArr[0]!==targetArr[1]){
// getRoad 寻找可以连通的路径
var arrTest=getRoad(x0,y0,x1,y1,arr);
// 判断是否有路径可以连通, 可以则将选中的格子清空
if(arrTest){
targetArr[0].innerText='';
targetArr[1].innerText='';
}
}else{
console.log('不相同')
}
// 清空数组
targetArr=[];
arr=null;
}
return ;
}
}
}
}
获取到整个表格的内容 getCellCondition();
var getCellCondition = function (){
//用来保存所有单元格对象
var arrs=new Array();
for(var i=0;i<len;i++){
arrs[i]=new Array();
for(var j=0;j<childLen;j++){
arrs[i][j]=rows[i].children[j].innerText;
}
}
return arrs;
}
接下来重点讲路径:
分为: 水平连接, 垂直连接, 一个拐点, 两个拐点, 如图
于是乎寻找路径的函数如下:
function getRoad(x0,y0,x1,y1,arr) {
if ( Horizontal(x0,y0,x1,y1,arr) ){
// 水平
return true;
}else if (Vertical(x0,y0,x1,y1,arr)){
// 垂直
return true;
}else if ( OnePoint(x0,y0,x1,y1,arr) ){
// 一个拐点
return true;
}else if (TwoPointPath(x0,y0,x1,y1,arr)){
// 两个拐点
return true;
}else return false;
}
水平连接;
// 对于上述生成的坐标来看, 水平遍历 x 不变
function Horizontal(x0,y0,x1,y1,arr){
// 判断 x 是否不变
if (x0!=x1) return false;
// 定义一个标记
var flag = true;
// 获取两个 y 坐标, -1, +1 的目的都是忽略本身
// 这个设定里面, 如果元素相邻, 则 yMax < yMin
var yMax = parseInt((y0 > y1 ? y0 : y1)) -1 ;
var yMin = parseInt((y0 < y1 ? y0 : y1)) +1 ;
// 判断从一个元素到另个元素进行水平遍历时, 中间的元素是否为空, 不是则路径不可用
for(i = yMin; i <= yMax; i++){
if (arr[x0][i] != ''){
flag = false;
break;
}
}
return flag;
}
垂直连接, 同理上面
function Vertical(x0,y0,x1,y1,arr){
if (y0!=y1) return false;
var flag = true;
var xMax = parseInt((x0 > x1 ? x0 : x1)) -1;
var xMin = parseInt((x0 < x1 ? x0 : x1)) +1;
for(i = xMin; i <= xMax; i++){
if (arr[i][y0] != ''){
flag = false;
break;
}
}
return flag;
}
一个拐点
可通过图来理解代码, A,B分别是选中的元素, C, D分别是拐点.
如果拐点C可行, 则C应该垂直于A且水平于B.
如果拐点D可行, 则D应该垂直于B且水平于A.
function OnePoint(x0,y0,x1,y1,arr){
var flag = false;
var x3 = x0, y3 = y1;
var x4 = x1, y4 = y0;
// 如果拐点不为空, 则路径是不合理的,返回false
if (arr[x3][y3]!=''&&arr[x4][y4]!=''){
return false};
flag = ((Horizontal(x0,y0,x3,y3,arr) && Vertical(x1,y1,x3,y3,arr) )|| (Vertical(x0,y0,x4,y4,arr) && Horizontal(x1,y1,x4,y4,arr)));
return flag;
}
两个拐点: 也就是说,两个拐点, 必定是其中一个元素的"一个拐点", 并且会垂直或水平于另一个元素
function TwoPointPath(x0,y0,x1,y1,arr){
var flag = false;
// 网上参考的方式, 全部遍历一次来找拐点
for (var i = 0; i < childLen; i++){
for (var j = 0; j < len; j++){
// 四个顶脚我给排除了,如果找到这四个顶脚也符合的可以滴滴我,因为我真的没有找到
if ((i==0&&j==0)||(i==0&&j==7)||(i==7&&j==0)||(i==7&&j==7)){
continue;
}else {
var x3 = i, y3 = j;
// 现在找的就是拐点,必须为空路径才是成立的
if (arr[x3][y3]!=''){
continue;}
var flag1 = (OnePoint(x0,y0,x3,y3,arr) && (Vertical(x1,y1,x3,y3,arr) || Horizontal(x1,y1,x3,y3,arr)));
var flag2 = (OnePoint(x1,y1,x3,y3,arr) && (Vertical(x0,y0,x3,y3,arr) || Horizontal(x0,y0,x3,y3,arr)));
flag = flag1 || flag2;
return flag;
}
结束!