Last active
March 23, 2020 14:37
-
-
Save msafadieh/0e987f99709c1d0c4e433da253b7ef11 to your computer and use it in GitHub Desktop.
Implementation of conway's game of life using Python and ncurses
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
#!/usr/bin/env python | |
# pylint: disable = C0103, C0116, R0912 | |
""" | |
An implementation of Conways's Game of Life using ncurses. | |
Controls: | |
When playing: | |
p: pause | |
q: quit | |
When paused: | |
p: unpause | |
q: quit | |
arrow keys: move cursor | |
enter: toggle state of highlighted cell | |
""" | |
import curses | |
from itertools import product | |
from random import randint | |
import sys | |
from time import sleep | |
__author__ = "Mohamad Mounir Safadieh" | |
__copyright__ = "Copyright 2020, Mohamad Mounir Safadieh" | |
__license__ = "GPLv3" | |
def step(grid, window): | |
max_y, max_x = len(grid), len(grid[0]) | |
new_grid = [row.copy() for row in grid] | |
for y, x in product(range(max_y), range(max_x)): | |
alive_neighbors = 0 | |
for off_x, off_y in filter(any, product(range(-1, 2), repeat=2)): | |
if in_grid(grid, j := y + off_y, i := x + off_x): | |
alive_neighbors += grid[j][i] | |
if grid[y][x] and alive_neighbors not in (2, 3): | |
new_grid[y][x] = 0 | |
elif not grid[y][x] and alive_neighbors == 3: | |
new_grid[y][x] = 1 | |
draw_grid(new_grid, window) | |
return new_grid | |
def draw_grid(grid, window): | |
window.erase() | |
for row in grid: | |
for alive in row: | |
window.addstr(" ", curses.color_pair(alive)) | |
window.addstr("\n") | |
window.refresh() | |
def init_curses(): | |
window = curses.initscr() | |
curses.curs_set(False) | |
curses.noecho() | |
curses.start_color() | |
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_MAGENTA) | |
window.nodelay(True) | |
return window | |
def generate_new_grid(window): | |
y, x = window.getmaxyx() | |
grid = [[randint(0, 1) for _ in range(1, x)] for _ in range(1, y)] | |
draw_grid(grid, window) | |
return grid | |
def in_grid(grid, y, x): | |
return 0 <= y < len(grid) and 0 <= x < len(grid[y]) | |
def get_input(grid, window): | |
delay = True | |
y = x = 0 | |
while (char := window.getch()) != curses.ERR: | |
if char == 112: | |
delay = not delay | |
window.nodelay(delay) | |
curses.curs_set(not delay) | |
elif char == ord("q"): | |
curses.endwin() | |
sys.exit() | |
elif not delay: | |
if char == ord("\x1b")\ | |
and window.getch() == ord("[")\ | |
and ord("A") <= (key := window.getch()) <= ord("D"): | |
if key == ord("A"): | |
y -= y > 0 | |
elif key == ord("B"): | |
y += y < len(grid) | |
elif key == ord("C"): | |
x += x < len(grid[y]) | |
elif key == ord("D"): | |
x -= x > 0 | |
elif char == ord("\n"): | |
grid[y][x] = 1 - grid[y][x] | |
draw_grid(grid, window) | |
elif char == ord(" "): | |
grid = step(grid, window) | |
elif char == ord("c"): | |
grid = [[0]*len(row) for row in grid] | |
draw_grid(grid, window) | |
window.move(y, x) | |
return grid | |
def main(): | |
window = init_curses() | |
grid = generate_new_grid(window) | |
while not sleep(0.1): | |
grid = step(get_input(grid, window), window) | |
if __name__ == "__main__": | |
try: | |
main() | |
except KeyboardInterrupt: | |
curses.endwin() | |
except: | |
curses.endwin() | |
raise |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment