From a7a5fcabf7649f16cf26263953cbed644ed4232d Mon Sep 17 00:00:00 2001 From: Darius Berghe Date: Thu, 8 Dec 2016 12:23:14 +0100 Subject: [PATCH] Fixed Lifeform rules which were causing overpopulation --- .gitignore | 3 ++ universe.py | 89 +++++++++++++++++++++++++------------------------ universeview.py | 28 ++++++++++++---- 3 files changed, 71 insertions(+), 49 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..af5c577 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +.idea +.gitignore diff --git a/universe.py b/universe.py index f2781cf..f4e1518 100644 --- a/universe.py +++ b/universe.py @@ -1,3 +1,11 @@ +from enum import Enum + +class LifeformState(Enum): + dead = 0, + alive = 1, + dying = 2, + resurrecting = 3 + class Lifeform(): def __init__(self, state=False): ''' @@ -5,21 +13,21 @@ def __init__(self, state=False): :param state: True stands for alive, False stands for dead. ''' self._age = 0 - self._state = state + self._state = LifeformState.alive if state else LifeformState.dead self._neighbors = [] def alive(self): ''' Is this cell alive? ''' - return self._state + return True if self._state in [LifeformState.alive, LifeformState.dying] else False - def specifyNeighbor(self, neighbor): + def specifyNeighbors(self, neighbors): ''' Tell the lifeform whom its neighbor is. :param neighbor: another lifeform ''' - self._neighbors.append(neighbor) + self._neighbors = neighbors def aliveNeighbors(self): ''' @@ -33,18 +41,21 @@ def play(self): This is where the Game of Life rules get implemented ''' nc = self.aliveNeighbors() + if (nc < 2 or nc > 3) and self.alive(): - self.kill() - elif nc == 3 and not self.alive(): - self.resurrect() - return 0 + self._state = LifeformState.dying + if nc == 3 and not self.alive(): + self._state = LifeformState.resurrecting - def kill(self): - self._state = False + if self.alive(): + self._age += 1 - def resurrect(self): - self._state = True + def updateState(self): + if self._state == LifeformState.dying: + self._state = LifeformState.dead + if self._state == LifeformState.resurrecting: + self._state = LifeformState.alive class Universe(): @@ -59,49 +70,41 @@ def __init__(self, state): # create all the Lifeforms and store them into the Universe's state self._state = [[Lifeform(i) for i in row] for row in state] # 2D list of Lifeforms - # repass over the Universe's state to specify neighbors (there must be a better way!) + def updateNeighbors(self): + # repass over the Universe's state to specify neighbors for rowi, row in enumerate(self._state): for lifei, life in enumerate(row): + neighbors = [] for j in range(rowi - 1, rowi + 2): for i in range(lifei - 1, lifei + 2): - if (i, j) != (lifei, rowi) \ - and i >= 0 \ - and j >= 0 \ - and i < len(row) \ - and j < len(self._state): - #print('attempt to access _state[{}][{}]'.format(j,i)) - life.specifyNeighbor(self._state[j][i]) - ''' - try: - print('attempt to access _state[{}][{}]'.format(rowi - 1, lifei - 1)) - life.specifyNeighbor(self._state[rowi - 1][lifei - 1]) - print('attempt to access _state[{}][{}]'.format(rowi - 1, lifei)) - life.specifyNeighbor(self._state[rowi - 1][lifei ]) - print('attempt to access _state[{}][{}]'.format(rowi - 1, lifei + 1)) - life.specifyNeighbor(self._state[rowi - 1][lifei + 1]) - print('attempt to access _state[{}][{}]'.format(rowi, lifei -1)) - life.specifyNeighbor(self._state[rowi ][lifei - 1]) - print('attempt to access _state[{}][{}]'.format(rowi, lifei + 1)) - life.specifyNeighbor(self._state[rowi ][lifei + 1]) - print('attempt to access _state[{}][{}]'.format(rowi + 1, lifei - 1)) - life.specifyNeighbor(self._state[rowi + 1][lifei - 1]) - print('attempt to access _state[{}][{}]'.format(rowi + 1, lifei)) - life.specifyNeighbor(self._state[rowi + 1][lifei ]) - print('attempt to access _state[{}][{}]'.format(rowi + 1, lifei + 1)) - life.specifyNeighbor(self._state[rowi + 1][lifei + 1]) - except Exception as e: - pass - ''' + if (i, j) != (lifei, rowi): + if i == len(row): + i = 0 + if j == len(self._state): + j = 0 + # print('attempt to access _state[{}][{}]'.format(j,i)) + neighbors.append(self._state[j][i]) + life.specifyNeighbors(neighbors) + def evolve(self): ''' At each time tick, the universe evolves and updates its lifeforms. ''' self._age += 1 - [[life.play() for life in row] for row in self._state] + + self.updateNeighbors() + + for row in self._state: + for life in row: + life.play() + + for row in self._state: + for life in row: + life.updateState() def state(self): ''' Get a 2D boolean representation of the Universe's state :return: 2D list of booleans ''' - return [[life.alive() for life in row] for row in self._state] \ No newline at end of file + return [[life.alive() for life in row] for row in self._state] diff --git a/universeview.py b/universeview.py index a471227..04e688d 100644 --- a/universeview.py +++ b/universeview.py @@ -5,8 +5,8 @@ from universe import Universe class constants(): - CellToScreenRatio = 0.002 - AtomicTick = 1.0 + CellToScreenRatio = 0.001 + AtomicTick = 0.2 background = QColor(60, 60, 60) grid = QColor(20, 20, 20) cell = QColor(84, 158, 39) @@ -46,6 +46,13 @@ def start(self, wscene, hscene): # create a random initial state for the universe initial = [[(randint(0, 10) == 9) for i in range(self.cols)] for j in range(self.rows)] + '''initial = [[False for i in range(self.cols)] for j in range(self.rows)] + initial[0][0] = True + initial[0][1] = True + initial[1][2] = True + initial[2][2] = True + initial[3][2] = True + ''' # create the universe self.universe = Universe(initial) @@ -76,9 +83,7 @@ def draw(self, state): self.drawCell(celli, rowi) def rePaint(self): - # evolve - self.universe.evolve() - print("Universe age {}".format(self.universe._age)) + print("Drawing Universe of age {}".format(self.universe._age)) # delete everything on the canvas self.scene.clear() @@ -96,4 +101,15 @@ def rePaint(self): # draw the universe state = self.universe.state() - self.draw(state) \ No newline at end of file + self.draw(state) + + # evolve + self.universe.evolve() + + def keyPressEvent(self, QKeyEvent): + # delete selected items when pressing the keyboard's delete key + if QKeyEvent.key() == Qt.Key_Space: + if self.timer.isActive(): + self.stop() + else: + self.timer.start(constants.AtomicTick * 1000) \ No newline at end of file