Одновременное рисование черепахами. Метод ontimer модуля turtle языка Python
Словарь урока
из модуля turtle: |
|
---|---|
из модуля random: |
|
из языка Python: |
|
Зачем нам на экране несколько черепах, если они все-равно рисуют по очереди? Чтобы последовательно рисовать, достаточно и одной. Сначала она начертит одну фигуру, потом перейдет в другое место и нарисует там другую. Если надо, перед этим поменяет свои настройки.
Интересней было бы, если бы черепахи рисовали одновременно. Одновременное, или параллельное, выполнение разных участков кода ‒ это многопоточность, которая обеспечивается другими модулями и требует более глубоких знаний программирования. Реализовать настоящую многопоточность средствами самого модуля turtle не получится.
Однако мы можем имитировать одновременность, если заставим черепах рисовать по чуть-чуть, быстро переключаясь между ними. Сделать это можно с помощью цикла.
bob = Turtle() bob.shape('turtle') lucy = Turtle() lucy.color('brown') side = 70 angle = 30 bob.teleport(100, -100) lucy.teleport(-200, -100) for i in range(12): bob.forward(50) lucy.forward(side) bob.left(30) lucy.left(angle) side = side - 1 angle = angle + 3
В примере Боб рисует круг, Люси ‒ спираль. Но каждая черепаха за одну итерацию цикла чертит только одну черточку. Переменные side
и angle
нужны только для Люси, так как аргументы ее команд должны меняться. Выражение side = side - 1
означает, что сначала из старого значения side
вычитается единица, после этого полученное новое число присваивается side
. То есть переменная меняет свое значение.
Другой способ заставить черепах как бы одновременно работать ‒ это использовать метод ontimer
модуля turtle. Но сначала изучим, что он делает сам по себе. Метод выполняет задержку на указанное количество миллисекунд (в 1 секунде 1000 миллисекунд). Код, выполнение которого должно задерживаться, помещается в функцию. Имя функции передается первым аргументом в ontimer
.
def pink_circle(): fillcolor('pink') begin_fill() circle(100) end_fill() dot(10) ontimer(pink_circle, 50) teleport(-120, 50) circle(50, steps=4) teleport(200, 50) circle(50, steps=8)
Можно было бы ожидать, что после того как будет нарисована точка, черепаха подождет 50 миллисекунд и начнет чертить круг, который будет касаться точки. Однако выполнение функции, переданной в ontimer
, просто откладывается на 50 миллисекунд. При этом черепаха времени даром не теряет. Она исполняет код ниже вызова ontimer
. Когда пройдет 50 миллисекунд, она, независимо от того, какую строчку кода сейчас читает, все бросит и пойдет исполнять код функции.
Задержка в 50 миллисекунд очень небольшая. Поэтому черепаха успевает только выполнить команду teleport
после ontimer
. В результате получается, что сначала она рисует точку, потом телепортируется, потом рисует круг, потом квадрат.
Если в ontimer
вторым аргументом передать число 500, то получится такая картина (у вас может быть по-другому, так как видимо есть зависимость от скорости компьютера):
Здесь задержка достаточно большая. Перед исполнением тела функции черепаха успевает не только начертить квадрат, но и телепортироваться в место расположения восьмиугольника.
Вернемся к нашей основной задаче ‒ сделать так, чтобы две черепахи рисовали одновременно. Для этого поместим вызов ontimer
в тело функции, а самому методу передадим эту же функцию в качестве аргумента:
t1 = Turtle() t1.color('brown') t2 = Turtle() t2.color('blue') t2.speed(1) def f(): t1.forward(30) t1.left(360/12) ontimer(f, 200) f() t2.circle(-100)
В коде после настроек двух черепах и определения функции, мы сразу вызываем функцию f
, после чего вторая черепаха рисует круг. В теле f
действия выполняет первая черепаха. Она чертит одну сторону двенадцатиугольника, и вызывается ontimer
с этой же функцией, но отложенной на 200 миллисекунд.
Пока отложенная на потом ждет своего "часа", вызванная из основной части программы функция завершает свою работу. Поток выполнения программы уходит в основную часть и здесь начинает исполнять код ниже вызова функции f
. Там находится команда, которая заставляет вторую черепаху рисовать окружность.
Черепаха t2
, ни о чем не подозревая, начинает рисовать круг. Но тут вдруг поток выполнения программы получает сигнал, что прошло 200 миллисекунд и надо выполнить код функции, который был ранее отложен. Поток выполнения останавливает t2
и уходит выполнять тело функции. Там опять происходит вызов ontimer
. Пока длится задержка, поток выполнения снова дает возможность t2
еще немного порисовать. И так далее.
Поскольку переключение между черепахами происходит достаточно быстро, нам будет казаться, что они рисуют одновременно. На самом деле, по очереди.
Проблема кода выше в том, что первая черепаха никогда не остановится, функция f
так и будет вызывать себя из себя с помощью ontimer
. Мы можем завершить программу, только закрыв окно.
Чтобы такого не было, надо поместить вызов ontimer
в условный оператор. Тогда функция будет вызываться только при соблюдении какого-то условия. Что это может быть за условие, зависит от вашей программы. Это, например, может быть значение координаты, лежащее в определенных пределах. Или мы можем ввести глобальную переменную, значение которой менять в функции. При этом вызов ontimer
будет зависеть от оценки значения этой переменной:
n = 1 def f(): t1.forward(30) t1.left(360/12) global n if n < 12: n = n + 1 ontimer(f, 200)
Переменная n
должна быть глобальной (то есть определенной в основной части программы), потому что если ее определить внутри функции, то при каждом вызове этой функции она будет получать новое значение 1. И счетчика из нее уже не получится. Чтобы из тела функции обращаться к глобальной переменной в языке программирования Python используется команда global
.
Задания для самостоятельной работы
- Расставьте три черепахи по горизонтали экрана. Запросите у пользователя длину стороны. Черепахи должны начать одновременно рисовать фигуры с такой стороной. Первая пусть рисует квадрат, вторая треугольник, третья ‒ шестиугольник.
- Разработайте программу, в которой две черепахи попеременно телепортируются в случайные места экрана до тех пор, пока не попадут в определенную зону (внутрь небольшой квадратной области). Оказавшаяся там черепаха исчезает.