南京邮电大学
通达学院
算法与数据结构设计报告( 2016/ 2017学年第二学期)
专业软件工程嵌入式
学号姓名
学号姓名
学号姓名
指导教师
指导单位计算机学院计算机科学与技术系
日期2017-5-26
目录
课题内容---------------------------------------1 算法设计与分析---------------------------------1 算法实现---------------------------------------9 测试数据及结果分析----------------------------38 调试过程中的问题------------------------------40 总结------------------------------------------41
俄罗斯方块
一、课题内容
实现俄罗斯方块游戏。主要功能为游戏界面显示、上下左右键响应以及当前得分统计。通过该课题全面熟悉数组、字符串等的使用。掌握设计的基本方法及友好界面的设计。
课题要求:
1、游戏界面显示:下落方块和方块堆、左右移动、旋转、删除行等特效以及得分。
2、动作选择:上下左右键对应于旋转、加速、左右移动的功能。
3、得分统计判断:判定能否消除行、并统计得分总数等。
扩展要求:
1、用户数据管理。
2、游戏玩法:由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。
基本规则
1、一个用于摆放小型正方形的平面虚拟场地,其标准大小:行宽为10,列高为20,以每个小正方形为单位。
2、一组由4个小型正方形组成的规则图形,英文称为Tetromino,中文通称为方块共有7种,分别以S、Z、L、J、I、O、T这7个字母的形状来命名。
I:一次最多消除四层
J(左右):最多消除三层,或消除二层
L:最多消除三层,或消除二层
O:消除一至二层
S(左右):最多二层,容易造成孔洞
Z (左右):最多二层,容易造成孔洞
T:最多二层
(1)部分游戏有单格方块,可以穿透固定的方块到达最下层空位。其他的改版中出现更多特别的造型。
方块会从区域上方开始缓慢继续落下。
(2)玩家可以做的操作有:以90度为单位旋转方块,以格子为单位左右移动方块,让方
块加速落下。
(3)方块移到区域最下方或是着地到其他方块上无法移动时,就会固定在该处,而新的方块出现在区域上方开始落下。
(4)当区域中某一列横向格子全部由方块填满,则该列会消失并成为玩家的得分。同时删除的列数越多,得分指数上升。
(5)当固定的方块堆到区域最上方而无法消除层数时,则游戏结束。
(6)一般来说,游戏还会提示下一个要落下的方块,熟练的玩家会计算到下一个方块,评估要如何进行。由于游戏能不断进行下去对商业用游戏不太理想,所以一般还会随着游戏的进行而加速提高难度。
二、算法设计与分析
I、俄罗斯方块游戏需要解决的问题包括
(1)、随机产生方块并自动下移
(2)键变体
(3)Q退出,按space暂停
II
(1)、声明俄罗斯方块的结构体
(2)、函数原型声明
(3)、制作游戏窗口
(4)、制作俄罗斯方块
(5)、判断是否可动
(6)、随机产生俄罗斯方块类型序号
(7)、判断是否满行并删除满行的俄罗斯方块
(8)暂停,继续功能
(9)新游戏创建
(10)用户的创建,分数用户名的保存,查看分数
类之间的关系
Tetris类(主要类)
该类包含m a i n方法,应为应用程序的主类。该类用来创建游戏的用户界面,事件处理功能和menu餐单,用户信息的存储。整个程序从该类的m a i n方法开始执行。
成员变量:String userName;
构造方法:Tetris
userName=JOptionPane.showInputDialog(null, "输入你的名字");
if(userName==null||userName.equals("")){
userName="无名氏";
}//如果没有命名就定义为无名氏
内部类:Members,Tetrisblock
Tetrisblok类:
用来设计游戏界面。游戏界面显示在由Tetrisblok类创建的整个用户界面的中(Center)区,游戏的即时分数、方块的效果图及方的预览功能都在整个类里面实现。用来封装俄罗斯小方块。一个方块的属性是由方块1位置即x和y的坐标、颜色决定的。
成员变量
private int blockType;
Timer timer=null;
private int turnState;
private int x;
private int y;
private int i = 0;
int j = 0;
static int score = 0;
int flag = 0;
int delay=1000;
// 定义已经放下的方块x=0-12,y=0-22;
int[][] map = new int[14][24];
// 方块的形状第一组代表方块类型有S、Z、L、J、I、O、T 7种第二组代表旋转几次第三四组为方块矩阵
private final int shapes[][][]
成员方法:
public void newblock()
public void drawwall()
public void newmap()
public void newgame()
public void turn();
public void left();
public void right(); public void down() ;
public int blow(int x, int y, int blockType, int turnState);
public void delline() ; public int gameover(int x, int y); public void add(int x, int y, int blockType, int turnState); public void paintComponent(Graphics g); public void keyPressed(KeyEvent e); public void keyTyped(KeyEvent e)
Members类:
用来创建io流,在D盘中查找username.txt文件,如果没有就创建。并且在username 和score中间用:隔开,方便以后用split对其进行分割。
成员变量:
private FileWriter fw=null;
private BufferedWriter bw=null;
private FileReader fr=null;
private BufferedReader br=null;
Tetris tt=null;
boolean vip=true;//如果有usernametxt这个文件的话就返回true并且允许查看分数判断是否有用户已经创建了
ArrayList al=new ArrayList();
成员方法:
getMembers()
saveMembers()
getpaint()
GetMembers()方法
获取username.txt 的File对象
NameScore类:
private String username;
private String score;
public String getUsername() {
public String getUsername() {
public void setUsername(String username) {
public String getScore() {
每一个用户的分数和姓名存到一个对象NameScore类。
ScorePanel类;
Vector col=null;
Vector rol=null;
JTable jt;
public ScorePanel(ArrayList al) throws IOException{
这个是用来接收Tetris类中传递过来的储存NameScore对象的ArrayList集合,然后把用迭代器将集合中的每一个对象的username和score取出来然后放到Vector中。然后添加到JTable中。
三、算法实现
1.0 Tetris类(主要类)
Tetris类功能
该类包含main方法,应为应用程序的主类。该类用来创建游戏的用户界面,事件处理功能和menu餐单,用户信息的存储。整个程序从该类的main方法开始执行。
成员变量:String userName;
构造方法:Tetris
实现在初始化的时候进行弹框如果没有输入值则就将username命名为无名氏
public Tetris() throws IOException{
userName=JOptionPane.showInputDialog(null, "输入你的名字");
if(userName==null||userName.equals("")){
userName="无名氏";
}//如果没有命名就定义为无名氏
final JMenuItem pause;
final JMenuItem goon;
final JMenuItem getscore;
final JMenuItem exit;
final JMenuItem saveexit;
newgame.addActionListener(new ActionListener(){ pause.addActionListener(new ActionListener(){ goon.addActionListener(new ActionListener(){ getscore.addActionListener(new ActionListener(){ exit.addActionListener(new
ActionListener(){
saveexit.addActionListener(new ActionListener(){
high.addActionListener(new ActionListener()
2.Tetrisblok类
Tetrisblok类功能:
用来设计游戏界面。游戏界面显示在由Tetrisblok类创建的整个用户界面的中(Center)区,游戏的即时分数、方块的效果图及方的预览功能都在整个类里面实现。用来封装俄罗斯小方块。实现创建新游戏,暂停,继续并且通过调用members类来实现用户姓名,分数的存储,和记录的读取。
画出俄罗斯方块的形状和变形之后的形状是根据三维数组来的
private final int shapes[][][] = new int[][][] { { 0, 0, 0, 0, 1, 1, 1, 1,
0, 0, 0, 0,
0, 0, 0, 0 },
{ 0, 1, 0, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 1, 0, 0 },
{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 }} 这个只是一种形状和变换之后的形状{………}还有s,z,j,l,t和方形
Newblock()方法
Newblock方法的功能
这个方法是产生一个新的方块,并且判断游戏是否已经结束,如果游戏结束的话就弹出一个提示框并且将Map清零
blockType = (int) (Math.random() * 1000) % 7;
turnState = (int) (Math.random() * 1000) % 4;
x = 4;
y = 0;
if (gameover(x, y) == 1) {
newmap();
drawwall();
score = 0;
JOptionPane.showMessageDialog(null, "GAME OVER");
}
}
Blow方法(判断方块的下一个动作是否合法)
Blow方法功能
for循环出所有4*4表格中的值,每当取到一个1的时候表示这是方块的组成元素之一,map[x+b+z][y+a]表示组成元素之一碰撞到障碍物的时候或者碰撞到墙壁的时候因为墙壁是2。返回1就是合法,返回0就是不合法
public int blow(int x, int y, int blockType, int turnState) { for (int a = 0; a < 4; a++) {
for (int b = 0; b < 4; b++) {
if(((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x + b + 1][y + a] == 1))
|| ((shapes[blockType][turnState][a * 4 + b] == 1) && (map[x + b + 1][y + a] == 2))) {
return 0;
}
}
} return 1;
}
Deline()方法
Deline()方法功能
判断每一行是否满行,满行的话就消行,消行就上让满行的上一行的每一个元素下移一行。
public void delline() {
int c = 0;
for (int b = 0; b < 23; b++) {
for (int a = 0; a < 13; a++) {
if (map[a][b] == 1) {
c = c + 1;
if (c == 11) {
score += 11;
for (int d = b; d > 0; d--) { //这行是上面的那行下
来需要消行上面的那行下来就嫩实现消行
for (int e = 0; e < 12; e++) {
map[e][d] = map[e][d - 1];
}
}
} } }
c = 0;
}
}
paintComponent(Graphics g)方法:
这个方法实现画笔的功能,将当前正在运行的方块和已经存在的画到panel中,并且显示已经得到的分数因为每个方块都是有一个含有16个元素的数组组成所以要从第一个元素开始查找到最后一个,如果有一个元素为1就表示这个位置是一个方块的组成。
同样的固定的方块也是这样画出来的。
super.paintComponent(g);
// 画当前方块
for (j = 0; j < 16; j++) {
if (shapes[blockType][turnState][j] == 1) {
g.fillRect((j % 4 + x + 1) * 15, (j / 4 + y) * 15, 15, 15); }
}
// 画已经固定的方块在这里变成13列 23行
for (j = 0; j < 23; j++) {
for (i = 0; i < 13; i++) {
if (map[i][j] == 1) {
g.fillRect(i * 15, j * 15, 15, 15);
}
if (map[i][j] == 2) {
g.drawRect(i * 15, j * 15, 15, 15);
}
}
}
g.drawString("score=" + score , 200, 10);
// g.drawString("你的名字:"+new Tetris().userName, 200, 30); g.drawString("抵制不良游戏,", 200, 80); g.drawString("拒绝盗版游戏。", 200, 100); g.drawString("注意自我保护,", 200, 120); g.drawString("谨防受骗上当。", 200, 140); g.drawString("适度游戏益脑,", 200, 160); g.drawString("沉迷游戏伤身。", 200, 180); g.drawString("合理安排时间,", 200, 200); g.drawString("享受健康生活。", 200, 220);
}
public void turn(){ public void left(){ public void right(){ public void down(){ add 方法: add 方法的功能:
因为每个方块是由16个元素构成,16个元素又可以构成4行4列。从第一行开始,后面的每一列,如果map 中在正在运行的方块的当前位置的x 坐标+1是一个0的话,也就表示x 的下一个位置不是墙或是已经形成的障碍物就让这个正在运行的方块成为下一个障碍物,也就是Map 数组中对应位置的元素改为1
public void add(int x, int y, int blockType, int turnState) {
int j = 0;
for (int a = 0; a < 4; a++) {
for (int b = 0; b < 4; b++) {
if (map [x + b + 1][y + a] == 0) { map [x + b + 1][y + a] = shapes [blockType][turnState][j]; }; j++; }
}
}
Members类;
这个类主要是用来对用户的名字和的分进行储存,和读取,并且能够创建新的面板(得分
面板)
private FileWriter fw=null;
private BufferedWriter bw=null;
private FileReader fr=null;
private BufferedReader br=null;
Tetris tt=null;
boolean vip=true;/
/如果有usernametxt这个文件的话就返回true并且允许查看分数判断是否有用户已
经创建了
ArrayList al=new ArrayList();
//将每一个用户对象存储到集合中
saveMembers()方法
储存用户信息的方式使用io流在d盘中创建txt的文件,这个方法是创建file对象,
如果d盘中没有txt文件就想创建。将用户信息写在txt文件中并且将username和score
之间用:分开为了之后的方法将他分开。并且在文件存在将FileWriter端口关闭。
public void saveMembers() throws IOException{
String username=userName;//将外部类的username赋值给内部类username Tetrisblok tb=new Tetrisblok();//这是存数据
File file=new File("d:\\username.txt");
if(!file.exists()){
file.createNewFile();
}
// int map[][]=tb.map;
fw=new FileWriter("d:\\username.txt",true);
bw=new BufferedWriter(fw);
// for(int i=0;i// for(int j=0;j