百行 HTML5 代码完毕多样双人对弈游戏

2012/06/30 · HTML5 · 1
评论 ·
HTML5

来源:于丙超@developerworks

简介: 本文是一个卓殊富有挑衅性的编制程序,因为 100 行代码,大约 一千0
个字符左右,将促成围棋、五子棋、四子棋和扭转棋八种双人对弈游戏。请小心,那多个对弈游戏不是中低端编制程序者的习作,而是有着棋盘、立体棋子、事件、走棋规则判别、输赢决断的完好对弈游戏,并且能够离线存款和储蓄到
华为平板、Android
平板中,试想一下,把这种游戏下载到平板中,就足以在列车,旅游景区,等尚未复信号的地点进行对弈,是否扩展了机械Computer的机能,是还是不是一种很满意的职业。而且,关键是,那几个程序尚未图片,不需求去行使集团付费下载,仅仅是用
HTML5 技巧写的 100
行代码而已,相对是日前最迷您精悍的双人对弈游戏源码。(编者注:由于网页代码的宽度有限量,所以笔者的源代码经过了部分换行管理,特此表达。)

目标

要做四个完好无损的双人对弈游戏,至少要做如下事情,第一步:绘制棋盘。不相同的棋子游戏棋盘分化,这或多或少急需实行动态管理;第二步:绘制棋子。供给注脚的是,围棋,五子棋等那一个棋子都以圆的呦,请不要为了图片困扰,在
HTML5
时期,大家用代码就足以兑现立体圆形棋子;第三步:推断落子事件。当然是要牢固手指的点击位置,这四种棋中,有的是落在框里面包车型大巴,有的却是落在头晕目眩的棋盘十字线上,须要动态管理;第四步:决断落子规则。下棋都有规则,不要因为代码少,就将规则减价扣,否则程序不成熟,会变成孩子的玩具了;第五步:决断输赢。最终,大家要看清输赢。也等于要数子,那个工作必须由程序来成功,因为下棋总得供给二个公开宣判嘛;第六步:就是干BabaComputer时期,大家得完结离线应用。这几个太重大了,否则,要是在台式Computer上,接根网线玩的13日游,已经各处都是了,您写得再牛,有如何用?正是要活动,在未曾非确定性信号的地点,才有市镇,今后机械,智能手提式有线电话机这么多,在尚未互联网非数字信号的地点,掏出活动设备来下棋,才是一件很牛的职业。

绘图棋盘

近日说了围棋、五子棋、四子棋和扭转棋的棋盘并区别样,围棋是驰骋 十多个格,别的二种棋则是 8
个格。所以绘制棋盘是索要有参数。那是个小标题,大难题是,选取怎么样措施来绘制棋盘?

HTML5 框架下,有最少 3 种方法:第一种,用 Canvas 画线;第二种,用
DIV,CSS3 里面扩张了行列属性;第二种,用 table 标签。

用哪个种类速度最快,代码少啊?答案是:第三种。多少有一点失望啊,HTML5
不是全能的。详细代码如下:

XHTML

