>  기사  >  웹 프론트엔드  >  HTML5 Canvas는 주사위 놀이 게임(그림 및 텍스트)에 대한 코드 공유를 구현합니다.

HTML5 Canvas는 주사위 놀이 게임(그림 및 텍스트)에 대한 코드 공유를 구현합니다.

黄舟
黄舟원래의
2017-03-22 15:43:586387검색

배경 소개

이전에 C# winform에서 gdi+ 및 java 그래픽 패키지를 사용하여 주사위 놀이를 했기 때문에 이러한 논리적인 아이디어는 익숙합니다. 그러나 최근에는 html5의 캔버스 그리기 기능을 검토하고 싶습니다. (회사에서는 일반적으로 사용하지 않습니다) 이) 그래서 주사위 놀이를 만들었습니다. 물론 이전 클라이언트 코드를 참조하지는 않았습니다. 이전의 승패 판단 알고리즘과 컴퓨터 AI(네트워크 차용) 알고리즘만 사용했습니다. 물론 Baidu에는 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는 주사위 놀이 게임(그림 및 텍스트)에 대한 코드 공유를 구현합니다.

전체 디자인 및 메인코드 소개

전체 디자인

체스 플레이 프로세스: 플레이어 또는 컴퓨터 AI가 체스를 놓는다 ---> > 체스 말의 2차원 좌표 값 설정----> >
  ↑                |
  |          ↓
  < ;------------------- ----------------- ------- ------------아들 다섯 없음

회개 과정(모두가 서로 대결): 한 플레이어가 수를 후회합니다---> 체스 기록 더미를 올려 놓고 설정합니다. 마지막 체스 말이기 때문입니다 ---> 마지막 체스 말 이미지 지우기 ---> 체스 말의 2차원 좌표 값 지우기 ---> 마지막 체스 위치 표시 및 깜박임  

회개 과정(인간-기계 전투): ​​

플레이어가 체스를 후회합니다----> 체스 기록 스택을 2번 팝업하고 마지막 컴퓨터를 마지막 체스로 설정 ---> 기록된 이미지 올리기 ---> 두 체스 말의 2차원 좌표 값 지우기 ---> 마지막 체스 위치를 재배치하여 표시하고 깜박입니다

메인 코드 소개

  

메인 코드는 두 개의 블록으로 나누어집니다. 1. 인터페이스 로직 블록 2. 게임 메인 블록(인터페이스와 게임 코드가 분리됨) , 명확한 로직과 분업으로 Clear)

Simulation

Event

Notification: 게임 메인 로직 블록, 각 결과는 인터페이스 레이어에 통보됩니다. 상호 작용용(C# 또는 Java Delegate 또는 이벤트와 유사) 인터페이스 로직 코드

<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으로 문의하세요.