diff --git a/examples/highlife.py b/examples/highlife.py index b528000..e92e988 100644 --- a/examples/highlife.py +++ b/examples/highlife.py @@ -16,4 +16,4 @@ if __name__ == '__main__': p = cam_parser.CAMParser('B368/S23', c) c.randomize() - c.start_plot(100, p.ruleset) + c.start_plot(50, p.ruleset) diff --git a/examples/life.py b/examples/life.py index 1b253fa..ced4206 100644 --- a/examples/life.py +++ b/examples/life.py @@ -15,5 +15,22 @@ if __name__ == '__main__': c = cam.CAM(1, 100, 2) p = cam_parser.CAMParser('B3/S23', c) - c.randomize() - c.start_plot(50, p.ruleset) + #c.randomize() + + # Glider Gun 9x36 + from bitarray import bitarray + row = [1<<11 + ,1<<13|1<<11 + ,1<<23|1<<22|1<<15|1<<14|1<<1|1<<0 + ,1<<24|1<<20|1<<15|1<<14|1<<1|1<<0 + ,1<<35|1<<34|1<<25|1<<19|1<<15|1<<14 + ,1<<35|1<<34|1<<25|1<<21|1<<19|1<<18|1<<13|1<<11 + ,1<<25|1<<19|1<<11 + ,1<<24|1<<20 + ,1<<23|1<<22 + ] + + for i in range(9): + c.master.grid[35+i][12:48] = bitarray(bin(row[i])[2:].zfill(36)) + + c.start_console(50, p.ruleset) diff --git a/examples/life_without_death.py b/examples/life_without_death.py index b5d214d..e8498ef 100644 --- a/examples/life_without_death.py +++ b/examples/life_without_death.py @@ -16,4 +16,4 @@ if __name__ == '__main__': p = cam_parser.CAMParser('B3/S012345678', c) c.randomize() - c.start_plot(100, p.ruleset) + c.start_plot(50, p.ruleset) diff --git a/examples/morley.py b/examples/morley.py index 6a2df77..19a4749 100644 --- a/examples/morley.py +++ b/examples/morley.py @@ -16,4 +16,4 @@ if __name__ == '__main__': p = cam_parser.CAMParser('B368/S245', c) c.randomize() - c.start_plot(100, p.ruleset) + c.start_plot(50, p.ruleset) diff --git a/examples/replicator.py b/examples/replicator.py index 3cb948f..3b321d9 100644 --- a/examples/replicator.py +++ b/examples/replicator.py @@ -15,5 +15,7 @@ if __name__ == '__main__': c = cam.CAM(1, 100, 2) p = cam_parser.CAMParser('B1357/S1357', c) - c.randomize() - c.start_plot(100, p.ruleset) + for i in range(49, 52): + c.master.grid[i][49:51] = 1 + + c.start_plot(50, p.ruleset) diff --git a/examples/seeds.py b/examples/seeds.py index a85f5d7..a3f17b8 100644 --- a/examples/seeds.py +++ b/examples/seeds.py @@ -16,4 +16,4 @@ if __name__ == '__main__': p = cam_parser.CAMParser('B2/S', c) c.randomize() - c.start_plot(100, p.ruleset) + c.start_plot(50, p.ruleset) diff --git a/src/cam.py b/src/cam.py index de67c27..f0f17cf 100644 --- a/src/cam.py +++ b/src/cam.py @@ -5,11 +5,16 @@ The CAM consists of a number of cell planes that allow for increasingly complex This is the top-level module that should be used by anyone wanting to work with fifth, and provides all methods needed (i.e. supported) to interact/configure with the cellular automata directly. +Displays can happen via matplotlib's animation library or the ncurses lib. Note both will support +tracing/echoing/multi-dimensional displays + @date: June 01, 2015 """ import plane import time +import curses +import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as ani @@ -85,19 +90,56 @@ class CAM: plt.axis('off') plt.show() + def _console_run(self, stdscr, clock, rules, *args): + """ + The following displays all bits onto the console. + + Since overflow of the window is most probable, we create a pad allowing the user to navigate + the scene via the arrow keys. Note this does wrap around, so one can go left (for example) indefinitely. + For multiple bit planes, curses.panels are used. + """ + y, x = 0, 0 + max_y, max_x = stdscr.getmaxyx() + width, height = self.master.shape + + pad = curses.newpad(width+1, height+1) + pad.nodelay(1) + pad.keypad(1) + + while True: + + # Allow navigating plane + c = pad.getch() + if c == curses.KEY_UP: + y = (y + 1) % height + elif c == curses.KEY_DOWN: + y = (y - 1) % height + elif c == curses.KEY_LEFT: + x = (x + 1) % width + elif c == curses.KEY_RIGHT: + x = (x - 1) % width + + # Cycle around grid + grid = self.master.grid + grid = np.append(grid[y:], grid[:y]) + + # Draw out to console + line = 0 + for bits in grid.flat: + pad.move(line, 0) + pad.addstr((bits[x:] + bits[:x]).to01()) + line += 1 + pad.refresh(0, 0, 0, 0, max_y-1, max_x-1) + time.sleep(clock / 1000) + self.tick(rules, *args) def start_console(self, clock, rules, *args): """ Initates main console loop. Works similarly to start_plot but prints out to the console. - TODO: Incorporate curses, instead of just printing repeatedly. """ - while True: - print(self.master.bits()) - time.sleep(clock / 1000) - self.tick(rules, *args) - + curses.wrapper(self._console_run, clock, rules, *args) def randomize(self): """