俄罗斯方块游戏自动机

《用electron制造俄罗斯方块游戏》 后续文章,智能顺序玩俄罗斯方块游戏。

背景

前不久用ES6完成了基础的俄罗斯方块游戏,本日已完成了一个开端的智能算法,能够自动玩俄罗斯方块了,让本身的主意朝完成更近了一步。

效果图

第一次运转,消除了1398行,窃喜!最高纪录3676行。

《俄罗斯方块游戏自动机》

顺序构造

重要关注智能算法,构造简朴化,悉数放在了index.js中。

用定时器驱动游戏

function autoPlayClick(){
    isAutoPlay = document.getElementById('autoPlay').checked;
    if(isAutoPlay){
        clearInterval(interval)
        interval = setInterval( autoTick, 1 );        //自动算法进口
    }else{
        clearInterval(interval)
        interval = setInterval( tick, TICKVAL );      //自动着落进口
    }
    document.getElementById('speedShow').focus();
}

变量定义

模仿手动操纵,一个方块分三步走:扭转、左或右移、着落究竟。

const MOVEOPS = ['moveLeft','moveRight']                //左、右挪动定义
var opList = [], bestEva;                               //待操纵行列

class Opration{                                         //操纵细节
    constructor(op,num){                    
        this.op = op;                                   //操纵方法
        this.num = num;                                 //操纵次数
    }
}

class Evaluation{                                      //局势评价函数效果定义
    constructor(r,x,eva){
        this.r = r;                                    //扭转次数
        this.x = x;                                    //方块程度位置
        this.eva = eva;                                //评价效果
    }
}

智能算法调理

function autoTick(){
    if(opList.length == 0){                            //上个方块已处理完毕
        getStrategy();                                 //战略算法,天生下一个方块的操纵方法战略序列
    }else{
        let op = opList.shift();                       //取操纵方法
        for(let i=0; i<op.num; i++){                   //实行既定战略
            tetris[op.op]();
            if(op.op == 'moveDown')                    //是着落操纵,取下一块方块
                generateNext();
        }
    }
}

战略算法

这是算法中心,肯定每一块方块的操纵方法。

function getStrategy(){
    let max = 0;                                        //存最优评价值
    tetris.erase();
    let tmp = new Tetris(tetris.shape,tetris.ctx,tetris.x,tetris.y,'rgb(1,1,1,1)','rgb(111,111,111)')                                                //天生用于测试的方块
    for(let i = 0; i < 4; i++){                        //让测试方块与实在方块保持一致,由于我的每一个方块天生时都举行了随机次数的扭转
        for(let j = 0; j < 4; j++){
            tmp.data[i][j] = tetris.data[i][j];  
        }
    }
    for(let r = 0; r < 4; r++){                    //每一个方块,扭转四次,离别举行局势评价
        tmp.erase();
        tmp.x = tetris.x;
        tmp.y = tetris.y;
        if(r > 0)
            tmp.rotate();
        while(tmp.moveLeft());                                //从最左测试到右
        while(tmp.moveDown());                                //着落究竟
        while(rightOver(tmp)){                                //到右完毕这一形状的评价
            let score = evaluate(tmp);                        //局势评价
            if(score > max){                                  //保留最优效果
                max = score;
                bestEva = new Evaluation(r,tmp.x,max)
            }
            if(!tmp.moveRight()){                            //右移失利
                if(!tmp.moveUp()){                           //上移,绕过停滞
                    max = 1000;                              //上移失利,申明填补了朴陋,方块就放这
                    bestEva = new Evaluation(r,tmp.x,max)
                    break;
                }
            }else{
                while(tmp.moveDown());                      //右移胜利后着落究竟
            }
        }
        let score = evaluate(tmp);                          //末了一个位置
        if(score > max){
            max = score;
            bestEva = new Evaluation(r,tmp.x,max)
        }
    }
    tmp.erase();
    // console.log(max)

    opList.push(new Opration('rotate',bestEva.r));        //扭转操纵
    let moveAct = bestEva.x - tetris.x > 0 ? 1 : 0;       //程度位置差转化成左或右移操纵
    let actNum = Math.abs(bestEva.x - tetris.x)
    opList.push(new Opration(MOVEOPS[moveAct],actNum));   //左或右移操纵
    opList.push(new Opration('moveDown',1));              //着落操纵

}

评价函数

如今只做了几个基础参数评价,有待优化。更深切的做法是到场机械进修算法,举行自立反应进修。

function evaluate(t){
    let ct = t.y;                                                            //调试越大越好
    for(let i = 0; i < 4; i++){                                              //检察每一个小方块的四个邻人的状况
        for(let j = 0; j < 4; j++){
            if(t.data[i][j]){
                if(t.canSee(t.x +i, t.y + j + 1))                            //下方是朴陋
                    ct -= 5;
                for(let k=0; k<4; k++){
                    switch(k){
                        case 0: ct += t.canSee(t.x + i + 1, t.y + j) ? 0 : 1;   //右
                        break;
                        case 1: ct += t.canSee(t.x + i - 1, t.y + j) ? 0 : 1;   //左
                        break;
                        case 2: ct += t.canSee(t.x + i, t.y + j + 1) ? 0 : 1;   //下
                        break;
                        case 3: ct += t.canSee(t.x + i, t.y + j - 1) ? 0 : 1;   //上
                        break;
                    }
                }
            }
        }
    }
    return ct;
}

源代码

git clone https://git.oschina.net/zhoutk/Tetris.git

或许:

git clone https://github.com/zhoutk/Tetris

小结

开启了我的智能算法进修之路,这还只是一个最简朴的自动顺序,都谈不上任何智能,但对我来说是一个新方向的最先,加油!

    原文作者:zhoutk
    原文地址: https://segmentfault.com/a/1190000005590120
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