User:Danf/TurtleGraphics: Difference between revisions
Jump to navigation
Jump to search
(better demo-size rows & columns setting) |
('x' to re-randomize ... lulz) |
||
Line 5: | Line 5: | ||
<pre> | <pre> | ||
# turtlife.py - Artistic License w/ Attribution -> "(evil) Dan of MOISEBRIDGE" | # turtlife.py - Artistic License w/ Attribution -> "(evil) Dan of MOISEBRIDGE" | ||
# note: press 'n' to advance frame, 'r' to run, 'p' to pause | # note: press 'n' to advance frame, 'r' to run, 'p' to pause, 'x' to re-randomize | ||
from turtle import Screen, Turtle, mainloop | from turtle import Screen, Turtle, mainloop |
Revision as of 21:08, 20 January 2015
python turtle module -> Conway's Game of Life ... and stuff.
experimental work in progress, needs to be cleaned up and refactored a bit ...
# turtlife.py - Artistic License w/ Attribution -> "(evil) Dan of MOISEBRIDGE" # note: press 'n' to advance frame, 'r' to run, 'p' to pause, 'x' to re-randomize from turtle import Screen, Turtle, mainloop from itertools import islice, product, repeat, starmap from random import randint from time import sleep class Cell(object): def __init__(self, colony, row, col): self.colony = colony self.row = row self.col = col self.val = 0 self.extra = 0 self.rules = colony.rules self._neighbors = None def neighbors(self): if self._neighbors is None: self._neighbors = list(self.colony.neighbormap(self, self.colony.cells)) return self._neighbors def neighborsum(self): return sum(o.val for o in self.neighbors()) def destiny(self): n = self.neighborsum() if self.rules == 'prime': return ((self.val if (n == 5 or n == 7) else 1 if (n == 2 or n == 3) else 0), n) elif self.rules == 'life': return ((self.val if (n == 2) else 1 if (n == 3) else 0), n) def value(self, val=None, extra=None): if val is not None: self.val = val if extra is not None: self.extra = extra return self.val def valchar(self): return (' ', 'o')[self.val] class Raster(object): def __init__(self, rules, displaymode, rows, cols): self.rules = rules self.displaymode = displaymode self.rows = rows self.cols = cols self.cells = list(starmap( lambda x, y: Cell(self, x, y), product(range(rows), range(cols)) )) self.turtles = None def rowslice(self, r): i = r * self.cols return islice(self.cells, i, i + self.cols) def neighborhood(self, row, col): up = row - 1 if row else self.rows - 1 down = row + 1 if row < self.rows - 1 else 0 left = col - 1 if col else self.cols - 1 right = col + 1 if col < self.cols - 1 else 0 return ( (up, left), (up, col), (up, right), (row, left), (row, right), (down, left), (down, col), (down, right) ) def neighbormap(self, o, sq): return starmap( lambda x, y: sq[x * self.cols + y], self.neighborhood(o.row, o.col) ) def turtledisplay(self): if self.turtles is None: self.turtles = list(CellularTurtle(self, row, col) for row in range(self.rows) for col in range(self.cols)) for c, t in zip(self.cells, self.turtles): if c.val: if c.extra == 2: t.rgb = list(t.colors['blue']) elif c.extra == 3: t.rgb = list(t.colors['green']) elif c.extra == 5: t.rgb = list(t.colors['yellow']) elif c.extra == 7: t.rgb = list(t.colors['red']) else: if self.displaymode == 'ambient': t.rgb = list(t.ambience()) elif self.displaymode == 'fade': for i in range(3): t.rgb[i] *= 0.618 else: t.rgb = list(t.colors['black']) t.color(t.rgb) def textdisplay(self): for r in range(self.rows): print(.join(map(lambda x: x.valchar(), self.rowslice(r)))) def display(self): self.turtledisplay() self.textdisplay() class CellularTurtle(Turtle): def __init__(self, colony, row, col): Turtle.__init__(self) self.colony = colony self.row = row self.col = col self.speed(0) # self.hideturtle() self.shape("circle") # self.settiltangle(90) self.resizemode("user") self.shapesize(2, 2, 0) self.pu() self.setx(col) self.sety(row) self.colors = dict( ( ( 'black', (0.0, 0.0, 0.0) ), ( 'grey50', (0.5, 0.5, 0.5) ), ( 'white', (1.0, 1.0, 1.0) ), ( 'red', (0.7, 0.0, 0.0) ), ( 'yellow', (0.7, 0.7, 0.0) ), ( 'green', (0.0, 0.7, 0.0) ), ( 'blue', (0.0, 0.0, 0.7) ) ) ) self.rgb = list(self.colors['black']) self.color(self.rgb) self._neighbors = None def neighbors(self): if self._neighbors is None: self._neighbors = list(self.colony.neighbormap(self, self.colony.turtles)) return self._neighbors def avg_rgb(self, turtles): rgb = [0.0, 0.0, 0.0] n = len(turtles) for t in turtles: for i in range(3): rgb[i] += t.rgb[i] return map(lambda x: x/n, rgb) def ambience(self): return self.avg_rgb(self.neighbors()) class CellRunner(object): def __init__(self, rules, displaymode, rows, cols): self.raster = Raster(rules, displaymode, rows, cols) self.randomize() def randomize(self): list(map(lambda x: x.value(randint(0, 1)), self.raster.cells)) def update(self, sync=True): dst = map(lambda x: x.destiny(), self.raster.cells) if sync: dst = list(dst) list(starmap( lambda x, y: x.value(*y), zip(self.raster.cells, dst) )) self.raster.display() def run(self, n=0, delay=0.1): f = (lambda: repeat(1, n)) if n else (lambda: repeat(1)) for x in f(): try: self.update(sync=True) if(delay): sleep(delay) except: break class ScreenRunner(object): def __init__(self, rules='prime', displaymode='ambient', rows=16, cols=32): self.screen = self.initscreen(rows, cols) self.cellrunner = CellRunner(rules, displaymode, rows, cols) self.running = False self.next() def initscreen(self, rows, cols): screen = Screen() screen.delay(0) offset = map(lambda x: x - 0.3, (0, rows, cols, 0)) screen.setworldcoordinates(*offset) screen.bgcolor(0.0, 0.0, 0.0) screen.tracer(n=rows*cols) self.bindkeys(screen) return screen def bindkeys(self, screen): screen.onkey(self.randomize, 'x') screen.onkey(self.next, 'n') screen.onkey(self.run, 'r') screen.onkey(self.save, 's') screen.onkey(self.pause, 'p') screen.onkey(self.quit, 'q') screen.listen() def randomize(self): self.cellrunner.randomize() self.next() def next(self): self.cellrunner.run(1, 0) def run(self): self.running = True self.timer() def save(self): self.pause(r) s = .join(str(o.val) for o in self.cellrunner.raster.cells) print(s) def pause(self): self.running = False def quit(self): exit() def timer(self, delay=100): if self.running: self.next() self.screen.ontimer(lambda: self.timer(delay), delay) def main(): sr = ScreenRunner(rules='life', displaymode='fade', rows=7, cols=11) return "EVENTLOOP" if __name__ == "__main__": msg = main() print(msg) mainloop()