Toggle Navigation
Hatchery
Eggs
Stranger Tractors
__init__.py
Users
Badges
Login
Register
MCH2022 badge?
go to mch2022.badge.team
__init__.py
raw
Content
from collections import namedtuple from time import sleep import badge import ugfx class Attractor(object): def __init__(self,dt,scales,variables=['x','y','z'],initial=0.1): self.dt = dt self.var_count = range(len(variables)) self.variables = variables self.point = namedtuple('point',variables) self.scale = namedtuple('scale',['mi','mx']) self.scales = [self.scale(*i) for i in scales] self.ranges = [1.0 / (s.mx - s.mi) for s in self.scales ] self.initial = initial def delta(self,i,p,dp): l = list(p) l[i] += dp return self.point(*l) def rk4(self,p): k1 = [self.dt*f(p) for f in self.partials] k2 = [self.dt*self.partials[i](self.delta(i,p,0.5 * k1[i])) for i in self.var_count] k3 = [self.dt*self.partials[i](self.delta(i,p,0.5 * k2[i])) for i in self.var_count] k4 = [self.dt*self.partials[i](self.delta(i,p,k3[i])) for i in self.var_count] return self.point(*[p[i] + (0.5 * k1[i] + k2[i] + k3[i] + 0.5 * k4[i]) / 3.0 for i in self.var_count]) def euler(self,p): return self.point(*[r + self.dt * f(p) for r,f in zip(p,self.partials)]) def trace(self,use_rk4=True): p = self.point(*[self.initial for i in self.var_count]) if use_rk4: solver = self.rk4 else: solver = self.euler while True: new_p = solver(p) trigger = new_p.x * p.x < 0.1 yield tuple([self.ranges[i] * (p[i] - self.scales[i].mi) for i in self.var_count] + [trigger] ) p = new_p class Lorenz(Attractor): def __init__(self,sigma=10.0,rho=28.0,beta=8.0/3.0,dt=0.01): self.sigma = sigma self.rho = rho self.beta = beta self.partials = (lambda p: self.sigma * (p.y - p.x), lambda p: p.x * (self.rho - p.z) - p.y, lambda p: p.x * p.y - self.beta * p.z) super(Lorenz,self).__init__(dt, [(-20,25), (-40,40), (0,60)]) class Chua(Attractor): def __init__(self,alpha=15.6,beta=25,dt=0.015): self.alpha = alpha self.beta = beta self.partials = (lambda p: self.alpha * (p.y - p.x - self.f(p.x)), lambda p: p.x - p.y + p.z, lambda p: -self.beta * p.y) super(Chua,self).__init__(dt, [(-3,3), (-0.5,0.5), (-5,5)]) def f(self,h): return -0.7142857142857143 * h + (-0.21428571428571425)*(abs(h+1)-abs(h-1)) class Rossler(Attractor): def __init__(self,a=0.1,b=0.1,c=14.0,dt=0.05): self.a = a self.b = b self.c = c self.partials = (lambda p: -p.y - p.z, lambda p: p.x + self.a * p.y, lambda p: self.b + p.z * (p.x - self.c)) super(Rossler,self).__init__(dt, [(-20,25), (-25,20), (-5,110)],initial=1.0) class App(object): def __init__(self): self.WIDTH = 296 self.HEIGHT = 128 self.scale = 0 self.animal = 0 self.zoo = [Lorenz,Chua,Rossler] self.reset = False self.toggle = False self.blinken = False self.scalers = (lambda x,y,z: [int(x*self.WIDTH),self.HEIGHT-int(z*self.HEIGHT)], lambda x,y,z: [int(x*self.WIDTH),self.HEIGHT-int(y*self.HEIGHT)], lambda x,y,z: [int(y*self.WIDTH),self.HEIGHT-int(z*self.HEIGHT)]) badge.init() ugfx.init() ugfx.input_init() self.reset_trace() self.running = True ugfx.input_attach(ugfx.BTN_B, self.quit) ugfx.input_attach(ugfx.BTN_A, self.blinken_lichten) ugfx.input_attach(ugfx.JOY_LEFT, self.prev_scale) ugfx.input_attach(ugfx.JOY_RIGHT, self.next_scale) ugfx.input_attach(ugfx.JOY_DOWN, self.prev_animal) ugfx.input_attach(ugfx.JOY_UP, self.next_animal) def stream(self): powers = [2**i for i in range(6)] while True: for i in range(64): green = [127 if p & i else 0 for p in powers] lights = [] # Wot no itertools.chain? for g in green: lights.append(g) lights.append(0) lights.append(0) lights.append(0) print(lights) yield bytes(lights) def reset_trace(self): ugfx.clear(ugfx.WHITE) self.attract = self.zoo[self.animal]() self.scaled_trace = (self.scalers[self.scale](x,y,z) for x,y,z,tr in self.attract.trace()) self.points = [self.scaled_trace.__next__() for i in range(128)] for p1, p2 in zip(self.points,self.points[1:]): ugfx.line(* p1 + p2 + [ugfx.BLACK]) def blinken_lichten(self,junk): if not self.toggle: self.toggle = True self.blinken = not self.blinken def quit(self,junk): self.running = False def prev_scale(self,junk): if not self.reset: self.scale = (self.scale - 1 ) % 3 self.reset = True ugfx.flush() def next_scale(self,junk): if not self.reset: self.scale = (self.scale + 1 ) % 3 self.reset = True ugfx.flush() def prev_animal(self,junk): if not self.reset: self.animal = (self.animal - 1 ) % 3 self.reset = True ugfx.flush() def next_animal(self,junk): if not self.reset: self.animal = (self.animal + 1 ) % 3 self.reset = True ugfx.flush() def run(self): lights = self.stream() while self.running: if self.toggle: if self.blinken: badge.leds_init() else: badge.leds_disable() self.toggle = False if self.reset: ugfx.flush() self.reset_trace() self.reset = False if self.blinken: badge.leds_send_data(lights.__next__(), 24) ugfx.line(* self.points[0] + self.points[1] + [ugfx.WHITE]) del self.points[0] self.points.append(self.scaled_trace.__next__()) ugfx.line(* self.points[-2] + self.points[-1] + [ugfx.BLACK]) ugfx.flush() app = App() app.run()