import argparse import copy import os import sys import time DEFAULT_GRID = [ [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], ] DEFAULT_SPEED = 500 class GameOfLife: def __init__(self, speed: int = DEFAULT_SPEED, grid: list[list[int]] = DEFAULT_GRID): self.grid = grid.copy() self.height = len(self.grid) self.width = len(self.grid[0]) self.speed = speed @classmethod def from_string(cls, template: str, speed: int = DEFAULT_SPEED): lines = template.strip().split('\n') for line in lines: print("line is: ", line, "+++") grid = [[int(col) for col in line] for line in lines] return GameOfLife(grid=grid, speed=speed) def play(self): while True: self.iterate() self.show() time.sleep(self.speed / 1000) def iterate(self): new_grid = copy.deepcopy(self.grid) for y, row in enumerate(self.grid): for x, current_value in enumerate(row): is_alive = current_value == 1 living_neighbors = self.get_living_neighbors(y, x) if is_alive: if living_neighbors < 2: new_grid[y][x] = 0 elif living_neighbors == 2 or living_neighbors == 3: new_grid[y][x] = 1 else: new_grid[y][x] = 0 else: if living_neighbors == 3: new_grid[y][x] = 1 self.grid = new_grid def get_living_neighbors(self, y: int, x: int): neighbors = self.get_neighbors(y, x) living = [n for n in neighbors if n == 1] return len(living) def get_neighbors(self, y: int, x: int): neighbors = [] if y > 0: neighbors.append(self.grid[y - 1][x]) # N if x > 0: neighbors.append(self.grid[y - 1][x - 1]) # NW if x < self.width - 1: neighbors.append(self.grid[y - 1][x + 1]) # NE if x > 0: neighbors.append(self.grid[y][x - 1]) # W if x < self.width - 1: neighbors.append(self.grid[y][x + 1]) # E if y < self.height - 1: neighbors.append(self.grid[y + 1][x]) # S if x > 0: neighbors.append(self.grid[y + 1][x - 1]) # SW if x < self.width - 1: neighbors.append(self.grid[y + 1][x + 1]) # SE return neighbors def show(self): self.clear() for row in self.grid: for col in row: if col == 0: # print('□', end='') print('·', end='') else: print('■', end='') print('\n') def clear(self): os.system('cls' if os.name == 'nt' else 'clear') if __name__ == "__main__": parser = argparse.ArgumentParser(description='Conway\'s Game of Life') parser.add_argument( '-f', '--file', help='The path to a file containing a starting grid. The grid file should use 0 for dead cells and 1 for living cells.') parser.add_argument( '-s', '--speed', help='The delay between iterations in milliseconds (default: 500, minimum: 100)', default=500, type=int), args = parser.parse_args() if args.speed < 100: print('Speed must be at least 100 milliseconds') exit(1) if args.file: with open(args.file, 'r') as f: contents = f.read() GameOfLife.from_string(contents, args.speed).play() else: GameOfLife(args.speed).play()