Занятие №31 "Рекурсия: процедуры, которые вызывают себя сами"
Структуры, с которыми мы сталкивались раньше, позволяют нам повторять команду или набор команд посредством итераций. Еще одна эффективная техника повторения — рекурсия.
Она позволяет процедуре либо снова вызвать саму себя напрямую, либо опосредованно через другую процедуру (например, A вызывает B, B вызывает C, затем C вызывает A). Полезность такого подхода может быть сразу не очевидна, но на деле рекурсия упрощает решение многих задач программирования. Посмотрим, как работает этот метод, на простом примере
Процедура Тик выполняет две команды говорить (первая говорит «Тик», вторая — «Так»), затем вызывает себя снова. Спрайт продол- жит говорить «Тик-Так» бесконечно, если его не остановит внешнее действие. Единственный способ остановить процедуру — кликнуть по красному значку «Стоп». То, что процедура сама себя вызывает подобным образом, дает нам возможность бесконечно повторять две команды говорить, не используя блоков-циклов. Форма рекурсии, использованная в этом примере, называется концевой, поскольку рекурсивный вызов вставлен в самом конце процедуры. В Scratch рекурсивные вызовы могут располагаться и раньше, но такой тип рекурсии мы рассматривать не будем.

Бесконечная рекурсия — в целом не лучшая идея. Стоит контролировать выполнение процедуры с помощью условных операторов. Например, процедура может включать блок если, который определяет, нужен ли рекурсивный вызов. На рисунке показана рекурсивная процедура, которая от некой первой цифры (ее задает переменная счет) считает вниз до 0.

Разберемся, как работает процедура ОбратныйСчет, если ее вызывают с аргументом 3. Когда процедура запускается, команда говорить выводит цифру 3, затем проверяет, верно ли, что переменная счет больше 0. Поскольку 3 больше 0, процедура вычтет 1 из значения переменной счет, чтобы вызвать себя саму с аргументом 2. При втором вызове процедура показывает число 2 и, поскольку 2 больше 0, еще раз вызывает себя с аргументом 1. Это будет продолжаться до тех пор, пока не будет совершен вызов ОбратныйСчет(0). Когда цифра 0 появится в облачке разговора, процедура проверит, больше ли значение перемен- ной счет, чем 0. Поскольку выражение в шапке блока если оценивается
Теперь, когда мы разобрались с основами концевой рекурсии, мы можем применить этот принцип в более интересных программах. Рассмотрим в качестве примера процедуру Лезвие (Blade)
Предположим, спрайт, выполняющий эту процедуру, начинает работу в некой точке на Сцене и его исходное направление — 90°. Нарисовав равносторонний треугольник, спрайт проходит 12 шагов вперед и затем поворачивает на 10° против часовой стрелки. Затем процедура проверяет новое направление спрайта. Если он не смотрит в направлении 90°, процедура вызывает себя еще раз, чтобы нарисовать новый треугольник. Иначе рекурсивного вызова не произойдет и процедура завершит работу после того, как нарисует лезвие.

В простых случаях, вроде приведенных здесь примеров, проще использовать блок повторить, чем применять рекурсию.
Стрельба по птицам

Создадим простую игру с использованием всех блоков, с которыми мы познакомились в этой главе. Целью пользователя будет сбить всех птиц в небе
Пользовательский интерфейс игры «Стрельба по птицам»
В игре задействовано пять спрайтов: Птица1, клон Птицы1, Птица2, Стрелок и Пуля (Bird1, Bird2, Shooter и Bullet). Игрок может перемещать Стрелка по горизонтали при помощи клавиш со стрелками вправо и влево. При нажатии клавиши «пробел» в небо вылетит пуля. Если она попадает в Птицу1 или ее клон, игрок получает очко. Птица2 — это птица из Красной книги, в нее стрелять нельзя: если пуля попадет в нее, игра закончится. У пользователя есть одна минута на то, чтобы подстрелить как можно больше птиц. Каждая птица использует два костюма. Переключение с одного на другой создает эффект хлопания крыльями. У Сцены два фона: старт и конец. Первый показан на рисунке выше. Второй отличается от него только надписью Game Over (Игра закончена) в центре. Скрипты Сцены показаны ниже
Когда зеленый флажок нажат, Сцена меняет фон на старт, обнуляет таймер и запускает цикл, который будет обновлять и проверять оставшееся время игры (его отслеживает переменная ВремяОсталось). Когда эта переменная достигнет 0 или Сцена получит сообщение ИграЗакончена, она запустит обработчик события ИграЗакончена. Этот скрипт ждет некоторое время, чтобы позволить птицам спрятаться, меняет фон на конец и вызывает команду стоп все, чтобы завершить все работаю- щие скрипты. Как вы вскоре увидите, сообщение ИграЗакончена отправляется спрайтом Пуля при попадании в Птицу2. А теперь посмотрим на скрипт спрайта Стрелок
Этот скрипт первым делом размещает Стрелка внизу Сцены по цен- тру. Затем он запускает бесконечный цикл, который определяет, были ли нажаты клавиши со стрелками вправо и влево, и перемещает Стрелка в соответствующую сторону. Теперь перейдем к скриптам для спрайта Птица1
Когда игра начинается, спрайт Птица1 клонирует себя, перемещается к левому краю Сцены и вызывает процедуру Старт. Клон также начинает в левом краю Сцены (на другой высоте) и вызывает процедуру Старт. Она использует цикл всегда, чтобы перемещать птицу и ее клон по горизонтали через всю Сцену, слева направо на случайное число шагов. Когда птица достигает правого края Сцены, она перемещается обратно на левый край, как будто пролетела вокруг и появилась снова. Последний скрипт прячет обеих птиц, когда спрайту передается сообщение ИграЗакончена. Скрипты для Птицы2 очень похожи на скрипты для Птицы1, и мы не будем их тут разбирать. После клика по зеленому флажку Птица2 перемещается на правый край Сцены на высоте 40 и затем выполняет цикл, подобный процедуре Старт. Птица передвигается справа налево и как будто пролетает вокруг, достигая правого края Сцены. Птица2 также реагирует на сообщение ИграЗакончена, спрайт скрывается. Естественно, пользователь не может сбивать птиц, просто перемещая Стрелка, для этого нужен спрайт Пуля
Теперь игра готова, но вы можете добавить много дополнительных функций. Вот несколько предложений.
  • Дайте пользователю ограниченное количество пуль и ведите счет на основании числа пропущенных выстрелов.
  • Увеличьте число птиц и сделайте так, чтобы они летели с раз- ной скоростью.
  • Вознаграждайте игрока бóльшим количеством очков за попадание в более быстрых птиц.

Когда пользователь щелкнет по зеленому флажку, скрипт инициализирует переменные Выстрелил (число совершенных выстрелов) и Попал (сколько птиц сбито) со значением 0. Затем он поворачивает спрайт Пуля по направлению вверх и скрывает его. Потом он запускает бесконечный цикл, чтобы снова и снова перепроверять статус клавиши «пробел». Когда она нажата, скрипт увеличивает переменную Выстрелил на 1 и создает клон спрайта Пуля, чтобы переместить пулю вверх. Затем скрипт ждет какое-то время, чтобы игрок не смог слишком рано выстрелить снова. Теперь мы готовы запустить скрипт клонированной пули, показанный на рисунке

Scratch - Учись играя!
This site was made on Tilda — a website builder that helps to create a website without any code
Create a website