from manimlib.imports import *

class ExamPaper(VGroup):
    def __init__(self, grade, **kwargs):
        exam_paper = SVGMobject("exam_paper")
        grade = TextMobject(grade).scale(1.3).set_color(RED).shift(UP*.2)

        VGroup.__init__(self, exam_paper, grade)

class Thumbnail(Scene):
    def construct(self):
        plane = NumberPlane().fade()
        coords = plane.get_coordinate_labels().fade()
        graph = FunctionGraph(lambda x : x / 2)
        eqn = TexMobject("2y = x").scale(4).shift(UP*2 + LEFT*3.5)
        title = VGroup(
            TextMobject("Persamaan").scale(2.5).center(),
            TextMobject("Linear").scale(2.5).center().shift(DOWN*1.5)
        ).shift(DOWN*1.25 + RIGHT*3.5).set_color_by_gradient(GREEN_A, GREEN)

        self.add(plane, coords, graph, eqn, title)

class Pendahuluan(Scene):
    def construct(self):
        text_pl = TextMobject("Persamaan Linear").scale(2)

        branches = [
            [
                "Matematik",
                "Geometri",
                "Kalkulus",
                "Algebra abstrak",
                "Sejarah matematik"
            ],
            [
                "Fizik",
                "Kejuruteraan",
                "Penyelidikan"
            ],
            [
                "Sains komputer",
                "Kejuruteraan komputer",
                "Statistik",
                "Analisis data"
            ]
        ]

        # Generate lists
        for i in range(len(branches)):
            for j in range(len(branches[i])):
                if j == 0:
                    if i == 0:
                        text = branches[i][j]
                        branches[i][j] = TextMobject(text)
                        continue
                    text = branches[i][j]
                    branches[i][j] = TextMobject(text).next_to(branches[i-1][0], RIGHT, buff=1.5)
                else:
                    text = branches[i][j]
                    branches[i][j] = TextMobject(text).next_to(branches[i][j-1], UP).scale(.7)
            branches[i].append(TexMobject("\\vdots").next_to(branches[i][len(branches[i])-1], UP, buff=.5))
        # Program braces
        for i in range(len(branches)):
            branches[i][0].move_to(branches[i][1])
            if branches[i][0].get_width() > branches[i][1].get_width():
                branches[i].insert(1, Brace(branches[i][0]))
            else:
                branches[i].insert(1, Brace(branches[i][1]))
            branches[i][0].next_to(branches[i][1], DOWN)
        branches.append([TexMobject("\\cdots").next_to(branches[len(branches)-1][0], RIGHT, buff=1.5)])

        vbranches = VGroup(*[
            sub_branch
            for branch in branches
            for sub_branch in branch
        ]).center().shift(UP*1.25)
        big_brace = Brace(vbranches)

        self.play(Write(text_pl))
        self.wait()
        self.play(text_pl.shift, DOWN*2.25)
        self.play(Write(vbranches), GrowFromCenter(big_brace))
        self.wait()

        # Terdapat ramai pelajar...
        self.play(Uncreate(vbranches), FadeOut(big_brace))
        exam_papers = VGroup(*[
            ExamPaper((["E","C+","D","C"])[i]).shift(RIGHT*2.5*i)
            for i in range(4)
        ]).center()
        exam_papers.shift(UP)
        self.play(AnimationGroup(
            *[FadeInFromDown(exam_paper) for exam_paper in exam_papers],
            lag_ratio=0.2
        ))
        self.wait()

        # Oleh itu...
        self.play(FocusOn(text_pl))

        self.wait(2)

class Persamaan(Scene):
    def construct(self):
        title_transition = TexMobject("\\text{Persamaan}", "\\rightarrow", "\\text{Persamaan Linear}").scale(1.5)
        title = TextMobject("Persamaan").scale(1.5).to_edge(UP)

        # Pada awalnya...
        self.play(Write(title_transition[0]))
        self.wait()
        self.play(FadeInFromDown(title_transition[1]))
        self.play(Write(title_transition[2]))
        self.wait()

        # Perkara asas...
        # Contohnya...
        example = TexMobject("3+5", "=", "2\\times4").scale(1.5)
        example[0].set_color(GREEN)
        example[2].set_color(BLUE)
        self.play(
            title_transition[0].replace, title,
            FadeOut(title_transition[1:3])
        )
        self.play(Write(example))
        self.wait()

        # Namun...
        left_brace = Brace(example[0])
        lb_text = left_brace.get_text("8").scale(1.5)
        right_brace = Brace(example[2])
        rb_text = right_brace.get_text("8").scale(1.5)
        self.play(AnimationGroup(
            GrowFromCenter(left_brace),
            GrowFromCenter(right_brace),
            Write(lb_text),
            Write(rb_text),
            lag_ratio=0.3
        ))
        self.wait()

        # Dalam beberapa situasi...
        example_manipulation = TexMobject("3+5", "+5", "-3", "=", "2\\times4", "+5", "-3").scale(1.5)
        example_manipulation[0].set_color(GREEN)
        example_manipulation[4].set_color(BLUE)
        example_manipulation.get_slice(1, 2, 5, 6).set_color(ORANGE)
        self.play(
            FadeOutAndShiftDown(left_brace),
            FadeOutAndShiftDown(right_brace),
            FadeOutAndShiftDown(lb_text),
            FadeOutAndShiftDown(rb_text),
            ReplacementTransform(example, example_manipulation.get_slice(0, 3, 4)),
        )
        self.play(FadeInFromDown(example_manipulation[1]))
        self.play(FadeInFromDown(example_manipulation[2]))
        self.wait()
        self.play(ReplacementTransform(example_manipulation[1:3].copy(), example_manipulation[5:7], path_arc=-np.pi/2))
        self.play(
            example_manipulation.get_slice(1, 2).set_color, GREEN,
            example_manipulation.get_slice(5, 6).set_color, BLUE
        )
        self.remove(example)
        self.add(example_manipulation)
        self.wait()

        # Setiap sebutan ... boleh diubah susunannya
        self.remove(example_manipulation)
        example_manipulation = TexMobject("3", "+", "5", "+", "5", "-", "3", "=", "2\\times4", "+5", "-3").scale(1.5)
        self.add(example_manipulation)
        example_manipulation[0:7].set_color(GREEN)
        example_manipulation[8:11].set_color(BLUE)
        self.play(AnimationGroup(
            Indicate(example_manipulation[1]),
            Indicate(example_manipulation[3]),
            Indicate(example_manipulation[5]),
            lag_ratio=0.3
        ))
        self.wait()
        self.play(Swap(example_manipulation[3:5], example_manipulation[5:7]))
        self.play(Swap(example_manipulation[1:3], example_manipulation[3:5]))
        self.play(Swap(example_manipulation[1:3], example_manipulation[5:7]))
        self.wait()

        # Ingat...
        surround_operation = SurroundingCircle(example_manipulation[5], color=YELLOW)
        surround_number = SurroundingRectangle(example_manipulation[6], color=YELLOW)
        arrow = CurvedArrow(surround_operation.get_top(), surround_number.get_top(), color=YELLOW, angle=-np.pi/2)
        self.play(ShowCreation(surround_operation))
        self.wait()
        self.play(ShowCreation(arrow), ShowCreation(surround_number))
        self.wait()

        # ...dan...
        self.play(example_manipulation[0].shift, UP)
        self.wait()
        hidden_plus = TexMobject("+").scale(1.5).set_color(YELLOW).next_to(example_manipulation[0], LEFT)
        self.play(Write(hidden_plus))
        self.play(
            hidden_plus.shift, DOWN,
            example_manipulation[0].shift, DOWN
        )
        self.wait()
        
        # Fade out everything & fade in original equation
        example = TexMobject("3+", "5", "=", "2\\times4").scale(1.5)
        example[0:2].set_color(GREEN)
        example[3].set_color(BLUE)
        self.play(
            *[
                FadeOut(mobject)
                for mobject in [
                    example_manipulation,
                    surround_operation,
                    surround_number,
                    arrow,
                    hidden_plus
                ]
            ],
            FadeIn(example)
        )
        self.wait()

        # ...menyertakannya di tepi...
        example_wrong = TexMobject("3+", "5", "\\times", "3", "=", "2\\times4", "\\times3").scale(1.5)
        example_wrong[0:2].set_color(GREEN)
        example_wrong[5].set_color(BLUE)
        example_wrong.get_slice(2, 3, 6).set_color(ORANGE)
        self.play(ReplacementTransform(
            example.get_slice(0, 1, 2, 3), example_wrong.get_slice(0, 1, 4, 5)
        ))
        self.play(Write(example_wrong.get_slice(2, 3, 6)))
        self.wait()
        cross = Cross(example_wrong)
        self.play(ShowCreation(cross))
        self.wait()
        surround_multiplication = SurroundingRectangle(example_wrong[1:4], color=YELLOW)
        self.play(FadeOut(cross))
        self.play(ShowCreation(surround_multiplication))
        self.wait()
        self.play(Uncreate(surround_multiplication))
        self.wait()

        # Oleh itu...
        example_right = TexMobject("3", "(", "3+", "5", ")", "=", "2\\times4", "\\times3").scale(1.5)
        example_right[2:4].set_color(GREEN)
        example_right[6].set_color(BLUE)
        example_right.get_slice(0, 1, 4, 7).set_color(ORANGE)
        self.play(
            ReplacementTransform(
                example_wrong.get_slice(0, 1, 3, 4, 5, 6),
                example_right.get_slice(2, 3, 0, 5, 6, 7)
            ),
            FadeOut(example_wrong[2])
        )
        self.play(*[Write(example_right[i]) for i in [1, 4]])
        self.play(
            example_right.get_slice(0, 1, 4).set_color, GREEN,
            example_right[7].set_color, BLUE
        )
        self.wait()

        self.wait(2)

