class Glider(Mode): def start(self, count, randomize, step, **params): info("start life") self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) mask = self.fluepdot.buffer.read() self.life = life.Life(mask=mask) if randomize: for c in range(count): a, b = int(2. * (random.getrandbits(1) - 0.5)), (int( 2. * (random.getrandbits(1) - 0.5))) log("got random {:d},{:d}".format(a, b)) direction = Direction((a, b)) log("got direction {:s}".format(str(direction))) pos = Position(random.randint(0, FRAMESIZE.w - 1), random.randint(0, FRAMESIZE.h - 1)) step = random.randint(0, 3) log("add glider #{:d} at {:d}/{:d} course {:s}".format( c, pos.x, pos.y, str(direction))) self.life.spawn(life.Pattern.glider, pos=pos, step=step) else: d = int(FRAMESIZE.w / count) direction = Direction.southeast stp = step % 4 pos = Position(int(FRAMESIZE.w / 2), int(FRAMESIZE.h / 2)) for c in range(count): log("add glider #{:d} at {:d}/{:d} course {:s}".format( c, pos.x, pos.y, str(direction))) self.life.spawn(life.Pattern.glider, pos=pos, step=stp) pos = Position((pos.x + d) % FRAMESIZE.w, pos.y) lon, lat = direction.value direction = Direction((lon * -1, lat * -1)) stp = (stp + 1) % 5 # self.life.addGlider(direction=Direction.SouthEast) # self.life.addGlider(pos=(25,4),step=2,direction=Direction.NorthEast) # self.life.addGlider(pos=(50,6),step=4,direction=Direction.SouthWest) # self.life.addGlider(pos=(100,8),step=3,direction=Direction.NorthWest) self.mask = self.draw(**params) return True def draw(self, **params): prev = self.fluepdot.buffer.read() mask = Mask(mask=self.life) self.fluepdot.buffer.write(mask) info(str(mask)) return mask flags = [ Mode.FLAG("count"), Mode.FLAG("randomize"), Mode.FLAG("step"), ]
class Flueptext(Mode): def start(self, randomize, x, y, fluepfont, msg=None, **params): # self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.randomize = randomize self.font = font self.msg = "hello, world." if msg: self.msg = msg info("start flueptext {:s}: {:s}".format(fluepfont, self.msg)) self.mask = self.draw(x, y, fluepfont, **params) log(str(self.mask)) return True def draw(self, x, y, fluepfont, **params): self.mask = self.fluepdot.text(x, y, fluepfont, self.msg) return self.mask flags = [ ("F:", "fluepfont=", "fluepfont", "fixed_10x20", "fluepdot font", None), Mode.FLAG("x"), Mode.FLAG("y"), Mode.FLAG("randomize"), (None, None, "msg", "hello, world.", "message", None), ]
class Pixel(Mode): def start(self, x, y, invert, **params): info("start pixel {:d}/{:d}".format(x, y)) pxl = self.fluepdot.pixel.read(x, y) if pxl: log("pixel {:d}/{:d} ⬛︎ bright".format(x, y)) else: log("pixel {:d}/{:d} ⬜︎ dark".format(x, y)) if not invert and not pxl: log("pixel {:d}/{:d} flip bright: ⬛︎".format(x, y)) self.fluepdot.pixel.flip(x, y, True) if invert and pxl: log("pixel {:d}/{:d} flip dark: ⬜︎".format(x, y)) self.fluepdot.pixel.flip(x, y, False) mask = self.fluepdot.buffer.read() log(str(mask)) return False def draw(self, **params): log(str(self.mask)) return self.mask flags = [ Mode.FLAG("x"), Mode.FLAG("y"), Mode.FLAG("invert"), ]
class Life(Mode): def start(self,count,**params): info("start life") self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) mask = self.fluepdot.buffer.read() self.life = life.Life(mask=mask) self.draw(**params) return True def draw(self,**params): self.life.step() return Mask(mask=self.life) flags = [ Mode.FLAG("count"), ]
class Grow(Mode): def start(self,**params): info("start grow") self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.mask = self.draw(**params) return True def draw(self,invert,**params): cx = int(FRAMESIZE.w/2) cy = int(FRAMESIZE.h/2) r0 = random.gauss(0.,1.) r1 = random.gauss(0.,1.) x = cx + int(r0*(cx/4.)) y = cy + int(r1*(cy/4.)) pxl = self.fluepdot.pixel.read(x,y) if invert: if pxl: self.fluepdot.pixel.flip(x,y,False) self.mask = self.fluepdot.buffer.read() log(str(self.mask)) else: if not pxl: self.fluepdot.pixel.flip(x,y,True) self.mask = self.fluepdot.buffer.read() log(str(self.mask)) return self.mask flags = [ Mode.FLAG("invert"), ]
class Spawn(Mode): Pattern = life.Pattern DefaultPattern = life.Pattern.glider DefaultPosition = Position(0,0) def start(self,x,y,randomize,pattern,step,count,flip,**params): info("start spawn {:s}".format(pattern.name.lower())) self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.life = life.Life(mask=self.mask) if randomize: for c in range(count): pos = Position(random.randint(0,FRAMESIZE.w-1),random.randint(0,FRAMESIZE.h-1)) self.life.spawn(pattern,pos,step,random.choice( list(Flip) )) else: pos = Position(x,y) self.life.spawn(pattern,pos,step,flip) self.draw(**params) return True def draw(self,**params): self.life.step() mask = Mask(mask=self.life) self.fluepdot.buffer.write(mask) return mask flags = [ Mode.FLAG("pattern",DefaultPattern), Mode.FLAG("step"), Mode.FLAG("count"), Mode.FLAG("randomize"), ("F:","flip=","flip",Flip.noflip,"flip pattern?",lambda x: Flip[x]), Mode.FLAG("x"), Mode.FLAG("y"), ]
class Dots(Mode): def start(self, **params): info("start dots") self.count = 0 self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.mask = self.fluepdot.buffer.read() self.mask = self.draw(**params) return True def draw(self, invert, **params): cx = int(FRAMESIZE.w / 2) cy = int(FRAMESIZE.h / 2) r0 = random.gauss(0., 1.5) r1 = random.gauss(0., 2.) x = cx + int(r0 * (cx / 4.)) y = cy + int(r1 * (cy / 4.)) prev = Mask(mask=self.mask) self.mask[x, y] ^= True self.mask[x, y - 1] ^= True self.mask[x + 1, y] ^= True self.mask[x, y + 1] ^= True self.mask[x - 1, y] ^= True self.fluepdot.pixel.flip(x, y, self.mask[x, y]) self.fluepdot.pixel.flip(x, y - 1, self.mask[x, y - 1]) self.fluepdot.pixel.flip(x - 1, y, self.mask[x - 1, y]) self.fluepdot.pixel.flip(x + 1, y, self.mask[x + 1, y]) self.fluepdot.pixel.flip(x, y + 1, self.mask[x, y + 1]) log(str(self.mask)) return self.mask flags = [ Mode.FLAG("invert"), ]
class Guns(Mode): def start(self, randomize, **params): info("start guns") self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.life = life.Life(mask=self.mask) pos1 = Position(10, 2) pos2 = Position(60, 7) off1 = Position(x=24, y=10) off2 = Position(x=24, y=-5) self.life.spawn(life.Pattern.gun, pos=pos1) self.life.spawn(life.Pattern.eater, pos=pos1 + off1) self.life.spawn(life.Pattern.gun, pos=pos2, flip=Flip.horizontal) self.life.spawn(life.Pattern.eater, pos=pos2 + off2, flip=Flip.horizontal) self.mask = Mask(self.life) self.draw(**params) return True def draw(self, **params): self.life.step() self.mask = Mask(mask=self.life) self.fluepdot.buffer.write(self.mask) info(str(self.mask)) return self.mask flags = [ Mode.FLAG("randomize"), ]
class Smooth(Mode): DefaultFont = FONT.font3x5 def start(self, font, msg=None, **params): # self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.font = Font(font) debug(str(self.font)) self.msg = "hello, world." if msg: self.msg = msg info("start scroll: {:s}".format(self.msg)) self.mask = Mask() self.text = self.font.render(self.msg, fixed=True) p0 = int(math.floor(FRAMESIZE.w / (self.font.size.w + 1))) p1 = p0 - len(self.msg) self.pos0 = Position((self.font.size.w + 1) * int(p1 / 2), 0) # self.pos0 = Position(int(FRAMESIZE.w/2)-int(self.text.w/2), 0 ) self.mask.addMask(self.text, pos=self.pos0, wrap=True) self.fluepdot.buffer.write(self.mask) self.l = self.text.w self.k = 0 return True def draw(self, **params): ret = [] k = self.k L = self.l W, H = self.font.size.w + 1, self.font.size.h + 1 next = Mask() pos0 = Position(k, 0) next = Mask() next.addMask(self.text, pos=self.pos0 + pos0, wrap=True) log("from\n" + str(self.mask)) log("to\n" + str(next)) # steps = Morph2(self.mask,next) # steps = Scan(self.mask,next) # steps = [self.mask,next] steps = [self.mask, next] return next for i in range(len(steps)): step = steps[i] ret += [step] self.mask = step self.k += 1 if self.k >= self.l: log("step") self.k = 0 self.pos0.x += self.l if self.pos0.x + self.l >= FRAMESIZE.w: self.pos0.x -= FRAMESIZE.w return ret flags = [ Mode.FLAG("font", DefaultFont), ("P:", "pause=", "pause", 1.0, "pause", lambda x: int(x)), (None, None, "msg", "hello, world.", "message", None), ]
class Clock(Mode): Style = dotlife.clock.Style DefaultStyle = dotlife.clock.Style.large def start(self, style, stamp, cuckoo, **params): self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.clock = dotlife.clock.Clock() self.timezone = datetime.timezone( datetime.timedelta(seconds=-time.timezone)) self.now = datetime.datetime.now(self.timezone) if stamp != "": self.now = datetime.datetime.fromisoformat(stamp) self.start = datetime.datetime.now(self.timezone) info("start clock: {:s}{:s}".format(self.now.strftime("%F %T"), " [kuckuck]" if cuckoo else "")) self.mask = self.clock.mask(size=FRAMESIZE, now=self.now, style=style) self.next = self.mask self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.kuckuck = None self.hour = self.now.hour return True def step(self, style, stamp, **params): self.now = datetime.datetime.now(self.timezone) if stamp != "": self.now = datetime.datetime.fromisoformat(stamp) + ( datetime.datetime.now(self.timezone) - self.start) self.next = self.clock.mask(size=FRAMESIZE, now=self.now, style=style) def draw(self, style, stamp, cuckoo, **params): if self.kuckuck and self.kuckuck.active(): hour = int(self.kuckuck.repeat / 1) count = int(self.kuckuck.count / 1) + 1 ret = Mask() idx = self.kuckuck.count % 2 if 1 <= hour <= 4: vader = invader.INVADER.one.Mask(idx).double() msk = Mask(size=Size((4 + vader.w) * hour, vader.h)) for c in range(hour): pos = Position(c * (4 + vader.w), 0) msk.addMask(vader, pos=pos) ret.addMask(msk) elif 5 <= hour <= 8: vader = invader.INVADER.one.Mask(idx) msk = Mask(size=Size((2 + vader.w) * hour, vader.h)) for c in range(hour): pos = Position(c * (2 + vader.w), 0) msk.addMask(vader, pos=pos) ret.addMask(msk) elif 9 <= hour <= 12: vader = invader.INVADER.one.Mask(idx) msk = Mask(size=Size((2 + vader.w) * ceil(hour / 2), 2 * (vader.h))) for c in range(hour): pos = Position(int(c / 2) * (2 + vader.w), 0) if c % 2 == 1: pos.y += vader.h msk.addMask(vader, pos=pos) ret.addMask(msk) return ret hour = datetime.datetime.now(self.timezone).hour if stamp != "": hour = (datetime.datetime.fromisoformat(stamp) + (datetime.datetime.now(self.timezone) - self.start)).hour if cuckoo == True and hour != self.hour: self.step(style, stamp, **params) times = hour % 12 if times == 0: times = 12 self.kuckuck = dotlife.time.Clock.Timer(1500., times) debug("KUCKUCK {:}".format(self.kuckuck)) self.hour = hour self.step(style, stamp, **params) prev = self.mask self.mask = self.next return self.draw(style, stamp, cuckoo, **params) # recurse once! if self.next != self.mask: if style in [Clock.Style.small, Clock.Style.large]: m = Morph2(self.mask, self.next, steps=1, flipcount=1) debug("to\n" + str(self.next)) self.mask = m[1] elif style in [Clock.Style.split]: m = Morph2(self.mask, self.next, steps=1, flipcount=2) debug("to\n" + str(self.next)) self.mask = m[1] else: # debug("to\n"+str(self.next)) self.mask = self.next self.hour = hour return self.mask flags = [ Mode.FLAG("style", DefaultStyle), ("K", "kuckuck", "cuckoo", True, "kuckuck?", None), ("", "stamp=", "stamp", "", "timestamp", None), ]
class Pipe(Mode): DefaultFont = FONT.font3x5 def start(self, font, **params): # self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.font = Font(font) log(str(self.font)) info("start pipe".format()) if font == FONT.font3x5: self.pos = [Position(0, 2), Position(0, 9)] self.buffer = [" ", " "] elif font == FONT.font5x5: self.pos = [Position(0, 2), Position(0, 9)] self.buffer = [" ", " "] elif font == FONT.font5x7: self.pos = [Position(0, 0), Position(0, 9)] self.buffer = [" ", " "] else: self.pos = [Position(0, 0)] self.buffer = [" "] self.rows = len(self.buffer) # self.buf = self.font.render(self.msg) # log(str(self.buf)) self.mask = self.draw(**params) while True: line = sys.stdin.readline() if not line: log("end of file.") break debug("read " + line) if len(self.buffer) > 1: self.buffer[1] = self.buffer[0] self.buffer[0] = line.rstrip()[:30] self.draw(**params) return False def draw(self, **params): pos = Position(0, 0) self.mask = Mask() #self.fluepdot.buffer.read() for i in range(self.rows): try: self.mask.addMask(self.font.render(self.buffer[i]), pos=self.pos[i]) except Error as x: pass # self.mask.mask(self.buf,pos=pos) ret = self.fluepdot.buffer.write(self.mask) info(str(self.mask)) return ret flags = [ Mode.FLAG("font", DefaultFont), ]
class Echo(Mode): DefaultFont = FONT.font5x5 def start(self, font, alignv, scroll, msg="hello, world", **params): dump(params) self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.font = Font(font) self.msg = msg info("start echo: {:s}".format(self.msg)) if scroll and alignv == AlignVertical.center: log("cannot scroll with center vertical alignment") scroll = False self.text = self.font.render(self.msg) log("text is {:}".format(self.text.size())) log(str(self.text)) self.mask = self.draw(scroll, alignv, **params) return False def draw(self, scroll, alignv, alignh, **params): self.mask = Mask() if scroll and alignv in [AlignVertical.top, AlignVertical.bottom]: rest = Size(FRAMESIZE.w, FRAMESIZE.h - (self.font.size.h + 1)) top = Position(0, 0) bot = Position(0, self.font.size.h + 1) prev = self.fluepdot.buffer.read() if alignv == AlignVertical.top: tmp = prev.subMask(pos=top, size=rest) self.mask.addMask(tmp, pos=bot) elif alignv == AlignVertical.bottom: tmp = prev.subMask(pos=bot, size=rest) self.mask.addMask(tmp, pos=top) pos = Position(0, 0) if alignv == AlignVertical.top: pos.y = 0 elif alignv == AlignVertical.center: pos.y = math.floor(abs(FRAMESIZE.h - self.text.h) / 2) elif alignv == AlignVertical.bottom: pos.y = FRAMESIZE.h - self.text.h if alignh == AlignHorizontal.left: pos.x = 0 elif alignh == AlignHorizontal.center: pos.x = math.floor(abs(FRAMESIZE.w - self.text.w) / 2) elif alignh == AlignHorizontal.right: pos.x = FRAMESIZE.w - self.text.w self.mask.addMask(self.text, pos=pos) return self.mask flags = [ ("S", "scroll", "scroll", False, "scroll line?", None), Mode.FLAG("font", DefaultFont), Mode.FLAG("msg"), Mode.FLAG("alignv", AlignVertical.center), Mode.FLAG("alignh", AlignHorizontal.center), ]
class Fill(Mode): Style = Style DefaultStyle = Style.check DefaultFont = FONT.font3x5 def start(self, style, invert, font, offset, **params): log("start fill with {:s}{:s}".format(str(style), " [invert]" if invert else "")) self.font = Font(font) self.offset = offset log("before:\n" + str(self.mask)) msk = self.render(style, invert, **params) self.mask.addMask(msk) log("after:\n" + str(self.mask)) return True def render(self, style, invert, cutoff, **params): ret = Mask() if style == Style.check: for y in range(FRAMESIZE.h): for x in range(FRAMESIZE.w): if x % 2 != y % 2: ret[x, y] = True elif style == Style.gauss: for y in range(FRAMESIZE.h): for x in range(FRAMESIZE.w): if random.gauss(0., 1.) > cutoff: ret[x, y] = True elif style == Style.font: fill = self.font.render_repertoire(offset=self.offset, size=self.mask.size()) self.offset += 1 ret.addMask(fill) elif style == Style.axis: fill = Axis(self.mask.size()) ret.addMask(fill) elif style == Style.border: fill = Border(self.mask.size()) ret.addMask(fill) if invert: ret = ret.inverse() return ret def draw(self, style, invert, **params): self.offset += 1 self.mask = self.render(style, invert, **params) return self.mask flags = [ ("o:", "offset=", "offset", 0, "offset", lambda x: int(x)), ("c:", "cutoff=", "cutoff", 0.5, "cutoff", lambda x: float(x)), Mode.FLAG("style", DefaultStyle), Mode.FLAG("invert"), Mode.FLAG("font", DefaultFont), ]
class Scroll(Mode): DefaultFont = FONT.font3x5 def start(self, font, msg=None, **params): # self.fluepdot.rendering.setMode(Fluepdot.Mode.full) self.fluepdot.rendering.setMode(Fluepdot.Mode.diff) self.font = Font(font) debug(str(self.font)) self.msg = "hello, world." if msg: self.msg = msg info("start scroll: {:s}".format(self.msg)) self.mask = Mask() self.text = self.font.render(self.msg, fixed=True) p0 = int(math.floor(FRAMESIZE.w / (self.font.size.w + 1))) p1 = p0 - len(self.msg) self.pos0 = Position((self.font.size.w + 1) * int(p1 / 2), 0) # self.pos0 = Position(int(FRAMESIZE.w/2)-int(self.text.w/2), 0 ) self.mask.addMask(self.text, pos=self.pos0, wrap=True) self.fluepdot.buffer.write(self.mask) self.l = int(self.text.w / (self.font.size.w + 1)) self.k = 0 return True def draw(self, **params): ret = [] k = self.k L = self.text.w W, H = self.font.size.w + 1, self.font.size.h + 1 next = Mask() pos0 = Position(-W, 0) pos1 = Position(k * W, 0) if k != 0: txt0 = self.text.subMask(size=Size(k * W, H)) next.addMask(txt0, pos=self.pos0 + pos0, wrap=True) if self.l - k != 0: txt1 = self.text.subMask(pos=Position((k) * W, 0), size=Size((self.l - k) * W, H)) next.addMask(txt1, pos=self.pos0 + pos1, wrap=True) # log("from\n"+str(self.mask)) # log("to\n"+str(next)) steps = Morph2(self.mask, next) if len(steps) >= 2: return steps[1] return steps[0] steps = [self.mask, next] for i in range(len(steps)): step = steps[i] ret += [step] self.mask = step self.k += 1 if self.k > self.l: log("step") self.k = 0 self.pos0.x -= W if self.pos0.x <= -L: self.pos0.x += FRAMESIZE.w return ret flags = [ Mode.FLAG("font", DefaultFont), ("P:", "pause=", "pause", 1.0, "pause", lambda x: int(x)), (None, None, "msg", "hello, world.", "message", None), ]