PHP前端开发

HTML5 Canvas实现五子棋游戏的代码分享(图文)

百变鹏仔 3个月前 (10-18) #H5教程
文章标签 五子

背景介绍

因为之前用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.双方思考总时间记录

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

     

  

整体设计和主代码介绍

整体设计

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

 

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

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

主代码介绍

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

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

界面逻辑代码

<script type="text/javascript">        var gb = null;        var infoboj = document.getElementsByClassName("info")[0];        var pl1obj = document.getElementById("pl1");        var pl2obj = document.getElementById("pl2");        var plname1obj = document.getElementById("plname1");        var plname2obj = document.getElementById("plname2");        var chesstypeobj = document.getElementsByName("chesstype");        var chesscolorobj = document.getElementsByName("chesscolor");        var chessbgObj = document.getElementsByName("chessbg");        var winerpnl = document.getElementById("winer");        document.getElementById("startgame").addEventListener("click", function() {                        function initParams() {                var chessTypeValue = 1;                if (chesstypeobj.length > 0) {                    for (var i = 0; i < chesstypeobj.length; i++) {                        if (chesstypeobj[i].checked) {                            chessTypeValue = chesstypeobj[i].value;                            break;                        }                    }                }                var linevalue = "";                if (chesscolorobj.length > 0) {                    for (var i = 0; i < chesscolorobj.length; i++) {                        if (chesscolorobj[i].checked) {                            linevalue = chesscolorobj[i].value;                            break;                        }                    }                }                var bcorimgvalue = "";                if (chessbgObj.length > 0) {                    for (var i = 0; i < chessbgObj.length; i++) {                        if (chessbgObj[i].checked) {                            bcorimgvalue = chessbgObj[i].value;                            break;                        }                    }                }                return {                    lineColor: linevalue,                    chessType: chessTypeValue, //1 色彩棋子 2 仿真棋子                    playAName: plname1Input.value,                    playBName: plname2Input.value,                    backColorORImg: bcorimgvalue,                    playAImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playA.png",                    playBImg: "http://sandbox.runjs.cn/uploads/rs/62/nbqodq5i/playB.png",                    playerBIsComputer:openComputer.checked                };            }            document.getElementById("cc").style.display = "block";            gb = new gobang(initParams());            /**             * 设置一些界面信息             * @param {Object} opt             */            gb.info = function(opt) {                    infoboj.style.visibility = "visible";                    document.getElementsByClassName("startpnl")[0].style.visibility = "hidden";                    plname1obj.innerHTML = opt.playAName;                    plname2obj.innerHTML = opt.playBName;                    if (opt.chessType == 1) {                        var span1 = document.createElement("span");                        pl1obj.insertBefore(span1, plname1obj);                        var span2 = document.createElement("span");                        pl2obj.insertBefore(span2, plname2obj);                    } else {                        var img1 = document.createElement("img");                        img1.src = opt.playAImg;                        pl1obj.insertBefore(img1, plname1obj);                        var img2 = document.createElement("img");                        img2.src = opt.playBImg;                        pl2obj.insertBefore(img2, plname2obj);                    }                }                /**                 * 每次下棋后触发事件                  * @param {Object} c2d                 */            gb.operate = function(opt, c2d) {                if (!c2d.winer || c2d.winer <= 0) {                    pl1obj.removeAttribute("class", "curr");                    pl2obj.removeAttribute("class", "curr");                    if (c2d.player == 1) {                        pl2obj.setAttribute("class", "curr");                    } else {                        pl1obj.setAttribute("class", "curr");                    }                    document.getElementById("backChessman").innerHTML="悔棋("+c2d.canBackTimes+")";                } else {                    var winname = c2d.winer == 1 ? opt.playAName : opt.playBName;                    var str = "恭喜,【" + winname + "】赢了!"                    alert(str);                    winerpnl.style.display = "block";                    document.getElementById("winerName").innerHTML = "恭喜,【" + winname + "】赢了!";                    document.getElementById("pl" + c2d.winer).style.backgroundColor = "pink";                    document.getElementById("scoreA").innerHTML = c2d.playScoreA;                    document.getElementById("scoreB").innerHTML = c2d.playScoreB;                }            }            gb.start();        });                document.getElementById("openComputer").addEventListener("change", function() {            if (this.checked) {                plname2Input.value = "电脑";                plname2Input.disabled = "disabled";            } else {                plname2Input.value = "玩家二";                plname2Input.disabled = "";            }        });                //document.getElementById("openComputer").checked="checked";                //重新开始        function restartgui() {            if (gb) {                winerpnl.style.display = "none";                pl1obj.removeAttribute("class", "curr");                pl2obj.removeAttribute("class", "curr");                document.getElementById("pl1").style.backgroundColor = "";                document.getElementById("pl2").style.backgroundColor = "";                gb.restart();            }        };    </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个交叉的 活二  , 因为是断掉的所以没有纳入算法权重计算,如果加入这个算法,估计很难下赢电脑了。

如符号图:

**
**
空位         
下这里

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