Created
March 24, 2023 18:21
-
-
Save ErinLMoore/faa70bd59e68bfb7e6b723563ee67a21 to your computer and use it in GitHub Desktop.
Adafruit Neotrellis Micropython coe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-FileCopyrightText: 2022 ladyada for Adafruit Industries | |
# SPDX-License-Identifier: MIT | |
import time | |
import board | |
from adafruit_neotrellis.neotrellis import NeoTrellis | |
from adafruit_neotrellis.multitrellis import MultiTrellis | |
from random import randint | |
###### Settings ######## | |
i2c_bus = board.I2C() | |
trellis = MultiTrellis([ | |
[NeoTrellis(i2c_bus, False, addr=0x2E), NeoTrellis(i2c_bus, False, addr=0x2F)], | |
[NeoTrellis(i2c_bus, False, addr=0x30), NeoTrellis(i2c_bus, False, addr=0x31)], | |
]) | |
trelli = [ | |
[NeoTrellis(i2c_bus, False, addr=0x2E), NeoTrellis(i2c_bus, False, addr=0x2F)], | |
[NeoTrellis(i2c_bus, False, addr=0x30), NeoTrellis(i2c_bus, False, addr=0x31)], | |
] | |
trellis.brightness = 0.5 | |
MAX_X = 7 #leds in column | |
MAX_Y = 7 #leds in row | |
# some color definitions | |
OFF = (0, 0, 0) | |
RED = (255, 0, 0) | |
YELLOW = (255, 255, 0) | |
ORANGE = (255, 100, 0) | |
GREEN = (0, 255, 0) | |
CYAN = (0, 255, 255) | |
BLUE = (0, 0, 255) | |
INDIGO = (100, 0, 255) | |
PURPLE = (255, 0, 150) | |
COLORS = [OFF, YELLOW, BLUE, RED, GREEN, CYAN, ORANGE, INDIGO, PURPLE] | |
the_matrix = [ [0] * (MAX_X + 1) for _ in range(MAX_Y + 1)] | |
#################################################################### | |
####################life function ##############33 | |
OFF = 0 | |
LIFE_MODE = [0] | |
BORN = 3 | |
SURVIVES = [2,3] | |
def life_callback(x, y, edge): | |
if edge == NeoTrellis.EDGE_RISING: | |
if the_matrix[y][x] != OFF: | |
the_matrix[y][x] = OFF | |
else: | |
the_matrix[y][x] = randint(1, len(COLORS)) | |
show_matrix_colors(the_matrix) | |
check_for_switch(x,y,edge) | |
check_for_life_switch(x,y,edge) | |
def calc_life(): | |
if LIFE_MODE[0] == 1: | |
new_matrix = [x[:] for x in the_matrix] | |
[maybe_life(x,y, new_matrix) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
[update_matrix(new_matrix, y, x) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
def maybe_life(x,y, new_matrix): | |
neighbors = list(map(toroid_neighbors, get_neighbors_moore(x,y))) | |
frequency = neighbor_frequencies(neighbors) | |
if the_matrix[y][x] == OFF and OFF in frequency and frequency[OFF] == (8 - BORN): | |
new_matrix[y][x] = randint(1, len(COLORS)) | |
if the_matrix[y][x] != OFF and OFF in frequency and (frequency[OFF] < (8 - SURVIVES[1]) or frequency[OFF] > (8 - SURVIVES[0])): | |
new_matrix[y][x] = 0 | |
def check_for_life_switch(x,y,edge): | |
if (x,y) == (7,0) : | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[0] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[0] = False | |
elif (x,y) == (7,7): | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[1] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[1] = False | |
if PRESSED == [True, True]: | |
print("Switching Life Mode...") | |
switch_life_mode() | |
print("Life Mode Switched") | |
print(LIFE_MODE[0]) | |
def switch_life_mode(): | |
PRESSED[0] = False | |
PRESSED[1] = False | |
LIFE_MODE[0] = LIFE_MODE[0] ^ 1 | |
################3 | |
##################### wires functions #################################3 | |
WIRES_MODE = [0] | |
OFF = 0 | |
CONDUCTOR = 1 | |
ELECTRON_HEAD = 2 | |
ELECTRON_TAIL = 3 | |
def wires_callback(x, y, edge): | |
if edge == NeoTrellis.EDGE_RISING: | |
the_matrix[y][x] = the_matrix[y][x] + 1 | |
if the_matrix[y][x] > ELECTRON_TAIL: | |
the_matrix[y][x] = OFF | |
show_matrix_colors(the_matrix) | |
check_for_switch(x,y,edge) | |
check_for_wires_switch(x,y,edge) | |
def calc_wires(): | |
if WIRES_MODE[0] == 1: | |
new_matrix = [x[:] for x in the_matrix] | |
[maybe_change(x, y, new_matrix) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
[update_matrix(new_matrix, y, x) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
def maybe_change(x, y, new_matrix): | |
neighbors = list(map(toroid_neighbors, get_neighbors_moore(x,y))) | |
if the_matrix[y][x] == ELECTRON_HEAD: | |
new_matrix[y][x] = ELECTRON_TAIL | |
elif the_matrix[y][x] == ELECTRON_TAIL: | |
new_matrix[y][x] = CONDUCTOR | |
elif the_matrix[y][x] == CONDUCTOR and enough_neighbors(neighbors) == True: | |
new_matrix[y][x] = ELECTRON_HEAD | |
def enough_neighbors(neighbors): | |
frequency = neighbor_frequencies(neighbors) | |
if ELECTRON_HEAD in frequency and (frequency[ELECTRON_HEAD] == 1 or frequency[ELECTRON_HEAD] == 2): | |
return True | |
else: return False | |
# conductor → electron head if exactly one or two of the neighbouring cells are electron heads, otherwise remains conductor. | |
def check_for_wires_switch(x,y,edge): | |
if (x,y) == (7,0) : | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[0] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[0] = False | |
elif (x,y) == (7,7): | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[1] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[1] = False | |
if PRESSED == [True, True]: | |
print("Switching Wires Mode...") | |
switch_wires_mode() | |
print("Wires Mode Switched") | |
print(WIRES_MODE[0]) | |
def switch_wires_mode(): | |
PRESSED[0] = False | |
PRESSED[1] = False | |
the_matrix[0][7] = 0 | |
the_matrix[7][7] = 0 | |
WIRES_MODE[0] = WIRES_MODE[0] ^ 1 | |
########################## sandpile functions ############################# | |
MAX_PILE_SIZE = 3 #it will topple if it goes over this number. 3 topples to 4 neighbors, 7 to 8. | |
TOPPLE_AMOUNT = MAX_PILE_SIZE + 1 | |
def sandpile_callback(x, y, edge): | |
if edge == NeoTrellis.EDGE_RISING: | |
the_matrix[y][x] = the_matrix[y][x] + 1 | |
show_matrix_colors(the_matrix) | |
check_for_switch(x,y,edge) | |
def calc_sandpile(): | |
new_matrix = [x[:] for x in the_matrix] | |
[maybe_overflow(x, y, new_matrix) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
[update_matrix(new_matrix, y, x) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
def maybe_overflow(x, y, new_matrix): | |
if the_matrix[y][x] > MAX_PILE_SIZE: | |
new_matrix[y][x] = the_matrix[y][x] - TOPPLE_AMOUNT | |
neighborhood = get_neighbors_vn if TOPPLE_AMOUNT <= 4 else get_neighbors_moore | |
[increment_neighbor(neighbor, new_matrix) for neighbor in neighborhood(x,y)] | |
def increment_neighbor(neighbor, new_matrix): | |
n_x = neighbor[0] | |
n_y = neighbor[1] | |
if neighbor_in_range(neighbor) == True: | |
new_matrix[n_y][n_x] = the_matrix[n_y][n_x] + 1 | |
def neighbor_in_range(value): | |
x_ok = value[0] >= 0 and value[0] <= MAX_X | |
y_ok = value[1] >= 0 and value[1] <= MAX_Y | |
return x_ok and y_ok | |
##################################################### | |
####################### shared functions ################################## | |
MODE = [0] | |
CALLBACKS = [life_callback, sandpile_callback, wires_callback] | |
CALCS = [calc_life, calc_sandpile, calc_wires] | |
PRESSED = [False, False] | |
def update_matrix(new_matrix, y, x): | |
the_matrix[y][x] = new_matrix[y][x] | |
def neighbor_frequencies(neighbors): | |
neighbor_values = [the_matrix[neighbor[1]][neighbor[0]] for neighbor in neighbors] | |
frequency = {} | |
for i in neighbor_values: | |
frequency[i] = frequency.get(i,0) + 1 | |
return frequency | |
def get_neighbors_vn(x, y): | |
return [(x - 1, y), (x + 1, y), (x, y + 1), (x, y - 1)] | |
def get_neighbors_moore(x, y): | |
return [(x - 1, y), (x + 1, y), (x, y + 1), (x, y - 1), (x - 1, y + 1), (x - 1, y - 1), (x + 1, y + 1), (x + 1, y - 1)] | |
def toroid_neighbors(neighbor): | |
x = neighbor[0] | |
y = neighbor[1] | |
if x < 0: | |
x = MAX_X | |
elif x > MAX_X: | |
x = 0 | |
if y < 0: | |
y = MAX_Y | |
elif y > MAX_Y: | |
y = 0 | |
return (x,y) | |
def change_color(x, y, value): | |
#OFF is a color | |
color = value if value < len(COLORS) else len(COLORS) -1 | |
trellis.color(x, y, COLORS[color]) | |
def show_matrix_colors(the_matrix): | |
[change_color(x, y, the_matrix[y][x]) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
def check_for_switch(x,y, edge): | |
if (x,y) == (0,0) : | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[0] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[0] = False | |
elif (x,y) == (0,7): | |
if edge == NeoTrellis.EDGE_RISING: | |
PRESSED[1] = True | |
if edge == NeoTrellis.EDGE_FALLING: | |
PRESSED[1] = False | |
if PRESSED == [True, True]: | |
print("Switching...") | |
switch_mode() | |
print(CALLBACKS[MODE[0]]) | |
time.sleep(1) | |
print("Mode Switched!") | |
def switch_mode(): | |
PRESSED[0] = False | |
PRESSED[1] = False | |
MODE[0] = MODE[0] + 1 | |
if MODE[0] >= len(CALLBACKS): | |
MODE[0] = 0 | |
init() | |
############################################# | |
################### init neotrellis ######## | |
def init(): | |
[test_and_set_callback(x, y, COLORS[y+1]) for y in range(MAX_Y + 1) for x in range(MAX_X + 1)] | |
for i in range(MAX_Y + 1): | |
the_matrix[i] = [0] * (MAX_X + 1) | |
show_matrix_colors(the_matrix) | |
def test_and_set_callback(x, y, color): | |
trellis.activate_key(x, y, NeoTrellis.EDGE_RISING) | |
trellis.activate_key(x, y, NeoTrellis.EDGE_FALLING) | |
trellis.set_callback(x, y, CALLBACKS[MODE[0]]) | |
trellis.color(x, y, color) | |
init() | |
######################################## | |
######## main loop ##################### | |
while True: | |
# The NeoTrellis can only be read every 17 milliseconds or so | |
trellis.sync() | |
time.sleep(0.02) | |
show_matrix_colors(the_matrix) | |
CALCS[MODE[0]]() | |
############################################ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment