aboutsummaryrefslogtreecommitdiffstats
path: root/scenes/v3_cumple.py
blob: ba9dd79a1563b835fb700d1c1400354fd41d2edc (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
# -*- coding: utf-8 -*-
import sys, os, itertools
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from manim import *
from tiktok import *

N = 23
CX, CY, R = 0.0, 2.95, 2.78


def prob(n):
    p = 1.0
    for k in range(n):
        p *= (365 - k) / 365
    return 1 - p


class Cumple(TikTok):
    NAME = "cumple"

    def construct(self):
        self.prepare()
        chip = self.chip("Paradoja del cumpleaños", CELESTE)

        pts = [np.array([CX + R * np.cos(a), CY + R * np.sin(a), 0])
               for a in np.linspace(PI / 2, PI / 2 + TAU, N, endpoint=False)]
        people = VGroup(*[Dot(p, radius=0.17, color="#8FB8FF") for p in pts])

        with self.beat(0) as b:
            q = self.fit(Text("¿cuánta gente hace falta?", font=FONT, font_size=50,
                              weight=BOLD, color=WHITE), 8.0).move_to(UP * 3.3)
            q2 = self.fit(Text("para que dos cumplan el mismo día", font=FONT,
                               font_size=36, color=GRIS), 8.0).next_to(q, DOWN, buff=0.35)
            b.play(FadeIn(chip, shift=DOWN * 0.3), run_time=0.45)
            b.play(Write(q), run_time=0.9)
            b.play(FadeIn(q2, shift=UP * 0.15), run_time=0.6)

        with self.beat(1) as b:
            guess = Text("¿180?", font=FONT, font_size=62, weight=BOLD, color=GRIS).move_to(UP * 0.4)
            cross = Cross(guess, stroke_color=ROSA, stroke_width=11, scale_factor=0.75)
            ans = Text("23", font=FONT, font_size=170, weight=BOLD, color=AMBAR).move_to(DOWN * 2.2)
            b.play(FadeOut(VGroup(q, q2)), run_time=0.3)
            b.play(FadeIn(guess), run_time=0.4)
            b.play(Create(cross), run_time=0.45)
            b.play(FadeIn(ans, scale=0.55), run_time=0.7)
            b.play(Flash(ans, color=AMBAR, line_length=0.8, num_lines=20, flash_radius=2.0),
                   run_time=0.6)

        with self.beat(2) as b:
            b.play(FadeOut(VGroup(guess, cross)),
                   ans.animate.scale(0.40).move_to(DOWN * 2.8), run_time=0.6)
            lbl = Text("personas   →   50%", font=FONT, font_size=38, weight=BOLD, color=VERDE)
            lbl.next_to(ans, RIGHT, buff=0.35)
            grp = VGroup(ans, lbl)
            grp.move_to(DOWN * 2.8)
            b.play(LaggedStart(*[GrowFromCenter(d) for d in people], lag_ratio=0.06),
                   run_time=1.1)
            b.play(FadeIn(lbl, shift=LEFT * 0.2), run_time=0.5)

        # --- el error: uno contra todos ---
        with self.beat(3) as b:
            hero = people[0]
            spokes = VGroup(*[Line(pts[0], pts[k], stroke_width=3.5, color=AMBAR)
                              for k in range(1, N)])
            cnt = Text("22 comparaciones", font=FONT, font_size=40, weight=BOLD,
                       color=AMBAR).move_to(DOWN * 1.3)
            b.play(hero.animate.set_color(AMBAR).scale(1.6), run_time=0.4)
            b.play(LaggedStart(*[Create(s) for s in spokes], lag_ratio=0.05), run_time=1.3)
            b.play(FadeIn(cnt, shift=UP * 0.15), run_time=0.5)

        # --- todos contra todos ---
        pairs = list(itertools.combinations(range(N), 2))
        with self.beat(4) as b:
            chords = VGroup(*[Line(pts[i], pts[j], stroke_width=1.7,
                                   color="#4CC9F0", stroke_opacity=0.5)
                              for i, j in pairs])
            b.play(FadeOut(spokes), FadeOut(cnt),
                   hero.animate.set_color("#8FB8FF").scale(1 / 1.6), run_time=0.5)
            b.play(LaggedStart(*[Create(c) for c in chords], lag_ratio=0.004),
                   run_time=max(1.4, b.floor - 0.9))

        with self.beat(5) as b:
            big = Text("253", font=FONT, font_size=112, weight=BOLD, color=CELESTE)
            cap = Text("parejas posibles", font=FONT, font_size=38, weight=BOLD, color=WHITE)
            box = VGroup(big, cap).arrange(DOWN, buff=0.18).move_to(DOWN * 1.1)
            b.play(FadeIn(big, scale=0.6), run_time=0.6)
            b.play(FadeIn(cap, shift=UP * 0.15), run_time=0.5)

        with self.beat(6) as b:
            b.play(Circumscribe(box, color=CELESTE, buff=0.35, stroke_width=6), run_time=1.0)
            b.wait(0.3)

        # --- la curva ---
        axes = Axes(x_range=[0, 70, 10], y_range=[0, 100, 25],
                    x_length=7.4, y_length=5.0,
                    axis_config=dict(color="#4A5878", stroke_width=4,
                                     include_tip=False, font_size=26),
                    y_axis_config=dict(include_numbers=True,
                                       numbers_to_include=[0, 50, 100]))
        axes.move_to(UP * 2.15)
        xlab = Text("personas", font=FONT, font_size=30, color=GRIS).next_to(axes, DOWN, buff=0.3)
        curve = axes.plot(lambda n: prob(int(n)) * 100, x_range=[1, 70, 1],
                          color=AMBAR, stroke_width=8)

        with self.beat(7) as b:
            b.play(FadeOut(VGroup(people, chords, box, grp)), run_time=0.5)
            b.play(Create(axes), FadeIn(xlab), run_time=0.8)
            b.play(Create(curve), run_time=max(0.9, b.floor - 1.5))

        marks = VGroup()

        def mark(n, txt, col):
            d = Dot(axes.c2p(n, prob(n) * 100), radius=0.13, color=col)
            t = Text(txt, font=FONT, font_size=34, weight=BOLD, color=col)
            t.next_to(d, DOWN, buff=0.28)
            return VGroup(d, t)

        with self.beat(7 if False else 8) as b:
            m50 = mark(50, "97%", VERDE)
            m50[1].next_to(m50[0], DOWN, buff=0.35).shift(LEFT * 0.35)
            m30 = mark(30, "70%", CELESTE)
            m30[1].next_to(m30[0], RIGHT, buff=0.3).shift(DOWN * 0.35)
            b.play(FadeIn(m30[0], scale=0.5), Write(m30[1]), run_time=0.7)
            b.wait(0.2)
            marks.add(m30)
            b.play(FadeIn(m50[0], scale=0.5), Write(m50[1]), run_time=0.7)
            marks.add(m50)

        with self.beat(9) as b:
            m70 = mark(70, "99,9%", AMBAR)
            m70[1].next_to(m70[0], UP, buff=0.3).shift(LEFT * 0.55)
            b.play(FadeIn(m70[0], scale=0.5), Write(m70[1]), run_time=0.8)
            b.play(Flash(m70[0], color=AMBAR, line_length=0.5, num_lines=16,
                         flash_radius=1.0), run_time=0.7)
            marks.add(m70)

        with self.beat(10) as b:
            cta = self.fit(Text("probalo en tu grupo", font=FONT, font_size=64,
                                weight=BOLD, color=AMBAR), 7.9).move_to(DOWN * 2.1)
            b.play(Write(cta), run_time=0.9)
            b.play(Circumscribe(cta, color=AMBAR, buff=0.3, stroke_width=7), run_time=1.0)

        self.finish()