-2

I'm having a hard time implementing the method below for Project 0: 2048 Game:

public static boolean maxTileExists(Board b)

This method should return true if any of the tiles in the board are equal to the winning tile value 2048. Note that rather than hard coding the constant 2048 into your code, you should use MAX_PIECE, which is a constant that is part of the Model class. In other words, you shouldn’t do if (x == 2048) but rather if (x == MAX_PIECE). Leaving in hard coded numbers like 2048 is a bad programming practice sometimes referred to as a “magic number”. 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. After you’ve written the method, the tests in TestMaxTileExists.java should pass.

Here is my code below:

 /**
     * 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.
        for (int i = 0; i < b.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                if (b.tile(i, j).value() == MAX_PIECE) {
                    return true;
                }
            }
        }
        return false;
    }

I keep getting this error when testing:

java.lang.NullPointerException: Cannot invoke "game2048.Tile.value()" because the return value of "game2048.Board.tile(int, int)" is null

The first method that I needed to implement is below which worked perfectly and passed all test cases:

public static boolean emptySpaceExists(Board b)

This method should return true if any of the tiles in the given board are null. You should NOT modify the Board.java file in any way for this project. 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. Note: We’ve designed the Board class using a special keyword private that disallows you from using the instance variables of Board directly. For example, if you try to access b.values[0][0], this will not work. This is a good thing! It forces you to learn to use the tile method, which you’ll use throughout the rest of the project. Try opening the TestEmptySpace.java folder. Run the tests. You should see that 6 of the tests fail and 2 of them pass. After you’ve correctly written the emptySpaceExists method, all 8 tests in TestEmptySpace should pass.

Here is that code below:

/**
     * 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.
        for (int i = 0; i < b.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                if (b.tile(i, j) == null) {
                    return true;
                }
            }
        }
        return false;
    }

1 Answers1

1

Firstly, a NullPointerException generally occurs when you are trying to access something that hasn't been initialized yet. In your case, this is the .value() function.

In your second code block you may realize there is one major difference in the code you're using: this would be the "== null" part of your code as opposed to ".value() == MAX_PIECE".

Now, why would one of these throw an error while the other one does not?

This is because when you are checking if something is "null" you are seeing whether it exists or not. If it doesn't, then your program will return true, if it does exist, then your program will return false.

On the other hand, when you call .value() on an object you are already assuming the object exists. This means that, if the object has not been initialized for example, your program will attempt to dereference the pointer stored in your variable but will quickly realize that the pointer is not actually pointing to anything.

To fix an error such as this you simply need to make sure that what you're trying to access exists.

An example: lets say that we have Person x.

Person x;

Here we can quickly see that we will throw an error if we try something like this:

System.out.println(x.name());

Naturally this is because x doesn't exist yet.

However, if we wanted to see if Person x exists we would simply do something like this:

System.out.println(x == null);

In our case this isn't really necessary since we can plainly see that Person x has not been defined yet, but in a case like yours, where you are handling many different objects at once, a line like this could really help us.

This means that, if you want to make sure you don't throw a NullPointerException in your method you would only have to add one line (or change a line, this is a less verbose version of preventing an exception for the goal of learning).

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

By adding in the if statement that continues the for loop we skip the point in which the program would attempt to dereference an object that doesn't seem to exist.

One important thing to note, however, before you use this code: It's also possible that your tile should already exist, and in my opinion this is very likely. This would be a deeper problem in your code and one that you would solve by going through and making sure every tile is initialized at the beginning of your program.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Nicholas Zolton
  • 305
  • 1
  • 4