class Pemindahan(Scene):
    def construct(self):
        title = TextMobject("Pemindahan").scale(1.5).to_edge(UP)
        abc = [
            TexMobject("a", "+", "b", "=", "c").scale(2),
            TexMobject("a", "=", "c", "-", "b").scale(2),
        ]
        plus_b = TexMobject("+", "b").scale(2).shift(UP*1.5)
        minus_b = TexMobject("-", "b").scale(2).shift(UP*1.5)

        ori_abc = abc[0].copy()
        ori_abc_sbs = TexMobject("a", "+", "b", "-", "b", "=", "c", "-", "b").scale(2)

        # Contohnya...
        self.play(Write(title))
        self.wait()
        self.play(Write(abc[0]))
        self.wait()
        self.play(ori_abc.shift, DOWN*2, ori_abc.fade)
        self.play(ReplacementTransform(
            abc[0][1:3], plus_b
        ))
        self.play(ReplacementTransform(plus_b, minus_b))
        self.play(
            ReplacementTransform(
                abc[0].get_slice(0, 3, 4),
                abc[1].get_slice(0, 1, 2)
            ),
            ReplacementTransform(minus_b, abc[1][3:5], path_arc=-np.pi/2)
        )
        self.remove(abc[0], plus_b, minus_b)
        self.wait()
        self.play(
            FadeOut(abc[1]),
            ori_abc.center,
            ori_abc.fade, -1
        )
        self.play(ReplacementTransform(
            ori_abc.get_slice(0, 1, 2, 3, 4),
            ori_abc_sbs.get_slice(0, 1, 2, 5, 6)
        ))
        self.play(Write(ori_abc_sbs.get_slice(3, 4, 7, 8)))
        self.wait()
        self.play(Indicate(ori_abc_sbs.get_slice(1, 2)))
        self.wait()
        self.play(Indicate(ori_abc_sbs.get_slice(3, 4)))
        self.wait()
        cross = Cross(ori_abc_sbs.get_slice(1, 2, 3, 4))
        self.play(ShowCreation(cross))
        self.wait()
        self.play(AnimationGroup(
            *[FadeOut(v) for v in [ori_abc_sbs.get_slice(1, 2, 3, 4), cross]],
        ))
        self.play(ReplacementTransform(
            ori_abc_sbs.get_slice(0, 5, 6, 7, 8), abc[1]
        ))

        self.wait(2)

class TakBolehPindah(Scene):
    def construct(self):
        title = TextMobject("Pemindahan").scale(1.5).to_edge(UP)
        self.add(title)
        self.wait()

        # Suatu sebutan yang berada di dalam kurungan...
        eqn = TexMobject("2(x", "+", "y", ")=4y").scale(2)
        eqn_wrong = TexMobject("2(x", ")=4y", "-", "y").scale(2)
        self.play(Write(eqn))
        self.wait()
        self.play(
            ReplacementTransform(eqn.get_slice(0, 3), eqn_wrong.get_slice(0, 1)),
            ReplacementTransform(eqn.get_slice(1, 2), eqn_wrong.get_slice(2, 3), path_arc=-np.pi/2),
        )
        cross = Cross(eqn_wrong)
        self.play(ShowCreation(cross))
        eqn = TexMobject("2(x", "+", "y", ")=4y").scale(2)
        self.wait()

        # Terdapat beberapa cara...
        self.play(FadeOut(cross))
        self.play(
            ReplacementTransform(eqn_wrong.get_slice(0, 1), eqn.get_slice(0, 3)),
            ReplacementTransform(eqn_wrong.get_slice(2, 3), eqn.get_slice(1, 2), path_arc=np.pi/2),
        )
        self.wait()

        # Setup two ways
        method_1 = VGroup(
            TexMobject(*list("2(x+y)=4y")),
            TexMobject(*list("2x+2y=4y")),
            TexMobject(*list("2x=2y")),
            TexMobject(*list("x=y")),
        )
        self.arrange_steps(method_1)
        method_1.shift(LEFT*3)

        # Cara pertama...
        self.play(
            eqn.replace, method_1[0]
        )
        self.remove(eqn)
        self.add(method_1[0])
        self.wait()
        # 0 -> 1
        self.play(ReplacementTransform(
            method_1[0].get_slice(2,3,4, 6,7,8).copy(),
            method_1[1].get_slice(1,2,4, 5,6,7),
        ))
        self.play(
            ReplacementTransform(method_1[0][0].copy(), method_1[1][0]),
            ReplacementTransform(method_1[0][0].copy(), method_1[1][3]),
        )
        self.wait()
        # 1 -> 2
        before_transfer = method_1[1].copy()
        self.play(before_transfer.shift, DOWN*(method_1[1].get_center()[1] - method_1[2].get_center()[1]))
        after_transfer = TexMobject(*list("2x=4y-2y")).move_to(before_transfer)
        self.wait()
        self.play(
            ReplacementTransform(before_transfer.get_slice(0,1,5,6,7), after_transfer.get_slice(0,1,2,3,4)),
            ReplacementTransform(before_transfer.get_slice(2,3,4), after_transfer.get_slice(5,6,7), path_arc=-np.pi/2),
        )
        self.wait(.5)
        self.play(
            ReplacementTransform(after_transfer.get_slice(0,1,2), method_1[2].get_slice(0,1,2)),
            ReplacementTransform(after_transfer.get_slice(3,4,5,6,7), method_1[2].get_slice(3,4)),
        )
        self.wait()
        # 2 -> 3
        cross_l = Cross(method_1[2][0])
        cross_r = Cross(method_1[2][3])
        self.play(
            ShowCreation(cross_l),
            ShowCreation(cross_r),
        )
        self.play(Write(method_1[3]))
        self.wait()

        # Cara kedua...
        method_2 = VGroup(
            TexMobject(*list("2(x+y)=4y")),
            TexMobject(*list("x+y={4y"), "\\over", "2", "}"),
            TexMobject(*list("x+y=2y")),
            TexMobject(*list("x=y")),
        )
        self.arrange_steps(method_2)
        method_2.shift(RIGHT*3)

        # 0
        self.play(ReplacementTransform(method_1[0].copy(), method_2[0]))
        self.wait()
        # 0 -> 1
        shifted = method_2[0].copy()
        self.play(shifted.shift, DOWN*(method_2[0].get_center()[1] - method_2[1].get_center()[1]))
        self.play(
            FadeOut(shifted.get_slice(1,5)),
            ReplacementTransform(shifted.get_slice(2,3,4,6,7,8), method_2[1].get_slice(0,1,2,3,5,6)),
            ReplacementTransform(shifted.get_slice(0), method_2[1].get_slice(8)),
            Write(method_2[1].get_slice(7))
        )
        self.wait()
        # 1 -> 2
        self.play(ReplacementTransform(
            method_2[1].get_slice(0,1,2,3).copy(),
            method_2[2].get_slice(0,1,2,3),
        ))
        self.play(Write(method_2[2].get_slice(4,5)))
        self.wait()
        # 2 -> 3
        shifted = method_2[2].copy()
        self.play(shifted.shift, DOWN*(method_2[2].get_center()[1] - method_2[3].get_center()[1]))
        shifted_mod = TexMobject(*list("x=2y-y")).move_to(shifted)
        self.wait(.5)
        self.play(
            ReplacementTransform(
                shifted.get_slice(0,3,4,5),
                shifted_mod.get_slice(0,1,2,3),
            ),
            ReplacementTransform(shifted.get_slice(1,2), shifted_mod.get_slice(4,5), path_arc=-np.pi/2)
        )
        self.play(
            ReplacementTransform(shifted_mod.get_slice(0,1), method_2[3].get_slice(0,1)),
            ReplacementTransform(shifted_mod.get_slice(2,3,4,5), method_2[3].get_slice(2)),
        )
        self.wait()

        # Kita terhad kepada...
        fade_group = VGroup(*[v for v in [title, method_1, method_2, cross_l, cross_r]])
        self.play(fade_group.fade)
        text_operations = ["+", "-", "\\times", "\\text{÷}"]
        operations = VGroup(*[
            TexMobject(text_operations[i*2 + j]).shift(RIGHT*3*j + DOWN*3*i).scale(5)
            for i in range(2)
            for j in range(2)
        ]).center()
        operations.set_color_by_gradient(BLUE, PURPLE)
        self.play(Write(operations))

        self.wait(2)
    
    def arrange_steps(self, group):
        for i in range(len(group)):
            if i == 0:
                continue
            group[i].next_to(group[i-1], DOWN)
        for obj in group:
            obj.next_to(obj.get_center(), RIGHT)
        group.center()

