1

I have been debugging my implementation of Game of Life, and my main problem looks like its coming from how I use arrays.

public boolean[][] oldState;
public boolean[][] newState;
private boolean gameState = true;

public LifeBoard(Seed seed) {
    oldState = seed.getSeed();
    newState = new boolean[oldState.length][oldState[0].length];
    run();
}

public void run() {
    //debug code to run for x generations
    for (int i = 0; i < 5; i++) {
        BoardPrinter.print(oldState);
        evaluateCells();
        oldState = newState;        
    }
    BoardPrinter.print(oldState);
    System.out.println("game over");
}

the boolean[][] from Seed is a 5x5 grid, all false (dead) except the 3 horizontal middle cells in the middle row

00000
00000
0+++0
00000
00000

evaluateCells() looks at each cell in the grid, looks at the 8 cells around it, counts them, and based on the number of neighbors it writes a new value to newState.

What should happen: use oldState to calculate newState, copy newState to oldState, then go back through newState, writing each cell again based on the new oldState.

What really happens: the first generation works correctly, but after that the results are increasingly weird, it evaluates cells to be false that I know to be true, etc. The problem seems to be in the way I am copying the arrays.

If I initialize a 3rd blank array blankState[][] = new boolean[5][5]; and during the loop in run say:

public void run() {
    //debug code to run for x generations
    for (int i = 0; i < 5; i++) {
        BoardPrinter.print(oldState);
        evaluateCells();
        oldState = newState;
            newState = blankState;
    }
    BoardPrinter.print(oldState);
    System.out.println("game over");
}

...then the game works correctly for an additional 1 generation, then the weird garbage returns.

I have 2 questions: first, it looks like I have to use System.arraycopy(), but unless someone tells me about a version for multidimensional arrays, I will have to write a simple loop.

My real question: why do you have to use this special System method to copy an array? Why can't you use the = operator?

EDIT: the conceptual answer is accepted below. Here is the code that solved the implementation problem:

for (int n = 0; n < oldState.length; n++) {
            System.arraycopy(newState[n], 0, oldState[n], 0, oldState.length);
}
for (int t = 0; t < newState.length; t++) {
            System.arraycopy(blankState[t], 0, newState[t], 0, newState.length);
}

Also for the record, System.arraycopy(boolean[][], 0, boolean[][], 0, boolean.length); did not work correctly, you have to iterate through each line.

nexus_2006
  • 744
  • 2
  • 14
  • 29

2 Answers2

6

My real question: why do you have to use this special System method to copy an array? Why can't you use the = operator?

This is actually an important Java lesson, so pay attention. Are you paying attention? Good. This will be important in the future.

Now, this applies for all objects in Java, as arrays are objects. If you use = then you only set the reference, and encounter all kinds of fun as seen here. Namely, if I have a simple class with a getter and setter called TestClass with a public int test, then the following code will work:

TestClass t=new TestClass();
t.test=1;
TestClass t1=t;
t1.test=6;
System.out.println(t.test); //prints 6.

Now, why? Because the references t and t1 point to the same object on the heap. And this holds for arrays as well. To get copies, you need to perform tasks that are object-specific. Some let you call clone() directly(Cloneable interface), some let you pass another instance into the constructor to get a new instance(Like the ArrayList constructor), and some use utility methods, like arrays here.

Community
  • 1
  • 1
nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • Ok, that makes sense, I hadn't realized/remembered arrays were objects, I was thinking that arrays of primitive types were also primitive types. – nexus_2006 Sep 12 '13 at 23:10
  • @nexus_2006 No, primitive arrays could have caused a big hit for performance when being passed around. They live on the heap, and live and die with other objects. – nanofarad Sep 12 '13 at 23:11
  • 1
    Oh, I see. arrays can be huge, and primitives would be duplicated whereas objects can simply move. – nexus_2006 Sep 12 '13 at 23:17
1

evaluateCells() looks at each cell in the grid, looks at the 8 cells around it, counts them, and based on the number of neighbors it writes a new value to newState.

What should happen: use oldState to calculate newState, copy newState to oldState, then go back through newState, writing each cell again based on the new oldState.

What really happens: the first generation works correctly, but after that the results are increasingly weird, it evaluates cells to be false that I know to be true, etc. The problem seems to be in the way I am copying the arrays.

Without seeing your bit shifting code, I'd bet this is caused by a higher level problem. Most likely your bit shifting algorithm has a bug somewhere.

Have you stepped through your code with Eclipse's debugger? If not, read this tutorial and try a few different seeds. This will tell you where, if anywhere, in your algorithm the bit shift error occurs.

http://www.vogella.com/articles/EclipseDebugging/article.html

JaneGoodall
  • 1,478
  • 2
  • 15
  • 22
  • 1
    Thanks for the input, but I'm very sure the model works, after I started copying the 2d arrays correctly, the code works great with no further refinements - all seeds I give it work as expected, oscillators, pulsars, spaceships, puffer trains, etc. I wrote this entire app with command line tools and gedit, but I do use Eclipse for Android dev, thanks for the link. – nexus_2006 Sep 13 '13 at 02:08