# -*- coding: utf-8 -*- import sys, os, math sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from manim import * from tiktok import * X0, X1 = -3.75, 3.75 Y0, Y1 = -1.30, 3.30 def seq(n): s = [n] while n != 1: n = n // 2 if n % 2 == 0 else 3 * n + 1 s.append(n) return s def curva(sq, color=AMBAR, sw=5, mx=None, nx=None, log=False): """Trayectoria como poligonal. mx/nx permiten compartir escala entre curvas.""" mx = mx or max(sq) nx = nx or len(sq) if log: f = lambda v: math.log(v) / math.log(mx) else: f = lambda v: v / mx pts = [[X0 + (X1 - X0) * i / (nx - 1), Y0 + (Y1 - Y0) * f(sq[i]), 0] for i in range(len(sq))] m = VMobject(stroke_color=color, stroke_width=sw) m.set_points_as_corners(pts) return m, pts def tile(v, col): t = Text(str(v), font=FONT, font_size=44, weight=BOLD, color="#0B0F1A") box = RoundedRectangle(corner_radius=0.16, width=max(0.95, t.width + 0.45), height=0.88, stroke_width=0, fill_color=col, fill_opacity=1) return VGroup(box, t) class Collatz(TikTok): NAME = "collatz" def construct(self): self.prepare() chip = self.chip("Abierto desde 1937", ROSA) with self.beat(0) as b: n = self.big("27", 150, AMBAR).move_to(UP * 1.9) cap = self.fit(Text("agarrá cualquier número", font=FONT, font_size=50, weight=BOLD, color=WHITE), 8.2).move_to(DOWN * 0.3) b.play(FadeIn(chip, shift=DOWN * 0.3), run_time=0.45) b.play(FadeIn(n, scale=0.6), run_time=0.45) for v in ("6", "19", "41"): b.play(Transform(n, self.big(v, 150, AMBAR).move_to(UP * 1.9)), run_time=0.26) b.play(FadeIn(cap, shift=UP * 0.15), run_time=0.5) def regla(txt, op, col): a = Text(txt, font=FONT, font_size=46, weight=BOLD, color=col) fl = Arrow(ORIGIN, RIGHT * 0.85, buff=0, color=GRIS, stroke_width=6, max_tip_length_to_length_ratio=0.35) c = Text(op, font=FONT, font_size=52, weight=BOLD, color=WHITE) return VGroup(a, fl, c).arrange(RIGHT, buff=0.35) with self.beat(1) as b: b.play(FadeOut(VGroup(n, cap)), run_time=0.3) r1 = regla("es PAR", "÷ 2", CELESTE) r2 = regla("es IMPAR", "× 3 + 1", AMBAR) rr = VGroup(r1, r2).arrange(DOWN, buff=0.7).move_to(UP * 1.6) self.fit(rr, 8.2) b.play(FadeIn(r1, shift=UP * 0.2), run_time=0.7) b.play(FadeIn(r2, shift=UP * 0.2), run_time=0.7) s6 = seq(6) with self.beat(2) as b: b.play(rr.animate.scale(0.72).move_to(UP * 5.2), run_time=0.5) seis = self.big("6", 140, VERDE).move_to(UP * 1.0) b.play(FadeIn(seis, scale=0.6), run_time=0.6) with self.beat(3) as b: b.play(FadeOut(seis), run_time=0.25) tiles = VGroup(*[tile(v, VERDE if v == 1 else (CELESTE if v % 2 == 0 else AMBAR)) for v in s6]) fila1 = VGroup(*tiles[:5]).arrange(RIGHT, buff=0.28) fila2 = VGroup(*tiles[5:]).arrange(RIGHT, buff=0.28) grid = VGroup(fila1, fila2).arrange(DOWN, buff=0.45).move_to(UP * 1.4) self.fit(grid, 8.2) b.play(LaggedStart(*[FadeIn(t, scale=0.6) for t in tiles], lag_ratio=0.5), run_time=max(1.4, b.floor - 0.4)) with self.beat(4) as b: b.play(Circumscribe(tiles[-1], color=VERDE, buff=0.12, stroke_width=6), run_time=0.7) b.play(FadeOut(grid), run_time=0.35) siete = self.big("7", 140, AMBAR).move_to(UP * 1.0) b.play(FadeIn(siete, scale=0.6), run_time=0.5) base = Line([X0 - 0.25, Y0, 0], [X1 + 0.25, Y0, 0], stroke_width=4, color="#33405C") uno = Text("1", font=FONT, font_size=32, weight=BOLD, color=VERDE) uno.next_to(base.get_start(), LEFT, buff=0.12) s7 = seq(7) with self.beat(5) as b: b.play(FadeOut(siete), run_time=0.25) c7, p7 = curva(s7, AMBAR, 6) pico = Text("52", font=FONT, font_size=34, weight=BOLD, color=AMBAR) pico.next_to([p7[s7.index(max(s7))][0], Y1, 0], UP, buff=0.12) b.play(FadeIn(base), FadeIn(uno), run_time=0.35) b.play(Create(c7), run_time=max(1.2, b.floor - 1.1)) b.play(FadeIn(pico), run_time=0.4) s27 = seq(27) with self.beat(6) as b: b.play(FadeOut(VGroup(c7, pico)), run_time=0.3) c27, p27 = curva(s27, ROSA, 5) k = s27.index(max(s27)) top = Text("9.232", font=FONT, font_size=40, weight=BOLD, color=ROSA) top.next_to([p27[k][0], Y1, 0], UP, buff=0.12) lab = Text("27", font=FONT, font_size=40, weight=BOLD, color=ROSA) lab.move_to([X0 - 0.05, Y1 + 0.45, 0]) b.play(FadeIn(lab), run_time=0.3) b.play(Create(c27), run_time=max(1.3, b.floor - 1.0)) b.play(FadeIn(top), run_time=0.4) with self.beat(7) as b: fin = Dot([p27[-1][0], Y0, 0], radius=0.14, color=VERDE) pasos = self.fit(Text("111 pasos y cae al 1", font=FONT, font_size=48, weight=BOLD, color=VERDE), 8.0).move_to(DOWN * 2.6) b.play(FadeIn(fin, scale=0.4), run_time=0.4) b.play(Flash(fin, color=VERDE, line_length=0.35, num_lines=14, flash_radius=0.8), run_time=0.6) b.play(FadeIn(pasos, shift=UP * 0.15), run_time=0.6) with self.beat(8) as b: b.play(FadeOut(VGroup(c27, top, lab, fin, pasos)), run_time=0.4) todos = [seq(k) for k in range(2, 80)] MX = max(max(s) for s in todos) NX = max(len(s) for s in todos) cols = [AMBAR, CELESTE, ROSA, VERDE] gr = VGroup(*[curva(s, cols[i % 4], 2.4, mx=MX, nx=NX, log=True)[0] for i, s in enumerate(todos)]) gr.set_stroke(opacity=0.65) b.play(LaggedStart(*[Create(c) for c in gr], lag_ratio=0.02), run_time=max(1.6, b.floor - 0.9)) marca = self.fit(Text("todos terminan en 1", font=FONT, font_size=46, weight=BOLD, color=VERDE), 8.0).move_to(DOWN * 2.6) b.play(FadeIn(marca, shift=UP * 0.15), run_time=0.6) with self.beat(9) as b: b.play(FadeOut(VGroup(gr, marca, base, uno, rr)), run_time=0.45) t = VGroup( self.fit(Text("nadie pudo demostrar", font=FONT, font_size=50, weight=BOLD, color=WHITE), 8.2), self.fit(Text("que pasa SIEMPRE", font=FONT, font_size=54, weight=BOLD, color=ROSA), 8.2), ).arrange(DOWN, buff=0.35).move_to(UP * 1.2) b.play(FadeIn(t[0], shift=UP * 0.15), run_time=0.6) b.play(FadeIn(t[1], scale=0.8), run_time=0.7) with self.beat(10) as b: b.play(FadeOut(t), run_time=0.35) cta = VGroup( self.fit(Text("conjetura de Collatz", font=FONT, font_size=56, weight=BOLD, color=AMBAR), 8.0), self.fit(Text("dejá tu número abajo", font=FONT, font_size=46, weight=BOLD, color=WHITE), 8.0), ).arrange(DOWN, buff=0.38).move_to(UP * 0.8) b.play(Write(cta[0]), run_time=0.9) b.play(FadeIn(cta[1], shift=UP * 0.15), run_time=0.6) self.finish()