As stated in my previous question here, I am attempting to write a game AI. Currently, I have a loop which iterates through the neighbors of a cell, generating a list of possible moves. At some point in this loop (which is heavily recursive), I declare a new DotMove
object which stores the information for that particular move. This move is then appended to an ever growing list of moves.
Each move has a ordered list of dots which are considered it's "path".
Unfortunately, these DotMove
objects do not seem to hold the references to the paths correctly. Specifically, when I go to print the paths of the DotMove
objects which are generated, the paths come back as only one item long. (The paths should be several items long, and vary as the list prints out.)
List<Edge> e = getEdgesAt(p, con);
ArrayList<DotMove> moveList = new ArrayList<DotMove>();
for (Edge edge : e) {
if (visited.add(edge)) {
Point next = edge.getNextPoint(p);
path.add(next);
findMovesAtPointHelper(next, path, connected, visited);
moveList.add(new DotMove(path, this));
}
}
path.remove(path.size() - 1);
return moveList;
Which yields the following output:
r r b g r g r g
r r b g y r r b
b r b g b r r p
b r b b g r r r
b r b r r r b r
r b b p r p b b
p r y y g g b b
p y r b y p b r
[(0, 0)]
[(0, 1)]
[(1, 0)]
[(1, 1)]
[(1, 2)]
[(1, 2)]
[(1, 2)]
However, when I replace the moveList.add(...)
with a statement that prints the path at that time, I get the following (correct) output:
r r b g r g r g
r r b g y r r b
b r b g b r r p
b r b b g r r r
b r b r r r b r
r b b p r p b b
p r y y g g b b
p y r b y p b r
[(0, 0), (0, 1), (1, 1), (1, 0)]
[(0, 0), (0, 1), (1, 1)]
[(0, 0), (0, 1), (1, 1), (1, 2), (1, 3)]
[(0, 0), (0, 1), (1, 1), (1, 2)]
[(0, 0), (0, 1), (1, 1)]
[(0, 0), (0, 1)]
[(0, 0)]
I believe this discrepancy is caused by my DotMove constructor, and the Path constructor which it calls. The two have been included here for reference.
public DotMove(ArrayList<Point> path, BoardModel boardModel) {
this.path = new Path(path);
this.cleared = path;
this.score = path.size();
}
public Path(List<Point> path){
this.path = new ArrayList<Point>(path);
}
It appears that the Path()
constructor is retaining a reference to the entire list, rather than making a shallow copy of the list. This would explain the why the lists inside the DotMove
objects are shorter, because the move-finding algorithm relies on removing items from the end of a list as it traverses the board. The DotMove
objects are meant to store "snapshots" of this list, not references to the list itself.
How can I create shallow copies of this list correctly?