- PVSM.RU - https://www.pvsm.ru -
Давайте рассмотрим наипростейшую модель естественного отбора. В сети встречал модель с двумя параметрами-генами, а у нас будет всего один, при сохранении наглядности. Модель настолько элементарна, что её можно обсудить даже со своим ребёнком (проверил со своей шестилетней дочкой).
NB: Весь код в статье интерактивный, кликайте, чтобы открыть, запустить, попробовать свои идеи сразу на ходу. Используется Python + p5py [1], который разрабатывался для книги для детей [2], преподавания в Универе, детских кружках и школе.
Внимание: 21 гифка, 29 фрагментов кода и 12 ссылок на запускаемый код.
У нас будет гордый птыц со всего одним геном, который хранит направление полёта из гнезда к еде. Альфа-ген. Птыц летит куда-то в соответствии со своим геном направления и каждый ход тратит на это энергию.
Если птыц добудет еду, он:
восстановит свою энергию;
вернётся в гнездо;
и там даст два потомка, передав свой ген с мутациями.
Если не добудет, то просто отразится от стенок и полетит назад. Когда энергия закончится, он умрёт. Гнездо — в центре экрана. Еда спавнится где повезёт.
Итак, нужна птица, направление и факт полёта. Для начала сама птица:
bird_position = Vector(width / 2, height / 2)
И её отображение:
def display_bird():
text_size(140)
text_align(CENTER, CENTER)
text("
", bird_position.x, bird_position.y)
Всё вместе (чтобы можно было запустить):
from p5py import *
import random
run()
# Устанавливаем размеры окна
size(400, 400)
# Инициализация позиции птицы
bird_position = Vector(width / 2, height / 2)
# Функция для отображения птицы
def display_bird():
text_size(140)
text_align(CENTER, CENTER)
text("
", bird_position.x, bird_position.y)
# Вечный игровой "цикл"
def draw():
background(30, 30, 40) # Устанавливаем цвет фона
display_bird() # Отображаем птицу
Код [3] — нажмите, чтобы запустить сразу в браузере.
Поменяйте птицу на что-нибудь забавное. Можно исследовать не только в браузере. Модуль также доступен как
p5
для VS Code, но в нём не реализовано отображение эмоджи, поэтому придётся поменять наellipse(x, y, radius
).
Теперь направление. Единственный ген птицы — это угол полёта
. Он будет наследоваться и иногда мутировать.
bird_angle = random.uniform(-PI, PI)
И скорость:
bird_speed = 4
Клюв поверни, и полетели...
def move_bird():
# Обновляем координаты птицы в зависимости от её скорости и угла
bird_position.x += bird_speed * cos(bird_angle)
bird_position.y += bird_speed * sin(bird_angle)
Всё вместе:
from p5py import *
import random
run()
size(400, 400)
bird_position = Vector(width / 2, height / 2)
bird_angle = random.uniform(-PI, PI)
bird_speed = 4
def move_bird():
bird_position.x += bird_speed * cos(bird_angle)
bird_position.y += bird_speed * sin(bird_angle)
def display_bird():
text_size(140)
text_align(CENTER, CENTER)
text("
", bird_position.x, bird_position.y)
Запускаем [4]
Запустить [5]
Чтобы еда не спавнилась на курице, используем полярные координаты.
food_angle = rand(-PI, PI)
food_distance = 3 * width / 5
food_position = Vector(width / 2 + food_distance * cos(food_angle), height / 2 + food_distance * sin(food_angle))
food_size = 140
def display_food():
text_size(food_size)
text_align(CENTER, CENTER)
text("
", food_position.x, food_position.y)
Запустить [6]
Пусть птица возвращается, если долетела до края экрана или до еды.
Если она нашла еду, то возвращается в гнездо в центре экрана, чтобы дать потомство — две новых птицы. Они наследуют всё множество родительских генов, то есть один ген — направление.
Сначала просто возвращение:
def move_bird():
global bird_angle
bird_position.x += bird_speed * cos(bird_angle)
bird_position.y += bird_speed * sin(bird_angle)
# Проверка на достижение края экрана
if (bird_position.x < 0 or bird_position.x > width or
bird_position.y < 0 or bird_position.y > height):
# Пусть летит в центр, инвертируем угол
invert_angle()
# Проверка на достижение пищи
if (dist(bird_position.x, bird_position.y, food_position.x, food_position.y) < food_size / 2):
invert_angle()
Запустить [7]
Уже сейчас понятно, что одна птица обречена на вымирание, если при рождении её угол не совпал с углом еды. Поэтому у нас будет много птиц. Мы же популяцию исследуем. Давайте сделаем рефакторинг и определим класс птиц. Так будет легче потом ими управлять.
class Bird:
def __init__(self, x, y, speed):
self.position = Vector(x, y)
self.angle = rand(-PI, PI)
self.speed = speed
def move(self):
self.position.x += self.speed * cos(self.angle)
self.position.y += self.speed * sin(self.angle)
if (self.position.x < 0 or self.position.x > width or
self.position.y < 0 or self.position.y > height):
self.invert_angle()
if (dist(self.position.x, self.position.y, food_position.x, food_position.y) < food_size / 2):
self.invert_angle()
def invert_angle(self):
self.angle = self.angle + PI
def display(self):
text_size(140)
text_align(CENTER, CENTER)
text("
", self.position.x, self.position.y)
bird = Bird(width / 2, height / 2, 4)
Код [8]
Пусть у птицы будет энергия, которая уменьшается ход за ходом. Если птица нашла еду, то энергия восстанавливается.
INITIAL_ENERGY = 700 # Начальное количество энергии у птиц
А при движении энергия уменьшается.
def move(self):
if not self.alive:
return
# Тратим энергию
self.energy -= self.speed
# Проверка, осталась ли энергия
if self.energy <= 0:
self.alive = False
return
Заодно добавили атрибут alive
— жива ещё старушка или уже нет. Прозрачностью покажем, что жизнь на исходе и пора сожалеть об упущенных возможностях.
def display(self):
text_size(140)
text_align(CENTER, CENTER)
fill(255, lerp(self.energy, Bird.INITIAL_ENERGY, 0, 255, 0))
text("
", self.position.x, self.position.y)
Но применение прозрачности к эмоджи — ненадёжное дело: где-то работает, а где-то нет. Если что, можно заменить
text()
на простойellipse(x, y, r)
.lerp()
из p5.js (и p5py) соотносит один интервал с другим — масштабирует. Энергияself.energy
в интервале от 0 до максимальной будет масштабирована так, чтобы уместиться в диапазон от 0 до 255.
А если пернатое коснулось еды, то энергия восстановилась, птица ягодка опять.
if (dist(self.position.x, self.position.y, food_position.x, food_position.y) < food_size / 2):
self.invert_angle()
self.energy = Bird.INITIAL_ENERGY
Запускаем [9]
Прежде чем перейти к размножению, наплодим хотя бы сотню птиц.
Видно, как быстро вымирают те, кому «повезло» родиться с геном угла, не совпадающим с направлением на еду:
# Параметры симуляции
NUM_BIRDS = 100
# Создаем массив из птиц
birds = [Bird(Vector(width / 2, height / 2), rand(-PI, PI)) for _ in range(NUM_BIRDS)]
def draw():
background(30, 30, 40)
display_food()
for bird in birds:
bird.move()
bird.display()
Запустить код [10]
Введём признак того, что птица накушалась и летит в гнездо размножаться:
self.is_returning = False
И главный фактор для нас, вероятность мутации гена:
MUTATION_RATE = 0.2 # Вероятность мутации направления у потомков
Добавим метод репродукции:
def invert_angle(self):
self.angle = self.angle + PI
def update(self):
self.move()
self.display()
# Проверяем, находится ли птица в круге и возвращается ли она
center_position = Vector(width / 2, height / 2) # Центр экрана
if self.is_returning and self.position.dist(center_position) < 5: # - радиус круга размножения
self.is_returning = False
return self.reproduce()
return []
def reproduce(self):
new_birds = []
self.invert_angle()
if rand(0, 1) < MUTATION_RATE:
angle = rand(-PI, PI) # Большая вариация угла
else:
angle = self.angle + rand(-0.1, 0.1) # Небольшая вариация угла
new_birds.append(Bird(Vector(200, 200), angle))
new_birds.append(Bird(Vector(200, 200), angle))
return new_birds
С вероятностью MUTATION_RATE
потомки будут иметь случайный угол. Во всех других случаях они будут иметь незначительное отклонение угла, чтобы визуально птицы не сливались.
Сначала все птицы гордо разлетаются из гнезда в разные стороны:
Но потом вымирают те, кому не повезло с геном и которые не нашли еды:
А кто еду нашёл, тот молодец. Притащил её в гнездо и произвёл потомков, у которых скопировался родительский ген.
Да, у нас тут для упрощения — клонирование, почкование, бесполое размножение. Если бы не это, можно было бы претендовать на полноценный генетический алгоритм.
Видно, как популяция приспособилась к окружающей среде и размножилась. Я добавил отображение хлебушка, который они домой несут, чтобы отличить счастливчиков по жизни.
Запустить код [11]
Наступает самое интересное! Окружающая среда меняется: через какой-то интервал еда появится в новом месте (старую съели).
Пространство для экспериментов. Сейчас не реализовано, но можно уменьшать размер еды, когда птицы её растаскивают. И посмотреть, как такое изменение окружающей среды скажется на популяции.
FOOD_CHANGE_INTERVAL = 250 # Интервал изменения позиции еды
Для удобства перенесём работу с едой в класс:
class Food:
def __init__(self):
self.size = 140
self.get_random_position()
def get_random_position(self):
food_angle = rand(-PI, PI)
food_distance = 3 * width / 5
self.position = Vector(width / 2 + food_distance * cos(food_angle), height / 2 + food_distance * sin(food_angle))
def display(self):
text_size(self.size)
text_align(CENTER, CENTER)
fill(255)
text("
", self.position.x, self.position.y)
Запускайте наш главный код здесь [12] и экспериментируйте.
Сейчас есть смешной баг: NPC застревают в текстурах. Если еда появляется там, где уже есть птицы, то они начинают дёргаться почти на одном месте из-за того, что при смене угла (чтобы вернуться в гнездо) они не успевают улететь за пределы еды.
Как поправить? Будем менять направление только если птица не возвращается.
Главный код [13]
# Параметры симуляции
NUM_BIRDS = 100
MUTATION_RATE = 0.0 # Вероятность мутации направления у потомков
FOOD_CHANGE_INTERVAL = 250 # Интервал изменения позиции еды
BIRD_SPEED = 5
Новые поколения находят еду, адаптируются, успешно размножаются.
Но потомки почти полностью копируют родителей, без отклонений. Они не экспериментируют и не ищут.
Окружающая среда меняется. Еда теперь в другом месте. Потомки не могут её найти.
Все умирают.
# Параметры симуляции
NUM_BIRDS = 100
MUTATION_RATE = 1.0 # Вероятность мутации направления у потомков
FOOD_CHANGE_INTERVAL = 250 # Интервал изменения позиции еды
BIRD_SPEED = 5
Дети всё время не похожи на родителей.
В итоге найденная родителями приспособленность к окружающим условиям игнорируется всеми детьми. Они ищут только своё. Часто не находят.
Потомки не успевают достаточно размножиться, ведь не используют «знания» родителей.
Все умерли.
# Параметры симуляции
NUM_BIRDS = 100
MUTATION_RATE = 0.3 # Вероятность мутации направления у потомков
FOOD_CHANGE_INTERVAL = 250 # Интервал изменения позиции еды
BIRD_SPEED = 5
Часть потомков пользуется находкой родителей и летят за уже разведанной едой, отчего быстро размножаются.
Другая часть потомков (30 %) занята исследованием нового пространства. В случае смены среды им удаётся найти еду и продолжить род.
Количество птиц резко увеличивается.
Популяция выживает в данных условиях.
В этом эксперименте с птицами и едой мы наблюдаем простую и наглядную модель естественного отбора. Даже в упрощённом варианте становится очевидно: без мутаций потомки теряют способность адаптироваться к изменениям, а при избыточной изменчивости теряется преемственность и популяция становится нестабильной. Идеальный баланс — это сочетание небольших мутаций с сохранением ключевых свойств, позволяющее поддерживать как стабильность, так и гибкость.
На примере этого алгоритма видно, как важна изменчивость для выживания, но также и то, что стабильные базовые черты обеспечивают преемственность поколений. Наши эксперименты показывают, что адаптация к новому окружению — это не только про случайные изменения, но и про правильное наследование успешных черт. Всё «как в жизни»: да, изменения необходимы (ох), но слишком резкие шаги могут всё испортить.
Случайно еда может повторно оказаться на том же месте, что драматически увеличивает популяцию. Лучше бы сделать более-менее предсказуемое изменение среды. Например, вращение еды по кругу с прогнозируемыми промежутками. Сейчас проверим.
Скорость p5py при большом количестве птиц неприемлемо низкая. Нужно или переписать на JS, или ускорить сам модуль. Вы можете использовать черновую версию [14] похожего кода на Processing. Она на порядок быстрее.
Можно добавить ограничение, чтобы больше XXX птиц не появлялось.
Если вы будете играть с предыдущим кодом, то поймёте, что из-за слишком больших случайностей в появлении еды общую закономерность иногда сложно заметить, и вероятность мутаций в 100 % часто прекрасным образом себя чувствует. Поэтому давайте упростим и сделаем более наглядный вариант. Вот готовый код [15]. Его будем использовать в экспериментах дальше.
Еда теперь бегает по кругу:
class Food:
def __init__(self):
self.size = FOOD_SIZE
self.angle = 0
self.radius = width / 2 # Фиксированное расстояние
self.speed = 0.002 # Скорость вращения
def move(self):
self.angle += self.speed
self.position = Vector(width / 2 + self.radius * cos(self.angle),
height / 2 + self.radius * sin(self.angle))
def display(self):
text_size(self.size)
text_align(CENTER, CENTER)
fill(255)
text("
", self.position.x, self.position.y)
И репродукция упростилась: вместо охвата всех 360 градусов мы будем просто задавать диапазон мутации:
ANGLE_MUTATION_RANGE = 0.8 # Диапазон изменения угла
Вот так:
def reproduce(self):
if len(birds) >= MAX_BIRDS:
return [] # Если количество птиц достигло максимума, не создаваем новых
new_birds = []
self.invert_angle()
angle = self.angle + rand(-ANGLE_MUTATION_RANGE, ANGLE_MUTATION_RANGE)
new_birds.append(Bird(Vector(200, 200), angle))
new_birds.append(Bird(Vector(200, 200), angle))
return new_birds
Теперь крайние варианты и средний оптимальный видны очень отчетливо.
Первый вариант — мутаций нет:
ANGLE_MUTATION_RANGE = 0.0 # Диапазон изменения угла
Ха-ха, не успели. Пытаются найти еду, где её уже нет.
Второй вариант — сильные мутации:
ANGLE_MUTATION_RANGE = 1.0 # Диапазон изменения угла
Ищут не там и промахиваются. Слишком большой разброс.
Вариант третий — мутации ближе к оптимальным:
ANGLE_MUTATION_RANGE = 0.3 # Диапазон изменения угла
И через некоторое время можно, открыв птицефабрику, написать в «Упал, поднялся»:
Отключив отображение, можно запустить набор симуляций с целью определить оптимальную долю для данных окружающих условий (размер и скорость перемещения еды). На глаз 0.3
, но не факт.
Бездушный чёрствый ломоть хлеба сейчас перемещается сам, но мы можем, поменяв пару строк, управлять им мышкой. Проведем такую замену в классе Food:
def move(self):
self.position = Vector(mouse_x, mouse_y)
# self.angle += self.speed
# self.position = Vector(width / 2 + self.radius * cos(self.angle),
# height / 2 + self.radius * sin(self.angle))
Интерактивный код [16]
Я стараюсь дочке рассказывать и объяснять, чем занимаюсь и как что работает. Так и эта статья не прошла мимо. Вкратце, в этой модели получилась интересная педагогическая составляющая: если дети слишком сильно похожи на родителей (как некоторые родители требуют от детей: «прекрати рисовать, будь бухгалтером, как я»), то такая популяция слабо адаптивна и вымирает. Если же у нас другая крайность, когда дети уходят в полный отрыв от родителей так, что вообще ничему у них не учатся (крайняя степень конфликта «отцы и дети»), то и такая популяция вымирает, так как дети не используют находки и адаптивную приспособленность родителей. Для популяции идеален поиск среднего (aurea mediocritas), где дети учатся у родителей, но идут по жизни своим независимым путем.
Мы с вами написали самую простую визуализацию эволюции и естественного отбора всего с одним геном.
О важности девиации. Птицы с геном направления (угла) летят к еде и возвращаются, чтобы дать потомство. Если нет разнообразия, то при смещении еды все погибают, так как улетают в поисках и не могут вернуться. А если есть разнообразие, то отдельные девианты обязательно найдут еду и вернутся, оставив потомство с новым углом поиска, и из девиантов станут основным новым «видом» потомства.
Если вам понравилось быстро тестировать гипотезы в браузере, вот ещё статьи про p5py
:
Давайте-ка наваяем PumpKeen Game. Как Commander Keen, только про Pumpkin (тыкву). Хэллоуин же [18]
Как я написал книгу для детей: «Мама, не отвлекай. Я Python учу!» [2]
Модуль p5py
в бета-версии, узнать новости, обсудить ошибки, идеи и свои работы можно в общей группе в Telegram: @p5py_ru [19]
Автор: Gressus
Источник [20]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/404090
Ссылки в тексте:
[1] p5py: https://p5py.khasang.ru/
[2] книги для детей: https://habr.com/ru/articles/851880/
[3] Код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCopQDEUgGCCA8IIPwggfCCACIIEIggHCA2DCIIKwgZUgjCAOeDcIA1TqtAXCDNYCRACg0GbFBABDAHYATSAWLlq9Jmw7c+AoaPnK10QCwgvQPIgUQMwgrQLwgrGoAYQQGIgDBlECCIL2aA4iCugJwgjoDSIICiIFABDD6svJKSIACuSgAUAJQaUIDoIK4UzD7CruxQVD6OVIBMIJXBUJ7CvFAUNAy8VIBsIE4M1onEgMQgPnSujq5V-FUlHG6A7CBkLmFlwqOSAM4oAF4ApmkALAAM+wA0UAf7GX2kjgyervwzHj3NVDM3Xs2M7mGSAEYoICoAPoYdZYFBgJRQAC8UAAalsAMZYTBpADuKBUWAAFlAAPRQABMJyxWxQAHMsTh8QSskQoIBCEBeFimUCqIjotCgVls1Fenm8FE+30kxEAJCDMRzCTy2bllDmcNxda48oWSFRbYBQFQoVYwAA2CkQgL+AMyAC5JAQCFgtgAPLCA9bbNIARgOFytUBt9sBCj15PSAGEAKIAOQAKsGAEonEMR6Meq3erBpABEgF4NwBkO6mTiagSCUGCIQA6W25-75sCg8FKYuIWnEQAEILE9B8bmJLoA8EAq1VGtkAIiASqVPQStHzVYQMNUarWKVHmy1Wn4KBEAazJ4FSKjSAGZjlA9yd3dlBsNRuMGJNSu42XQoP2qCtPdrdQajXnMtlO-LFSzBe2gA
[4] Запускаем: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQaG2UIAhgHYAmk++IArhQBQCUdAzigF4CmzAFgAMQgDRRhQ9vgBGKEFQD6GLlhRgKUALxQAarwDGWTMwDuKKlgAWUAPRQATOKu8UAcys57D9nIWLKNwAbXm1SShoIADomFGBMCGYAWgAFAElxdN95JQ4YXl4qMIE6Kl5gKAgwADdeRT8qNgAufCg2qAblMFV1CiiADygAah1OvIKi3CgDbuZOwJD2do6crp6NKOQRlf9xwrwoLhZ5imDeaTKKqhQ8oLJEepzm1vasXn6sRS4+ZgBGYSWr3enzIQXcLAAwgBRAByABUoQAlcTQ+FIwFtN4fZgAIkAvBuAMh2ceJOioUGoNv0SasyRS+ogMVB8JcoFRyKZnssZGQDABrNzgJiNADMYigovEAJebSqtUeCjY0tZNxgdweDTYQA
[5] Запустить: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQaG2UIAhgHYAmk++IArhQBQCUdAzigF4CmzAFgAMQgDRRhQ9vgBGKEFQD6GLlhRgKUALxQAarwDGWTMwDuKKlgAWUAPRQATOKu8UAcys57D9nIWLKNwAbXm1SShoIADomFGBMCGYAWgAFAElbJyh0zN95JQ4YXl4qMIE6Kl5gKAgwADdeRT8qNgAufChOqGblMFV1CiiADygAah0ewuLS3CgDPuYewJD2Lu783v6NKORx9f8pkrwoLhYlimDeaUrqqhRCoLJEJvy2jq6sXiGsRS4+ZgAjMJVh8vj8yEF3CwAMIAUQAcgAVWEAJXEcKRqJBnU+32YACJALwbgDId-HiHoqFBqbZDckbSnUwaIa5VKBUcimN5rGRkAwAazc4CYLQAzGIoGLxMD3p1ag0Xgo2DKoMqAMRQQAEIIAOEEAgiCAYRBAKwggB4QKCALhA9TrAEIggGkQZXAFBBILMcUAkTiKSddWAdBBAAwggBYQH3GqCAdhADYBuEANgF4Qa2AThAoIAxEEATCAGy1QP1hwDyIGaLZbAHwgieVIEMWDMFmsdkc7vE5ksNm8zlcHiwrE9UEAWCA5qCAfhBc37u5atfGDTHlXcHk8FS1saRi6XaxWHGMoK7xeKa+X61AXO5PC3Wx2rVBI-7+4Ph8qgA
[6] Запустить: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQaG2UIAhgHYAmk++IArhQBQCUdAzigF4CmzAFgAMQgDRRhQ9vgBGKEFQD6GLlhRgKUALxQAarwDGWTMwDuKKlgAWUAPRQATOKu8UAcys57D9nIWLKNwAbXm1SShoIADomFGBMCGYAWgAFAElxdN95JQ4YXl4qMIE6eLAlQJCw8mpk9My09jKlKhQOLEoDUJ0AZjwoc0sbezh8ZuUwVXVNHX0jE0HrO0coAGoocdb2ztDcKANJ5nHK3lZnVw8vFfXNto6KLv6uFmOKYNOmsHLFLj4wgEZhHQqLxgFAIGAAG68RR+KhsABc+CgKKgcImUw0UQAHmsdOi8gUinsDhxmOiTuxUWichiUGoschVvjaYTCk8UCwKW8QtIQWCtjAgmRELCcojkaisLxsVgfjx+ICpJKUdLZQEgu4WABhACiADkACq6gBK4j1RtNVKlMqwzAARIBeDcAZDv28TolT06Y4920z0MihRRB80FQQXC0XNCXUtVy378cbx62q20arXMC3Gs1QTNWlVQWMOwA8G4A9fbdGy+Sn93ux4nG1cZrGpzZR+fw-LD5FM0dRMjIBgA1m5wEx4T0xFBx+JhMnwVCYXC2PnwyKxQol9SV5HK2wgA
[7] Запустить: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgCMUIACYB9DHSwowJKAF4oANUYBjLJjIB3FCKwALKAHooAJm77GKAOb6cJ01SGixAQxLWANowVQQ7kTIAWgAFAElucKdhcRoYRkYRXxZqYDAwcXcvH0V-EkDQiKgo-DSMsREUGix3VRyoAGY8KB09QxM4UvTxSRRpWV8VdU1Wg2MzKABqKDLxSuran1woVTAaMlm3D28KCytbewnpzfmakjrmunJNrJ2qTbomXwBGdmoRRmAoCDAAN0YxM5AhQAFz4KAQqBeMACVyeKBArbZKDgyGI3r9EgAOgAHlNFIi4gkkstVutEbdGFRIQiYhI1n0ZNjkJMCXSiYlLihyBTtlTqDSAMRQQD4IIABEEAfCCAJhBAKwgYsAXCCABhAoIBeEGVgBYQCWAQRBAEIggA4QQBsIDKVXqZVB5WLFYB5ECggFkQC2KtWoiEoL5kdEMzG4qAAHigbCgmFpLgxTO9AD4WroxkHnTTgz1PWHkH6A0GPVJk1BI5YbHZQXGhaLAMIgusAMiBQQDcIDL9TqoFKoIAxEGNOrF3D1KtlYv1YuLMsAPCBQYuAZhAJZXC5Duf9sEjvJQBZDheLpXKlaqNdr9UaTWbAPwgesAkiB6uOuqBkU7uumh2S47gZxk3xDcTbX7E45-demZx8UX0zT+PD4DgFvGk4kNOWCzsw-AfF8U6MDOlKUCCNJxtCsLwry2Rxlh3i+LhPjTOE7yfFA8wwJ4riIICMTIXGWCMDikGAWQrx8PRjGQXCNjkAAwgAogAcgAKvxABK3ACSJ4nUpCDFMWQABEgC8G4AZDuKXeV5Jje74Jl+D7MjBpHkZR1GzHRNLycxDDMA8NmyRCVluJ4PFkFJokSVA7kyRxCmKYAPBuAHr7Gn-uUr63qFibfoZoHxnG+CwWR-haBZaKuKoADW1jgKQgQNFwjQFewDnfH8AJAvONImVRYjmSV1XURVFBAA
[8] Код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGMANgEMaNKACEUIACYAufFGVRZjYFAD6mlCRRZtZGoyHBuAD26JuNGI0ayKilS6jHTAOgx0sKMCSgAXigANUYBLEwySyhEKlcVd2APERIAcyFGIKgQVNkyAFoABQBJblL4hLcTZNt7WWy6hyUVFuU1DQgwADdmJKc21ySvMB8-Eg9zKABqYOGmhtwoAVGjGpT0zMqE4e99cY9kWerPBbw3XTXPVIzGfirUDSvkvd9-SagAHig2KEwTl6jfbvKYAPigAHcULIsAALP4gKCDB67IFvCbIb6-f6osbvZDg2GMFBpWFYAYPFzDXS9bCaG6ZSjUB4oJ6yFA0LDPEZ4iYxXHAjHcYBgMCyTSvA4xEViiVog5xL5QGXiuhMKAAeigACYKZTlNSSLSDAzmBR9QlmSoOqgjYw6abnk4XMjEutTY13ZsstMoKUre11KoOTBRIgnc4qlhGOYDGrmABGdjbVzR2P0oQk8gAYQAogA5AAquYAStw80XSymXGmuQAiQC8G4AyHbrNnWkpBbc8HYx-AARjIGsFpHIyFCYfCtdruESSWTNTruCx+Cr6d7srkSPlimU-SUqKv2ZzUgIssEAMzncdwhdwfCrnvZMIRKLXyc6mbK0Xio9YE9ZJYVhoMhV1NCgZ2JUkcCnT9Dw5P8SFPc46HIUDvQoA9v00eNsiTNhqBtI9QxERBNBVShI2UWtsIYZhV3jFNqJETM0hzAtizLKAKw4xiY3rQAeDcAPX3Wy-WUe0mYUsPExV9QIoNZFyCEKMGPsRAEABrNJwFIfJzy4KA9KXPhBiIsMyO-JkXAHOQPC6XpLJUazZA8UySKZIA
[9] Запускаем: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21dQGMANgEMaNKACEUIACYAufFGVQAkgDlVAFVUBBADIB9AKLrjAJQDiATSgBeKAHYOygMRRAuCCAGEEDiIF8DcIIAyIIC8IIB8IICsIFCAXCCh-oAcID7hgIIggEIggEwgoVCAsiDB4YACIIDMIHFxUIDCIFCA-CApcYBiIEoq9cqyjMBQhoYoJChY7WQ0jELA3AAe3IjcNDCMjLIUiioLUP2DAHQYdFgoYCT2UABqjAJYmGSjUIhUiyrLwCsiJADmQoy7IPeyZAC0AAqq3L+XK5LAa3SbTWS7MEzRqLG53IQoABuLwcWmILyBMIWcMYJEYIAeyAc0jkKw02j0RlMFhsbiggCIQcIVfKBSrVGqAaRAoHFADwg4UAciApKCAFhBQqlShVompNDoDCYzFZrDCYc1WhAwMi+iC5liVChWiQwDg4SIEcj5kCFiBGFgiCASLqro6oO56XkvNUedlcoU4vznTi8QTkJ8HHCobJnc73IB8EDyoTS+SiXm4YpSAS8SVZ8W9+SKgHkQZ364GrXH4wlQAA8DjYFstyhNZpRUAAYqb+s6rTa7Q7LQGQWswBstiQVsMoABqMMDiN4KACIda1b3J6MQFXOHrbojlbIKcl0FTGZzujkE2PZ78S3Fpe3LebbZjqtQNhQTAHwfDx-jgB8UAA7igshYAAFm+IBQJ21wDveO7IJWL7gR+sGPsgf4gYwKAPCBWA6vW0GrJ0yLYIYK7PJQ1DXq0ZCyCgNBYLen7bt+EwwUOzGjuMUDAGAYCyIYKGjmcPF8QJ7EPpxFDPiJ-F0EwUAAPRQAATHh+EfkR+I9GRzBSfhUENgOZbBrsJKyGSMqUvKNJKiqLSoCQxHaRezA3HMCz9suLmQgOOmTlAvyUSoqpQLRkyiIgt5qVcWCMMMPRycwACM7DrossXxaRCIPOQADCphaBY3D5eohXmGlCzACgQhCGQylwHA3DPCAMCMcZhLcGZFkUnK1KKtwXAqQ1A0UBVKgZQxABEgC8G4AZDuTaxqyCWOi13uJcH8AARjIELEjtZCAcBYFKcp3AYVhOGKSp3AsPwMmkd5DhvCQHw-H8AWqFQ91hVg9wCM2ADMc6HaBV1wPg92CbsBxHCcIPHSp-nfXRv0kP9c4LjQZD3TpFBnZh2E4CdSO8fxP1-S8uBLJ02Okw9q6jRDdOJbsKVsNQIVhTAEWGDJlB1lAE2GIltOiYlaVC6aWF5QVRVQCVZVpVVNV1Q1EtxVNgA8G4AevsLdxdPLcJBvrahen1hz9myG8-78zCm0iAIADWDzgKQHwA4NHs3XwKp0dzIiILzpMUQs22kuqmppWH5lcxFFFAA
[10] Запустить код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO1AMYANgCGNDRQNiggACYAXPhQCVB2JnYAKnYAggAyVgCiJrkOAOIAmh5QAOwcUPGJtQlRjMBQVlYoJChYrWQ0jAHA3Bh0WChgJNxBJADmAYwUcYmLUL39AHRDnaMk5RsjY-VLK8CrkzOM5aezB4tHqzQwjIxR5QBM14m3QQEoAG7nnqliOclgl3glbowSIwQFNkJ4ItFVsk0pkcvlCqUaosDo1mhAwH8en1gPMwahmiQwDhPt8-gsQUsQIwsEQQCQydiGctiatIdDYVAALSeW73R5RMlklDNCFQmHIAA8njY9K54J5X1+-ygADEvr0OYkmSy2ZKubddltVgAPKAAahFPLFTzwUD8YBoRLWlzmZItHs2Y1WyAd3LWzueuGW7S9xx9-C50qgsfWAb2JBtUAVUDYUEwYeOlqDtoAfFAAO4oKJYAAWeZAWLV6rWRYzipz9YLqeGVuQZZrjBQUxrWFJTebx3af2wVh9lGoieaZCiKBoWBTrZt3H9PaDiG4wDAYCiVk31oPR5Pm8QFCzUEPx6sdCYUAA9FAXmPx7cp9CunPbybQ0J15OUBXhSIoiRFJ0myPICmKEoF0SXFUBIad-2mWZY3mTkGU+LDtQIs57SgAAFOxkIaJooBXe5gkQHDVSWLBGGtLpn2YdhbzJVj2Nnb4pnIABhfJUkKbhRJMcSHCoLlgBQAIAjIF44DgbhZhAGAUz5eVuARKDkVgtEENKbguA-NTzIoOSGT49cACJAF4NwAyHYc7ceTPDyWzTXt+CEQBCEEAPhBAHYQQAWEFEGQpCgKRRBUdRACYQKA1BCqBAH4QOQ1H0fAACNILCTwAG0DLIAA1Rg-CwTAyEras63fF5uAHIcRzfD8KG4EBJiiMhBQo7gKJs+98ysNCoC66ZmHMax7GcFwKAAXWoB8Tx9coJp6vq7AGuwqBWqw6KwSY-G1ABmV1atrNq4HwfbW3KcrKuqy76o-Uj9sO47zijd1PX2+MmsHYccAa97LwO1cjpIE7XToch-sImzbvBzjyi8dhqFQuiYAYqwVsoZj7KfBhmH2zjbISInNSEsgpJkySxMKCn70U5TVLgZn7LIBzAB4NwA9ffc4bHy8oWr18vdALVTGaKiLrywJg4cqCPwAGspnAUgetOizte4bicVXHGgkQPHL3nPCEkPBs8uiMabaiGhmMWe3VnxQlmedyDVmxhj5yAA
[11] Запустить код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO+C2YAVAEEAuwB5EysHEIBRDyg2ADoAJigoIUAkEBlxQD4QXTlAXhAclTlAGRAoLTlRQzUoAtFAfhBJQCYQbRkCtV0oTSgGnLkcqUAuEBzm6gBjABsAQxoaKBsUEAATAC58NLS7EztQoIAZKxiTGIcAcQBNeIB2DigNzYe05cZgKCsrFBIULA+yGkYk2A3AwdCwKDAJG40xIAHNJowKOtNiioACgYlQT8ISR4ljwZCnqj0cBEjD4Yx4uSEUSUSTEjQYIxGMt4slaZt6dNJigAG6UzwBYiU1FpDlpemMEiMECw5CeRYrRLbXZ2A5HE7nK7itGA0koGhWECMLBEEDfOHxABi3IBRKJLzeEDA-P+eqROpQbxIYBwXJ5-ORotRxtN5p1KJ1kulsuQAFpPPTGczljrPW9ozK5VAADyeNhB4OcvVkgMCqA2yZ2oso0Nmkhpov0-E4xIADygAGpEyXkyy8FBxmAaG6MdTEVGSy3IYlkN3dRi+6zcGivqPSeP+EWvVB15jh9iZx2cwkoJgF6TpyR21AAHxQADuKGWWAAFmeQPca8WMVfZ7nT3PZsDwJa9kHvV9GBQWFXywD1vwlEsvn5bArHHShqG3N4yGWA0sD3P8224YCwVbRBuGAMAwGWKxCIoqiaL-RAKAAyjqKsOgmCgAB6KBknghD6WQmVfnQljvwjH9SSlLN5QWJZlmVHY9kOY5TkuSTEIxA0jRNesvlheIhSIRhMM2R1UBIFDRLhBF1yRSMmxLcd4i5WzKU7KAAAU7DM55XigIgYGWaYsGYEkBNFelnVdKgnIxXDGRmRAMJ1IRhFyZpsl0GQpG4epAFEQHJABYQNQ5BULptFqBo5DUfRRCgZooCGcRNEAZhAZCgWpmhyQB2EGaSRAEkQUR5AqqAqqgHJ6h1cYpTCkBaJAnF4gANUYcYsEwMgnxfd9eOSbhIOg2CeL48ShEAMhB2gUKBAFkQFrRGmrCL0SHS63NAyoBhVkSMPa9Evw2aSHmxbSMhFiTzgVY0iEOMoEkUrNBUZrWrahrJF6qQikANhB2k6TSXrevSPstTxK2rBD3txeljRgcBliIWaMKLKmoAAbQAXT8qALNp+nGfC91C1RaUHysAAjBT5k8TnJ20qyRLQ9zmeDHcQG+sguG8CGoH8YJQgiKJYmhgmXM8dWSGWMg4x87gfPOqBAEQQHJtFKQAJEFELpmgkNRqk6bo2u0UQdUBAFhaLM2XpczyLatuMki8bgE5YoRAFwQGRAEYQF33c9xqfb9rp2qDnVRYlqWyRgJlLbIRUrbWjatuSDhuCbvhoXcig4uDUvJZWGgK6rq3a7IevNpAMhW5bjgKHbilO51Vme6lotuYsxKYGS+zw82MK21+TjmHYFidV30SeVhcgAGFjgCU5uGvkxb4cLvRWAFBJkmCe4DgbgERAGA9wyVjNwWuSlVTqjUlqJOLdv5J3nkWU+ZAABEgBeDcAGQ7SDiJTiWkeLBv4cFgRfqiHcQlDRUwMtvUUp8OIMGYD4Y+CEoCIKQYAHg3AB6+5gl6hEoBwx8Hgy8BD-y8L4NQIQgBCED6sVEaUgKiiBUOoJqaheq9FqvofAvdljS3ZsPUeW0dpvlOgdKAR0YI4H2jPKAsdra228nYTuUBKKfisJZSx5JmDmGsPYZwLgKBc3wGxGikcrE2zsHbOx-iGJWABjCWa8QADMA59F7SgHACJ7EryrXWmPbaz4DH7S7A4yJ0SSCxJXEOEcASlZz0OlBUxhiCmVOKaU1c5BKmbioJUg+8QvDsGoGvA0G9piICsAEygwtqEHzIJ02hRDqHcmglfG+d8oAPyfkQt+H8v5wFmYwPeyD2GcMqXRQp6TBHMQQn0gKyx1YPjGUSeEYBxbcigBomgRInnjAANawnAKQK2cStYAu4EfB0AzkojIYirMUKIl593iJzGGUAJG9SkblVQDQ1AqByEMKAxU9B1FGIoAqKi6pEkcS8hSLjXmUKgLCzRiRdlhWrhoxIQUQphUoA7QAeCAZyKK0PGnUap1S6r0F2mhADiIAKglzQiXvOXvOOl8x0hQEACggOQM6iFaDlGRfKiUkv0M1VQmhBoyBKM0TQgA5EEGhoOVcKZYaMKZ+B1XwKVwp3Cy+Z-IObKsAMQgUi9BoqkIARRBxByBlcSoVaigA
[12] здесь: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO+C2YAVAEEAuwB5EysHEIBRDyg2ADoAJigoIUAkEBlxQD4QXTlAXhAclTlAGRAoLTlRQzUoAtFAfhBJQCYQbRkCtV0oTSgGnLkcqUAuEBzm-AAxMLCnKwBhAAkgkwBxGKs7EwCYhwA1IIAZeOS4NjShQAwQArls5tFtKDVAdhBZAvbO3pzHtRqoGUAWEEU+HszisLgACjEYk4jtQAMYAGwAhjQaFAbCgQAATABc+DSaQ2dlCBysMRM22WAE14gB2DhQPH4xlpTGMYBQKxWFAkFBYTlkGiMeHAbgYOhYFBgEjcREkADm8MYFFx+NVUEFwsSYt5kpI8W1EqlzLVGuAiVlCsY8QtiuNqtNiRoMEYjEx8WBM3BkKcdvxDsR8JQADcrZ4AsQrWq0r60g7GCRGCA5chPOisYlCcT9qTyQ4qQyo7GhWaUDQrCBGFgiCAefL4uMA4LjcbWeyIGAQwLi8qY6h2SQwDh-YGQyrC6qK1Wa73Vb24wmk8gALSeB1Ol2Y3u9lDs+eJ5NQAA8njYY-HRc1AeDoagDfhTfP+Mn1ZIW-HDoNusSAA8oABqVdi0dZ1XTwKBYTAGgu0veVFSod8gM-KVEmQAD1SA9dQNwdVuWgs0bSVahxx3KA8K1SCdWQ39DwSKBMHQzUkJIH8oAAPigAB3FBMSwAALOiQALR8GLNJiUKPWj6I-CjDWY5B2N4xgUDlXisB7YSRMSbkQ2wKwCMoIjCxIshMVLLAyLE79uGk8Uv0QbhgDAMBMXI2yqIcpyXLExAKAkxznMdBgrQAeigZJ1OEh1tMTPl9N8x8Zz9ID433FM0QxFzMzsEkyQpSlEovEsy2fGtuTleJwyIRhDJZNlUBIHTYtg5hTWVWcEJgy14n9Zr-ygME7BqqBWygIgYExREsBa7szxNID207eDCwdUynSRRADN7IRhFyZpsl0GQpG4epAFEQHI-jUOQVC6bRagaORvlEKBmigIZxE0QBmEBkB5ns+ZpJEASRBRHka6oFuqAcnqXtYXjKaQCsJj4h2RhYSwTAyC4nj+NC5JuEU5TVKgHH4qEQAyEHaBQoEAWRA3tEKHiN3IDS3LSsXzKqBZTdGzKOY1bzJhkg4YRmTdV8mi4GxM4oCXKBJAuzQVFe96PqeyRniKQA2EDeXQCs05mStrcrPDvB9hINzSKxgcBMSIGGDPHc2AG0AF0hpGy3rdt6bhQiqMEw4qwACMMtRTwXbnJmGpivTmvtoz2RATmyC4bwxagfxglCCIoliSXdYI+JE5ITEyCXAbuAGkmoEARBAcm0UpAAkQUQulucQ1Gqd5Pu0UReyFQVZvHAvAM6xU+qLkulySLxuCn3yhEAXBAZEARhA68b5vnokdvDC6Lue-Hf2g5D80YGdYuyDTEvkdR9Hkg4bhb74GVmooJa-cYAPg6xGhj9PkuL7IK+aMQBkAfvfDgFAn6Whfr2c2B9P6YlRFGN2dVVowHWnhX2aoprfj5HQJgrA+BCSjNg2KgY5TkFmGSLYDhuCUM2NsV+apgAoHhPCEBcA4DcEVCAGAZEUqLm4BfDMJgiTZWzLlPMlIZ73w4TPaB44SFkAAESAF4NwAZDtKOsohEW7lNLeUYaqEiUViqs1KvKAehYSFWDwcwHwvldaKKUYAHg3AB6+5ovROjmK-hlj4LRjFPHiR8XwOESIUS3k8rNEanJuS8n5K1CxhVApMHiF4dgEdNRykrOWTmkBhZuXIPwVUI1Ml8nHrkpiGCElQH8piGOXVPDj1LuXfqdgDH4hqVYPmsoYbxAAMxgUxnxImUA4DpNEp4pGKMgEY24kMnGfUOldJID07CEEoIdIIhAqA+MVI4HmX+apnlOlmW6VabCdByAbOfoU-EI0Fre2AJg1UQhAB4IEvIorQDpSA+F8QwgA5EF+ACbc7JQCIggIwKwEFSA4AAKS3imDMBYSxVjrHobsA4HgTxVPtEBEp2Ti7lM8ZQIhJKRqoPQfE3sVibFkRsW0tIVirzkLIHQ6htCqEMN7Mw1h7C4D0qgI41x7juayR-H48Z+SUL8HgaHKAjt-6APRoM7GYU8ZKV2cM8K3BGllzsBXVpvlHKCSsPVKARdMlkHMNYD0LgKCuxqfWTyxLZz4DJYnDilBZoKjAIHAMUAZXGl9bCAA1nKcApAS69JTlG7g7BGE1MSPcuOaQE3ksRBteKzZVRwJDvEF20ZVRGv9RlU1Mqqk5q-okRgOD4wl3gYkMaE0pqUEzaqGV-5PAVoQQW-E7aw7wMOYJAd3Ji1fz7KOlyV4QzOwZMaV5Awl6SC1h0b6IxbqAHEQGQJRbi9AevoZ6HRHg9BppIem7SWFsOOHy401KgpkC8AANkYYysh5B9gxHGAEZ91bzLACUcIPdksADeipyAyooAAXxEDkNdbwZDAdBeCyFYBoVgQ9KCCEUIiahSEVlHKuYqQQfcb47Z6rCZBJuVLHaox9qHW4MUKot0VDlHBhrNQzRFDfXut8QEhj+yDgnTQKpQbQ3hrPjGqAEm41covby6RCR+W3vwb08KVKf16VfSyjlDhFM-uUcIF5gAiEEAAQggAEEEAOQggBUEHni89xyrNVqoJnssK-KBxWHhE5XhVAgA
[13] Главный код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO+C2YAVAEEAuwB5EysHEIBRDyg2ADo2KCghQCQQGXFAPhBdOUBeEGyVOUAZECgtOVFDNSh80UB+EElAJhBtGXy1XShNKHrsuWypQC4QbKb8ADEwsKcrAGEACSCTAHEYqzsTAJiHADUggBl4rzgUtKhADBB8uSym0W0oNUB2EFl8to6e7Ie1aqgZQBYQRXw9mcVhcAAUYjEnPE4NQAMYAGwAhjQaFAbCgQAATABc+FSqXWdlC+ysMRMWyWAE14gB2DhQPH4xmpTGMYBQKxWFAkFBYTlkGiMeHAbgYOhYFBgEjcREkADm8MYFFx+NVUEFwsSYt5kpI8W1EqlzLVGuAiVlCsY8QtiuNqtNiRoMEYjEx8SB0zBEKcdvxDsR8JQADcrZ4AsQrWrUr7Ug7GCRGCA5chPOisYlCcS9qTyQ4qQyo7GhWaUDQrCBGFgiCAefL4mMA4LjcbWeyIGAQwLi8qY6h2SQwDh-YGQyrC6qK1Wa73Vb24wmk8gALSeB1Ol2Y3u9lDs+eJ5NQAA8njYY-HRc1AeDoagDfhTfP+Mn1ZIW-HDoNusSAA8oABqVdi0dZ1XTwKBYTAGgu0veVFSod8gM-KVEmQAD1SA9dQNwdVuWgs0bSVahxx3KA8K1SCdWQ39DwSKBMHQzUkJIH8oAAPigAB3FBMSwAALOiQALR8GLNJiUKPWj6I-CjDWY5B2N4xgUDlXisB7YSRMSbkQ2wKwCMoIjCxIsgByHIDS3LSsX25OUhI01JZTdTFSywMixO-bhpPFL9EG4YAwDATFyO8qi-ICoKxMQCgJP8wLHQYK0AHooAAJnU4SHW0xM+X06LHxnP0gPjfcUzRDEgszOwSTJClKQKi8SzLZ8axs+JwyIRhDJZNlUBIHSctg5hTWVWcEJgy14n9Qb-ygUE7C6qBWygIgYExREsCG7szxNID207eDCwdZynSRRADN7IRhByJosl0GQpG4OpAFEQbJfjUOQVE6bQanqOQvlEKAmigQZxE0QBmEBke5AY+JpJEASRBRHkT6oG+qBsjqXtYXjDaQCsJj4m2RhYSwTAyC4nj+OSlLuEU5TVKgKm8qEQAyEDaBQoEAWRAQdEDHiN3cymqslq60czSxOO1ysZIHG8Zk3VopouBsVSIQlygSQ3s0FRgdBsGAckJ5CkANhBXl0erNIs5ra1szw7wfYSrc0isYHATEiCxgzx0dgBtABdBalud133c24V0qjBMOKsAAjcrUU8P253Mvrsr0wbPaM9kQEcsguG8BWoH8YJQgiKJYmV82CPibOSExMglzm7g5qZqBAEQQbJtBKQAJEFETobnENQqjecHtFEXshUFbbxyrwDxsVGaa7rpcki8bgV+ioRAFwQGRAEYQDvu97wGJEHwxOhHsfx0jmO4-NGBnVrsg0zrwnidJlKOG4d++BlQaKAOiPGBR1jliGgt9751yfmQF+JMQBkC-p-DgFAf6Wj-r2R2V9gGYlRAyFsPVjowFOnhcOaoNrfj5HQJgrA+B2RIYwMhelAxynIDMMkmwHDcBYRsLY-81TABQPCeEcC4BwG4IqEAMAyLFUXNwJ+GYTBEiqtmGqeZKRr0-sIteqDxykNcgAIkALwbgAyHd0Z5RCctQpi3MXJHhqoSKZUFlOa2U9Cw6KsBQ5gPhormx0WQXRgAeDcAHr7JjLEhWYr+NWPhTGMSseJCJfA4RIhRLecK20lqcm5Lyfkw1nENXikwQ47Ak6ajlJWcsjlICy1CedVUS0Sl8kXhUpiRCclQFipiNOE1PCL3ro3WadgbH4jaVYCWsosbxAAMxgXJnxBmUAYRjVElYgmRMYFk24jMqmM0hkjJIGM7CEEoJDIIkgqAtMVI4E2X+Vp4VhkuVGVabCdByBHN-vwGpPU9qh2AMQ1UQhAB4IDvQoLQ7pSHeJ8QwgA5EB+P8bc7JQCIggIwKwEFSA4AAKS3kmNMeYiwVhrC4TsfYHgTwtPtEBOpZTa6NKsZQGhuD2T4MIdk3srj3FkXcQM1IrirxMLIJwthHDWHcN7HwgRQi4CcqgD4-xQSomLNCT+OVwVKLWOoJg+OUBvaQOgaTaZlNUo0yUuc2ZaVuDdIbnYJu-Tor+UElYXqUAa4lLIOYawHoXAUH9m0+s4VaWznwEtTE2cOKUG2gqMA0cAxQHVcaSNsIADWcpwCkDruMvOabuDsB4W0xInyM6pBzYyxEZ08rNlVBguO8Q-bRlVLa6N5UHXqpaRWkBiQ6EbQfpgxIK01obUoKW1U6r-yeBbVgmt+Ih0J0wdcwS07uT1pAX2BdQUrwhl9jg2t-DBEpWETw1lCUyBeAAGx7vbQw5S5A9gxDGAEU9ZCyDAF0cIP6+hlYAG9FTkHVRQAAviIbIwxWjtBkO++FiLkVgFRWBD0IJwSQgZslWRlVqq5ipD+4JkTTlGvpnEt5+ISKmWXTQFpcbE3JofhmqAlGs0iq3eKtRCRJX7soeMtKLKz08uYUKhwTH22+OEH8wARCCAAIQQACCCAHIQQAqCCbz+cEvVJrDV0wualSVA4rDwgChIqgQA
[14] использовать черновую версию: https://khasang.io/p/javaprocessing?id=eae4fb99bff7dc7f5d0da209a6ba4b5f
[15] код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO+AIImAOIAMgCiVhZmACp+UXYA8iZWDgGBoR5QbAB0ABxQUEKAKCBqooD8IKKA7CCAfCCAvCBQahWyNTI1arpQmoDMINqi+PbOVi4ACqGhThlw+BZ+ABq2jq4ZAEwcbPlCgDggooBcIOpSotqAMiA1VTJQ21XaaoDiIDIqcoBMIFVQpXJq+vgAYvHxToN2AC10p4AGxsagAYwANgBDGg0KA2FAgAAmAC58Pl8nYTHY4n5glZQiZQg5AgBNDIAdg4UExWPp+RRjGAUCsVhQJBQWHZZBojChwG4GDoWBQYBI3BhJAA5lDGBQMVjlVB+YKsiLueKSBlNWKJYyVWrgFlpXLGBkzfLDcrjVkaDBGIwURl+n9hqMnDasXaYVCUAA3C2eKLEC0q-Le-J2xgkRggGXITxI1FZHF4uwEokksmUqOqgUmlA0KwgRhYIggLmyjKfP38w2G5msiBgIN8wuK-MoVkkMA4X3+oNKiMqssVqv55X5mNxhPIAC0njtDqdKPz3dZs-jiagAB5PGwR6OfYXTUPg1A61CGyflePKyQNye7XrtVkAB5QADUy7Pq+dPAoAhMAaA7dUrQVGczzfCUsmQX8C3VACXVwVVOXAk1IP4E8eygTCNVArU4K-PdMigTAkJNWCSE-KAAD4oAAdxQFEsAACwokA6TvU91Ro+D93IyjXyI-VaOQRj2MYFAZXYrAu146Mz05INsCsSDKGoXDWTIPsBxUksHyrTkZR4pTlWlF0UWLLACIEj9uFE0V30QbhgDAMAUUIlySPczzvIExAKCEjyvPtBgLQAeigJZFKUu1VPjHlNJC3ipz4k1Yx3JNEWRbz03xQliVJCkMuU9Vi1LctH1MjJQyIRhtKxZtUBINSUtleVMMVacXzPSCMl9LqLW-KAhjsZqmRZKAiBgFEYSwZhjXiiM7VbdsqH69UbIdWFEC0-MhGEcQqgeGRxF0GQpG4GpREAURAqkAFhA1DkFR2iuF43n0UQoAec5xC6M41D+qoKgeSRAEkQUR5HeqBPtqXoTwhWMlpAKwaIyAA1RgISwTAyBYtjOJipZuGk2T5KgUm0qEQAyEBaBQoEAWRBtkkO7NyorIquM6szKsrmBN2uyUZINGMbE7UQrIuA0XWKAFygSQXs0FQAa6X7JEaE5ADYQFo2nKrmeZqkya08a9byU3mubLGBwBRIgUa0k9rYAbQAXSmqBWtt+3HeWztjxVPD5XIAAjfKaBC+jPGmOY3RcIOXZNnUPflwBUEBUT6LiuW57ieL73igJ6qnuNRumefZdg0TR9lus4VDBp7RAeGGpCgE4HkUe7n1HOMmKsCPUQRTwPegyr2uSjSRud0dBr-CCRp-KAQCssgF1SMIImiWIEiSFIglCbhN-CSIYjiRJklSUIQvzfvB8j00YEdEgUTIFM35xvGCZWLhYo4CgUoRoUC2n3RgA8h4ohoE-F+b8P5kC-vjEAZBf7cF-oAqA2FQERmtvfSBCJRxe1artGA+0epJyxEtD8PI6BMFYHwcyEYqEpX9DKcgABhYkURSTcE4SYbhDhsEqmACgKEUIUFwDgNweUIAYAEWyvObgH80y4iKtmUq5JuB-yWJIrRID8zMLIAAIkALwbgAyHaMU5GCks-KCxsRJIRyo8KJSMinUyFCmGMGoVYWhzAfC3wsoYoxgAeDcAHr7li7G+Vol+RWPgrH8XsYJWJfBISwnhFeAKQdWrsk5NyXkK0PFc18bWH47pAShHHlhJeh5KlZFXjZIgI9mKsQ4tTWK8tAAkIGoaup1W41BOGcSQKh7hVF0K0GQtSUIZGyBwJYBQoCAEIQC4p17iHD+lDfWugiEzQ2gHQUq0jQDSXohFcjpnS1Mxp4RBBMiatNJsvO09SUCNKAiBMCw1zQYMNhZUcFM5I4HuWNR5MIGkIjQnQcgHz5T6L6i1GaJCyEFIMV4mhkUCK+McZQlFGlWEcK4TwqAfCBGYvyCIsREi4AkqgEEsJETnLEWifE6iiTgrUHwRkV28DrnINuSTWK5MZL-LaXFbgq9X7rwmtwCaICoAeW4lYNqK8zTMHMNYBOFBPZhRdObAKlAVTUGIavJilAg5yjAGHP0UB8GNicb2fsVrI6FItRCAA1jKcApA34AGY-4+u4OwKlZLxE6KkZkPRyLvG+LIF6uKEaWGyTxfw0kVKgnCEAHgggAiEEAAQggAEEEAOQg6dAC4IGmiJvLhUCspgC2KVLeY2qxM6t1HrxV+qgC2gNhotVZF2bPUlAUsgIphAdNKdb8h4Mjhy92kZlRyodaiRV+DCljuHlkFFsY36QKyHNBaS1KDDuVOyxCS6oFTvreO0ekDZWUQvZyWdx68Ibr9IGRgk6vZBopUI5hPi0VeBBB+7Fj62FkDCJ8KIf7qFkGAEY4Q305YAG9Q5kHwRQAAviIKoOd9YyDg6AGEEBGBWBAqQHAaE3SDBGGMamMVlGFUzMVHMFJkMRLiVAP5VNklUCAA
[16] Интерактивный код: https://p5py.khasang.ru/ide/lz/GYJw9gtgBADgrDAnlAlhGYQBcoCoBQIArgHYAUAlPvgM4oBeApmQCwAMbANFO21fgGIogfBBADCCABEFGAeEECsIICEQcYGkQKIEEQQBwgUwMIggbhBA8iCAxEDVr8AOQCqAWQD6AIQCSAJQAiAZSgBeKAEYO+AIImAOIAMgCiVhZmACp+UXYA8iZWDgGBoR5QbAB0AMxQUEKAKCBqooD8IKKA7CCAfCCAvCBQahWyNTI1arpQmoDMINqi+PbOVi4ACqGhThlw+BZ+ABq2jq4ZAEwcbPlCgDggooBcIOpSotqAMiA1VTJQ21XaaoDiIDIqcoBMIFVQpXJq+vgAYvHxToN2AC10p4AGxsagAYwANgBDGg0KA2FAgAAmAC58Pl8nYTHY4n5glZQiZQg5AgBNDIAdg4UExWPp+RRjGAUCsVhQJBQWHZZBojChwG4GDoWBQYBI3BhJAA5lDGBQMVjlVB+YKsiLueKSBlNWKJYyVWrgFlpXLGBkzfLDcrjVkaDBGIwURl+n9hqMnDasXaYVCUAA3C2eKLEC0q-Le-J2xgkRggGXITxI1FZHF4uwEokksmUqOqgUmlA0KwgRhYIggLmyjKfP38w2G5msiBgIN8wuK-MoVkkMA4X3+oNKiMqssVqv55X5mNxhPIAC0njtDqdKPz3dZs-jiagAB5PGwR6OfYXTUPg1A61CGyflePKyQNye7XrtVkAB5QADUy7Pq+dPAoAhMAaA7dUrQVGczzfCUsmQX8C3VACXVwVVOXAk1IP4E8eygTCNVArU4K-PdMigTAkJNWCSE-KAAD4oAAdxQFEsAACwokA6TvU91Ro+D93IyjXyI-VaOQRj2MYFAZXYrAu146Mz05INsCsSDKGoXDWTIPsBxUksHyrTkZR4pTlWlF0UWLLACIEj9uFE0V30QbhgDAMAUUIlySPczzvIExAKCEjyvPtBgLQAeigJZFKUu1VPjHlNJC3ipz4k1Yx3JNEWRbz03xQliVJCkMuU9Vi1LctH1MjJQyIRhtKxZtUBINSUtleVMMVacXzPSCMl9LqLW-KAhjsZqmRZKAiBgFEYSwZhjXiiM7VbdsqH69UbIdWFEC0-MhGEcQqgeGRxF0GQpG4GpREAURAqkAFhA1DkFR2iuF43n0UQoAec5xC6M41D+qoKgeSRAEkQUR5HeqBPtqXoTwhWMlpAKwaIyAA1RgISwTAyBYtjOJipZuGk2T5KgUm0qEQAyEBaBQoEAWRBtkkO7NyorIquM6szKsrmBN2uyUZINGMbE7UQrIuA0XWKAFygSQXs0FQAa6X7JEaE5ADYQFo2nKrmeZqkya08a9byU3mubLGBwBRIgUa0k9rYAbQAXSmqBWtt+3HeWztjxVPD5XIAAjfKaBC+jPGmOY3RcIOXZNnUPflwBUEBUT6LiuW57ieL73igJ6qnuNRumefZdg0TR9lus4VDBp7RAeGGpCgE4HkUe7n1HOMmKsCPUQRTwPegyr2uSjSRud0dBr-CCRp-KAQCssgF1SMIImiWIEiSFIglCbhN-CSIYjiRJklSUIQvzfvB8j00YEdEgUTIFM35xvGCZWLhYo4CgUoRoUC2n3RgA8h4ohoE-F+b8P5kC-vjEAZBf7cF-oAqA2FQERmtvfSBCJRxe1artGA+0epJyxEtD8PI6BMFYHwcyEYqEpX9DKcgABhYkURSTcE4SYbhDhsEqmACgKEUIUFwDgNweUIAYAEWyvObgH80y4iKtmUq5JuB-yWJIrRID8zMLIAAIkALwbgAyHaMU5GCks-KCxsRJIRyo8KJSMinUyFCmGMGoVYWhzAfC3wsoYoxgAeDcAHr7li7G+Vol+RWPgrH8XsYJWJfBISwnhFeAKQdWrsk5NyXkK0PFc18bWH47pAShHHlhJeh5KlZFXjZIgI9mKsQ4tTWK8tAAkIGoaup1W41BOGcSQKh7hVF0K0GQtSUIZGyBwJYBQoCAEIQC4p17iHD+lDfWugiEzQ2gHQUq0jTWKidjXGSCyCtkaYwKwjkoAXP5FYYKR0uaDUQiuR0zonnOWIjqTwiCCZE1aaTZedp6koEaUBECYFhrmgwU8iySkKZyRwECsaIKYQNIRGhOg5BoXyn0X1FqM0SFkIKQYrxNDIoEV8Y4yh5KNKsI4VwnhUA+ECJpfkERYiJFwHZVAIJYSIlfPEp+eJ1FEmPPwPgjIrt4F-OQQCkmsVyYySRW0uK3BV6v3XhNbgE0QFQA8txKwbUV5mmYOYawCcKCezCi6c2AVKAqmoMQ1eTFKBBzlGAMOfooD4MbE43s-ZfWR0Kd6iEABrGU4BSBvxyH-ON3B2C8s5eInRUjMh6LJd43xZAchxSzSw2SjL+Gkl5UE4QgA8EEAEQggACEEAAgggByEHToAXBAK0RIVWq5VlNkWxV5bzf1WIw2RujVqhNUAx1JsNLarIuzZ4coClkYlMIDppQHfkPBkdpXu0jMqQ1wbUQmvwYUjdw8sjktjG-SBWQ5oLSWpQVdyopWIRPVAndg7N2j0gQayiX7OT7tfXhK9fpAyMG3V7FN3KhHMJ8ZSrwIIoN0uA2wsgYRPhRAQ9QsgwAjHCG+nLAA3qHMg+CKAAF8RBVBzvrGQBHQAwggFckCpAcBoTdIMEYYxqYxWUYVTMxUcwUlIxEuJUBEVU2SVQIAA
[17] Хотите, покажу вам магию живого кода на p5py?: https://habr.com/ru/companies/sberbank/articles/854474/
[18] Давайте-ка наваяем PumpKeen Game. Как Commander Keen, только про Pumpkin (тыкву). Хэллоуин же: https://habr.com/ru/companies/sberbank/articles/855374/
[19] @p5py_ru: https://t.me/p5py_ru
[20] Источник: https://habr.com/ru/companies/sberbank/articles/863110/?utm_campaign=863110&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.