class PersamaanLinearPendahuluan(Scene):
    def construct(self):
        title = TextMobject("Persamaan Linear").scale(1.5).set_color_by_gradient(TEAL, GREEN).to_edge(UP)
        definition = FullWidthText("Persamaan antara ", "dua pemboleh ubah", " yang memberikan ", "garis lurus", " apabila diplotkan pada ", "graf", ".")
        definition[1].set_color(ORANGE)
        definition[3].set_color(RED)
        definition[5].set_color(PINK)
        definition.next_to(title, DOWN, buff=.5)

        self.add(title)
        self.wait()
        self.play(Write(definition))
        self.wait()
        self.play(AnimationGroup(
            Indicate(definition[1]),
            Indicate(definition[3]),
            Indicate(definition[5]),
            lag_ratio=1.2
        ))
        self.wait()

        # Apa yang kita perlu tahu...
        characteristics_statement = TextMobject("{\\large Tiada pemboleh ubah...}").set_color(BLUE)
        characteristics = VGroup(
            characteristics_statement,
            BulletedList(
                "mempunyai kuasa lebih daripada 1",
                "digunakan sebagai penyebut pecahan",
            ).next_to(characteristics_statement, DOWN, buff=.7)
        ).center().scale(.7).shift(DOWN*.5)
        self.play(Write(characteristics))
        self.wait()

        # Berikut bukan persamaan linear...
        self.play(characteristics.shift, LEFT*3)
        not_lin_eqns = VGroup(*[
            TexMobject(*v).shift(DOWN*.8*i)
            for i, v in enumerate([
                ["\\log_a b = 5c"],
                ["3 - m^3 = 6 + n"],
                ["k = \\sin 4"],
                list("x(4-x)=7y"),
                list("y(2-x)=3")
            ])
        ]).center().shift(RIGHT*3.5 + DOWN*.5)
        self.play(GrowFromCenter(not_lin_eqns))
        self.wait()

        # Walau bagaimanapun...
        sur_rect = SurroundingRectangle(not_lin_eqns.get_slice(3,4), color=YELLOW)
        self.play(ShowCreation(sur_rect))
        self.wait()
        self.play(AnimationGroup(
            *[
                Indicate(v)
                for v in characteristics[1]
            ], lag_ratio=.5
        ))
        self.wait()

        # ...permudahan...
        simplified = TexMobject(*list("4x-x^2=7y")).move_to(not_lin_eqns[3])
        self.play(FadeOut(sur_rect))
        self.play(
            FadeOut(not_lin_eqns[3].get_slice(1,5)),
            ReplacementTransform(
                not_lin_eqns[3].get_slice(2,3,4,6,7,8),
                simplified.get_slice(0,2,3,6,7,8),
            ),
            ReplacementTransform(not_lin_eqns[3][0].copy(), simplified[1], path_arc=-np.pi/2),
            ReplacementTransform(not_lin_eqns[3][0], simplified[5], path_arc=-np.pi/2),
        )
        self.wait()

        # ...pemindahan...
        transferred = TexMobject(*list("2-x={3"), "\\over", *list("y}")).move_to(not_lin_eqns[4]).shift(DOWN*MED_SMALL_BUFF)
        self.play(
            FadeOut(not_lin_eqns[4].get_slice(1,5)),
            ReplacementTransform(
                not_lin_eqns[4].get_slice(2,3,4,6,7),
                transferred.get_slice(0,1,2,3,5)
            ),
            ReplacementTransform(not_lin_eqns[4][0], transferred[7], path_arc=np.pi/2),
            Write(transferred[6])
        )
        self.wait()

        # ...sudah terang...
        circle_a = SurroundingCircle(simplified[5])
        circle_b = SurroundingCircle(transferred[7])
        self.play(AnimationGroup(
            ShowCreation(circle_a),
            ShowCreation(circle_b),
            lag_ratio=.3
        ))

        self.wait(2)

