首頁 web前端 H5教程 HTML5 Canvas實作五子棋遊戲的程式碼分享(圖文)

HTML5 Canvas實作五子棋遊戲的程式碼分享(圖文)

Mar 22, 2017 pm 03:43 PM

背景介紹

  因為之前用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.雙方思考總時間記錄

介面截圖賞析(沒花時間美化,比較醜)

 HTML5 Canvas實作五子棋遊戲的程式碼分享(圖文)  #  

#  

整體設計與主程式碼介紹

整體設計




下棋流程:玩家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个交叉的 活二  , 因为是断掉的所以没有纳入算法权重计算,如果加入这个算法,估计很难下赢电脑了。

如符号图:

*        *
*      *
空位         
下这里

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

以上是HTML5 Canvas實作五子棋遊戲的程式碼分享(圖文)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1421
52
Laravel 教程
1315
25
PHP教程
1266
29
C# 教程
1239
24
HTML 中的表格邊框 HTML 中的表格邊框 Sep 04, 2024 pm 04:49 PM

HTML 表格邊框指南。在這裡,我們以 HTML 中的表格邊框為例,討論定義表格邊框的多種方法。

HTML 中的巢狀表 HTML 中的巢狀表 Sep 04, 2024 pm 04:49 PM

這是 HTML 中巢狀表的指南。這裡我們討論如何在表中建立表格以及對應的範例。

HTML 左邊距 HTML 左邊距 Sep 04, 2024 pm 04:48 PM

HTML 左邊距指南。在這裡,我們討論 HTML margin-left 的簡要概述及其範例及其程式碼實作。

HTML 表格佈局 HTML 表格佈局 Sep 04, 2024 pm 04:54 PM

HTML 表格佈局指南。在這裡,我們詳細討論 HTML 表格佈局的值以及範例和輸出。

HTML 輸入佔位符 HTML 輸入佔位符 Sep 04, 2024 pm 04:54 PM

HTML 輸入佔位符指南。在這裡,我們討論 HTML 輸入佔位符的範例以及程式碼和輸出。

HTML 有序列表 HTML 有序列表 Sep 04, 2024 pm 04:43 PM

HTML 有序列表指南。在這裡我們也分別討論了 HTML 有序列表和類型的介紹以及它們的範例

HTML onclick 按鈕 HTML onclick 按鈕 Sep 04, 2024 pm 04:49 PM

HTML onclick 按鈕指南。這裡我們分別討論它們的介紹、工作原理、範例以及各個事件中的onclick事件。

在 HTML 中移動文字 在 HTML 中移動文字 Sep 04, 2024 pm 04:45 PM

HTML 中的文字移動指南。在這裡我們討論一下marquee標籤如何使用語法和實作範例。

See all articles