实现五子棋html AI+普通结合

AI/普通 实现五子棋html

大二期末,js老师布置实训任务中其中一项:五子棋。
先了解一下五子棋算法慨念吧。
五子棋应该大多数都玩过,人机或两人作战,各执黑白棋子,上下左右,左上,左下,右上,右下等方向若凑齐5颗连成线均为赢。
在网上各大博客中,都有谈到AI来实现算法,用三维数组,这里可以参考百度搜一下来看看。

现在,关键是如何利用这个三维数组,其实很多机器博弈其实就是在打分,再把棋子下到分高(或分低)的地方,比如下红色位置,如果没有棋子,应该 给一个较高分,因为在下一个白棋子就赢了,但是如果下了一个黑棋子,那么,上面的第一种赢法无论如何也不可能了,所以直接设置为零分。所以在设置两个一位数组,记录每种赢法的得分,再查找棋盘上哪些位置可以实现这种赢法,给这些位置加分,最后从所有位置中,找出分最高的落子即可。而且,一种赢法上的落子越多,就越接近获胜,所以分数应该越高。

    // 计算机下棋
    var computerAI = function() {
            var myScore = [];
            var computerScore = [];
            var max = 0;
            var u = 0,v = 0;
            for(var i = 0; i < 15; i++) {
                myScore[i] = [];
                computerScore[i] = [];
                for(var j = 0; j < 15; j++) {
                    myScore[i][j] = 0;
                    computerScore[i][j] = 0;
                }
            }
            for(var i = 0; i < 15; i++) {
                for(var j = 0; j < 15; j++) {
                    if(chressBord[i][j] == 0) {
                        for(var k = 0; k < count; k++) {
                            if(wins[i][j][k]) {
                                if(myWin[k] == 1) {
                                    myScore[i][j] += 200;
                                } else if(myWin[k] == 2) {
                                    myScore[i][j] += 400;
                                } else if(myWin[k] == 3) {
                                    myScore[i][j] += 2000;
                                } else if(myWin[k] == 4) {
                                    myScore[i][j] += 10000;
                                }
                                if(computerWin[k] == 1) {
                                    computerScore[i][j] += 220;
                                } else if(computerWin[k] == 2) {
                                    computerScore[i][j] += 420;
                                } else if(computerWin[k] == 3) {
                                    computerScore[i][j] += 2100;
                                } else if(computerWin[k] == 4) {
                                    computerScore[i][j] += 20000;
                                }
                            }
                        }
                        if(myScore[i][j] > max) {
                            max = myScore[i][j];
                            u = i;
                            v = j;
                        } else if(myScore[i][j] == max) {
                            if(computerScore[i][j] > computerScore[u][v]) {
                                u = i;
                                v = j;
                            }
                        }
                        if(computerScore[i][j] > max) {
                            max = computerScore[i][j];
                            u = i;
                            v = j;
                        } else if(computerScore[i][j] == max) {
                            if(myScore[i][j] > myScore[u][v]) {
                                u = i;
                                v = j;
                            }
                        }
                    }
                }
            }
            _compi = u;
            _compj = v;
            oneStep(u, v, false);
            chressBord[u][v] = 2;//计算机占据位置
        for(var k = 0; k < count; k++) {
            if(wins[u][v][k]) {
                computerWin[k]++;
                _myWin[k] = myWin[k];
                myWin[k] = 6; //这个位置对方不可能赢了
                if(computerWin[k] == 5) {
                    resultTxt.innerHTML = '遗憾,计算机赢了,继续加油哦!';
                    over = true;
                }
            }
        }
        if(!over) {
            me = !me;
        }
        backAble = true;
        returnAble = false;
        var hasClass = new RegExp('unable').test(' ' + returnbtn.className + ' ');
        if(!hasClass) {
            returnbtn.className+=' '+'unable';
        }
    }

首先棋盘设定是15*15
赢的方式有572中赢法