class PersamaanLinearDalamSatuPembolehUbah(Scene):
    def construct(self):
        colors = [ORANGE, GOLD, LIGHT_PINK]
        questions = VGroup(*[
            TexMobject(*v).shift(DOWN*i).set_color(colors[i])
            for i, v in enumerate([
                list("x+5=7"),
                list("4x=2+3x"),
                list("x-6+2=0"),
            ])
        ]).center().scale(1.5)

        self.play(Write(questions))
        self.wait()

        # TODO: Show timer

        # Soalan pertama
        self.play(
            questions[0].center,
            FadeOut(questions[1:3])
        )
        self.wait()
        next_step_a = self.create_equation("x=7-5", colors[0])
        self.play(
            ReplacementTransform(questions[0].get_slice(0,3,4), next_step_a.get_slice(0,1,2)),
            ReplacementTransform(questions[0].get_slice(1,2), next_step_a.get_slice(3,4), path_arc=-np.pi/2)
        )
        self.wait()
        next_step_b = self.create_equation("x=2", colors[0])
        self.play(
            ReplacementTransform(next_step_a.get_slice(0,1), next_step_b.get_slice(0,1)),
            ReplacementTransform(next_step_a.get_slice(2,3,4), next_step_b.get_slice(2))
        )
        self.wait()

        # Soalan kedua
        self.play(
            FadeOut(next_step_b),
            FadeInFromDown(questions[1].center()),
        )
        self.wait()
        next_step_a = self.create_equation("4x-3x=2", colors[1])
        self.play(
            ReplacementTransform(questions[1].get_slice(0,1,2,3), next_step_a.get_slice(0,1,5,6)),
            ReplacementTransform(questions[1].get_slice(4,5,6), next_step_a.get_slice(2,3,4), path_arc=np.pi/2)
        )
        self.wait()
        next_step_b = self.create_equation("1x=2", colors[1])
        self.play(
            ReplacementTransform(next_step_a.get_slice(5,6), next_step_b.get_slice(2,3)),
            ReplacementTransform(next_step_a.get_slice(0,1,2,3,4), next_step_b.get_slice(0,1))
        )
        self.wait()
        next_step_a = self.create_equation("x=2", colors[1])
        self.play(
            FadeOut(next_step_b[0]),
            ReplacementTransform(next_step_b.get_slice(1,2,3), next_step_a.get_slice(0,1,2)),
        )
        self.wait()

        # Soalan ketiga
        self.play(
            FadeOut(next_step_a),
            FadeInFromDown(questions[2].center()),
        )
        self.wait()
        next_step_a = self.create_equation("x-4=0", colors[2])
        q_copy = questions[2].copy()
        self.play(q_copy.shift, UP*2, q_copy.fade)
        self.play(
            ReplacementTransform(questions[2].get_slice(0,5,6), next_step_a.get_slice(0,3,4)),
            ReplacementTransform(questions[2].get_slice(1,2,3,4), next_step_a.get_slice(1,2))
        )
        self.wait()
        next_step_b = self.create_equation("x=4", colors[2])
        self.play(
            FadeOut(next_step_a[4]),
            ReplacementTransform(next_step_a.get_slice(0,3), next_step_b.get_slice(0,1)),
            ReplacementTransform(next_step_a.get_slice(1,2), next_step_b.get_slice(2), path_arc=-np.pi/2)
        )
        self.wait()

        # ...ataupun...
        self.play(
            FadeOut(next_step_b),
            q_copy.center,
            q_copy.fade, -1
        )
        self.wait()
        expression = self.create_equation("-6+2", colors[2]).shift(UP*1.5)
        expression_conv = self.create_equation("+6-2", colors[2]).shift(UP*1.5)
        next_step_a = self.create_equation("x=6-2", colors[2])
        self.play(
            ReplacementTransform(q_copy.get_slice(1,2,3,4), expression),
        )
        self.wait()
        self.play(
            ReplacementTransform(expression, expression_conv)
        )
        self.wait()
        self.play(
            FadeOut(q_copy[6]),
            FadeOut(expression_conv[0]),
            ReplacementTransform(q_copy.get_slice(0,5), next_step_a.get_slice(0,1)),
            ReplacementTransform(expression_conv.get_slice(1,2,3), next_step_a.get_slice(2,3,4), path_arc=-np.pi/2)
        )
        self.wait()
        next_step_b = self.create_equation("x=4", colors[2])
        self.play(
            ReplacementTransform(next_step_a.get_slice(0,1), next_step_b.get_slice(0,1)),
            ReplacementTransform(next_step_a.get_slice(2,3,4), next_step_b.get_slice(2))
        )
        self.wait()
        self.play(FadeOut(next_step_b))
        self.show_questions()

        self.wait(2)
    
    def create_equation(self, eqn, color=WHITE):
        mobject = TexMobject(*list(eqn))
        mobject.scale(1.5)
        mobject.set_color(color)
        return mobject
    
    def show_questions(self):
        arr = [
            "2x + 3 = 7",
            "3x + 2 = -7",
            "2 = 6 - 2x",
            "4 + 2x - 12 = 0",
            "2x + 2 = -2",
            "5x + 2 = 3x - 4",
            "2x + 3 = -(6 + x)",
            "735 + 23x = -70",
            "56 + 91x = 5607",
            "10x + 23 = 2x - 33",
        ]
        question = TexTitle("\\text{Cari nilai }x\\text{.}")
        # for i, v in enumerate(arr):
        #     print([v, int(i/3), i%3])
        vg_arr = VGroup(*[
            TexMobject(v).shift(DOWN*1*(int(i/2)) + RIGHT*6*(i%2))
            for i, v in enumerate(arr)
        ]).center()
        see_in_desc = TextMobject("(Jawapan dalam description)").scale(.8).set_color(PURPLE).to_edge(DOWN)

        self.play(
            Write(question),
            Write(vg_arr)
        )
        self.wait(2)
        self.play(FadeIn(see_in_desc))

