Conway's Game Of Life Not Counting Neighbors Correctly
Solution 1:
You are getting that index error because your newgrid
only contains a single empty row. And your testing for neighbours in newgrid
instead of in grid
(as Blckknght mentions in the comments). I've made a few repairs, but there's a lot more that can be done to improve this code. It looks like it's working now, but it's hard to tell when you're working with random Life forms. :) I suggest giving your program some way of using known Life patterns like blinkers and gliders to see that they behave correctly.
The simplest way to ensure that newgrid
is valid is to copy it from grid
. If we just do newgrid = grid
that simply makes newgrid
another name for the grid
object. To copy a list of lists properly we need to make copies of each of the internal lists. My new code does that with the copy_grid
function.
I've fixed a couple of minor bugs that you had in the if
tests in the section that counts neighbours, and I've simplified the logic that updates a cell from its neighbour count. I've also condensed the code that makes a random grid, and I've added a simple function that can read a Life pattern from a string and build a grid from it. This lets us test the code with a Glider. I've also added a function that makes an empty grid. The program doesn't currently use that function although I used it during my tests, and I guess it's a useful example. :)
import random
# Set a seed so that we get the same random numbers each time we run the program# This makes it easier to test the program during development
random.seed(42)
numrows = 10
numcols = 10
glider = '''\
----------
--O-------
---O------
-OOO------
----------
----------
----------
----------
----------
----------
'''# Make an empty griddefempty_grid():
return [['-'for y inrange(numcols)]
for x inrange(numrows)]
# Make a random griddefrandom_grid():
return [[random.choice('O-') for y inrange(numcols)]
for x inrange(numrows)]
# Make a grid from a pattern stringdefpattern_grid(pattern):
return [list(row) for row in pattern.splitlines()]
# Copy a grid, properly!defcopy_grid(grid):
return [row[:] for row in grid]
# Print a griddefshow_grid(grid):
for row in grid:
print(*row)
print()
defrun(grid):
show_grid(grid)
# Copy the grid to newgrid.
newgrid = copy_grid(grid)
whileTrue:
for r inrange(numrows):
for c inrange(numcols):
# Count the neighbours, making sure that they are in bounds
count = 0# Above this rowif(r-1 > -1and c-1 > -1):
if(grid[r-1][c-1] == 'O'):
count += 1if(r-1 > -1):
if(grid[r-1][c] == 'O'):
count += 1if(r-1 > -1and c+1 < numcols):
if(grid[r-1][c+1] == 'O'):
count += 1# On this rowif(c-1 > -1):
if(grid[r][c-1] == 'O'):
count += 1if(c+1 < numcols):
if(grid[r][c+1] == 'O'):
count += 1# Below this rowif(r+1 < numrows and c-1 > -1):
if(grid[r+1][c-1] == 'O'):
count += 1if(r+1 < numrows):
if(grid[r+1][c] == 'O'):
count += 1if(r+1 < numrows and c+1 < numcols):
if(grid[r+1][c+1] == 'O'):
count += 1# Update the cell in the new gridif grid[r][c] == '-':
if count == 3:
newgrid[r][c] ='O'else:
if count < 2or count> 3:
newgrid[r][c] = '-'# Copy the newgrid to grid
grid = copy_grid(newgrid)
show_grid(grid)
answer = input("Continue? [Y/n]: ")
ifnot answer in'yY':
print(" Hope you had a great life! Goodbye!")
break#grid = random_grid()
grid = pattern_grid(glider)
run(grid)
This code does work correctly, but there is still plenty of room for improvement. For example, here's an improved version of run()
that condenses the neighbour counting section by using a couple of loops.
defrun(grid):
show_grid(grid)
# Copy the grid to newgrid.
newgrid = copy_grid(grid)
whileTrue:
for r inrange(numrows):
for c inrange(numcols):
# Count the neighbours, making sure that they are in bounds# This includes the cell itself in the count
count = 0for y inrange(max(0, r - 1), min(r + 2, numrows)):
for x inrange(max(0, c - 1), min(c + 2, numcols)):
count += grid[y][x] == 'O'# Update the cell in the new gridif grid[r][c] == '-':
if count == 3:
newgrid[r][c] ='O'else:
# Remember, this count includes the cell itselfif count < 3or count > 4:
newgrid[r][c] = '-'# Copy the newgrid to grid
grid = copy_grid(newgrid)
show_grid(grid)
answer = input("Continue? [Y/n]: ")
ifnot answer in'yY':
print(" Hope you had a great life! Goodbye!")
break
Solution 2:
To count the neighbors, just follow this simple rule. You will have the row and col of the current cell. Using that form two arrays, one for rows and another for columns. Below would be your logic.
You can find the detailed implementation with a demo video here.
this.neibhours = function() {
var rows = [row-1, row, row+1];
var cols = [col-1, col, col+1];
neibhourCells = [];
for(var i=0; i < rows.length; i++) {
for(var j=0; j < cols.length; j++) {
if(!(col === cols[j] && row === rows[i])) {
var cell = newCell(rows[i], cols[j])
if(cell.isOnGrid()) {
neibhourCells.push(cell);
}
}
}
}
return neibhourCells;
}
Post a Comment for "Conway's Game Of Life Not Counting Neighbors Correctly"