国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JS+canvas實現五子棋人機大戰

sutaking / 709人閱讀

摘要:五子棋人機大戰創建實例是否結束我電腦所有棋子已經落下的棋子贏法總數所有贏法統計我的贏法統計電腦贏法統計初始化初始化生成棋盤棋盤初始化鼠標移動聚焦功能實現算法初始化落子功能實現生成棋盤初始化生成不是的倍數棋盤列初始化棋盤棋盤初始化畫棋盤畫

JS+canvas五子棋人機大戰

1. 創建實例
function Gobang () {
    this.over = false; // 是否結束
    this.player = true; // true:我  false:電腦
    this.allChesses = []; // 所有棋子
    this.existChesses = [] // 已經落下的棋子
    this.winsCount = 0; // 贏法總數
    this.wins = []; // 所有贏法統計
    this.myWins = []; //我的贏法統計
    this.computerWins = []; //電腦贏法統計
}
2. 初始化
//初始化
Gobang.prototype.init = function(opts) {
    // 生成canvas棋盤
    this.createCanvas(opts);

    //棋盤初始化 
    this.boardInit();

    // 鼠標移動聚焦功能實現
    this.mouseMove();

    //算法初始化
    this.algorithmInit();

    //落子功能實現
    this.dorpChess();
}
3. 生成canvas棋盤
//初始化
//生成canvas
Gobang.prototype.createCanvas = function(opts) {
    var opts = opts || {};
    if (opts.width && opts.width%30 !== 0) throw new RangeError(opts.width+"不是30的倍數");
    this.col = (opts.width && opts.width/30) || 15; // 棋盤列

    var oCanvas = document.createElement("canvas");
    oCanvas.width = oCanvas.height = opts.width || 450;
    this.canvas = oCanvas;
    document.querySelector(opts.container || "body").appendChild(this.canvas);
    this.ctx = oCanvas.getContext("2d");
}
4. 初始化棋盤
//棋盤初始化
Gobang.prototype.boardInit = function(opts){
    this.drawBoard();
}

// 畫棋盤
Gobang.prototype.drawBoard = function(){
    this.ctx.strokeStyle = "#bfbfbf";
    for (var i = 0; i < this.col; i++) {
        this.ctx.moveTo(15+ 30*i, 15);
        this.ctx.lineTo(15+ 30*i, this.col*30-15);
        this.ctx.stroke();
        this.ctx.moveTo(15, 15+ 30*i);
        this.ctx.lineTo(this.col*30-15, 15+ 30*i);
        this.ctx.stroke();
    }
}

5. 畫棋子
// 畫棋子
Gobang.prototype.drawChess = function(x, y, player){
    var x = 15 + x * 30,
        y = 15 + y * 30;
    this.ctx.beginPath();
    this.ctx.arc(x, y, 13, 0, Math.PI*2);


    var grd = this.ctx.createRadialGradient(x + 2, y - 2, 13 , x + 2, y - 2, 0);
    if (player) { //我 == 黑棋 
        grd.addColorStop(0, "#0a0a0a");
        grd.addColorStop(1, "#636766");
    }else{  //電腦 == 白棋
        grd.addColorStop(0, "#d1d1d1");
        grd.addColorStop(1, "#f9f9f9");
    }
    this.ctx.fillStyle = grd;
    this.ctx.fill()
}

6. 移動聚焦
// 鼠標移動時觸發聚焦效果, 需要前面的聚焦效果消失, 所有需要重繪canvas
Gobang.prototype.mouseMove = function(){
    var that = this;
    this.canvas.addEventListener("mousemove", function (e) {
        that.ctx.clearRect(0, 0, that.col*30, that.col*30);
        var x = Math.floor((e.offsetX)/30),
            y = Math.floor((e.offsetY)/30);

        //重繪棋盤
        that.drawBoard();

        //移動聚焦效果
        that.focusChess(x, y);

        //重繪已經下好的棋子
        that.redrawedChess()
    });
}

