import threading import time import sys import math import random from collections import deque # Install colorama for color support (pip install colorama) try: from colorama import init as colorama_init, Fore, Back, Style colorama_init(autoreset=True) except ImportError: # fallback, no colors class DummyColor: def __getattr__(self, name): return '' Fore = Back = Style = DummyColor() # Optional sound — pygame for cross-platform beep try: import pygame pygame.mixer.init() SOUND_ENABLED = True except ImportError: SOUND_ENABLED = False WIDTH = 80 HEIGHT = 40 # L-system parameters for fractal tree AXIOM = "X" RULES = { "X": "F-[[X]+X]+F[+FX]-X", "F": "FF" } ANGLE = 25 # degrees # Global state lsystem_string = "" lsystem_lock = threading.Lock() # Turtle graphics for drawing in ASCII grid class TurtleState: def __init__(self, x, y, angle): self.x = x self.y = y self.angle = angle # Initialize empty screen grid screen_grid = [[' ' for _ in range(WIDTH)] for __ in range(HEIGHT)] def clear_screen(): print("\033[2J\033[H", end='') def draw_pixel(x, y, char='*', color=Fore.GREEN): if 0 <= x < WIDTH and 0 <= y < HEIGHT: screen_grid[y][x] = color + char + Style.RESET_ALL def print_screen(): clear_screen() for row in screen_grid: print(''.join(row)) def lsystem_iterate(s): """Perform one iteration of the L-system""" result = [] for c in s: if c in RULES: result.append(RULES[c]) else: result.append(c) return ''.join(result) def polar_to_cartesian(angle_deg, length): rad = math.radians(angle_deg) return length * math.cos(rad), length * math.sin(rad) def draw_lsystem(lsys_str, start_x, start_y, start_angle, length=3): stack = [] x, y = start_x, start_y angle = start_angle for command in lsys_str: if command == 'F': dx, dy = polar_to_cartesian(angle, length) new_x, new_y = x + dx, y - dy # Draw line from (x,y) to (new_x,new_y) approx: draw_line(int(round(x)), int(round(y)), int(round(new_x)), int(round(new_y))) x, y = new_x, new_y elif command == '+': angle += ANGLE elif command == '-': angle -= ANGLE elif command == '[': stack.append(TurtleState(x, y, angle)) elif command == ']': state = stack.pop() x, y, angle = state.x, state.y, state.angle def draw_line(x0, y0, x1, y1): """Bresenham's line algorithm""" dx = abs(x1 - x0) dy = abs(y1 - y0) x, y = x0, y0 sx = 1 if x0 < x1 else -1 sy = 1 if y0 < y1 else -1 if dx > dy: err = dx / 2.0 while x != x1: draw_pixel(x, y) err -= dy if err < 0: y += sy err += dx x += sx draw_pixel(x, y) else: err = dy / 2.0 while y != y1: draw_pixel(x, y) err -= dx if err < 0: x += sx err += dy y += sy draw_pixel(x, y) def fractal_generator(iterations, delay=1.5): global lsystem_string s = AXIOM for i in range(iterations): with lsystem_lock: lsystem_string = s time.sleep(delay) s = lsystem_iterate(s) def render_loop(): while True: with lsystem_lock: current = lsystem_string # Clear grid for y in range(HEIGHT): for x in range(WIDTH): screen_grid[y][x] = ' ' draw_lsystem(current, WIDTH//2, HEIGHT-2, -90, length=2) # Add color gradient based on iteration length iteration_depth = len(current) # Apply some color pulses for fun color = random.choice([Fore.GREEN, Fore.CYAN, Fore.MAGENTA, Fore.YELLOW]) for y in range(HEIGHT): for x in range(WIDTH): c = screen_grid[y][x] if c != ' ': screen_grid[y][x] = color + '*' + Style.RESET_ALL print_screen() print(f"Fractal length: {len(current)} | Press Ctrl+C to exit.") time.sleep(0.5) def sound_thread(): if not SOUND_ENABLED: return frequencies = [262, 294, 330, 349, 392, 440, 494] while True: freq = random.choice(frequencies) sound = pygame.mixer.Sound(frequency=freq, size=-16, channels=1, buffer=1024) sound.play() time.sleep(0.3) def user_input_loop(): global ANGLE print("Press '+' or '-' to increase/decrease branch angle; Ctrl+C to quit.") while True: try: key = input() if key == '+': ANGLE = min(90, ANGLE + 5) print(f"Angle increased to {ANGLE}") elif key == '-': ANGLE = max(0, ANGLE - 5) print(f"Angle decreased to {ANGLE}") except KeyboardInterrupt: print("\nExiting...") sys.exit(0) def main(): iterations = 6 fg_thread = threading.Thread(target=fractal_generator, args=(iterations,), daemon=True) fg_thread.start() rl_thread = threading.Thread(target=render_loop, daemon=True) rl_thread.start() if SOUND_ENABLED: snd_thread = threading.Thread(target=sound_thread, daemon=True) snd_thread.start() user_input_loop() if __name__ == "__main__": main()