二、实现算法
说实在话,算法这东西,我真不适合讨论,只因太菜(默默流泪ing...)。但是既然选择写这么一篇文章,是螺是马都得放出来溜溜。
1.每个滑块是一个Block对象,重写equals和hashCode方法,并在内部处理滑块颜色。总共16个滑块,数字相同的滑块代表的是同一个对象。用SparseArray<Block>保存0-2048对应的Block对象,这样可方便处理操作。以下是Block类代码:
package com.walk.game2048.model;
/**
* 滑块实体类
* @author walk
*
*/
public class Block {
public static final int MAX = 2048;
private int number;
private int color;
public Block(int number) {
super();
this.number = number;
setColor();
}
public int getNumber() {
return number;
}
public int getColor() {
return color;
}
private void setColor () {
switch (number) {
case 0:
color = 0xFFCDC0B5;
break;
case 2:
color = 0xFFEEE4DB;
break;
case 4:
color = 0xFFEDE0C9;
break;
case 8:
color = 0xFFF0B17D;
break;
case 16:
color = 0xFFF39568;
break;
case 32:
color = 0xFFF47C63;
break;
case 64:
color = 0xFFF35F43;
break;
case 128:
color = 0xFFECCB69;
break;
case 256:
color = 0xFFECC75A;
break;
case 512:
color = 0xFFFFAA00;
break;
case 1024:
color = 0xFFFFEE00;
break;
case 2048:
color = 0xFF1100FF;
break;
}
}
@Override
public String toString() {
return "Block [number=" + number + ", color=" + color + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + color;
result = prime * result + number;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Block other = (Block) obj;
if (color != other.color)
return false;
if (number != other.number)
return false;
return true;
}
}
2.玩法操作
首先,这游戏有四个操作,上、下、左、右,四个操作需要处理的方式是一样的。这里只讨论向左滑动。
复杂的算法真心不会,小菜就只能用最普通的了。向左滑动后,同一行的情况下,从左边第一个滑块算起(除掉空的),如果两相邻滑块是相同数字的,就合在一起,并且左边的滑块数字在原来的基础上乘以2,并且这一行的所有滑块会向左填充空块,当然前提是左边有空块。(唉~表达能力实在是不行呀,还是按图说话吧)
操作分两部分完成:
1)、图一,滑块1和滑块2相同(2),可合并成(4)并填充在滑块1的位置,滑块2置为空块。同样的,滑块3、4合并填充在滑块3的位置上,也就是图二;
2)、原滑块2与滑块1合并后,成为空块,所以滑块3要向左填充过来,并把原来的位置置为空块。所以操作的最终效果如图三。
其他三个方向操作也是这样的,只是具体实现的代码有些差异。下面附上小菜实现的代码(求拍砖,求指导~):
//1.合并步骤
//行列,mBlocks是4X4数组,保存的是滑块Block对象
for (int row = 0; row < mBlocks.length; row++) {
for (int column = 0; column < mBlocks[row].length; column++) {
//已经是最后一个元素,结束循环
if (column == mBlocks[row].length - 1) {
break;
}
//mBlockObjArray保存0-2048对应滑块Block对象,其中0代表空块
if (mBlocks[row][column] == mBlockObjArray.get(0)) {
//元素为空块,跳出当前循环
continue;
}
for (int k = column + 1; k < mBlocks[row].length; k++) {
//元素为空块,跳出当前循环
if (mBlocks[row][k] == mBlockObjArray.get(0)) {
continue;
}
if (mBlocks[row][column] == mBlocks[row][k]) {
//相邻有效元素相同,合并,并把后无素置为空块,结束循环
mBlocks[row][column] = mBlockObjArray.get(mBlocks[row][column].getNumber() * 2);
mScore += mBlocks[row][column].getNumber();
mBlocks[row][k] = mBlockObjArray.get(0);
break;
} else {
//元素不为空块,并且不相等,结束循环
break;
}
}
}
}
//2.移动步骤
for (int row = 0; row < mBlocks.length; row++) {
for (int column = 0; column < mBlocks[row].length; column++) {
//如果当前元素为空块,则拿同行最近且不为空块的滑块来填充
if (mBlocks[row][column] == mBlockObjArray.get(0)) {
for (int k = column + 1; k < mBlocks[row].length; k++) {
if (mBlocks[row][k] != mBlockObjArray.get(0)) {
mBlocks[row][column] = mBlocks[row][k];
mBlocks[row][k] = mBlockObjArray.get(0);
break;
}
}
}
}
}
(砖头+1...+1...+1024...)
其他三个方向的也是类似的,就不上代码了。这里要特别说明一点的时,完成一个操作后,会随机生成一个新的滑块,并把该滑块填充到可放置的位置(也就是空块位置),在这里就不讨论这个功能的实现了。
3.GameOver or Win
玩是可以玩了,但是告知玩家游戏状态还是很有必要的。
1)、游戏结束:当四个方向都不可操作的时候,可判断游戏结束。直接附上我的实现代码:
private boolean isGameOver () {
for (int row = 0; row < mBlocks.length - 1; row++) {
for (int column = 0; column < mBlocks[row].length; column++) {
if (mBlocks[row][column].equals(mBlocks[row + 1][column])) {
//游戏未结束
return false;
}
}
}
for (int column = 0; column < mBlocks[0].length - 1; column++) {
for (int row = 0; row < mBlocks.length; row++) {
if (mBlocks[row][column].equals(mBlocks[row][column + 1])) {
//游戏未结束
return false;
}
}
}
//游戏结束
return true;
}
有点搓,使用地毯式匹配,求优化~
2)、游戏胜利:当16个滑块中有一个达到了2048,即为胜利。方法:遍历元素,或者在合并的时候判断即可。
算法部分就到这吧。
PS:文中如有不对之处,敬请指出!谢谢~