[转载]俄罗斯方块AI源码!
看了确实不错。所以转载过来了。虽然是JAVA的,好在还能看懂一些。
想要运行此代码的把最后两个函数内容清空即可(为防盗版,源码已改过)
/* 俄罗斯方块人工智能版 */
/* 作者:wzb32 */
/* Copyright(C) 2007.11 - 2007.12 */
/*导入类包*/
import java.awt.*;
import java.applet.*;
import java.awt.event .*;
/*创建一个从Applet派生并实现Runnable和ItemListener接口的用于被浏览器加载的类*/
public class WzbEluosi extends Applet implements Runnable,ItemListener
{
final int GameStart = 0; //游戏开始状态
final int GameGoing = 1; //游戏进行状态
final int GameStop = 2; //游戏暂停状态
final int GameAuto = 3; //游戏自动打状态
int gamestate = GameStart; //定义游戏初始状态
private Image bgImage; //这里声明bgImage和bg两个实例变量用来存储后台图画
private Graphics bg; //目的是为了采用双缓冲机制来解决屏幕的闪烁现象
int width = 12; //定义游戏一行的格子数
int height = 20; //定义游戏一列的格子数
int frameX = 150; //定义程序框架打印到屏幕上的x坐标
int frameY = 30; //定义程序框架打印到屏幕上的y坐标
int frameSize = 20; //定义程序框架的大小
int[][] map = new int[31][38]; //定义一个储存布局的点阵数据的二维数组
int x, y; //方块的坐标
int type, shape; //当前方块的类型和形态
int typeNext, shapeNext; //下一个方块的类型和形态
int level; //等级,包含方块下落速度和方块自动上移的速度
int scoreLevel; //分数与等级的联系
long score; //记录分数
int fallTime; //方块下落一格的时间
String ordinaryEasy; //根据用户选择的难度判断方块是否自动上升的变量
int blockUpTime; //定义方块自动整体上移一格的时间
byte upStyle; //定义方块上移的两种方式
int xBest; //当前方块的最佳下落的x坐标
int xBest2; //下一个方块的最佳下落x坐标
int shapeBest, shapeBest2; //当前方块和下个一个方块的最佳形态
int xblockDownMove,yblockDownMove; //当前方块在下落完成后移动的最佳坐标
int xblockDownMove2,yblockDownMove2; //当前方块在下落完成后移动的最佳坐标
int xAutoMoveTime; //方块的自动移动一次的时间
int autoSwitch; //自动移动的类型转换
int bug; //一个郁闷了我很久的bug,熬了个通宵都没解决,感觉特莫名其妙,在做了多个测试之后,经过反复的思想斗争,最终用了一个不
负责的方法解决了T_T
final Color []colors =
{Color.white,Color.red,Color.blue,Color.green,Color.magenta,Color.orange,Color.pink,Color.cyan,Color.darkGray};//颜色数组
final byte [][][][]block = //定义一个四维数组储存七种方块类型和方块四种形态的数据,一个方块存储在一个4*4正方形容器里
{
{
{{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}}, //形态1 ■
{{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,1,1,1}}, //形态2 ■
{{1,0,0,0},{1,0,0,0},{1,0,0,0},{1,0,0,0}}, //形态3 ■
{{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,1,1,1}} //形态4 ■
}
,
{
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{1,1,0,0}}, //形态1
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{1,1,0,0}}, //形态2 ■■
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{1,1,0,0}}, //形态3 ■■
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{1,1,0,0}} //形态4
}
,
{
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{0,1,1,0}}, //形态1
{{0,0,0,0},{0,1,0,0},{1,1,0,0},{1,0,0,0}}, //形态2 ■■
{{0,0,0,0},{0,0,0,0},{1,1,0,0},{0,1,1,0}}, //形态3 ■■
{{0,0,0,0},{0,1,0,0},{1,1,0,0},{1,0,0,0}} //形态4
}
,
{
{{0,0,0,0},{0,0,0,0},{0,1,1,0},{1,1,0,0}}, //形态1
{{0,0,0,0},{1,0,0,0},{1,1,0,0},{0,1,0,0}}, //形态2 ■■
{{0,0,0,0},{0,0,0,0},{0,1,1,0},{1,1,0,0}}, //形态3 ■■
{{0,0,0,0},{1,0,0,0},{1,1,0,0},{0,1,0,0}} //形态4
}
,
{
{{0,0,0,0},{0,0,0,0},{1,0,0,0},{1,1,1,0}}, //形态1
{{0,0,0,0},{1,1,0,0},{1,0,0,0},{1,0,0,0}}, //形态2 ■
{{0,0,0,0},{0,0,0,0},{1,1,1,0},{0,0,1,0}}, //形态3 ■■■
{{0,0,0,0},{0,1,0,0},{0,1,0,0},{1,1,0,0}} //形态4
}
,
{
{{0,0,0,0},{0,0,0,0},{0,0,1,0},{1,1,1,0}}, //形态1
{{0,0,0,0},{1,0,0,0},{1,0,0,0},{1,1,0,0}}, //形态2 ■
{{0,0,0,0},{0,0,0,0},{1,1,1,0},{1,0,0,0}}, //形态3 ■■■
{{0,0,0,0},{1,1,0,0},{0,1,0,0},{0,1,0,0}} //形态4
}
,
{
{{0,0,0,0},{0,0,0,0},{1,1,1,0},{0,1,0,0}}, //形态1
{{0,0,0,0},{0,1,0,0},{1,1,0,0},{0,1,0,0}}, //形态2 ■■■
{{0,0,0,0},{0,0,0,0},{0,1,0,0},{1,1,1,0}}, //形态3 ■
{{0,0,0,0},{1,0,0,0},{1,1,0,0},{1,0,0,0}} //形态4
}
};
/*程序首次启动时首先自动调用的用于初始化的函数*/
public void init()
{
reNew(); //初始化数据
modeSelect(); //游戏开始前让用户选择模式
bgImage = createImage(this.getSize().width, this.getSize().height); //新建一个后台图像类变量
bg = bgImage.getGraphics(); //得到当前图像的图形关联
}
/*定义初始化数据的函数*/
public void reNew()
{
blockUpTime = 0; //初始化方块上移时间
score = 0; //初始化分数
scoreLevel = 0;
upStyle = (byte) (Math.random() * 2); //随机给upStyle赋一个小于2的正整数值
for (int j=0; j<height+4; j++) //初始化屏幕布局数据
for (int i=0; i<width; i++)
map[j][i] = 0;
typeNext = (int) (Math.random() * 7); //初始化下一个方块类型
shapeNext = (int) (Math.random() * 4); //初始化下一个方块的形态
nextBlockUpdate(); //更新下一个方块数据
}
/*游戏开始前模式选择的函数*/
public void modeSelect()
{
final Choice c = new Choice(); //定义一个下拉列表对象
final CheckboxGroup cbg = new CheckboxGroup(); //定义一个单选按钮组对象
final Checkbox cb3 = new Checkbox("困难",true,cbg); //定义单选按钮对象1
final Checkbox cb1 = new Checkbox("简单",true,cbg); //定义单选按钮对象1
final Checkbox cb2 = new Checkbox("普通",false,cbg); //定义单选按钮对象2
final Button bt1 = new Button("开始游戏"); //定义一个按钮对象1
final Button bt2 = new Button(" 暂停 "); //定义一个按钮对象2
final Button bt3 = new Button("高手汪汪狗表演"); //定义一个按钮对象3
final TextField tf1 = new TextField(String.valueOf(width),1); //定义文本编辑区对象1
final TextField tf2 = new TextField(String.valueOf(height),1); //定义文本编辑区对象2
final TextField tf3 = new TextField(String.valueOf(frameX),1); //定义文本编辑区对象3
final TextField tf4 = new TextField(String.valueOf(frameY),1); //定义文本编辑区对象4
final TextField tf5 = new TextField(String.valueOf(frameSize),1); //定义文本编辑区对象5
Label lb1=new Label("行列格数"); //定义标签1
Label lb2=new Label("框架坐标和大小"); //定义标签2
tf1.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){}}); //监听文本编辑区1的对象
tf2.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){}}); //监听文本编辑区2的对象
tf3.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){}}); //监听文本编辑区3的对象
tf4.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){}}); //监听文本编辑区4的对象
tf5.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){}}); //监听文本编辑区5的对象
c.add ("等级一"); //加入列表对象
c.add ("等级二");
c.add ("等级三");
c.add ("等级四");
c.add ("等级五");
c.add ("等级六");
c.add ("等级七");
c.add ("等级八");
c.add ("等级九");
c.addItemListener(new ItemListener() //建立下拉列表对象的监听者
{
public void itemStateChanged(ItemEvent e)
{
level = c.getSelectedIndex() + 1; //获得用户选择的等级
scoreLevel = 0;
remove(c);remove(cb1);remove(cb2);remove(cb3);remove(bt1);remove(bt2);remove(bt3);//删除全部列表和按钮,再加入
全部列表和按钮
remove(tf1);remove(tf2);remove(tf3);remove(tf4);remove(tf5);
add(bt1);add(cb1);add(cb2);add(cb3);add(c);add(bt2);add(bt3);//作用是避免无法控制方块,,我测试了N次才解决这个
问题,当时郁闷了我N久,笨死
add(tf1);add(tf2);add(tf3);add(tf4);add(tf5);
}
});
cb1.addItemListener(new ItemListener() //建立单选按钮1对象的监听者
{
public void itemStateChanged(ItemEvent e) //按下单选按钮1时产生事件
{
ordinaryEasy = cbg.getSelectedCheckbox().getLabel(); //获得用户选择的难度
remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(bt2); remove(bt3); //删除全部列表和按钮
add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(bt2); add(bt3); //加入全部列表和按钮
}
});
cb2.addItemListener(new ItemListener() //建立单选按钮2对象的监听者
{
public void itemStateChanged(ItemEvent e) //按下单选按钮2时产生事件
{
ordinaryEasy = cbg.getSelectedCheckbox().getLabel(); //获得用户选择的难度
remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(bt2); remove(bt2); //删除全部列表和按
钮
add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(bt2); add(bt3); //加入全部列表和按钮
}
});
cb3.addItemListener(new ItemListener() //建立单选按钮3对象的监听者
{
public void itemStateChanged(ItemEvent e) //按下单选按钮3时产生事件
{
ordinaryEasy = cbg.getSelectedCheckbox().getLabel(); //获得用户选择的难度
remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(bt2); remove(bt2); //删除全部列表和按
钮
add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(bt2); add(bt3); //加入全部列表和按钮
}
});
add(c); //将下拉列表加入容器
add(cb1); //将单选按钮1加入容器
add(cb2); //将单选按钮2加入容器
add(cb3); //将单选按钮3加入容器
add(bt1); //将按钮1加入容器
add(bt2); //将按钮2加入容器
add(bt3); //将按钮3加入容器
add(lb1); //将标签1加入容器
add(tf1); //将文本编辑区1加入容器
add(tf2); //将文本编辑区2加入容器
add(lb2); //将标签2加入容器
add(tf3); //将文本编辑区3加入容器
add(tf4); //将文本编辑区4加入容器
add(tf5); //将文本编辑区5加入容器
bt1.addActionListener(new ActionListener() //建立按钮1对象的监听者
{
public void actionPerformed(ActionEvent e) //当用户按下按钮1产生的事件,是个内部类
{
level = c.getSelectedIndex() + 1; //获得用户选择的等级
ordinaryEasy = cbg.getSelectedCheckbox().getLabel(); //获得用户选择的难度
try //抛出一个异常
{
width = Integer.parseInt(tf1.getText()); //得到文本编辑区1里的内容并赋给width
height = Integer.parseInt(tf2.getText()); //得到文本编辑区2里的内容并赋给height
frameX = Integer.parseInt(tf3.getText()); //得到文本编辑区3里的内容并赋给frameX
frameY = Integer.parseInt(tf4.getText()); //得到文本编辑区4里的内容并赋给frameY
frameSize = Integer.parseInt(tf5.getText()); //得到文本编辑区5里的内容并赋给frameSize
}
catch (Exception e2) //捕获异常
{
}
width = width < 5 ? 5 : width > 38 ? 38 : width; //限定width的范围
height = height < 5 ? 5 : height > 27 ? 27 : height; //限定height的范围
remove(bt2); remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(tf1); remove(bt3); //删除
全部列表和按钮
add(bt2); add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(tf1); add(bt3); //加入全部列表和按钮
reNew(); //初始化所有数据
gamestate = GameGoing; //让游戏状态为进行中
bt2.setLabel(" 暂停 ");
bt3.setLabel("高手汪汪狗表演");
}
});
bt2.addActionListener(new ActionListener() //建立按钮2对象的监听者
{
public void actionPerformed(ActionEvent e) //当用户按下按钮2产生的事件,是个内部类
{
if (gamestate == GameGoing || gamestate == GameAuto)
{
bt2.setLabel(" 继续 "); //设置按钮名称
bt3.setLabel("高手汪汪狗表演");
gamestate = GameStop; //设置游戏状态为暂停
}
else
if (gamestate == GameStop)
{
bt2.setLabel(" 暂停 "); //设置按钮名称
gamestate = GameGoing; //设置游戏状态为进行中
}
remove(bt2); remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(bt3); //删除全部列表和按钮
add(bt2); add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(bt3); //加入全部列表和按钮
}
});
bt3.addActionListener(new ActionListener() //建立按钮3对象的监听者
{
public void actionPerformed(ActionEvent e) //当用户按下按钮3产生的事件,是个内部类
{
if (gamestate == GameStart || gamestate == GameGoing)
{
bt3.setLabel("我是菜鸟我怕谁"); //设置按钮名称
autoSwitch = 0;
autoPlayCurrent(); //计算当前方块的最佳下落方法和坐标
gamestate = GameAuto; //设置游戏状态为自动
}
else
if (gamestate == GameAuto)
{
bt3.setLabel("高手汪汪狗表演"); //设置按钮名称
gamestate = GameGoing; //设置游戏状态为进行中
}
remove(bt3); remove(bt1); remove(cb1); remove(cb2); remove(cb3); remove(c); remove(bt2); //删除全部列表和按钮
add(bt3); add(bt1); add(cb1); add(cb2); add(cb3); add(c); add(bt2); //加入全部列表和按钮
}
});
}
public void itemStateChanged(ItemEvent e) //覆盖ItemListener接口中的抽象函数,抽象的函数必须要重新定义
{
}
/*程序调用init()之后自动调用这个函数*/
public void start()
{
Thread th = new Thread(this); //定义一个新的线程,控制方块下落
th.start(); //启动此线程
}
/*创建线程对象的实例时自动调用的一个抽象函数*/
public void run()
{
final int[] speed = {300000,300000,250000,150000,100000,80000,50000,20000,7000,0};
while (true) //设置个死循环
{
switch (gamestate) //根据游戏状态选择分支程序运行
{
case GameAuto :
if (((width > 20 || height < 6) && level == 9) || ordinaryEasy == "困难" || level == 9)
{
x = xBest;
shape = shapeBest;
}
if (xAutoMoveTime >= speed[level])
{
if (x < xBest) x++; //方块水平移动到最佳下落x坐标
if (x > xBest) x--;
if (shape != shapeBest) //方块变换成最佳形态
{
shape++;
if (shape == 4)
shape = 0;
}
xAutoMoveTime = 0;
}
if (xblockDownMove != xBest && y == yblockDownMove)
{
x = xblockDownMove; //方块下落完成时移动到最佳x坐标
}
xAutoMoveTime++; //方块自动移动时间自增
case GameGoing :
try //抛出一个异常
{ //暂停方块下落线程在一个等待时间内,这里是1ms
Thread.sleep(1); //这里必须要让线程暂停一下,不然autoPlay()方法的调用会对程序运行的速度影响非常大,暂停一
下又没有影响了
} //反正感觉莫名其妙,估计是线程时间片的问题吧,当时郁闷了我N久N久啊,苯死我拉,啊啊,不过后来又莫名其妙的解决了,
我真是个天才,哈哈
catch (Exception e) //捕获异常
{
}
if (ordinaryEasy == "普通" || ordinaryEasy == "困难") blockUpTime++; //方块自动上移时间自增
if (gamestate == GameAuto && x == xBest && shape == shapeBest)
{
int z = level < 9 ? 8 : 9;
if (fallTime > speed[z]) fallBlock(); //调用方块下落方法
}
else
if (fallTime > speed[level]) fallBlock(); //调用方块下落方法
fallTime++; //方块下落时间自增
repaint(); //刷新屏幕
break;
case GameStop :
break;
}
}
}
/*在Applet界面上进行相应的绘画动作的函数*/
public void paint(Graphics g)
{
bg.clearRect(0,0,getSize().width,getSize().height);
drawInfo(bg); //将程序的框架和基本信息存储到后台
if(gamestate == GameGoing || gamestate == GameStop || gamestate == GameAuto)
{
drawBlock(bg); //在后台绘制方块
drawNextBlock(bg); //在后台绘制下一个方块
}
g.drawImage(bgImage, 0, 0, this); //将后台存储的图画打印到屏幕上来
}
/*调用repaint()方法时自动调用此函数,因为原此函数会清屏,造成屏幕闪烁,所以要重写此函数*/
public void update(Graphics g)
{
paint(g); //调用paint方法
}
/*定义打印程序的框架和基本信息的函数*/
public void drawInfo(Graphics g)
{
if (scoreLevel > 9999) //计算等级
{
level++;
scoreLevel -= 10000;
}
if (level > 9) level = 9; //限定等级范围
g.setColor(Color.black); //设置颜色
g.drawRect(frameX-1, frameY-1, frameSize*width+1, frameSize*height+1); //绘制界面大方框
g.drawString("NEXT", frameX+frameSize*(width+1), frameY+25);
g.drawRect(frameX+frameSize*(width+1), frameY+25, 80, 80); //绘制显示下一个方块的方框
g.drawString("LEVEL", frameX+frameSize*(width+1), frameY+125);
g.drawRect(frameX+frameSize*(width+1), frameY+125, 80, 20); //绘制显示等级的方框
g.drawString(String.valueOf(level), frameX+frameSize*(width+1)+1, frameY+141); //绘制等级
g.drawString("SCORE", frameX+frameSize*(width+1), frameY+165);
g.drawRect(frameX+frameSize*(width+1), frameY+165, 80, 20); //绘制显示分数的方框
g.drawString(String.valueOf(score), frameX+frameSize*(width+1)+1, frameY+181); //绘制分数
g.drawString("操作:↑↓←→", frameX+frameSize*(width+1), frameY+250);
g.drawString("暂停:P", frameX+frameSize*(width+1), frameY+270);
g.drawString("作者:wzb32", frameX+frameSize*(width+1), frameY+305);
g.drawString("QQ:103168834", frameX+frameSize*(width+1), frameY+325);
g.drawString("Email:wzb32@qq.com
g.drawString("版本:v1.00", frameX+frameSize*(width+1), frameY+365);
g.drawString("Copyright(C) 2007.11 - 2007.12", frameX+frameSize*(width+1), frameY+385);
for (int j=4; j<height+4; j++) //绘制所有静止的方块
for (int i=0; i<width; i++)
if (map[j][i] != 0) //判断屏幕布局方阵上的这个位子的数据是否为0
{
g.setColor(colors[map[j][i]]); //设置颜色
g.fill3DRect(frameX+i*frameSize, frameY+j*frameSize-4*frameSize, frameSize, frameSize, true); //画2个小小
方块,组成个小方块
g.fill3DRect(frameX+i*frameSize+1, frameY+j*frameSize+1-4*frameSize, frameSize-2, frameSize-2, true);
}
}
/*定义绘制方块的函数,一个方块由16个小方块组成,一个小方块由2个小小方块组成*/
public void drawBlock(Graphics g)
{
if (bug == 1) return; //不负责的处理掉一个让人莫名其妙的bug,怒
for (int j=0; j<4; j++)
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1 && y+j > 3) //判断此格是否要绘制一个小小方块
{
g.setColor(colors[type+1]); //设定方块颜色
g.fill3DRect(frameX+x*frameSize+i*frameSize, frameY+y*frameSize+j*frameSize-4*frameSize, frameSize,
frameSize, true);
g.fill3DRect(frameX+x*frameSize+i*frameSize+1, frameY+y*frameSize+j*frameSize+1-4*frameSize, frameSize-2,
frameSize-2, true);
}
}
}
}
/*定义方块下落的函数*/
public void fallBlock()
{
if (!moveFit(x, y+1)) //判断方块将向下移动的一格是否能移动
{
fallOver(); //下落完成
if(ordinaryEasy == "困难")
{
if (blockUpTime > 3000000) blockAllUp(); //方块整体自动上移一格
}
else
if (blockUpTime > 6999999) blockAllUp(); //普通模式的方块自动上移
}
y++; //方块下落一格
fallTime=0;
}
/*定义方块下落完成的函数*/
public void fallOver()
{
for (int j=0; j<4; j++)
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是否有小小方块
{
map[y+j][x+i] = type + 1; //将当前方块的坐标数据存储到布局的点阵里
if (y + j < 5) gamestate = GameStart; //方块超出上界,游戏结束
}
}
}
if(gamestate == GameStart)
{
y--;
return;
}
RemoveRow(); //调用消行函数
if (gamestate == GameAuto)
{
switch (autoSwitch)
{
case 0:
type = typeNext; //将下一个方块类型覆盖当前方块类型
shape = shapeNext; //将下一个方块形态覆盖当前方块形态
x = width / 2 - 1; //初始化方块的坐标
y = 0;
autoPlayCurrent(); //计算当前方块的最佳下落方法
typeNext = type;
shapeNext = shape;
shapeBest2 = shapeBest;
xBest2 = xBest;
xblockDownMove2 = xblockDownMove;
yblockDownMove2 = yblockDownMove;
autoPlayNext(); //计算下一个方块的最佳下落方法
autoSwitch++;
break;
case 1:
shapeBest = shapeBest2;
xBest = xBest2;
xblockDownMove = xblockDownMove2;
yblockDownMove = yblockDownMove2;
nextBlockUpdate(); //更新下一个方块的数据
autoSwitch = 0;
break;
}
}
else
nextBlockUpdate(); //刷新下一个方块的数据
}
/*定义绘制下一个方块的函数*/
public void drawNextBlock(Graphics g)
{
g.setColor(colors[typeNext+1]);
for (int j=0; j<4; j++)
{
for (int i=0; i<4; i++)
{
if (block[typeNext][shapeNext][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是否有小方
块
{
g.fill3DRect(frameX+i*16+frameSize*(width+1)+9, frameY+j*16+29, 16, 16, true);
g.fill3DRect(frameX+i*16+frameSize*(width+1)+10, frameY+j*16+30, 14, 14, true);
}
}
}
}
/*更新下一个方块数据的函数*/
public void nextBlockUpdate()
{
type = typeNext; //将下一个方块类型覆盖当前方块类型
shape = shapeNext; //将下一个方块形态覆盖当前方块形态
typeNext = (int) (Math.random() * 7); //初始化下一个方块类型
shapeNext = (int) (Math.random() * 4); //初始化下一个方块形态
x = width / 2 - 1; //初始化方块的坐标
y = 0;
}
/*判断方块下一步的移动是否可行的函数*/
public boolean moveFit(int xmove, int ymove)
{
for (int j=0; j<4; j++)
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是否有小小方块
{
if (xmove + i < 0 || xmove+i > width - 1 || ymove < 0 || ymove+j > height + 3 || (map[ymove+j][xmove+i]
!= 0))
return false; //不能移动
}
}
}
return true; //能移动
}
/*定义消行的函数*/
public void RemoveRow()
{
int rowSmallBlockNum; //定义一个保存当行已有多少的方块的变量
int reMoveRowNum = 0; //定义一个保存一次共消去多少行的变量
int sc[] = {0,100,300,700,1200}; //定义一个存储分数的数组
for(int j=0; j<4; j++)
{
rowSmallBlockNum = 0;
for (int i=0; i<width; i++)
{
if (map[y+j][i] != 0) //判断地图布局上的此格是否有小方块
rowSmallBlockNum++;
if (rowSmallBlockNum == width) //判断当行格子是否填满了
{
reMoveRowNum++;
for (int jj=y+j; jj>1; jj--)
{
for (int ii=0; ii<width; ii++)
{
map[jj][ii] = map[jj-1][ii]; //把要消去的行的上面所有行的数据向下移动一行
}
}
}
}
}
score += sc[reMoveRowNum]; //根据一次消去几个行的情况而加相应的分数
scoreLevel += sc[reMoveRowNum]; //等级和分数关系
}
/*定义响应键盘的函数*/
public boolean keyDown(Event e, int key)
{
switch (gamestate) //根据游戏状态选择分支程序运行
{
case GameGoing : //游戏进行状态下的分支
if (key == Event.DOWN) //判断是否按下下键
{
fallBlock(); //调用方块下落方法
}
if (key == Event.LEFT) //判断是否按下左键
{
x = moveFit(x-1,y) ? --x : x; //根据周围有没有其它方块或墙壁来判断能否左移
}
if (key == Event.RIGHT) //判断是否按下右键
{
x = moveFit(x+1,y) ? ++x : x; //根据周围有没有其它方块或墙壁来判断能否右移
}
if (key == Event.UP) //判断是否按下上键
{
shapeChange(); //调用方块变形的方法
}
if (key == 'p' || key == 'P') //判断是否按下P键
{
gamestate = GameStop; //设置游戏状态为暂停
}
repaint(); //刷新屏幕
break;
case GameStop : //游戏暂停状态下的分支
if (key == 'p' || key == 'P')
{
gamestate = GameGoing; //设置游戏状态为进行
}
break;
}
return true;
}
/*定义方块变形的函数*/
public void shapeChange()
{
shape++; //方块变形
if (shape == 4) shape = 0; //一个四种形态,变到第五种的时候又变回第一种形态
if (moveFit(x,y)) //根据周围有没有其它方块或墙壁来判断能否变形
{
shape--;
if (shape == -1) shape = 3;
shape++;
if (shape == 4) shape = 0;
}
else
{
shape--; //不能变形,所以把第一行程序变了的形态又变回来
if (shape == -1) shape = 3;
}
}
/*定义方块自动上移的函数*/
public void blockAllUp()
{
upStyle = (byte) (upStyle == 1 ? 0 : 1); //有两种上移方式,变换方式
for (int j=1; j<height+4; j++) //所有方块上移一格
for (int i=0; i<width; i++)
map[j-1][i] = map[j][i];
for (int i=0; i<width; i+=2) //创造底部一行方块
{
map[height+3][i] = (upStyle == 1 ? 0 : 8);
map[height+3][i+1] = (upStyle == 1 ? 8 : 0);
}
blockUpTime = 0; //重置上移的时间
}
/*计算下一个方块的最佳下落方法*/
public void autoPlayNext()
{
int typeCopy = typeNext;
int shapeCopy = shapeNext;
int shapeBestCopy = shapeBest2;
int xCopy, yCopy, xMoveMin, xMoveMax;
int xCopyCopy;
int xMoveMinDown,xMoveMaxDown; //方块下落完成后的最佳坐标
int rowSmallBlockNum, reMoveRowNum; //定义保存当行已有多少的方块的变量和保存一次共消去多少行的变量
int topRowThis = 0, topRowAll; //当行高度和局面的最大高度
int emptyBlockNum; //压在方块下的空格子数目
int valueMax = 0; //当前局面的评估值
int mapCopy[][]=new int [height+4][width]; //声明2个数组保存不同时间局面的数据
int mapCopy2[][]=new int [height+4][width];
int[] aRam = {54, 11, 32, 53, 44, 51, 65, 0, 13, 25, 31, 42, 57, 63,55};
bug = 1; //bug开始发生
for (int i=0; i<width; i++) //保存当前局面
for (int j=0; j<height+4; j++)
mapCopy[j][i] = map[j][i];
type = typeNext;
shape = shapeBest2;
xBest = xBest2;
xblockDownMove = xblockDownMove2;
yblockDownMove = yblockDownMove2;
if (xblockDownMove != xBest) //模拟方块下落
{
x = xblockDownMove;
y = yblockDownMove;
}
else
{
x = xBest;
for (; moveFit(x, y+1); y++){}
}
for (int j=0; j<4; j++) //保存模拟方块下落后的局面
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是否有小小方块
{
map[y+j][x+i] = 9; //将当前方块的坐标数据存储到布局的点阵里
}
}
}
for (int j=0; j<4; j++) //模拟消行
{
rowSmallBlockNum = 0;
for (int i=0; i<width; i++)
{
if (map[y+j][i] != 0) //判断地图布局上的此格是否有小方块
rowSmallBlockNum++;
if (rowSmallBlockNum == width) //判断当行格子是否填满了
{
for (int jj=y+j; jj>1; jj--)
{
for (int ii=0; ii<width; ii++)
{
map[jj][ii] = map[jj-1][ii]; //把要消去的行的上面所有行的数据向下移动一行
}
}
}
}
}
for (int i=0; i<width; i++) //保存当前局面
for (int j=0; j<height+4; j++)
mapCopy2[j][i] = map[j][i];
boolean hasEmptyBlock = false;
for (int i=0; i<width; i++) //计算局面的高度
{
for (topRowThis=0;topRowThis<height+4;topRowThis++)
{
if (map[topRowThis][i] != 0)
{
break;
}
}
if (topRowThis < height + 3) //计算有多少个空格子
{
for (int j=topRowThis+1; j<height+4; j++)
{
if (map[j][i] == 0) //这儿是一个压在方块下的空的格子
{
hasEmptyBlock = true;
break;
}
}
}
if (hasEmptyBlock) break;
}
for (int iii = (int) (Math.random() * aRa), jjj=0; jjj<adWan; iii++, jjj++)
{
type=typeRam[iii];
for (shape=0; shape<4; shape++)
{
for(xCopy = width/2-1; moveFit(xCopy+1,0); xCopy++){} //计算方块的最大水平位移
xMoveMax = xCopy;
for (xCopy=0; xCopy<=xMoveMax; xCopy++) //模拟方块的水平移动
{
for (yCopy=0; moveFit(xCopy, yCopy+1); yCopy++){} //模拟方块下落
xCopyCopy=xCopy;
for(; moveFit(xCopy-1, yCopy); xCopy--){} //模拟方块在底部的移动
xMoveMinDown = xCopy;
for(; moveFit(xCopy+1, yCopy); xCopy++){}
xMoveMaxDown = xCopy;
for (xCopy=xMoveMinDown; xCopy<=xMoveMaxDown; xCopy++)
{
int yy=yCopy;
for(;moveFit(xCopy,yy);yy--)
{
}
if (yy < 1 && xCopy != xCopyCopy) continue;
for (int j=0; j<4; j++) //保存模拟后的局面
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是
否有小小方块
{
map[yCopy+j][xCopy+i] = 9; //将当前方块的坐标数据存储到布局的点阵里
}
}
}
reMoveRowNum = 0; //模拟消行
for (int j=0; j<4; j++)
{
rowSmallBlockNum = 0;
for (int i=0; i<width; i++)
{
if (map[yCopy+j][i] != 0) //判断地图布局上的此格是否有小方块
rowSmallBlockNum++;
if (rowSmallBlockNum == width) //判断当行格子是否填满了
{
reMoveRowNum++;
}
}
}
topRowAll = 999;
emptyBlockNum = 0;
for (int i=0; i<width; i++) //计算局面高度
{
for (topRowThis=0;topRowThis<height+4;topRowThis++)
{
if (map[topRowThis][i] != 0)
{
break;
}
}
if (topRowThis < height + 3) //计算空格子
{
for (int j=topRowThis+1; j<height+4; j++)
{
if (map[j][i] == 0) //这儿是一个压在方块下的空的格子
{
emptyBlockNum++;
}
}
}
if (topRowThis < topRowAll)
topRowAll = topRowThis;
}
topRowAll += reMoveRowNum;
if(type == 0 && topRowAll > 5) emptyBlockNum=999;
//根据当前情况采取不同的进攻或防守策略
if (ordinaryEasy != "困难" && xCopy == xMoveMax && !hasEmptyBlock && topRowAll > 7 && reMoveRowNum <
3) emptyBlockNum=999;
if (topRowAll*aRam[as] + reMoveRowNum*aRam[zc] - emptyBlockNum*aRam[da] + yCopy > valueMax) //当前局面的评估方程
{
valueMax = topRowAll*aRam[as] + reMoveRowNum*aRam[zc] - emptyBlockNum*aRam[da] + yCopy;
if (xCopyCopy == xCopy) //保存到当前最佳的下落方法的数据
{
xBest2 = xCopy;
}
else
{
xBest2 = xCopyCopy;
yblockDownMove2 = yCopy;
}
shapeBest2 = shape;
xblockDownMove2 = xCopy;
}
for (int i=0; i<width; i++) //恢复局面数据
for (int j=0; j<height+4; j++)
map[j][i] = mapCopy2[j][i];
}
xCopy= xCopyCopy;
}
}
}
for (int i=0; i<width; i++) //恢复局面数据
for (int j=0; j<height+4; j++)
map[j][i] = mapCopy[j][i];
type = typeCopy;
shape = shapeCopy;
shapeNext = (int) (Math.random() * 4); //初始化下一个方块形态
shapeBest = shapeBestCopy;
x = width / 2 - 1; //初始化方块的坐标*/
y = 0;
bug = 0; //bug结束
}
/*计算当前方块的最佳下落方法*/
public void autoPlayCurrent()
{
int typeCopy = type;
int shapeCopy = shape;
int xCopy, yCopy, xMoveMin, xMoveMax;
int xCopyCopy;
int xMoveMinDown,xMoveMaxDown;
int rowSmallBlockNum, reMoveRowNum; //定义保存当行已有多少的方块的变量和保存一次共消去多少行的变量
int topRowThis = 0, topRowAll;
int emptyBlockNum;
int valueMax = 0;
yblockDownMove=0;
boolean hasEmptyBlock = false;
for (int i=0; i<width; i++) //计算空格子数目
{
for (topRowThis=0;topRowThis<height+4;topRowThis++)
{
if (map[topRowThis][i] != 0) break;
}
if (topRowThis < height + 3)
{
for (int j=topRowThis+1; j<height+4; j++)
{
if (map[j][i] == 0) //这儿是一个压在方块下的空的格子
{
hasEmptyBlock = true;
break;
}
}
}
if (hasEmptyBlock) break;
}
for (shape=0; shape<4; shape++)
{
for(xCopy = x; moveFit(xCopy-1,y); xCopy--){} //计算方块的移动范围
xMoveMin = xCopy;
for(xCopy = x; moveFit(xCopy+1,y); xCopy++){}
xMoveMax = xCopy;
for (xCopy=xMoveMin; xCopy<=xMoveMax; xCopy++) //模拟方块的水平移动
{
for (yCopy=y; moveFit(xCopy,yCopy+1); yCopy++) //模拟方块下移
{
}
xCopyCopy=xCopy;
for(; moveFit(xCopy-1,yCopy); xCopy--){} //计算方块在底部的移动范围
xMoveMinDown = xCopy;
for(; moveFit(xCopy+1,yCopy); xCopy++){}
xMoveMaxDown = xCopy;
for (xCopy=xMoveMinDown; xCopy<=xMoveMaxDown; xCopy++) //模拟方块在底部的水平移动
{
int yy=yCopy;
for(;moveFit(xCopy,yy);yy--) //模拟方块上移
{
}
if (yy < 1 && xCopy != xCopyCopy) continue;
for (int j=0; j<4; j++)
{
for (int i=0; i<4; i++)
{
if (block[type][shape][j][i] == 1) //一个方块存储在一个4*4正方形容器里,判断容器里这个位子是否有
小小方块
{
map[yCopy+j][xCopy+i] = 9; //将当前方块的坐标数据存储到布局的点阵里
}
}
}
reMoveRowNum = 0;
for (int j=0; j<4; j++) //计算当前下落方法可以消多少行
{
rowSmallBlockNum = 0;
for (int i=0; i<width; i++)
{
if (map[yCopy+j][i] != 0) //判断地图布局上的此格是否有小方块
rowSmallBlockNum++;
if (rowSmallBlockNum == width) //判断当行格子是否填满了
{
reMoveRowNum++; //消去的行数自增
}
}
}
topRowAll = 999;
emptyBlockNum = 0;
for (int i=0; i<width; i++) //计算局面高度
{
for (topRowThis=0;topRowThis<height+4;topRowThis++)
{
if (map[topRowThis][i] != 0)
{
break;
}
}
if (topRowThis < height + 3) //计算空格子数
{
for (int j=topRowThis+1; j<height+4; j++)
{
if (map[j][i] == 0) //这儿是一个压在方块下的空的格子
emptyBlockNum++;
}
}
if (topRowThis < topRowAll)
topRowAll = topRowThis;
}
topRowAll += reMoveRowNum;
//根据当前情况采取不同的进攻或防守策略
if (ordinaryEasy != "困难" && xCopy == xMoveMax && !hasEmptyBlock && topRowAll > 7 && reMoveRowNum < 3)
emptyBlockNum=999;
if (topRowAll*aRam[as] + reMoveRowNum*aRam[ws] - emptyBlockNum*aRam[cx] + yCopy > valueMax) //当前局面的评估方程
{
valueMax = topRowAll*aRam[as] + reMoveRowNum*aRam[ws] - emptyBlockNum*aRam[cx] + yCopy;
if (xCopyCopy == xCopy) //保存当前方块的最佳下落方法的数据
{
xBest = xCopy;
}
else
{
xBest = xCopyCopy;
yblockDownMove = yCopy;
}
xblockDownMove = xCopy;
shapeBest = shape;
}
for (int j=0; j<4; j++) //把刚才储存到布局里的点全部去除
for (int i=0; i<4; i++)
if (block[type][shape][j][i] == 1)
map[yCopy+j][xCopy+i] = 0;
}
xCopy= xCopyCopy;
}
}
type = typeCopy;
shape = shapeCopy;
}
}