Skip to content

Instantly share code, notes, and snippets.

@msafadieh
Last active March 23, 2020 14:37
Show Gist options
  • Save msafadieh/0e987f99709c1d0c4e433da253b7ef11 to your computer and use it in GitHub Desktop.
Save msafadieh/0e987f99709c1d0c4e433da253b7ef11 to your computer and use it in GitHub Desktop.
Implementation of conway's game of life using Python and ncurses
#!/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