//赢法的统计数组
    var myWin = [];
    var computerWin = [];
    //赢法数组
    var wins = [];
    for(var i = 0; i < 15; i++) {
        wins[i] = [];
        for(var j = 0; j < 15; j++) {
            wins[i][j] = [];
        }
    }

    var count = 0; //赢法总数
    //横线赢法
    for(var i = 0; i < 15; i++) {
        for(var j = 0; j < 11; j++) {
            for(var k = 0; k < 5; k++) {
                wins[i][j + k][count] = true;
            }
            count++;
        }
    }
    //竖线赢法
    for(var i = 0; i < 15; i++) {
        for(var j = 0; j < 11; j++) {
            for(var k = 0; k < 5; k++) {
                wins[j + k][i][count] = true;
            }
            count++;
        }
    }
    //正斜线赢法
    for(var i = 0; i < 11; i++) {
        for(var j = 0; j < 11; j++) {
            for(var k = 0; k < 5; k++) {
                wins[i + k][j + k][count] = true;
            }
            count++;
        }
    }
    //反斜线赢法
    for(var i = 0; i < 11; i++) {
        for(var j = 14; j > 3; j--) {
            for(var k = 0; k < 5; k++) {
                wins[i + k][j - k][count] = true;
            }
            count++;
        }
    }
另外我也在程序中用到悔棋,撤销悔棋

实现五子棋html AI+普通结合_第1张图片

这是利用canvas的棋盘和AI算法来完成的五子棋游戏。
也有经典的算法来实现它。(看代码注释)

也可以参考我们老师写的:
实现五子棋html AI+普通结合_第2张图片

资源文件我一并上传吧:
实现五子棋html AI+普通结合_第3张图片
这里写图片描述

这里写图片描述

代码我贴上来吧:


