cellular_automaton.py (4325B)
1 #!/usr/bin/env python3 2 3 import math 4 import random 5 from rpi_ws281x import Color 6 import time 7 8 import patterns 9 10 class CellularAutomaton(patterns.Pattern): 11 12 CELL_ON_COLOR = (0x00, 0xFF, 0x00) 13 CELL_OFF_COLOR = (0x00, 0x00, 0x00) 14 15 def cell_is_on(self, buf, x, y): 16 x = (x + self.led_matrix_width) % self.led_matrix_width 17 y = (y + self.led_matrix_height) % self.led_matrix_height 18 return (buf[self.xy2i(x, y)] == self.CELL_ON_COLOR) 19 20 21 def show_buf(self, buf): 22 for i in range(len(buf)): 23 if(buf[i]): 24 self.strip.setPixelColor(i, Color(buf[i][0], buf[i][1], buf[i][2])) 25 else: 26 self.strip.setPixelColor(i, Color(0x00, 0x00, 0x00)) 27 self.strip.show() 28 29 30 def __init__(self, strip, led_matrix_width, led_matrix_height, led_strip_snake, opts=None): 31 patterns.Pattern.__init__(self, strip=strip, led_matrix_width=led_matrix_width, led_matrix_height=led_matrix_height, led_strip_snake = led_strip_snake, opts=opts) 32 self.matrix_buf = [[None] * (math.ceil(self.led_matrix_width) * math.ceil(self.led_matrix_height)), 33 [None] * (math.ceil(self.led_matrix_width) * math.ceil(self.led_matrix_height))] 34 self.number_of_updates = 0 35 self.stable_pattern = True 36 self.current_buf = self.matrix_buf[0] 37 for index in range(math.ceil(self.led_matrix_width) * math.ceil(self.led_matrix_height)): 38 self.current_buf[index] = self.CELL_OFF_COLOR 39 40 41 def step(self): 42 self.current_buf = self.matrix_buf[self.number_of_updates % 2] 43 self.next_buf = self.matrix_buf[(self.number_of_updates + 1) % 2] 44 # Since we get a stable pattern after sometime, we restart with a 45 # new random cellular automaton after a fixed number of steps or 46 # when we detect a stable situation. 47 if self.stable_pattern or (self.number_of_updates == 100): 48 if True: 49 # Initialize with random values 50 for index in range(math.ceil(self.led_matrix_width) * math.ceil(self.led_matrix_height)): 51 if (random.random() < .5): 52 self.current_buf[index] = self.CELL_ON_COLOR 53 else: 54 self.current_buf[index] = self.CELL_OFF_COLOR 55 else: 56 # Start with a glider 57 self.current_buf[self.xy2i(3,6)] = self.CELL_ON_COLOR 58 self.current_buf[self.xy2i(4,6)] = self.CELL_ON_COLOR 59 self.current_buf[self.xy2i(5,6)] = self.CELL_ON_COLOR 60 self.current_buf[self.xy2i(5,7)] = self.CELL_ON_COLOR 61 self.current_buf[self.xy2i(4,8)] = self.CELL_ON_COLOR 62 self.number_of_updates = 0 63 self.stable_pattern = False 64 65 self.number_of_updates += 1 66 # Cycle over all cells 67 for y in range(math.ceil(self.led_matrix_height)): 68 for x in range(math.ceil(self.led_matrix_width)): 69 # Count neighbors 70 neighbors = 0 71 for y_neighbor in range(3): 72 for x_neighbor in range(3): 73 if (((x_neighbor != 1) or (y_neighbor != 1)) and 74 self.cell_is_on(self.current_buf, 75 (x-x_neighbor+1) % self.led_matrix_width, 76 (y-y_neighbor+1) % self.led_matrix_height)): 77 neighbors += 1 78 # Update cell 79 if (neighbors < 2) or (neighbors > 3): 80 self.next_buf[self.xy2i(x, y)] = self.CELL_OFF_COLOR 81 elif neighbors == 3: 82 self.next_buf[self.xy2i(x, y)] = self.CELL_ON_COLOR 83 else: 84 self.next_buf[self.xy2i(x, y)] = self.current_buf[self.xy2i(x, y)] 85 # Check if pattern has changed since last update. 86 # (We will exit the loop if the pattern becomes stable) 87 self.stable_pattern = True 88 for i in range(math.ceil(self.led_matrix_height) * math.ceil(self.led_matrix_width)): 89 if self.next_buf[i] != self.current_buf[i]: 90 self.stable_pattern = False 91 break 92 self.show_buf(self.current_buf) 93 time.sleep(.1) 94 95