this.board=function(name,width,height,rowBak,colBak){ /* 画棋盘 */
nameBak=name; if(“turnover”==name){row=8;col=8;}else
if(“gogame”==name){row=18;col=18;} var
aW=Math.floor(width/(col+2)),aH=Math.floor(height/(row+2));
minL=(aW>aH?aH:aW)-4;// 那几个减法很关键,否则填空时会把表格撑大 var
array=new Array(“<div style=\”margin:”+minL+”px;\”> “+
“<table border=1 cellspacing=0 width=\””+(aW*col)+”\”
height=\””+(aH*row)+”\”>”); for(var i=0;i<row;i++){
array.push(“<tr>”); for(var j=0;j<col;j++){array.push(“<td
align=center>”+
evt(i,j,minL,minL,aW*j+minL/2+8,aH*i+minL/2)+”</td>”);}
if(nameBak!=”four”&&nameBak!=”turnover”)/* 将事件增加到表格中 */
array.push(evt(i,col,minL,minL,aW*col+minL/2+8,aH*i+minL/2));
array.push(“</tr>”); } if(nameBak!=”four”&&nameBak!=”turnover”){
for(var j=0;j<=col;j++){
array.push(evt(row,j,minL,minL,aW*j+minL/2+8,aH*row+minL/2)); } }
document.write(array.join(“”)+”</table></div>”);
setClick(row,col,minL,minL);/* 起始化事件 */ start();/* 初阶化棋子
*/ }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
this.board=function(name,width,height,rowBak,colBak){ /* 画棋盘 */
nameBak=name;
if("turnover"==name){row=8;col=8;}else if("gogame"==name){row=18;col=18;}
var aW=Math.floor(width/(col+2)),aH=Math.floor(height/(row+2));
minL=(aW>aH?aH:aW)-4;// 这个减法很重要,否则填空时会把表格撑大
var array=new Array("<div style=\"margin:"+minL+"px;\"> "+
"<table border=1 cellspacing=0 width=\""+(aW*col)+"\"
height=\""+(aH*row)+"\">");
for(var i=0;i<row;i++){
       array.push("<tr>");
       for(var j=0;j<col;j++){array.push("<td align=center>"+
evt(i,j,minL,minL,aW*j+minL/2+8,aH*i+minL/2)+"</td>");}
       if(nameBak!="four"&&nameBak!="turnover")/* 将事件添加到表格中 */
             array.push(evt(i,col,minL,minL,aW*col+minL/2+8,aH*i+minL/2));
             array.push("</tr>");
}
   if(nameBak!="four"&&nameBak!="turnover"){
           for(var j=0;j<=col;j++){
               array.push(evt(row,j,minL,minL,aW*j+minL/2+8,aH*row+minL/2));
               }
           }
document.write(array.join("")+"</table></div>");
setClick(row,col,minL,minL);/* 初始化事件 */
start();/* 初始化棋子 */
}

地点代码中,最要害的是标宋体的第 6 行代码,那其间有五个妙法,第一个就是table 的概念,第三个便是利用了 Array
数组。为何要动用数组,而不是概念一个字符串呢?答案是优化,正是 Array
数组的 push 方法的速度要远远快于 String 字符串的加 + 运算。共计 16
行代码,八个棋盘就画好了,当然那其间不止是画线,还应该有棋子管理,事件定义等方法的调用,前边将接力提起。

绘图棋子

绘制完棋盘,大家来绘制棋子。我们挑选的那多样棋,固然棋盘区别,不过棋子都以平等的,都以黑白棋子。那在此前,做在线对弈,除了
Flash 能完成赏心悦目效果外,别的的总得先请美术职业做几副小图片,HTML5
时代,美术职业的人工和联系开销就省去了。

我们起码有三种方法绘制棋子,第一种是:canvas 类,第二种就是 css
的圆角属性。用哪一种速度又快代码又少吗?答案是第三种,圆角。代码如下:

CSS

