你的位置:首页 > 网页设计

[网页设计]HTML5 五子棋


背景介绍

  因为之前用c#的winform中的gdi+,java图形包做过五子棋,所以做这个逻辑思路也就驾轻就熟,然而最近想温故html5的canvas绘图功能(公司一般不用这些),所以做了个五子棋,当然没参考之前的客户端代码,只用使用之前计算输赢判断算法和电脑AI(网络借取)的算法,当然现在html5做的五子棋百度一下非常多,但是自己实现一边总归是好事情,好了废话不多说了进入正题。^_^

界面功能介绍与后续可增加功能

 目前界面功能:

  主界面包含

    1:人人、人机对战选项 2:棋子外观选择 3:棋盘背景选择 4:棋盘线条颜色选择

  游戏界面包含

    1:玩家名称 2:玩家棋子 3:当前由谁下棋背景定位 4:玩家比分 5:功能菜单区域(重新开始和无限悔棋) 6:棋盘区域 7.胜利后连环棋子连接 8.最后下棋位置闪烁显示 9.光标定位

  游戏结束界面

    1:胜利背景图 2:胜利玩家姓名 3:继续下一把按钮

 可增加功能

  1.返回主界面 2.保存棋局和相关数据 3.读取棋局和相关数据 4.交换角色 5.网络对战(2台机器)6.双方思考总时间记录

演示地址

http://sandbox.runjs.cn/show/pl3fyuy4   (注意:没有加棋子图片下载提示,如果使用仿真棋子,出现下棋为空,请等待棋子图片下载完毕)

 

界面截图赏析(没花时间美化,比较丑)

 相关设置选择    

  

整体设计和主代码介绍

整体设计

  下棋流程:玩家or电脑AI下棋 ---> 绘制棋子 ---> 设定棋子二维坐标值 ----> logic(逻辑判断) ----> (玩家)一方五子连环 ---> 获胜界面
      ↑                                          |
      |                                          ↓
      <--------------------------------------------------------------------------------------------没有五子

 

  悔棋流程(人人对战):一方玩家悔棋 ----> 弹出下棋记录堆栈并设定为它是最后一枚棋 ---> 清除最后一枚棋子图像 ---> 清除棋子二维坐标值---> 重新定位显示最后下棋位置并闪烁

  悔棋流程(人机对战):玩方悔棋 ----> 弹出下棋记录堆栈2次,设定上一次电脑为最后一枚棋 ---> 清除弹出的2次记录图像 ---> 清除棋子2个棋子二维坐标值---> 重新定位显示最后下棋位置并闪烁

 

主代码介绍

   主代码分为二块: 1.界面逻辑块  2.游戏主体块 (界面与游戏代码分离,逻辑清晰,分工明确)

