From 4dae1683048c933a1aea315bad2a246cc87d426d Mon Sep 17 00:00:00 2001 From: Sebastian Sangervasi Date: Tue, 30 Oct 2018 23:34:38 -0700 Subject: [PATCH 1/2] Implemented Conway's Game of Life with classic "glider" example * Module is executable and also importable. * Supports converting a game board to and from a multiline string. --- cellular-automaton/conways_game_of_life.py | 157 +++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 cellular-automaton/conways_game_of_life.py diff --git a/cellular-automaton/conways_game_of_life.py b/cellular-automaton/conways_game_of_life.py new file mode 100644 index 0000000..21919c3 --- /dev/null +++ b/cellular-automaton/conways_game_of_life.py @@ -0,0 +1,157 @@ +""" +Conway's Game of Life +""" +import itertools + +class GameOfLife: + @classmethod + def dead_grid(cls, *, height=None, width=None): + return [ + [Dead() for _cols in range(width)] + for _rows in range(height) + ] + + @classmethod + def from_str(cls, string): + non_empty_lines = ( + line for line in string.splitlines() + if len(line) > 0 + ) + parsed_grid = [ + [Cell.from_str(char) for char in line] + for line in non_empty_lines + ] + return cls(grid=parsed_grid) + + def __init__(self, grid=None): + self.grid = grid + self.height = len(grid) + self.width = len(grid[0]) + + + def __str__(self): + return '\n'.join( + ''.join(str(cell) for cell in row) + for row in self.grid + ) + + def next_generation(self): + next_grid = [ + [ + cell.next_state(neighbor_count) + for cell, neighbor_count in row + ] + for row in self.grid_with_live_neighbor_counts() + ] + return GameOfLife(grid=next_grid) + + def grid_with_live_neighbor_counts(self): + ''' + Returns an iterator of grid rows in which each element + is a tuple containing the cell and the count of living neighbors + adjacent to that cell. + E.g. [[(Live, 0), (Dead, 3), ...], ...] + ''' + return ( + ( + (cell, self.count_live_neighbors(row, col)) + for (row, col), cell in coordinated_row + ) + for coordinated_row in self.coordinate() + ) + + def coordinate(self): + ''' + Returns an iterator of grid rows in which each element + is a tuple containg the coordinates and the content of the grid + at those coordinates. + E.g. [[((0, 0), Live), ((0, 1), Dead), ...], ...] + ''' + return ( + ( + ((row_index, col_index), cell) + for col_index, cell in enumerate(row) + ) + for row_index, row in enumerate(self.grid) + ) + + def count_live_neighbors(self, row, col): + directions_1D = (-1, 0, 1) + directions_2D = itertools.product(directions_1D, directions_1D) + neighbor_coords = ( + (row + d_row, col + d_col) + for (d_row, d_col) in directions_2D + if (d_row, d_col) != (0, 0) + ) + + def is_coord_alive(coord): + cell = self.get(*coord, default=Dead()) + return int(cell.is_alive) + + return sum(map(is_coord_alive, neighbor_coords)) + + def get(self, row, col, default=None): + is_within_rows = (0 <= row < self.height) + is_within_cols = (0 <= col < self.width) + if is_within_rows and is_within_cols: + return self.grid[row][col] + return default + + +class Cell: + @classmethod + def from_str(cls, string): + if string == Live.string_form: + return Live() + return Dead() + + def __str__(self): + return self.string_form + +class Dead(Cell): + string_form = '·' + is_alive = False + + def next_state(self, neighbor_count): + if neighbor_count == 3: + return Live() + return Dead() + +class Live(Cell): + string_form = '0' + is_alive = True + + def next_state(self, neighbor_count): + if neighbor_count in [2, 3]: + return Live() + return Dead() + + +def glider_example(): + from textwrap import dedent + + glider_string = dedent(''' + ··0···· + 0·0···· + ·00···· + ······· + ······· + ······· + ''') + + glider_game = GameOfLife.from_str(glider_string) + num_gens = 15 + print(dedent(f''' + Conway's Game of Life + Starting with seed: "Glider" + Running for {num_gens} generations. + ''')) + for gen_num in range(1, num_gens + 1 + ): + print(f'Generation {gen_num}:') + print(str(glider_game)) + glider_game = glider_game.next_generation() + print('Done') + +if __name__ == '__main__': + glider_example() From ae241cd2042314c4f596fe1d347a55926389449c Mon Sep 17 00:00:00 2001 From: Sebastian Sangervasi Date: Sun, 4 Nov 2018 12:08:01 -0800 Subject: [PATCH 2/2] Overly fancy formatting string header --- cellular-automaton/conways_game_of_life.py | 58 ++++++++++++++++------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/cellular-automaton/conways_game_of_life.py b/cellular-automaton/conways_game_of_life.py index 21919c3..bf66999 100644 --- a/cellular-automaton/conways_game_of_life.py +++ b/cellular-automaton/conways_game_of_life.py @@ -127,9 +127,33 @@ def next_state(self, neighbor_count): return Dead() -def glider_example(): - from textwrap import dedent +from textwrap import dedent + +def run_string_example( + *, + seed_string=None, + seed_name=None, + num_gens=10 +): + seed_game = GameOfLife.from_str(seed_string) + if seed_name is None: + seed_name = f'A {seed_game.height}x{seed_game.width} grid' + print(dedent(f''' + ========================= + | Conway's Game of Life | + {'':=^50} + | {f'Starting with seed: "{seed_name:.10}"': <46.46} | + | {f'Running for {str(num_gens):1.3} generations.': <46.46} | + {'':=^50} + ''')) + latest_generation = seed_game + for gen_num in range(1, num_gens + 1): + print(f'Generation {gen_num}:') + print(str(latest_generation)) + latest_generation = latest_generation.next_generation() + print('Done') +def glider_example(): glider_string = dedent(''' ··0···· 0·0···· @@ -138,20 +162,24 @@ def glider_example(): ······· ······· ''') + run_string_example( + seed_string=glider_string, + seed_name='Glider', + num_gens=15 + ) - glider_game = GameOfLife.from_str(glider_string) - num_gens = 15 - print(dedent(f''' - Conway's Game of Life - Starting with seed: "Glider" - Running for {num_gens} generations. - ''')) - for gen_num in range(1, num_gens + 1 - ): - print(f'Generation {gen_num}:') - print(str(glider_game)) - glider_game = glider_game.next_generation() - print('Done') +def question_example(): + from textwrap import dedent + + game_string = dedent(''' + ·0· + 0·0 + ''') + run_string_example( + seed_string=game_string, + num_gens=4 + ) if __name__ == '__main__': glider_example() + question_example() pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy