Reputation: 422
For learning purpose I've started creating my implementation of Conway's Game of Life. I've used numpy to store big array, contating dead and alive cells, then I've apllied Conway's rules, to create mechanics of cells life. To manage grid, and graphics I used pygame module. After many reviews, and rewriting code in many ways, I can't find out what's wrong with it, so I decided to ask you. For example I've tried to make a glider, (as code shows), but he dies after 3 loop cycles. I'd be appreciate for help and tips. Can you help me find out why the cells aren't reproducing? Thanks in advance. Code:
import pygame
import numpy as np
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
N = 195
WIDTH = 10
HEIGHT = 10
grid = np.zeros(shape=(N, N), dtype=np.int32)
glider = np.array([[0, 0, 1],
[1, 0, 1],
[0, 1, 1]])
grid[3:6, 3:6] = glider
pygame.init()
WINDOW_SIZE = [980, 980]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("GAME OF LIFE")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for row in range(N):
for column in range(N):
color = BLACK
if grid[row][column] == 1:
color = GREEN
pygame.draw.rect(screen, color,
[WIDTH * column,
HEIGHT * row,
WIDTH,
HEIGHT])
newGrid = grid.copy()
for i in range(N):
for j in range(N):
total = grid[(i-1) % N:(i+1) % N, (j-1) % N:(j+1) % N].sum() - grid[i, j]
if grid[i, j] == 1:
if(total < 2) or (total > 3):
newGrid[i, j] = 0
else:
if total == 3:
newGrid[i, j] = 1
grid = newGrid
clock.tick(60)
pygame.display.flip()
pygame.quit()
Upvotes: 0
Views: 1536
Reputation: 3417
Possibly the else clause in the newGrid loop is over-indented? Because as of now, the grid only goes from 1 to 0 and never from 0 to 1. And it's probably because of the array slicing: [(i-1) % n : (i+1) % n]. There are 2 issues:
Here's a trick
a.take(range(-1,2),mode='wrap', axis=0).take(range(-1,2),mode='wrap',axis=1)
from this post Wrap slice around edges of a 2D array in numpy. I've modified code below with this trick.
import pygame
import numpy as np
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
N = 195
WIDTH = 10
HEIGHT = 10
grid = np.zeros(shape=(N, N), dtype=np.int32)
glider = np.array([[0, 0, 1],
[1, 0, 1],
[0, 1, 1]])
grid[3:6, 3:6] = glider
pygame.init()
WINDOW_SIZE = [980, 980]
screen = pygame.display.set_mode(WINDOW_SIZE)
pygame.display.set_caption("GAME OF LIFE")
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
for row in range(N):
for column in range(N):
color = BLACK
if grid[row][column] == 1:
color = GREEN
pygame.draw.rect(screen, color,
[WIDTH * column,
HEIGHT * row,
WIDTH,
HEIGHT])
newGrid = grid.copy()
for i in range(N):
for j in range(N):
total = grid.take(range(i-1,i+2),mode='wrap', axis=0).take(range(j-1,j+2),mode='wrap',axis=1).sum() - grid[i, j]
if grid[i, j] == 1:
if(total < 2) or (total > 3):
newGrid[i, j] = 0
else:
if total == 3:
newGrid[i, j] = 1
grid = newGrid
clock.tick(60)
pygame.display.flip()
pygame.quit()
Upvotes: 0
Reputation: 5914
I think you have a couple of subtle bugs in the way you implement Conway's rules. See my comments in the code for details:
for i in range(N):
for j in range(N):
# I changed the range of the extent of the sum, note +2 rather than +1 !
total = grid[(i-1) % N:(i+2) % N, (j-1) % N:(j+2) % N].sum() - grid[i, j]
if grid[i, j] == 1:
if(total < 2) or (total > 3):
newGrid[i, j] = 0
# allow for survival in case of total = 2 or 3 (this could be dropped though)
else:
newGrid[i, j] = 1
# allow for reproduction if cell is empty
else:
if total == 3:
newGrid[i, j] = 1
With these edits the glider should glide :)
Upvotes: 1