class PersamaanLinearDalamDuaPembolehUbah(Scene):
    def construct(self):
        # Namun...
        title = TextMobject("Dua pemboleh ubah...").scale(1.5).set_color_by_gradient(PINK, RED).shift(UP*1.5)
        x_and_y = TexMobject(*list("x,y")).scale(3)
        VGroup(title, x_and_y).center()

        self.play(Write(VGroup(title, x_and_y)))
        self.wait()

        # Contohnya...
        examples = VGroup(*[
            TexMobject(*v).scale(1.5).shift(DOWN*1.25*i)
            for i, v in enumerate([
                list("x+y=5"),
                list("0+5=5"),
                list("2+3=5"),
                ["2.5","+","2.5","=","5"],
                ["-5","+","10","=","5"],
            ])
        ]).center()

        self.play(
            FadeOut(title),
            FadeOut(x_and_y[1]),
            ReplacementTransform(x_and_y.get_slice(0,2), examples[0].get_slice(0,2))
        )
        self.play(Write(examples[0].get_slice(1,3,4)))
        self.wait()

        self.play(ReplacementTransform(examples[0].copy(), examples[1], run_time=.8))
        self.wait()

        self.play(ReplacementTransform(examples[1].copy(), examples[2], run_time=.8))
        self.wait()

        self.play(ReplacementTransform(examples[2].copy(), examples[3], run_time=.8))
        self.wait()

        self.play(ReplacementTransform(examples[3].copy(), examples[4], run_time=.8))
        self.wait()

        # Sebaliknya...
        eqn = examples[0]
        plane = NumberPlane(
            x_min=-FRAME_X_RADIUS*10,
            x_max=FRAME_X_RADIUS*10,
            y_min=-FRAME_Y_RADIUS*10,
            y_max=FRAME_Y_RADIUS*10,
            x_line_frequency=2,
            y_line_frequency=2,
        ).fade().shift(DOWN*2)
        plane.scale(1/2)
        plane_scale = ValueTracker(1/2)
        plane.add_coordinates(
            x_vals=[i*2 for i in range(-int(FRAME_X_RADIUS)*2,int(FRAME_X_RADIUS)*2)],
            y_vals=[i*2 for i in range(-int(FRAME_Y_RADIUS)*2,int(FRAME_Y_RADIUS)*2)]
        )
        def get_coord(x, y):
            return (x * plane_scale.get_value(), y * plane_scale.get_value(), 0) + plane.get_center()

        self.add(plane, eqn)
        self.play(
            ShowCreation(plane, run_time=3, lag_ratio=0.1),
            eqn.to_corner, UL,
            AnimationGroup(
                *[FadeOutAndShift(v, RIGHT) for v in examples[1:5]],
                lag_ratio=.1
            )
        )
        self.wait()

        # Dot moving along path
        dot = Dot(color=YELLOW).move_to(get_coord(-4,1))
        coord_text = self.get_coord_text(dot, plane, plane_scale, YELLOW).scale(.8)
        coord_text.add_updater(lambda o: o.next_to(dot, RIGHT))

        self.add(coord_text)
        self.play(
            GrowFromCenter(dot),
            Write(coord_text)
        )
        self.wait()
        self.play(
            dot.move_to, get_coord(-5,7),
            run_time=2,
        )
        self.wait(.5)
        self.play(
            dot.move_to, get_coord(7,6),
            run_time=2,
        )
        self.wait(.5)
        self.play(
            dot.move_to, get_coord(0,5),
            run_time=2,
        )
        self.wait()

        # ...apabila digantikan...
        x_coord = coord_text[2].copy()
        y_coord = coord_text[3].copy()
        substituted = TexMobject("0.0","+","5.0","=","5").scale(1.5).to_corner(UL)
        substituted.get_slice(0,2).set_color(YELLOW)

        self.remove(coord_text[2], coord_text[3])
        self.play(
            FadeOut(eqn.get_slice(0,2)),
            ReplacementTransform(eqn.get_slice(1,3,4), substituted.get_slice(1,3,4)),
            ReplacementTransform(x_coord, substituted[0]),
            ReplacementTransform(y_coord, substituted[2]),
        )
        self.wait()
        # True equation
        self.play(Indicate(substituted, color=LIGHT_PINK))
        self.wait()
        eqn = TexMobject(*list("x+y=5")).scale(1.5).to_corner(UL)
        self.play(
            FadeIn(eqn.get_slice(0,2)),
            ReplacementTransform(substituted.get_slice(1,3,4), eqn.get_slice(1,3,4)),
            ReplacementTransform(substituted[0], coord_text[2]),
            ReplacementTransform(substituted[2], coord_text[3]),
        )
        self.wait()

        # Kita hanya perlu tentukan nilai suatu pemboleh ubah, contohnya x = 1...
        plot_example_equations = VGroup(
            TexMobject(*list("x+y=5")).next_to((0,0,0)),
            TexMobject(*list("1+y=5")).next_to((0,0,0)),
            TexMobject(*list("x=1")).next_to((0,-.5,0)),
            TexMobject(*list("y=4")).next_to((0,-1,0)),
        ).center().shift(RIGHT*4.5 + DOWN*.5)
        bg_rect = Rectangle(
            width=3,
            height=2,
            stroke_color=WHITE,
            fill_color=BLACK,
            fill_opacity=.5
        ).move_to(plot_example_equations)
        self.play(
            FadeOut(coord_text),
            FadeOut(dot),
        )
        self.add(bg_rect, plot_example_equations[2])
        self.play(FadeIn(bg_rect), Write(plot_example_equations[2]))
        self.wait()

        # Maksudnya...
        line_xeq1 = Line(DOWN*FRAME_Y_RADIUS, UP*FRAME_X_RADIUS, color=GREEN).shift(RIGHT*.5)
        line_xeq1.fade()
        dot = Dot(color=GREEN).move_to(get_coord(1,-1))
        coord_text = TexMobject(*list("(1,?)"))
        coord_text[3].set_color(RED)
        coord_text.add_updater(lambda v: v.next_to(dot, RIGHT))
        self.add(coord_text)
        self.play(
            ShowCreation(line_xeq1),
            GrowFromCenter(dot),
            Write(coord_text),
        )
        self.play(
            dot.move_to, get_coord(1,9), run_time=3
        )
        self.wait()

        # Untuk mencari koordinat y pula...
        self.play(ReplacementTransform(
            eqn.copy(), plot_example_equations[0]
        ))
        self.play(
            FadeOut(plot_example_equations[0][0]),
            ReplacementTransform(plot_example_equations[0][1:5], plot_example_equations[1][1:5]),
            ReplacementTransform(plot_example_equations[2][2].copy(), plot_example_equations[1][0]),
        )
        self.wait()
        self.play(Indicate(plot_example_equations[1][0]))
        self.wait()

        # Kemudian...
        self.play(CircleIndicate(plot_example_equations[1][2]))
        self.wait()
        self.play(Write(plot_example_equations[3]))
        self.play(
            FadeOut(line_xeq1),
            dot.move_to, get_coord(1,4),
        )
        coord_text_full = TexMobject(*list("(1,4)")).next_to(dot)
        self.play(
            FadeOut(coord_text[3]),
            ReplacementTransform(coord_text.get_slice(0,1,2,4), coord_text_full.get_slice(0,1,2,4)),
            ReplacementTransform(plot_example_equations[3][2].copy(), coord_text_full[3]),
        )
        self.wait()

        # Lakukan perkara yang sama...
        dots = VGroup(*[
            Dot(color=GREEN).move_to(get_coord(x,y))
            for (x,y) in [
                (-1,6),
                (2,3),
                (0.5,4.5),
            ]
        ])
        coord_texts = VGroup(*[
            TexMobject("(%s,%s)" % (x,y)).next_to(dots[i], LEFT)
            for i, (x,y) in enumerate([
                (-1,6),
                (2,3),
                (0.5,4.5),
            ])
        ])
        for i in range(3):
            self.play(
                GrowFromCenter(dots[i]),
                Write(coord_texts[i])
            )
            self.wait()
        
        # Jika kita lakukannya berterusan...
        rnds = [random.uniform(-6.0, 8.0) for i in range(8)]
        more_dots = VGroup(*[
            Dot(color=GREEN).move_to(get_coord(x,5-x))
            for x in rnds
        ])
        self.play(*[
            FadeOut(v)
            for v in [coord_text_full, coord_texts, bg_rect, plot_example_equations[1:4]]
        ])
        self.play(AnimationGroup(
            *[
                GrowFromCenter(v)
                for v in more_dots
            ],
            lag_ratio=.2
        ))
        self.wait()
        graph = FunctionGraph(lambda x : .5-x)
        self.play(
            FadeOut(dot),
            FadeOut(dots),
            FadeOut(more_dots),
            ShowCreation(graph)
        )
        self.wait()

        # Kita dapat simpulkan...
        dot = Dot(color=YELLOW).move_to(get_coord(-5,10))
        coord_text = self.get_coord_text(dot, plane, plane_scale, YELLOW).scale(.8)
        coord_text.add_updater(lambda v: v.next_to(dot, RIGHT))

        self.add(coord_text)
        self.play(
            GrowFromCenter(dot),
            Write(coord_text)
        )
        self.play(
            dot.move_to, get_coord(7,-2),
            run_time=2.5
        )
        self.wait()
        
        self.remove(plane, graph, dot, coord_text)
        self.play(
            VGroup(
                plane,
                graph,
            ).scale_about_point, 2/3, (0,0,0),
            plane_scale.set_value, plane_scale.get_value() * (2/3),
            dot.move_to, dot.get_center() * (2/3),
            coord_text.fade, 0,
        )
        self.play(
            dot.move_to, get_coord(10,-5),
            run_time=2
        )
        self.wait()

        x_coord = coord_text[2].copy()
        y_coord = coord_text[3].copy()
        substituted = TexMobject("10.0","+", "(","-5.0", ")","=","5").scale(1.5).to_corner(UL)
        substituted.get_slice(0,3).set_color(YELLOW)

        self.remove(coord_text[2], coord_text[3])
        self.play(
            FadeOut(eqn.get_slice(0,2)),
            ReplacementTransform(eqn.get_slice(1,3,4), substituted.get_slice(1,5,6)),
            ReplacementTransform(x_coord, substituted[0]),
            ReplacementTransform(y_coord, substituted[3]),
        )
        self.play(Write(substituted.get_slice(2,4)))
        self.wait()
        # True equation
        self.play(Indicate(substituted), color=LIGHT_PINK)

        self.wait(2)
    
    def get_coord_text(self, dot, plane, plane_scale, color):
        x_label = TexMobject("x = ")
        y_label = TexMobject("y = ").shift(DOWN*.5)

        x_text = DecimalNumber(dot.get_center()[0], num_decimal_places=1).next_to(x_label, aligned_edge=x_label.get_bottom())
        x_text.add_updater(lambda v: v.set_value(((dot.get_center() - plane.get_center()) / plane_scale.get_value())[0]))
    
        y_text = DecimalNumber(dot.get_center()[1], num_decimal_places=1).next_to(y_label, aligned_edge=x_label.get_bottom())
        y_text.add_updater(lambda v: v.set_value(((dot.get_center() - plane.get_center()) / plane_scale.get_value())[1]))

        vg = VGroup(x_label, y_label, x_text, y_text).set_color(color)

        return vg

