Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Game of Life---EDGES?

2,075 views
Skip to first unread message

Deener

unread,
May 31, 2002, 1:35:19 PM5/31/02
to
Hi There!

I am working on programming a simple version of Conway's Game of Life,
but I am stuck as to how to go about checking all the edges (right now
I am ignoring them so they just stay at their default values). I know
one idea would be to make the board wrap around, but I don't really
get how that works in terms of the coding, so I'm guessing it may be
easier if I just find a way to check the edges while keeping it a
finite and bounded board. I know that for the first row (excluding the
corner) you would check:
[r][c-1], [r][c+1], [r+1][c-1], [r+1][c], [r+1][c+1]
and for the last row, which is somewhat simmilar you would check:
[r][c-1], [r][c+1], [r-1][c-1], [r-1][c], [r-1][c+1]
Similarly for the first column you would check:
[r-1][c], [r-1][c+1], [r][c+1], [r+1][c], [r+1][c+1]
and for the last column you would check:
[r-1][c], [r-1][c-1], [r][c-1], [r+1][c], [r+1][c-1]
Finally, for the CORNERS, you would check:
Top Right: [0][1], [1][0], [1][1]
Top Left: [0][8], [1][9], [1][8]
Bottom Right: [9][1], [8][0], [8][1]
Bottom Left: [9][8], [8][9], [8][8]
(phew!) but my problem is I'm not quite sure how to put that into
actual code though I'm smelling some more for loops and conditionals
=-P (I just can't figure out wha thte conditions for each loop and
within the loops and stuff)
Any help you could provide would be greatly appreciated =)

Simon Righarts

unread,
Jun 1, 2002, 1:41:48 AM6/1/02
to

"Deener" <Deen...@aol.com> wrote in message
news:a2fc42c4.02053...@posting.google.com...

I posted this over in c.l.j.programmer as well, but I guess you didn't see
it

Assuming you're still running with the same example I fixed for you in
c.l.j.p, then this is how I did edge-testing

public static int numOfNeighbors(int row,int col) {
int numNeighbors = 0;

if (CurrentGen[(row-1+x)%x][(col-1+y)%y] == 1){ numNeighbors++;}
if (CurrentGen[(row-1+x)%x][col] == 1){ numNeighbors++;}
if (CurrentGen[(row-1+x)%x][(col+1)%y] == 1){ numNeighbors++;}
if (CurrentGen[row][(col-1+y)%y] == 1){ numNeighbors++;}
if (CurrentGen[row][(col+1)%y] == 1){ numNeighbors++;}
if (CurrentGen[(row+1)%x][(col-1+y)%y] == 1){ numNeighbors++;}
if (CurrentGen[(row+1)%x][col] == 1){ numNeighbors++;}
if (CurrentGen[(row+1)%x][(col+1)%y] == 1){ numNeighbors++;}
return numNeighbors;
}
x and y are static data fields, set to the dimensions of the array, row &
col are the position you're currently interested in, and the bit that does
the actual edge correction is inside the array reference:
CurrentGen[(row-1+x)%x][(col-1+y)%y]
% is the modulo operator - eg. x=10
row+1: row+1%x
1 1
2 2
... ....
8 8
9 9
10 0

Spot the difference? Basically, '% x' removes any multiples of x from the
number before that, spitting out a number -x > n > x. Because (-1 % x) is
still -1 (we'd then get a ArrayIndexOutOfBoundsException), we add x so we
get a positive result.
With me? If you ain't, I've posted my code @
http://www.geocities.com/rigsi397nz/LifeApp.java - it's an extension of your
concept, with variable width & height - modify x & y to change dimensions.
I've done the initial setup a little differently too ..... now, 'fill' is
used to represent the chance that any given cell will be set to alive :-)

Patricia Shanahan

unread,
Jun 2, 2002, 8:30:44 AM6/2/02
to

