你的位置:首页 > Java教程

[Java教程]俄罗斯方块游戏自动机


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

背景

前不久用ES6完成了基本的俄罗斯方块游戏,今天已经完成了一个初步的智能算法,可以自动玩俄罗斯方块了,让自己的想法朝实现更近了一步。

效果图

第一次运行,消除了1398行,窃喜!

程序结构

主要关注智能算法,结构简单化,全部放在了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

小结

开启了我的智能算法学习之路,这还只是一个最简单的自动程序,都谈不上任何智能,但对我来说是一个新方向的开始,加油!