def construct(self): t1 = TextMobject( "Let's look at our \\texttt{power(x,n)} function from Part 1 again" ) t1.to_edge(UP) power1_code = CodeBlock( 'Java', r""" public static int power(int x, int n) { if (n == 0) { return 1; } int t = power(x, n - 1); return x * t; } """) power1_code.next_to(t1, DOWN, buff=MED_LARGE_BUFF) self.play( FadeIn(t1), FadeIn(power1_code), ) self.wait() t2 = TextMobject("How many times does it call itself?") t2.next_to(power1_code, DOWN, buff=MED_LARGE_BUFF) self.play(Write(t2)) self.wait(duration=2) t3 = TextMobject( "It call's itself $n$ times. Recall our original equation:") t3.move_to(t2) f1 = TexMobject('x^n=', 'x \\times x \\times ... \\times x', '= x \\times x^{n-1}') f1.next_to(t3, DOWN) b1 = BraceLabel(f1[1], '$n$ times', brace_direction=DOWN, label_constructor=TextMobject) f1 = VGroup(f1, b1) hr = SurroundingRectangle(power1_code.get_code().get_lines(5)[-5:-2]) self.play(ReplacementTransform(t2, t3), FadeInFromDown(f1), FadeIn(hr)) self.wait(duration=4) t4 = TextMobject('Can we do better?') self.play(*[FadeOut(o) for o in self.mobjects], FadeIn(t4)) self.wait() self.play(FadeOut(t4))
def construct(self): code_scale = 0.75 foo_code = CodeBlock( 'Java', r""" int foo() { int n = bar(2, 1); n += bar(2, 2); return n; } """, code_scale=code_scale, ) bar_code = CodeBlock( 'Java', r""" int bar(int x, int y) { if (x == 1) { return y; } int b = bar(x - 1, y + 1); return b; } """, line_offset=5, code_scale=code_scale, ) main_code = CodeBlock('Java', 'off_screen') main_code.shift(UP * 8) # Offscreen up self.add(main_code) title = TextMobject('CodeBlock Stepping Demo') title.to_edge(UP) foo_code.next_to(title, DOWN) bar_code.next_to(foo_code.get_code(), DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT, submobject_to_align=bar_code.get_code()) self.play(*[FadeIn(o) for o in [title, foo_code, bar_code]]) self.wait() # Step through both code blocks until done. xi = main_code.pre_call(foo_code, 1) self.play(*main_code.get_control_transfer_counterclockwise(xi)) foo_code.post_control_transfer(xi, self) foo_code.prep_annotations(2, 3) foo_code.generate_target().highlight_lines(2).set_annotation(2, 'n: ?') self.play(MoveToTarget(foo_code)) n = self.run_bar(bar_code, foo_code, 2, 2, 1) self.play(foo_code.highlight_lines, 3, foo_code.set_annotation, 2, None, foo_code.set_annotation, 3, 'n: %d' % n, bar_code.fade_labels) n += self.run_bar(bar_code, foo_code, 3, 2, 2) self.play(foo_code.highlight_lines, 4, foo_code.set_annotation, 3, 'n: %d' % n) xi = foo_code.pre_return(main_code, 1) self.play(*foo_code.get_control_transfer_clockwise(xi)) main_code.post_control_transfer(xi, self) self.play(FadeOut(title), FadeOut(foo_code), FadeOut(bar_code)) self.wait()
def construct(self): code_scale = 0.75 foo_code = CodeBlock( 'Java', r""" int foo() { int n = bar(2, 1); n += bar(2, 2); return n; } """, add_labels=True, code_scale=code_scale, ) bar_code = CodeBlock( 'Java', r""" int bar(int x, int y) { if (x == 1) { return y; } int b = bar(x - 1, y + 1); return b; } """, line_offset=5, add_labels=True, code_scale=code_scale, ) title = TextMobject('CodeBlock Basics Demo') title.to_edge(UP) foo_code.next_to(title, DOWN) foo_code.fade_labels() bar_code.next_to(foo_code.get_code(), DOWN, buff=MED_LARGE_BUFF, aligned_edge=LEFT, submobject_to_align=bar_code.get_code()) self.play(*[FadeIn(o) for o in [title, foo_code, bar_code]]) self.wait(0.5) self.play(foo_code.highlight_lines, 1, bar_code.highlight_lines, (6, 8)) self.wait(0.5) self.play(foo_code.highlight_lines, 2, bar_code.highlight_lines, (8, 10)) self.play(foo_code.highlight_lines, 3, bar_code.highlight_lines, (10, 12)) self.wait(0.5) self.play(Indicate(foo_code)) self.wait(0.5) self.play(Indicate(bar_code)) self.wait(0.5) self.play(foo_code.remove_highlight, bar_code.remove_highlight) self.wait(0.5) self.play(FadeOut(foo_code)) self.wait(0.5) self.play(FadeIn(foo_code)) self.wait(0.5) self.play(foo_code.show_labels, bar_code.fade_labels) self.wait(0.5) self.play(foo_code.fade_labels, bar_code.show_labels) self.wait(0.5) foo_code.move_hidden_highlight(2) bar_code.move_hidden_highlight((8, 10)) self.wait(0.5) self.play(foo_code.highlight_lines, 2, bar_code.highlight_lines, (8, 10)) self.wait(0.5) self.play(foo_code.highlight_lines, 4, bar_code.highlight_lines, (6, 9)) self.wait(0.5) self.play(foo_code.remove_highlight, bar_code.remove_highlight) self.wait(0.5) self.play(FadeOut(foo_code), FadeOut(bar_code)) self.wait()
def construct(self): unsorted = [11, 0, 8, 2, 2, 9, 14, 5] code_scale = 0.6 # TODO: move to base, since it references code lines and runs this code ms_code = CodeBlock( 'Java', r""" public static int[] mergeSort(int[] a) { if (a.length == 1) { return a; } int m = a.length / 2; int[] l, r; l = Arrays.copyOfRange(a, 0, m); r = Arrays.copyOfRange(a, m, a.length); l = mergeSort(l); r = mergeSort(r); return merge(l, r); } """, code_scale=code_scale, ) ms_code.set_annotation(5, None) t1 = TextMobject("Recursive mergesort in Java") t1.to_edge(UP) ms_code.next_to(t1, DOWN, buff=MED_LARGE_BUFF) self.play(FadeIn(t1)) self.play( LaggedStartMap(FadeInFromDown, ms_code.get_code(), lag_ratio=0.2)) self.wait(duration=3.0) t2 = TextMobject( "Let's trace through this and track our work with a tree", buff=LARGE_BUFF) t2.next_to(ms_code, DOWN, buff=LARGE_BUFF) self.play(FadeInFromDown(t2)) self.wait(duration=3) self.play(ms_code.to_edge, DR, FadeOutAndShiftDown(t2), FadeOutAndShift(t1, UP)) colors = color_gradient([PINK, BLUE, YELLOW_D], 15) tree = build_merge_sort_tree(unsorted, text_scale=1.0) update_tree_colors(tree, colors) tree.layout(1.6, 1.2) g = tree.to_vgroup() g.center().to_edge(UP) be = Merge8Exposition(self, tree, ms_code) t1 = TextMobject("Start with an array of random numbers") t1.next_to(tree.label, DOWN, buff=MED_LARGE_BUFF) be.deferred_play(1, FadeIn(t1)) be.deferred_wait(1) be.deferred_play(3, FadeOut(t1)) be.play(FadeIn(tree.label)) self.run_merge_sort(tree, be, 0) self.wait() t1 = TextMobject("We divide the problem on the way down") t2 = TextMobject("and we recombine by merging on the way up") t1.shift(DOWN * 1.5) t2.next_to(t1, DOWN) self.play(FadeInFromDown(t1)) self.wait() self.play(FadeInFromDown(t2)) self.wait(duration=3) t3 = TextMobject("We call this \\textit{divide-and-conquer}") t4 = TextMobject("\\textit{This is very common!} You'll see it a lot.") t3.shift(DOWN * 1.5) t4.next_to(t3, DOWN) self.play(FadeOutAndShiftDown(t1), FadeOutAndShiftDown(t2)) self.play(FadeInFromDown(t3)) self.wait() self.play(FadeInFromDown(t4)) self.wait(duration=3) t5 = TextMobject("This one was nicely balanced and even...") t6 = TextMobject("let's try one that's a little bit odd") t5.shift(DOWN * 1.5) t6.next_to(t5, DOWN) self.play(FadeOutAndShiftDown(t3), FadeOutAndShiftDown(t4)) self.play(FadeInFromDown(t5)) self.wait() self.play(FadeInFromDown(t6)) self.wait(duration=3) self.play(*[FadeOut(o) for o in self.mobjects])
def construct(self): high_quality = False # - Foo calls bar passing some args. Bar does something, returns. code_scale = 0.75 main_code = CodeBlock( 'Java', r""" public static void main(String[] args) { foo(); } """, code_scale=code_scale, ) foo_code = CodeBlock( 'Java', r""" static int foo() { int n = bar(1, 2); return n; } """, code_scale=code_scale, ) bar_code = CodeBlock( 'Java', r""" static int bar(int x, int y) { int a = x + y; int b = a * 2; return b; } """, code_scale=code_scale, ) fbg = VGroup(foo_code, bar_code) bar_code.next_to(foo_code, DOWN, aligned_edge=LEFT, buff=LARGE_BUFF) fbg.to_edge(TOP) title = TextMobject('We have two Java functions, foo() and bar()') title.to_edge(UP) self.play( ShowCreation(title), FadeInFromDown(fbg), ) self.wait(duration=2) # Let's write down what happens when we run this. t2 = TextMobject("Let's run them and write down\\\\" "each variable as we go...") t2.to_edge(LEFT) self.play(Write(t2), fbg.to_edge, RIGHT, {'buff': MED_SMALL_BUFF}) self.wait() t3 = TextMobject('Running foo() and bar() by hand').to_edge(UP) if high_quality: self.play(ReplacementTransform(VGroup(title, t2), t3)) else: self.play(FadeOut(title), FadeOut(t2), FadeIn(t3)) self.remove(title, t2) title = t3 self.wait() t4 = TextMobject('First, make a place\\\\to write each variable') t4.next_to(title, DOWN, buff=LARGE_BUFF).to_edge(LEFT) self.play(FadeIn(t4)) self.wait() foo_vars = VGroup(TexMobject('n:', '\\_')) foo_vars.next_to(foo_code, LEFT, buff=LARGE_BUFF * 2) bar_vars = VGroup( TexMobject('x:', '\\_'), TexMobject('y:', '\\_').shift(DOWN * .75), TexMobject('a:', '\\_').shift(DOWN * 1.5), TexMobject('b:', '\\_').shift(DOWN * 2.25), ) bar_vars.next_to(bar_code, LEFT, aligned_edge=TOP, buff=LARGE_BUFF * 2) self.play(Write(foo_vars)) self.play(Write(bar_vars)) self.wait() t5 = TextMobject("Start in foo()...") t5.move_to(t4, aligned_edge=LEFT) self.play(FadeOut(t4), FadeIn(t5)) self.wait() foo_code.move_hidden_highlight(2) self.play(FadeOut(t5), foo_code.highlight_lines, 2) self.wait() foo_n_q = TexMobject('?').move_to(foo_vars[0][1], aligned_edge=BOTTOM).shift(UP * 0.1) self.play(Write(foo_n_q)) foo_vars.add(foo_n_q) self.wait() xi = foo_code.pre_call(bar_code, (1, 3)) self.play(*foo_code.get_control_transfer_counterclockwise(xi), ) bar_code.post_control_transfer(xi, self) self.wait() bar_x = TexMobject('1').move_to(bar_vars[0][1], aligned_edge=BOTTOM).shift(UP * 0.1) bar_y = TexMobject('2').move_to(bar_vars[1][1], aligned_edge=BOTTOM).shift(UP * 0.1) a = Arrow(bar_code.get_code().get_lines(2), VGroup(bar_x, bar_y).get_right(), stroke_width=3) self.play(Write(bar_x), Write(bar_y), ShowCreationThenDestruction(a)) bar_vars_extras = VGroup() bar_vars_extras.add(bar_x, bar_y) self.play(bar_code.highlight_lines, 3) self.wait() bar_a = TexMobject('3').move_to(bar_vars[2][1], aligned_edge=BOTTOM).shift(UP * 0.1) a = Arrow(bar_code.get_code().get_lines(3), bar_a.get_right(), stroke_width=3) self.play(Write(bar_a), ShowCreationThenDestruction(a)) bar_vars_extras.add(bar_a) self.play(bar_code.highlight_lines, 4) self.wait() bar_b = TexMobject('6').move_to(bar_vars[3][1], aligned_edge=BOTTOM).shift(UP * 0.1) a = Arrow(bar_code.get_code().get_lines(4), bar_b.get_right(), stroke_width=3) self.play(Write(bar_b), ShowCreationThenDestruction(a)) bar_vars_extras.add(bar_b) self.play(bar_code.highlight_lines, 5) self.wait() xi = bar_code.pre_return(foo_code, 2) self.play(*bar_code.get_control_transfer_clockwise(xi), ) foo_code.post_control_transfer(xi, self) self.wait() foo_n = TexMobject('6').move_to(foo_vars[0][1], aligned_edge=BOTTOM).shift(UP * 0.1) a = Arrow(foo_code.get_code().get_lines(2), foo_n.get_right(), stroke_width=3) self.play( foo_code.highlight_lines, 3, ReplacementTransform(foo_n_q, foo_n), ShowCreationThenDestruction(a), ) foo_vars.add(foo_n) self.wait() # - Now give the variables "homes" in each function. Variables like # homes; they're warm and safe and sized just for them! print('Give variables homes') t1 = TextMobject('So how does the\\\\computer do this?').to_edge(LEFT) self.play(FadeIn(t1), foo_code.remove_highlight) self.wait(duration=2) t2 = TextMobject( 'Every variable is stored\\\\someplace in memory').to_edge(LEFT) new_title = TextMobject('Where are variables stored?').to_edge(UP) self.play( FadeOut(t1), FadeOut(title), FadeIn(new_title), FadeIn(t2), ) title = new_title self.wait() em = TextMobject('M') slot_height = em.get_height() + SMALL_BUFF * 2 slot_width = em.get_width() * 4 + SMALL_BUFF * 2 def build_var_home(name, value): var_name = TextMobject(name) slot_box = Rectangle(height=slot_height, width=slot_width, stroke_width=1) var_value = TextMobject(value) var_value.move_to(slot_box) var_name.next_to(slot_box, LEFT) stack_slot = VGroup(slot_box, var_name, var_value) return stack_slot foo_homes = build_var_home('n', '6') foo_homes.move_to(foo_vars, aligned_edge=LEFT) self.play(ReplacementTransform(foo_vars, foo_homes)) self.wait() bar_var_vals = [('x', '1'), ('y', '2'), ('a', '3'), ('b', '6')] bar_homes = VGroup() bar_homes_shift = 0 for n, v in bar_var_vals: bar_homes.add(build_var_home(n, v).shift(DOWN * bar_homes_shift)) bar_homes_shift += 0.75 bar_homes.move_to(bar_vars, aligned_edge=LEFT) t3 = TextMobject("Each variable lives in a\\\\``slot''").to_edge(LEFT) self.play( ReplacementTransform(bar_vars, bar_homes), # FadeOut(bar_vars), FadeOut(bar_vars_extras), FadeIn(bar_homes), ) self.wait() self.play( FadeOut(t2), FadeIn(t3), ) self.wait() # - Now arrange the homes into a "stack frame". print('Build stack frames') t4 = TextMobject( "All slots for a function\\\\are put together in a\\\\``frame''") t4.to_edge(LEFT) self.play(FadeOut(t3), FadeIn(t4)) frame_width = 2.8 foo_vars = [('n', '6')] foo_frame = StackFrame(foo_code, 'foo()', 3, foo_vars, width=frame_width) foo_frame.move_to(foo_homes, aligned_edge=LEFT).shift(LEFT * .5) self.play(ReplacementTransform(foo_homes, foo_frame)) self.wait() bar_frame = StackFrame(bar_code, 'bar(1,2)', 9, bar_var_vals, width=frame_width) bar_frame.move_to(bar_homes, aligned_edge=LEFT).shift(LEFT * .5) self.play(ReplacementTransform(bar_homes, bar_frame)) self.wait() t5 = TextMobject("\\textit{They're happy and warm\\\\together!}")\ .scale(0.75).next_to(t4, DOWN, buff=LARGE_BUFF) self.play(FadeIn(t5)) self.wait() # Cool, so where do frames live? print('Where do frames live') t6 = TextMobject('So where do frames live?').to_edge(LEFT) self.play( FadeOut(t5), FadeOut(t4), FadeIn(t6), ) self.wait() t7 = TextMobject("On the ``call stack''!").next_to(t6, DOWN, buff=LARGE_BUFF) self.play(FadeIn(t7)) self.wait() new_title = TextMobject('The Call Stack').to_edge(UP) t1 = TextMobject('Function calls push a new frame\\\\onto the stack')\ .to_edge(LEFT).shift(UP) t2 = TextMobject('Returning pops a frame off\\\\the stack').next_to( t1, DOWN, buff=LARGE_BUFF) box_count = 8 colors = color_gradient([BLUE, ORANGE], box_count) little_boxes = VGroup(*[ Rectangle(height=0.25, width=0.75, fill_opacity=1, color=colors[i]) for i in range(box_count) ]) little_boxes.arrange(UP, buff=0.1) little_boxes.next_to(VGroup(foo_code, bar_code), LEFT, buff=LARGE_BUFF) self.play( ReplacementTransform(title, new_title), FadeOut(t6), FadeOut(t7), FadeOut(foo_frame), FadeOut(bar_frame), FadeIn(t1), LaggedStartMap(FadeInFrom, little_boxes, lambda m: (m, UP), lag_ratio=1.0, run_time=4.0), ) title = new_title self.wait() self.play( FadeIn(t2), LaggedStartMap(FadeOutAndShift, VGroup(*reversed(little_boxes)), lambda m: (m, UP), lag_ratio=1.0, run_time=4.0), ) self.wait(duration=1) t3 = TextMobject( "Let's run again and see\\\\the call stack in action...").to_edge( LEFT) t3.shift(UP) self.play(FadeOut(t1), FadeOut(t2), FadeIn(t3)) self.wait() print('Run with real call stack') # Let's also put main() into the picture. Start it off-frame upper right t4 = TextMobject("... and get main()\\\\into the picture.")\ .next_to(t3, DOWN, buff=LARGE_BUFF) main_code.next_to(title, DOWN, buff=MED_SMALL_BUFF).to_edge(RIGHT) main_code.shift(UP * 3 + RIGHT * 3) g = VGroup(main_code, foo_code, bar_code) self.play( g.arrange, DOWN, { 'aligned_edge': LEFT, 'buff': MED_SMALL_BUFF }, g.next_to, title, DOWN, {'buff': MED_SMALL_BUFF}, g.to_edge, RIGHT, FadeInFromDown(t4), ) self.wait(duration=2) t1 = TextMobject('Start in main()...') t1.next_to(title, DOWN, buff=LARGE_BUFF).to_edge(LEFT) frame_width = 3.0 args_ref = TextMobject('[ ]').scale(0.5) main_frame = StackFrame(main_code, 'main()', 3, [('args', args_ref)], width=frame_width) main_frame.next_to(g, LEFT, buff=LARGE_BUFF).to_edge(DOWN) main_code.move_hidden_highlight(3) self.play(FadeIn(t1), FadeInFromDown(main_frame), main_code.highlight_lines, 3, FadeOut(t3), FadeOut(t4)) self.wait() foo_frame = StackFrame(foo_code, 'foo()', 5, ['n'], width=frame_width) foo_frame.next_to(main_frame, UP, buff=SMALL_BUFF) b1 = BraceLabel(foo_frame, 'Calling foo()\\\\pushes a frame', brace_direction=LEFT, label_constructor=TextMobject) xi = main_code.pre_call(foo_code, 1) self.play( *main_code.get_control_transfer_counterclockwise(xi), FadeInFrom(foo_frame, UP), FadeInFrom(b1, UP), FadeOut(t1), ) foo_code.post_control_transfer(xi, self) self.wait(duration=2) self.play(foo_code.highlight_lines, 2, foo_frame.set_line, 6, FadeOut(b1)) self.wait() bar_frame = StackFrame(bar_code, 'bar(1, 2)', 10, ['x', 'y', 'a', 'b'], width=frame_width) bar_frame.next_to(foo_frame, UP, buff=SMALL_BUFF) b1 = BraceLabel(bar_frame, 'Calling bar()\\\\pushes a frame', brace_direction=LEFT, label_constructor=TextMobject) xi = foo_code.pre_call(bar_code, (1, 3)) self.play( *foo_code.get_control_transfer_counterclockwise(xi), FadeInFrom(bar_frame, UP), FadeInFrom(b1, UP), ) bar_code.post_control_transfer(xi, self) self.wait() self.play(bar_frame.update_slot, 'x', 1, bar_frame.update_slot, 'y', 2, FadeOut(b1)) self.play(bar_code.highlight_lines, 3, bar_frame.set_line, 11) self.wait() self.play(bar_frame.update_slot, 'a', 3) self.play(bar_code.highlight_lines, 4, bar_frame.set_line, 12) self.wait() self.play(bar_frame.update_slot, 'b', 6) self.play(bar_code.highlight_lines, 5, bar_frame.set_line, 13) b1 = BraceLabel(bar_frame, "Returning pops\\\\bar's frame", brace_direction=LEFT, label_constructor=TextMobject) self.play(FadeIn(b1)) self.wait(duration=2) xi = bar_code.pre_return(foo_code, 2) self.play( *bar_code.get_control_transfer_clockwise(xi), Uncreate(bar_frame), FadeOut(b1), ) foo_code.post_control_transfer(xi, self) self.wait() self.play(foo_code.highlight_lines, 3, foo_frame.set_line, 7, foo_frame.update_slot, 'n', 6) b1 = BraceLabel(foo_frame, "Returning pops\\\\foo's frame", brace_direction=LEFT, label_constructor=TextMobject) self.play(FadeIn(b1)) self.wait() xi = foo_code.pre_return(main_code, 3) self.play( *foo_code.get_control_transfer_clockwise(xi), Uncreate(foo_frame), FadeOut(b1), ) main_code.post_control_transfer(xi, self) self.wait() self.play(main_code.highlight_lines, 4, main_frame.set_line, 4) self.wait() t1 = TextMobject( 'And when main() returns\\\\the program ends').to_edge(LEFT) self.play(FadeIn(t1)) self.wait() off_screen_code = CodeBlock('Java', 'off_screen') off_screen_code.shift(UP * 8) # Offscreen up self.add(off_screen_code) xi = main_code.pre_return(off_screen_code, 1) self.play( *main_code.get_control_transfer_clockwise(xi), Uncreate(main_frame), FadeOut(t1), ) off_screen_code.post_control_transfer(xi, self) self.wait() t1 = TextMobject("Alright, let's do a more complicated one!") self.play( FadeInFromDown(t1), FadeOutAndShift(g, RIGHT), ) self.wait()