# -*- 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 Birthday(TikTok): NAME = "cumple" def construct(self): self.prepare() chip = self.chip("Paradoja del cumpleaños", C_SKY) 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=C_GRAY), 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=C_GRAY).move_to(UP * 0.4) cross = Cross(guess, stroke_color=C_PINK, stroke_width=11, scale_factor=0.75) ans = Text("23", font=FONT, font_size=170, weight=BOLD, color=AMBER).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=AMBER, 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=C_GREEN) 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) # --- the mistake: one against everyone --- with self.beat(3) as b: hero = people[0] spokes = VGroup(*[Line(pts[0], pts[k], stroke_width=3.5, color=AMBER) for k in range(1, N)]) cnt = Text("22 comparaciones", font=FONT, font_size=40, weight=BOLD, color=AMBER).move_to(DOWN * 1.3) b.play(hero.animate.set_color(AMBER).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) # --- everyone against everyone --- 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=C_SKY) 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=C_SKY, buff=0.35, stroke_width=6), run_time=1.0) b.wait(0.3) # --- the curve --- 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=C_GRAY).next_to(axes, DOWN, buff=0.3) curve = axes.plot(lambda n: prob(int(n)) * 100, x_range=[1, 70, 1], color=AMBER, 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%", C_GREEN) m50[1].next_to(m50[0], DOWN, buff=0.35).shift(LEFT * 0.35) m30 = mark(30, "70%", C_SKY) 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%", AMBER) 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=AMBER, line_length=0.5, num_lines=16, flash_radius=1.0), run_time=0.7) marks.add(m70) with self.beat(10) as b: count_txt = self.fit(Text("probalo en tu grupo", font=FONT, font_size=64, weight=BOLD, color=AMBER), 7.9).move_to(DOWN * 2.1) b.play(Write(count_txt), run_time=0.9) b.play(Circumscribe(count_txt, color=AMBER, buff=0.3, stroke_width=7), run_time=1.0) self.finish()