Deener wrote:
>
> Hi There!
>
> I am working on programming a simple version of Conway's Game of Life,
> but I am stuck as to how to go about checking all the edges (right now
> I am ignoring them so they just stay at their default values). I know
> one idea would be to make the board wrap around, but I don't really
> get how that works in terms of the coding, so I'm guessing it may be
> easier if I just find a way to check the edges while keeping it a
> finite and bounded board. I know that for the first row (excluding the
> corner) you would check:

...

If you want to do the wrapping, use % as Simon Righarts suggested.

Another general approach to edges is add a border of non-displayed cells
around the outside of your displayed cells, increasing each dimension by
a total of 2.

Have a third cell state, "edge". An edge cell remains an edge cell
regardless of the state of its neighbours. However, you can now set the
life/death rules for other cells to take into account the number of
adjacent edge cells as well as the number of adjacent live cells.

Patricia

Deener

unread,
Jun 3, 2002, 6:01:22 PM6/3/02
to
"Simon Righarts" <righ...@xtra.com.nz> wrote in message news:<r6ZJ8.6425$EZ5.6...@news.xtra.co.nz>...

> I posted this over in c.l.j.programmer as well, but I guess you didn't see
> it

Yeah, sorry, I didn't. =-P

Aaah...I see...thanks for the explanation. I had come up with a
different way to avoid ArrayOutOfBoundsExceptions when checking the
edges, simply:

if ((r-1)>=0 && (c-1)>=0 && (r-1)<x && (c-1)<y && CurrentGen[r-1][c-1]
== 1) {
numNeighbors++;
}

if ((r-1)>=0 && c>=0 && (r-1)<x && c<y && CurrentGen[r-1][c] ==1) {
numNeighbors++;
}

if ((r-1)>=0 && (c+1)>=0 && (r-1)<x && (c+1)<y && CurrentGen[r-1][c+1]
==1) {
numNeighbors++;
}

if (r>=0 && (c-1)>=0 && r<x && (c-1)<y && CurrentGen[r][c-1] ==1) {
numNeighbors++;
}

if (r>=0 && (c+1)>=0 && r<x && (c+1)<y && CurrentGen[r][c+1] ==1) {
numNeighbors++;
}

if ((r+1)>=0 && (c-1)>=0 && (r+1)<x && (c-1)<y &&
CurrentGen[r+1][c-1]==1){
numNeighbors++;
}

if ((r+1)>=0 && c>=0 && (r+1)<x && c<y && CurrentGen[r+1][c] ==1){
numNeighbors++;
}

if ((r+1)>=0 && (c+1)>=0 && (r+1)<x && (c+1)<y &&
CurrentGen[r+1][c+1]==1){
numNeighbors++;
}

return numNeighbors;

but having the board wrap around provides a finite but *unbounded*
board, which I like much better. Thanks so much! =)

Oh, right...I like your idea of using static variables for the width
and height, so that you can easily change the dimensions. Actually, I
extended that a bit and now added some code prompting the user to
indicate the desired dimensions (though, in my case, the mimimum
possible is 10 by 10 to avoid an AOOB exception since I already have
pre-determined start patterns (which users can choose from) made with
a 10 by 10 in mind. What is wierd though, is that the program compiled
correctly, but then when it was running I got an
ArrayIndexOutOfBoundsException and I can't seem to fix it. When I
assigned values to my static ints x and y and commented out the user
prompting code, the program worked perfectly, so I know the error most
likely lies somewhere in the user-prompting code, but everything seems
fine to me. I think for some reason the JVM is reading whatever number
I type in first (which is when you're prompted to choose a start
pattern between 1 and 7) as the dimensions, but I'm not sure why. I
will continue to work on it, but if you have any ides that would be
greatly apprecited as well. =)

My code would probably be helpful =-P so here it is (happy to say that
it is a MUCH better version than what I had before...well, at least
more interesting =):

