Skip to content

Instantly share code, notes, and snippets.

@z-------------
Last active June 22, 2019 06:28
Show Gist options
  • Save z-------------/a1c01653bad6705774173374bfe83902 to your computer and use it in GitHub Desktop.
Save z-------------/a1c01653bad6705774173374bfe83902 to your computer and use it in GitHub Desktop.
"""
Any live cell with fewer than two live neighbours dies, as if by underpopulation.
Any live cell with two or three live neighbours lives on to the next generation.
Any live cell with more than three live neighbours dies, as if by overpopulation.
Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
"""
import sys
import time
import re
import argparse
import curses
CHAR_ALIVE = "#"
CHAR_DEAD = " "
height, width, size_x, size_y = -1, -1, -1, -1
ticks_per_second = 30
filename = None
neighbors = [
(-1, -1), (-1, 0), (-1, 1),
(0, -1), (0, 1),
(1, -1), (1, 0), (1, 1)
]
def cleanup() -> None:
if stdscr:
curses.endwin()
def create_board(size_y: int, size_x: int) -> list:
board = [[0 for _ in range(0, size_x)] for _ in range(0, size_y)]
return board
def print_board(board: list) -> None:
for y in range(0, size_y):
for x in range(0, size_x):
if y is size_y - 1 and x is size_x - 1:
break # curses can't draw bottom right character
stdscr.addch(y, x, CHAR_ALIVE if board[y][x] is 1 else CHAR_DEAD)
stdscr.refresh()
def count_neighbors(board: list, y: int, x: int) -> int:
count = 0
for neighbor in neighbors:
nx = x + neighbor[1]
ny = y + neighbor[0]
if nx >= 0 and nx < size_x and ny >= 0 and ny < size_y and board[ny][nx] is 1:
count += 1
return count
def copy_board(board_to: list, board_from: list) -> None:
for y in range(0, size_y):
for x in range(0, size_x):
board_to[y][x] = board_from[y][x]
def update_board(board: list) -> None:
buffer = create_board(size_y, size_x)
for y in range(0, size_y):
for x in range(0, size_x):
n = count_neighbors(board, y, x)
if board[y][x] is 1:
if n < 2:
buffer[y][x] = 0
elif n is 2 or n is 3:
buffer[y][x] = 1
elif n > 3:
buffer[y][x] = 0
else:
if n is 3:
buffer[y][x] = 1
copy_board(board, buffer)
def tick(board: list) -> None:
update_board(board)
print_board(board)
def main():
board = create_board(size_y, size_x)
if filename:
pat_int_line = re.compile(r"^\d+$")
offset_y = 0
offset_y_set = False
offset_x = 0
offset_x_set = False
with open(filename, "r") as f:
contents = f.read()
lines = contents.split("\n")
for y, line in enumerate(lines):
if line:
if line[0] == "#":
continue
elif pat_int_line.match(line):
n = int(line)
if not offset_y_set:
offset_y = n
offset_y_set = True
elif not offset_x_set:
offset_x = n
offset_x_set = True
for x, c in enumerate(line):
if c == "X":
if y + offset_y < size_y and x + offset_x < size_x:
board[y + offset_y][x + offset_x] = 1
if ticks_per_second:
while True:
tick(board)
time.sleep(1 / ticks_per_second)
else:
while True:
tick(board)
try:
parser = argparse.ArgumentParser(description="A simple implementation of Conway's Game of Life in Python")
parser.add_argument("file", type=str, nargs="?",
help="name of file from which to load an initial board pattern")
parser.add_argument("--tps", type=int,
help="(ideal) number of ticks per second")
args = parser.parse_args()
if not args.tps is None and args.tps >= 0:
ticks_per_second = args.tps
if args.file:
filename = args.file
stdscr = curses.initscr()
height, width = stdscr.getmaxyx()
size_y = height
size_x = width
main()
except KeyboardInterrupt:
cleanup()
except SystemExit:
exit(0)
except:
cleanup()
exp = sys.exc_info()[0]
print("Exception:", exp.__name__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment