Proj 0
约 1425 字大约 5 分钟
2025-04-16
设计模式
MVC 模式
MVC(Model-View-Controller)把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)
- 模型(Model):负责数据和业务逻辑,通常包含数据存储、检索和业务规则。
- 视图(View):负责显示数据(模型)的用户界面,不包含业务逻辑。
- 控制器(Controller):接收用户的输入,调用模型和视图去完成用户的请求。
说简单点,模型存储了数据,视图负责展示,控制器把模型的数据传输到视图,视图实时展示;控制器还可以接收用户的输入,来改变模型中的数据。
Observer 模式
当对象间存在一对多关系时,则使用观察者模式。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
项目介绍
本项目主要是为了完成“2048”这个小游戏。规则的话可以在 CS 61B 官网查看。
核心代码介绍
Tile
这个类表示棋盘上的瓷砖编号。如果类型为 Tile
的变量是 null
,则它在棋盘上被视为一个空瓷砖。这个类你唯一需要使用的方法是 .value()
,它返回给定瓷砖的值。例如,如果 Tile t
对应一个值为 8 的瓷砖,那么 t.value()
将返回8。
Side
Side
类是一种枚举类。该枚举类可以选择四个方向的值:“北”(NORTH)、“南”(SOUTH)、“东”(EAST)和“西”(WEST)。你不需要使用这个类的任何方法,也不需要操作实例变量。枚举可以使用类似于 Side s = Side.NORTH
的语法进行赋值。
Model
Model
类代表了游戏“2048”的整个状态。一个 Model 对象代表一局 2048 游戏。它具有表示棋盘状态的实例变量(例如所有 Tile 对象的位置、当前得分等)以及多种方法。在这个项目的第四个也是最后一个任务(编写 tilt 方法)中,挑战之一是确定这些方法和实例变量中哪些是有用的。
Board
这个类代表瓷砖板本身。它有三个你将使用的方法:setViewingPerspective
、tile
、move
。可选地,为了进行实验,你可以使用 getRandomNonNullTile
。在这个作业中你将只编辑Model.java文件。Gradescope 将只接受你的Model.java文件。
实验内容
我们只需要在 Model.java
里进行实验,在这个文件里面我们只需要补充四个函数:
emptySpaceExists
maxTileExists
atLeastOneMoveExists
tilt
前三种方法将处理游戏结束的情况,最后一种方法 tilt
将在用户按下按键后修改棋盘。你可以阅读 checkGameOver
方法的简短主体,以了解你的方法将如何用于检查游戏是否结束。
emptySpaceExists
如果给定棋盘中的任何方块为空,则此方法应返回 true。
在这个项目中,你不应以任何方式修改 Board.java 文件。对于此方法,你将需要使用 tile(int col, int row)
和 size()
方法。不需要其他方法。
尝试运行 TestEmptySpace.java
,你应该看到有 6 个测试失败,2 个测试通过。在你正确编写了 emptySpaceExists
方法后,TestEmptySpace
中的所有 8 个测试都应该通过。
maxTileExists
如果棋盘上的任何一块瓷砖等于 2048,此方法应返回 true。
在这里不应将常量 2048 硬编码到代码中,而应使用 MAX_PIECE
,它是Model类中的一个常量。
在代码中保留像2048这样的硬编码数字有时是一种不良的编程习惯,被称为“魔法数字”。这种魔法数字的危险在于,如果你在代码的一部分更改了它们,但在另一部分没有更改,你可能会得到意外的结果。通过使用像 MAX_PIECE
这样的变量,你可以确保它们都一起被更改。在你编写了方法之后,TestMaxTileExists.java
中的测试应该通过。
atLeastOneMoveExists
这个方法更具挑战性。如果存在任何有效移动,它应该返回 true。
所谓“有效移动”,是指在玩 2048 游戏时,如果用户可以按下一个按钮(上、下、左、右),并且该操作会导致至少一个方块移动,那么这样的按键操作被认为是有效移动。
有两种情况可以有有效的移动:
- 棋盘上至少有一个空位。
- 有两个相邻的方块具有相同的值。
在你编写完方法后,TestAtLeastOneMoveExists.java
中的测试应该通过。
tilt
tilt
方法实际上负责移动所有的方块。
除了修改棋盘,还有另外两件事情必须发生:
- 分数实例变量必须更新,以反映所有方块合并的总值(如果有的话)。对于上面的例子,我们将两个 4 合并成一个 8,将两个 2 合并成一个 4,所以分数应该增加 8 + 4 = 12。
- 如果棋盘有任何变化,我们必须将changed局部变量设置为true。这是因为在tilt的框架代码末尾,你可以看到我们调用了一个
setChanged()
方法:这通知图形用户界面有东西要绘制。你自己不会调用setChanged
:只修改changed
局部变量。
棋盘上所有方块的移动都必须使用 move
类提供的移动方法来完成。必须使用 Board
类提供的 tile
方法来访问棋盘上的所有方块。由于图形用户界面实现中的一些细节,在每次调用 tilt
时,对给定方块只能调用一次 move
。