Here's my Python implementation of Conway's Game of Life:
class Game(object):
def __init__(self, state, infinite_board = True):
self.state = state
self.width = state.width
self.height = state.height
self.infinite_board = infinite_board
def step(self, count = 1):
for generation in range(count):
new_board = [[False] * self.width for row in range(self.height)]
for y, row in enumerate(self.state.board):
for x, cell in enumerate(row):
neighbours = self.neighbours(x, y)
previous_state = self.state.board[y][x]
should_live = neighbours == 3 or (neighbours == 2 and previous_state == True)
new_board[y][x] = should_live
self.state.board = new_board
def neighbours(self, x, y):
count = 0
for hor in [-1, 0, 1]:
for ver in [-1, 0, 1]:
if not hor == ver == 0 and (self.infinite_board == True or (0 <= x + hor < self.width and 0 <= y + ver < self.height)):
count += self.state.board[(y + ver) % self.height][(x + hor) % self.width]
return count
def display(self):
return self.state.display()
class State(object):
def __init__(self, positions, x, y, width, height):
active_cells = []
for y, row in enumerate(positions.splitlines()):
for x, cell in enumerate(row.strip()):
if cell == 'o':
active_cells.append((x,y))
board = [[False] * width for row in range(height)]
for cell in active_cells:
board[cell[1] + y][cell[0] + x] = True
self.board = board
self.width = width
self.height = height
def display(self):
output = ''
for y, row in enumerate(self.board):
for x, cell in enumerate(row):
if self.board[y][x]:
output += ' o'
else:
output += ' .'
output += '\n'
return output
glider = """ oo.
o.o
o.. """
my_game = Game(State(glider, x = 2, y = 3, width = 10, height = 10))
print my_game.display()
my_game.step(27)
print my_game.display()
Output:
. . . . . . . . . . . . . . . . . . . . . . o o . . . . . . . . o . o . . . . . . . o . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . o . . . . . . . . o o . . . . . . . . o . o . . . . . . . . . . . . . . . . . . . . . .
I have several concerns:
It feels a bit unnatural to write
self.state.board[y][x]
, instead of[x][y]
. However, I thought it would make sense to let the board be an array of rows rather than columns.I'm not sure how to divide the tasks between the two classes. For instance, I could have implemented the
neighbours()
function in theState
class, rather than in theGame
class.I know it's good practice to write a lot of comments, but I found most of this code self-explanatory (though that could be because I've just written it).
I used several nested
for
-loops, but maybe I could replace some with list comprehensions.I could have left out the
display()
function of theGame
class and just writeprint my_game.state.display()
on the last line. Does this simplify things, or does it only make it more complicated?
State
will be ignored as you are redefining them when you use them as loop variables. \$\endgroup\$x
andy
twice, but it's not a bug. Thex
andy
variables passed toState
signify where the passed positions should be placed on the board and they are used infor cell in active_cells: board[cell[1] + y][cell[0] + x] = True
. Those variables are not affected by thex
andy
variables I used in thefor
loops. \$\endgroup\$print x, y
after the loop to see this. \$\endgroup\$__init__
should fix it, though choosing different variable names would be better. Thanks! \$\endgroup\$