Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- from __future__ import print_function
- from copy import deepcopy
- import curses
- from time import sleep
- import random
- import os
- from collections import namedtuple
- from line_profiler import LineProfiler
- try:
- range = xrange
- except NameError:
- pass
- Area = namedtuple('Area', ['x', 'y'])
- A = Area
- Point = namedtuple('Point', ['x', 'y'])
- P = Point
- profiler = LineProfiler()
- class Board(object):
- def __init__(self, seed_or_area, fill=False):
- if isinstance(seed_or_area, Area):
- self = self.make(seed_or_area, fill)
- return
- self.seed = seed_or_area
- self.grid = deepcopy(self.seed)
- @classmethod
- def make(cls, area, fill=False):
- return cls([[fill for _ in range(area.x)]
- for _ in range(area.y)])
- @classmethod
- def make_random(cls, area):
- return cls([[random.choice([True, False]) for _ in range(area.x)]
- for _ in range(area.y)])
- @classmethod
- def parse(cls, s, alive='o'):
- return cls([[cell == alive for cell in row] for row in s.split('\n') if row])
- @property
- def width(self):
- return len(self.grid[0])
- @property
- def height(self):
- return len(self.grid)
- @property
- def area(self):
- return Area(x=self.width,
- y=self.height)
- def __repr__(self):
- return '<{}.{} {}x{} at 0x{:x}>'.format(
- __name__,
- self.__class__.__name__,
- self.width,
- self.height,
- hash(self),
- )
- def __str__(self):
- return '\n'.join(''.join('o' if cell else '-' for cell in row) for row in self.grid)
- def __getitem__(self, key):
- return self.grid[key]
- # @profile
- # def get_neighbor_points(self, point):
- # for other in (Point(x=point.x+x_offset, y=point.y+y_offset)
- # for x_offset in range(-1, 2)
- # for y_offset in range(-1, 2)):
- # if other == point:
- # continue
- # if not -1 < other.x < self.width:
- # continue
- # if not -1 < other.y < self.height:
- # continue
- # yield other
- @profile
- def get_all_neighbor_points(self, point):
- yield Point(x=point.x-1, y=point.y-1)
- yield Point(x=point.x, y=point.y-1)
- yield Point(x=point.x+1, y=point.y-1)
- yield Point(x=point.x-1, y=point.y)
- yield Point(x=point.x+1, y=point.y)
- yield Point(x=point.x-1, y=point.y+1)
- yield Point(x=point.x, y=point.y+1)
- yield Point(x=point.x+1, y=point.y+1)
- @profile
- def get_neighbor_points(self, point):
- for pt in self.get_all_neighbor_points(point):
- if not -1 < pt.x < self.width:
- continue
- if not -1 < pt.y < self.height:
- continue
- yield pt
- @profile
- def get_neighbors(self, point):
- return (self.grid[pt.y][pt.x] for pt in self.get_neighbor_points(point))
- @property
- def cell_count(self):
- return self.width * self.height
- @property
- def alive(self):
- return sum(cell for row in self.grid for cell in row)
- @property
- def dead(self):
- return self.cell_count - self.alive
- class ConwaysGameOfLife(object):
- def __init__(self, seed_or_board):
- self.board = seed_or_board if isinstance(seed_or_board, Board) else Board(seed_or_board)
- self.generation = 0
- def __getitem__(self, key):
- return self.board[key]
- def __getattr__(self, attr):
- return getattr(self.board, attr)
- @profile
- def age(self, generations=1):
- new_grid = deepcopy(self.board.grid)
- for x in range(self.width):
- for y in range(self.height):
- pt = Point(x=x, y=y)
- neighbors = self.get_neighbors(pt)
- alive = sum(neighbors)
- if alive < 2:
- living = False
- elif alive > 3:
- living = False
- elif alive == 3:
- living = True
- else:
- living = None
- if living is not None:
- new_grid[pt.y][pt.x] = living
- self.board.grid = new_grid
- self.generation += 1
- def prompt(window, options):
- window.clear()
- s = '\n'.join('({}) {}'.format(opt[0], opt[1]) for opt in enumerate(options))
- window.addstr(0, 0, s)
- y, x = window.getmaxyx()
- window.move(y-1, x-1)
- choice = int(window.getkey())
- return choice
- def inner_main(window):
- y, x = window.getmaxyx()
- area = A(x=x-1, y=y-1)
- idx = prompt(window, ['All alive', 'Random', 'Common seed'])
- if idx == 0:
- seed = Board.make(area)
- elif idx == 1:
- seed = Board.make_random(area)
- else:
- seed = COMMON
- curses.noecho()
- curses.cbreak()
- window.nodelay(True)
- window.clear()
- bottom_row = y - 1
- game = ConwaysGameOfLife(seed)
- fmt = 'Generation: {} | A/D/T: {}/{}/{} | {:2.2%} alive'
- while True:
- window.clear()
- window.addstr(0, 0, str(game.board))#, curses.A_NORMAL)
- # for x in range(game.width):
- # for y in range(game.height):
- # alive = game[y][x]
- # ch = ord('o' if alive else '-')
- # window.addch(y, x, ch)
- window.addstr(bottom_row, 0, fmt.format(
- game.generation,
- game.alive,
- game.dead,
- game.cell_count,
- float(game.alive) / game.cell_count,
- ))#, curses.A_REVERSE | curses.A_DIM)
- y, x = window.getmaxyx()
- window.move(y-1, x-1)
- game.age()
- window.refresh()
- sleep(.01)
- c = window.getch()
- if c > 0 and chr(c) == 'q':
- return
- def main():
- curses.wrapper(inner_main)
- COMMON = Board.parse("""
- --------------------------------------
- -oo---oo----oo---oo----o---------oo---
- -oo--o--o--o--o--o-o---o----ooo--o----
- ------oo----o-o---o----o---ooo------o-
- -------------o---------------------oo-
- --------------------------------------
- --------------------------------------
- -----o-----o--------------------------
- -----o-----o--------------------------
- -----oo---oo--------------------------
- --------------------------------------
- -ooo--oo-oo--ooo----------------------
- ---o-o-o-o-o-o------------------------
- -----oo---oo--------------------------
- --------------------------------------
- -----oo---oo--------------------------
- ---o-o-o-o-o-o------------------------
- -ooo--oo-oo--ooo----------------------
- --------------------------------------
- -----oo---oo--------------------------
- -----o-----o--------------------------
- -----o-----o--------------------------
- --------------------------------------
- """)
- if __name__ == '__main__':
- main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement