CS61B 2021 pro0 2048

本文详细描述了在2048游戏中实现Mode.java类的四个关键方法:判断空位、最大值存在、是否至少有一次移动以及游戏逻辑构建。同时介绍了运行中遇到的上下左右键移动BUG的修复过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CS61B 2021 pro0 : 2048

1.简介

要求实现2048游戏中Mode.java中的四个函数,分别是

public static boolean emptySpaceExists(Board b)
public static boolean maxTileExists(Board b)
public static boolean atLeastOneMoveExists(Board b)
public boolean tilt(Side side)

2.实现

Task 1. public static boolean emptySpaceExists(Board b)

笼统看下全局代码可以知道这是一个判断board中的tile数组是否存在空位。

pro0要求中说:*** For this method, you’ll want to use the tile(int col, int row) and size() methods of the Board class. No other methods are necessary.***

其中 Board 类中的tile和size方法,分别是返回相应(col,row)的数组中的值和返回数组长度,所以我们可以简单的实现它,及遍历整个tile 如果有null则true。

/** Returns true if at least one space on the Board is empty.
 *  Empty spaces are stored as null.
 * */
public static boolean emptySpaceExists(Board b) {
    int size = b.size();
    for (int col = 0; col < size; col++) {
        for (int row = 0; row < size; row++) {
            if (b.tile(col, row) == null) {
                return true;
            }
        }
    }
    return false;
}

Task 2. public static boolean maxTileExists(Board b)

这个方法就是判断2048游戏中是否有2048数值,所以是实现和上面差不多就是遍历,再加一个判断t.values() == MAX_PIECE

因为要求中说明了要使用MAX_PIECE代替直接使用2048,解释如下:

The danger of such magic numbers is that if you change them in one part of your code but not another, you might get unexpected results. By using a variable like MAX_PIECE you can ensure they all get changed together.

/**
 * 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) {
    int size = b.size();
    for (int col = 0; col < size; col++) {
        for (int row = 0; row < size; row++) {
            Tile t = b.tile(col, row);
            // only when t != null should we check t.value()
            if (t != null && t.value() == MAX_PIECE) {
                return true;
            }
        }
    }
    return false;
}

Task 3. public static boolean atLeastOneMoveExists(Board b)

这个方法是为了判断游戏是否能继续进行,有两种情况:

1.2048 的所有方格中至少有一个是空的. 这个可以用前面实现的 emptySpaceExists()
2.如果移动的方向上有相邻而且值一样的格子, 此时我们可以进行合并.

第一个条件好解决,就是使用Task 1,第二个条件则需要考虑tile中数组的上下左右,四个方向的数值,判断是否相等,这里有挺多方法,我选择用两个一维数组x,y.其中x来控制colum方向,y控制row方向。

 public static boolean atLeastOneMoveExists(Board b) {
        if(emptySpaceExists(b)){
            return true;
        }
        int size = b.size();
        int[] x = {0,-1,0,1};
        int[] y = {-1,0,1,0};
        for (int i=0;i<size;i++){
            for (int j =0;j<size;j++){
                int curTileValue = b.tile(i,j).value();
                for (int n=0 ;n<4;n++){
                    int change_i= i+x[n];
                    int change_j = j+y[n];
                    if(change_i<size&&change_j<size&&change_i>0&&change_j>0){
                        int change_value = b.tile(change_i, change_j).value();
                        if (change_value == curTileValue){
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

Task 4. Building the Game Logic

这个是最难的任务*I must warn you, this is probably going to be a frustrating experience. It is likely that you will attempt several approaches that will ultimately fail before you have to start back over.**

这里我们需要拆分为两部 :

1.首先把每一个空的格子移到 “后面”(此时不考虑合并). 保证前面都是连续的有效格子. 这里的前面和后面是相对于我们移动的方向而言的.[x, 2, 2, x] -> [2, 2, x, x]

2.然后我们再考虑合并这件事情, 我们需要检查相邻的格子是否值一样, 从最前面的开始检查, 把它和下一个相邻的格子检查是否可以合并, 如果可以, 就把后面的移动到前面来进行合并, 然后再处理下一个. 比如 [2, 2, 2, x] -> [4, x, 2, x] -> [4, 2, x, x]. 然后我们会移动到下一个位置也就是 2 看看 2 能不能和 x 合并.

public boolean tilt(Side side) {
    boolean changed;
    changed = false;
    
    board.setViewingPerspective(side);
    int size = board.size();
    for (int col = 0; col < size; col++) {
        // Step1. move every non-empty tile in order
        // [x, 2, 2, x] -> [2, 2, x, x]
        // skip merging this step.
        for (int row = size - 1; row >= 0; row--) {
            Tile t = board.tile(col, row);
            if (t != null) {
                // find nextPos which is null
                int nextPos = 3;
                while (nextPos >= row) {
                    if (board.tile(col, nextPos) == null) {
                        break;
                    }
                    nextPos--;
                }
                // check if nextPos is a legal position
                if (nextPos >= row) {
                    board.move(col, nextPos, t);
                    changed = true;
                }
            }
        }
        // Step2. try to merge
        // [2, 2, x, x] -> [4, x, x, x]
        for (int row = 3; row >= 0; row--) {
            Tile curTile = board.tile(col, row);
            int nextLine = row - 1;
            if (nextLine < 0) {
                break;
            }
            Tile nextTile = board.tile(col, nextLine);
            if (curTile == null || nextTile == null) {
                break;
            }
            int nextValue = nextTile.value();
            if (nextValue == curTile.value()) {
                board.move(col, row, nextTile);
                score += curTile.value() * 2;
                for (int p = nextLine - 1; p >= 0; p--) {
                    Tile tt = board.tile(col, p);
                    if (tt == null) {
                        break;
                    }
                    if (p < size) {
                        board.move(col, p + 1, tt);
                    }
                }
                changed = true;
            }
        }
    }
    board.setViewingPerspective(Side.NORTH);

    checkGameOver();
    if (changed) {
        setChanged();
    }
    return changed;
}

3.运行中遇到的BUG

运行时发现按上下左右格子无法移动。

我们需要找到GUISource.java中

String command = _source.readKey();
//        System.out.println(command);
switch (command) {
    case "↑" :
        command = "Up";
        break;
    case "→" :
        command = "Right";
        break;
    case "↓" :
        command = "Down";
        break;
    case "←" :
        command = "Left";
        break;
    default :
        break;
}

修改为:

 String command = _source.readKey();
        switch (command) {
            case "W" :
                command = "Up";
                break;
            case "D" :
                command = "Right";
                break;
            case "S" :
                command = "Down";
                break;
            case "A" :
                command = "Left";
                break;
            default :
                break;
        }

即可成功运行。

4.参考链接

1.方法实现

2.BUG解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值