Framework-LED-Matrix 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Background Runner (Screensaver) for LED Matrix.
4
+ Cycles through various scenes randomly.
5
+ """
6
+ import time
7
+ import random
8
+ import sys
9
+ from typing import List
10
+
11
+ try:
12
+ from framework_led_matrix.core.led_commands import log, reset_modules
13
+ from framework_led_matrix.apps.runtime import (
14
+ game_of_life_totalistic_sim,
15
+ run_outer_totalistic_simulation,
16
+ run_inner_totalistic_simulation,
17
+ run_bml_simulation,
18
+ run_draw_anagram_on_matrix,
19
+ run_math_funs_game_of_life,
20
+ show_random_graphs,
21
+ random_greyscale_animation
22
+ )
23
+ from framework_led_matrix.simulations.HardyPomeauPazzis import run_hpp_simulation
24
+ except ImportError as e:
25
+ print(f"Background Runner Import Error: {e}")
26
+ sys.exit(1)
27
+
28
+ def scene_game_of_life():
29
+ steps = random.randint(100, 300)
30
+ initial_board = None
31
+ log(f"[BG] Starting Game of Life for {steps} steps...")
32
+ game_of_life_totalistic_sim(initial_board, timesteps=steps, delay_sec=0.05, which='both')
33
+
34
+ def scene_outer_totalistic():
35
+ b_rule = [random.randint(1, 8) for _ in range(random.randint(1, 3))]
36
+ s_rule = [random.randint(1, 8) for _ in range(random.randint(1, 3))]
37
+ steps = random.randint(100, 200)
38
+ log(f"[BG] Starting Outer-Totalistic (B{b_rule}/S{s_rule}) for {steps} steps...")
39
+ run_outer_totalistic_simulation(None, b_rule, s_rule, timesteps=steps, delay_sec=0.05)
40
+
41
+ def scene_inner_totalistic():
42
+ rule = random.randint(100, 1000)
43
+ steps = random.randint(100, 200)
44
+ log(f"[BG] Starting Inner-Totalistic Rule {rule} for {steps} steps...")
45
+ run_inner_totalistic_simulation(None, rule, timesteps=steps, delay_sec=0.05)
46
+
47
+ def scene_bml_traffic():
48
+ density = random.uniform(0.3, 0.45)
49
+ steps = random.randint(400, 800)
50
+ log(f"[BG] Starting BML Traffic (density={density:.2f}) for {steps} steps...")
51
+ run_bml_simulation(density, timesteps=steps, delay_sec=0.02)
52
+
53
+ def scene_hpp_gas():
54
+ density = random.uniform(0.4, 0.6)
55
+ steps = random.randint(300, 600)
56
+ log(f"[BG] Starting HPP Lattice Gas (density={density:.2f}) for {steps} steps...")
57
+ run_hpp_simulation(None, density, steps, 0.03, 'both')
58
+
59
+ def scene_anagrams():
60
+ words = random.randint(2, 4)
61
+ log(f"[BG] Drawing anagrams for {words} random words...")
62
+ run_draw_anagram_on_matrix(words, 'both')
63
+
64
+ def scene_math_gof():
65
+ steps = random.randint(50, 150)
66
+ log(f"[BG] Starting Math-GoL for {steps} steps...")
67
+ run_math_funs_game_of_life(steps, 0.05)
68
+
69
+ def scene_math_graphs():
70
+ num = random.randint(3, 7)
71
+ log(f"[BG] Showing {num} random math graphs...")
72
+ show_random_graphs(num, 3.0, 'both')
73
+
74
+ def scene_random_noise():
75
+ duration = random.randint(5, 15)
76
+ log(f"[BG] Showing random noise for {duration} seconds...")
77
+ random_greyscale_animation(animate=True, duration_sec=duration)
78
+
79
+ SCENES = [
80
+ scene_game_of_life,
81
+ scene_outer_totalistic,
82
+ scene_inner_totalistic,
83
+ scene_bml_traffic,
84
+ scene_hpp_gas,
85
+ scene_anagrams,
86
+ scene_math_gof,
87
+ scene_math_graphs,
88
+ scene_random_noise
89
+ ]
90
+
91
+ def run_background_mode():
92
+ """
93
+ Main loop for background runner.
94
+ """
95
+ log("--- Starting Background Runner ---")
96
+ log("Press Ctrl+C to stop.")
97
+
98
+ try:
99
+ while True:
100
+ # Pick a random scene
101
+ scene = random.choice(SCENES)
102
+
103
+ try:
104
+ scene()
105
+ # Brief pause between scenes
106
+ time.sleep(1.0)
107
+ reset_modules()
108
+ except KeyboardInterrupt:
109
+ raise
110
+ except Exception as e:
111
+ log(f"[BG] Error in scene {scene.__name__}: {e}")
112
+ # Log traceback for debugging if needed
113
+ # import traceback
114
+ # traceback.print_exc()
115
+ time.sleep(2.0)
116
+ reset_modules()
117
+
118
+ except KeyboardInterrupt:
119
+ log("\nBackground runner stopped by user.")
120
+ finally:
121
+ reset_modules()
122
+ log("Modules reset.")
123
+
124
+ if __name__ == "__main__":
125
+ run_background_mode()
@@ -0,0 +1,185 @@
1
+ from framework_led_matrix.core.led_commands import log, draw_greyscale_on_board, set_led, clear_graph, start_animation, stop_animation, draw_matrix_on_board, reset_modules, WIDTH, HEIGHT, coordinates_to_matrix
2
+ from framework_led_matrix.simulations.BihamMiddletonLevineTrafficModel import run_bml
3
+ from framework_led_matrix.utils.anagrams import draw_anagram_on_matrix, anagrams, ensure_nltk_words
4
+ # Note: 'words' corpus is imported inside anagrams.py or needs to be available
5
+ from framework_led_matrix.utils.text_rendering import draw_text_vertical
6
+ from framework_led_matrix.core.math_engine import MATH_OPERATIONS, pick_largest_graph
7
+ from framework_led_matrix.simulations.inner_totalistic import run_totalistic_ca
8
+ from framework_led_matrix.simulations.outer_totalistic import run_outer_totalistic_ca, game_of_life_rules, STARTING_STATES_GOF
9
+ from typing import List, Optional
10
+ from framework_led_matrix.simulations.HardyPomeauPazzis import run_hpp_simulation, create_hpp_board_np
11
+ import random
12
+ import time
13
+ import numpy as np
14
+ import nltk
15
+ from nltk.corpus import words
16
+
17
+
18
+ def run_hpp_with_math(density: float = 0.3, timesteps: int = 500, delay_sec: float = 0.1, graphs_count: int = 5):
19
+ log("HPP: Running HPP simulation with math function graphs.")
20
+ for func in random.sample(MATH_OPERATIONS, graphs_count):
21
+ func = pick_largest_graph(func)
22
+ draw_matrix_on_board(func)
23
+ func = create_hpp_board_np(initial_state=np.array(func))
24
+ time.sleep(3)
25
+ run_hpp_simulation(
26
+ initial_state=func,
27
+ density=density,
28
+ timesteps=timesteps,
29
+ delay_sec=delay_sec,
30
+ which='both'
31
+ )
32
+
33
+ def run_outer_totalistic_simulation(initial_state: Optional[List[List[int]]] = None, b_rule: Optional[List[int]] = None, s_rule: Optional[List[int]] = None, timesteps: int = 100, delay_sec: float = 0.1, oscilation_max_steps: int = 20, still_board_max_steps: int = 10, empty_board_max_steps: int = 5):
34
+ # normalize defaults to avoid mutable default arguments and satisfy type annotations
35
+ if b_rule is None:
36
+ b_rule = [3]
37
+ if s_rule is None:
38
+ s_rule = [2,3]
39
+
40
+ initial_state_np = np.random.randint(0, 2, size=(HEIGHT, WIDTH), dtype=int) if initial_state is None else np.array(initial_state, dtype=int)
41
+ log(f"Running Outer-Totalistic CA: B{b_rule}/S{s_rule} for {timesteps} steps.")
42
+ all_generations = run_outer_totalistic_ca(initial_state_np, timesteps, b_rule, s_rule)
43
+ oscilation_counter = 0
44
+ still_board_counter = 0
45
+ empty_board_counter = 0
46
+ for t in range(all_generations.shape[0]):
47
+ frame_np = all_generations[t]
48
+ frame_list = frame_np.tolist()
49
+ draw_matrix_on_board(frame_list, which='both')
50
+ time.sleep(delay_sec)
51
+ #oscilation
52
+ if all_generations[t].tolist() == all_generations[t-2].tolist() and t >=2:
53
+ oscilation_counter +=1
54
+ if oscilation_counter >= oscilation_max_steps:
55
+ log(f"oscillation at step {t-oscilation_max_steps}. Ending simulation.")
56
+ break
57
+ else:
58
+ oscilation_counter = 0
59
+
60
+ # still life
61
+ if np.all(frame_np == 0):
62
+ still_board_counter += 1
63
+ if still_board_counter >= still_board_max_steps:
64
+ log(f"still life detected at step {t-still_board_max_steps}. Ending simulation.")
65
+ break
66
+ else:
67
+ still_board_counter = 0
68
+
69
+ # empty board
70
+ if np.all(frame_np == 0):
71
+ empty_board_counter += 1
72
+ if empty_board_counter >= empty_board_max_steps:
73
+ log(f"empty board detected at step {t-empty_board_max_steps}. Ending simulation.")
74
+ break
75
+ else:
76
+ empty_board_counter = 0
77
+
78
+
79
+ def game_of_life_totalistic_sim(initial_board: Optional[List[List[int]]] = None, generations: int = 200, delay_sec: float = 0.1, which: str = 'both'):
80
+ initial_state_np = np.array(initial_board, dtype=int) if initial_board is not None else np.random.randint(0, 2, size=(HEIGHT, WIDTH), dtype=int)
81
+ b_rule = game_of_life_rules['Original']['B']
82
+ s_rule = game_of_life_rules['Original']['S']
83
+ run_outer_totalistic_simulation(initial_state_np.tolist(), b_rule, s_rule, generations, delay_sec)
84
+
85
+
86
+ def run_bml_simulation(density: float = 0.3, timesteps: int = 100, delay_sec: float = 0.1):
87
+ run_bml(density=density, steps=timesteps, delay_sec=delay_sec)
88
+
89
+ def run_inner_totalistic_simulation(initial_state: Optional[List[List[int]]] = None, rule_number: int = 777, timesteps: int = 200, delay_sec: float = 0.1):
90
+ initial_state_np = np.array(initial_state, dtype=int) if initial_state is not None else np.random.randint(0, 2, size=(HEIGHT, WIDTH), dtype=int)
91
+ log(f"Running Inner-Totalistic CA: rule={rule_number} for {timesteps} steps.")
92
+ all_generations = run_totalistic_ca(initial_state_np, timesteps, rule_number)
93
+
94
+ try:
95
+ for t in range(all_generations.shape[0]):
96
+ frame_np = all_generations[t]
97
+ frame_list = frame_np.tolist()
98
+ draw_matrix_on_board(frame_list, which='both')
99
+ time.sleep(delay_sec)
100
+
101
+ except KeyboardInterrupt:
102
+ log("Animation stopped by user.")
103
+ clear_graph()
104
+
105
+ def random_greyscale_animation(animate: bool = True, duration_seconds: int = 10):
106
+ log(f"random_greyscale_animation: start animate={animate} duration_seconds={duration_seconds}")
107
+ matrix = [[0 for _ in range(WIDTH)] for _ in range(HEIGHT)]
108
+ if animate:
109
+ log("random_greyscale_animation: starting hardware animation")
110
+ start_animation()
111
+ else:
112
+ log("random_greyscale_animation: ensuring animation stopped")
113
+ stop_animation()
114
+
115
+ timeout_start = time.time()
116
+ frames = 0
117
+ while time.time() < timeout_start + duration_seconds:
118
+ frames += 1
119
+ # fill matrix with random brightness
120
+ for row in range(HEIGHT):
121
+ for col in range(WIDTH):
122
+ brightness = int(random.triangular(0, 255, 0))
123
+ set_led(matrix, row, col, brightness)
124
+ draw_greyscale_on_board(matrix, which='both')
125
+ # log periodically to avoid overwhelming logs
126
+ if frames % 20 == 0:
127
+ remaining = max(0, timeout_start + duration_seconds - time.time())
128
+ log(f"random_greyscale_animation: frames={frames} time_remaining={remaining:.1f}s")
129
+ log(f"random_greyscale_animation: completed frames={frames}")
130
+ stop_animation()
131
+ clear_graph()
132
+ log("random_greyscale_animation: stopped animation and cleared display")
133
+
134
+ def run_anagrams_game_of_life(word_limit: int = 4, generations: int = 100, delay_sec: float = 0.1, which: str = 'both'):
135
+ log("runtime.py: run_anagrams_game_of_life() entry")
136
+ ensure_nltk_words()
137
+ eligible_words = [word for word in words.words() if len(word) <= 7]
138
+ actual_limit = min(word_limit, len(eligible_words))
139
+ for word in random.sample(eligible_words, actual_limit):
140
+ ana_lst = anagrams(word)
141
+ ana_lst.add(word)
142
+ ana_lst = list(ana_lst)
143
+ for w in ana_lst:
144
+ log(f"runtime.py: run_anagrams_game_of_life() rendering word '{w}'")
145
+ matrix = draw_text_vertical(w, which=which)
146
+ time.sleep(2)
147
+ start_animation()
148
+ time.sleep(3)
149
+ stop_animation()
150
+ draw_text_vertical(w, which=which)
151
+ game_of_life_totalistic_sim(initial_board=matrix, generations=generations, delay_sec=delay_sec, which=which)
152
+
153
+ def run_draw_anagram_on_matrix(word_limit: int = 3, which: str = 'both'):
154
+ log("runtime.py: run_draw_anagram_on_matrix() entry")
155
+ ensure_nltk_words()
156
+ eligible_words = [word for word in words.words() if len(word) <= 7]
157
+ actual_limit = min(word_limit, len(eligible_words))
158
+ for word in random.sample(eligible_words, actual_limit):
159
+ draw_anagram_on_matrix(word, which=which, animate=True)
160
+
161
+
162
+ def run_math_funs_game_of_life(generations: int = 100, delay_sec: float = 0.1):
163
+ for func in random.sample(MATH_OPERATIONS, len(MATH_OPERATIONS)):
164
+ func = pick_largest_graph(func)
165
+ draw_matrix_on_board(func)
166
+ time.sleep(2)
167
+ game_of_life_totalistic_sim(initial_board=func, generations=generations, delay_sec=delay_sec, which='both')
168
+
169
+ def show_random_graphs(num_graphs: int = 5, delay_sec: float = 2.0, which: str = 'both'):
170
+ log(f"show_random_graphs: start num_graphs={num_graphs} delay_sec={delay_sec} which={which}")
171
+ for i in range(num_graphs):
172
+ func = random.choice(MATH_OPERATIONS)
173
+ log(f"show_random_graphs: graph {i+1}/{num_graphs}, selected function {func.__name__}")
174
+ graph_matrix = pick_largest_graph(func)
175
+ draw_matrix_on_board(graph_matrix, which=which)
176
+ time.sleep(delay_sec)
177
+ log("show_random_graphs: completed all graphs, clearing display")
178
+ clear_graph()
179
+
180
+
181
+ if __name__ == "__main__":
182
+ try:
183
+ run_math_funs_game_of_life(generations=300, delay_sec=0.001)
184
+ finally:
185
+ reset_modules()
File without changes