栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

game2048

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

game2048

Game 2048

文章目录

Game 2048

Environment PreparationMain task

`emptySpaceExists(Board b)`

Related classSolutionReview `maxTileExists(Board b)`

Related classSolutionReview `atLeastoneMoveExists(Board b)`

Related classSolutionReview `tilt(Side side)`

Related classSolutionReview Java Basic knowledge

static variable`assert`finalFor-each LOOPIterable<>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2GqVbXqa-1648373110374)(game2048.assets/image-20220327165731872.png)]

Environment Preparation

参见项目指导书game2048

Main task

  • emptySpaceExists(Board b)

  • Time take(1h)
  • maxTileExists(Board b)

  • Time take(5min)
  • atLeastoneMoveExists(Board b)

  • Time take(15min)
  • tilt(Side side)

  • Time take(3h) emptySpaceExists(Board b) Related class

    Board

    tile method

        public Tile tile(int col, int row) {
            return vtile(col, row, viewPerspective);
        }
    

    TestEmptySpace

    共有8个测试案例,其中前6个是棋盘上有空(return true),后两个全满(return false)的

    testreturn
    1true
    2true
    3true
    4true
    5true
    6true
    7 满false
    8 满false

    Tile(棋子类)

    这个类定义了每一个棋子的状态,包括:数值、列、行、和下一个棋子。可以看作是一个有三个值一个指针的链表。

    public class Tile {
    
        
        private Tile(int value, int col, int row) {
            this.value = value;
            this.row = row;
            this.col = col;
            this.next = null;
        }
    

    createmovemergenext

    Model

    Solution

    Solution 1:

    public static boolean emptySpaceExists(Board b) {
            // TODO: Fill in this function.
            int count = 0; // count the number of empty tiles
            int board_size = b.size();
            for(int i = 0; i < board_size; ++i){
                for(int j = 0; j < board_size; ++j){
                   if( b.tile(i,j) == null){
                       count++;
                   }
                }
            }
            return count != 0;
        }
    

    Solution 2: Modified on the solution 1

    public static boolean emptySpaceExists(Board b) {
        // TODO: Fill in this function.
        int board_size = b.size();
        for(int i = 0; i < board_size; ++i){
            for(int j = 0; j < board_size; ++j){
                if( b.tile(i,j) == null){
                   return true;
                }
            }
        }
        return false;
    }
    
    Review

    ​ 第一个task的难度不在于思路而在于:

    1. 阅读理解`game2048`文档,配置换进并了解测试程序的使用。
    1. 看懂各个类之间的调用关系,每个类所定义的变量、提供的接口。
    1. 对于某些看不懂的`Java`前置引用概念的不理解就使用。
    

    思路就是一个对于一个二维数组的遍历,去看每个元素的值是否为null,但是就如指导书里说的那样,封装的Board类中定义了private Tiel[][] values;所以无法直接调用,只能通过Board中的这两个函数进行调用

     
        private Tile vtile(int col, int row, Side side) {
            return values[side.col(col, row, size())][side.row(col, row, size())];
        }
    
        
        public Tile tile(int col, int row) {
            return vtile(col, row, viewPerspective);
        }
    

    于是我们就很清楚,具体该怎么做了,正如项目指导书中写的我们只会用到.size()和.tile()两个方法就可以完成,不过通过在逐个类中分析出来是一种有点累但却很快乐的方式。

    maxTileExists(Board b) Related class

    和emptySpaceExists(Board b)相同

    Solution
        public static boolean maxTileExists(Board b) {
            // TODO: Fill in this function.
            
            int board_size = b.size();
            for (int i = 0; i < board_size; ++i)
                for (int j = 0; j < board_size; ++j) {
                    if (b.tile(i, j) == null) {
                    } else {
                        if (b.tile(i, j).value() == MAX_PIECE)
                            return true;
                    }
                }
            return false;
        }
    
    Review

    一开始直接写,没有考虑完整,碰到了这样的错,也就是提示我们要注意是空的位置的棋子的特殊情况。考虑到这点就没问题啦。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tt0n66Oe-1648373110376)(game2048.assets/image-20220326103538932.png)]

    atLeastoneMoveExists(Board b) Related class

    同前

    Solution
    
        
        public static boolean hasSameAdjacentTiles(Board b){
            int board_size = b.size();
            // test (n-1)*(n-1) size board
            for (int i = 0; i < board_size -1; ++i){
                for (int j = 0; j < board_size -1 ; ++j){
                    if ((b.tile(i, j).value() == b.tile(i + 1, j).value()) || (b.tile(i, j).value() == b.tile(i, j + 1).value())){
                        return true;
                    }
                }
            }
            // test n_th  col
            int col = board_size -1;
            for (int i = 0; i < board_size - 1; ++i){
               if (b.tile(col, i).value() == b.tile(col, i+1).value())
                   return true;
            }
            // test n_th row
            int row = board_size -1;
            for (int j = 0; j < board_size - 1; ++j){
                if (b.tile(j, row).value() == b.tile(j+1, row).value())
                    return true;
            }
    
            return false;
        }
    
    		public static boolean atLeastOneMoveExists(Board b) {
            // TODO: Fill in this function.
            // condition 1
            boolean b1 = true;
            if (emptySpaceExists(b))
                return b1;
            else{ // condition 2
                if(hasSameAdjacentTiles(b))
                    return b1;
                else
                    return false;
            }
        }
    
    Review

    通过一个辅助函数hasSameAdjacentTiles(Board b)来遍历board查看是否有可移动的位置,只需做基础判断就可,比较容易。

    tilt(Side side) Related class

    TileBoardModleMain Solution

    //    public void moveToghterInline ()
    
        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.
    
            // set the side to be NORTH, if it is not north, therefor easy to manipulate
            if (side != Side.NORTH) {
                board.setViewingPerspective(side);
            }
            // press up, and turn all the tiles be adjacent
            int board_size = board.size();
            for (int colIndex = 0; colIndex < board_size; ++colIndex){ // move all tiles in a line adjacent, col by col
                int nullCount = 0; // count how many null tile is before current tile in a line
                for (int rowIndex = board_size -1; rowIndex >= 0; --rowIndex){
                    if(board.tile(colIndex, rowIndex) == null) {
                        nullCount++;
                        continue;
                    }
                    Tile t = board.tile(colIndex, rowIndex);
                    if(board.tile(colIndex, rowIndex+nullCount) == null) {
                        board.move(colIndex, rowIndex + nullCount, t);
                        changed = true;
                    }
                }
            }
    
            // merge if possible
            for (int colIndex = 0; colIndex < board_size; ++colIndex){
                for (int rowIndex = board_size -1; rowIndex > 0; --rowIndex){
                    if((board.tile(colIndex, rowIndex) != null) && (board.tile(colIndex, rowIndex -1) != null) && (board.tile(colIndex, rowIndex).value() == board.tile(colIndex, rowIndex - 1).value())){
                        //Tile currentTile = board.tile(colIndex, rowIndex);
                        Tile nextTile = board.tile(colIndex, rowIndex-1);
                        board.move(colIndex, rowIndex, nextTile);
                        score += nextTile.value()*2;
                        changed = true;
                    }
                }
            }
    
            // turn all tiles together again after merge
            for (int colIndex = 0; colIndex < board_size; ++colIndex){ // move all tiles in a line adjacent, col by col
                int nullCount = 0; // count how many null tile is before current tile in a line
                for (int rowIndex = board_size -1; rowIndex >= 0; --rowIndex){
                    if(board.tile(colIndex, rowIndex) == null) {
                        nullCount++;
                        continue;
                    }
                    Tile t = board.tile(colIndex, rowIndex);
                    if(board.tile(colIndex, rowIndex+nullCount) == null) {
                        board.move(colIndex, rowIndex+nullCount, t);
                    }
                }
            }
    
            // turn the side back, if the origin side is not north
            if(side != Side.NORTH) {
                board.setViewingPerspective(Side.NORTH);
            }
    
            checkGameOver();
            if (changed) {
                setChanged();
            }
    
            return changed;
        }
    
        
        private void checkGameOver() {
            gameOver = checkGameOver(board);
        }
    
        
        private static boolean checkGameOver(Board b) {
            return maxTileExists(b) || !atLeastOneMoveExists(b);
        }
    
        
        public static boolean emptySpaceExists(Board b) {
            // TODO: Fill in this function.
            int board_size = b.size();
            for(int i = 0; i < board_size; ++i){
                for(int j = 0; j < board_size; ++j){
                   if( b.tile(i,j) == null){
                       return true;
                   }
                }
            }
            return false;
        }
    
    Review

    这确实是整个proj0中最难的一个,难点在于:

      理解合并的过程,和游戏的规则,把文档提供的Google quiz轻易完成很有必要。
        虽然不应该提醒,更应该是自己发现,这点搞错的话会做不了的,但是还是想说一下,这里的棋盘是以左下角为原点的,其他就不多说了,自己去javadoc里会慢慢发现的
      处理复杂控制问题:向上,向下,向左,向右,排列在一起,合并,合并后再排列在一起细节处理:我在第一次完成后debug的时间大多花在了nullPoiinterException上了,发现是自己不小心用错了.tilt()函数后一切都顺利多了。处理顺序的考虑

    我自己还有一些没做好的地方是这一部分的代码写得过于冗杂,不够简单,实现的方式也不够巧妙,下一周复习的时候再来思考一下应该怎么优化。

    Java Basic knowledge static variable

    static variable is a variable that all classes could use.

    We generally use static methods to perform an operation that is not dependent upon instance creation.

    In order to share a code across all instances of that class, we write that code in a static method:

    public static void setNumberOfCars(int numberOfCars) {
        Car.numberOfCars = numberOfCars;
    }
    

    We also commonly use static methods to create utility or helper classes so that we can get them without creating a new object of these classes.

    Just take a look at Collections or Math utility classes from JDK, StringUtils from Apache or CollectionUtils from Spring framework and notice that all methods are static.

    assert

    粗浅理解一下是像写操作系统项目会遇到的assert(expression)函数,类似if-else的简单版,只有确保了expression为真才可以运行之后的语句。

    final

    For-each LOOP

    Iterating over a collection is uglier than it needs to be. Consider the following method, which takes a collection of timer tasks and cancels them:

    void cancelAll(Collection c) {
        for (Iterator i = c.iterator(); i.hasNext(); )
            i.next().cancel();
    }
    

    The iterator is just clutter. Furthermore, it is an opportunity for error. The iterator variable occurs three times in each loop: that is two chances to get it wrong. The for-each construct gets rid of the clutter and the opportunity for error. Here is how the example looks with the for-each construct:

    void cancelAll(Collection c) {
        for (TimerTask t : c)
            t.cancel();
    }
    

    When you see the colon (:) read it as “in.” The loop above reads as “for each TimerTask t in c.” As you can see, the for-each construct combines beautifully with generics. It preserves all of the type safety, while removing the remaining clutter. Because you don’t have to declare the iterator, you don’t have to provide a generic declaration for it. (The compiler does this for you behind your back, but you need not concern yourself with it.)

    The for-each construct is also applicable to arrays, where it hides the index variable rather than the iterator. The following method returns the sum of the values in an int array:

    >// Returns the sum of the elements of a>
    int sum(int[] a) {
        int result = 0;
        for (int i : a)
            result += i;
        return result;
    }
    
    Iterable<>
    public interface Iterable
    

    Implementing this interface allows an object to be the target of the “for-each loop” statement. See For-each Loop

    In general, an object Implementing Iterable allows it to be iterated. An iterable interface allows an object to be the target of enhanced for loop(for-each loop).

  • 转载请注明:文章转载自 www.mshxw.com
    本文地址:https://www.mshxw.com/it/782690.html
    我们一直用心在做
    关于我们 文章归档 网站地图 联系我们

    版权所有 (c)2021-2022 MSHXW.COM

    ICP备案号:晋ICP备2021003244-6号