//鼠標移動聚焦
Gobang.prototype.focusChess = function(x, y){
    this.ctx.beginPath();
    this.ctx.fillStyle = "#E74343";
    this.ctx.arc(15 + x * 30, 15 + y * 30, 6, 0, Math.PI*2);
    this.ctx.fill();
}

//重繪當前下好的棋子
Gobang.prototype.redrawedChess = function(x, y){
    for (var i = 0; i < this.existChesses.length; i++) {
        this.drawChess(this.existChesses[i].x, this.existChesses[i].y, this.existChesses[i].player);
    }
}

7. 算法初始化
//算法初始化
Gobang.prototype.algorithmInit = function(){
    //初始化棋盤的每個位置和贏法
    for (var x = 0; x < this.col; x++) {
        this.allChesses[x] = [];
        this.wins[x] = [];
        for (var y = 0; y < this.col; y++) {
            this.allChesses[x][y] = false;
            this.wins[x][y] = [];
        }
    }

    //獲取所有贏法
    this.computedWins();

    // 初始化電腦和我每個贏法當前擁有的棋子數
    for (var i = 0; i < this.winsCount; i++) {
        this.myWins[i] = 0;
        this.computerWins[i] = 0;
    }
}
8. 獲取所有贏法
Gobang.prototype.computedWins = function(){
    /*
        直線贏法
        以15列為準
    */
    for (var x = 0; x < this.col; x++) { //縱向所有贏法
        for (var y = 0; y < this.col-4; y ++) {
            this.winsCount ++; 

            /*
                如: 
                1.組成的第一種贏法
                    [0,0]
                    [0,1]
                    [0,2]
                    [0,3]
                    [0,4]
                
                2.組成的第二種贏法
                    [0,1]
                    [0,2]
                    [0,3]
                    [0,4]
                    [0,5]
                以此類推一列最多也就11種贏法, 所有縱向x有15列  每列最多11種, 所有縱向總共15 * 11種
            */
            //以下for循環給每種贏法的位置信息儲存起來
            for (var k = 0; k < 5; k ++) {
                this.wins[x][y+k][this.winsCount] = true;
                /*
                    位置信息
                    第一種贏法的時候:
                        this.wins = [
                                        [
                                            [1:true],
                                            [1:true],
                                            [1:true],
                                            [1:true],
                                            [1:true]
                                        ],
                                        [
                                            ......
                                        ]
                                    ]

                        雖然這是一個三維數組, 我們把它拆分下就好理解了
                        相當于  this.wins[0][0][1], this.wins[0][4][1], this.wins[0][5][1], this.wins[0][6][1], this.wins[0][7][1]
                        
                        因為對象可以這樣取值:
                            var obj = {
                                a: 10,
                                b: "demo"
                            }
                            obj["a"] === obj.a

                        所有也就相當于 this.wins[0][0].1, this.wins[0][8].1, this.wins[0][9].1, this.wins[0][10].1, this.wins[0][11].1 

                        雖然數組不能這么取值,可以這么理解

                        所以      this.wins[0][0].1  就可以理解為  在 x=0, y=0, 上有第一種贏法
                                this.wins[0][12].1  就可以理解為  在 x=0, y=1, 上有第一種贏法
                                ......

                        以上this.wins[0][0],this.wins[0][13]...可以看作是 this.wins[x][y]
                        所以第一種贏法的坐標就是: [0,0] [0,1] [0,2] [0,3] [0,4] 
                */
            }
        }
    }

    for (var y = 0; y < this.col; y++) { //橫向所有贏法, 同縱向贏法一樣,也是15 * 11種
        for (var x = 0; x < this.col-4; x ++) {
            this.winsCount ++;
            for (var k = 0; k < 5; k ++) {
                this.wins[x+k][y][this.winsCount] = true;
            }
        }
    }

交叉贏法

    /*
        交叉贏法
    */
    for (var x = 0; x < this.col-4; x++) { // 左 -> 右 開始的所有交叉贏法  總共11 * 11種
        for (var y = 0; y < this.col-4; y ++) {
            this.winsCount ++;

            /*
            如:
            1.  [0,0]
                [1,1]
                [2,2]
                [3,3]
                [4,4]
            
            2.  [0,1]
                [1,2]
                [2,3]
                [3,4]
                [4,5]

            3.  [0,2]
                [1,3]
                [2,4]
                [3,5]
                [4,6]
            ...

                [1,0]
                [2,1]
                [3,2]
                [4,3]
                [5,5]

            相當于從左至右  一列列計算過去

            */

            for (var k = 0; k < 5; k ++) {
                this.wins[x+k][y+k][this.winsCount] = true;
            }
        }
    }

    for (var x = this.col-1; x >= 4; x --) { //右 -> 左 開始的所有交叉贏法  總共11 * 11種
        for (var y = 0; y < this.col-4; y ++) {
            this.winsCount ++;
            for (var k = 0; k < 5; k ++) {
                this.wins[x-k][y+k][this.winsCount] = true;
            }
        }
    }
}
9. 落子實現
//落子實現
Gobang.prototype.dorpChess = function(){
    var that = this;
    this.canvas.addEventListener("click", function(e) {
        // 判斷是否結束
        if (that.over) return;

        var x = Math.floor((e.offsetX)/30),
            y = Math.floor((e.offsetY)/30);

        //判斷該棋子是否已存在
        if (that.allChesses[x][y]) return;

        // 檢查落子情況
        that.checkChess(x, y)

        if (!that.over) {
            that.player = false;
            that.computerDropChess();//計算機落子
        }
    })
}