class MaksudDefinisi(Scene):
    def construct(self):
        title = TextMobject("Persamaan Linear").scale(1.5).set_color_by_gradient(TEAL, GREEN).to_edge(UP)
        definition = FullWidthText("Persamaan antara ", "dua pemboleh ubah", " yang memberikan ", "garis lurus", " apabila diplotkan pada ", "graf", ".")
        definition[1].set_color(ORANGE)
        definition[3].set_color(RED)
        definition[5].set_color(PINK)
        definition.next_to(title, DOWN, buff=.5)
        self.add(title)
        self.wait()

        self.play(Write(definition))
        self.wait()
        characteristics_statement = TextMobject("{\\large Tiada pemboleh ubah...}").set_color(BLUE)
        characteristics = VGroup(
            characteristics_statement,
            BulletedList(
                "mempunyai kuasa lebih daripada 1",
                "digunakan sebagai penyebut pecahan",
            ).next_to(characteristics_statement, DOWN, buff=.7)
        ).center().scale(.7).shift(DOWN*.5)
        self.play(Write(characteristics))
        self.wait()

        # Graphs and labels
        linear_graph = FunctionGraph(lambda x: x, color=YELLOW)
        quadratic_graph = FunctionGraph(lambda x: x ** 2, color=YELLOW)
        reciprocal_graph = VGroup(
            FunctionGraph(lambda x: 1 / x, x_max=-.01, color=YELLOW),
            FunctionGraph(lambda x: 1 / x, x_min=.01, color=YELLOW),
        )
        trigonometric_graph = FunctionGraph(lambda x: np.sin(x), color=BLUE)
        logarithmic_graph = FunctionGraph(lambda x: np.log2(x), color=ORANGE)

        linear_eqn = TexMobject("y=", "x", color=YELLOW).to_corner(UL)
        quadratic_eqn = TexMobject("y=", "x^2", color=YELLOW).to_corner(UL)
        reciprocal_eqn = TexMobject("y=", "\\frac{1}{x}", color=YELLOW).to_corner(UL)
        trigonometric_eqn = TexMobject("y=", "\\sin x", color=BLUE).to_corner(UL).shift(DOWN*1.25)
        logarithmic_eqn = TexMobject("y=", "\\log_2 x", color=ORANGE).to_corner(UL).shift(DOWN*1.75)

        # Line text
        line_text = TextMobject("Line").scale(2).shift(DOWN + RIGHT*2)

        plane = NumberPlane().fade()
        self.play(AnimationGroup(
            *[
                FadeOutAndShift(v, LEFT)
                for v in [title, definition, characteristics_statement, *characteristics[1]]
            ],
            lag_ratio=.1
        ))
        self.play(
            ShowCreation(plane, run_time=3, lag_ratio=.1)
        )
        self.wait()

        # Linear merujuk kepada line...
        self.play(
            GrowFromCenter(linear_eqn),
            ShowCreation(linear_graph),
            Write(line_text),
        )
        self.wait()

        # Kuasa selain daripada 1...
        self.play(Uncreate(line_text))
        self.play(
            ReplacementTransform(linear_eqn, quadratic_eqn),
            ReplacementTransform(linear_graph, quadratic_graph),
        )
        self.wait()

        # Digunakan sebagai penyebut pecahan...
        self.play(
            ReplacementTransform(quadratic_eqn, reciprocal_eqn),
            ReplacementTransform(quadratic_graph, reciprocal_graph),
        )
        self.wait()

        # Begitu juga...
        self.play(
            GrowFromCenter(trigonometric_eqn),
            ShowCreation(trigonometric_graph),
        )
        self.play(
            GrowFromCenter(logarithmic_eqn),
            ShowCreation(logarithmic_graph),
        )
        self.wait()

        self.wait(2)

class DisuruhMembentukGraf(Scene):
    def construct(self):
        plane = NumberPlane().fade()
        self.add(plane)
        self.wait()

        dot_1 = Dot(color=YELLOW).move_to((-2,-1,0))
        dot_2 = Dot(color=YELLOW).move_to((2,.5,0))

        def func(x):
            c1 = dot_1.get_center()
            c2 = dot_2.get_center()
            m = (c1[1] - c2[1]) / (c1[0] - c2[0])
            return m * (x - c1[0]) + c1[1]
        
        graph = FunctionGraph(func, color=YELLOW)
        
        self.play(AnimationGroup(
            FadeInFromDown(dot_1),
            FadeInFromDown(dot_2),
            lag_ratio=.5
        ))
        self.play(ShowCreation(graph))
        self.wait()

        def new_func(x):
            c1 = (-5,-2,0)
            c2 = (5,1.5,0)
            m = (c1[1] - c2[1]) / (c1[0] - c2[0])
            return m * (x - c1[0]) + c1[1]
        
        new_graph = FunctionGraph(new_func, color=YELLOW)

        self.play(
            dot_1.move_to, (-5,-2,0),
            dot_2.move_to, (5,1.5,0),
            ReplacementTransform(graph, new_graph),
            run_time=3
        )

        self.wait(2)

