欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

js+canvas 人机井字棋

程序员文章站 2022-05-19 15:02:24
...
<html>
<head>
    <meta charset='utf-8'>
    <style>
        #again {
            font-size: 18px;
            font-family: 华文细黑;
            letter-spacing: 5px;
            padding-left: 12px;
            border-radius: 5px;
            background: -webkit-linear-gradient(top, #66B5E6, #2e88c0);
            background: -moz-linear-gradient(top, #66B5E6, #2e88c0);
            background: linear-gradient(top, #66B5E6, #2e88c0);
            background: -ms-linear-gradient(top, #66B5E6, #2e88c0);
            border: 1px solid #2576A8;
            box-shadow: 0 1px 2px #B8DCF1 inset, 0 -1px 0 #316F96 inset;
            color: #fff;
            text-shadow: 1px 1px 0.5px #22629B;
            cursor:pointer;
            position:absolute;
        }
        #again:hover {
            background: -webkit-linear-gradient(top, #8DC9EF, #4E9FD1);
            background: -moz-linear-gradient(top, #8DC9EF, #4E9FD1);
            background: linear-gradient(top, #8DC9EF, #4E9FD1);
            background: -ms-linear-gradient(top, #8DC9EF, #4E9FD1);
        }
    </style>
</head>
<body>
<canvas id='canvas' style="position:absolute" ></canvas>
<div onclick="location.reload()" style='width: 105px;height: 30px;'id="again" hidden>再来一局</div>
</body>
<script>

    window.onload = function(){
        canvas.init();
        chessBoard.draw();
        player.listen();
    };

    var game ={
        OVER:0,//游戏结束
        PLAYER_TURN:1,//轮到玩家
        COMPUTER_TURN:2,//轮到电脑
        status:1,//当前状态
        PLAYER_COUNT:1,
        COMPUTER_COUNT:-1,
        turn:function(){
            this.judge();
            if(this.status===this.OVER){
                canvas.body.onclick ='';
                button.body.style.display='block';
            }else if(this.status ===this.PLAYER_TURN){
                this.status = this.COMPUTER_TURN;
                computer.move();
            }else{
                this.status = this.PLAYER_TURN;
            }
        },
        judge:function(){
            var equal =true;
            //检查平局
            for(var i=0;i<3;i++){
                for(var j=0;j<3;j++){
                    if(chessBoard.box[i][j]===0){
                        equal = false;
                    }
                }
            }
            if(equal){
                alert("双方战平");
                this.status = this.OVER;
            }else {
                for (var i = 0; i < 3; i++) {
                    this.check(chessBoard.box[0][i], chessBoard.box[1][i], chessBoard.box[2][i]);
                    if(this.status===this.OVER) return;
                    this.check(chessBoard.box[i][0], chessBoard.box[i][1], chessBoard.box[i][2]);
                    if(this.status===this.OVER) return;
                }
                this.check(chessBoard.box[0][0], chessBoard.box[1][1], chessBoard.box[2][2]);
                if(this.status===this.OVER) return;
                this.check(chessBoard.box[2][0], chessBoard.box[1][1], chessBoard.box[0][2]);
                if(this.status===this.OVER) return;
            }
        },
        check:function(v1,v2,v3){
            var val = this.sum(v1,v2,v3);
            if(val === game.PLAYER_COUNT*3){
                alert("玩家胜");
                this.status = this.OVER;
            }else if(val === game.COMPUTER_COUNT*3){
                alert("电脑胜");
                this.status = this.OVER;
            }
        },
        sum:function(v1,v2,v3){
            return v1+v2+v3;
        },
        move:function(x,y){
            chessBoard.box[x][y] = (this.status===this.PLAYER_TURN)?this.PLAYER_COUNT:this.COMPUTER_COUNT;
            chess.draw(x,y);
            game.turn();
        }
    };

    var player ={
        listen:function(){
            canvas.body.onclick = function(e){
                if(game.status === game.COMPUTER_TURN){
                    return;
                }
                player.move(e);
            }
        },
        move:function(e){
            var x = parseInt(e.offsetX/(chessBoard.width/3));
            var y = parseInt(e.offsetY/(chessBoard.width/3));
            if(chessBoard.box[x][y]===0) {
                game.move(x, y);
            }
        }
    };

    var computer ={
        mayLose:{x:3,y:3},
        emptyPos:{x:3,y:3},
        horizon:0,
        vertical:1,
        diagonal1:2,
        diagonal2:3,
        move:function(){
            this.think();
            if(game.status === game.OVER){
                return;
            }
            if(this.mayLose.x!==3){
                game.move(this.mayLose.x,this.mayLose.y);
            }else{
                var x =1,y=1;
                while(chessBoard.box[x][y]!==0){
                    x = parseInt(Math.random()*11)%3;
                    y = parseInt(Math.random()*11)%3;
                }
                game.move(x,y);
            }
        },
        //判断顺序:己方能不能赢,对方能不能赢
        think:function(){
            this.mayLose = {x:3,y:3};
            this.emptyPos ={x:3,y:3};
            for(var i=0;i<3;i++){
                if(this.read(i,this.horizon)||
                    this.read(i,this.vertical)){
                    return;
                };
            }
            if(this.read('',this.diagonal1)||
                this.read('',this.diagonal2)){
                return;
            }
        },
        read:function(i,type){
            var sum =0;
            for(var j=0;j<3;j++){
                var pos = this.getPosByType(type,i,j);
                sum +=chessBoard.box[pos.x][pos.y];
                if(chessBoard.box[pos.x][pos.y]===0){
                    this.emptyPos.x = pos.x;
                    this.emptyPos.y = pos.y;
                }
            }
            return this.check(sum);
        },
        getPosByType:function(type,i,j){
            switch(type) {
                case this.horizon:
                    return {x:i,y:j};
                case this.vertical:
                    return {x:j,y:i};
                case this.diagonal1:
                    return {x:j,y:j};
                case this.diagonal2:
                    return {x:j,y:2-j}
            }
        },
        check:function(val){
            if(val===game.COMPUTER_COUNT*2){
                game.move(this.emptyPos.x,this.emptyPos.y);
                return true;
            }else if(val===game.PLAYER_COUNT*2){
                this.mayLose.x = this.emptyPos.x;
                this.mayLose.y = this.emptyPos.y;
            }
            return false;
        }
    };

    var chessBoard = {
        margin:100,
        width:600,
        box:[[0,0,0],[0,0,0],[0,0,0]],
        draw:function(){
            //绘制棋面
            drawRect(0,0,chessBoard.width,chessBoard.width,'#e6e61a',1,'#020202');
            //绘制格子
            canvas.cxt.beginPath();
            for(var i=1;i<3;i++){
                //绘制纵线
                canvas.cxt.moveTo(chessBoard.width/3*i,0);
                canvas.cxt.lineTo(chessBoard.width/3*i,chessBoard.width);
                //绘制横线
                canvas.cxt.moveTo(0,chessBoard.width/3*i);
                canvas.cxt.lineTo(chessBoard.width,chessBoard.width/3*i);
            }
            canvas.cxt.stroke();
        }

    };

    var chess = {
        margin:10,
        draw:function(x,y){
            canvas.cxt.beginPath();
            canvas.cxt.arc(
                chess.getCenterPos(x), //圆心的x坐标
                chess.getCenterPos(y), //圆心的y坐标
                (chessBoard.width/3-chess.margin*2)/2//圆半径
                , 0, 2 * Math.PI);
            canvas.cxt.closePath();
            //渐变
            var gradient = canvas.cxt.createRadialGradient(
                chess.getCenterPos(x)+5, //圆心的x坐标
                chess.getCenterPos(y)-5, //圆心的y坐标
                (chessBoard.width/3-chess.margin*2)/2, //圆半径
                chess.getCenterPos(x)+5,
                chess.getCenterPos(y)-5, 0);

            if(game.status === game.PLAYER_TURN){
                gradient.addColorStop(0,'#0a0a0a');
                gradient.addColorStop(1,'#636766');
            }else{
                gradient.addColorStop(0,'#d1d1d1');
                gradient.addColorStop(1,'#f9f9f9');
            }
            canvas.cxt.fillStyle = gradient;
            canvas.cxt.fill();
        },
        //得到圆心的位置;
        getCenterPos:function(arg){
            return chessBoard.width/3*arg+chessBoard.width/6;
        }
    };

    var canvas ={
        body:'',
        cxt:'',
        left:650,
        top:100,
        init:function(){
            this.body = document.getElementById('canvas');
            this.body.width = chessBoard.width +chessBoard.margin;
            this.body.height = chessBoard.width +chessBoard.margin;
            this.body.style.left = this.left;
            this.body.style.top = this.top;
            this.cxt = this.body.getContext('2d');
            button.location();
        }
    };
    
    var button ={
        body:'',
        location:function(){
            this.body = document.getElementById('again');
            this.body.style.left = canvas.left  + (chessBoard.margin+chessBoard.width)/2 -105;
            this.body.style.top = canvas.top + chessBoard.width +chessBoard.margin;
        }
    };

    //绘制矩形
    function drawRect( x, y, width, height, fillColor, borderWidth, borderColor){
        canvas.cxt.beginPath();
        canvas.cxt.moveTo(x, y);
        canvas.cxt.lineTo(x + width, y);
        canvas.cxt.lineTo(x + width, y + height);
        canvas.cxt.lineTo(x, y + height);
        canvas.cxt.lineTo(x, y);
        canvas.cxt.closePath();

        canvas.cxt.lineWidth = borderWidth;
        canvas.cxt.strokeStyle = borderColor;
        canvas.cxt.fillStyle = fillColor;

        canvas.cxt.fill();
        canvas.cxt.stroke();
    }
</script>
</html>

js+canvas 人机井字棋

主要类:

canvas:  封装canvas的相对位置和初始化。

button: 封装再来一局按钮的相对位置。

chessBoard:封装棋盘相对位置和绘画,保存已落子的情况。

chess: 封装棋子的相对位置和绘画。

game:封装游戏状态(玩家落子、电脑落子、游戏结束);游戏结束的判断及展示。

player:封装鼠标事件监听响应。

computer: 封装电脑的落子判断。


电脑落子基本思想:

 先判断自己能不能赢,再判断自己会不会输。再随机选择一个空白位置落子