public class GameOfLife2 {

//static int userWidth;
//static int userHeight;
static int x; // static variable corresponding to the width of the
board (later specified by the user)
static int y; // static variable corresponding to the heigth of the
board (later specified by the user)

static int[][] CurrentGen = new int[x][y];
static int[][] NextGen = new int[x][y];

public static void main(String[] args) {

BufferedReader reader = new BufferedReader(new
InputStreamReader(System.in));
boolean gotValidNumGen = false;
int numGen = 0;
boolean gotValidNumber = false;
int inputNumber = 0;
int secPause = 0;
boolean gotValidPause = false;
//int x;
//int y;
boolean gotValidWidth = false;
boolean gotValidHeight = false;

for (int i = 0; i <x; i++) { // initializing elements of
CurrentGen[][] to 0
for (int j = 0; j<y; j++) {
CurrentGen[i][j] = 0;
}
}

// prompting user for a start pattern (with exception-handling):

do {

System.out.println("\nPlease choose a starting pattern by typing the
integer corresponding to the choice you would like.");
System.out.println();
System.out.println("(1) Cross ");
System.out.println("(2) Oscillator ");
System.out.println("(3) Glider ");
System.out.println("(4) R-pentamino ");
System.out.println("(5) Exploder ");
System.out.println("(6) Still Life ");
System.out.println("(7) Randomly generated pattern");

try {
inputNumber = Integer.parseInt(reader.readLine());
gotValidNumber = true;
}

catch (NumberFormatException nfe) {
System.out.println("That is not a valid integer. Please try
again.");
}

catch (IOException ioe) {
System.out.println("I/O Exception occurred");
}
}

while (!gotValidNumber);

switch (inputNumber) {

case 1: // setting cross pattern

for (int j= 0; j<10; j++)
CurrentGen[4][j] = 1;

for (int i= 0; i<10; i++)
CurrentGen[i][4] = 1;

break;

case 2: // setting oscillator pattern

for (int j= 4; j<=6; j++)
CurrentGen[3][j] = 1;

for (int j= 3; j<=5; j++)
CurrentGen[4][j] = 1;

break;

case 3: // setting glider pattern

CurrentGen[2][1] = 1;
CurrentGen[2][3] = 1;
CurrentGen[3][2] = 1;
CurrentGen[3][3]= 1;
CurrentGen[1][3] = 1;

break;

case 4: // setting R-pentamino pattern

CurrentGen[3][4] = 1;
CurrentGen[3][5] = 1;
CurrentGen[4][3] = 1;
CurrentGen[4][4] =1;
CurrentGen[5][4] = 1;

break;

case 5: // setting exploder pattern

CurrentGen[3][5] = 1;
CurrentGen[4][4] = 1;
CurrentGen[4][5] = 1;
CurrentGen[4][6] = 1;
CurrentGen[5][4] = 1;
CurrentGen[5][6] = 1;
CurrentGen[6][5] = 1;

break;

case 6: // setting still-life pattern

CurrentGen[2][4] = 1;
CurrentGen[2][5] = 1;
CurrentGen[3][3] = 1;
CurrentGen[3][5] = 1;
CurrentGen[4][3] = 1;
CurrentGen[4][4] = 1;

break;

case 7: // setting random pattern

for (int i = 0; i <x; i++) {
for (int j = 0; j<y; j++) {
CurrentGen[i][j] = (int)(Math.random()*2);
}
}
}

for (int s = 0; s<=0; s++) {
// prompting user for the desired board size (with
exception-handling):

do {

System.out.println();
System.out.println("What dimensions would you like the board to
have?");
System.out.println();
System.out.println("When prompted, please type an integer
corresponding to the desired width and height of the board.");
System.out.println("The MINIMUM possible dimensions are 10 by 10.");
System.out.println();
System.out.print("What is the width you would like? ");
try {
x = Integer.parseInt(reader.readLine());
gotValidWidth =true;
}

catch (NumberFormatException nfe) {
gotValidWidth = false;
System.out.println("That is not a valid integer. Please try
again.");
}
catch (IOException ioe) { }

}
while (!gotValidWidth);
}
//if (x < 10) {
//System.out.println("Sorry, but that is not a valid width. (The
minimum possible width is 10). The default width of 10 will be
used.");
//x = 10;
//}
for (int s = 0; s<=0; s++) {
do {
System.out.println();
System.out.print("What is the height you would like? ");

try {
y = Integer.parseInt(reader.readLine());
gotValidHeight = true;

}

catch (NumberFormatException nfe) {
gotValidHeight = false;
System.out.println("That is not a valid integer. Please try
again.");
}
catch (IOException ioe) { }
}

while (!gotValidHeight);

//if (y < 10) {

//System.out.println("Sorry, but that is not a valid height. (The
minimum possible height is 10). The default height of 10 will be
used.");
//y = 10;
//}
}
// prompting user for the desired number of generations to be
generated (with exception-handling):

do {

System.out.println();
System.out.print("How many generations would you like to be
generated? (please type an integer corresponding to that number): ");

try {

numGen = Integer.parseInt(reader.readLine());
gotValidNumGen =true;
}

catch (NumberFormatException nfe) {
System.out.println("That is not a valid integer. Please try
again.");
gotValidNumGen = false;
}
catch (IOException ioe) { }
}

while (!gotValidNumGen);

// prompting user for the desired pause between generations (with
exception-handling):

do {

System.out.println();
System.out.print("How much of a pause would you like between
generations? (please type an integer corresponding to the # of
seconds) ");

try {

secPause = Integer.parseInt(reader.readLine());
gotValidPause =true;
}

catch (NumberFormatException nfe) {
System.out.println("That is not a valid integer. Please try
again.");
}
catch (IOException ioe) { }
}

while (!gotValidPause);

// printing start pattern:
System.out.println("\nInitial generation: ");
System.out.println();
for (int i = 0; i <CurrentGen.length; i++) {
for (int j = 0; j<CurrentGen[i].length; j++)
if (CurrentGen[i][j] == 1)
System.out.print("* ");
else
System.out.print("- ");

System.out.println();
}

for(int z = 1; z<= numGen; z++){ // having the
Game iterate however many times the user specified

NextGeneration(); // call to
method which determines the next generation

for(int p = 0; p<=(100000000 * secPause); p++){
} //
pausing the amount specified by the user (before next generation is
printed)

System.out.println();
System.out.println("Here comes generation " + z +"...");
System.out.println();
// printing next generation
for (int i = 0; i <CurrentGen.length; i++) {
for (int j = 0; j<CurrentGen[i].length; j++)
if (CurrentGen[i][j] == 1)
System.out.print("* ");
else
System.out.print("- ");
System.out.println();
}
}
}

/************Method to determine number of neighbors of a given
cell***************/

public static int numOfNeighbors(int r, int c) {

int numNeighbors = 0; // initializing the number of neighbors
to 0

if ((r-1)>=0 && (c-1)>=0 && (r-1)<x && (c-1)<y &&
CurrentGen[r-1][c-1] == 1) {
numNeighbors++;
}

if ((r-1)>=0 && c>=0 && (r-1)<x && c<y && CurrentGen[r-1][c] ==1) {
numNeighbors++;
}

if ((r-1)>=0 && (c+1)>=0 && (r-1)<x && (c+1)<y &&
CurrentGen[r-1][c+1] ==1) {
numNeighbors++;
}

if (r>=0 && (c-1)>=0 && r<x && (c-1)<y && CurrentGen[r][c-1] ==1) {
numNeighbors++;
}

if (r>=0 && (c+1)>=0 && r<x && (c+1)<y && CurrentGen[r][c+1] ==1) {
numNeighbors++;
}

if ((r+1)>=0 && (c-1)>=0 && (r+1)<x && (c-1)<y &&
CurrentGen[r+1][c-1]==1){
numNeighbors++;
}

if ((r+1)>=0 && c>=0 && (r+1)<x && c<y && CurrentGen[r+1][c] ==1){
numNeighbors++;
}

if ((r+1)>=0 && (c+1)>=0 && (r+1)<x && (c+1)<y &&
CurrentGen[r+1][c+1]==1){
numNeighbors++;
}

return numNeighbors;
}


/***going through a generation and applying the rules to determine the
next generation***/

public static void NextGeneration() {

for (int r = 0; r< x; r++) {
for (int c = 0; c<y; c++)
{
int numOfNeighbors = numOfNeighbors(r,c); // getting the number of
neighbors


/***Conway's rules***/

switch (numOfNeighbors) {

case 2:

NextGen[r][c] = CurrentGen[r][c]; // a cell, whether occupied or
empty,
break; // will
stay the same if it has 2 neighbors

case 3:

NextGen[r][c] = 1; // an occupied cell with 3 neighbors will
stay occupied
break; // an empty cell with 3 neighbors will become occupied

default:

NextGen[r][c] = 0; // otherwise, a cell stays empty or becomes
empty
} // (b/c it had more than
3 or less than 2 neighbors)

}
}

/**when finished checking, copy NextGen to CurrentGen**/

for (int i = 0; i<x; i++) {
for (int j = 0; j<y; j++)
CurrentGen[i][j] = NextGen[i][j] ;

}
}
}

Once again, thanks for all of your help! =)

Deener

unread,
Jun 3, 2002, 6:04:30 PM6/3/02
to
Patricia Shanahan <pa...@acm.org> wrote in message news:<3CFA104F...@acm.org>...

>
> Another general approach to edges is add a border of non-displayed cells
> around the outside of your displayed cells, increasing each dimension by
> a total of 2.
Hi!

Thanks for the suggestion! Yeah, I had originally just had a border of
unused cells (initialized them to "empty" and then just didnt have the
checked when determining the number of neighbors of a given cell) but
thats bending the rules a bit I think, so I wanted to see if there was
a better way. Your idea of having 3 states for the cells however is a
good one...thanks. =)

Thalius

unread,
Jun 5, 2002, 11:19:01 AM6/5/02
to
Hello,

Wouldn't it be simpler to use OOP to implement the game? Each cell would be
an object with value, neighbours and nextGeneration method.
It seems easier to code...
Has anybody tried this already (I suppose so! ;-) )?

greetings,
Ricardo

"Simon Righarts" <righ...@xtra.com.nz> wrote in message
news:r6ZJ8.6425$EZ5.6...@news.xtra.co.nz...
>

Simon Righarts

unread,
Jun 6, 2002, 11:07:36 AM6/6/02
to

"Thalius" <Tha...@hotmail.com> wrote in message
news:adlaab$ks1$1...@snic.vub.ac.be...

> Hello,
>
> Wouldn't it be simpler to use OOP to implement the game? Each cell would
be
> an object with value, neighbours and nextGeneration method.
> It seems easier to code...
> Has anybody tried this already (I suppose so! ;-) )?

I haven't :-) What I do have is a static method that will take a boolean[][]
and stuff the next generation back into that same array, and (once I figured
it out) it was pretty simple :-)

