from manimlib.imports import * class ShowExampleTest(ExternallyAnimatedScene): pass class IntroducePutnam(Scene): CONFIG = { "dont_animate" : False, } def construct(self): title = TextMobject("Putnam Competition") title.to_edge(UP, buff = MED_SMALL_BUFF) title.set_color(BLUE) six_hours = TextMobject("6", "hours") three_hours = TextMobject("3", "hours") for mob in six_hours, three_hours: mob.next_to(title, DOWN, MED_LARGE_BUFF) # mob.set_color(BLUE) three_hours.shift(FRAME_X_RADIUS*LEFT/2) three_hours_copy = three_hours.copy() three_hours_copy.shift(FRAME_X_RADIUS*RIGHT) question_groups = VGroup(*[ VGroup(*[ TextMobject("%s%d)"%(c, i)) for i in range(1, 7) ]).arrange(DOWN, buff = MED_LARGE_BUFF) for c in ("A", "B") ]).arrange(RIGHT, buff = FRAME_X_RADIUS - MED_SMALL_BUFF) question_groups.to_edge(LEFT) question_groups.to_edge(DOWN, MED_LARGE_BUFF) flat_questions = VGroup(*it.chain(*question_groups)) rects = VGroup() for questions in question_groups: rect = SurroundingRectangle(questions, buff = MED_SMALL_BUFF) rect.set_stroke(WHITE, 2) rect.stretch_to_fit_width(FRAME_X_RADIUS - 1) rect.move_to(questions.get_left() + MED_SMALL_BUFF*LEFT, LEFT) rects.add(rect) out_of_tens = VGroup() for question in flat_questions: out_of_ten = TexMobject("/10") out_of_ten.set_color(GREEN) out_of_ten.move_to(question) dist = rects[0].get_width() - 1.2 out_of_ten.shift(dist*RIGHT) out_of_tens.add(out_of_ten) out_of_120 = TexMobject("/120") out_of_120.next_to(title, RIGHT, LARGE_BUFF) out_of_120.set_color(GREEN) out_of_120.generate_target() out_of_120.target.to_edge(RIGHT, LARGE_BUFF) median = TexMobject("2") median.next_to(out_of_120.target, LEFT, SMALL_BUFF) median.set_color(RED) median.align_to(out_of_120[-1]) median_words = TextMobject("Typical median $\\rightarrow$") median_words.next_to(median, LEFT) difficulty_strings = [ "Pretty hard", "Hard", "Harder", "Very hard", "Ughhh", "Can I go home?" ] colors = color_gradient([YELLOW, RED], len(difficulty_strings)) difficulties = VGroup() for i, s, color in zip(it.count(), difficulty_strings, colors): for question_group in question_groups: question = question_group[i] text = TextMobject("\\dots %s \\dots"%s) text.scale(0.7) text.next_to(question, RIGHT) text.set_color(color) difficulties.add(text) if self.dont_animate: test = VGroup() test.rect = rects[0] test.questions = question_groups[0] test.out_of_tens = VGroup(*out_of_tens[:6]) test.difficulties = VGroup(*difficulties[::2]) test.digest_mobject_attrs() self.test = test return self.add(title) self.play(Write(six_hours)) self.play(LaggedStartMap( GrowFromCenter, flat_questions, run_time = 3, )) self.play( ReplacementTransform(six_hours, three_hours), ReplacementTransform(six_hours.copy(), three_hours_copy), *list(map(ShowCreation, rects)) ) self.wait() self.play(LaggedStartMap( DrawBorderThenFill, out_of_tens, run_time = 3, stroke_color = YELLOW )) self.wait() self.play(ReplacementTransform( out_of_tens.copy(), VGroup(out_of_120), lag_ratio = 0.5, run_time = 2, )) self.wait() self.play( title.next_to, median_words.copy(), LEFT, LARGE_BUFF, MoveToTarget(out_of_120), Write(median_words) ) self.play(Write(median)) for difficulty in difficulties: self.play(FadeIn(difficulty)) self.wait() class NatureOf5sAnd6s(TeacherStudentsScene): CONFIG = { "test_scale_val" : 0.65 } def construct(self): test = self.get_test() self.students.fade(1) self.play( test.scale, self.test_scale_val, test.to_corner, UP+LEFT, FadeIn(self.teacher), self.get_student_changes( *["horrified"]*3, look_at_arg = test ) ) self.wait() mover = VGroup( test.questions[-1].copy(), test.difficulties[-1].copy(), ) mover.generate_target() mover.target.scale(1./self.test_scale_val) mover.target.next_to( self.teacher.get_corner(UP+LEFT), UP, ) new_words = TextMobject("\\dots Potentially very elegant \\dots") new_words.set_color(GREEN) new_words.set_height(mover.target[1].get_height()) new_words.next_to(mover.target[0], RIGHT, SMALL_BUFF) self.play( MoveToTarget(mover), self.teacher.change, "raise_right_hand", ) self.change_student_modes(*["pondering"]*3) self.play(Transform(mover[1], new_words)) self.look_at((FRAME_X_RADIUS*RIGHT + FRAME_Y_RADIUS*UP)/2) self.wait(4) ### def get_test(self): prev_scene = IntroducePutnam(dont_animate = True) return prev_scene.test class OtherVideoClips(Scene): def construct(self): rect = ScreenRectangle() rect.set_height(6.5) rect.center() rect.to_edge(DOWN) titles = list(map(TextMobject, [ "Essence of calculus, chapter 1", "Pi hiding in prime regularities", "How do cryptocurrencies work?" ])) self.add(rect) last_title = None for title in titles: title.to_edge(UP, buff = MED_SMALL_BUFF) if last_title: self.play(ReplacementTransform(last_title, title)) else: self.play(FadeIn(title)) self.wait(3) last_title = title class IntroduceTetrahedron(ExternallyAnimatedScene): pass class IntroduceTetrahedronSupplement(Scene): def construct(self): title = TextMobject("4", "random$^*$ points on sphere") title.set_color(YELLOW) question = TextMobject("Probability that this tetrahedron \\\\ contains the sphere's center?") question.next_to(title, DOWN, MED_LARGE_BUFF) group = VGroup(title, question) group.set_width(FRAME_WIDTH-1) group.to_edge(DOWN) for n in range(1, 4): num = TextMobject(str(n)) num.replace(title[0], dim_to_match = 1) num.set_color(YELLOW) self.add(num) self.wait(0.7) self.remove(num) self.add(title[0]) self.play(FadeIn(title[1], lag_ratio = 0.5)) self.wait(2) self.play(Write(question)) self.wait(2) class IntroduceTetrahedronFootnote(Scene): def construct(self): words = TextMobject(""" $^*$Chosen independently with a \\\\ uniform distribution on the sphere. """) words.to_corner(UP+LEFT) self.add(words) self.wait(2) class HowDoYouStart(TeacherStudentsScene): def construct(self): self.student_says( "How do you even start?", target_mode = "raise_left_hand" ) self.change_student_modes("confused", "raise_left_hand", "erm") self.wait() self.teacher_says("Try a simpler case.") self.change_student_modes(*["thinking"]*3) self.wait(2) class TwoDCase(Scene): CONFIG = { "center" : ORIGIN, "random_seed" : 4, "radius" : 2.5, "center_color" : BLUE, "point_color" : YELLOW, "positive_triangle_color" : BLUE, "negative_triangle_color" : RED, "triangle_fill_opacity" : 0.25, "n_initial_random_choices" : 9, "n_p3_random_moves" : 4, } def construct(self): self.add_title() self.add_circle() self.choose_three_random_points() self.simplify_further() self.fix_two_points_in_place() self.note_special_region() self.draw_lines_through_center() self.ask_about_probability_p3_lands_in_this_arc() self.various_arc_sizes_for_p1_p2_placements() self.ask_about_average_arc_size() self.fix_p1_in_place() self.overall_probability() def add_title(self): title = TextMobject("2D Case") title.to_corner(UP+LEFT) self.add(title) self.set_variables_as_attrs(title) def add_circle(self): circle = Circle(radius = self.radius, color = WHITE) center_dot = Dot(color = self.center_color).center() radius = DashedLine(ORIGIN, circle.radius*RIGHT) VGroup(circle, center_dot, radius).shift(self.center) self.add(center_dot) self.play(ShowCreation(radius)) self.play( ShowCreation(circle), Rotating(radius, angle = 2*np.pi, about_point = self.center), rate_func = smooth, run_time = 2, ) self.play(ShowCreation( radius, rate_func = lambda t : smooth(1-t), remover = True )) self.wait() self.set_variables_as_attrs(circle, center_dot) def choose_three_random_points(self): point_mobs = self.get_point_mobs() point_labels = self.get_point_mob_labels() triangle = self.get_triangle() self.point_labels_update = self.get_labels_update(point_mobs, point_labels) self.triangle_update = self.get_triangle_update(point_mobs, triangle) self.update_animations = [ self.triangle_update, self.point_labels_update, ] for anim in self.update_animations: anim.update(0) question = TextMobject( "Probability that \\\\ this triangle \\\\", "contains the center", "?", arg_separator = "", ) question.set_color_by_tex("center", self.center_color) question.scale(0.8) question.to_corner(UP+RIGHT) self.question = question self.play(LaggedStartMap(DrawBorderThenFill, point_mobs)) self.play(FadeIn(triangle)) self.wait() self.play(LaggedStartMap(Write, point_labels)) self.wait() self.play(Write(question)) for x in range(self.n_initial_random_choices): self.change_point_mobs_randomly() self.wait() angles = self.get_point_mob_angles() target_angles = [5*np.pi/8, 7*np.pi/8, 0] self.change_point_mobs([ta - a for a, ta in zip(angles, target_angles)]) self.wait() def simplify_further(self): morty = Mortimer().flip() morty.scale(0.75) morty.to_edge(DOWN) morty.shift(3.5*LEFT) bubble = SpeechBubble( direction = RIGHT, height = 3, width = 3 ) bubble.pin_to(morty) bubble.to_edge(LEFT, SMALL_BUFF) bubble.write("Simplify \\\\ more!") self.play(FadeIn(morty)) self.play( morty.change, "hooray", ShowCreation(bubble), Write(bubble.content) ) self.play(Blink(morty)) self.wait() self.play( morty.change, "happy", morty.fade, 1, *list(map(FadeOut, [bubble, bubble.content])) ) self.remove(morty) def fix_two_points_in_place(self): push_pins = VGroup() for point_mob in self.point_mobs[:-1]: push_pin = SVGMobject(file_name = "push_pin") push_pin.set_height(0.5) push_pin.move_to(point_mob.get_center(), DOWN) line = Line(ORIGIN, UP) line.set_stroke(WHITE, 2) line.set_height(0.1) line.move_to(push_pin, UP) line.shift(0.3*SMALL_BUFF*(2*DOWN+LEFT)) push_pin.add(line) push_pin.set_fill(LIGHT_GREY) push_pin.save_state() push_pin.shift(UP) push_pin.fade(1) push_pins.add(push_pin) self.play(LaggedStartMap( ApplyMethod, push_pins, lambda mob : (mob.restore,) )) self.add_foreground_mobjects(push_pins) d_thetas = 2*np.pi*np.random.random(self.n_p3_random_moves) for d_theta in d_thetas: self.change_point_mobs([0, 0, d_theta]) self.wait() self.set_variables_as_attrs(push_pins) def note_special_region(self): point_mobs = self.point_mobs angles = self.get_point_mob_angles() all_arcs = self.get_all_arcs() arc = all_arcs[-1] arc_lines = VGroup() for angle in angles[:2]: line = Line(LEFT, RIGHT).scale(SMALL_BUFF) line.shift(self.radius*RIGHT) line.rotate(angle + np.pi) line.shift(self.center) line.set_stroke(arc.get_color()) arc_lines.add(line) self.play(ShowCreation(arc_lines)) self.change_point_mobs([0, 0, angles[0]+np.pi-angles[2]]) self.change_point_mobs( [0, 0, arc.angle], ShowCreation(arc, run_time = 2) ) self.change_point_mobs([0, 0, np.pi/4 - angles[1]]) self.change_point_mobs([0, 0, 0.99*np.pi], run_time = 4) self.wait() self.set_variables_as_attrs(all_arcs, arc, arc_lines) def draw_lines_through_center(self): point_mobs = self.point_mobs angles = self.get_point_mob_angles() all_arcs = self.all_arcs lines = self.get_center_lines() self.add_foreground_mobjects(self.center_dot) for line in lines: self.play(ShowCreation(line)) self.play(FadeIn(all_arcs), Animation(point_mobs)) self.remove(self.circle) self.wait() self.play( all_arcs.space_out_submobjects, 1.5, Animation(point_mobs), rate_func = there_and_back, run_time = 1.5, ) self.wait() self.change_point_mobs( [0, 0, np.mean(angles[:2])+np.pi-angles[2]] ) self.wait() for x in range(3): self.change_point_mobs([0, 0, np.pi/2]) self.wait() def ask_about_probability_p3_lands_in_this_arc(self): arc = self.arc arrow = Vector(LEFT, color = BLUE) arrow.next_to(arc.get_center(), RIGHT, MED_LARGE_BUFF) question = TextMobject("Probability of landing \\\\ in this arc?") question.scale(0.8) question.next_to(arrow, RIGHT) question.shift_onto_screen() question.shift(SMALL_BUFF*UP) answer = TexMobject( "{\\text{Length of arc}", "\\over", "\\text{Circumference}}" ) answer.set_color_by_tex("arc", BLUE) answer.scale(0.8) answer.next_to(arrow, RIGHT) equals = TexMobject("=") equals.rotate(np.pi/2) equals.next_to(answer, UP, buff = 0.35) self.play(FadeIn(question), GrowArrow(arrow)) self.have_p3_jump_around_randomly(15) self.play( question.next_to, answer, UP, LARGE_BUFF, Write(equals), FadeIn(answer) ) self.have_p3_jump_around_randomly(4) angles = self.get_point_mob_angles() self.change_point_mobs( [0, 0, 1.35*np.pi - angles[2]], run_time = 0, ) self.wait() question.add(equals) self.arc_prob_question = question self.arc_prob = answer self.arc_size_arrow = arrow def various_arc_sizes_for_p1_p2_placements(self): arc = self.arc self.triangle.save_state() self.play(*list(map(FadeOut, [ self.push_pins, self.triangle, self.arc_lines ]))) self.update_animations.remove(self.triangle_update) self.update_animations += [ self.get_center_lines_update(self.point_mobs, self.center_lines), self.get_arcs_update(self.all_arcs) ] #90 degree angle self.change_point_mobs_to_angles([np.pi/2, np.pi], run_time = 1) elbow = VGroup( Line(DOWN, DOWN+RIGHT), Line(DOWN+RIGHT, RIGHT), ) elbow.scale(0.25) elbow.shift(self.center) ninety_degrees = TexMobject("90^\\circ") ninety_degrees.next_to(elbow, DOWN+RIGHT, buff = 0) proportion = DecimalNumber(0.25) proportion.set_color(self.center_color) # proportion.next_to(arc.point_from_proportion(0.5), DOWN, MED_LARGE_BUFF) proportion.next_to(self.arc_size_arrow, DOWN) def proportion_update_func(alpha): angles = self.get_point_mob_angles() diff = abs(angles[1]-angles[0])/(2*np.pi) return min(diff, 1-diff) proportion_update = ChangingDecimal(proportion, proportion_update_func) self.play(ShowCreation(elbow), FadeIn(ninety_degrees)) self.wait() self.play( ApplyMethod( arc.rotate_in_place, np.pi/12, rate_func = wiggle, ) ) self.play(LaggedStartMap(FadeIn, proportion, run_time = 1)) self.wait() #Non right angles angle_pairs = [ (0.26*np.pi, 1.24*np.pi), (0.73*np.pi, 0.78*np.pi), (0.5*np.pi, np.pi), ] self.update_animations.append(proportion_update) for angle_pair in angle_pairs: self.change_point_mobs_to_angles( angle_pair, VGroup(elbow, ninety_degrees).fade, 1, ) self.remove(elbow, ninety_degrees) self.wait() self.set_variables_as_attrs(proportion, proportion_update) def ask_about_average_arc_size(self): proportion = self.proportion brace = Brace(proportion, DOWN, buff = SMALL_BUFF) average = brace.get_text("Average?", buff = SMALL_BUFF) self.play( GrowFromCenter(brace), Write(average) ) for x in range(6): self.change_point_mobs_to_angles( 2*np.pi*np.random.random(2) ) self.change_point_mobs_to_angles( [1.2*np.pi, 0.3*np.pi] ) self.wait() self.set_variables_as_attrs(brace, average) def fix_p1_in_place(self): push_pin = self.push_pins[0] P1, P2, P3 = point_mobs = self.point_mobs self.change_point_mobs_to_angles([0.9*np.pi]) push_pin.move_to(P1.get_center(), DOWN) push_pin.save_state() push_pin.shift(UP) push_pin.fade(1) self.play(push_pin.restore) for angle in [0.89999*np.pi, -0.09999*np.pi, 0.4*np.pi]: self.change_point_mobs_to_angles( [0.9*np.pi, angle], run_time = 4, ) self.play(FadeOut(self.average[-1])) def overall_probability(self): point_mobs = self.point_mobs triangle = self.triangle one_fourth = TexMobject("1/4") one_fourth.set_color(BLUE) one_fourth.next_to(self.question, DOWN) self.triangle_update.update(1) self.play( FadeIn(triangle), Animation(point_mobs) ) self.update_animations.append(self.triangle_update) self.have_p3_jump_around_randomly(8, wait_time = 0.25) self.play(ReplacementTransform( self.proportion.copy(), VGroup(one_fourth) )) self.have_p3_jump_around_randomly(32, wait_time = 0.25) ##### def get_point_mobs(self): points = np.array([ self.center + rotate_vector(self.radius*RIGHT, theta) for theta in 2*np.pi*np.random.random(3) ]) for index in 0, 1, 0: if self.points_contain_center(points): break points[index] -= self.center points[index] *= -1 points[index] += self.center point_mobs = self.point_mobs = VGroup(*[ Dot().move_to(point) for point in points ]) point_mobs.set_color(self.point_color) return point_mobs def get_point_mob_labels(self): point_labels = VGroup(*[ TexMobject("P_%d"%(i+1)) for i in range(len(self.point_mobs)) ]) point_labels.set_color(self.point_mobs.get_color()) self.point_labels = point_labels return point_labels def get_triangle(self): triangle = self.triangle = RegularPolygon(n = 3) triangle.set_fill(WHITE, opacity = self.triangle_fill_opacity) return triangle def get_center_lines(self): angles = self.get_point_mob_angles() lines = VGroup() for angle in angles[:2]: line = DashedLine( self.radius*RIGHT, self.radius*LEFT ) line.rotate(angle) line.shift(self.center) line.set_color(self.point_color) lines.add(line) self.center_lines = lines return lines def get_labels_update(self, point_mobs, labels): def update_labels(labels): for point_mob, label in zip(point_mobs, labels): label.move_to(point_mob) vect = point_mob.get_center() - self.center vect /= get_norm(vect) label.shift(MED_LARGE_BUFF*vect) return labels return UpdateFromFunc(labels, update_labels) def get_triangle_update(self, point_mobs, triangle): def update_triangle(triangle): points = [pm.get_center() for pm in point_mobs] triangle.set_points_as_corners(points) if self.points_contain_center(points): triangle.set_color(self.positive_triangle_color) else: triangle.set_color(self.negative_triangle_color) return triangle return UpdateFromFunc(triangle, update_triangle) def get_center_lines_update(self, point_mobs, center_lines): def update_lines(center_lines): for point_mob, line in zip(point_mobs, center_lines): point = point_mob.get_center() - self.center line.rotate_in_place( angle_of_vector(point) - line.get_angle() ) line.move_to(self.center) return center_lines return UpdateFromFunc(center_lines, update_lines) def get_arcs_update(self, all_arcs): def update_arcs(arcs): new_arcs = self.get_all_arcs() Transform(arcs, new_arcs).update(1) return arcs return UpdateFromFunc(all_arcs, update_arcs) def get_all_arcs(self): angles = self.get_point_mob_angles() all_arcs = VGroup() for da0, da1 in it.product(*[[0, np.pi]]*2): arc_angle = (angles[1]+da1) - (angles[0]+da0) arc_angle = (arc_angle+np.pi)%(2*np.pi)-np.pi arc = Arc( start_angle = angles[0]+da0, angle = arc_angle, radius = self.radius, stroke_width = 5, ) arc.shift(self.center) all_arcs.add(arc) all_arcs.set_color_by_gradient(RED, MAROON_B, PINK, BLUE) self.all_arcs = all_arcs return all_arcs def points_contain_center(self, points): p0, p1, p2 = points v1 = p1 - p0 v2 = p2 - p0 c = self.center - p0 M = np.matrix([v1[:2], v2[:2]]).T M_inv = np.linalg.inv(M) coords = np.dot(M_inv, c[:2]) return np.all(coords > 0) and (np.sum(coords.flatten()) <= 1) def get_point_mob_theta_change_anim(self, point_mob, d_theta): curr_theta = angle_of_vector(point_mob.get_center() - self.center) d_theta = (d_theta + np.pi)%(2*np.pi) - np.pi new_theta = curr_theta + d_theta def update_point(point_mob, alpha): theta = interpolate(curr_theta, new_theta, alpha) point_mob.move_to(self.center + self.radius*( np.cos(theta)*RIGHT + np.sin(theta)*UP )) return point_mob return UpdateFromAlphaFunc(point_mob, update_point, run_time = 2) def change_point_mobs(self, d_thetas, *added_anims, **kwargs): anims = it.chain( self.update_animations, [ self.get_point_mob_theta_change_anim(pm, dt) for pm, dt in zip(self.point_mobs, d_thetas) ], added_anims ) self.play(*anims, **kwargs) for update in self.update_animations: update.update(1) def change_point_mobs_randomly(self, *added_anims, **kwargs): d_thetas = 2*np.pi*np.random.random(len(self.point_mobs)) self.change_point_mobs(d_thetas, *added_anims, **kwargs) def change_point_mobs_to_angles(self, target_angles, *added_anims, **kwargs): angles = self.get_point_mob_angles() n_added_targets = len(angles) - len(target_angles) target_angles = list(target_angles) + list(angles[-n_added_targets:]) self.change_point_mobs( [ta-a for a, ta in zip(angles, target_angles)], *added_anims, **kwargs ) def get_point_mob_angles(self): point_mobs = self.point_mobs points = [pm.get_center() - self.center for pm in point_mobs] return np.array(list(map(angle_of_vector, points))) def have_p3_jump_around_randomly(self, n_jumps, wait_time = 0.75, run_time = 0): for x in range(n_jumps): self.change_point_mobs( [0, 0, 2*np.pi*random.random()], run_time = run_time ) self.wait(wait_time) class FixThreePointsOnSphere(ExternallyAnimatedScene): pass class AddCenterLinesAndPlanesToSphere(ExternallyAnimatedScene): pass class AverageSizeOfSphericalTriangleSection(ExternallyAnimatedScene): pass class AverageSizeOfSphericalTriangleSectionSupplement(Scene): def construct(self): words = TextMobject( "Average size of \\\\", "this section", "?", arg_separator = "" ) words.set_color_by_tex("section", GREEN) words.set_width(FRAME_WIDTH - 1) words.to_edge(DOWN) self.play(Write(words)) self.wait(3) class TryASurfaceIntegral(TeacherStudentsScene): def construct(self): self.student_says("Can you do \\\\ a surface integral?") self.change_student_modes("confused", "raise_left_hand", "confused") self.wait() self.teacher_says( "I mean...you can \\emph{try}", target_mode = "sassy", ) self.wait(2) class RevisitTwoDCase(TwoDCase): CONFIG = { "random_seed" : 4, "center" : 3*LEFT + 0.5*DOWN, "radius" : 2, "n_random_trials" : 200, } def construct(self): self.force_skipping() self.setup_circle() self.show_probability() self.add_lines_and_comment_on_them() self.rewrite_random_procedure() self.four_possibilities_for_coin_flips() def setup_circle(self): point_mobs = self.get_point_mobs() point_labels = self.get_point_mob_labels() triangle = self.get_triangle() circle = Circle(radius = self.radius, color = WHITE) center_dot = Dot(color = self.center_color) VGroup(circle, center_dot).shift(self.center) self.point_labels_update = self.get_labels_update(point_mobs, point_labels) self.triangle_update = self.get_triangle_update(point_mobs, triangle) self.update_animations = [ self.triangle_update, self.point_labels_update, ] for anim in self.update_animations: anim.update(1) self.add( center_dot, circle, triangle, point_mobs, point_labels ) self.add_foreground_mobjects(center_dot) self.set_variables_as_attrs(circle, center_dot) def show_probability(self): title = TexMobject( "P(\\text{triangle contains the center})", "=", "1/4" ) title.to_edge(UP, buff = MED_SMALL_BUFF) title.set_color_by_tex("1/4", BLUE) four = title[-1][-1] four_circle = Circle(color = YELLOW) four_circle.replace(four, dim_to_match = 1) four_circle.scale_in_place(1.2) self.n_in = 0 self.n_out = 0 frac = TexMobject( "{0", "\\over", "\\quad 0", "+", "0 \\quad}", "=" ) placeholders = frac.get_parts_by_tex("0") positions = [ORIGIN, RIGHT, LEFT] frac.next_to(self.circle, RIGHT, 1.5*LARGE_BUFF) def place_random_triangles(n, wait_time): for x in range(n): self.change_point_mobs_randomly(run_time = 0) contain_center = self.points_contain_center( [pm.get_center() for pm in self.point_mobs] ) if contain_center: self.n_in += 1 else: self.n_out += 1 nums = list(map(Integer, [self.n_in, self.n_in, self.n_out])) VGroup(*nums[:2]).set_color(self.positive_triangle_color) VGroup(*nums[2:]).set_color(self.negative_triangle_color) for num, placeholder, position in zip(nums, placeholders, positions): num.move_to(placeholder, position) decimal = DecimalNumber(float(self.n_in)/(self.n_in + self.n_out)) decimal.next_to(frac, RIGHT, SMALL_BUFF) self.add(decimal, *nums) self.wait(wait_time) self.remove(decimal, *nums) return VGroup(decimal, *nums) self.play(Write(title)) self.add(frac) self.remove(*placeholders) place_random_triangles(10, 0.25) nums = place_random_triangles(self.n_random_trials, 0.05) self.add(nums) self.wait() self.play(*list(map(FadeOut, [frac, nums, title]))) def add_lines_and_comment_on_them(self): center_lines = self.get_center_lines() center_lines.save_state() center_line_shadows = center_lines.copy() center_line_shadows.set_stroke(LIGHT_GREY, 2) arcs = self.get_all_arcs() center_lines.generate_target() center_lines.target.to_edge(RIGHT, buff = LARGE_BUFF) rect = SurroundingRectangle(center_lines.target, buff = MED_SMALL_BUFF) rect.set_stroke(WHITE, 2) words1 = TextMobject("Helpful new objects") words2 = TextMobject("Reframe problem around these") for words in words1, words2: words.scale(0.8) words.next_to(rect, UP) words.shift_onto_screen() self.play(LaggedStartMap(ShowCreation, center_lines, run_time = 1)) self.play( LaggedStartMap(FadeIn, arcs, run_time = 1), Animation(self.point_mobs), ) self.wait() self.add(center_line_shadows) self.play(MoveToTarget(center_lines)) self.play(ShowCreation(rect), Write(words1)) self.wait(2) self.play(ReplacementTransform(words1, words2)) self.wait(2) self.play( center_lines.restore, center_lines.fade, 1, *list(map(FadeOut, [ rect, words2, center_line_shadows, self.triangle, arcs, self.point_mobs, self.point_labels, ])) ) center_lines.restore() self.remove(center_lines) def rewrite_random_procedure(self): point_mobs = self.point_mobs center_lines = self.center_lines random_procedure = TextMobject("Random procedure") underline = Line(LEFT, RIGHT) underline.stretch_to_fit_width(random_procedure.get_width()) underline.scale(1.1) underline.next_to(random_procedure, DOWN) group = VGroup(random_procedure, underline) group.to_corner(UP+RIGHT) words = VGroup(*list(map(TextMobject, [ "Choose 3 random points", "Choose 2 random lines", "Flip coin for each line \\\\ to get $P_1$ and $P_2$", "Choose $P_3$ at random" ]))) words.scale(0.8) words.arrange(DOWN, buff = MED_LARGE_BUFF) words.next_to(underline, DOWN) words[1].set_color(YELLOW) point_label_groups = VGroup() for point_mob, label in zip(self.point_mobs, self.point_labels): group = VGroup(point_mob, label) group.save_state() group.move_to(words[0], LEFT) group.fade(1) point_label_groups.add(group) self.point_label_groups = point_label_groups cross = Cross(words[0]) cross.set_stroke(RED, 6) self.center_lines_update = self.get_center_lines_update( point_mobs, center_lines ) self.update_animations.append(self.center_lines_update) self.update_animations.remove(self.triangle_update) #Choose random points self.play( Write(random_procedure), ShowCreation(underline) ) self.play(FadeIn(words[0])) self.play(LaggedStartMap( ApplyMethod, point_label_groups, lambda mob : (mob.restore,), )) self.play( ShowCreation(cross), point_label_groups.fade, 1, ) self.wait() #Choose two random lines self.center_lines_update.update(1) self.play( FadeIn(words[1]), LaggedStartMap(GrowFromCenter, center_lines) ) for x in range(3): self.change_point_mobs_randomly(run_time = 1) self.change_point_mobs_to_angles([0.8*np.pi, 1.3*np.pi]) #Flip a coin for each line def flip_point_label_back_and_forth(point_mob, label): for x in range(6): point_mob.rotate(np.pi, about_point = self.center) self.point_labels_update.update(1) self.wait(0.5) self.wait(0.5) def choose_p1_and_p2(): for group in point_label_groups[:2]: group.set_fill(self.point_color, 1) flip_point_label_back_and_forth(*group) choose_p1_and_p2() self.play(Write(words[2])) #Seems convoluted randy = Randolph().flip() randy.scale(0.5) randy.to_edge(DOWN) randy.shift(2*RIGHT) self.play(point_label_groups.fade, 1) self.change_point_mobs_randomly(run_time = 1) choose_p1_and_p2() point_label_groups.fade(1) self.change_point_mobs_randomly(FadeIn(randy)) self.play( PiCreatureSays( randy, "Seems \\\\ convoluted", bubble_kwargs = {"height" : 2, "width" : 2}, target_mode = "confused" ) ) choose_p1_and_p2() self.play( FadeOut(randy.bubble), FadeOut(randy.bubble.content), randy.change, "pondering", ) self.play(Blink(randy)) self.play(FadeOut(randy)) #Choosing the third point self.change_point_mobs([0, 0, -np.pi/2], run_time = 0) p3_group = point_label_groups[2] p3_group.save_state() p3_group.move_to(words[3], LEFT) self.play(Write(words[3], run_time = 1)) self.play( p3_group.restore, p3_group.set_fill, YELLOW, 1 ) self.wait() self.play(Swap(*words[2:4])) self.wait() #Once the continuous randomness is handled rect = SurroundingRectangle(VGroup(words[1], words[3])) rect.set_stroke(WHITE, 2) brace = Brace(words[2], DOWN) brace_text = brace.get_text("4 equally likely outcomes") brace_text.scale_in_place(0.8) self.play(ShowCreation(rect)) self.play(GrowFromCenter(brace)) self.play(Write(brace_text)) self.wait() self.random_procedure_words = words def four_possibilities_for_coin_flips(self): arcs = self.all_arcs point_mobs = self.point_mobs arc = arcs[-1] point_label_groups = self.point_label_groups arc_update = self.get_arcs_update(arcs) arc_update.update(1) self.update_animations.append(arc_update) def second_arc_update_func(arcs): VGroup(*arcs[:-1]).set_stroke(width = 0) arcs[-1].set_stroke(PINK, 6) return arcs second_arc_update = UpdateFromFunc(arcs, second_arc_update_func) second_arc_update.update(1) self.update_animations.append(second_arc_update) self.update_animations.append(Animation(point_label_groups)) def do_the_rounds(): for index in 0, 1, 0, 1: point_mob = point_mobs[index] point_mob.generate_target() point_mob.target.rotate( np.pi, about_point = self.center, ) self.play( MoveToTarget(point_mob), *self.update_animations, run_time = np.sqrt(2)/4 #Hacky reasons to be irrational ) self.wait() self.revert_to_original_skipping_status() do_the_rounds() self.triangle_update.update(1) self.remove(arcs) self.update_animations.remove(arc_update) self.update_animations.remove(second_arc_update) self.play(FadeIn(self.triangle)) self.wait() self.update_animations.insert(0, self.triangle_update) do_the_rounds() self.wait() self.change_point_mobs_randomly() for x in range(2): do_the_rounds() class ThisIsWhereItGetsGood(TeacherStudentsScene): def construct(self): self.teacher_says( "This is where \\\\ things get good", target_mode = "hooray" ) self.change_student_modes(*["hooray"]*3) self.wait(2) class ContrastTwoRandomProcesses(TwoDCase): CONFIG = { "radius" : 1.5, "random_seed" : 0, } def construct(self): circle = Circle(color = WHITE, radius = self.radius) point_mobs = self.get_point_mobs() for point in point_mobs: point.scale_in_place(1.5) point.set_stroke(RED, 1) labels = self.get_point_mob_labels() self.get_labels_update(point_mobs, labels).update(1) center_lines = self.get_center_lines() point_label_groups = VGroup(*[ VGroup(*pair) for pair in zip(point_mobs, labels) ]) right_circles = VGroup(*[ VGroup(circle, *point_label_groups[:i+1]).copy() for i in range(3) ]) left_circles = VGroup( VGroup(circle, center_lines).copy(), VGroup( circle, center_lines, point_label_groups[2] ).copy(), VGroup( circle, center_lines, *point_label_groups[2::-1] ).copy(), ) for circles in left_circles, right_circles: circles.scale(0.5) circles[0].to_edge(UP, buff = MED_LARGE_BUFF) circles[2].to_edge(DOWN, buff = MED_LARGE_BUFF) for c1, c2 in zip(circles, circles[1:]): circles.add(Arrow(c1[0], c2[0], color = GREEN)) left_circles.shift(3*LEFT) right_circles.shift(3*RIGHT) vs = TextMobject("vs.") self.show_creation_of_circle_group(left_circles) self.play(Write(vs)) self.show_creation_of_circle_group(right_circles) self.wait() def show_creation_of_circle_group(self, group): circles = group[:3] arrows = group[3:] self.play( ShowCreation(circles[0][0]), FadeIn(VGroup(*circles[0][1:])), ) for c1, c2, arrow in zip(circles, circles[1:], arrows): self.play( GrowArrow(arrow), ApplyMethod( c1.copy().shift, c2[0].get_center() - c1[0].get_center(), remover = True ) ) self.add(c2) n = len(c2) - len(c1) self.play(*list(map(GrowFromCenter, c2[-n:]))) class Rewrite3DRandomProcedure(Scene): def construct(self): random_procedure = TextMobject("Random procedure") underline = Line(LEFT, RIGHT) underline.stretch_to_fit_width(random_procedure.get_width()) underline.scale(1.1) underline.next_to(random_procedure, DOWN) group = VGroup(random_procedure, underline) group.to_corner(UP+LEFT) words = VGroup(*list(map(TextMobject, [ "Choose 4 random points", "Choose 3 random lines", "Choose $P_4$ at random", "Flip coin for each line \\\\ to get $P_1$, $P_2$, $P_3$", ]))) words.scale(0.8) words.arrange(DOWN, buff = MED_LARGE_BUFF) words.next_to(underline, DOWN) words[1].set_color(YELLOW) cross = Cross(words[0]) cross.set_stroke(RED, 6) self.play( Write(random_procedure), ShowCreation(underline) ) self.play(FadeIn(words[0])) self.play(ShowCreation(cross)) self.wait() self.play(LaggedStartMap(FadeIn, words[1])) self.play(LaggedStartMap(FadeIn, words[2])) self.wait(2) self.play(Write(words[3])) self.wait(3) class AntipodalViewOfThreeDCase(ExternallyAnimatedScene): pass class ThreeDAnswer(Scene): def construct(self): words = TextMobject( "Probability that the tetrahedron contains center:", "$\\frac{1}{8}$" ) words.set_width(FRAME_WIDTH - 1) words.to_edge(DOWN) words[1].set_color(BLUE) self.play(Write(words)) self.wait(2) class FormalWriteupScreenCapture(ExternallyAnimatedScene): pass class Formality(TeacherStudentsScene): def construct(self): words = TextMobject( "Write-up by Ralph Howard and Paul Sisson (link below)" ) words.scale(0.7) words.to_corner(UP+LEFT, buff = MED_SMALL_BUFF) self.student_says( "How would you \\\\ write that down?", target_mode = "sassy" ) self.change_student_modes("confused", "sassy", "erm") self.wait() self.play( Write(words), FadeOut(self.students[1].bubble), FadeOut(self.students[1].bubble.content), self.teacher.change, "raise_right_hand" ) self.change_student_modes( *["pondering"]*3, look_at_arg = words ) self.wait(8) class ProblemSolvingTakeaways(Scene): def construct(self): title = TextMobject("Problem solving takeaways") underline = Line(LEFT, RIGHT) underline.set_width(title.get_width()*1.1) underline.next_to(title, DOWN) group = VGroup(title, underline) group.to_corner(UP+LEFT) points = VGroup(*[ TextMobject(string, alignment = "") for string in [ "Ask a simpler version \\\\ of the question", "Try reframing the question \\\\ around new constructs", ] ]) points[0].set_color(BLUE) points[1].set_color(YELLOW) points.arrange( DOWN, buff = LARGE_BUFF, aligned_edge = LEFT ) points.next_to(group, DOWN, LARGE_BUFF) self.play(Write(title), ShowCreation(underline)) self.wait() for point in points: self.play(Write(point)) self.wait(3) class BrilliantPuzzle(PiCreatureScene): CONFIG = { "random_seed" : 2, } def construct(self): students = self.students tests = VGroup() for student in students: test = self.get_test() test.move_to(0.75*student.get_center()) tests.add(test) student.test = test for i, student in enumerate(students): student.right = students[(i+1)%len(students)] student.left = students[(i-1)%len(students)] arrows = VGroup() for s1, s2 in adjacent_pairs(self.students): arrow = Arrow( s1.get_center(), s2.get_center(), path_arc = np.pi/2, buff = 0.8 ) arrow.tip.shift(SMALL_BUFF*arrow.get_vector()) arrow.tip.shift(-0.1*SMALL_BUFF*arrow.tip.get_center()) # arrow.shift(-MED_SMALL_BUFF*arrow.get_vector()) arrow.set_color(RED) arrow.pointing_right = True arrows.add(arrow) s1.arrow = arrow arrow.student = s1 title = TextMobject("Puzzle from Brilliant") title.scale(0.75) title.to_corner(UP+LEFT) question = TextMobject("Expected number of \\\\ circled students?") question.to_corner(UP+RIGHT) self.remove(students) self.play(Write(title)) self.play(LaggedStartMap(GrowFromCenter, students)) self.play( LaggedStartMap(Write, tests), LaggedStartMap( ApplyMethod, students, lambda m : (m.change, "horrified", m.test) ) ) self.wait() self.play(LaggedStartMap( ApplyMethod, students, lambda m : (m.change, "conniving") )) self.play(LaggedStartMap(ShowCreation, arrows)) for x in range(2): self.swap_arrows_randomly(arrows) self.wait() circles = self.circle_students() self.play(Write(question)) for x in range(10): self.swap_arrows_randomly(arrows, FadeOut(circles)) circles = self.circle_students() self.wait() #### def get_test(self): lines = VGroup(*[Line(ORIGIN, 0.5*RIGHT) for x in range(6)]) lines.arrange(DOWN, buff = SMALL_BUFF) rect = SurroundingRectangle(lines) rect.set_stroke(WHITE) lines.set_stroke(WHITE, 2) test = VGroup(rect, lines) test.set_height(0.5) return test def create_pi_creatures(self): self.students = VGroup(*[ PiCreature( color = random.choice([BLUE_C, BLUE_D, BLUE_E, GREY_BROWN]) ).scale(0.25).move_to(3*vect) for vect in compass_directions(8) ]) return self.students def get_arrow_swap_anim(self, arrow): arrow.generate_target() if arrow.pointing_right: target_color = GREEN target_angle = np.pi - np.pi/4 else: target_color = RED target_angle = np.pi + np.pi/4 arrow.target.set_color(target_color) arrow.target.rotate( target_angle, about_point = arrow.student.get_center() ) arrow.pointing_right = not arrow.pointing_right return MoveToTarget(arrow, path_arc = np.pi) def swap_arrows_randomly(self, arrows, *added_anims): anims = [] for arrow in arrows: if random.choice([True, False]): anims.append(self.get_arrow_swap_anim(arrow)) self.play(*anims + list(added_anims)) def circle_students(self): circles = VGroup() circled_students = list(self.students) for student in self.students: if student.arrow.pointing_right: to_remove = student.right else: to_remove = student.left if to_remove in circled_students: circled_students.remove(to_remove) for student in circled_students: circle = Circle(color = YELLOW) circle.set_height(1.2*student.get_height()) circle.move_to(student) circles.add(circle) self.play(ShowCreation(circle)) return circles class ScrollThroughBrilliantCourses(ExternallyAnimatedScene): pass class BrilliantProbability(ExternallyAnimatedScene): pass class Promotion(PiCreatureScene): CONFIG = { "seconds_to_blink" : 5, } def construct(self): url = TextMobject("https://brilliant.org/3b1b/") url.to_corner(UP+LEFT) rect = Rectangle(height = 9, width = 16) rect.set_height(5.5) rect.next_to(url, DOWN) rect.to_edge(LEFT) self.play( Write(url), self.pi_creature.change, "raise_right_hand" ) self.play(ShowCreation(rect)) self.wait(2) self.change_mode("thinking") self.wait() self.look_at(url) self.wait(10) self.change_mode("happy") self.wait(10) self.change_mode("raise_right_hand") self.wait(10) self.remove(rect) self.play( url.next_to, self.pi_creature, UP+LEFT ) url_rect = SurroundingRectangle(url) self.play(ShowCreation(url_rect)) self.play(FadeOut(url_rect)) self.wait(3) class AddedPromoWords(Scene): def construct(self): words = TextMobject( "First", "$2^8$", "vistors get", "$(e^\\pi - \\pi)\\%$", "off" ) words.set_width(FRAME_WIDTH - 1) words.to_edge(DOWN) words.set_color_by_tex("2^8", YELLOW) words.set_color_by_tex("pi", PINK) self.play(Write(words)) self.wait() class PatreonThanks(PatreonEndScreen): CONFIG = { "specific_patrons" : [ "Randall Hunt", "Burt Humburg", "CrypticSwarm", "Juan Benet", "David Kedmey", "Marcus Schiebold", "Ali Yahya", "Mayank M. Mehrotra", "Lukas Biewald", "Yana Chernobilsky", "Kaustuv DeBiswas", "Kathryn Schmiedicke", "Yu Jun", "Dave Nicponski", "Damion Kistler", "Jordan Scales", "Markus Persson", "Egor Gumenuk", "Yoni Nazarathy", "Ryan Atallah", "Joseph John Cox", "Luc Ritchie", "James Park", "Samantha D. Suplee", "Delton", "Thomas Tarler", "Jake Alzapiedi", "Jonathan Eppele", "Taro Yoshioka", "1stViewMaths", "Jacob Magnuson", "Mark Govea", "Dagan Harrington", "Clark Gaebel", "Eric Chow", "Mathias Jansson", "David Clark", "Michael Gardner", "Erik Sundell", "Awoo", "Dr. David G. Stork", "Tianyu Ge", "Ted Suzman", "Linh Tran", "Andrew Busey", "John Haley", "Ankalagon", "Eric Lavault", "Boris Veselinovich", "Julian Pulgarin", "Jeff Linse", "Cooper Jones", "Ryan Dahl", "Robert Teed", "Jason Hise", "Meshal Alshammari", "Bernd Sing", "Mustafa Mahdi", "Mathew Bramson", "Jerry Ling", "Shimin Kuang", "Rish Kundalia", "Achille Brighton", "Ripta Pasay", ] }