//檢查落子情況
Gobang.prototype.checkChess = function(x, y){
    //畫棋
    this.drawChess(x, y, this.player);
    //記錄落下的棋子
    this.existChesses.push({
        x: x,
        y: y,
        player: this.player
    });
    //該位置棋子置為true,證明已經存在
    this.allChesses[x][y] = true;

    this.currWinChesses(x, y, this.player);
}

//判斷當前坐標贏的方法各自擁有幾粒棋子
Gobang.prototype.currWinChesses = function(x, y, player){
    var currObj = player ? this.myWins : this.computerWins;
    var enemyObj = player ? this.computerWins : this.myWins;
    var currText = player ? "我" : "電腦";
    for (var i = 1; i <= this.winsCount; i++) {
        if (this.wins[x][y][i]) { //因為贏法統計是從1開始的  所以對應我的贏法需要減1
            currObj[i-1] ++;  // 每個經過這個點的贏法都增加一個棋子;

            enemyObj[i-1] = 6; //這里我下好棋了,證明電腦不可能在這種贏法上取得勝利了, 置為6就永遠不會到5

            if (currObj[i-1] === 5) { //當達到 5 的時候,證明我勝利了
                alert(currText+"贏了")
                this.over = true;
            }
        }
    }
}
9. 計算機落子實現
// 計算機落子
Gobang.prototype.computerDropChess = function(){
    var myScore = [], //玩家比分
        computerScore = [], // 電腦比分
        maxScore = 0; //最大比分
    

    //比分初始化
    var scoreInit = function(){
        for( var x = 0; x < this.col; x ++) {  
            myScore[x] = [];
            computerScore[x] = [];
            for (var y = 0; y < this.col; y ++) {
                myScore[x][y] = 0;
                computerScore[x][y] = 0;
            }
        }
    }
    scoreInit.call(this);

    //電腦待會落子的坐標
    var x = 0, y = 0; 

    // 基于我和電腦的每種贏法擁有的棋子來返回對應的分數
    function formatScore(o, n) { 
        if (o < 6 && o > 0) {
            var n = 10;
            for (var i = 0; i < o; i++) {
                n *= 3;
            }
            return n
        }
        return 0
    }

    // 獲取沒有落子的棋盤區域
    function existChess(arr) { 
        var existArr = [];
        for (var i = 0; i < arr.length; i++) {
            for (var j = 0; j < arr[i].length; j++) {
                if (!arr[i][j]) {
                    existArr.push({x:i, y:j})
                }
            }
        }
        return existArr;
    }

    var exceptArr = existChess(this.allChesses);

    // 循環未落子區域,找出分數最大的位置
    for (var i = 0; i < exceptArr.length; i++) { 
        var o = exceptArr[i];

        // 循環所有贏的方法
        for (var k = 0; k < this.winsCount; k++) {

            //判斷每個坐標對應的贏法是否存在
            if (this.wins[o.x][o.y][k]) {

                // 計算每種贏法,擁有多少棋子,獲取對應分數
                // 電腦起始分數需要高一些,因為現在是電腦落子, 優先權大
                myScore[o.x][o.y] += formatScore(this.myWins[k-1], 10);
                computerScore[o.x][o.y] += formatScore(this.computerWins[k-1], 11); 
            }
        }

        //我的分數判斷
        if (myScore[o.x][o.y] > maxScore) { //當我的分數大于最大分數時, 證明這個位置的是對我最有利的
            maxScore = myScore[o.x][o.y];
            x = o.x;
            y = o.y;
        }else if (myScore[o.x][o.y] === maxScore) { //當我的分數與最大分數一樣時, 證明我在這兩個位置下的效果一樣, 所以我們應該去判斷在這兩個位置時,電腦方對應的分數
            if (computerScore[o.x][o.y] > computerScore[x][y]) {
                x = o.x;
                y = o.y;
            }
        }

        // 電腦分數判斷, 因為是電腦落子, 所以優先權大
        if (computerScore[o.x][o.y] > maxScore) {
            maxScore = computerScore[o.x][o.y];
            x = o.x;
            y = o.y;
        }else if (computerScore[o.x][o.y] === maxScore) {
            if (myScore[o.x][o.y] > myScore[x][y]) {
                x = o.x;
                y = o.y;
            }
        }
    }

    this.checkChess(x, y)

    if (!this.over) {
        this.player = true;
    }
}
var gobang = new Gobang();
gobang.init()