<html lang="en">
<head>
    <meta charset="UTF-8">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>五子棋title>
    <script>
        var n=15;
        var winCount=5;
        var isComputer;
        var tbWidth=15*30+2;
        var tbHeight=15*30+2;
        var qipan=new Array(n);
        window.onload=initBoard;
        //画棋盘,并初始化数组
        function initBoard() {
            isComputer=true;
            var table=document.createElement("table");
            for(var i=0;ivar td=document.createElement("tr");
                for(var j=0;j//每行有n列,n个单元格
                    var td=document.createElement("td");
                    //设置单元格的id,规则是前缀p加坐标i和j(此处坐标只是表示位置,不非用像素表示的坐标),编号从上往下,从左往右,i代表横坐标,j代表纵坐标
                    td.setAttribute("id","p"+j+"_"+i);
                    tr.appendChild(td);
                }
                table.appendChild(tr);
            }
            //设置表格的宽度和高度
            table.style.width=tbWidth+"px";
            table.style.height=tbHeight+"px";
            var div=document.getElementsByTagName("div")[0]; //获取到放棋盘的div对象
            div.innerHTML="";  //清空原来的内容
            div.appendChild(table);
            //设置div的位置
            var left = (window.screen.availWidth-tbWidth)/2;
            var top = (window.screen.availHeight-tbHeight)/2-50;
            //设置div的宽度、高度和位置
            div.style.width=tbWidth+"px";
            div.style.height=tbHeight+"px";
            div.style.left=left+"px";
            div.style.top=top+"px";
            //同时设置一个最后一个段落的位置
            document.getElementsByTagName("p")[0].style.left=left+"px";
            //初始化数组
            for (var i=0;inew Array(n);
                for(var j=0;j0;
                }
            }
            //绑定每个单元格的单击时间
            var tds=document.getElementsByTagName("td");
            for(var i = 0;i//棋手走棋
                }
            //电脑走棋子
            computer();
            }
        //棋手走棋
        function user() {
            //播放点击的声音
            document.getElementById("dianji").play();
            var id=this.id; //获取当前单元格的id
            id=id.substr();
            var i=id.split("_")[0];  //取出横向位置
            var j=id.split("_")[0];  //取出纵向位置
            if(qipan[i][j]==0) {   //没有子可以下,否则不响应
                this.style.background="url(img/white.jpg) no-repeat";
                qipan[i][j]=2;  //记录下的棋子,2表示白子,用户
                checkWin(i,j);  //判断胜负情况
                computer();  //让计算机继续下
            }
        }
        //计算机走棋,如果要让计算机更智能,需要设计算法,不是随机下
        function computer() {
            //每次计算机走之前都要判断还有位置走没有,如果已经没有位置可走,则平局
            var next=false;  //是否可以走下一步,初值为0;没有位置可以走了
            for (var i=0;ifor (var j=0;jif(qipan[i][j]==0) {
                        next=true;
                        break;
                    }
                }
            }
            if(!next) {
                alert("平局");
                location.reload();  //刷新页面,重新开始
            }
            var i=Math.floor(Math.random()*n) ;  //floor向下取整数,获取一个0到n-1的随机数
            var j=Math.floor(Math.random()*n);
            //判断当前有棋子没有
            while(qipan[i][j]!=0) {
                //表示已经有子,重新产生一个位置
                var i=Math.floor(Math.random()*n);
                var j=Math.floor(Math.random()*n);
            }
            var td = document.getElementById("p"+i+"_"+j);
            td.style.background="url(img/black.jpg) no-repeat";
            document.getElementById("p"+preComputer[0]+"_"+preComputer[1]).className="";  //取消前一颗棋子设置的样式
            td.className="cur";  //设置当前棋子为红色边框
            preComputer[0]=i;
            preComputer[1]=j;
            qipan[i][j]=1;  //记录下的棋子。1表示黑子,计算机
            checkWin(i,j);  //判断胜负情况
        }
        //获胜判断,x代表水平坐标,y代表垂直坐标
        function checkWin(x,y) {
            x=parseInt(x);  //作数据类型转换
            y=parseInt(y);
            var total=0;  //
            //i 的取值范围0至n-1,j的取值范围0至n-1
            var begin;
            var end;
            //判断水平方向,y不变
            if(x-winCount+1<=0){
                begin=0;
            }else {
                begin=x-winCount+1;
            }
            if(x+winCount-1>=n) {
                end=n-1;
            }else {
                end=x+winCount-1;
            }
            for (var i = begin;i<=end;i++) {
                //如果当前棋子是计算机统计的个数,如果是棋子是用户就统计2的个数
                if (isComputer) {
                    if(qipan[i][y]==1){
                        total++;
                        if(total>=5) {
                            alert("计算机获胜!");
                            location.reload(); //刷新页面,重新开始
                        }
                    }else {
                        total=0;  //重新计算
                    }
                } else{
                    if(qipan[i][y] == 2) {
                        total++;
                        if(total >= 5) {
                            alert("选手获胜");
                            location.reload(); //刷新页面,重新开始
                        }
                    }else {
                        total=0;  //重新计算
                    }
                }
            }
            total=0;   //重新设置为0
            //判断垂直方向,x不变
            if(y-winCount+1 <= 0) {
                begin=0;
            }else {
                begin=y-winCount+1;
            }if(y+winCount-1 >= n) {
                end = n-1;
            }else {
                end=y+winCount-1;
            }
            for (var i = begin;i<=end;i++) {
                //如果当前棋子是计算机统计的个数,如果是棋子是用户就统计2的个数
                if(isComputer) {
                    if(qipan[x][i] == 1) {
                        total++;
                        if(total >= 5) {
                            alert("计算机获胜!");
                            location.reload(); 
                        }
                    }else {
                        total=0;
                    }
                }else {
                    if(qipan[x][i] == 2) {
                        total++;
                        if(total >= 5) {
                            alert("选手获胜!");
                            location.reload();
                        }
                    }else {
                        total=0;  //重新计算
                    }
                }
            }
            total=0;
            //左上角到右下角,x,y都要变
            var tx=x;  //保存当前棋子的x位置
            var ty=y;  //保存当前棋子的y位置
            var xBegin,xEnd;
            var yBegin,yEnd;
            //确定开始位置,X往左移动,y往上移动
            if(tx==0||ty==0) {
                xBegin=tx;
                yBegin=ty;
            }else {
                for(var i=0;i1;i++) {  //5子连胜就循环4次
                    tx--;
                    ty--;
                    if(tx==0||ty==0) {
                        break;
                    }
                    xBegin=tx;
                    yBegin=ty;
                }
            }
                //重新回到当前点击棋子的位置
                tx=x;
                ty=y;
                //确认结束位置,x向右移动,y向下移动
                if(tx==n-1 || ty==n-1){
                    xEnd=tx;
                    yEnd=ty;
                }else {
                    for (var i=0;i1;i++) {
                        tx++;
                        ty++;
                        if(tx==n-1||ty==n-1)
                        break;
                    }
                    xEnd=tx;
                    yEnd=ty;
                }
                for (var i=xBegin,j=yBegin;i//如果。。
                    if(isComputer){
                        if(qipan[i][j]==1) {
                            total++;
                            if(total>=5) {
                                alert("计算机获胜");
                                location.reload();
                            }
                        }else {
                            if(qipan[x][i] == 2) {
                            total++;
                        if(total >= 5) {
                            alert("选手获胜!");
                            location.reload();
                        }
                    }else {
                        total=0;  //重新计算
                        }
                    }
                }
            }
                    total=0;
                    tx=x;
                    ty=y;
                    if(tx==n-1 || ty==0) {
                        xBegin=tx;
                        yBegin=ty;
                    }else {
                        for (var i =0;i1;i++) {
                            tx++;
                            ty--;
                            if(tx==n-1 || ty ==0)
                            break;
                        }
                        xBegin=tx;
                        yBegin=ty;
                    }
                    tx=x;
                    ty=y;
                    if(tx==0||ty==n-1) {
                        xEnd=tx;
                        yEnd=ty;
                    }else{
                        for (var i=0;i1;i++) {
                            tx--;
                            ty++;
                            if(tx==0||ty==n-1)
                            break;
                        }
                        xEnd=tx;
                        yEnd=ty;
                    }
                    for(var i=xBegin,j=yBegin;i>=xEnd;i--,j++) {
                        if(isComputer) {
                            if(qipan[i][j]==1) {
                                total++;
                                if(total>=5){
                                    alert("计算机获胜");
                                    location.reload();
                                }
                    }else {
                        total=0;
                    }
                }else{
                    if(qipan[i][j]==2){
                        total++;
                        if(total>=5){
                            alert("选手获胜");
                            location.reload();
                        }
                    }else{
                        total=0;
                    }
                }
            }
                    if(total<5) {
                        //没有人获胜
                        if(isComputer){
                            isComputer=false;
                        }else {
                            isComputer=true;
                        }
                    }

                //制作背景音乐
                function contronlMusic(){
                    var music=document.getElementById("backmusic");
                    if(music.paused){
                        music.play();
                    }else {
                        music.pause();
                    }
                }
    script>
    <style>
        body{
            background: black;color: red;font-weight: bold;
        }
        table{
            border-collapse: collapse;
        }       
        td{
            border: 2px solid black;height: 26px;width: 286px;background: #f89d1b;
        }
        div{
            position: absolute;
        }
        .cur{
            border: 2.2px solid red;
        }
        p{
            position: absolute;bottom: 10px; color: orange;
        }
    style>
head>
<body>
    <center>
        <h2>五子棋对人机,计算机先下(黑子)h2>
        <button onclick="contronlMusic();">播放/暂停button>
    center>
    <div>div>
    <p>
        初级版版-计算机智能极其低下
    p>
    <audio id="backmusic" autoplay="autoplay" loop="loop">
        <source src="music.aac" type="audio/ogg">source>
        你的浏览器不支持audio标签
    audio>
    <audio id="dianji">
        <source src="beep.mp3" type="audio/ogg">source>
        你的浏览器不支持audio标签
    audio>

body>
html>




这里贴一下链接代码实现的效果:
实现五子棋html AI+普通结合_第4张图片

实现五子棋html AI+普通结合_第5张图片
代码:github代码链接

云盘也给一个吧:百度云盘
链接:https://pan.baidu.com/s/1o8gN5Ke 密码:y0k3

感谢大佬的指点:http://www.cnblogs.com/zhaoyu1995/p/5639101.html
http://blog.csdn.net/show_me_the_world/article/details/48884841

你可能感兴趣的:(JavaScript)