2

I'm working on a 1D Game of Life (based upon the rules set out here at Mathworld). Essentially, each generation is represented as a row of 0's or 1's (dead or alive) and the next generation is created based upon the binary representation of a "rule" command line argument.

For example, rule 30 turns into 00011110 (binary for 30) and this is used to determine which patterns of bits will spawn new cells or die off themselves in the subsequent generation.

In order to program this, I need to be able to access bits in groups of three (to apply a rule to) from the previous row. Below is a sample image (note that the starting row is always 0's with a central 1):

00000100000  #seed row
11001011001  #generated from seed row
...........
11110010101  #n-th row, generated from n-1 row

In order to generate a row, I must look at the bits from the row above in groups of three and then apply the rule as a 1/0, live/die decision.

Basically I plan to match the 3 bit pattern and the rule and use that to print either a 0 or a 1 for the offspring. this is the general algo:

if three_bit_pattern == 'xxx' && rule[x] == 0/1 {print 0/1} else {print 1/0}

The portion of the program where I am having difficulties is in accessing the contents of the previous row. All my attempts yield garbage or incorrect data.

In short, how would I access the previous row's values in groups of three bits?

The rows are created like this:

int i, j, k;
int row = atoi(argv[1]) + 1;
int col = 2 * atoi(argv[1]) + 1;

int arr[col];
int output[col];

char rule[9]; //binary representation of rule (2^8 stores up to 255 + null term)
int2binary(atoi(argv[2]), &rule, 10);

for(i = 0; i < row; i++){
   for(j = 0; j < col; j++){
    if(i == 0){
        if(j == col / 2) //print 1 in center of first row
        arr[i] = 1;     
        else
        arr[i] = 0;
        printf("%d", arr[i]);
    }
    else{
        //output[i] = arr[i-1];
        output[i+1] = arr[i];
        output[i+2] = arr[i+1];
        output[i+3] = arr[i+2];
        printf("%s", output);
    }
    }//end inner for_loop
   printf("\n");
}//end outer for_loop

}

Ok so I made this a whole lot simpler and am just going to have two arrays (one holding the previous column and one with the current). What I don't understand is why printing the output array produces garbage? Is output[i] = arr[i] not a valid expression?

Richard Martinez
  • 692
  • 1
  • 8
  • 16
  • You don't show the code that doesn't work. It is thoroughly impossible to divine why an invisible piece of code doesn't work. Show all the code. – n. m. could be an AI Sep 18 '11 at 05:36
  • So, it the row index called "row" or "i"? For the first row, I'd probably use 0; waiting to introduce a variable until the value needs to vary. – luser droog Sep 18 '11 at 05:44
  • That's true. Right now I don't have any code (I've been taking out non-working tries), but I'll edit the post to reflect some of the attempts. – Richard Martinez Sep 18 '11 at 05:47

1 Answers1

2

You haven't specified the inputs or outputs, which might influence the data structures to use. For example, you might only have to keep two rows or even just one row if you print them out as you compute them. It looks like you plan to keep all the rows in an array.

It looks like you have a logic error in the initial row:

    if(firstTime == 1){
        if(j == row-1) //print 1 in center of first row
            arr[i][j] = 1;      
        else
            arr[i][j] = 0;
    }

should probably be

    if(i == 0){
        if(j == col / 2) //print 1 in center of first row
            arr[i][j] = 1;      
        else
            arr[i][j] = 0;
    }

or something even simpler.

The algorithm to generate the other rows is not that complicated.

1) build a number from 0 to 7 using the elements of the row above.

2) Bitwise & 1<<(number from 1) with the rule to get result

parent = 0;
if(j>0 && arr[i-1][j-1]) parent = 4;
if(arr[i-1][j]) parent += 2;
if(j<col-1 && arr[i-1][j+1]) parent += 1;

position = 1 << parent;
arr[i][j] = (rule & position)?1:0;

There are some obvious ways to make this quicker. E.g., build the parent for this column based on the parent of the previous column and the cell to the upper right: & with 3, shift left, | with cell contents. The only ugly part is handling the first and last columns separately.

EDIT IN RESPONSE TO A COMMENT:

The algorithm has some natural implementations in integers with bit operations, which is where the "rule XX" idea comes from.

At its heart, the choice for the current space is determined by the three spaces above it. There are 8 possibilities for these. We can think of these as corresponding to the 8 bits of a byte.

Each rule is a correspondence from the set of 8 possibilities to the set {0,1}. There are 2^8 = 256 possible correspondences or rules, which coincidentally is the same as the number of possible values for a byte.

The most convenient way to label the rules is with a number that shows exactly how the current cell is to be filled as determined by the parent cells. For example,

rule 30:

30 = 16 + 8 + 4 + 2 = 2^4 + 2^3 + 2^2 + 2^1

So the rule is to fill the cell when the parent cells are:

4 = 100
3 = 011
2 = 010
1 = 001

For another example, what is the rule that merely copies the previous row?

In this case we fill in the cell if the cell above is filled, but the neighbouring cells can be anything:

010 = 2
011 = 3
110 = 6
111 = 7

So this is rule 2^2 + 2^3 + 2^6 + 2^7 = rule 4 + 8 + 64 + 128 = rule 204.

I hope the algorithm to determine the cell makes more sense now.

1) determine the number of the pattern of the parents.

2) determine if 2^pattern is part of the rule. If so, fill in the cell.

The other comment I had was how much you need to store. If you output as you go, you only need one row of the array (that is, only one dimension). As you traverse the row, you can replace entries with values for the next row. The only difficulty is that you need to somehow keep the current value that you are replacing to use in determining the next cell.

But you can keep this value and reduce the amount of computation with the same trick: keep the last parent number; & it with 3 to remove the left parent; shift it left by 1; | it with the parent on the right. This gives you the current parent number. Be careful to handle the end entries of the array appropriately, and you're done.

ANOTHER EDIT:

Implement the previous version first, but if you really want to get crazy on saving space, and warp your mind even more, try storing the row as bit values of an integer instead of an array of 1s and 0s. If you want a row even longer than the number of bits in a long, then you need an array of integers holding the bits, and some crazy bit manipulation to handle cells on the boundary of two such integers. Have fun!

UncleO
  • 8,299
  • 21
  • 29
  • You are right about the two minor fixes. Both do the same thing as my code but are more correct. Can you explain what the parent variable is holding? What is it keeping track of? – Richard Martinez Sep 18 '11 at 06:17
  • It seems that part 1 of your algo is where I am stuck. I am unable to pull the values from the row above. I would think that something as simple as next_gen[x] = prev_gen[x], but that doesn't seem to work correctly. – Richard Martinez Sep 18 '11 at 06:37