HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Python implementation of a wrapped Conway's Game Of Life board

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
conwaygamewrappedpythonlifeimplementationboard

Problem

```
import random

import rlereader

class Board:
"""Handles the status of all cells."""

def __init__(self, size):
self.size = size
self.grid = self.make_blank_grid()
self.furthest_col = 0
self.furthest_row = 0

def run_turns(self, num_turns):
"""Run a the simulator for a number of turns."""
while num_turns > 0:
self.run_turn()
num_turns -= 1

def run_turn(self):
"""Run a single turn of the simulator."""
new_grid = self.make_blank_grid()
for row in range(0, self.size):
for col in range(0, self.size):
new_grid[row][col] = self.get_cell_life(row, col)

self.grid = new_grid

def toggle_cell(self, row, col):
"""Toggle the dead or alive status of a single cell."""
self.grid[row][col] = not self.grid[row][col]

def check_furthest(self, row, col):
"""Check the furthest processed cell against this one and update if we
near the edge."""
if row + 1 >= self.furthest_row:
self.furthest_row = row + 2
if col + 1 >= self.furthest_col:
self.furthest_col = col + 2

def get_cell_life(self, row, col):
"""Return whether a given cell should become dead or alive.

This may update the processed cell boundaries if neccessary."""
living_neighbours = self.count_living_neighbours(row, col)
if self.grid[row][col]:
if living_neighbours in [2, 3]:
return True
else:
self.check_furthest(row, col)
return False
else:
if living_neighbours == 3:
self.check_furthest(row, col)
return True
return False

def check_cell(self, row, col):
"""Return whether the cell is dead or alive for the current
generation."""
if row self.size - 1:
row = 0

if col self.size - 1:
col = 0

Solution

import random

import rlereader

class Board:
    """Handles the status of all cells."""

    def __init__(self, size):
        self.size = size
        self.grid = self.make_blank_grid()
        self.furthest_col = 0
        self.furthest_row = 0

    def run_turns(self, num_turns):
        """Run a the simulator for a number of turns."""
        while num_turns > 0:


Use a for turn in range(num_terms) loop instead of a while loop

self.run_turn()
            num_turns -= 1

    def run_turn(self):
        """Run a single turn of the simulator."""
        new_grid = self.make_blank_grid()
        for row in range(0, self.size):


Just use range(self.size), the 0 is not needed.

for col in range(0, self.size):
                new_grid[row][col] = self.get_cell_life(row, col)

        self.grid = new_grid

    def toggle_cell(self, row, col):
        """Toggle the dead or alive status of a single cell."""
        self.grid[row][col] = not self.grid[row][col]

    def check_furthest(self, row, col):
        """Check the furthest processed cell against this one and update if we
near the edge."""
        if row + 1 >= self.furthest_row:
            self.furthest_row = row + 2
        if col + 1 >= self.furthest_col:
            self.furthest_col = col + 2


Write it like this instead:

self.furthest_row = max(self.furthest_row, row + 2)
 self.furthest_col = max(self.furthest_col, col + 2)


Also, the function updates rather then checks the furthest, a better name would be update_furthest

I don't know why you are adding 2 here, a comment explaining that would be helpful

def get_cell_life(self, row, col):
        """Return whether a given cell should become dead or alive.

This may update the processed cell boundaries if neccessary."""
        living_neighbours = self.count_living_neighbours(row, col)
        if self.grid[row][col]:
            if living_neighbours in [2, 3]:
                return True
            else:
                self.check_furthest(row, col)
                return False
        else:
            if living_neighbours == 3:
                self.check_furthest(row, col)
                return True
            return False


Write it like this instead:

living_neighbours = self.count_living_neighbours(row, col)
        if self.grid[row][cell]:
            new_value = living_neighbors in [2,3]
        else:
            new_value = living_neighbors == 3

        if new_value != self.grid[row][cell]:
             self.check_furthest(row, cell)

         return new_value


This way we separate the furthest updating from the decision of the new value of the cell. It might also be a good idea to move the furthest updating to run_turn

def check_cell(self, row, col):
        """Return whether the cell is dead or alive for the current
generation."""
        if row  self.size - 1:
            row = 0

        if col  self.size - 1:
            col = 0

        return self.grid[row][col]


Use modulous instead of all those ifs

def check_cell(self, row, col):
        return self.grid[row % self.size][col % self.size]


The % divides with remainder which gives exactly the wrap around feature you want.

def count_living_neighbours(self, row, col):
        """Find how many neighnours of a given cell are alive."""
        active_count = 0
        to_check = [
            (row - 1, col - 1), # Top left
            (row - 1, col), # Top
            (row - 1, col + 1), # Top right
            (row, col - 1), # Left
            (row, col + 1), # Right
            (row + 1, col - 1), # Bottom left
            (row + 1, col), # Bottom
            (row + 1, col + 1) # Bottom Right
        ]

        for crow, ccol in to_check:
            if self.check_cell(crow, ccol):
                active_count += 1

        return active_count


You can simplify the function by replacing it with:

return sum(self.check_cell(row, col) for row, col in to_check)


I recommend moving to_check to a global constant.

def make_blank_grid(self):
        """Returns a blank grid for future use."""
        grid = []
        for row in range(0, self.size):
            grid.append([])
            for col in range(0, self.size):
                grid[row].append([])
                grid[row][col] = False
        return grid


Write it like this instead:

def make_blank_grid(self):
        """Returns a blank grid for future use."""
        grid = []
        for row in range(0, self.size):
            grid.append([False] * self.size)
        return grid


The multiply produces a new list which is the original list repeated. But only use it on immutable values like numbers and bools. Don't use on anything that can be modified like other lists.

```
def load_rle_into_grid(self, rle):
"""Loads a RLE representation of a playing field into the grid.

rle should be a file like object."""
reader = rlereader.GRLEReader()
data = reader.rea

Code Snippets

import random

import rlereader

class Board:
    """Handles the status of all cells."""

    def __init__(self, size):
        self.size = size
        self.grid = self.make_blank_grid()
        self.furthest_col = 0
        self.furthest_row = 0

    def run_turns(self, num_turns):
        """Run a the simulator for a number of turns."""
        while num_turns > 0:
self.run_turn()
            num_turns -= 1

    def run_turn(self):
        """Run a single turn of the simulator."""
        new_grid = self.make_blank_grid()
        for row in range(0, self.size):
for col in range(0, self.size):
                new_grid[row][col] = self.get_cell_life(row, col)

        self.grid = new_grid

    def toggle_cell(self, row, col):
        """Toggle the dead or alive status of a single cell."""
        self.grid[row][col] = not self.grid[row][col]

    def check_furthest(self, row, col):
        """Check the furthest processed cell against this one and update if we
near the edge."""
        if row + 1 >= self.furthest_row:
            self.furthest_row = row + 2
        if col + 1 >= self.furthest_col:
            self.furthest_col = col + 2
self.furthest_row = max(self.furthest_row, row + 2)
 self.furthest_col = max(self.furthest_col, col + 2)
def get_cell_life(self, row, col):
        """Return whether a given cell should become dead or alive.

This may update the processed cell boundaries if neccessary."""
        living_neighbours = self.count_living_neighbours(row, col)
        if self.grid[row][col]:
            if living_neighbours in [2, 3]:
                return True
            else:
                self.check_furthest(row, col)
                return False
        else:
            if living_neighbours == 3:
                self.check_furthest(row, col)
                return True
            return False

Context

StackExchange Code Review Q#2303, answer score: 4

Revisions (0)

No revisions yet.