本人项目链接CS61B-Tutorial/proj0/game2048 at main · xxbaizero0/CS61B-Tutorial (github.com)

我的任务仅驻留在 Model.java 并且仅限于四个方法:

  • public static boolean emptySpaceExists(Board b)

  • public static boolean maxTileExists(Board b)

  • public static boolean atLeastOneMoveExists(Board b)

  • public boolean tilt(Side side)

前置工作

配置项目cdk,导入库

我们想要使用 javalib 文件夹中的这些 .jar 文件。仍然在“项目结构”中,单击左侧名为“库”的项目设置部分。如果您看到已添加, javalib 则无事可做。否则,我们将单击“+”按钮,然后单击“Java”,这将启动我们操作系统的文件浏览器,然后单击该 javalib 文件夹。然后,在屏幕的右下角,点击“应用”,然后点击蓝色的“确定”按钮。

IntelliJ Setup

修改项目文件

游戏运行的上下左右移动键英语语言下的按键,我们需要修改GUISource.java

img

代码答案

public static boolean emptySpaceExists(Board b)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/** Returns true if at least one space on the Board is empty.
* Empty spaces are stored as null.
* */
public static boolean emptySpaceExists(Board b) {
// TODO: Fill in this function.
int length = b.size();
for(int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
if (b.tile(i, j) == null)
return true;
}
}
return false;
}

public static boolean maxTileExists(Board b)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Returns true if any tile is equal to the maximum valid value.
* Maximum valid value is given by MAX_PIECE. Note that
* given a Tile object t, we get its value with t.value().
*/
public static boolean maxTileExists(Board b) {
// TODO: Fill in this function.
int length = b.size();
for(int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
if(b.tile(i, j) != null&&b.tile(i, j).value() == MAX_PIECE)
return true;
}
}
return false;
}

public static boolean atLeastOneMoveExists(Board b)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static boolean atLeastOneMoveExists(Board b) {
// TODO: Fill in this function.
int length = b.size();
if(emptySpaceExists(b)) return true;
for(int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
if(i - 1 >= 0 && i + 1 < length)
if(
(b.tile(i-1, j).value() == b.tile(i, j).value())
||(b.tile(i+1, j).value() == b.tile(i, j).value())) return true;
else if (j - 1 >=0 && j+1 < length)
if((b.tile(i,j-1).value() == b.tile(i, j).value())
||(b.tile(i, j +1).value() == b.tile(i, j).value())) return true;
}
}
return false;
}

调用了emptySpaceExists()函数,实际上增加了无所谓的时间,但是如果要完善的话if条件句还需要加长,可读性不高,因此没有修改。

如果有任何有效的移动,则应返回 true。所谓“有效移动”,是指如果用户在玩 2048 时可以按下一个按钮(UP、DOWN、LEFT 或 RIGHT),导致至少一个图块移动,那么这样的按键被视为有效移动。

有两种方法可以进行有效移动:

  • 棋盘上至少有一个空白区域。
  • 有两个相邻的图块具有相同的值。

例如,对于下面的板,我们应该返回 true,因为至少有一个空白区域。

1
2
3
4
|   2|    |   2|    |
| 4| 4| 2| 2|
| | 4| | |
| 2| 4| 4| 8|

对于下面的板子,我们应该返回 false。无论你在 2048 年按下什么按钮,都不会发生任何事情,即没有两个相邻的瓷砖具有相等的值。

1
2
3
4
|   2|   4|   2|   4|
| 16| 2| 4| 2|
| 2| 4| 2| 4|
| 4| 2| 4| 2|

对于下面的棋盘,我们将返回 true,因为向右或向左移动将合并两个 64 个图块,并且向上或向下移动将合并 32 个图块。或者换句话说,至少存在两个值相等的相邻图块。

1
2
3
4
|   2|   4|  64|  64|
| 16| 2| 4| 8|
| 2| 4| 2| 32|
| 4| 2| 4| 32|

public boolean tilt(Side side)

倾斜方法的工作是实际移动所有瓷砖。如:

1
2
3
4
|   2|    |   2|    |
| 4| 4| 2| 2|
| | 4| | |
| 2| 4| 4| 8|

然后按 up,将修改 board 实例变量, tilt 使游戏的状态现在为:

1
2
3
4
|   2|   8|   4|   2|
| 4| 4| 4| 8|
| 2| | | |
| | | | |

除了修改板之外,还必须发生另外两件事:

  1. 必须更新评分实例变量,以反映所有图块合并的总值(如果有)。在上面的例子中,我们将两个 4 合并成一个 8,将两个 2 合并成一个 4,因此分数应该增加 8 + 4 = 12。
  2. 如果板发生任何变化,我们必须将 changed 局部变量设置为 true 。这是因为在 的 tilt 框架代码的末尾,您可以看到我们调用了一个 setChanged() 方法:这通知 GUI 有一些东西要绘制。您不会对自己 setChanged 进行任何调用:只需修改 changed 局部变量。

示例:

image-20240118213830819

image-20240118213851546

image-20240118214110920

image-20240118214147334

tip

  • 我们可以只专注于一个方向的实现,然后通过数组的旋转来实现多方向的实现。
  • 由上图可知,我们最好从每列顶部开始遍历,这样才能符合游戏逻辑

答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public boolean tilt(Side side) {
boolean changed;
changed = false;

// TODO: Modify this.board (and perhaps this.score) to account
// for the tilt to the Side SIDE. If the board changed, set the
// changed local variable to true.
board.setViewingPerspective(side);

for (int c = 0; c < board.size(); c++){
for(int r = board.size()-1; r >= 0; r--){
Tile t = board.tile(c, r);
int row = r;
if(board.tile(c, r) != null){
for(int i = board.size()-1; i > r; i--){
if (board.tile(c, i) == null) {
board.move(c, i, t);
row = i;
changed = true;
break;
}
}
for (int i = row -1; i >= 0; i--){
if(board.tile(c, i)!=null && t.value() != board.tile(c, i).value()) break;
else if(board.tile(c, i)!=null && t.value() == board.tile(c, i).value()){
board.move(c, row, board.tile(c, i));
changed = true;
score += board.tile(c, row).value();
break;
}
}
}
}
}
board.setViewingPerspective(Side.NORTH);
checkGameOver();
if (changed) {
setChanged();
}
return changed;
}