github地址
線上地址

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/90080.html

相關文章

  • 原生JS+Canvas實現子棋游戲

    摘要:撤銷悔棋功能悔棋過后,再撤銷,相當于還原悔棋之前的狀態。三總結五子棋游戲的核心關鍵點是弄清楚有多少種贏法怎么判斷是否已經贏了計算機下棋算法。 一、功能模塊 先看下現在做完的效果: showImg(https://segmentfault.com/img/remote/1460000009826653?w=481&h=640); 線上體驗:https://wj704.github.io/...

    Joyven 評論0 收藏0
  • Vue 實現人機子棋

    摘要:預覽效果源碼核心代碼記錄是否走過所有贏法數量贏法數組我方贏法的統計數組計算機贏法的統計數組初始化填充數組是否走過贏法數組橫豎斜反斜贏法的統計數組繪制水印繪制棋盤落子實現我方落子統計贏法你贏了計算機落子最大分數所在坐標遍歷棋盤遍 預覽效果 github源碼 showImg(https://segmentfault.com/img/bVbk02l?w=450&h=450); 核心代碼 ...

    codeGoogle 評論0 收藏0
  • Vue 實現人機子棋

    摘要:預覽效果源碼核心代碼記錄是否走過所有贏法數量贏法數組我方贏法的統計數組計算機贏法的統計數組初始化填充數組是否走過贏法數組橫豎斜反斜贏法的統計數組繪制水印繪制棋盤落子實現我方落子統計贏法你贏了計算機落子最大分數所在坐標遍歷棋盤遍 預覽效果 github源碼 showImg(https://segmentfault.com/img/bVbk02l?w=450&h=450); 核心代碼 ...

    Object 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<