class PersamaanLinearSerentak(Scene):
    def construct(self):
        title = TextMobject("Persamaan Linear Serentak").scale(1.5)
        title.set_color_by_gradient(YELLOW, ORANGE)
        self.play(Write(title))
        self.wait()

        sim_eqn = TexMobject(*list("2y=x-4,"), "\\quad", *list("3y=9-6x")).scale(1.5).shift(UP)
        title_penggantian = TextMobject("Penggantian").shift(DOWN + LEFT*3).set_color(GREEN).scale(1.5)
        title_penghapusan = TextMobject("Penghapusan").shift(DOWN + RIGHT*3).set_color(BLUE).scale(1.5)
        self.play(FadeOut(title))
        self.play(Write(sim_eqn.get_slice(*range(0,7), *range(8,15))))
        self.wait()
        self.play(GrowFromCenter(title_penggantian))
        self.play(GrowFromCenter(title_penghapusan))
        self.wait()

        # Kaedah penggantian
        title_penggantian.generate_target()
        title_penggantian.target.shift(RIGHT*3)
        title_penggantian.target.to_edge(UP)

        eqn_1 = sim_eqn.get_slice(*range(0,6))
        eqn_2 = sim_eqn.get_slice(*range(8,15))
        eqn_1_mod = TexMobject(*list("y={x-4"), "\\over", *list("2}")).scale(1.5)
        eqn_2_mod = TexMobject("3", "\\left(", *list("{x-4"), "\\over", *list("2}"), "\\right)", *list("=9-6x")).scale(1.5).shift(DOWN*2.25)
        eqn_x = TexMobject(*list("x=2")).scale(1.5).shift(DOWN*3.75)
        VGroup(eqn_1_mod, eqn_2_mod, eqn_x).center()

        self.play(
            MoveToTarget(title_penggantian, path_arc=-np.pi/2),
            FadeOutAndShiftDown(title_penghapusan),

            FadeOut(sim_eqn[6]),
            eqn_1.move_to, eqn_1_mod,
            eqn_2.move_to, eqn_2_mod,
            eqn_2.fade
        )
        title_penghapusan.shift(LEFT*3)
        title_penghapusan.to_edge(UP)
        self.wait()
        self.play(
            ReplacementTransform(eqn_1.get_slice(1,2,3,4,5), eqn_1_mod.get_slice(0,1,3,4,5)),
            ReplacementTransform(eqn_1.get_slice(0), eqn_1_mod.get_slice(7), path_arc=np.pi/2),
        )
        self.play(Write(eqn_1_mod.get_slice(6)))
        self.wait()
        self.play(eqn_2.fade, -1)
        self.play(
            FadeOut(eqn_2[1]),
            ReplacementTransform(eqn_2.get_slice(0,2,3,4,5,6), eqn_2_mod.get_slice(0,10,11,12,13,14)),
            ReplacementTransform(eqn_1_mod.get_slice(*range(2,9)).copy(), eqn_2_mod.get_slice(*range(2,9))),
        )
        self.play(Write(eqn_2_mod.get_slice(1,9)))
        self.wait()
        self.play(Write(eqn_x))

        # Kaedah penghapusan
        self.play(
            *[
                FadeOut(v)
                for v in [
                    title_penggantian,
                    eqn_1_mod,
                    eqn_2_mod,
                    eqn_x,
                ]
            ],
            FadeInFromDown(title_penghapusan),
        )
        eqn_1 = TexMobject(*list("2y=x-4")).scale(1.5)
        eqn_2 = TexMobject(*list("3y=9-6x")).scale(1.5).shift(DOWN*1.25)
        eqn_1_mod = TexMobject("3", "\\times", *list("2y=3(x-4)")).scale(1.5)
        eqn_2_mod = TexMobject("2", "\\times", *list("3y=2(9-6x)")).scale(1.5).shift(DOWN*1.25)
        eqn_1_final = TexMobject(*list("6y=3x-12")).scale(1.5)
        eqn_2_final = TexMobject(*list("6y=18-12x")).scale(1.5).shift(DOWN*1.25)
        eqn_new = TexMobject(*list("6y-6y=(3x-12)-(18-12x)")).scale(1.5).shift(DOWN*2.5)
        VGroup(eqn_1, eqn_2, eqn_1_mod, eqn_2_mod, eqn_1_final, eqn_2_final, eqn_new).center()

        self.play(
            Write(eqn_1),
            Write(eqn_2),
        )
        self.wait()
        self.play(ReplacementTransform(eqn_1, eqn_1_mod.get_slice(*range(2,5), *range(7,10))))
        self.play(Write(eqn_1_mod.get_slice(0,1,5,6,10)))
        self.wait()
        self.play(ReplacementTransform(eqn_2, eqn_2_mod.get_slice(*range(2,5), *range(7,11))))
        self.play(Write(eqn_2_mod.get_slice(0,1,5,6,11)))
        self.wait(.5)
        self.play(
            FadeOut(eqn_1_mod.get_slice(6,10)),
            FadeOut(eqn_2_mod.get_slice(6,11)),

            ReplacementTransform(eqn_1_mod.get_slice(0,1,2), eqn_1_final[0]),
            ReplacementTransform(eqn_2_mod.get_slice(0,1,2), eqn_2_final[0]),
            ReplacementTransform(eqn_1_mod.get_slice(3,4,7,8), eqn_1_final.get_slice(1,2,4,5)),
            ReplacementTransform(eqn_2_mod.get_slice(3,4,10,8), eqn_2_final.get_slice(1,2,8,5)),

            ReplacementTransform(eqn_1_mod[5].copy(), eqn_1_final[3]),
            ReplacementTransform(VGroup(eqn_2_mod[5].copy(), eqn_2_mod[9]), eqn_2_final[6:8]),
            ReplacementTransform(eqn_1_mod.get_slice(5,9), eqn_1_final[6:8]),
            ReplacementTransform(eqn_2_mod.get_slice(5,7), eqn_2_final[3:5]),
        )
        self.wait()

        self.play(ReplacementTransform(eqn_1_final[0:2], eqn_new[0:2]))
        self.wait()
        self.play(Write(eqn_new[2]))
        self.play(ReplacementTransform(eqn_2_final[0:2], eqn_new[3:5]))
        self.wait()
        self.play(
            AnimationGroup(*[FadeOutAndShift(v, LEFT) for v in [eqn_1_final[2], eqn_2_final[2]]], lag_ratio=.3),
            Write(eqn_new[5])
        )
        self.wait()
        self.play(ReplacementTransform(eqn_1_final[3:], eqn_new[7:12]))
        self.play(Write(eqn_new.get_slice(6,12)))
        self.wait()
        self.play(Write(eqn_new[13]))
        self.play(ReplacementTransform(eqn_2_final[3:], eqn_new[15:21]))
        self.play(Write(eqn_new.get_slice(14,21)))
        self.wait()

        eqn_newer = TexMobject(*list("0=(3x-12)-(18-12x)")).scale(1.5)
        eqn_x = TexMobject(*list("x=2")).scale(1.5).shift(DOWN*1.25)
        eqn_y = TexMobject(*list("y=-1")).scale(1.5).shift(DOWN*2.25)
        VGroup(eqn_newer, eqn_x, eqn_y).center()
        self.play(eqn_new.move_to, eqn_newer)
        self.play(
            ReplacementTransform(eqn_new[0:5], eqn_newer[0]),
            ReplacementTransform(eqn_new[5:], eqn_newer[1:]),
        )
        self.wait()
        self.play(
            CircleIndicate(eqn_newer[4]),
            CircleIndicate(eqn_newer[16]),
        )
        self.wait()
        
        self.play(Write(eqn_x))
        self.wait()

        # Setelah mendapati...
        eqn_1 = TexMobject(*list("2y=x-4")).scale(1.5).move_to(eqn_newer)
        eqn_1_sub = TexMobject(*list("2y=2-4")).scale(1.5).move_to(eqn_newer)
        self.play(
            FadeOut(eqn_newer),
            FadeIn(eqn_1),
        )
        self.wait()
        self.play(
            FadeOut(eqn_1[3]),
            ReplacementTransform(eqn_x[2].copy(), eqn_1_sub[3]),
            ReplacementTransform(eqn_1.get_slice(0,1,2,4,5), eqn_1_sub.get_slice(0,1,2,4,5)),
        )
        self.wait()
        self.play(Write(eqn_y))

        self.wait(2)

class GrafPersamaanLinearSerentak(Scene):
    def construct(self):
        plane = NumberPlane().fade()
        plane.add_coordinates()
        psl = VGroup(*[
            TextMobject(v).shift(DOWN*.5*i)
            for i,v in enumerate([
                "Persamaan",
                "Linear",
                "Serentak"
            ])
        ]).scale(1.5).set_color(GREEN)
        psl.center().shift(LEFT*3)
        arrow = TexMobject("\\longleftrightarrow").scale(1.5)
        grfq = TextMobject("Graf", "?").scale(2).shift(RIGHT*3)
        grfq[0].set_color(BLUE)

        self.play(Write(VGroup(psl, arrow, grfq)))
        self.wait()

        # Seperti yang diterangkan tadi...
        eqn_1 = TexMobject("2y=x-4").set_color(GREEN_A).to_corner(UL)
        eqn_2 = TexMobject("3y=9-6x").set_color(BLUE_A).to_corner(UL).shift(DOWN*.5)
        self.play(
            *[FadeOut(v) for v in [psl, arrow, grfq]],
            ShowCreation(plane, run_time=3, lag_ratio=.1),
            Write(plane.get_axis_labels())
        )
        self.play(Write(VGroup(eqn_1, eqn_2)))
        self.wait()

        # Bezanya...
        self.play(AnimationGroup(
            Indicate(eqn_1),
            Indicate(eqn_2),
            lag_ratio=.2
        ))
        self.wait()

        graph_1 = FunctionGraph(lambda x: (x-4)/2, color=GREEN)
        graph_2 = FunctionGraph(lambda x: (9-6*x)/3, color=BLUE)

        eqn_1.generate_target()
        eqn_2.generate_target()
        eqn_1.target.move_to((-2,-1.5,0))
        eqn_2.target.move_to((2,3,0))

        self.play(AnimationGroup(
            MoveToTarget(eqn_2),
            MoveToTarget(eqn_1),
            ShowCreation(graph_1),
            ShowCreation(graph_2),
            lag_ratio=.2
        ))
        self.wait()

        # Eqn 1: (-2,-3) -> (5,.5)
        # Eqn 2: (0,3) -> (3,-3)

        # Persamaan pertama
        dot = Dot(color=YELLOW).move_to((-2,-3,0))
        surround = SurroundingRectangle(eqn_1, color=YELLOW)
        self.play(GrowFromCenter(dot))
        self.play(dot.move_to, (5,.5,0), run_time=3)
        self.wait()
        self.play(ShowCreation(surround))
        self.wait()
        self.play(FadeOut(dot), FadeOut(surround))

        # Persamaan kedua
        dot = Dot(color=YELLOW).move_to((0,3,0))
        surround = SurroundingRectangle(eqn_2, color=YELLOW)
        self.play(GrowFromCenter(dot))
        self.play(dot.move_to, (3,-3,0), run_time=3)
        self.wait()
        self.play(ShowCreation(surround))
        self.wait()
        self.play(FadeOut(dot), FadeOut(surround))

        # Daripada maklumat ini, kita dapat simpulkan...
        dot = Dot(color=YELLOW).move_to((2,-1,0))
        graph_1_indicator = FunctionGraph(lambda x: (x-4)/2, color=YELLOW, stroke_width=5)
        graph_2_indicator = FunctionGraph(lambda x: (9-6*x)/3, color=YELLOW, stroke_width=5)
        self.play(
            GrowFromCenter(dot),
            FocusOn(dot)
        )
        self.wait()
        self.play(AnimationGroup(
            ShowCreationThenDestruction(graph_1_indicator, run_time=2),
            ShowCreationThenDestruction(graph_2_indicator, run_time=2),
            lag_ratio=.2
        ))
        self.wait()

        # Memuaskan...
        surround_1 = SurroundingRectangle(eqn_1, color=YELLOW)
        surround_2 = SurroundingRectangle(eqn_2, color=YELLOW)
        self.play(AnimationGroup(
            ShowCreation(surround_1),
            ShowCreation(surround_2),
            lag_ratio=.3
        ))

        self.wait(2)