模拟事件通知:游戏主体逻辑块,每次结果都会通知到界面层来进行交互(类似于c#或者java的委托或事件)

界面逻辑代码

 1 <script type="text/javascript"> 2     var gb = null; 3     var infoboj = document.getElementsByClassName("info")[0]; 4     var pl1obj = document.getElementById("pl1"); 5     var pl2obj = document.getElementById("pl2"); 6     var plname1obj = document.getElementById("plname1"); 7     var plname2obj = document.getElementById("plname2"); 8     var chesstypeobj = document.getElementsByName("chesstype"); 9     var chesscolorobj = document.getElementsByName("chesscolor"); 10     var chessbgObj = document.getElementsByName("chessbg"); 11     var winerpnl = document.getElementById("winer"); 12     document.getElementById("startgame").addEventListener("click", function() { 13        14       function initParams() { 15         var chessTypeValue = 1; 16         if (chesstypeobj.length > 0) { 17           for (var i = 0; i < chesstypeobj.length; i++) { 18             if (chesstypeobj[i].checked) { 19               chessTypeValue = chesstypeobj[i].value; 20               break; 21             } 22           } 23         } 24         var linevalue = ""; 25         if (chesscolorobj.length > 0) { 26           for (var i = 0; i < chesscolorobj.length; i++) { 27             if (chesscolorobj[i].checked) { 28               linevalue = chesscolorobj[i].value; 29               break; 30             } 31           } 32         } 33         var bcorimgvalue = ""; 34         if (chessbgObj.length > 0) { 35           for (var i = 0; i < chessbgObj.length; i++) { 36             if (chessbgObj[i].checked) { 37               bcorimgvalue = chessbgObj[i].value; 38               break; 39             } 40           } 41         } 42         return { 43           lineColor: linevalue, 44           chessType: chessTypeValue, //1 色彩棋子 2 仿真棋子 45           playAName: plname1Input.value, 46           playBName: plname2Input.value, 47           backColorORImg: bcorimgvalue, 48           playAImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playA.png", 49           playBImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playB.png", 50           playerBIsComputer:openComputer.checked 51         }; 52       } 53       document.getElementById("cc").style.display = "block"; 54       gb = new gobang(initParams()); 55       /** 56        * 设置一些界面信息 57        * @param {Object} opt 58       */ 59       gb.info = function(opt) { 60           infoboj.style.visibility = "visible"; 61           document.getElementsByClassName("startpnl")[0].style.visibility = "hidden"; 62           plname1obj.innerHTML = opt.playAName; 63           plname2obj.innerHTML = opt.playBName; 64           if (opt.chessType == 1) { 65             var span1 = document.createElement("span"); 66             pl1obj.insertBefore(span1, plname1obj); 67             var span2 = document.createElement("span"); 68             pl2obj.insertBefore(span2, plname2obj); 69           } else { 70             var img1 = document.createElement("img"); 71             img1.src = opt.playAImg; 72             pl1obj.insertBefore(img1, plname1obj); 73             var img2 = document.createElement("img"); 74             img2.src = opt.playBImg; 75             pl2obj.insertBefore(img2, plname2obj); 76           } 77         } 78         /** 79          * 每次下棋后触发事件  80          * @param {Object} c2d 81         */ 82       gb.operate = function(opt, c2d) { 83         if (!c2d.winer || c2d.winer <= 0) { 84           pl1obj.removeAttribute("class", "curr"); 85           pl2obj.removeAttribute("class", "curr"); 86           if (c2d.player == 1) { 87             pl2obj.setAttribute("class", "curr"); 88           } else { 89             pl1obj.setAttribute("class", "curr"); 90           } 91           document.getElementById("backChessman").innerHTML="悔棋("+c2d.canBackTimes+")"; 92         } else { 93           var winname = c2d.winer == 1 ? opt.playAName : opt.playBName; 94           var str = "恭喜,【" + winname + "】赢了!" 95           alert(str); 96           winerpnl.style.display = "block"; 97           document.getElementById("winerName").innerHTML = "恭喜,【" + winname + "】赢了!"; 98           document.getElementById("pl" + c2d.winer).style.backgroundColor = "pink"; 99           document.getElementById("scoreA").innerHTML = c2d.playScoreA;100           document.getElementById("scoreB").innerHTML = c2d.playScoreB;101         }102       }103       gb.start();104     });105     106     document.getElementById("openComputer").addEventListener("change", function() {107       if (this.checked) {108         plname2Input.value = "电脑";109         plname2Input.disabled = "disabled";110       } else {111         plname2Input.value = "玩家二";112         plname2Input.disabled = "";113       }114     });115     116     //document.getElementById("openComputer").checked="checked";117     118     //重新开始119     function restartgui() {120       if (gb) {121         winerpnl.style.display = "none";122         pl1obj.removeAttribute("class", "curr");123         pl2obj.removeAttribute("class", "curr");124         document.getElementById("pl1").style.backgroundColor = "";125         document.getElementById("pl2").style.backgroundColor = "";126         gb.restart();127       }128     };129   </script>

 

游戏主体代码块(只包含函数声明代码)

 

// ========== // =name:gobang 游戏 // =anthor:jasnature// =last modify date:2016-04-13// ========== (function(win) {  var gb = function(option) {    var self = this,      canObj = document.getElementById("cc"),      can = canObj.getContext("2d");    self.contextObj = canObj;    self.context = can;    if (!self.context) {      alert("浏览器不支持html5");      return;    };    self.Opt = {      lineColor: "green",      chessType: 1, //1 色彩棋子 2 仿真棋子      playAName: "play1",      playBName: "play2",      playAColor: "red",      playBColor: "blue",      playAImg: "img/playA.png",      playBImg: "img/playB.png",      backColorORImg: "default",      playerBIsComputer: false    };    self.operate;    //合并属性    for (var a in option) {      //console.log(opt[a]);      self.Opt[a] = option[a];    };    //私有变量    var my = {};    my.enableCalcWeightNum = false; //显示AI分数    my.gameover = false;    //棋盘相关    my.baseWidth = 30;    my.lastFocusPoint = {}; //鼠标最后移动到的坐标点,计算后的    my.cw = self.contextObj.offsetWidth; //棋盘宽    my.ch = self.contextObj.offsetHeight; //高    my.xlen = Math.ceil(my.cw / my.baseWidth); //行数    my.ylen = Math.ceil(my.ch / my.baseWidth); //列    my.chessRadius = 14; //棋子半径    my.playerBIsComputer = false; //棋手B是否是电脑    my.ComputerThinking = false; //电脑是否在下棋    my.goBackC2dIsComputer = false; //最后下棋是否为电脑    my.switcher = 1; //由谁下棋了 1-a 2-b or computer    my.winer = -1; //赢家,值参考my.switcher    my.playScoreA = 0;    my.playScoreB = 0;    //x,y 正方形数量(20*20)    my.rectNum = my.xlen;    //存储已下的点    my.rectMap = [];    my.NO_CHESS = -1; //没有棋子标识    my.goBackC2d = {}; //最后下的数组转换坐标    my.downChessmanStackC2d = []; // 记录已下棋子的顺序和位置,堆栈    my.focusFlashInterval = null; //焦点闪烁线程    my.focusChangeColors = ["red", "fuchsia", "#ADFF2F", "yellow", "purple", "blue"];    my.eventBinded = false;    my.currChessBackImg = null;    my.currChessAImg = null;    my.currChessBImg = null;    my.currDrawChessImg = null;    my.ChessDownNum = 0; //2个玩家 下棋总数    /**     * 开始游戏     */    self.start = function() {          };    /**     * 重新开始游戏     */    self.restart = function() {          };    /**     * 悔棋一步 ,清棋子,并返回上一次参数     */    self.back = function() {          }    /**     * 初始化一些数据     */    function init() {          }    //    self.paint = function() {    //    //      //window.requestAnimationFrame(drawChessboard);    //    };    /**     * 游戏逻辑     */    function logic(loc, iscomputer) {          };    /**     * 判断是否有玩家胜出     * @param {Object} c2d     */    function isWin(c2d) {            return false;    }    /**     * 连接赢家棋子线     * @param {Object} points     */    function joinWinLine(points) {          }    /**     * 画棋盘     */    function drawChessboard() {          };    /**     * 画棋子     * @param {Object} loc 鼠标点击位置     */    function drawChessman(c2d) {          }    function drawRect(lastRecord, defColor) {          }    /**     * 闪烁最后下棋点     */    function flashFocusChessman() {          }    /**     * 清棋子     * @param {Object} c2d     */    function clearChessman() {          }    /**     * @param {Object} loc     * @return {Object} I 二维数组横点(),J二维数组纵点,IX 横点起始坐标,JY纵点起始坐标,player 最后下棋玩, winer 赢家     */    function calc2dPoint(loc) {      var txp = Math.floor(loc.x / my.baseWidth),        typ = Math.floor(loc.y / my.baseWidth)      dxp = txp * my.baseWidth, dyp = typ * my.baseWidth;      loc.I = txp;      loc.J = typ;      loc.IX = dxp;      loc.JY = dyp;      return loc;    }    my.isChangeDraw = true;    /**     * 位置移动光标     * @param {Object} loc     */    function moveFocus(loc) {          }    /**     * 绑定事件     */    function bindEvent() {      if (!my.eventBinded) {        self.contextObj.addEventListener("touchstart", function(event) {          //console.log(event);          var touchObj = event.touches[0];          eventHandle({            s: "touch",            x: touchObj.clientX - this.offsetLeft,            y: touchObj.clientY - this.offsetTop          })        });        self.contextObj.addEventListener("click", function(event) {          //console.log("click event");          eventHandle({            s: "click",            x: event.offsetX,            y: event.offsetY          })        });        self.contextObj.addEventListener("mousemove", function(event) {          //console.log("mousemove event");          moveFocus({            x: event.offsetX,            y: event.offsetY          });        });        my.eventBinded = true;      }      function eventHandle(ps) {        if (!my.gameover && !my.ComputerThinking) {          logic(ps);          if (my.playerBIsComputer && my.switcher == 2) {            my.ComputerThinking = true;            var pp = AI.analysis(my.goBackC2d.I, my.goBackC2d.J);            logic({              I: pp.x,              J: pp.y            }, true);            my.ComputerThinking = false;          }        }        event.preventDefault();        event.stopPropagation();        return false;      }    }  };  win.gobang = gb;})(window);

 

主要算法介绍

玩家OR电脑胜出算法

/**     * 判断是否有玩家胜出     * @param {Object} c2d     */    function isWin(c2d) {      //四个放心计数 竖 横 左斜 右斜      var hcount = 0,        vcount = 0,        lbhcount = 0,        rbhcount = 0,        temp = 0;      var countArray = [];      //左-1      for (var i = c2d.I; i >= 0; i--) {        temp = my.rectMap[i][c2d.J];        if (temp < 0 || temp !== c2d.player) {          break;        }        hcount++;        countArray.push({          I: i,          J: c2d.J        });      }      //右-1      for (var i = c2d.I + 1; i < my.rectMap.length; i++) {        temp = my.rectMap[i][c2d.J];        if (temp < 0 || temp !== c2d.player) {          break;        }        hcount++;        countArray.push({          I: i,          J: c2d.J        });      }      if (countArray.length < 5) {        countArray = [];        //上-2        for (var j = c2d.J; j >= 0; j--) {          temp = my.rectMap[c2d.I][j];          if (temp < 0 || temp !== c2d.player) {            break;          }          vcount++;          countArray.push({            I: c2d.I,            J: j          });        }        //下-2        for (var j = c2d.J + 1; j < my.rectMap[c2d.I].length; j++) {          temp = my.rectMap[c2d.I][j];          if (temp < 0 || temp !== c2d.player) {            break;          }          vcount++;          countArray.push({            I: c2d.I,            J: j          });        }      }      if (countArray.length < 5) {        countArray = [];        //左上        for (var i = c2d.I, j = c2d.J; i >= 0, j >= 0; i--, j--) {          if (i < 0 || j < 0) break;          temp = my.rectMap[i][j];          if (temp < 0 || temp !== c2d.player) {            break;          }          lbhcount++;          countArray.push({            I: i,            J: j          });        }        //右下        if (c2d.I < my.rectMap.length - 1 && c2d.I < my.rectMap[0].length - 1) {          for (var i = c2d.I + 1, j = c2d.J + 1; i < my.rectMap.length, j < my.rectMap[0].length; i++, j++) {            if (i >= my.rectMap.length || j >= my.rectMap.length) break;            temp = my.rectMap[i][j];            if (temp < 0 || temp !== c2d.player) {              break;            }            lbhcount++;            countArray.push({              I: i,              J: j            });          }        }      }      if (countArray.length < 5) {        countArray = [];        //右上        for (var i = c2d.I, j = c2d.J; i < my.rectMap.length, j >= 0; i++, j--) {          if (i >= my.rectMap.length || j < 0) break;          temp = my.rectMap[i][j];          if (temp < 0 || temp !== c2d.player) {            break;          }          rbhcount++;          countArray.push({            I: i,            J: j          });        }        //左下        if (c2d.I >= 1 && c2d.J < my.rectMap[0].length - 1) {          for (var i = c2d.I - 1, j = c2d.J + 1; i > 0, j < my.rectMap[0].length; i--, j++) {            if (j >= my.rectMap.length || i < 0) break;            temp = my.rectMap[i][j];            if (temp < 0 || temp !== c2d.player) {              break;            }            rbhcount++;            countArray.push({              I: i,              J: j            });          }        }      }      if (hcount >= 5 || vcount >= 5 || lbhcount >= 5 || rbhcount >= 5) {        my.winer = c2d.player;        my.gameover = true;        joinWinLine(countArray);        return true;      }      return false;    }

算法简介:主要思路是搜索最后落下棋子的位置(二维坐标)计算 米  字形线坐标,看是否有连续5个或以上棋子出现。

 

连接赢家棋子线

/**     * 连接赢家棋子线     * @param {Object} points     */    function joinWinLine(points) {      points.sort(function(left, right) {        return (left.I + left.J) > (right.I + right.J);      });      var startP = points.shift();      var endP = points.pop();      var poffset = my.baseWidth / 2;      can.strokeStyle = "#FF0000";      can.lineWidth = 2;      can.beginPath();      var spx = startP.I * my.baseWidth + poffset,        spy = startP.J * my.baseWidth + poffset;      can.arc(spx, spy, my.baseWidth / 4, 0, 2 * Math.PI, false);      can.moveTo(spx, spy);      var epx = endP.I * my.baseWidth + poffset,        epy = endP.J * my.baseWidth + poffset;      can.lineTo(epx, epy);      can.moveTo(epx + my.baseWidth / 4, epy);      can.arc(epx, epy, my.baseWidth / 4, 0, 2 * Math.PI, false);      can.closePath();      can.stroke();    }

算法简介:根据赢家返回的连子位置集合,做坐标大小位置排序,直接使用lineto 连接 第一个棋子和最后一个

 

坐标换算

/**     * 坐标换算     * @param {Object} loc     * @return {Object} I 二维数组横点(),J二维数组纵点,IX 横点起始坐标,JY纵点起始坐标,player 最后下棋玩, winer 赢家     */    function calc2dPoint(loc) {      var txp = Math.floor(loc.x / my.baseWidth),        typ = Math.floor(loc.y / my.baseWidth)      dxp = txp * my.baseWidth, dyp = typ * my.baseWidth;      loc.I = txp;      loc.J = typ;      loc.IX = dxp;      loc.JY = dyp;      return loc;    }

算法简介:这个比较简单,根据每个格子的宽度计算出实际坐标

 

电脑AI主要代码(修改来源于网络)

/**     * AI棋型分析     */    AI.analysis = function(x, y) {      //如果为第一步则,在玩家棋周围一格随机下棋,保证每一局棋第一步都不一样      if (my.ChessDownNum == 1) {        return this.getFirstPoint(x, y);      }      var maxX = 0,        maxY = 0,        maxWeight = 0,        i, j, tem;      for (i = BOARD_SIZE - 1; i >= 0; i--) {        for (j = BOARD_SIZE - 1; j >= 0; j--) {          if (my.rectMap[i][j] !== -1) {            continue;          }          tem = this.computerWeight(i, j, 2);          if (tem > maxWeight) {            maxWeight = tem;            maxX = i;            maxY = j;          }          if (my.enableCalcWeightNum) {            can.clearRect(i * 30 + 2, j * 30 + 2, 24, 24);            can.fillText(maxWeight, i * 30 + 5, j * 30 + 15, 30);          }        }      }      return new Point(maxX, maxY);    };    //下子到i,j X方向 结果: 多少连子 两边是否截断    AI.putDirectX = function(i, j, chessColor) {      var m, n,        nums = 1,        side1 = false, //两边是否被截断        side2 = false;      for (m = j - 1; m >= 0; m--) {        if (my.rectMap[i][m] === chessColor) {          nums++;        } else {          if (my.rectMap[i][m] === my.NO_CHESS) {            side1 = true; //如果为空子,则没有截断          }          break;        }      }      for (m = j + 1; m < BOARD_SIZE; m++) {        if (my.rectMap[i][m] === chessColor) {          nums++;        } else {          if (my.rectMap[i][m] === my.NO_CHESS) {            side2 = true;          }          break;        }      }      return {        "nums": nums,        "side1": side1,        "side2": side2      };    };    //下子到i,j Y方向 结果    AI.putDirectY = function(i, j, chessColor) {      var m, n,        nums = 1,        side1 = false,        side2 = false;      for (m = i - 1; m >= 0; m--) {        if (my.rectMap[m][j] === chessColor) {          nums++;        } else {          if (my.rectMap[m][j] === my.NO_CHESS) {            side1 = true;          }          break;        }      }      for (m = i + 1; m < BOARD_SIZE; m++) {        if (my.rectMap[m][j] === chessColor) {          nums++;        } else {          if (my.rectMap[m][j] === my.NO_CHESS) {            side2 = true;          }          break;        }      }      return {        "nums": nums,        "side1": side1,        "side2": side2      };    };    //下子到i,j XY方向 结果    AI.putDirectXY = function(i, j, chessColor) {      var m, n,        nums = 1,        side1 = false,        side2 = false;      for (m = i - 1, n = j - 1; m >= 0 && n >= 0; m--, n--) {        if (my.rectMap[m][n] === chessColor) {          nums++;        } else {          if (my.rectMap[m][n] === my.NO_CHESS) {            side1 = true;          }          break;        }      }      for (m = i + 1, n = j + 1; m < BOARD_SIZE && n < BOARD_SIZE; m++, n++) {        if (my.rectMap[m][n] === chessColor) {          nums++;        } else {          if (my.rectMap[m][n] === my.NO_CHESS) {            side2 = true;          }          break;        }      }      return {        "nums": nums,        "side1": side1,        "side2": side2      };    };    AI.putDirectYX = function(i, j, chessColor) {      var m, n,        nums = 1,        side1 = false,        side2 = false;      for (m = i - 1, n = j + 1; m >= 0 && n < BOARD_SIZE; m--, n++) {        if (my.rectMap[m][n] === chessColor) {          nums++;        } else {          if (my.rectMap[m][n] === my.NO_CHESS) {            side1 = true;          }          break;        }      }      for (m = i + 1, n = j - 1; m < BOARD_SIZE && n >= 0; m++, n--) {        if (my.rectMap[m][n] === chessColor) {          nums++;        } else {          if (my.rectMap[m][n] === my.NO_CHESS) {            side2 = true;          }          break;        }      }      return {        "nums": nums,        "side1": side1,        "side2": side2      };    };    /**     * 计算AI下棋权重     * chessColor 玩家1为玩家2为AI     */    AI.computerWeight = function(i, j, chessColor) {      //基于棋盘位置权重(越靠近棋盘中心权重越大)      var weight = 19 - (Math.abs(i - 19 / 2) + Math.abs(j - 19 / 2)),        pointInfo = {}; //某点下子后连子信息      //x方向      pointInfo = this.putDirectX(i, j, chessColor);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重      pointInfo = this.putDirectX(i, j, chessColor - 1);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重      //y方向      pointInfo = this.putDirectY(i, j, chessColor);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重      pointInfo = this.putDirectY(i, j, chessColor - 1);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重      //左斜方向      pointInfo = this.putDirectXY(i, j, chessColor);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重      pointInfo = this.putDirectXY(i, j, chessColor - 1);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重      //右斜方向      pointInfo = this.putDirectYX(i, j, chessColor);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, true); //AI下子权重      pointInfo = this.putDirectYX(i, j, chessColor - 1);      weight += this.weightStatus(pointInfo.nums, pointInfo.side1, pointInfo.side2, false); //player下子权重      return weight;    };    //权重方案  活:两边为空可下子,死:一边为空    //其实还有很多种方案,这种是最简单的    AI.weightStatus = function(nums, side1, side2, isAI) {      var weight = 0;      switch (nums) {        case 1:          if (side1 && side2) {            weight = isAI ? 15 : 10; //一          }          break;        case 2:          if (side1 && side2) {            weight = isAI ? 100 : 50; //活二          } else if (side1 || side2) {            weight = isAI ? 10 : 5; //死二          }          break;        case 3:          if (side1 && side2) {            weight = isAI ? 500 : 200; //活三          } else if (side1 || side2) {            weight = isAI ? 30 : 20; //死三          }          break;        case 4:          if (side1 && side2) {            weight = isAI ? 5000 : 2000; //活四          } else if (side1 || side2) {            weight = isAI ? 400 : 100; //死四          }          break;        case 5:          weight = isAI ? 100000 : 10000; //五          break;        default:          weight = isAI ? 500000 : 250000;          break;      }      return weight;    };

AI分析:这个只是最简单的算法,其实很简单,计算每个没有下棋坐标的分数,也是按照 字形 计算,计算格子8个方向出现的 一个棋子 二个棋子 三个棋子 四个棋子,其中还分为是否被截断,其实就是边缘是否被堵死。

 

其实这个AI算法后续还有很多可以优化,比如 断跳 二活 其实就是2个交叉的 活二  , 因为是断掉的所以没有纳入算法权重计算,如果加入这个算法,估计很难下赢电脑了。

如符号图:

*        *
*      *
空位         
下这里

因为不是连续的,所有没有纳入。

 

开源与下载

 http://jasnature.github.io/gobang_html5/

有兴趣的可以下载修改并提交代码进来^_^