1

I am creating a connect 4 game in Java and i'm trying to make a deep copy of a custom object (The game Board), then modify that copy and add it to a list as part of the mini max algorithm.

This is the code i'm using for copying:

public void getPossibleBoards(Board board) {
    for(int i = 0; i < 7; i++) {
        if(!board.columns.get(i).isFull()) {    
            Board tmpBoard = board.copy(board);
            tmpBoard.columns.get(i).addCounter(turn);   
            boardList.add(tmpBoard);
        }
    }
}

public Board copy(Board other) {
    Board b = new Board(other);
    b.columns = other.columns;
    return b;
}

This takes the main board (passed as a parameter), loops through the columns on the board and if the column isn't full it creates a new board object and puts a counter in a empty column, then adds this new board object to a list for later use.

The problem is that when I copy the board, it keeps referencing the main board and modifying that, then each loop it adds a counter to a column without wiping the board clear first.

Expected output is: (Player 1 is human, player 2 is the computer)

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
2 0 0 0 0 0 1

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 2 0 0 0 0 1

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 2 0 0 0 1

And so on until the 7 loops are over.

Actual output:

0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 2 
2 2 2 2 2 2 1 

0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 0 
0 0 0 0 0 0 2 
2 2 2 2 2 2 1 

and so on until the 7 loops are over.

EDIT:

I had problems with the solution below so I decided to try another way, but got the same result and I don't understand why.

I'm basically creating a new Board object, within the constructor i'm assigning new blank columns to it, then looping through the main_board to get the colours of the counters at each slot (Stored as integers in the Slot class), and altering the new Board respectively.

if(!board.columns.get(i).isFull()) {    
    Board tmpBoard = new Board();

    for(int j = 0; j < 7; j++) {
        for(int k = 0; k < 7; k++) {
                    tmpBoard.columns.get(j).slots.get(k).setColour(board.columns.get(j).slots.get(k).getColour());
        }   
    }
}

Board constructor

public Board() {
    for(int i = 0; i < 7; i++) {
        columns.add(new Column());
    }
}

EDIT: Nevermind, above solution worked, just me forgetting to add a new counter after the copy.

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
SkelDave
  • 1,176
  • 2
  • 9
  • 23

2 Answers2

4

The line b.columns = other.columns; causes the problem since you are doing a reference assignment (i.e. its not doing a deep copy as you are expecting). You can copy that array by using System.arraycopy method.

I think in your case you are using an ArrayList to represent columns/rows if so, you can use:

Collections.copy(arrayList2,arrayList1);

or simply

new ArrayList<Integer>(oldList)

in order to create a copy.

Cemre Mengü
  • 18,062
  • 27
  • 111
  • 169
  • I tried using Collections.copy(newColList, oldColList) but I don't think it worked because I have a Board class with a Column ArrayList, then a Column class with a Slot Arraylist so although its copying the columns, the Slots are still referenced with the old Board object. I'll try and sort it, thanks for the help. – SkelDave Apr 13 '13 at 19:44
  • In that case you should probably override the `clone` method of the of the column then use a for loop to `clone` each column object one by one. (I am not sure if Collections.copy method automatically calls the clone method for the objects). See the first answer here: http://stackoverflow.com/questions/7042182/how-to-make-a-deep-copy-of-java-arraylist – Cemre Mengü Apr 13 '13 at 19:57
  • I had trouble implementing what you said, I think I did it correctly but still got the same result. I have edited my question with a new possible solution, but I can't seem to get that to work either. I'd appreciate it if you could take a look. Thanks – SkelDave Apr 14 '13 at 09:58
0

Why does Board take another Board as a constructor parameter?

Your problem is that you don't copy the columns, you only do b.columns = other.columns in your copy method. If one of the two boards is changed both boards are affected. Create a new column instances when copying and also deep copy all elements in an column until you reach immutable objects or primitives.

Franz Kafka
  • 10,623
  • 20
  • 93
  • 149