AI—五子棋

1 篇文章 0 订阅

五子棋人机对战

说明:初学AI,对具体的实现算法还不算太懂,这里分享出来,和大家一起学习…

描述:该项目主要通过JS脚本语言实现功能,先绘制棋盘(15×15),再设置点击显示棋子功能,最后设计AI算法实现人机交互。

算法:AI算法这里采用的是最简单的一个,首先创建一个三维数组用于存储所有的赢法(wins[i][j][k]表示在i,j坐标点中的第k种赢法),然后遍历棋盘中每一个点,根据局面情况,计算出各点的落子分值,取最大值的坐标点u,v,即(u,v)为计算机的落子点。玩家每落一子计算一次,直至有一方连成5子。所谓的根据局面情况计算分值是指:每一种赢法中的落子数,落4子的分值>落3子的分值>落2子的分值>落1子的分值>不落子的分值。这个分值也要根据是计算机的落子还是玩家的落子进行区分,例如:机器已落了3子且没有任何阻碍,同样情况下的玩家也是如此,这时轮机器走棋,就应该先顾自己的3子而不是去阻碍玩家的。按照这样一个规则去计算分值,最后取最大值。

好了,说了半天可能听不懂,上代码吧

HTML

Gobang.html
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>AI-五子棋</title>
        <link rel="stylesheet" type="text/css" href="css/Gobang.css" />
    </head>
    <body>
        <canvas id="chess" width="450px" height="450px">
        </canvas>

        <script type="text/javascript" language="JavaScript" src="js/Gobang.js"></script>
    </body>
</html>

CSS

Gobang.css
*{margin: 0; padding: 0;}

canvas{
    display: block;
    margin: 50px auto;
    box-shadow: -2px -2px 2px #EFEFEF, 5px 5px 5px #B9B9B9;
}

JS

Gobang.js
// 获取棋盘
var chess = document.getElementById("chess");
// 画布
var context = chess.getContext("2d");

// 直线颜色
context.strokeStyle = "#BFBFBF";

// 画棋盘
drawChessPlat();

// 轮流执行
var me = true;

// 是否胜利
var over = false;

// 存储棋子
var chessBoard = [];
for (var i=0; i<15; i++) {
    chessBoard[i] = [];
    for (var j=0; j<15; j++) {
        chessBoard[i][j] = 0;
    }
}

// 赢法种类索引
var count = 0;

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

/**
 * 填充赢法数组
 */
// 横线
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++;
    }
}

// 赢法统计数组
var myWin = []
var AIWin = []
for (var i=0; i<count; i++) {
    myWin[i] = 0;
    AIWin[i] = 0;
}

// 棋盘点击事件
chess.onclick = function(e){
    if(over) return;

    if(!me) return;

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

    // 允许落子
    if(chessBoard[i][j]==0){
        oneStep(i, j, me);

        // 黑棋:1,白棋:-1
//      chessBoard[i][j] = me ? 1 : -1;
        chessBoard[i][j] = 1;
//      me = !me;

        // 更新赢法数组
        for(var k=0; k<count; k++){
            if(wins[i][j][k]){
                myWin[k]++;
                AIWin[k] = 6; // 异常情况
                if(myWin[k]==5){
                    alert("You win!");
                    over = true;
                }
            }
        }

        if(!over){
            me = !me;
            AiStep();
        }
    }
}

// AI走棋
function AiStep(){
    // 初始化
    var myScore = [];
    var AiScore = [];
    var max = 0; // 最高点分数
    var u = 0, v = 0; // 最高点分数坐标

    for(var i=0; i<15; i++){
        myScore[i] = [];
        AiScore[i] = [];
        for (var j=0; j<15; j++) {
            myScore[i][j] = 0;
            AiScore[i][j] = 0;
        }
    }

    for (var i=0; i<15; i++) {
        for (var j=0; j<15; j++) {
            if(chessBoard[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(AIWin[k] == 1){
                            AiScore[i][j] += 220;
                        }else if(AIWin[k] == 2){
                            AiScore[i][j] += 420;
                        }else if(AIWin[k] == 3){
                            AiScore[i][j] += 2100;
                        }else if(AIWin[k] == 4){
                            AiScore[i][j] += 20000;
                        }
                    }
                }

                if(myScore[i][j] > max){
                    max = myScore[i][j]
                    u=i; v=j;
                } else if(myScore[i][j] == max){
                    if(AiScore[i][j] > AiScore[u][v]){
                        u=i; v=j;
                    }
                }

                if(AiScore[i][j] > max){
                    max = AiScore[i][j]
                    u=i; v=j;
                } else if(AiScore[i][j] == max){
                    if(myScore[i][j] > myScore[u][v]){
                        u=i; v=j;
                    }
                }
            }
        }
    }

    // 机器走棋
    oneStep(u, v, false);
    chessBoard[u][v] = -1;

    // 更新赢法数组
    for(var k=0; k<count; k++){
        if(wins[u][v][k]){
            AIWin[k]++;
            myWin[k] = 6; // 异常情况
            if(AIWin[k]==5){
                alert("You lose!");
                over = true;
            }
        }
    }

    if(!over){
        me = !me;
    }
}

/**
 * 走棋
 * me --> black
 */
function oneStep(i, j, me){
    context.beginPath();
    // 属性
    context.arc(15+i*30, 15+j*30, 13, 0, 2*Math.PI);
    context.closePath();

    // 棋子颜色渐变
    var gradient = context.createRadialGradient(15+i*30+2, 15+j*30-2, 13, 15+i*30+2, 15+j*30-2, 0);
    if(me){
        gradient.addColorStop(0, "#0A0A0A");
        gradient.addColorStop(1, "#636766");
    }else{
        gradient.addColorStop(0, "#D1D1D1");
        gradient.addColorStop(1, "#F9F9F9");
    }
    // 填充颜色
    context.fillStyle = gradient;
    // 填充
    context.fill();
}

/**
 * 画棋盘
 */
function drawChessPlat(){
    for(var i=0; i<15; i++){

        // 竖线
        context.moveTo(15 + i*30, 15); // 起始位置
        context.lineTo(15 + i*30, 435); // 终止位置
        context.stroke(); // 画直线

        // 横线
        context.moveTo(15, 15 + i*30); // 起始位置
        context.lineTo(435, 15 + i*30); // 终止位置
        context.stroke(); // 画直线
    }
}

这里写图片描述

这里写图片描述

PS:玩家是黑手,计算机是白手。这个算法可以说是最简单的,因此在下的过程中可能会有走棋漏洞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值