OOP probably would work, but for this case, it's probably too complicated,
given that:
A: you only really have to store the state (alive/dead)
B: You'd have to recompute the neighbour count every time, so might as well
not store it :-)

Unless you're doing some variant of the game that requires multiple data
fields to be stored (i.e. maybe how long it's been alive or dead for,
longest alive-time etc.), one boolean[][] array covers the data
requirements:-)

If you want to see the code, e-mail me (it's @xtra.co.nz, not @xtra.com.nz)


Deener

unread,
Jun 6, 2002, 7:19:42 PM6/6/02
to
Simon Righarts" <righ...@xtra.com.nz> wrote in message news:<r6ZJ8.6425$EZ5.6...@news.xtra.co.nz>...
> I posted this over in c.l.j.programmer as well, but I guess you didn't see
> it

Yeah, sorry, I didn't. =-P

Aaah...I see...thanks for the explanation. I had come up with a

Deener

unread,
Jun 7, 2002, 4:21:12 AM6/7/02
to
Never mind...I think I got it...looks like my arrays were being
intialized to 0 because x and y werent initialized (and I think JVM
automatically initializes them to 0 in that case)...now just gotta
declare the static arrays in the beginning but initialize them AFTER x
and y are initialized...hopefully that will fix the problem! Thanks.
0 new messages