From ff2171efd6f1860b111450f10a0f0ba5f6803b11 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 21 Jun 2021 16:46:31 +0200 Subject: [PATCH 1/4] add manim specific gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 998218d..a3fe1ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# -----> manim +media/ + # ---> Python # Byte-compiled / optimized / DLL files __pycache__/ From 0b983516c971395294e6c4859aae11858b954d24 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 5 Jul 2021 15:23:39 +0200 Subject: [PATCH 2/4] add file for useful references --- manim-resources.org | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 manim-resources.org diff --git a/manim-resources.org b/manim-resources.org new file mode 100644 index 0000000..4fd0d81 --- /dev/null +++ b/manim-resources.org @@ -0,0 +1,51 @@ +* Commands +=$ manim -pql scene.py SquareToCircle= + +** -n, --from_animation_number TEXT +Start rendering from n_0 until n_1. If n_1 +is left unspecified, renders all scenes +after n_0. + + +* Transform vs ReplacementTransform +[[https://www.reddit.com/r/manim/comments/bq5bk2/manim_tutorial_difference_between_transform_and/]] + + +* updater +useful to connecting animations? +[[https://docs.manim.community/en/stable/reference/manim.mobject.mobject.Mobject.html?highlight=add_updater#manim.mobject.mobject.Mobject.add_updater]] + + +* Value Tracker (e.g. for pointers) +[[https://docs.manim.community/en/stable/reference/manim.mobject.value_tracker.ValueTracker.html#manim.mobject.value_tracker.ValueTracker]] + + +* Matrix +maybe implement sequences and arrays with this? +[[https://docs.manim.community/en/stable/reference/manim.mobject.matrix.MobjectMatrix.html#manim.mobject.matrix.MobjectMatrix]] + + +* Indication +[[https://docs.manim.community/en/stable/reference/manim.animation.indication.html]] + + +* Graphs +[[https://docs.manim.community/en/stable/reference/manim.mobject.graph.Graph.html#manim.mobject.graph.Graph]] + + +* Animations +[[https://azarzadavila-manim.readthedocs.io/en/latest/animation.html]] + + +* [[https://eulertour.com/][Online Editor]] + + +* Examples +** [[https://www.youtube.com/channel/UCVefHPaA35CQUzBYZLDXoxQ/videos][Matterhorn - YouTube]] +** [[https://github.com/mitkonikov/manim-code][Manim Extension for Code Explanatory Videos]] +** [[https://manim.flipdot.org/detail/02_animations/custom_VMobject/][VMobject - Flipdot]] + +** https://github.com/Elteoremadebeethoven/ManimCE-changes/blob/main/mce-new-features.py + +* Reference Manual +[[https://docs.manim.community/en/stable/reference.html]] From 271e1500774e8e5a05ea21ca9c79288da82f3870 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 5 Jul 2021 15:24:31 +0200 Subject: [PATCH 3/4] add early version of binary search animation --- binary-search/binary-search-manim.py | 92 ++++++++++++++++++++++++++++ binary-search/binary-search.py | 7 +++ 2 files changed, 99 insertions(+) create mode 100644 binary-search/binary-search-manim.py create mode 100644 binary-search/binary-search.py diff --git a/binary-search/binary-search-manim.py b/binary-search/binary-search-manim.py new file mode 100644 index 0000000..8477117 --- /dev/null +++ b/binary-search/binary-search-manim.py @@ -0,0 +1,92 @@ +from manim import * + + +class Sequence(VMobject): +# evenly spaced characters + + def __init__(self, seq): + VMobject.__init__(self) + seq = [t.move_to(i * 0.5 * RIGHT) for i, t in enumerate(seq)] + self.add(VGroup(*seq).move_to(ORIGIN + 2*UP)) + + +class Pointer(VMobject): +# pointer to sequence element + + def __init__(self, pointee, name): + VMobject.__init__(self) + arrow = Arrow(ORIGIN, DOWN).next_to(pointee, UP) + name_tex = Tex(name).next_to(arrow, UP) + self.add(arrow, name_tex) + + +class ProgramCounter(VMobject): +# pointer to current code line + + def __init__(self, line): + VMobject.__init__(self) + self.add(Arrow(ORIGIN, RIGHT).next_to(line, LEFT)) + + +class Base(Scene): + def construct(self, n, k): + + # initial situation + seq = [Tex("1")] + [Tex("?") for _ in range(n-2)] + [Tex("0")] + self.play(Create(Sequence(seq))) + + # source code binary search + code = Code(file_name="binary-search.py", language="Python", insert_line_no=False, style='monokai') + code.move_to(DOWN) + self.play(Write(code)) + line_lr, line_while, line_m, line_test, line_l, _, line_r = code[2] + + def test(x): + return 1 if x <= k else 0 + + def update_pc(pc, line): + npc = ProgramCounter(line) + self.play(ReplacementTransform(pc, npc)) + return npc + + # initialize borders + pc = ProgramCounter(line_lr) + self.play(Create(pc)) + l, r = 0, n-1 + lp = Pointer(seq[l], "l") + rp = Pointer(seq[r], "r") + self.play(Write(lp), Create(rp)) + + while r - l > 1: + # calculate m + pc = update_pc(pc, line_m) + m = (l + r) // 2 + mp = Pointer(seq[m], "m") + self.play(Create(mp)) + + # test + pc = update_pc(pc, line_test) + old = seq.copy() + seq[m] = Tex(str(test(m))) + self.play(ReplacementTransform(Sequence(old), Sequence(seq))) + + if test(m): + # update left + pc = update_pc(pc, line_l) + l = m + op = lp + lp = Pointer(seq[m], "l") + self.play(Uncreate(mp), ReplacementTransform(op, lp)) + else: + # update right + pc = update_pc(pc, line_r) + r = m + op = rp + rp = Pointer(seq[m], "r") + self.play(Uncreate(mp), ReplacementTransform(op, rp)) + + self.wait(2) + +class Main(Base): + def construct(self): + Base.construct(self, 20, 6) diff --git a/binary-search/binary-search.py b/binary-search/binary-search.py new file mode 100644 index 0000000..937361e --- /dev/null +++ b/binary-search/binary-search.py @@ -0,0 +1,7 @@ +l, r = 0, n-1 +while r - l > 1: + m = (l + r) / 2 + if test(m): + l = m + else: + r = m From a65523652948291ec6dc302250b412b29ac412a3 Mon Sep 17 00:00:00 2001 From: bibin Date: Mon, 5 Jul 2021 15:30:20 +0200 Subject: [PATCH 4/4] improved binary search animation version --- binary-search/binary-search-manim.py | 176 +++++++++++++++------------ binary-search/binary-search.cpp | 7 ++ binary-search/binary-search.py | 7 -- 3 files changed, 105 insertions(+), 85 deletions(-) create mode 100644 binary-search/binary-search.cpp delete mode 100644 binary-search/binary-search.py diff --git a/binary-search/binary-search-manim.py b/binary-search/binary-search-manim.py index 8477117..8f383de 100644 --- a/binary-search/binary-search-manim.py +++ b/binary-search/binary-search-manim.py @@ -1,92 +1,112 @@ from manim import * -class Sequence(VMobject): -# evenly spaced characters +class Main(Scene): + def construct(self): + n = 13 + k = 8 - def __init__(self, seq): - VMobject.__init__(self) - seq = [t.move_to(i * 0.5 * RIGHT) for i, t in enumerate(seq)] - self.add(VGroup(*seq).move_to(ORIGIN + 2*UP)) - - -class Pointer(VMobject): -# pointer to sequence element - - def __init__(self, pointee, name): - VMobject.__init__(self) - arrow = Arrow(ORIGIN, DOWN).next_to(pointee, UP) - name_tex = Tex(name).next_to(arrow, UP) - self.add(arrow, name_tex) - - -class ProgramCounter(VMobject): -# pointer to current code line - - def __init__(self, line): - VMobject.__init__(self) - self.add(Arrow(ORIGIN, RIGHT).next_to(line, LEFT)) - - -class Base(Scene): - def construct(self, n, k): - - # initial situation - seq = [Tex("1")] + [Tex("?") for _ in range(n-2)] + [Tex("0")] - self.play(Create(Sequence(seq))) - - # source code binary search - code = Code(file_name="binary-search.py", language="Python", insert_line_no=False, style='monokai') - code.move_to(DOWN) - self.play(Write(code)) - line_lr, line_while, line_m, line_test, line_l, _, line_r = code[2] - - def test(x): + def check(x): return 1 if x <= k else 0 - def update_pc(pc, line): - npc = ProgramCounter(line) - self.play(ReplacementTransform(pc, npc)) - return npc + # initial situation + seq = Matrix([[1] + ["?" for _ in range(n-1)] + [0]], h_buff=1.0).elements.move_to(0.5*UP) + self.play(Create(seq)) + + # source code binary search + + # while(high - low > 1){ // line_while + # int mid = (low + high) / 2; // line_mid + # if(check(mid)) // line_check + # low = mid; // line_low + # else + # high = mid; // line_high + # } + code = Code(file_name="binary-search.cpp", language="c++", insert_line_no=False, style='monokai', tab_width=4, line_spacing=0.5).code + code.move_to(4*RIGHT + 2.5*DOWN) + while_line, mid_line, check_line, low_line, __, high_line, __ = code + + # check code + check_code = Code(code="check(x)", language="c++", insert_line_no=False, style='monokai', tab_width=4, line_spacing=0.5).code + check_background, check_code = check_code.move_to(2.5*UP).add_background_rectangle(opacity=1.0) + self.play(Create(check_background), Write(check_code), Write(code)) + + def pointer(name): + arrow = Arrow(start=ORIGIN, end=UP) + label = Tex(name).next_to(arrow, DOWN) + return VGroup(arrow, label).scale(0.7) # initialize borders - pc = ProgramCounter(line_lr) - self.play(Create(pc)) - l, r = 0, n-1 - lp = Pointer(seq[l], "l") - rp = Pointer(seq[r], "r") - self.play(Write(lp), Create(rp)) + low = 0 + high = n + low_pointer = pointer("low").next_to(seq[low], DOWN) + high_pointer = pointer("high").next_to(seq[high], DOWN) + self.play(Write(low_pointer), Create(high_pointer)) - while r - l > 1: - # calculate m - pc = update_pc(pc, line_m) - m = (l + r) // 2 - mp = Pointer(seq[m], "m") - self.play(Create(mp)) + mid_pointer = pointer("mid") - # test - pc = update_pc(pc, line_test) - old = seq.copy() - seq[m] = Tex(str(test(m))) - self.play(ReplacementTransform(Sequence(old), Sequence(seq))) + def indicate_start(line): + line.save_state() + self.play(line.animate.scale(1.3).set_color(YELLOW)) - if test(m): - # update left - pc = update_pc(pc, line_l) - l = m - op = lp - lp = Pointer(seq[m], "l") - self.play(Uncreate(mp), ReplacementTransform(op, lp)) + def indicate_end(line): + self.play(Restore(line)) + + def high_low_test(): + indicate_start(while_line) + brace = BraceText(VGroup(*seq[low:high]), "high - low = " + str(high - low), brace_direction=UP) + brace.label.scale(0.7) + self.play(FadeIn(brace)) + self.wait(1) + self.play(FadeOut(brace)) + indicate_end(while_line) + + while high_low_test() or high - low > 1: + + # calculate mid + indicate_start(mid_line) + mid = (low + high) // 2 + mid_pointer.next_to(seq[mid], DOWN) + self.play(Write(mid_pointer)) + indicate_end(mid_line) + + # check + indicate_start(check_line) + + seq[mid].add_background_rectangle(opacity=1.0) + path = Line(start=seq[mid].get_center(), end=check_background.get_center()) + rpath = Line(start=path.get_end(), end=path.get_start()) + laser = path.copy().set_length(0.3) + + self.bring_to_back(laser) + self.play(MoveAlongPath(laser, path)) + + color = GREEN if (ans := check(mid)) else RED + self.play(Indicate(check_code, color=color)) + + self.bring_to_back(laser) + self.play(MoveAlongPath(laser, rpath)) + self.remove(laser) + + # TODO: mark tested + range_seq = seq[low+1:mid+1] if ans else seq[mid:high] + self.play(*[Transform(s, Tex(ans).move_to(s)) for s in range_seq]) + + indicate_end(check_line) + + if check(mid): + # update low + indicate_start(low_line) + low = mid + low_pointer.generate_target().move_to(mid_pointer) + self.play(FadeOut(mid_pointer), MoveToTarget(low_pointer)) + indicate_end(low_line) else: - # update right - pc = update_pc(pc, line_r) - r = m - op = rp - rp = Pointer(seq[m], "r") - self.play(Uncreate(mp), ReplacementTransform(op, rp)) + # update high + indicate_start(high_line) + high = mid + high_pointer.generate_target().move_to(mid_pointer) + self.play(FadeOut(mid_pointer), MoveToTarget(high_pointer)) + indicate_end(high_line) self.wait(2) - -class Main(Base): - def construct(self): - Base.construct(self, 20, 6) diff --git a/binary-search/binary-search.cpp b/binary-search/binary-search.cpp new file mode 100644 index 0000000..140ad9f --- /dev/null +++ b/binary-search/binary-search.cpp @@ -0,0 +1,7 @@ +while(high - low > 1){ + int mid = (low + high) / 2; + if(check(mid)) + low = mid; + else + high = mid; +} diff --git a/binary-search/binary-search.py b/binary-search/binary-search.py deleted file mode 100644 index 937361e..0000000 --- a/binary-search/binary-search.py +++ /dev/null @@ -1,7 +0,0 @@ -l, r = 0, n-1 -while r - l > 1: - m = (l + r) / 2 - if test(m): - l = m - else: - r = m