0

I am creating a new board obtained by exchanging two adjacent blocks in the same row on an original board. The problem is that the new board overrides the content of the original board.

For example:

 int[][] origBoard = { { 0, 4, 6 }, {  5, 3, 1 }, { 2, 8, 7 } };
 int[][] twinBoard = { { 0, 6, 4 }, { 5, 3, 1 }, { 2, 8, 7 } };

What happens is that the origBoard becomes the same as the twinBoard when I assert the following:

 Board B = new Board(origBoard);
 Board b = B.twin();
 assertFalse("Calling twin() modifies the original Board.", B.equals(b));

My code is as follows:

public class Board {

    private int[][] goalBoard;

    private final Node node;

    private class Node {
        private int[][] board;
        private int move;
        private Node next;
    }

    // construct a board from an N-by-N array of blocks
    // (where blocks[i][j] = block in row i, column j)
    public Board(int[][] blocks) {
        int N = blocks.length;

        goalBoard = new int[N][N];
        for (int i = 0; i < dimension(); i++) {
            for (int j = 0; j < dimension(); j++) {
                if (i == N - 1 && j == N - 1) {
                    goalBoard[i][j] = 0;
                } else {
                    goalBoard[i][j] = N * i + (j + 1);
                }
            }
        }

        // initial node
        node = new Node();
        node.board = blocks;
        node.move = 0;
        node.next = null;
    }

    // board dimension N
    public int dimension() {
        return goalBoard.length;
    }

    // a board obtained by exchanging two adjacent blocks in the same row
    public Board twin() {
        int[][] testBoardATwin = new int[dimension()][dimension()];
        testBoardATwin = node.board;
        int x = node.board[0][0];
        int y = node.board[0][1];

        // DEFAULT
        if (x != 0 && y != 0) {
            testBoardATwin[0][0] = y;
            testBoardATwin[0][1] = x;
        }
        // 2x2
        if (dimension() == 2 || y == 0) {
            if (x == 0 || y == 0) {
                x = node.board[1][0];
                y = node.board[1][1];
                testBoardATwin[1][1] = x;
                testBoardATwin[1][0] = y;
            }
        } else {
            if (x == 0) {
                testBoardATwin[0][1] = node.board[0][2];
                testBoardATwin[0][2] = y;
            }
        }

        Board board = new Board(testBoardATwin);
        return board;
    }

    // does this board equal y?
    public boolean equals(Object y) {
        Board testBoard = (Board) y;
        if (testBoard == null) {
            return false;
        }
        for (int i = 0; i < dimension(); i++) {
            for (int j = 0; j < dimension(); j++) {
                if (testBoard.node.board[i][j] != node.board[i][j]) {
                    return false;
                }
            }
        }
        return true;
    }

}

What am i doing wrong? Please help. Thank you.

5
  • Why not just do a straight-forward copy of the original board's contents to the new board? Commented Sep 23, 2012 at 5:30
  • Also, in Java the convention is to implement the Clonable interface and have the method called clone instead of twin. Commented Sep 23, 2012 at 5:31
  • Where do you need object immutability in this scenario? Commented Sep 23, 2012 at 5:32
  • no... the twin method does not copy the board itself Commented Sep 23, 2012 at 5:35
  • the problem is when i do the twin method, the original board is being overwritten and becomes equal to the twin board(w/c has different content) Commented Sep 23, 2012 at 5:36

5 Answers 5

3

node = new Node(); node.board = blocks;

And same tricky place here in Board constructor. You not copying your input array but assigning a reference to a class member property.

Sign up to request clarification or add additional context in comments.

2 Comments

You've passed blocks[][] array into a constructor, so if you'll modify its value later outside of constructor it will be modified in a returned Board too (because of not copying it's value but assigning same reference). This can be a desired behaviour and can be not.
node = new Node(); node.board = new int[blocks.length][]; for (int i=0; i<blocks.length; i++) node.board[i] = Arrays.copyof(blocks[i], blocks[i].length)
3
int[][] testBoardATwin = new int[dimension()][dimension()];
testBoardATwin = node.board;

This is where your problem is. If you want to make a new one, don't follow that up by immediately changing it to the old one.

But the comments are right, too. A straightforward copy and modification would make more sense.

3 Comments

what do you mean by a straightforward copy and modification?
You could use Arrays.copyOf like Tim suggested to get a copy of the board array, then make changes to it. Right now you're not copying it, you're referencing the original board itself.
Hi! I've tried your suggestion: int[][] testBoardATwin = new int[dimension()][dimension()]; testBoardATwin = Arrays.copyOf(node.board, dimension()); But the problem is still the same. –
3

This is the problem:

int[][] testBoardATwin = new int[dimension()][dimension()];
testBoardATwin = node.board;

Everything starts off well when the code makes a new int[][] array, but then it immediately discards that new array and just uses the one belonging to the instance twin is called on.

Instead, what needs to happen is for node.board to be index by index, or by using something like Arrays.copyOf.

2 Comments

Hi! I've tried your suggestion: int[][] testBoardATwin = new int[dimension()][dimension()]; testBoardATwin = Arrays.copyOf(node.board, dimension()); But the problem is still the same.
Hi! I've tried your suggestion: int[][] testBoardATwin = new int[dimension()][dimension()]; testBoardATwin = Arrays.copyOf(node.board, dimension()); But the problem is still the same. –
0

In order to deep copy the multi-dimensional array, I did this:

  private static int[][] copy2d(int[][] nums) {
            int[][] copy = new int[nums.length][];

            for (int i = 0; i < copy.length; i++) {
                    int[] member = new int[nums[i].length];
                    System.arraycopy(nums[i], 0, member, 0, nums[i].length);
                    copy[i] = member;
            }

            return copy;
        }

    int[][] testBoardATwin = copy2d(node.board);

Comments

-1

To make an object you have to follow these instructions:

  • First of all you have to make the class final
  • Make all fields final and private.
  • Don't provide "setter" methods
  • Don't allow subclasses to override methods.
  • Notice that no Methods that modify state

And One of the best reference you can refer that http://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html

1 Comment

Don't forget to mention the need to do deep copies for your accessor methods that return objects (not primitives).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.