function man(width,height,id,colorBak){ /* 画棋子 */ var
color=colorBak==null?(order++%2==0?”000″:”CCC”):colorBak; var
r=”border-radius:”+width/2+”px;”; var
obj=id==null?event.srcElement:_$(id); obj.innerHTML=”<div
id=\”man_”+color+”_”+order+”\” style=\”display:block;-webkit-”
+r+”-moz-“+r+””+r+”-moz-box-shadow:inset 0 -10px 40px rgba(0,0,0,1);”+
“box-shadow:inset 0 -10px 40px rgba(0,0,0,1);”+
“background:-webkit-gradient(radial, 50 40, 30, center center, 80,
from(#”+color+”), to(rgba(255,255,255,1)));”+
“width:”+width+”px;height:”+height+”px;\”></div>”; }

1
2
3
4
5
6
7
8
9
10
11
function man(width,height,id,colorBak){ /* 画棋子 */
   var color=colorBak==null?(order++%2==0?"000":"CCC"):colorBak;
   var r="border-radius:"+width/2+"px;";
   var obj=id==null?event.srcElement:_$(id);
   obj.innerHTML="<div id=\"man_"+color+"_"+order+"\" style=\"display:block;-webkit-"
   +r+"-moz-"+r+""+r+"-moz-box-shadow:inset 0 -10px 40px rgba(0,0,0,1);"+
   "box-shadow:inset 0 -10px 40px rgba(0,0,0,1);"+
   "background:-webkit-gradient(radial, 50 40, 30, center center, 80, from(#"+color+"),
      to(rgba(255,255,255,1)));"+
   "width:"+width+"px;height:"+height+"px;\"></div>";
}

地点代码中,大家来看,大家将每叁个棋子定义了叁个 DIV,使用了 CSS3 的
shadow,gradient
属性,并且能够依赖棋盘的大大小小活动总结棋子的分寸,其余,假使用户不爱好黑白颜色,乃至足以定义成红黄颜色,女子和幼儿揣测会喜欢。那5
行代码是画贰个棋子的法子,做叁个轻易易行的循环,就能够画出五个棋子,方法如下。

CSS

function moreMan(array){for(var i=0;i<array.length;i++)
man(minL,minL,nameBak+”_”+array[i]);} /* 绘制多个棋子 *把这种游戏下载到平板中。/

1
2
3
function moreMan(array){for(var i=0;i<array.length;i++)
man(minL,minL,nameBak+"_"+array[i]);}
/* 绘制多个棋子 */

处管事人件

绘制完棋盘和棋子,大家来分析一下用户的动作。用户的动作仅仅正是三种,一种是点击棋盘
table,其余一种就是点击棋子 DIV。难题在点击 table
这里,大家要获知用户点击 table 的地点。

价值观思路恐怕是如此,使用 event 方法,得到 x,y 的坐标,然后与 table
的左上角做减法,然后再跟单元格 cell 做除法。听上去都困苦。

假设您精心翻阅了前头的代码,就应当发掘,其实在画棋盘是,我们向 array
数组中 push 了三个 evt 方法,很显眼,那些 evt
方法要赶回一个字符串变量的,那么他的剧情是哪些呢?答案公告:

CSS

function evt(i,j,width,height,left,top){ /*把这种游戏下载到平板中。 单一单元格事件 */ return
“<div id=\””+nameBak+”_”+i+”_”+j+”\” style=\”position:”+
(nameBak==”four”||nameBak==”turnover”?”block”:”absolute”)+ “;border:0px
solid #000;width:”+
width+”px;height:”+height+”px;top:”+top+”px;left:”+left+”px;\”></div>”;
}

1
2
3
4
5
6
function evt(i,j,width,height,left,top){ /* 单一单元格事件 */
  return "<div id=\""+nameBak+"_"+i+"_"+j+"\" style=\"position:"+
(nameBak=="four"||nameBak=="turnover"?"block":"absolute")+
";border:0px solid #000;width:"+
width+"px;height:"+height+"px;top:"+top+"px;left:"+left+"px;\"></div>";
}

原理是三个DIV。对了,那几个增添事件的秘籍十二分特别,实际上是在每个棋盘的穿插的地点画了七个DIV,然后给 DIV 加多事件。

CSS

function setClick(row,col,width,height){ for(var i=0;i<=row;i++){
for(var j=0;j<=col;j++){ var els=_$(nameBak+”_”+i+”_”+j);
if(els!=null)els.onclick=function(){if(rule())man(width,height);}; } } }

1
2
3
4
5
6
7
8
function setClick(row,col,width,height){
    for(var i=0;i<=row;i++){
            for(var j=0;j<=col;j++){
                var els=_$(nameBak+"_"+i+"_"+j);
                if(els!=null)els.onclick=function(){if(rule())man(width,height);};
}
    }
}

急需验证的是,DIV 一定要先定义,即 document.write 输出出来,然后技能实行onclick 的概念,否则会再次回到 DIV 未定义的不当。寥寥 10
行代码,把事件难题消除了。

落子规则

日前说了,用户点击事件有二种,点击棋盘 table 事件大家接纳额外增添 DIV
的情势玄妙化解了,第三种点击棋子的情势又该如何呢?

先要表明的是,点击棋子其实是一种错误的风浪,点击棋盘能够落子,点击棋子是如何意思?黑白棋点击棋子是空洞的,大家务供给举办剖断,不能够在有子的地点落子,那是规则之一。所以要求求定义七个情势,决断是还是不是点击的地方是还是不是有棋子。代码如下:

CSS

function isMan(row,col){var obj=_把这种游戏下载到平板中。$(nameBak+”_”+row+”_”+col,1);
if(obj==null||obj.indexOf(“man_”)==-1)return null; else
if(obj.indexOf(“000”)!=-1) return 0; else
if(obj.indexOf(“CCC”)!=-1)return 1;}

1
2
3
4
5
function isMan(row,col){var obj=_$(nameBak+"_"+row+"_"+col,1);
if(obj==null||obj.indexOf("man_")==-1)return null;
else if(obj.indexOf("000")!=-1)
  return 0;
else if(obj.indexOf("CCC")!=-1)return 1;}

不料吧,其实只要一行代码就足以就足以做是不是有子的论断,怎么决断的,秘籍就在于决断DIV 的颜料,棋子要么黑,重返 0,要么白,重回1,可是空白地点是一贯不颜色的,重临null。这里要非常注意再次回到值,后边判定输赢的时候还要用,所以不可能轻易通过
true 也许 false 的的再次来到值来剖断是不是有子,而是要一口咬住不放出有啥颜色的子。

对于五子棋和围棋,这一条规则够用了,不过对于翻转棋和四子棋,还或然有第二条规则:不能够在方圆空白的地点落子,正是说必须是持续的。也正是说,不止要咬定点击的地点是或不是有棋子,还要推断其相近是否有棋子,这几个,不是能够有,而是,必须有。供给做一个小循环啊,代码如下:

CSS

function rule(){/*把这种游戏下载到平板中。 走棋规则 */ var id=event.srcElement.id;
if(id.indexOf(“man_”)==0){alert(“不能够在有子的地点落子”);return
false;}else{ var p=id.indexOf(“_”),p1=id.lastIndexOf(“_”); var
row=id.substr(p+1,p1-p-1)*1,col=id.substr(p1+1)*1;
if(“gobang”==nameBak)return gobang(row,col); else if(“four”==nameBak){
if(isMan(row,col+1)==null&&isMan(row,col-1)==null&&
isMan(row+1,col)==null&& isMan(row-1,col)==null){
alert(“四子棋不可能在周围空白的地点落子!”); return false; } return
gobang(row,col,3); }else if(“turnover”==nameBak){
if(isMan(row,col+1)==null&&isMan(row,col-1)==null&&
isMan(row+1,col)==null&&isMan(row-1,col)==null&&
isMan(row-1,col-1)==null&& isMan(row+1,col+1)==null){
alert(“翻转棋不可能在左近空白的位置落子!”); return false; } turnover();
}else if(“gogame”==nameBak){ } } return true; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function rule(){/* 走棋规则 */
var id=event.srcElement.id;
if(id.indexOf("man_")==0){alert("不能在有子的地方落子");return false;}else{
     var p=id.indexOf("_"),p1=id.lastIndexOf("_");
     var row=id.substr(p+1,p1-p-1)*1,col=id.substr(p1+1)*1;
     if("gobang"==nameBak)return gobang(row,col);
        else if("four"==nameBak){
     if(isMan(row,col+1)==null&&isMan(row,col-1)==null&&
     isMan(row+1,col)==null&&
     isMan(row-1,col)==null){
     alert("四子棋不能在四周空白的地方落子!");
     return false;
}
return gobang(row,col,3);
}else if("turnover"==nameBak){
if(isMan(row,col+1)==null&&isMan(row,col-1)==null&&
isMan(row+1,col)==null&&isMan(row-1,col)==null&&
isMan(row-1,col-1)==null&&
isMan(row+1,col+1)==null){
alert("翻转棋不能在四周空白的地方落子!");
return false;
}
  turnover();
}else if("gogame"==nameBak){
     }
     }
  return true;
}

循环中,每每调用 isMan 方法剖断是不是有棋子,所以只要 isMan
写得远远不够精炼,神速,不知晓要消耗多少日子啊。数一数,总共 19
行代码就管理了落子规则。

到此处,我们绘制了棋盘,棋子,得到了点击时间,决断了落子规则,才用了 40
行左右的代码,其实程序基本上可用了,可是大家不能够满意啊,还得让她进而智能一些,大家还亟需贰个评推断输赢。

认清输赢

要看清输赢,咱们必必要精通下棋的平整:

五子棋是逐条方向的五子相连算赢,四子棋是各种方向三个子相连算赢,翻转棋数棋子的个数,围棋则要麻烦些,不止数棋子个数,还要数围住的区域。

逻辑上类似很复杂啊,仿佛也是持筹握算最多的地点,有一点人工智能的情致。没有错,若是前面的根基打得倒霉,这里实在要开支无尽代码,不过因为我们前面定义了
DIV 用颜色推断是还是不是留存棋子的 iaMan
方法,这里再利用八个小才干,就足以轻便化解那些输赢判定。先看看五子棋和四子棋的胜败剖断代码,然后相比较代码来深入分析。

CSS

function gobang(row,col,num){ num=num==null?4:num; var
rs=[[],[],[],[]],b=[],w=[];/*
这里运用四维数组来存款和储蓄棋子地方 */ for(var
i=0,j=0;i<num*2+1;i++,j++){ rs[0].push(isMan(row-num+i,col));
rs[1].push(isMan(row,col-num+j));
rs[2].push(isMan(row-num+i,col-num+j));
rs[3].push(isMan(row-num+i,col-num+j));
if(i<num){b.push(0);w.push(1);} }
if(rs.join(“#”).indexOf(b.join(“,”))!=-1){alert(“黑棋胜”);return false;
}else if(rs.join(“#”).indexOf(w.join(“,”))!=-1){alert(“白棋胜”);return
false;} return true; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function gobang(row,col,num){
num=num==null?4:num;
var rs=[[],[],[],[]],b=[],w=[];/* 这里采用四维数组来存储棋子位置 */
for(var i=0,j=0;i<num*2+1;i++,j++){
rs[0].push(isMan(row-num+i,col));
rs[1].push(isMan(row,col-num+j));
rs[2].push(isMan(row-num+i,col-num+j));
rs[3].push(isMan(row-num+i,col-num+j));
if(i<num){b.push(0);w.push(1);}
}
if(rs.join("#").indexOf(b.join(","))!=-1){alert("黑棋胜");return false;
}else if(rs.join("#").indexOf(w.join(","))!=-1){alert("白棋胜");return false;}
     return true;
}

累计 9 行代码就消除,看懂没?首先定义了多个 Javascript 多维数组
rs=[[],[],[],[]],这种概念多维数组的不二等秘书诀,挑出来器重说明一(Karicare)下,因为寻找引擎上都是搜不到的,小编教学时大都境遇的学习者也都不精通,他们好些个接纳new Array,然后加循环的蜗牛方法。

其次步:从落子的地点开首循环,注意,不是循环整个棋盘,为的就是节省时间啊。循环设计纵横交错四个样子,有棋子的位置,就向那个四维数组
push 棋子的颜料。

其三步:把数组 join 起来就 ok 啦,要是有 4 个或 5 个 1
相连,自然就是白棋胜,不然就是黑棋胜。

划线这里,就有一点意思啊,注意我们管理的数量的法子,小编称之为“块数据”的管理措施,就是丰盛利用
array
数组,保存一块一块的数额,无论写入,读取,依旧计算深入分析,都以针对这一块数据实行,那样不仅可以够压实内聚度,便于提炼出能够选拔的法门,就能够大大的加速进行进度。

拍卖相连都不言自明,数子就更简便易行了,使用块数据管理格局,3 行消除。

CSS

function turnover(){ if(order<64)return; var num=0;var
total=row*col;for(var i=0;i<row;i++){ for(var
j=0;j<col;j++){num+=isMan(i+”_”+j);} }
if(num<total/2)alert(“黑棋胜”+(total-num*2)+”子”); else
if(num>row*col/2)alert(“白棋胜”+(num*2-total)+”子”); else
alert(“平局”); }

1
2
3
4
5
6
7
8
9
function turnover(){
    if(order<64)return;
    var num=0;var total=row*col;for(var i=0;i<row;i++){
        for(var j=0;j<col;j++){num+=isMan(i+"_"+j);}
    }
if(num<total/2)alert("黑棋胜"+(total-num*2)+"子");
else if(num>row*col/2)alert("白棋胜"+(num*2-total)+"子");
else alert("平局");
}

棋子开端化

严密地写到这里,还应该有最后二个关于棋子的难题亟待管理。那正是,下五子棋是从一名不文棋盘起初,其余三种棋却一齐始都是有子的。其实给八个赤手棋盘也行,不过任何三种棋因为相似的前几步走法都是固定的,我们为了加强智能化水平,不得不在萧疏四行代码,终究,大家的靶子是叁个市场化的成品,而不是叁个初我们不思虑用户体验的先后。

CSS

function start(){
if(“turnover”==nameBak){moreMan([3+”_”+3,4+”_”+3,4+”_”+4,3+”_”+4]);
}else if(“four”==nameBak){man(minL,minL,nameBak+”_”+row/2+”_”+0);
}else
if(“gogame”==nameBak){moreMan([3+”_”+3,15+”_”+3,15+”_”+15,3+”_”+15]);
} }

1
2
3
4
5
6
function start(){
   if("turnover"==nameBak){moreMan([3+"_"+3,4+"_"+3,4+"_"+4,3+"_"+4]);
   }else if("four"==nameBak){man(minL,minL,nameBak+"_"+row/2+"_"+0);
   }else if("gogame"==nameBak){moreMan([3+"_"+3,15+"_"+3,15+"_"+15,3+"_"+15]);
   }
}

其实就是调用了刹那间 moreMan
方法,注意也是块数据援引,传输了二个数组,用下划线分割横向和纵向坐标。

做成离线应用

本文初始就说过,台式计算机的双人或四人博弈程序已经千千万万烂大街了,唯有移动使用技能有商场,大家的指标便是奔着那么些来的,所以最终必须做成离线应用。

什么样落实 HTML5
的离线应用,搜索引擎极快能找到结果,其实只要多少个关键步骤。

首先步;在 Web 服务器的配备文件中声雅培(Abbott)下。Tomcat 和 Apache
的注解格局不一样等,必要小心;

第二步:定义 manifest 文件,文件格式必要留意;

其三步:在 HTML 的公文中调用一下 manifest 文件。

听新闻说那三个步骤,读者能够自动物检疫索细节,这里就不赘述了,小编只讲寻找引擎搜不到的。

除此以外部供给要注解的是,平板电脑 和 Android
平板上浏览器完毕全屏的点子也不平等,针对 苹果平板用户,大家还必须定义一行能够落实全屏的代码。

  1. 意义图、在线演示、开放源代码

本文的在线演示网站是:,效果图如下图所示:

图 1. 效果图

图片 1

图中加了二个精选棋类型和装置背景成效,如要获得任何源代码,只要接纳浏览器的查看源代码功效就可以,限于篇幅,这里就不贴了。

总结

作为贰个程序猿,最高的境界不是写得代码越来越多越好,而是用最少的代码达成最多的计量,消除最多的题目。回看当年,盖茨在编排
Basic
时,为了省去多少个字符供给左思右想发愤忘食,以致于遗留了千年虫世纪难点,反观今天,在云总结时期,随着硬盘和内部存款和储蓄器的体积更加大,CPU
的运算越来越快,繁多大型项目标技术员如同失去了简要代码的习贯。不过运动计量的硬件,前段时间还尚未那么高的安顿,本文通过
HTML5
对弈游戏,使用“块数据”计算方法,完毕了用至少代码完成最多划算的指标,极其适用移动计量,与大家共勉。

 

赞 收藏 1
评论

图片 2

相关文章