javascript 实现五子棋人机PK

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        #box1 table{
            border: 0px;
            border-collapse: collapse;
            cursor: pointer;
        }

        #box1 th {
            border: 0px;
            border-collapse: collapse;
            cursor: pointer;
        }

         #box1 td{
            border: 1px solid #000;
            border-collapse: collapse;
            cursor: pointer;
         }


        #box2 table{
            border-collapse: collapse;
            border: 0px;
        }

        #box2 th {
            border-collapse: collapse;
            border: 0px;
        }

        #box2 td{
            border-collapse: collapse;
            border: 1px solid transparent;
            border-radius:20px;
        }

       .color_human{
         background-color: white;
       }

       .color_machine{
         background-color: black;
       }

        #box1{
           position: absolute;
           left: 100px;
           top: 100px;
           border: 0px;
           background-color: gray;
       }

        #box2{
           position: absolute;
           left: 110px;
           top: 110px;
           border: 0px;
       }

    </style>
</head>
<body>
<div id="box1">
</div>

<div id="box2">
</div>

</body>
<script type="text/javascript">
    var map_code_td = new Map();
    var map_code_color = new Map();
    var map_code_score = new Map();
    var win = false;
    var color_human = "color_human";
    var color_machine = "color_machine"

    // 辅助帮助显示横竖纹的底色棋盘,没有任何事件和业务逻辑
    function initBox1( ) {
        var table = document.createElement("table");
        // table.border = 1 ;
        table.rules  = 'all' ;
        for (var rowNum = 1; rowNum <= 15; rowNum++) {
            var tr = document.createElement("tr");
            for (var colNum = 1; colNum <= 15; colNum++) {
                var td = document.createElement("td");
                td.width = 20;
                td.height = 20;
                tr.appendChild(td);
            }
            table.appendChild(tr);
        }
        document.getElementById( "box1" ).appendChild(table);
    }

    function initBox2( ) {
        var table = document.createElement("table");
        // table.border = 1 ;
        table.rules  = 'all' ;
        for (var rowNum = 1; rowNum <= 15; rowNum++) {
            var tr = document.createElement("tr");
            for (var colNum = 1; colNum <= 15; colNum++) {
                var td = document.createElement("td");
                td.width = 20;
                td.height = 20;
                tr.appendChild(td);

                var code = rowNum + "_" + colNum;
                map_code_td.set( code,td );
                map_code_color.set( code,"white" );
            }
            table.appendChild(tr);
        }
        document.getElementById( "box2" ).appendChild(table);
        table.addEventListener( "click", clickChess );
    }

    initBox1(  );
    initBox2(  );

    // 获取到点击的 td,如果该人类落子,则将td的颜色改为 人类棋子颜色,否则该机器落子,将颜色改为机器棋子颜色
    var shouldHumanPoint = true;
    function clickChess(){
        if( win ){
            return;
        }
        if( !shouldHumanPoint ){
            alert("稍等,机器落子后您再落子!");
            return;
        }
        var td = event.srcElement;

        // todo 判断该格子是否已经落过子
        var className = td.className;
        if( className == color_machine || className==color_human ){
            alert( "该位置已落子" );
            return;
        }
        var rowNum = td.parentElement.rowIndex + 1;
        var colNum = td.cellIndex + 1;
        var code = rowNum + "_" + colNum;
        var td = map_code_td.get( code );
        // console.log( rowNum+"行" +colNum+ "列");
        td.className = color_human;
        map_code_color.set( code,color_human );
        shouldHumanPoint = false;
        // 人类落子后检测是否胜利
        winCheck();
        if( win ){
            alert("人类胜利");
            return;
        }

         window.setTimeout(function(){
            // 机器开始落子
            machinePoint();
            // 机器落子后检测是否胜利
            winCheck();
            if( win ){
                alert("机器胜利");
                return;
            }
        },5000);
    }

    function machinePoint(){
        // 机器开始落子,需要找到一个得分最高的格子开始落子
        // 从下面 15*15 格子中找到得分最高的一个格子
        var maxScore = 0;
        var rowNum_maxScore = 0;
        var colNum_maxScore = 0;
        for( var rowNum=1;rowNum<=15;rowNum++ ){
            for( var colNum=1;colNum<=15;colNum++ ){
                // todo 如果该位置已经落子了,则不考虑
                var code = rowNum + "_" + colNum;
                var color = map_code_color.get( code );
                if( color == color_human || color == color_machine ){
                    continue;
                }
                var score = calculateScore( rowNum, colNum );
                if( score > maxScore ){
                    maxScore = score;
                    rowNum_maxScore = rowNum;
                    colNum_maxScore = colNum;
                }
            }
        }

        console.log( "机器应该落在" + rowNum_maxScore + "行" + colNum_maxScore + "列,得分:" + maxScore );
        var code = rowNum_maxScore + "_" + colNum_maxScore;
        var td = map_code_td.get( code );
        td.className = color_machine;
        map_code_color.set( code,color_machine );
        shouldHumanPoint = true;
    }

    // 得分表,该程序的精髓,其实本程序未使用任何算法,只是使用了这个得分表,写这个得分表的人比较厉害,程序厉不厉害也是取决于得分表设计的精不精妙
    function calculateScoreForForHumanMachineColorCount( count_humanColor,count_machineColor){
        if( count_humanColor > 0 && count_machineColor > 0 ){
            return 0;
        }else if( count_humanColor == 0 && count_machineColor == 0 ){
            return 7;
        }else if( count_humanColor == 0 && count_machineColor == 1 ){
            return 35;
        }else if( count_humanColor == 0 && count_machineColor == 2 ){
            return 800;
        }else if( count_humanColor == 0 && count_machineColor == 3 ){
            return 15000;
        }else if( count_humanColor == 0 && count_machineColor == 4 ){
            return 800000;
        }else if( count_humanColor == 1 && count_machineColor == 0 ){
            return 15;
        }else if( count_humanColor == 2 && count_machineColor == 0 ){
            return 400;
        }else if( count_humanColor == 3 && count_machineColor == 0 ){
            return 1800;
        }else if( count_humanColor == 4 && count_machineColor == 0 ){
            return 100000;
        }else{
            return 0;
        }
    }

    // 为该五连子计算得分
    function calculateScoreFor5Point( code1,code2,code3,code4,code5 ){
        var color1 = map_code_color.get( code1 );
        var color2 = map_code_color.get( code2 );
        var color3 = map_code_color.get( code3 );
        var color4 = map_code_color.get( code4 );
        var color5 = map_code_color.get( code5 );

        if( color1 && color2 && color3 && color4 && color5 ){
            // 计算人类棋子颜色和机器棋子颜色的个数
            var count_humanColor = 0;
            var count_machineColor = 0;

            if( color1 ==color_human ){
                count_humanColor++;
            }else if( color1 == color_machine ){
                count_machineColor++;
            }
            if( color2 ==color_human ){
                count_humanColor++;
            }else if( color2 == color_machine ){
                count_machineColor++;
            }
            if( color3 ==color_human ){
                count_humanColor++;
            }else if( color3 == color_machine ){
                count_machineColor++;
            }
            if( color4 ==color_human ){
                count_humanColor++;
            }else if( color4 == color_machine ){
                count_machineColor++;
            }
            if( color5 ==color_human ){
                count_humanColor++;
            }else if( color5 == color_machine ){
                count_machineColor++;
            }
            return calculateScoreForForHumanMachineColorCount( count_humanColor, count_machineColor );
        }else{
            // 不是一个合法的无连子,可能超出边界了
            return 0;
        }
    }

    function calculateScore(rowNum, colNum){
        var totalScore = 0;
        // 该格子所在行( 左-->右:行不变,列++ )
        // 统计该格子作为第1、2、3、4、5个子时候的五连子的得分之和
        for( var i=0; i<5; i++){
            var code1 = rowNum + "_" + ( colNum + 0 - i );//  0、-1、-2、-3、-4
            var code2 = rowNum + "_" + ( colNum + 1 - i );//  1、0、-1、-2、-3
            var code3 = rowNum + "_" + ( colNum + 2 - i );//  2、1、0、-2、-2
            var code4 = rowNum + "_" + ( colNum + 3 - i );//  3、2、1、0、-1
            var code5 = rowNum + "_" + ( colNum + 4 - i );//  4、3、2、1、0
            totalScore += calculateScoreFor5Point( code1, code2, code3, code4, code5 );
        }

        // 该格子所在列( 上->下:行++,列不变 )
        // 统计该格子作为第1、2、3、4、5个子时候的五连子的得分之和
        for( var i=0; i<5; i++){
            code1 = ( rowNum + 0 - i ) + "_" + colNum; // 0、-1、-2、-3、-4
            code2 = ( rowNum + 1 - i ) + "_" + colNum; // 1、0、-1、-2、-3
            code3 = ( rowNum + 2 - i ) + "_" + colNum; // 2、1、0、-1、-2
            code4 = ( rowNum + 3 - i ) + "_" + colNum; // 3、2、1、0、-1
            code5 = ( rowNum + 4 - i ) + "_" + colNum; // 4、3、2、1、0
            totalScore += calculateScoreFor5Point( code1, code2, code3, code4, code5 );
        }

        // 该格子所在正斜线( 左下-->右上:行--,列++ )
        // 统计该格子作为第1、2、3、4、5个子时候的五连子的得分之和
        for( var i=0; i<5; i++){
            code1 = ( rowNum + i - 0 ) + "_" + ( colNum + 0 - i );
            code2 = ( rowNum + i - 1 ) + "_" + ( colNum + 1 - i );
            code3 = ( rowNum + i - 2 ) + "_" + ( colNum + 2 - i );
            code4 = ( rowNum + i - 3 ) + "_" + ( colNum + 3 - i );
            code5 = ( rowNum + i - 4 ) + "_" + ( colNum + 4 - i );
            totalScore += calculateScoreFor5Point( code1, code2, code3, code4, code5 );
        }

        // todo 该格子所在反斜线( 左上-->右下:行++,列++ )
        // 统计该格子作为第1、2、3、4、5个子时候的五连子的得分之和
        for( var i=0; i<5; i++){
             code1 = ( rowNum + 0 - i )  + "_" + ( colNum + 0 - i );
             code2 = ( rowNum + 1 - i ) + "_" +  ( colNum + 1 - i );
             code3 = ( rowNum + 2 - i ) + "_" +  ( colNum + 2 - i );
             code4 = ( rowNum + 3 - i ) + "_" +  ( colNum + 3 - i );
             code5 = ( rowNum + 4 - i ) + "_" +  ( colNum + 4 - i );
             totalScore += calculateScoreFor5Point( code1, code2, code3, code4, code5 );
        }
        return totalScore;
    }

    function winCheck(){
        if( win ){
            return;
        }
        // 检查全部的五连子,是否存在五个全是红子或者五个全部蓝子
        // 检查全部列上的五连子
        winCheck_col()
        if( win ){
            return;
        }

        // 检查全部行上的五连子
        winCheck_row();
        if( win ){
            return;
        }

        // 检查全部正斜线上的五连子
        winCheck_zhengxiexian();
        if( win ){
            return;
        }

        // 检查全部反斜线上的五连子
        winCheck_fanxiexian();
        if( win ){
            return;
        }
        //printColors()
    }

    function printColors(){
       for( rowNum=1;rowNum<=15;rowNum++ ){
           var colors_row = "";
           for( colNum=1;colNum<=15;colNum++ ){
                var code = rowNum + "_" + colNum;
                var color = map_code_color.get( code );
                colors_row += color + " ";
           }
           console.log( colors_row );
       }
    }

    function winCheck_zhengxiexian(){
        // 列--,行++
        for( rowNum=1;rowNum<=15;rowNum++ ){
            for( colNum=1;colNum<=15;colNum++ ){
                var code1 = rowNum + "_" + colNum;
                var code2 = ( rowNum + 1 ) + "_" + ( colNum - 1 );
                var code3 = ( rowNum + 2 ) + "_" + ( colNum - 2 );
                var code4 = ( rowNum + 3 ) + "_" + ( colNum - 3 );
                var code5 = ( rowNum + 4 ) + "_" + ( colNum - 4 );
                allSameColorCheck( code1,code2,code3,code4,code5 );
                if( win ){
                    return;
                }
            }
        }
    }

    function winCheck_fanxiexian(){
         // 列++,行++
        for( rowNum=1;rowNum<=15;rowNum++ ){
            for( colNum=1;colNum<=15;colNum++ ){
                var code1 = rowNum + "_" + colNum;
                var code2 = ( rowNum + 1 ) + "_" + ( colNum + 1 );
                var code3 = ( rowNum + 2 ) + "_" + ( colNum + 2 );
                var code4 = ( rowNum + 3 ) + "_" + ( colNum + 3 );
                var code5 = ( rowNum + 4 ) + "_" + ( colNum + 4 );
                allSameColorCheck( code1,code2,code3,code4,code5 );
                if( win ){
                    return;
                }
            }
        }
    }

    function winCheck_col(){
        // 检查全部列是否存在五连子
        // 列不变,行++
        for( var colNum=1;colNum<=15;colNum++ ){
            for( var rowNum=1;rowNum<=15;rowNum++ ){
                var code1 = rowNum + "_" + colNum;
                var code2 = ( rowNum + 1 ) + "_" + colNum;
                var code3 = ( rowNum + 2 ) + "_" + colNum;
                var code4 = ( rowNum + 3 ) + "_" + colNum;
                var code5 = ( rowNum + 4 ) + "_" + colNum;
                allSameColorCheck( code1, code2, code3, code4, code5 );
                if( win ){
                    return;
                }
            }
        }
    }

    function winCheck_row(){
        // 行不变,列++
        for( var rowNum=1;rowNum<=15;rowNum++ ){
            for( var colNum=1;colNum<=15;colNum++ ){
                var code1 = rowNum + "_" + colNum;
                var code2 = rowNum + "_" + ( colNum + 1 );
                var code3 = rowNum + "_" + ( colNum + 2 );
                var code4 = rowNum + "_" + ( colNum + 3 );
                var code5 = rowNum + "_" + ( colNum + 4 );
                allSameColorCheck( code1,code2,code3,code4,code5 );
                if( win ){
                    return;
                }
            }
        }
    }

    function allSameColorCheck( code1,code2,code3,code4,code5 ){
        var color1 = map_code_color.get( code1 );
        var color2 = map_code_color.get( code2 );
        var color3 = map_code_color.get( code3 );
        var color4 = map_code_color.get( code4 );
        var color5 = map_code_color.get( code5 );
        if( isAllHumanColor( color1,color2,color3,color4,color5 ) ){
            // 该五连子全部是 人类棋子颜色
            win = true;
        }else if( isAllMachineColor( color1,color2,color3,color4,color5 ) ){
            // 该五连子全部是 机器棋子颜色
            win = true;
        }
        console.log("win=" + win);
    }

    function isAllHumanColor(color1,color2,color3,color4,color5){
        if( color1 && color2 && color3 && color4 && color5 ){

        }else{
            return false;
        }
        if( color1 ==color_human && color2 ==color_human && color3 ==color_human && color4 ==color_human && color5 ==color_human ){
            return true;
        }
        return false;
    }

    function isAllMachineColor(color1,color2,color3,color4,color5){
        if( color1 && color2 && color3 && color4 && color5 ){

        }else{
            return false;
        }
        if( color1 ==color_machine && color2 ==color_machine && color3 ==color_machine && color4 ==color_machine && color5 ==color_machine ){
            return true;
        }
        return false;
    }
</script>
</html>

效果展示:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值