@stratos said:
i'm really looking for comment on how i could have implemented it beter, especially on the part of python specific implementations
This is a difficult question to answer, because your program is quite long. Instead of writing a number of paragraphs on this, I've written an alternative implementation in Python which makes more use of classes, generators and comprehensions than yours does. It has more or less the same functionality, so far as I can tell:
neighbour_deltas = [(1, 0), (-1, 0), (1, 1), (-1, 1),
(0, 1), (0, -1), (-1, -1), (1, -1)]
class Board:
cell = 'X'
blank = ' '
def __init__(self, (width, height)):
self.content = [[self.blank for x in xrange(width)] for y in xrange(height)]
self.width, self.height = width, height
def in_bounds(self, (x, y)):
return x >= 0 and x < self.width and y >= 0 and y < self.height
def get_neighbours(self, (x, y)):
neighbours = [(x + dx, y + dy) for dx, dy in neighbour_deltas]
return filter(self.in_bounds, neighbours)
def is_cell(self, (x, y)):
return self.content[y][x] == self.cell
def add(self, (x, y)):
self.content[y][x] = self.cell
def add_many(self, *seq):
for pos in seq: self.add(pos)
def add_predicate(self, predicate):
for pos in self.coords():
if predicate(pos): self.add(pos)
def remove(self, (x, y)):
self.content[y][x] = self.blank
def is_alive(self, pos):
n = len(filter(self.is_cell, self.get_neighbours(pos)))
return n == 3 or (self.is_cell(pos) and n >= 2 and n <= 3)
def coords(self):
for x in xrange(self.width):
for y in xrange(self.height):
yield x, y
def take_turn(self):
births, deaths = [], []
for pos in self.coords():
if self.is_alive(pos):
if not self.is_cell(pos):
births.append(pos)
elif self.is_cell(pos):
deaths.append(pos)
for cell in births: self.add(cell)
for cell in deaths: self.remove(cell)
def __repr__(self):
return "\n".join(" ".join(cell for cell in row) for row in self.content)
import random, time
def construct_board():
board = Board((50, 50))
# insert a glider
board.add_many((11, 11), (11, 12), (11, 13), (12, 11), (13, 12))
# fill the wall
board.add_predicate(lambda (x, y): x == 1 or y == 1)
# put some random stuff in
board.add_predicate(lambda _: random.randint(1, 10) == 1)
return board
if __name__ == '__main__':
board = construct_board()
print board
raw_input("press enter")
for i in xrange(1, 501):
begin = time.time()
board.take_turn()
print time.time() - begin
print board
time.sleep(0.2)
The above code uses nested lists to maintain the cells, but it's not too hard to change this to a hash. Just replace the __init__, add, remove and is_cell functions:
def __init__(self, (width, height)):
self.content = {}
self.width, self.height = width, height
def is_cell(self, position):
return self.content[position] == self.cell
def add(self, position):
self.content[position] = self.cell
def remove(self, position):
self.content[position] = self.blank
I thought about designing it to take an storage object of some kind, so you could use a list, dict, or whatever structure you wanted to store the data. However time was short, and it sounded a bit too much like feature creep.