Last active
May 3, 2018 12:19
-
-
Save Coldsp33d/dfabf0eb9f5f1c52d024fd61684a766f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy as np | |
import time | |
from enum import Enum | |
from typing import List, Iterator, Sequence, Tuple | |
NEIGHBOURS = [(i, j) for i in range(-1, 2) for j in range(-1, 2) if i or j] | |
class State(Enum): | |
''' enum class to represent possible cell states ''' | |
DEAD = 0 | |
ALIVE = 1 | |
class Board: | |
''' Board class to represent the game board ''' | |
def __init__(self, rows : int, columns : int, init : Sequence[Sequence[int]]): | |
self.rows = rows # the number of rows | |
self.columns = columns # the number of columns | |
self.board_ = [ | |
[ | |
State(init[i][j]) | |
for j in range(self.columns) | |
] | |
for i in range(self.rows) | |
] | |
def __str__(self) -> str: | |
''' return the __str__ representation of a Board object | |
* represents a live cell, and a space represents a dead one | |
''' | |
return '\n'.join([ | |
''.join([ | |
u" *"[cell.value] | |
for cell in row | |
]) | |
for row in self.board_ | |
]) | |
@property | |
def population(self) -> int: | |
''' population — the number of live cells on the board ''' | |
return sum(cell.value for row in self.board_ for cell in row) | |
def has_live_cells(self) -> bool: | |
''' return whether there are any live cells or not ''' | |
return any(cell.value for row in self.board_ for cell in row) | |
def neighbours(self, x: int, y: int) -> Iterator[Tuple[State, int, int]]: | |
for i, j in ((x + i, y + j) for i, j in NEIGHBOURS if x + i >= 0 and y + j >= 0): | |
try: | |
yield self.board_[i][j], i, j | |
except IndexError: | |
pass | |
def count_live_neighbours(self, x : int, y : int) -> int: | |
''' count the live neighbours of a cell ''' | |
return sum(cell.value for cell, _, _ in self.neighbours(x, y)) | |
def next_cell_state(self, x : int, y : int) -> State: | |
count = self.count_live_neighbours(x, y) | |
if count == 3 or (count == 2 and self.board_[x][y] == State.ALIVE): | |
return State.ALIVE | |
return State.DEAD | |
def next_board_state(self) -> List[List[State]]: | |
''' return board configuration for the next state ''' | |
return [ | |
[ | |
self.next_cell_state(i, j) | |
for j in range(self.columns) | |
] | |
for i in range(self.rows) | |
] | |
def advance_state(self): | |
''' update the board configuration with the config for the next state ''' | |
self.board_ = self.next_board_state() | |
if __name__ == '__main__': | |
arr = np.random.choice([0, 1], (20, 50), p=[0.85, 0.15]) | |
board = Board(arr.shape[0], arr.shape[1], init=arr.tolist()) | |
step = 0 | |
while board.has_live_cells(): | |
step += 1 | |
print( | |
'\x1bc', | |
'\033[91m', | |
board, | |
'\033[0m', | |
f'\nStep: {step:<3d}\tPopulation: {board.population:<4d}', | |
sep='', | |
end='\n\n' | |
) | |
board.advance_state() | |
time.sleep(.1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment