首页 > 其他 > 详细

俄罗斯方块

时间:2021-03-07 21:51:31      阅读:43      评论:0      收藏:0      [点我收藏+]

设计一个人工智能俄罗斯方块,让其可自行进行游戏。

在手动基础上增加AI, 主要是运用了El-Tetris 算法的特征点。

   // 在每一列中尝试放置当前图形
static void tryPlace(GamingArea gamingArea, Shape shape, Map<Double, Move> moveMap) {
for (int col = 0; col < gamingArea.getAreaWidth() - shape.getWidth() + 1; col++) {
int x = col;
int y = gamingArea.getDropHeight(shape, x);
Move move = new Move();
move.x = x;
move.y = y;
move.shape = shape;
gamingArea.undo();
int result = gamingArea.place(shape, x, y);
// 成功放置
if (result <= GamingArea.ROW_FULL) {
// 表示当前方块放置之后的高度。
int landingHeight = gamingArea.getLandingHeight(col, shape);
// 表示方块放置之后,消行层数与当前方块贡献出的方格数乘积
int rowsEliminated = gamingArea.getRowsEliminated(shape, x);
// 表示当前方块落下后被消减的行数。
int rowsTransition = gamingArea.getRowsTransition();
// 代表容器中水平方向上变换的次数。
int columnTransition = gamingArea.getColumnTransition();
// 代表方块放置之后,空洞的个数
int numOfHoles = gamingArea.getNumberOfHoles();
// 方块放置后,""深的"连加和" 每个结果都是累加
int wellSum = gamingArea.getWellSum();

double score = calcScore(landingHeight, rowsEliminated, rowsTransition, columnTransition, numOfHoles, wellSum);
move.score = score;
moveMap.put(score, move);
}
}
gamingArea.undo();
}


// 根据El-Tetris 算法的特征点,计算分数
static double calcScore(int landingHeight, int rowsEliminated, int rowsTransition, int columnTransition, int numOfHoles, int wellSum) {
return (-4.500158825082766 * landingHeight) +
(3.4181268101392694 * rowsEliminated) +
(-3.2178882868487753 * rowsTransition) +
(-9.348695305445199 * columnTransition) +
(-7.899265427351652 * numOfHoles) +
(-3.3855972247263626 * wellSum);
}

这是AI能运行的重要组成部分。

 

 

/*
AI
*/

// 放置之后的高度
public int getLandingHeight(int col, Shape shape) {
return getColumnHeight(col) - shape.getHeight() / 2;
}

// 放置后,消行层数与当前方块贡献出的方格数乘积
public int getRowsEliminated(Shape shape, int col) {
// 计算消除的行数
int rowsCleared = 0;
for (int row = 0; row < getMaxHeight(); row++) {
if (isFilledCol(row)) {
++rowsCleared;
}
}

// 当前方块贡献的方格数
int cout = 0;
for (int i = 0; i < shape.getPoints().length; i++) {
if (shape.getPoints()[i].y < rowsCleared) {
cout++;
}
}
return rowsCleared * cout;
}

// 方块放置后,水平向上方块的变换次数
public int getRowsTransition() {
int rowsTransition = 0;

for (int row = 0; row < height; row++) {
for (int col = -1; col < width; col++) {
if (isFilled(col, row) ^ isFilled(col + 1, row)) {
rowsTransition++;
}
}
}
return rowsTransition;
}

// 方块放置后,垂直向上方块的变换次数
public int getColumnTransition() {
int columnTransition = 0;
for (int col = 0; col < width; col++) {
for (int row = -1; row < height; row++) {
if (isFilled(col, row) ^ isFilled(col, row + 1)) {
columnTransition++;
}
}
}
return columnTransition;
}

// 空洞的个数
public int getNumberOfHoles() {
int numOfHoles = 0;
for (int col = 0; col < width; col++) {
boolean isHole = false;
int colH = getColumnHeight(col);
for (int row = -1; row < colH; row++) {
if (!isFilled(col, row)) {
isHole = true;
} else {
if (isHole) {
numOfHoles++;
}
isHole = false;
}
}
}
return numOfHoles;
}

//
public int getWellSum() {
List<Integer> wellsH = new ArrayList<>();

for (int col = 0; col < width; col++) {
int wellH = 0;
for (int row = 0; row < height; row++) {
if (!isFilled(col, row)) {
if (isFilled(col - 1, row) && isFilled(col + 1, row)) {
wellH++;
}
} else {
if (wellH > 0) {
wellsH.add(wellH);
wellH = 0;
}
}
}
}

int wellSum = 0;
for (int h : wellsH) {
for (int i = 1; i <= h; i++) {
wellSum += i;
}
}
return wellSum;
}



计算游戏界面砖块如何放置的算法。

还有利用测试尽量找出程序BUG
例如 这是在测试图形的宽度是否符合我们心中的预期
Test
public void geHightTest(){
assertEquals(4,i.getHeight());
assertEquals(3,l.getHeight());
assertEquals(3,j.getHeight());
assertEquals(2,s.getHeight());
assertEquals(2,z.getHeight());
assertEquals(2,o.getHeight());
assertEquals(2,t.getHeight());
assertEquals(1,shape_1.getHeight());
assertEquals(2,shape_2.getHeight());
assertEquals(2,shape_3.getHeight());
assertEquals(3,shape_5.getHeight());
assertEquals(4,shape_6.getHeight());
}


 

俄罗斯方块

原文:https://www.cnblogs.com/Ga7l/p/14496056.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!