制作五子棋AI

· · 个人记录

关于本文:

这是本蒟蒻的第一篇博客,介绍了我5升6暑假用一周时间做的作品

语言: Html5, JavaScript

成品:五子棋AI

正文:

摘要:

阿尔法狗对战柯洁围棋大赛很热门,那只是人工智能中的一个方向,展示了机器能代替人做某些事情。而围棋是很讲究智力的游戏,所以实现起来也是很难的,我用JS写了一个小程序——五子棋,五子棋相对来讲简单很多。

关键词

人工智能;网页编程;HTML5/JavaScript;

制作背景

现在,人工智能技术突飞猛进,许多职业已被机器取代,那么怎样用简单的算法实现五子棋ai呢?

制作材料

电脑

设计思路

制作过程:

第一步:写H5框架:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Wu Zi Qi--AI</title>
        <style type="text/css">
        </style>
    </head>
    <body>
        <script type="text/javascript">

        </script>
    </body>
</html>

第二步:

本程序主要使用canvas检测鼠标点击返回 值来进行落子,创建canvas对象:

document.body.innerHTML = '<canvas id="chess" width="450" height="450"> </canvas>';
var chess = document.getElementById('chess');

第三步:

创建赢法数组,统计数组等

//赢法数组,用来统计所有的赢法
var wins = [];
var count = 0;
//赢法统计数组,用来统计
var myWin = [];
var computerWin = [];

第四步:

创建并初始化数组显示棋盘

var chessBoard = [];
//数组显示棋盘
            for (var i = 0; i < 15; i++) {
                chessBoard[i] = [];
                for (var j = 0; j < 15; j++) {
                    chessBoard[i][j] = 0;
                }

第五步:

画棋盘

var context = chess.getContext('2d');
//画棋盘
            for (var i = 0; i < 15; i++) {
                context.strokeStyle = '#00000';//设置颜色
                context.beginPath();
                context.moveTo(15, 15 + i * 30);//移动
                context.lineTo(435, 15 + i * 30);//绘画

                context.moveTo(15 + i * 30, 15);//移动
                context.lineTo(15 + i * 30, 435);//绘画
                context.stroke();
            }

第六步:

对赢法数组进行初始化和赋值

//初始化赢法数组同初始化显示棋盘数组,省略
            //横向
            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++;
                }
            }
//纵向,左斜和右斜以此类推

第七步:

初始化玩家和ai数组(略

第八步:

画棋子,为了使棋子更加逼真,可以在棋子的脚上加一点渐变色,比如黑色棋子的右上角有白色渐变,从而模仿真实棋子反光(图一)。同时获取鼠标点击的位置,进行落子。

最后检查玩家获胜(即五子相连)

//画棋子
            chess.onclick = function(e) {
//鼠标点击容差再30以内(只要点击范围在以交叉点为中心的30*30的正方形状内,都算该交叉点)
                var i = Math.floor(e.offsetX / 30);
                var j = Math.floor(e.offsetY / 30);

                if (chessBoard[i][j] != 0) {
                    return;
                }

                context.beginPath();
                context.arc(15 + i * 30, 15 + j * 30, 13, 0, 2 * Math.PI);
                var grd = context.createRadialGradient(15 + i * 30, 15 + j * 30, 13, 15 + i * 30 + 2, 15 + j * 30 - 2, 0);
                grd.addColorStop(0, 'black');
                grd.addColorStop(1, 'white');
                context.fillStyle = grd;
                context.fill();
                context.stroke();

                chessBoard[i][j] = 1;
                //检查玩家获胜
                for (var k = 0; k < count; k++) {
                    if (wins[i][j][k]) {
                        myWin[k]++;
                    }
//如果玩家赢了,则弹出警告框显示 you win!
                    if (myWin[k] == 5) {
                        alert("you win!");
                    }

                }
//调用ai算法
                setTimeout("computerAI()",5000);
            }

第九步:

这是本程序最核心的部分--ai算法。

这里主要是运用了二维数组进行存储每个点上的危险指数,比如玩家在中心位置下了一颗棋子,那么ai就会对这个棋子周围一圈通过计算,加上相对应的值。例:图二,玩家为黑方,控制台中第六行第八列(经过反转处理)为黑子的落子点,周围对应的点加上了对应的值。

那么现在可以分两种ai,一种是进攻类,一种是防守类,两者的区别在于ai的分数和玩家的分数加的多少。

1.进攻类ai

//ai 算法
            function computerAI() {
                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++) {
//for循环嵌套,遍历棋盘
                        if (chessBoard[i][j] == 0) {
                            for (var k = 0; k < count; k++) {
                                if (wins[i][j][k]) {
                                    switch(myWin[k]) {
                                        case 1:
                                            myScore[i][j] += 10;
                                            break;  
case 2:
                                            myScore[i][j] += 200;
                                            break;
                                        //case 3和4只是增加的分数不同,略
                                    }
//ai加分大于myscore,故为攻击型,即case 1中加的分数>10,略
//判断落子点
                            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;
                                }
                            }
                            //后看进攻(与防守类似,略
                                }
                            }
                        }
                    }
                }

2.防守型

防守型为myscore加分大于ai,故为防守型(代码大致相似,略)

第十步:

画白色棋子,检查ai获胜(与玩家代码相似,略)

最终效果图:

[作者简介]

X3B0A1,女,北京市昌平区中山实验学校

主要研究方向:人工智能,c++、python、HTML5/JavaScript

参考资料:   
[1]JavaScript - 人工智能 五子棋AI篇
https://edu.csdn.net/course/detail/8660?
[2]五子棋AI设计心得
https://zhuanlan.zhihu.com/p/42811904
[3]jS实现五子棋——AI篇
https://www.jianshu.com/p/83fa8cc31a38
[4]jS实现五子棋——UI篇
https://www.jianshu.com/p/b178be0fbec3

欢迎各位大佬提出意见awa

本蒟蒻目前只会这样一种方法,有其他思路的欢迎提供嘿嘿。