diff --git a/conway.py b/conway.py index 813688d..0d1b336 100644 --- a/conway.py +++ b/conway.py @@ -3,6 +3,8 @@ from collections import namedtuple from math import floor import pygame from dataclasses import dataclass +from typing import List + CellStates = Enum("CellStates", ("ALIVE", "DEAD")) #using enum for possible iterations on cellular automata XYPair = namedtuple("XYPair", "x y") @@ -38,48 +40,47 @@ class Cell: calculate_spacing(self.position.y, self.dimensions.y, padding.y)) def __init__(self, position: XYPair, dimensions: XYPair, render_info: Render_Info, state: CellStates=CellStates.DEAD) -> None: - self.crowding_number = 0 - - self.position = position - self.dimensions = dimensions - self.state = state - self.click_state = None - self.screen_position = self.calculate_screen_position(render_info) - self.image = pygame.Surface(self.dimensions) + self.crowding_number: int = 0 + self.position: XYPair = position + self.dimensions: XYPair = dimensions + self.state: CellStates = state + self.click_state: CellStates = None + self.screen_position: XYPair = self.calculate_screen_position(render_info) + self.image: pygame.Surface = pygame.Surface(self.dimensions) self.image.fill(Colors.GRAY.value) self.rect = pygame.Rect(self.screen_position.x, self.screen_position.y, self.dimensions.x, self.dimensions.y) - def set_state(self, state: CellStates): + def set_state(self, state: CellStates) -> None: self.state = state self.image.fill(self.PALETTE_MAP[self.state]) - def set_crowding_number(self, n: int): + def set_crowding_number(self, n: int) -> None: self.crowding_number = n - def update_state(self): + def update_state(self) -> None: if self.crowding_number < 2 or self.crowding_number >= 4: self.set_state(CellStates.DEAD) if self.crowding_number == 3: self.set_state(CellStates.ALIVE) - def draw(self, screen): + def draw(self, screen: pygame.Surface) -> None: screen.blit(self.image, self.rect) class Board: - def __init__(self, dimensions: XYPair, evolution_time, render_info: Render_Info): - screen_dimenions = render_info.screen_dimensions - self.evolution_time = evolution_time - self.clock = 0 - padding = render_info.padding + def __init__(self, dimensions: XYPair, evolution_time, render_info: Render_Info) -> None: + screen_dimenions: XYPair = render_info.screen_dimensions + self.evolution_time: int = evolution_time + self.clock: int = 0 + padding: XYPair = render_info.padding #calculate cell dimensions once instead of x*y times cell_dimensions = XYPair(screen_dimenions.x/dimensions.x - 2*padding.x, screen_dimenions.y/dimensions.y - 2*padding.y) - self.dimensions = dimensions - self.matrix = [[Cell(XYPair(x,y), cell_dimensions, render_info) for x in range(dimensions.x)] for y in range(dimensions.y)] + self.dimensions: XYPair = dimensions + self.matrix: List[List[Cell]] = [[Cell(XYPair(x,y), cell_dimensions, render_info) for x in range(dimensions.x)] for y in range(dimensions.y)] def normalize_submatrix_point(self, p: XYPair) -> XYPair: @@ -92,12 +93,12 @@ class Board: return XYPair(normalize(p.x, self.dimensions.x), normalize(p.y, self.dimensions.y)) - def get_submatrix(self, center: XYPair, extents: XYPair): + def get_submatrix(self, center: XYPair, extents: XYPair) -> List[List[Cell]]: start_point = self.normalize_submatrix_point(XYPair(center.x - extents.x, center.y - extents.y)) end_point = self.normalize_submatrix_point(XYPair(center.x + extents.x, center.y + extents.y)) return [row[start_point.x:end_point.x+1] for row in self.matrix[start_point.y:end_point.y+1]] - def calculate_crowding_number(self, center: XYPair, extents: XYPair): + def calculate_crowding_number(self, center: XYPair, extents: XYPair) -> int: submatrix = self.get_submatrix(center, extents) #flattened_submatrix removes the center point because it does not contribute to the crowding number #if syntax is confusing, it just unrolls the 2d list and removes the cell in the center @@ -105,36 +106,36 @@ class Board: living_cells = map(lambda cell: cell.state == CellStates.ALIVE, flattened_submatrix) return sum(living_cells) - def fill_crowding(self): + def fill_crowding(self) -> None: for row in self.matrix: for cell in row: cell.set_crowding_number( self.calculate_crowding_number(cell.position, XYPair(1,1)) ) - def evolve_state(self): + def evolve_state(self) -> None: #calculate crowding numbers before updating any state, otherwise you'll be unhappy self.fill_crowding() for row in self.matrix: for cell in row: cell.update_state() - def set_state(self, p: XYPair, state: CellStates): + def set_state(self, p: XYPair, state: CellStates) -> None: self.matrix[p.y][p.x].set_state(state) - def draw(self, screen): + def draw(self, screen: pygame.Surface) -> None: for row in self.matrix: for cell in row: cell.draw(screen) - def tick_clock(self, dt): + def tick_clock(self, dt: int) -> None: self.clock += dt if self.clock >= self.evolution_time: self.evolve_state() self.clock = 0 - def handle_click(self, mouse_pos, render_info): - + def handle_click(self, mouse_pos, render_info: Render_Info) -> None: + def pixel_to_index(x, w, p): return floor((x - p)/(w + 2*p)) @@ -158,15 +159,15 @@ class Board: self.matrix[y][x].set_state(self.click_state) - def reset_click(self): + def reset_click(self) -> None: self.click_state = None - def reset(self): + def reset(self) -> None: for row in self.matrix: for cell in row: cell.set_state(CellStates.DEAD) - def __repr__(self): + def __repr__(self) -> None: lines = [] str_buffer = '' lines.append('-'*(self.dimensions.x+2))