Search code examples
javaclonecopy-constructortic-tac-toe

copy an object without chainging the original one - java


I'm doing a Tic-Tac-Toc game and I have a method the returns all the possible moves from a current state. I'm trying to recive an object and copy it, change it and enter it to an array list.

@Override
public ArrayList<State> getAllPossibleMoves(State current) {
    ArrayList<State> moves = new ArrayList<State>();
    for (int i=0; i<current.getState().length; i++){
        for (int j=0; j<current.getState().length; j++){
            if (current.getState(i, j) == '-'){
                char[][] tmp1;
                tmp1 = current.getState().clone();
                tmp1[i][j] = 'O';
                TicTacToeState tmp2 = new TicTacToeState(tmp1);
                tmp2.setState(tmp1);
                moves.add(tmp2);
                //current.setState(i, j, '-');
            }
        }
    }
    return moves;
}

no matter what I try - any change I do on tmp1 effects on "current". I tryed clone() and copy constructor. just to mention that the class "State" is abstract and "TicTacTicState" extends "State".

for more information - here is the class State

public abstract class State implements Cloneable {

protected char[][] state;
protected int evaluation;   


@Override
public Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
}

@Override
public boolean equals(Object obj) {
    return state.equals(((State)obj).getState());
    //return super.equals(obj);
}

public State(){

}

public State(State s){
    this.state = s.state;
    this.evaluation = s.evaluation;
}

public State(char[][] state){
    this.state = state;
    this.evaluation = 0;
}

public State(char[][] state, int evaluation){
    this.state = state;
    this.evaluation = evaluation;

}

public char[][] getState(){
    return this.state;
}

public char getState(int row, int column) {
    return state[row][column];
}


public void setState(char[][] state) {
    this.state = state;
}

public void setState(int row, int col, char player){
    this.state[row][col] = player;
}
public abstract int getEvaluation(State state);

public abstract boolean isStateFull(State current); //returns true is it's a "terminal node"

public abstract ArrayList<State> getAllPossibleMoves(State current);

}


Solution

  • You have to physically copy your array yourself. You can do this with java.lang.System.arraycopy():

    import java.util.Arrays;
    
    public class ArrayCopy {
    
        public static void main(String[] args) {
    
            // set up an empty source array
            char[][] src = new char[5][3];
    
            // fill it with random digits
            for(int i = 0 ; i < src.length; i++) {
                for(int j = 0 ; j < src[0].length; j++) {
                    src[i][j] = (char) (Math.random() * 10 + 48);
                }
            }
    
            // show what it looks like
            printArray(src);
    
            // create an empty destination array with the same dimensions
            char[][] dest = new char[src.length][src[0].length];
    
            // walk over array and copy subarrays using arraycopy
            for (int i = 0; i < src.length; i++) {
                System.arraycopy(src[i], 0, dest[i], 0, src[0].length);
            }
    
            // make a change to the copy
            dest[0][0] = 'X';
    
            // the source array is still the same
            printArray(src);
    
            // hey presto!
            printArray(dest);
        }
    
        private static void printArray(char[][] array) {
            for(int i = 0 ; i < array.length; i++) {
                System.out.println(Arrays.toString(array[i]));
            }
            System.out.println();
        }
    }   
    

    Example output:

    [5, 5, 9]
    [0, 4, 7]
    [4, 8, 6]
    [1, 5, 4]
    [3, 9, 3]
    
    [5, 5, 9]
    [0, 4, 7]
    [4, 8, 6]
    [1, 5, 4]
    [3, 9, 3]
    
    [X, 5, 9]
    [0, 4, 7]
    [4, 8, 6]
    [1, 5, 4]
    [3, 9, 3]