五子棋网页版
基于js的五子棋教程
先给出问题,然后一步一步的去解决;
- 需要的知识:html,css,js基础语法,包括创建对象和继承属性;
- 需要的知识很少,就是js的创建对象,如果不会就去看一下书吧。
- 整个js都是基于一个叫xuanran 的对象来操作的,所以请大家一边看教程,一遍对照源码,源码很短一共不到200行
面临的问题
- 第一个问题,就是这个棋盘怎么显示;
- 棋盘显示后,接下来的问题就是,怎么点一下,在一个特定的点显示出一个圆点。
- 上面两个问题解决了,五子棋的面貌就存在了,接下来是,怎么把五子棋的位置用变量描述出来,用于量化和计算。
- 这一步的问题是,怎么利用棋子的位置变量,计算某一时刻棋子的输赢。判断输赢
- 以上:这就是制作五子棋按顺序要面临的四个问题,接下来我会按顺序一步一步的解决这四个问题。所有源码和素材可以找我私发;
第一个问题
这个问题是怎么显示一个棋盘,是一个渲染问题,渲染这个词不是什么很高级的词,对于网页来说,我想到两种办法,一个是直接一个棋盘图片,另一个是canvas,canvas是个html标签,它在DOM中的对象有很多画图属性,他是一个块级标签,如果用这个就是直接取坐标绘画,我上学期做的MFC版的五子棋就是这个办法,我这次用的是背景图片,比较简单,直接绘图版的我有用MFC做过一个,我也写了实验报告,想参考的同学可以看一下,我把连接给出来:MFC版五子棋;
-
现在进入正题,用一个图片来显示五子棋’
‘就用这个来作为一个棋盘它的css是’’’#qipan { /*棋盘的大小格式*/ width: 500px; height: 500px; background: url(../imgs/board.jpg); background-size: cover; margin-left: 30%; padding-left: 4px; padding-top: 4px; }
这样就画出了一个棋盘;第一步OK
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tIZ3JBXR-1593344020745)(csdn/board.jpg)]
第二个问题
怎么显示棋子呢;和点一下出现一个棋子
-
首先先根据图片棋盘的大小,15*15d大小,它的大小是500px,在css中有设置,所以每一个棋子的大小是500px/(15+1)=31;这里加1是为了让两个棋子间有空隙
-
下面是创造15*15=225个’
'标签;每一个标签都代表一个棋子,通过设置css属性让每一个棋子变为一个圆形,下面先给出显示的js代码‘’’
for (var i = 1; i <= 15 * this.qipannum; i++) { //创建div,这个是1是为了计算行列值方便 var a = document.createElement("div"); a.setAttribute("data", i); a.className = "qizi"; document.getElementById('qipan').appendChild(a); //把div放进棋盘div里
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EifpxUYO-1593344020747)(csdn/qizi.png)]
-
这样就显示了15*15个棋子,从左到右,从上到下,每一个棋子都有一个id数值序号,这样五子棋就做好了,但是一开始肯定是不显示的,点击一下才会显示,所以它的css属性初始为’’’
.qizi { /*棋子的大小格式*/ width: 30.5px; height: 30.5px; margin: 1.2px; display: inline-block; border-radius: 50%; /*初始状态如果不设置背景属性就是空白的,不显示*/ }
-
现在这些棋子一开始都不显示,我们为每一个div都添加一个事件处理函数,点击一下就改变一下这个div的css属性,关键代码是:’’’
var y = _this.location(ev).y, x = _this.location(ev).x; if (_this.data[y][x].qizicontion == 0) { if (_this.role == 0) //白棋 { target.style.background = 'aliceblue'; //让这个棋子的颜色显示出来 _this.role = 1; _this.data[y][x].qizicontion = 1; //表示白色 } else { target.style.background = 'black'; _this.role = 0; _this.data[y][x].qizicontion = 2; //表示黑色 }
-
上面的代码中有一个location函数,这个函数是取一个div的坐标的函数,它的代码是’’’
xuanran.prototype.location = function(ev) { //给出div的dom对象,判断出这个div的x,y坐标。行列都取决于这个 var _this = this; //这个必须要设置,在别的函数调用该函数的时候,_this还是指向的对象 var target = ev.target; var data = target.getAttribute('data'); //获取到第N个div var y = Math.ceil(data / 15); //表示第y行 var x = (data % 15); //表示列 if (x == 0) x = 15; return { y: y - 1, x: x - 1 }; //返回一个json,包括div的x,y坐标 }
现在,棋子问题也解决了OK,会出现下面这个效果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9pzyu9mJ-1593344020749)(csdn/qizi2.png)]
-
-
第三个问题
-
上面的location函数,可以获取到每一个div棋子的x,y行竖直坐标,那为何我们不设置一个二维数组来储存它的属性呢?
‘’’
xuanran.prototype.initshuzu = function() { //初始化数组 var _this = this; for (var i = 0; i < 15; i++) { //每一行y _this.data[i] = new Array(); for (var ii = 0; ii < 15; ii++) { //每一列x _this.data[i][ii] = { qizicontion: 0 } } //每个元素代表一个棋子,0是没有下棋,1是白棋,2是黑棋 } }
这个函数,就是初始化数组函数,它会令这个数组,初始化,每一个数组元素保存的都是一个json状态变量。表示棋子的状态
最后一个问题
- 判断输赢,就是遍历每一行
怎么在某个方向上判断输赢,上下,左右,正斜,反斜;
-
先设置两个变量作为棋子在某一行的连在一起的数量。
-
设置两个嵌套的for循环,一个代表列,一个代表行,用于遍历数组
-
对一行的遍历,直接用逻辑表达式判断是否有五个状态变量qizicontion是否五个连在一起都一样,如果一样就令响应的白或者黑变量,设置为5
-
遍历的算法有很多,我这个和之前的MFC版的也不同,怎么样都行,如果你想不到什么好的办法,就用我这个,细节我在源码的注释中写的很清楚了,不做太多解释了,请看源码
‘’’
xuanran.prototype.panduanshuying = function() { //判断输赢 var _this = this; var bai = 1, hei = 1; //初始临时变量 //先竖直判断 for (var i = 0; i < _this.qipannum; i++) { //列 for (var q = 0; q < _this.qipannum - 4; q++) { //行遍历量,放第二级,减4最后留出五个做判断 if (_this.data[q][i].qizicontion == 1 && _this.data[q + 1][i].qizicontion == 1 && _this.data[q + 2][i].qizicontion == 1 && _this.data[q + 3][i].qizicontion == 1 && _this.data[q + 4][i].qizicontion == 1) { //直接判断有没有连续的五个在一起 bai = 5; } if (_this.data[q][i].qizicontion == 2 && _this.data[q + 1][i].qizicontion == 2 && _this.data[q + 2][i].qizicontion == 2 && _this.data[q + 3][i].qizicontion == 2 && _this.data[q + 4][i].qizicontion == 2) { hei = 5; } } } //判断竖直 for (var i = 0; i < _this.qipannum; i++) { //行遍历量 for (var q = 0; q < _this.qipannum - 4; q++) { //列 if (_this.data[i][q].qizicontion == 1 && _this.data[i][q + 1].qizicontion == 1 && _this.data[i][q + 2].qizicontion == 1 && _this.data[i][q + 3].qizicontion == 1 && _this.data[i][q + 4].qizicontion == 1) { //直接判断有没有连续的五个在一起 bai = 5; } if (_this.data[i][q].qizicontion == 2 && _this.data[i][q + 1].qizicontion == 2 && _this.data[i][q + 2].qizicontion == 2 && _this.data[i][q + 3].qizicontion == 2 && _this.data[i][q + 4].qizicontion == 2) { hei = 5; } } } //右上斜 for (var i = 4; i < _this.qipannum; i++) { //起始的行,从上往下,从第4行开始这个斜行才有五个棋子, //行是先最大,后小。列是先最小,再最大 for (var hang = i, lie = 0; hang >= 0 + 4, lie < i - 3; hang--, lie++) { if (_this.data[hang][lie].qizicontion == 1 && _this.data[hang - 1][lie + 1].qizicontion == 1 && _this.data[hang - 2][lie + 2].qizicontion == 1 && _this.data[hang - 3][lie + 3].qizicontion == 1 && _this.data[hang - 4][lie + 4].qizicontion == 1) bai = 5; if (_this.data[hang][lie].qizicontion == 2 && _this.data[hang - 1][lie + 1].qizicontion == 2 && _this.data[hang - 2][lie + 2].qizicontion == 2 && _this.data[hang - 3][lie + 3].qizicontion == 2 && _this.data[hang - 4][lie + 4].qizicontion == 2) hei = 5; }; //上面是上部分,下面是下部分 for (var hang = i - 4, lie = _this.qipannum - 1; hang < _this.qipannum - 4; hang++, lie--) { if (_this.data[hang][lie].qizicontion == 1 && _this.data[hang + 1][lie - 1].qizicontion == 1 && _this.data[hang + 2][lie - 2].qizicontion == 1 && _this.data[hang + 3][lie - 3].qizicontion == 1 && _this.data[hang + 4][lie - 4].qizicontion == 1) bai = 5; if (_this.data[hang][lie].qizicontion == 2 && _this.data[hang + 1][lie - 1].qizicontion == 2 && _this.data[hang + 2][lie - 2].qizicontion == 2 && _this.data[hang + 3][lie - 3].qizicontion == 2 && _this.data[hang + 4][lie - 4].qizicontion == 2) hei = 5; } } //右下斜 for (var i = 0; i < _this.qipannum - 4; i++) //起始的行 { for (var hang = i, lie = 0; hang < _this.qipannum - 4, lie < 14 - i - 3; hang++, lie++) { if (_this.data[hang][lie].qizicontion == 1 && _this.data[hang + 1][lie + 1].qizicontion == 1 && _this.data[hang + 2][lie + 2].qizicontion == 1 && _this.data[hang + 3][lie + 3].qizicontion == 1 && _this.data[hang + 4][lie + 4].qizicontion == 1) bai = 5; if (_this.data[hang][lie].qizicontion == 2 && _this.data[hang + 1][lie + 1].qizicontion == 2 && _this.data[hang + 2][lie + 2].qizicontion == 2 && _this.data[hang + 3][lie + 3].qizicontion == 2 && _this.data[hang + 4][lie + 4].qizicontion == 2) bai = 5; } for (var hang = i + 4, lie = _this.qipannum - 1; hang > 3; hang--, lie--) { if (_this.data[hang][lie].qizicontion == 1 && _this.data[hang - 1][lie - 1].qizicontion == 1 && _this.data[hang - 2][lie - 2].qizicontion == 1 && _this.data[hang - 3][lie - 3].qizicontion == 1 && _this.data[hang - 4][lie - 4].qizicontion == 1) bai = 5; if (_this.data[hang][lie].qizicontion == 2 && _this.data[hang - 1][lie - 1].qizicontion == 2 && _this.data[hang - 2][lie - 2].qizicontion == 2 && _this.data[hang - 3][lie - 3].qizicontion == 2 && _this.data[hang - 4][lie - 4].qizicontion == 2) hei = 5; } } // if (_this.data[0][0].qizicontion != 0 && _this.data[1][0].qizicontion != 0) bai = 5; //后判断 if (bai == 5) { _this.stutus = 1; _this.showend(); } if (hei == 5) { _this.stutus = 2; _this.showend(); } }
到这里,一个五子棋就算做完了
bai = 5;
//后判断
if (bai == 5) {
_this.stutus = 1;
_this.showend();
}
if (hei == 5) {
_this.stutus = 2;
_this.showend();
}
}
### 到这里,一个五子棋就算做完了