Ary
Ary

Reputation: 47

Rotating a bidimensional array - a working example and a broken one (why though?)

I'm experimenting with two different methods to get a bidimensional array to rotate. Both work when inheritance isn't involved, but as soon as I extend the class, one of them gives weird results.

This is the one that always works:

  1. Make a new, empty array of the same size as the one that I want to rotate.
  2. Copy the cells from the original array into this new array in a different order to imitate rotation - so, say, if I'm rotating the array anti-clockise, the cell that's in the upper-right corner [0][2] would go in the upper left corner [0][0] (this can and will be improved with for cycles instead, of course).
  3. Once it's all filled, copy the new array into the original array.

This is what doesn't work:

  1. Copy the bidimensional array.
  2. Take single cells from this new array I just filled and put them back into the original array, but in a different order - (as explained in step 2 above).

However, the results I get from this latter one indicate that it's like the copy array it's initialized everytime a new line in executes, so the copy array reflects the changes I make in the original array, rather than staying the same and letting me copy each cell.

Here's examples, assuming the array I'm trying to rotate is a piece of Tetris.

This does not work:

public abstract class Piece {
    private int y;
    private int x;
    private String[][] tetromino;

    public void setTetromino(String[][] a) { tetromino = a; }

    public void rotate()
    {
        String[][] copy = tetromino;
        tetramino[0][0] = copy[0][2];
        tetramino[0][1] = copy[1][2];
        tetramino[0][2] = copy[2][2];
        tetramino[1][0] = copy[0][1];
        tetramino[1][2] = copy[2][1];
        tetramino[2][0] = copy[0][0];
        tetramino[2][1] = copy[1][0];
        tetramino[2][2] = copy[2][0];
    }

    public void print()
    {
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                System.out.print(tetromino[i][j]);
            }
            System.out.println();
        }
    }
}

And its subclass:

public class TPiece extends Piece {
    String[][] a = {{ "1", "2", "3" },
                    { "4", "5", "6" },
                    { "7", "8", "9" }};

    public TPiece()
    {
        setTetromino(a);
    }

    public static void main(String[] args)
    {
        TPiece T = new TPiece();
        T.print();
        T.rotate();
        T.print();
    }
}

Output:

123
456
789
369
658
363

Not rotated!

Now, for the working one, here's the changes to rotate() (everything else stays the same):

public void rotate() {
    String[][] copy = new String[3][3];
    copy[0][0] = tetromino[0][2];
    copy[0][1] = tetromino[1][2];
    copy[0][2] = tetromino[2][2];
    copy[1][0] = tetromino[0][1];
    copy[1][1] = tetromino[1][1];
    copy[1][2] = tetromino[2][1];
    copy[2][0] = tetromino[0][0];
    copy[2][1] = tetromino[1][0];
    copy[2][2] = tetromino[2][0];
    tetromino = copy;
}

Output:

123
456
789
369
258
147

Rotated as intended.

Can anyone explain why?

Upvotes: 0

Views: 76

Answers (2)

kennemat
kennemat

Reputation: 190

It's not polymorphism that's the issue here, it's objects and what is happening. The way Java works is that when we create a new object, we have some reference to that object. Let's use a picture found in this answer.

enter image description here

While we're not using a Person object, the same principles hold for any object (keep in mind, arrays are objects in Java). What is happening is we create some person object. For this, we'll keep it simple and say the line is Person person = new Person();. Pretty standard. Let's say we make another person though, and this time, we say Person person2 = person; Perfectly legal, and this shows what is happening in the picture above; we have 2 references pointing to the same object.

The reason that long-winded explanation of object references is here is because that is what is happening in your code. In the rotate() method, the first line is String[][] copy = tetromino;. This will set copy equal to what tetromino is, and every change made in copy is also made in tetromino. I'm not sure what IDE you are using, but I know Eclipse has a debugger where you can step through a function and check values as you go. Doing so and checking the value of copy and tetramino will show the change happening in each at every line.

I fixed your code to show a working example.

Piece:

public abstract class Piece {
    private int y;
    private int x;
    private String[][] tetramino;

    public void setTetramino(String[][] a) { tetramino = a; }

    public void rotate()
    {
        String[][] copy = new String[3][3];
        copy[0][0] = tetramino[0][2];
        copy[0][1] = tetramino[1][2];
        copy[0][2] = tetramino[2][2];
        copy[1][0] = tetramino[0][1];
        copy[1][1] = tetramino[1][1];
        copy[1][2] = tetramino[2][1];
        copy[2][0] = tetramino[0][0];
        copy[2][1] = tetramino[1][0];
        copy[2][2] = tetramino[2][0];
        setTetramino(copy);
    }

    public void print()
    {
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                System.out.print(tetramino[i][j]);
            }
            System.out.println();
        }
    }
}

TPiece:

public class TPiece extends Piece {
    String[][] a = {{ "1", "2", "3" },
                    { "4", "5", "6" },
                    { "7", "8", "9" }};

    public TPiece()
    {
        setTetramino(a);
    }

    public static void main(String[] args)
    {
        TPiece T = new TPiece();
        T.print();
        T.rotate();
        T.print();
    }
}

As you can see, copy is now just an empty 2d array, and at the end, the setTetramino method is called.

Upvotes: 2

Asanka
Asanka

Reputation: 1648

Java have Objects and Primitive data types. object data types keep the reference in your programme but the actual object in the heap. so in first case,

 String[][] copy = tetromino;
 tetramino[0][0] = copy[0][2];

There your copy and tetramino both arrays points to same array.

 tetramino[0][0] = copy[0][2];
 tetramino[0][1] = copy[1][2];
 tetramino[0][2] = copy[2][2];
 tetramino[1][0] = copy[0][1];

is equals to

 copy[0][0] = copy[0][2];
 copy[0][1] = copy[1][2];
 copy[0][2] = copy[2][2];
 copy[1][0] = copy[0][1];

but in second scenario you have initialized a new array that's why you got correct results.If you want to working on first method you have to used to deep copy instead of shallow copy (not only reference but you want to copy objects). use this link to learn how to deep copy. Hope this will help :)

Upvotes: 3

Related Questions