class DuaGarisanLurusBersilang(Scene):
    def construct(self):
        plane = NumberPlane().fade()
        plane.add_coordinates()
        self.add(plane)
        graph_1 = FunctionGraph(lambda x: x + 0, color=GREEN)
        graph_2 = FunctionGraph(lambda x: -x + 0, color=BLUE)

        def to_intersection_point(obj):
            s_1 = graph_1.get_start()
            e_1 = graph_1.get_end()
            s_2 = graph_2.get_start()
            e_2 = graph_2.get_end()

            m1 = (s_1[1] - e_1[1]) / (s_1[0] - e_1[0])
            m2 = (s_2[1] - e_2[1]) / (s_2[0] - e_2[0])
            c1 = m1 * s_1[0] - s_1[1]
            c2 = m2 * s_2[0] - s_2[1]
            
            if m1 - m2 == 0:
                obj.move_to((0,-100,0))
            else:
                x = (c2 - c1) / (m1 - m2)
                y = m1 * x + c1
                obj.move_to((-x,-y,0))

        dot = Dot(color=YELLOW).add_updater(to_intersection_point)
        self.add(graph_1, graph_2, dot)

        self.wait()
        self.play(
            graph_1.shift, UP*.9,
            graph_1.rotate, -28*DEGREES,
            graph_2.shift, DOWN*.3,
            graph_2.rotate, 10*DEGREES,
            run_time=2
        )
        self.wait(.5)
        self.play(
            graph_1.shift, DOWN*2.6,
            graph_1.rotate, -52*DEGREES,
            graph_2.shift, UP*1.2,
            graph_2.rotate, 39*DEGREES,
            run_time=3
        )
        self.wait(.5)
        self.play(
            graph_1.shift, UP*.6,
            graph_1.rotate, -87*DEGREES,
            graph_2.shift, UP*.8,
            graph_2.rotate, 12*DEGREES,
            run_time=2.5
        )
        self.wait()
        self.play(
            graph_1.move_to, (0,0,0),
            graph_1.rotate, -13*DEGREES,
            graph_2.move_to, UP*1.5,
            graph_2.rotate, 29*DEGREES,
            run_time=2
        )

        text_except_1 = TextMobject("Kecuali jika kedua-dua")
        text_except_1.set_color(RED)
        text_except_1.to_corner(DR).shift(UP*.75)
        text_except_2 = TextMobject("persamaan tersebut selari")
        text_except_2.set_color(RED)
        text_except_2.to_corner(DR)
        self.play(Write(VGroup(text_except_1, text_except_2)))

        self.wait(2)

class MasalahLain(Scene):
    def construct(self):
        plane = NumberPlane().fade()
        self.add(plane)
        self.wait()

        branches = [
            [
                "Matematik",
                "Geometri",
                "Kalkulus",
                "Algebra abstrak",
                "Sejarah matematik"
            ],
            [
                "Fizik",
                "Kejuruteraan",
                "Penyelidikan"
            ],
            [
                "Sains komputer",
                "Kejuruteraan komputer",
                "Statistik",
                "Analisis data"
            ]
        ]

        # Generate lists
        for i in range(len(branches)):
            for j in range(len(branches[i])):
                if j == 0:
                    if i == 0:
                        text = branches[i][j]
                        branches[i][j] = TextMobject(text)
                        continue
                    text = branches[i][j]
                    branches[i][j] = TextMobject(text).next_to(branches[i-1][0], RIGHT, buff=1.5)
                else:
                    text = branches[i][j]
                    branches[i][j] = TextMobject(text).next_to(branches[i][j-1], UP).scale(.7)
            branches[i].append(TexMobject("\\vdots").next_to(branches[i][len(branches[i])-1], UP, buff=.5))
        # Program braces
        for i in range(len(branches)):
            branches[i][0].move_to(branches[i][1])
            if branches[i][0].get_width() > branches[i][1].get_width():
                branches[i].insert(1, Brace(branches[i][0]))
            else:
                branches[i].insert(1, Brace(branches[i][1]))
            branches[i][0].next_to(branches[i][1], DOWN)
        branches.append([TexMobject("\\cdots").next_to(branches[len(branches)-1][0], RIGHT, buff=1.5)])

        vbranches = VGroup(*[
            sub_branch
            for branch in branches
            for sub_branch in branch
        ]).center()

        self.play(Write(vbranches))
        self.wait()

        # Maksudnya...
        quadratic_graph = FunctionGraph(lambda x: x**2 - 1, color=GREEN)
        linear_graph = FunctionGraph(lambda x: x, color=BLUE)

        v1 = (1 - np.sqrt(5)) / 2
        v2 = (1 + np.sqrt(5)) / 2
        dot_1 = Dot(color=YELLOW).move_to((v1,v1,0))
        dot_2 = Dot(color=YELLOW).move_to((v2,v2,0))

        self.play(Uncreate(vbranches))
        self.play(AnimationGroup(
            ShowCreation(quadratic_graph),
            ShowCreation(linear_graph),
            FadeInFromDown(dot_1),
            FadeInFromDown(dot_2),
            lag_ratio=.3
        ))
        self.wait()
        self.play(
            plane.fade,
            quadratic_graph.fade,
            linear_graph.fade,
            dot_1.fade,
            dot_2.fade,
        )

        exam_papers = VGroup(*[
            ExamPaper((["A-","A","A-","A+"])[i]).shift(RIGHT*2.5*i)
            for i in range(4)
        ]).center()
        self.play(AnimationGroup(
            *[FadeInFromDown(exam_paper) for exam_paper in exam_papers],
            lag_ratio=0.2
        ))
        self.wait()
        self.play(plane.fade, -1, *[
            FadeOut(v)
            for v in [
                exam_papers,
                quadratic_graph,
                linear_graph,
                dot_1, dot_2,
            ]
        ])

        # Ini dicapai sekiranya...
        eqn = TexMobject("x^{2}+\\left(y-\\sqrt{\\left|x\\right|}\\right)^{2}=1").add_background_rectangle()
        graph = VGroup(
            FunctionGraph(lambda x: np.sqrt(1 - x**2) + np.sqrt(np.abs(x)), x_min=-1, x_max=1, color=LIGHT_PINK),
            FunctionGraph(lambda x: -np.sqrt(1 - x**2) + np.sqrt(np.abs(x)), x_min=-1, x_max=1, color=LIGHT_PINK).flip(),
        )

        self.play(Write(eqn))
        self.wait()
        self.play(eqn.to_edge, DOWN)
        self.play(ShowCreation(graph))

        self.wait(2)

class SkipToTime(Scene):
    def construct(self):
        time = TexMobject("4:27")
        triangle = Triangle(stroke_opacity=0, color=WHITE, fill_opacity=1).scale(.15).shift(DOWN*.7).rotate(180*DEGREES)
        
        group = VGroup(time, triangle).scale(5)

        self.play(FadeInFrom(group, UP))
        self.wait(2.5)
        self.play(FadeOutAndShift(group, UP))

