0

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?

Community
  • 1
  • 1
Peaches491
  • 1,239
  • 15
  • 27
  • Have a look at static method `copy` of `java.util.Collections` class - http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#copy(java.util.List, java.util.List). – PM 77-1 Jan 08 '14 at 01:38
  • I've just tried this, and it gives me lists with zero elements in them. – Peaches491 Jan 08 '14 at 02:04
  • Seems like you need to create `ArrayList` with **the same size** first. `new ArrayList(path.size);` – PM 77-1 Jan 08 '14 at 02:15
  • It baffles me why your original approach didn't work though. Are you sure you pinpointed the right spot to fix? – PM 77-1 Jan 08 '14 at 02:18
  • I did create a destination array of the appropriate size first, and still no luck. I am also baffled. I'm currently looking to see if there is a bug elsewhere – Peaches491 Jan 08 '14 at 02:27
  • Have you tried to go step-by-step under debugger and examine all the intermediate values. – PM 77-1 Jan 08 '14 at 02:52

1 Answers1

1

After much toil, the bug was located here:

ArrayList<DotMove> moveList = new ArrayList<DotMove>();

This created a new moveList at every recursion of the findMovesAtPointHelper method. This caused the other methods to be lost at every iteration.

For reference, here is a new list of moves, sorted by length, then by score (the last number is a hash which identifies functionally equivalent moves.):

  0 1 2 3 4 5 
0 r r b g b r 
1 r r b r r r 
2 b r b y y b 
3 b g b y b b 
4 b y b p b b 
5 y b r b y b 

Top 5 moves: 
 17 Loop [(4, 3), (4, 4), (5, 4), (5, 3), (4, 3)] -86374027
 17 Loop [(4, 4), (4, 3), (5, 3), (5, 4), (4, 4)] -86374027
 17 Loop [(5, 3), (4, 3), (4, 4), (5, 4), (5, 3)] -86374027
 17 Loop [(5, 4), (4, 4), (4, 3), (5, 3), (5, 4)] -86374027
 17 Loop [(5, 2), (5, 3), (4, 3), (4, 4), (5, 4), (5, 3)] -86374027

Bottom 5 moves: 
  2      [(5, 5), (5, 4)] -739973680
  2      [(5, 4), (4, 4)] -1399527984
  2      [(5, 3), (4, 3)] 831841744
  2      [(4, 4), (4, 3)] 1423500752
  2      [(5, 2), (5, 3)] 2075715024

Pre-uniquify: 105
Post-uniquify: 105
All 105 moves: 
 17 Loop [(4, 3), (4, 4), (5, 4), (5, 3), (4, 3)] -86374027
 17 Loop [(4, 4), (4, 3), (5, 3), (5, 4), (4, 4)] -86374027
 17 Loop [(5, 3), (4, 3), (4, 4), (5, 4), (5, 3)] -86374027
 17 Loop [(5, 4), (4, 4), (4, 3), (5, 3), (5, 4)] -86374027
 17 Loop [(5, 2), (5, 3), (4, 3), (4, 4), (5, 4), (5, 3)] -86374027
 17 Loop [(5, 3), (4, 3), (4, 4), (5, 4), (5, 3), (5, 2)] -86374027
 17 Loop [(5, 4), (4, 4), (4, 3), (5, 3), (5, 4), (5, 5)] -86374027
 17 Loop [(5, 5), (5, 4), (4, 4), (4, 3), (5, 3), (5, 4)] -86374027
 10 Loop [(0, 0), (0, 1), (1, 1), (1, 0), (0, 0)] -834522920
 10 Loop [(0, 1), (0, 0), (1, 0), (1, 1), (0, 1)] -834522920
 10 Loop [(1, 0), (0, 0), (0, 1), (1, 1), (1, 0)] -834522920
 10 Loop [(1, 1), (0, 1), (0, 0), (1, 0), (1, 1)] -834522920
 10 Loop [(1, 1), (0, 1), (0, 0), (1, 0), (1, 1), (1, 2)] -834522920
 10 Loop [(1, 2), (1, 1), (0, 1), (0, 0), (1, 0), (1, 1)] -834522920
  6      [(5, 2), (5, 3), (4, 3), (4, 4), (5, 4), (5, 5)] 1195567956
  6      [(5, 5), (5, 4), (4, 4), (4, 3), (5, 3), (5, 2)] 1195567956
  5      [(0, 1), (0, 0), (1, 0), (1, 1), (1, 2)] -1697404439

...
Peaches491
  • 1,239
  • 15
  • 27