led_pillar

Documentation: http://frombelow.net/projects/led_pillar/
Clone: git clone https://git.frombelow.net/led_pillar.git
Log | Files | Refs | Submodules | README | LICENSE

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