闲情奕趣(基于html5的围棋应用)

1、闲情奕趣html

  少时,闻奕而不知奕之趣,观棋而不识棋之髓。近日,略习奕之规矩,演练一二,始觉其妙。今见各手谈之软件,心生一念,自编一演习软件,以调闲暇之情,培对弈之趣,故取一名,曰:“闲情奕趣”。算法

——雪飘七月 chrome

  近日忙里偷闲得以编写此对弈软件,以HTML5为基础,canvas画布绘制展现棋盘棋子,localStorage本地存储本局的各个步骤。今日程序初具雏形,写此日志,以供你们交流学习。数据库

下面上图一张:canvas

2、棋布星罗小程序

下面就来说棋盘棋子的绘制,咱们的绘制都是在canvas中一条线一个圆地绘制成的。数组

棋盘是19*19的线条与9个星位组成,9个星位就是9个以星位为圆心的圆。socket

棋子的绘制也是画圆,只是圆半径较星位大,而棋子是经过一个19*19的数组存储标记位来实现的,数组中361个值与棋盘上的361个位置一一对应。若数值为0,表示没有落子;数值若为1,表示黑方落子;数值若为2,表示白方落子。ide

  
  
           
  
  
  1. //获取canvas画布 
  2. var canvas=document.getElementById('myCanvas'); 
  3. canvas.height = total_height; 
  4. canvas.width = total_width; 
  5. var cxt=canvas.getContext('2d'); 
  6.  
  7. //画棋盘 
  8. var drawBoard = function(){ 
  9.     //每次重画棋盘以前清楚canvas 
  10.     cxt.clearRect(0, 0, canvas.width, canvas.height); 
  11.  
  12.     cxt.beginPath(); 
  13.     //描绘横线 
  14.     for(var i = 0 ; i < 19 ; i++){ 
  15.         var start_company_x = chessboard_start_x; 
  16.         var start_company_y = chessboard_start_y + company_y*i; 
  17.         var end_company_x = chessboard_end_x; 
  18.         var end_company_y = chessboard_start_y + company_y*i; 
  19.         cxt.lineWidth = 2; 
  20.         cxt.moveTo(start_company_x,start_company_y); 
  21.         cxt.lineTo(end_company_x,end_company_y); 
  22.     } 
  23.  
  24.     //描绘竖线 
  25.     for(var j = 0 ; j < 19 ; j++){ 
  26.         var start_company_x = chessboard_start_x + company_x*j; 
  27.         var start_company_y = chessboard_start_y; 
  28.         var end_company_x = chessboard_start_x + company_x*j; 
  29.         var end_company_y = chessboard_end_y; 
  30.         cxt.moveTo(start_company_x,start_company_y); 
  31.         cxt.lineTo(end_company_x,end_company_y); 
  32.     } 
  33.     cxt.stroke(); 
  34.  
  35.     //画九星 
  36.     for(var i = 0 ; i < 3 ; i ++ ){ 
  37.         var star_y = chessboard_start_y + company_y*(i*6+3); 
  38.         for(var j = 0 ; j < 3 ; j++){ 
  39.             var star_x = chessboard_start_x + company_y*(j*6+3); 
  40.             cxt.fillStyle="black"
  41.             cxt.beginPath(); 
  42.             cxt.arc(star_x, star_y, 4, 0, Math.PI*2, false); 
  43.             cxt.stroke(); 
  44.             cxt.fill(); 
  45.         } 
  46.     } 
  47.  
  48. //根据arr数组画棋子 
  49. var drawPiece = function(){ 
  50.     for(var i in arr){ 
  51.         for(var j in arr[i]){ 
  52.             if(arr[i][j] == 1){ 
  53.                 //画黑子 
  54.                 var start_x = i*company_x + chessboard_start_x;//点击的x坐标起始位置 
  55.                 var start_y = j*company_y + chessboard_start_y;//点击的y坐标起始位置 
  56.  
  57.                 cxt.fillStyle= "black"
  58.                 cxt.beginPath(); 
  59.                 cxt.arc(start_x, start_y, piece_radius, 0, Math.PI*2, false); 
  60.                 cxt.stroke(); 
  61.                 cxt.fill(); 
  62.             } else if(arr[i][j] == 2){ 
  63.                 //画白子 
  64.                 var start_x = i*company_x + chessboard_start_x;//点击的x坐标起始位置 
  65.                 var start_y = j*company_y + chessboard_start_y;//点击的y坐标起始位置 
  66.  
  67.                 cxt.fillStyle= "white"
  68.                 cxt.beginPath(); 
  69.                 cxt.arc(start_x, start_y, piece_radius, 0, Math.PI*2, false); 
  70.                 cxt.stroke(); 
  71.                 cxt.fill(); 
  72.             } 
  73.         } 
  74.     } 

3、旁观者清学习

当局者迷,旁观者清。

这一块其实我想说的是对弈的步骤,固然不是真的对弈的步骤,而是对弈程序中对弈提子的算法。

下面这块代码就是用来计算落子处是否能够提子的方法,

首先,方法中依次判断该子上方、左方、右方、下方的棋子是否可以被提,若是能够被提,就提子,而后返回true,这个方法的名称是checkOthersidePiece(x,y,side);

而后,查看本子是否会致使本方棋子被提,若会被提,提子,而后返回true,这个方法依然是checkOthersidePiece(x,y,side);

  
  
           
  
  
  1. //检查该落子是否能够提子,能够就提子 
  2. var checkPiece = function(coordinate_x,coordinate_y){ 
  3.     var myside = 0; 
  4.     var otherside = 0; 
  5.     var iskill = false
  6.     if(side == "black"){ 
  7.         myside = 1; 
  8.         otherside = 2; 
  9.     }else if(side == "white"){ 
  10.         myside = 2; 
  11.         otherside = 1; 
  12.     } 
  13.  
  14.     //若是该子上方是对方棋子或者为第一行 
  15.     if((coordinate_y>0 && arr[coordinate_x][coordinate_y-1] == otherside)){ 
  16.         if(checkOthersidePiece(coordinate_x,coordinate_y-1,otherside)){ 
  17.             iskill = true
  18.         } 
  19.     } 
  20.     //若是该子左方是对方棋子或者为第一行 
  21.     if((coordinate_x>0 && arr[coordinate_x-1][coordinate_y] == otherside)){ 
  22.         if(checkOthersidePiece(coordinate_x-1,coordinate_y,otherside)){ 
  23.             iskill = true
  24.         } 
  25.     } 
  26.     //若是该子右方是对方棋子或者为第十九行 
  27.     if((coordinate_x<18 && arr[coordinate_x+1][coordinate_y] == otherside)){ 
  28.         if(checkOthersidePiece(coordinate_x+1,coordinate_y,otherside)){ 
  29.             iskill = true
  30.         } 
  31.     } 
  32.     //若是该子下方是对方棋子或者为第十九行 
  33.     if((coordinate_y<18 && arr[coordinate_x][coordinate_y+1] == otherside)){ 
  34.         if(checkOthersidePiece(coordinate_x,coordinate_y+1,otherside)){ 
  35.             iskill = true
  36.         } 
  37.     } 
  38.  
  39.     //若是有提掉对方棋子 
  40.     if(iskill == true){ 
  41.  
  42.     //监测本子落子后己方棋子是否会被提 
  43.     }else { 
  44.         //alert(JSON.stringify(arr)); 
  45.         checkOthersidePiece(coordinate_x,coordinate_y,myside); 
  46.     } 

接下来咱们就来看看这个神通广大的checkOthersidePiece(x,y,side);方法

该方法中新建一个19*19的数组,而后从该棋子位置循环遍历上、左、右、下的棋子,

若是周边棋子有空的,那将该空的位置标志位改成3;

若是周边棋子为己方的继续遍历该已方棋子的周边棋子,循环往复,直到遍历完与本子相连的已方棋子

  
  
           
  
  
  1. /** 
  2.  * 检查该子是否会被提,若能被提,提子 
  3.  * @param coordinate_x (该子x坐标) 
  4.  * @param coordinate_y (该子y坐标) 
  5.  * @param side 1(黑子) or 2(白子) 
  6.  */ 
  7. var checkOthersidePiece = function(coordinate_x,coordinate_y,side){ 
  8.     //新建一个二维数组,用于排放与该子链接的本方棋子 
  9.     var connection_arr = new Array(19); 
  10.     for(var i = 0 ; i < 19 ; i++){ 
  11.         var connection_arrj = new Array(19); 
  12.         for(var j = 0 ; j < 19 ; j++){ 
  13.             connection_arrj[j] = 0; 
  14.         } 
  15.         connection_arr[i] = connection_arrj; 
  16.     } 
  17.     var isdead = true;//是否被提,默认为被提 
  18.     var deadcount = 0; 
  19.  
  20.     //alert("1111"+JSON.stringify(connection_arr)+coordinate_x+":"+coordinate_y); 
  21.     //将全部与本子相连的同色棋子组成本数组 
  22.     connection_arr = setconnection_arr(connection_arr,coordinate_x,coordinate_y,side); 
  23.     //alert("2222"+JSON.stringify(connection_arr)); 
  24.  
  25.     //遍历该connection_arr数组,如有3则,不死 
  26.     for(var i in connection_arr){ 
  27.         for(var j in connection_arr[i]){ 
  28.             if(connection_arr[i][j] == 3){ 
  29.                 //console.log("i+j:"+i+"+"+j); 
  30.                 isdead = false
  31.             } 
  32.         } 
  33.     } 
  34.  
  35.     //若是会被提,则提子 
  36.     if(isdead == true){ 
  37.         for(var i in connection_arr){ 
  38.             for(var j in connection_arr[i]){ 
  39.                 if(connection_arr[i][j] == side){ 
  40.                     arr[i][j] = 0; 
  41.                     deadcount++; 
  42.                 } 
  43.             } 
  44.         } 
  45.     } 
  46.     console.log("isdead:"+isdead+ ":提子数量:"+ deadcount); 
  47.     //如有提子返回true 
  48.     if(deadcount > 0){ 
  49.         return true
  50.     }else { 
  51.         return false
  52.     } 

再而后,咱们来看一看这个递归遍历的方法吧setconnection_arr(arr,x,y,side);

在本方法中作的就是将本落子周围的己方棋子添加到connection_arr中,同时把周围的气以3为标志位添加到connection_arr中。

  
  
           
  
  
  1. /** 
  2.  * 递归组织链接的此方棋子 
  3.  * @param connection_arr 
  4.  * @param coordinate_x 
  5.  * @param coordinate_y 
  6.  * @param side 
  7.  * @return {*} 
  8.  */ 
  9. var setconnection_arr = function(connection_arr,coordinate_x,coordinate_y,side){ 
  10.     //设置数组为本块相连的 
  11.     if(connection_arr[coordinate_x][coordinate_y] != side && arr[coordinate_x][coordinate_y] == side){ 
  12.         connection_arr[coordinate_x][coordinate_y] = side; 
  13.         console.log(coordinate_x + "====" + coordinate_y); 
  14.         //若是该黑子上方是白子而且不为第一行 
  15.         if(coordinate_y>0 && arr[coordinate_x][coordinate_y-1] == side){ 
  16.             connection_arr = setconnection_arr(connection_arr,coordinate_x,coordinate_y-1,side); 
  17.         }else if(coordinate_y>0 && arr[coordinate_x][coordinate_y-1] == 0){ 
  18.             connection_arr[coordinate_x][coordinate_y-1] = 3; 
  19.         } 
  20.         //若是该黑子左方是白子或者为第一行 
  21.         if(coordinate_x>0 && arr[coordinate_x-1][coordinate_y] == side){ 
  22.             connection_arr = setconnection_arr(connection_arr,coordinate_x-1,coordinate_y,side); 
  23.         }else if(coordinate_x>0 && arr[coordinate_x-1][coordinate_y] == 0){ 
  24.             connection_arr[coordinate_x-1][coordinate_y] = 3; 
  25.         } 
  26.         //若是该黑子右方是白子或者为第十九行 
  27.         if(coordinate_x<18 && arr[coordinate_x+1][coordinate_y] == side){ 
  28.             connection_arr = setconnection_arr(connection_arr,coordinate_x+1,coordinate_y,side); 
  29.         }else if(coordinate_x<18 && arr[coordinate_x+1][coordinate_y] == 0){ 
  30.             connection_arr[coordinate_x+1][coordinate_y] = 3; 
  31.         } 
  32.         //若是该黑子下方是白子或者为第十九行 
  33.         if(coordinate_y<18 && arr[coordinate_x][coordinate_y+1] == side){ 
  34.             connection_arr = setconnection_arr(connection_arr,coordinate_x,coordinate_y+1,side); 
  35.         }else if(coordinate_y<18 && arr[coordinate_x][coordinate_y+1] == 0){ 
  36.             connection_arr[coordinate_x][coordinate_y+1] = 3; 
  37.         } 
  38.     } 
  39.  
  40.     //console.log("x:"+coordinate_x+"y:"+coordinate_y); 
  41.     return connection_arr; 

 

4、白璧微瑕

如今虽然能够顺畅地落子了,可是对于一些规则仍是没有做限制,好比说:

一、刚被吃掉一子的地方不可立马落子(这须要添加一个机制)

二、不可悔棋,虽然说落子无悔大丈夫,只是不当心点错位置致使整盘棋都废掉,实在有点惋惜(这个能够引入数据库来解决)

等等等等,这些我会在以后的时间里慢慢改进

将这些能想到的改进以后,打算以socketio为基础作一个在线的对弈的小程序。

最后,欢迎各位IT大神以及各位喜欢围棋的大神们不吝赐教……

固然,有问题的也欢迎多多提问……

…………

什么?源码?好吧,点击下面的附件go.rar,下载到本地以chrome或firefox打开canvasgo.html便可跑起来啦!

效果?想看效果?给你个传送门吧!记得用chrome或firefox打开。

相关文章
相关标签/搜索