aboutsummaryrefslogtreecommitdiffstats
path: root/scenes/v11_collatz.py
blob: 20c7ccd6a6cad32a13b483e6213a4c5b9fedc5d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# -*- 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 curve_obj(sq, color=AMBER, sw=5, mx=None, nx=None, log=False):
    """Trajectory as a polyline. mx/nx allow sharing the scale between curves."""
    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", C_PINK)

        with self.beat(0) as b:
            n = self.big("27", 150, AMBER).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, AMBER).move_to(UP * 1.9)), run_time=0.26)
            b.play(FadeIn(cap, shift=UP * 0.15), run_time=0.5)

        def ruler(txt, op, col):
            a = Text(txt, font=FONT, font_size=46, weight=BOLD, color=col)
            fl = Arrow(ORIGIN, RIGHT * 0.85, buff=0, color=C_GRAY, 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 = ruler("es PAR", "÷ 2", C_SKY)
            r2 = ruler("es IMPAR", "× 3 + 1", AMBER)
            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)
            six = self.big("6", 140, C_GREEN).move_to(UP * 1.0)
            b.play(FadeIn(six, scale=0.6), run_time=0.6)

        with self.beat(3) as b:
            b.play(FadeOut(six), run_time=0.25)
            tiles = VGroup(*[tile(v, C_GREEN if v == 1 else (C_SKY if v % 2 == 0 else AMBER))
                             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=C_GREEN, buff=0.12, stroke_width=6),
                   run_time=0.7)
            b.play(FadeOut(grid), run_time=0.35)
            seven = self.big("7", 140, AMBER).move_to(UP * 1.0)
            b.play(FadeIn(seven, scale=0.6), run_time=0.5)

        base = Line([X0 - 0.25, Y0, 0], [X1 + 0.25, Y0, 0], stroke_width=4, color="#33405C")
        one_val = Text("1", font=FONT, font_size=32, weight=BOLD, color=C_GREEN)
        one_val.next_to(base.get_start(), LEFT, buff=0.12)

        s7 = seq(7)
        with self.beat(5) as b:
            b.play(FadeOut(seven), run_time=0.25)
            c7, p7 = curve_obj(s7, AMBER, 6)
            peak_y = Text("52", font=FONT, font_size=34, weight=BOLD, color=AMBER)
            peak_y.next_to([p7[s7.index(max(s7))][0], Y1, 0], UP, buff=0.12)
            b.play(FadeIn(base), FadeIn(one_val), run_time=0.35)
            b.play(Create(c7), run_time=max(1.2, b.floor - 1.1))
            b.play(FadeIn(peak_y), run_time=0.4)

        s27 = seq(27)
        with self.beat(6) as b:
            b.play(FadeOut(VGroup(c7, peak_y)), run_time=0.3)
            c27, p27 = curve_obj(s27, C_PINK, 5)
            k = s27.index(max(s27))
            top = Text("9.232", font=FONT, font_size=40, weight=BOLD, color=C_PINK)
            top.next_to([p27[k][0], Y1, 0], UP, buff=0.12)
            lab = Text("27", font=FONT, font_size=40, weight=BOLD, color=C_PINK)
            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=C_GREEN)
            steps = self.fit(Text("111 pasos y cae al 1", font=FONT, font_size=48,
                                  weight=BOLD, color=C_GREEN), 8.0).move_to(DOWN * 2.6)
            b.play(FadeIn(fin, scale=0.4), run_time=0.4)
            b.play(Flash(fin, color=C_GREEN, line_length=0.35, num_lines=14,
                         flash_radius=0.8), run_time=0.6)
            b.play(FadeIn(steps, shift=UP * 0.15), run_time=0.6)

        with self.beat(8) as b:
            b.play(FadeOut(VGroup(c27, top, lab, fin, steps)), run_time=0.4)
            everyone = [seq(k) for k in range(2, 80)]
            MX = max(max(s) for s in everyone)
            NX = max(len(s) for s in everyone)
            cols = [AMBER, C_SKY, C_PINK, C_GREEN]
            gr = VGroup(*[curve_obj(s, cols[i % 4], 2.4, mx=MX, nx=NX, log=True)[0]
                          for i, s in enumerate(everyone)])
            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))
            tick_m = self.fit(Text("todos terminan en 1", font=FONT, font_size=46,
                                  weight=BOLD, color=C_GREEN), 8.0).move_to(DOWN * 2.6)
            b.play(FadeIn(tick_m, shift=UP * 0.15), run_time=0.6)

        with self.beat(9) as b:
            b.play(FadeOut(VGroup(gr, tick_m, base, one_val, 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=C_PINK), 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)
            count_txt = VGroup(
                self.fit(Text("conjetura de Collatz", font=FONT, font_size=56,
                              weight=BOLD, color=AMBER), 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(count_txt[0]), run_time=0.9)
            b.play(FadeIn(count_txt[1], shift=UP * 0.15), run_time=0.6)

        self.finish()