注:本文中的week对应课程时间安排。
week1
5.15
学习了java的基本语法和结构。java是一门面向对象语言。程序文件都是由一个个类构成,代码必须在函数内执行。
与python
需要区别语法是,它以大括号作为分隔,并且每行语句结束需要;
,其实大部分语法和cpp
比较接近。对于变量都要声明类型。
以hello world
为例:
1 2 3 4 5
| public class hello_world{ public static void main(String[] args){ System.out.println("hello world"); } }
|
另外对于方法而言,Java 允许我们定义两种类型方法。
static
,静态方法,由类本身执行的操作。
x = Math.sqrt(100);
- 非静态方法,实例方法,只能由类的特定实例执行。
Math m = new Math();
x = m.sqrt(100);
week2
5.17
主要学习了测试的方法,还有一些细节。
java中不可以滥用!=
,因为该运算符表示的是内存地址不同,如果内容相同但是内存地址不同那么是符合这个运算符的。如果比较内容,可以使用equal()
方法。
在测试中,可以使用JUnit
来简化。但是需要注意的是JUnit 要求测试方法必须是 public、非 static、无参数的方法,且带有 @Test
注解。这一章节只是看了看 slides。没有仔细学。
5.18
Lists
如果一个变量不是基本类型,那么它就是引用类型。当我们声明对象变量时,我们使用引用类型变量来存储对象在内存中的位置。而对于基本类型和方法,Java 采用的是pass-by-value
eg.
1 2 3 4 5 6 7 8 9 10 11
| public static void main(String[] args) { Walrus walrus = new Walrus(3500, 10.5); int x = 9; doStuff(walrus, x); System.out.println(walrus); System.out.println(x); } public static void doStuff(Walrus W, int x) { W.weight = W.weight - 100;
x = x - 5;
|
在这段代码中,W 是引用类型,所以在doStuff
方法中,与主方法指向用一个内存地址。而x 呢?x 作为基本类型,在doStuff
方法中,本质是对原来主方法x的二进制位的复制。x = 9
,在传入 doStuff(walrus, x)
时,是将 9
的拷贝传给 doStuff
。在 doStuff
中修改的是那个拷贝的 x
,对 main
中的 x
没有影响。
IntLists
使用链表构造了一个列表,对于列表长度,则使用递归来解决。当然也可以使用迭代,这里就不写了。 这里还要求构造一个获取i 索引元素的方法。使用了一个挺妙的递归:基线条件是索引为0,返回首位。否则向剩余列表获取索引为i-1的元素。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class IntList { public int first; public IntList rest; public IntList(int f, IntList r) { first = f; rest = r; } public int size(){ if (rest == null){ return 1; } return 1 + this.rest.size(); } public int get(int i){ if (i==0){ return first; } return rest.get(i-1); } public static void main(String[] args) { IntList l = new IntList(15,null); } }
|
另外课后还布置了额外的练习。
5.19
今天先把昨天剩下的列表练习做了。根据UCB的课程要求,代码不能公开。先把列表部分停一停,做做proj0的2048。难绷的是,2048的tilt
机翻成“倾斜”,其实是向某个方向滑动所有方块的意思。
5.23
先完成proj0 的前几个方法,对于tilt
,只需要完成一个方向,其余的则使用board.setViewingPerspective(side)
。算法思想是分两步走,移动+合并+移动。对于移动的实现,从上到下,对每个pos 一一确认。从顶部开始,如果非空,则移动到pos ,然后一个pos 就确认好了。如果为空,那么当前的pos 就没有被确认。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private boolean move_up(int col,int top){ boolean moved = false; int pos = top; for (int row = top; row >= 0; row--) { Tile t = board.tile(col, row); if (t != null){ if (row != pos){ board.move(col,pos,t); moved = true; } pos--; } } return moved; }
|
5.24
对于proj0 的合并部分,使用一个变量存储上一次的合并情况。然后一行行遍历列,如果上一次合并了,说明这次所在的行是上一次合并前的方块所在的行,所以跳过,并且重新记录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private boolean merge(int col) { boolean merged = false; int top = board.size() - 1; boolean lastMerged = false; for (int row = top; row > 0; row--) { if (lastMerged) { lastMerged = false; continue; } Tile current = board.tile(col, row); Tile below = board.tile(col, row - 1); if (current != null && below != null && current.value() == below.value()) { board.move(col, row, below); score += below.value() * 2; merged = true; lastMerged = true; } return merged; }
|
因为我们的合并只是移动了below
,所以方块没有到达最终位置,需要再进行一次移动。这次的移动后就不需要合并了,这是游戏的规则。
最后把两个方法集中到tilt 汇总。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public boolean tilt(Side side) { boolean changed; changed = false; board.setViewingPerspective(side); int top = board.size() - 1; for (int col = 0; col < board.size(); col++) { boolean moved1 = move_up(col,top); boolean merged = merge(col); boolean moved2 = move_up(col,top); if (moved1 || merged || moved2){ changed = true; } } board.setViewingPerspective(Side.NORTH); checkGameOver(); if (changed) { setChanged(); } return changed;
|