Zdrojové kódy k příkladům a úlohám 34. série KSP (Manim).
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
11 KiB

2 years ago
{
"cells": [
{
"cell_type": "markdown",
"id": "36cee816",
"metadata": {},
"source": [
"# Řešení 2. série"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "efe16561",
"metadata": {},
"outputs": [],
"source": [
"from manim import *"
]
},
{
"cell_type": "markdown",
"id": "36ec08cc",
"metadata": {},
"source": [
"## Trojúhelník"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e7a3da39",
"metadata": {},
"outputs": [],
"source": [
"%%manim -v WARNING -qh Triangle\n",
"\n",
"from random import *\n",
"\n",
"\n",
"class Triangle(Scene):\n",
" def construct(self):\n",
" seed(0xDEADBEEF)\n",
"\n",
" # vše trochu zvětšíme\n",
" c = 2\n",
"\n",
" p1 = Dot().scale(c).shift(UP * c)\n",
" p2 = Dot().scale(c).shift(DOWN * c + LEFT * c)\n",
" p3 = Dot().scale(c).shift(DOWN * c + RIGHT * c)\n",
"\n",
" points = VGroup(p1, p2, p3)\n",
" \n",
" self.play(Write(points, lag_ratio=0.5), run_time=1.5)\n",
"\n",
" l1 = Line()\n",
" l2 = Line()\n",
" l3 = Line()\n",
"\n",
" lines = VGroup(l1, l2, l3)\n",
"\n",
" def create_line_updater(a, b):\n",
" \"\"\"Vrátí funkci, která se chová jako updater nějaké úsečky.\"\"\"\n",
" return lambda x: x.become(Line(start=a.get_center(), end=b.get_center()))\n",
"\n",
" l1.add_updater(create_line_updater(p1, p2))\n",
" l2.add_updater(create_line_updater(p2, p3))\n",
" l3.add_updater(create_line_updater(p3, p1))\n",
"\n",
" self.play(Write(lines, lag_ratio=0.5), run_time=1.5)\n",
"\n",
" x = Tex(\"x\")\n",
" y = Tex(\"y\")\n",
" z = Tex(\"z\")\n",
"\n",
" x.add_updater(lambda x: x.next_to(p1, UP))\n",
" y.add_updater(lambda x: x.next_to(p2, DOWN + LEFT))\n",
" z.add_updater(lambda x: x.next_to(p3, DOWN + RIGHT))\n",
"\n",
" labels = VGroup(x, y, z).scale(c * 0.8)\n",
"\n",
" self.play(FadeIn(labels, shift=UP * 0.2))\n",
"\n",
" circle = Circle()\n",
" circle.add_updater(\n",
" lambda c: c.become(\n",
" Circle.from_three_points(\n",
" p1.get_center(), p2.get_center(), p3.get_center()\n",
" )\n",
" )\n",
" )\n",
"\n",
" self.play(Write(circle))\n",
"\n",
" self.play(\n",
" p2.animate.shift(LEFT + UP),\n",
" p1.animate.shift(RIGHT),\n",
" )"
]
},
{
"cell_type": "markdown",
"id": "171e8840",
"metadata": {},
"source": [
"## Vlna"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "252d64a3",
"metadata": {},
"outputs": [],
"source": [
"%%manim -v WARNING -qh Wave\n",
"\n",
"from random import *\n",
"\n",
"\n",
"class Wave(Scene):\n",
" def construct(self):\n",
" seed(0xDEADBEEF)\n",
"\n",
" maze_string = \"\"\"\n",
"#######################################################\n",
"# ################# ## #\n",
"# ################## #### #\n",
"# ################# #### #\n",
"# ############### ##### # ##\n",
"# ######### ##### ####\n",
"# ### ###### ######\n",
"# ### ## ##### ### #####\n",
"# #### ######## #### ##### ## #\n",
"# ##### ########## ### ######## # #\n",
"# ##### ########### ######## #\n",
"# #### ########### ########## #\n",
"# ## ########### ########## #\n",
"# #### ############ ############# #\n",
"# ###### ############ ############# #\n",
"# ######### ## ########### ######### # #\n",
"# ############### ######### ####### #\n",
"# ############### ###### ###### #\n",
"# ############### ##### #### #\n",
"# ############# # ## #\n",
"# # ####### ########### ####\n",
"# ### # #################\n",
"# ## #### #################\n",
"##### ###### ##################\n",
"###### ###### ##################\n",
"# ### ### ####### ### ############### #\n",
"# #### ############ #### ####### #\n",
"# ##### ############ ### #\n",
"# ### ########## #\n",
"#######################################################\n",
"\"\"\"\n",
"\n",
" maze = [] # 2D pole čtverců tak, jak ho vidíme\n",
" maze_bool = [] # 2D pole True/False\n",
" all_squares = VGroup()\n",
"\n",
" # parsujeme vstup, řádek po řádku\n",
" for row in maze_string.strip().splitlines():\n",
" maze.append([])\n",
" maze_bool.append([])\n",
"\n",
" for char in row:\n",
" square = Square(\n",
" side_length=0.23,\n",
" stroke_width=1,\n",
" fill_color=WHITE if char == \"#\" else BLACK,\n",
" fill_opacity=1,\n",
" )\n",
"\n",
" maze[-1].append(square)\n",
" maze_bool[-1].append(char == \" \")\n",
" all_squares.add(square)\n",
"\n",
" # rozměry bludiště\n",
" w = len(maze[0])\n",
" h = len(maze)\n",
"\n",
" # rozmístění do gridu\n",
" all_squares.arrange_in_grid(rows=h, buff=0)\n",
"\n",
" self.play(FadeIn(all_squares), run_time=2)\n",
"\n",
" # startovní pozice\n",
" x, y = 1, 1\n",
"\n",
" colors = [\"#ef476f\", \"#ffd166\", \"#06d6a0\", \"#118ab2\"]\n",
"\n",
" # vytvoříme si slovník se vzdálenostmi od startu\n",
" distances = {(x, y): 0}\n",
" stack = [(x, y, 0)]\n",
"\n",
" while len(stack) != 0:\n",
" x, y, d = stack.pop(0)\n",
"\n",
" for dx, dy in ((0, 1), (1, 0), (-1, 0), (0, -1)):\n",
" nx, ny = dx + x, dy + y\n",
"\n",
" # není potřeba, jelikož vstup je ohraničený a nikde nevyběhneme :)\n",
" #if nx < 0 or nx >= w or ny < 0 or ny >= h:\n",
" # continue\n",
"\n",
" if maze_bool[ny][nx] and (nx, ny) not in distances:\n",
" stack.append((nx, ny, d + 1))\n",
" distances[(nx, ny)] = d + 1\n",
"\n",
" max_distance = max([d for d in distances.values()])\n",
"\n",
" all_colors = color_gradient(colors, max_distance + 1)\n",
"\n",
" # vytvoříme skupiny podle vzdálenosti od startu\n",
" groups = []\n",
" for d in range(max_distance + 1):\n",
" groups.append(\n",
" AnimationGroup(\n",
" *[\n",
" maze[y][x].animate.set_fill(all_colors[d])\n",
" for x, y in distances\n",
" if distances[x, y] == d\n",
" ]\n",
" )\n",
" )\n",
"\n",
" self.play(AnimationGroup(*groups, lag_ratio=0.08))\n"
]
},
{
"cell_type": "markdown",
"id": "e6f13b54",
"metadata": {},
"source": [
"## Hilbert"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "06ed2d5c",
"metadata": {},
"outputs": [],
"source": [
"%%manim -v WARNING -qh Hilbert\n",
"\n",
"\n",
"class Path(VMobject):\n",
" def __init__(self, points, *args, **kwargs):\n",
" super().__init__(self, *args, **kwargs)\n",
" self.set_points_as_corners(points)\n",
"\n",
" def get_important_points(self):\n",
" \"\"\"Vrátí důležité body křivky.\"\"\"\n",
" return list(self.get_start_anchors()) + [self.get_end_anchors()[-1]]\n",
"\n",
"\n",
"class Hilbert(Scene):\n",
" def construct(self):\n",
" directions = [LEFT + DOWN, LEFT + UP, RIGHT + UP, RIGHT + DOWN]\n",
"\n",
" hilbert = Path(directions).scale(3)\n",
"\n",
" self.play(Write(hilbert, lag_ratio=0.5))\n",
"\n",
" for i in range(1, 4):\n",
" # délka jedné úsečky\n",
" new_segment_length = 1 / (2 ** (i + 1) - 1)\n",
"\n",
" # škálování částí křivky tak, aby byla vycentrovaná\n",
" new_scale = (1 - new_segment_length) / 2\n",
"\n",
" # chceme si uchovat původní křivku, abychom pomocí ní vyrovnávali ostatní\n",
" lu = hilbert.copy()\n",
" lu, hilbert = hilbert, lu\n",
"\n",
" self.play(\n",
" lu.animate.scale(new_scale)\n",
" .set_color(DARK_GRAY)\n",
" .align_to(hilbert, directions[1])\n",
" )\n",
"\n",
" ru = lu.copy()\n",
" self.play(ru.animate.align_to(hilbert, directions[2]))\n",
"\n",
" ld, rd = lu.copy(), ru.copy()\n",
" self.play(\n",
" ld.animate.align_to(hilbert, directions[0]).rotate(-PI / 2),\n",
" rd.animate.align_to(hilbert, directions[3]).rotate(PI / 2),\n",
" )\n",
"\n",
" new_hilbert = Path(\n",
" list(ld.flip(LEFT).get_important_points())\n",
" + list(lu.get_important_points())\n",
" + list(ru.get_important_points())\n",
" + list(rd.flip(LEFT).get_important_points())\n",
" )\n",
"\n",
" self.play(Write(new_hilbert, run_time=2 ** i))\n",
"\n",
" self.remove(lu, ru, ld, rd)\n",
"\n",
" hilbert = new_hilbert"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.1"
}
},
"nbformat": 4,
"nbformat_minor": 5
}