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 theStateclass, rather than in theGameclass.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 theGameclass and just writeprint my_game.state.display()on the last line. Does this simplify things, or does it only make it more complicated?
Statewill be ignored as you are redefining them when you use them as loop variables. \$\endgroup\$xandytwice, but it's not a bug. Thexandyvariables passed toStatesignify 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 thexandyvariables I used in theforloops. \$\endgroup\$print x, yafter the loop to see this. \$\endgroup\$__init__should fix it, though choosing different variable names would be better. Thanks! \$\endgroup\$