/
Автор: Рубанцев В. Рубанцева Л.
Теги: программирование головоломки робототехника компьютерные технологии язык программирования pascal
Год: 2015
Текст
1
Валерий Рубанцев
Исполнительный Робот, или
Головоломки для программистов
2
Бесплатное издание
Все права защищены. Никакая часть этой книги не может быть воспроизведена в любой форме без письменного разрешения правообладателей.
Автор книги не несёт ответственности за возможный вред от использования информации, составляющей содержание книги и приложений.
Copyright 2015 Валерий Рубанцев
Лилия Рубанцева
3
От автора
Нельзя научиться программировать, усердно штудируя учебник. Тут нужна
практика! Только перерешав сотню-другую задач, вы твёрдо усвоите основы
языка паскаль.
В этой книге вы найдёте необходимый и достаточный материал для отработки
навыков программирования по начальному курсу языка PascalABC.NET.
При обучении очень важна наглядность. В предлагаемых заданиях она достигается за счёт использования Исполнителя, который называется Роботом. Это
виртуальный автомат, умеющий выполнять определённый набор команд для
перемещения по полю и закрашивания клеток.
Все наборы заданий для Робота были созданы Станиславом Станиславовичем
Михалковичем, руководителем проекта PascalABC.NET, в 2002-2007 годах. Они
идеально подходят для изучения программирования по таким темам как:
•
•
•
•
•
•
•
•
•
•
•
•
•
переменные
внутриблочные переменные
оператор присваивания
комбинированные операторы присваивания
математические операции
логические операции or и and
логические выражения и условный оператор if-else
цикл с параметром for
цикл с условием while
вложенные циклы
процедуры без параметров
процедуры с параметрами
операторы exit и break
Так как управлять Роботом невозможно без предварительной разработки алгоритма, то выполнение заданий хорошо развивает и укрепляет:
• логическое и алгоритмическое мышление
• умение находить и исправлять ошибки в алгоритме
4
• умение находить оптимальные решения
Имея правильный алгоритм, вы легко сможете перевести его на любой процедурный язык: паскаль, Си-шарп, Дельфи, Яву или Питон. Поэтому решение задач на паскале в будущем существенно облегчит вам изучение других, не
«учебных» языков программирования.
В книге имеется исчерпывающая информация по каждому набору заданий, а
также подробно разбирается решение всех задач (а их около полутора сотен!).
Но это не значит, что вы должны просто копировать готовые решения! Сначала попробуйте решить задачу самостоятельно. Ваше решение не обязательно
должно совпадать с решением автора книги. И только при затруднениях вы
можете «подглядывать» в книгу. Решив задачу собственным способом, сравните его с предложенным. Может быть, ваше решение окажется лучше…
Задания хотя и занимательны по форме, но вполне серьёзны по содержанию,
так что вам нередко придётся хорошенько подумать, разрабатывая алгоритм.
Однако наглядное воплощение алгоритма в виде перемещения Робота по полю сильно облегчит вам понимание сути заданий и отладку алгоритмов. Но
имейте в виду, что система PascalABC.NET строго следит за правильностью выполнения заданий, поэтому не надейтесь решить задачу по принципу Вовки-вТридевятом-царстве: А, ладно, и так сойдёт!
В конце книги вы найдёте полезные советы по решению заданий. Прежде
чем приступать к работе, прочитайте их. Другие приложения пригодятся вам
при изучении команд Робота, а также при составлении собственных заданий.
Валерий Рубанцев
5
Условные обозначения, принятые в книге:
Дополнение или замечание
Ненавязчивое требование или указание
Исходный код
Задание для самостоятельного решения
Проект
Исходный код программы.
Исходные коды всех проектов находятся в папке _Projects
6
Оглавление
Исполнительный Робот , или .......................................... 2
Головоломки для программистов ..................................... 2
От авт ора .................................................................. 4
Оглавление ................................................................. 7
Исполнители ................................................................................................... 13
Исполнитель Робот .................................................................................................. 14
Дрессируем Робота .................................................................................................. 21
Задание а2 .................................................................................................................. 31
Задание а3 ..................................................................................................................34
Задание а4 ..................................................................................................................35
Набор заданий с.................................................... 37
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
с1 ...................................................................................................................38
с2 .................................................................................................................. 41
с3 ..................................................................................................................43
с4 ..................................................................................................................44
с5 ..................................................................................................................45
с6 ..................................................................................................................47
с7 ..................................................................................................................49
с8 .................................................................................................................. 51
с9 ..................................................................................................................53
с10 ................................................................................................................55
с11 .................................................................................................................56
с12 ................................................................................................................58
с13 ................................................................................................................60
с14 ................................................................................................................62
с15 ................................................................................................................64
с16 ................................................................................................................67
7
Набор заданий if ................................................... 69
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
if1 ................................................................................................................. 69
if2 ................................................................................................................ 73
if3 ................................................................................................................ 75
if4 ................................................................................................................ 78
if5 ................................................................................................................ 79
if6 ................................................................................................................. 81
if7 ................................................................................................................ 83
if8 ................................................................................................................ 84
if9 ................................................................................................................ 86
if10 ............................................................................................................... 89
if11 ................................................................................................................ 91
Набор заданий w ................................................... 94
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
w1.................................................................................................................. 94
w2 ................................................................................................................. 96
w3 ................................................................................................................. 98
w4 ................................................................................................................. 99
w5 ............................................................................................................... 100
w6 ................................................................................................................ 101
w7 ............................................................................................................... 103
w8 ............................................................................................................... 104
w9 ............................................................................................................... 106
w10 ............................................................................................................. 108
w11 ............................................................................................................... 110
w12 ...............................................................................................................111
w13 .............................................................................................................. 113
w14 .............................................................................................................. 114
w15 .............................................................................................................. 115
w16 .............................................................................................................. 117
w17 .............................................................................................................. 118
Набор заданий cif ................................................. 120
Задание cif1 ............................................................................................................. 120
Задание cif2 ............................................................................................................. 121
8
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
cif3 ............................................................................................................. 123
cif4 ............................................................................................................. 124
cif5 ............................................................................................................. 125
cif6 ............................................................................................................. 126
cif7 ............................................................................................................. 127
cif8 ............................................................................................................. 129
cif9 ............................................................................................................. 130
cif10 ........................................................................................................... 132
cif11 ............................................................................................................ 133
cif12 ........................................................................................................... 135
cif13 ........................................................................................................... 136
cif14 ........................................................................................................... 137
cif15 ........................................................................................................... 139
cif16 ........................................................................................................... 140
cif17 ........................................................................................................... 143
cif18 ........................................................................................................... 145
cif19 ........................................................................................................... 146
cif20........................................................................................................... 148
cif21 ........................................................................................................... 150
cif22........................................................................................................... 152
Набор заданий count .............................................. 158
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
count1......................................................................................................... 158
count2 ........................................................................................................ 160
count3 ........................................................................................................ 162
count4 ........................................................................................................ 163
count5 ........................................................................................................ 165
count6 ........................................................................................................ 167
count7 ........................................................................................................ 169
count8 ........................................................................................................ 172
count9 ........................................................................................................ 173
count10 ...................................................................................................... 174
count11 ....................................................................................................... 175
count12 ...................................................................................................... 177
count13 ...................................................................................................... 178
9
Задание
Задание
Задание
Задание
count14...................................................................................................... 180
count15....................................................................................................... 181
count16...................................................................................................... 182
count17...................................................................................................... 184
Набор заданий cc.................................................. 187
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
cc1 .............................................................................................................. 187
cc2.............................................................................................................. 188
cc3.............................................................................................................. 190
cc4............................................................................................................... 191
cc5.............................................................................................................. 193
cc6.............................................................................................................. 194
cc7.............................................................................................................. 196
cc8.............................................................................................................. 197
cc9.............................................................................................................. 199
cc10 ............................................................................................................ 200
cc11 ............................................................................................................ 202
cc12 ............................................................................................................ 203
cc13 ............................................................................................................ 205
cc14 ............................................................................................................ 207
cc15 ............................................................................................................ 209
cc16 ............................................................................................................ 212
cc17 ............................................................................................................ 214
cc18 ............................................................................................................ 215
cc19 ............................................................................................................ 217
Набор заданий mix ................................................ 219
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
mix1 ............................................................................................................ 219
mix2 ........................................................................................................... 222
mix3 ........................................................................................................... 224
mix4 ........................................................................................................... 227
mix5 ........................................................................................................... 229
mix6 ........................................................................................................... 232
mix7 ........................................................................................................... 233
mix8 ........................................................................................................... 235
10
Задание mix9........................................................................................................... 237
Задание mix10 .......................................................................................................... 241
Набор заданий p .................................................. 247
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
p1 ................................................................................................................ 247
p2 ............................................................................................................... 249
p3 ................................................................................................................ 251
p4 ............................................................................................................... 252
p5 ............................................................................................................... 254
p6 ............................................................................................................... 256
p7 ............................................................................................................... 258
p8 ............................................................................................................... 260
p9 ............................................................................................................... 262
p10 ............................................................................................................. 264
Набор заданий pp ................................................. 267
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
pp1.............................................................................................................. 267
pp2 ............................................................................................................. 269
pp3 .............................................................................................................. 271
pp4 ............................................................................................................. 273
pp5 ............................................................................................................. 276
pp6 ............................................................................................................. 277
pp7 .............................................................................................................. 281
pp8 ............................................................................................................. 283
Набор заданий examen............................................ 286
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
Задание
examen1 .................................................................................................... 286
examen2 ................................................................................................... 288
examen3 ................................................................................................... 290
examen4 ................................................................................................... 292
examen5 ................................................................................................... 294
examen6 ................................................................................................... 295
examen7 ................................................................................................... 297
examen8 ................................................................................................... 299
examen9 ................................................................................................... 300
11
Задание examen10 .................................................................................................. 303
Приложения ............................................................. 305
Наборы заданий ..................................................................................................... 305
Система команд Робота ........................................................................................ 306
Советы по решению заданий ............................................................................. 310
Разработка собственных наборов заданий ..................................................... 320
Набор RVRobot ........................................................................................................ 329
Задание rvrobot1 .................................................................................................... 329
Задание rvrobot2 ................................................................................................... 331
Задание rvrobot3 ................................................................................................... 332
Задание rvrobot4 ................................................................................................... 334
Литература ............................................................... 336
12
Исполнители
Исполнители – это объекты программы, которые умеют выполнять определённый набор команд, который называют также системой команд исполнителя (СКИ).
Исполнители традиционно используются для обучения детей программированию. Первым исполнителем была знаменитая Черепашка в языке программирования Лого (Рис. 1).
Рис. 1. Знаменитая Черепашка-долгожительница
Теперь Черепашки имеются во многих языках программирования, например, в
Смолл Бейсике и Питоне. Черепашка умеет поворачиваться и ползти вперёд на
заданное расстояние, прочерчивания за собой прямую линию.
Со времени создания Черепашки появилось много новых исполнителей – Кузнечик, Чертёжник, Хамстер. А в этом номере журнала вы познакомитесь с Роботом, который поможет вам наглядно изучить основные конструкции языка
паскаль.
13
Исполнитель Робот
У лукоморья дуб зелёный;
Златая цепь на дубе том:
И днём и ночью кот учёный
Всё ходит по цепи кругом;
Идёт направо - песнь заводит,
Налево - сказку говорит.
А.С. Пушкин, Руслан и Людмила
Исполнитель Робот имеет покладистый нрав и
умеет выполнять простые команды.
Его рабочее место – игровое поле - представляет собой прямоугольник, разбитый на квадратные клетки. Сам Робот – это тоже квадрат, но, в отличие от белых клеток поля, он окрашен в жёлтый цвет и немного меньше клеток по размеру.
В начале решения задачи он находится в стартовой позиции. Маленький квадратик в левом верхнем углу одной из клеток поля отмечает его финишную позицию. В ней Робот должен закончить свой путь.
А его работа заключается в том, чтобы закрасить клетки поля, обозначенные
точками, которые находятся в их центре.
Игровое поле по периметру обнесено неприступной стеной, через которую Робот перешагнуть не может. Подобные стены могут разделять также клетки
поля, и тогда Робот не сможет перейти из одной клетки в другую, даже в соседнюю (Рис. 1).
Робот может переходить из одной клетки в другую, соседнюю, выполняя следующие команды (Рис. 2):
Right – идти вправо
Left – идти влево
Down – идти вниз
Up – идти вверх
14
Рис. 1. Робот и окружающая среда
Давайте посмотрим, как выглядит исходная позиция задания а1 в запущенной
программе (Рис. 3).
Во второй строке вы видите Робота в исходной позиции.
В первой, верхней строке располагаются 4 клетки с точками – их нужно закрасить.
Левая верхняя клетка помечена маленьким квадратиком – в неё должен прийти Робот, когда закрасит все клетки.
Сейчас Робот может сделать ход вниз, влево или вправо. Но если он попытается пойти вверх, то вы получите сообщение об аварии (Рис. 4), и выполнение
задания прекратится.
15
Рис. 2. Направления переходов
Рис. 3. «Вот и первое заданье…»
16
Рис. 4. ДТП
Итак, у Робота остаётся для начала только 3 хода на выбор: пойти налево,
направо или вниз. Любой из этих ходов допустим, но Робот должен не просто
бродить по полю, а стремиться как можно быстрее выполнить задание. Это
значит, что нужно за минимальное число ходов добраться до первой клетки с
точкой и закрасить её. На Рис. 3⬆ хорошо видно, что для Робота первая клетка
с точкой – это самая правая из них. Робот не сможет добраться до других точек, минуя её.
Легко догадаться, что, прежде всего, Робот должен выполнить 4 шага вправо,
чтобы обогнуть стену (Рис. 5).
Теперь он может беспрепятственно подняться в верхнюю горизонталь (Рис. 6).
И тут начинаются настоящие малярные работы!
Запомните: Робот может закрасить только ту клетку, в которой он находится.
17
Значит, он должен сделать шаг влево, а затем уже закрасить клетку (Рис. 7).
Рис. 5. Идём направо
Рис. 6. И вверх
18
Рис. 7. Первая закраска!
Эти действия он должен повторить трижды, чтобы закрасить и остальные
клетки (Рис. 8).
19
Рис. 8. Все клетки закрашены
И Роботу осталось сделать последний, решающий шаг влево, чтобы закончить
задание (Рис. 9).
Рис. 9. Задание выполнено!
20
Дрессируем Робота
Итак, на бумаге мы справились с задачей. Действительно, Робот только выполнял наши команды, поэтому слава и почёт должны достаться авторам, а не
исполнителям. Но как заставить Робота, даже самого послушного выполнять
наши команды в реальной программе? – А их нужно записать в исходном коде,
который Робот умеет читать.
Но сначала мы должны научиться получать задания для последующего их
осмысливания и исполнения.
Самый простой и в то же время правильный путь в этом направлении – нажать
кнопку Создать шаблон программы на Панели инструментов (Рис. 1) или
клавиши Ctrl+Shitf+L.
Рис. 1. Шаблонная кнопка
Откроется диалоговое окно Загрузка задания (Рис. 2).
Рис. 2. Вступаем в диалог
21
Внизу вы можете прочитать, какие имеются группы заданий. Нам нужны задания, которые начинаются с букв RB, которые означают Robot.
Набираем в текстовом поле Задание эти буквы (в любом регистре) и получаем
внизу диалогового окна буквы для наборов заданий (Рис. 3).
Рис. 3. Префиксы и суффиксы
Нам нужен самый первый набор а, который предназначен для предварительного знакомства с системой команд Робота.
Добавляем в текстовое поле Задание букву а и опять получаем подсказку: в
наборе 4 задания (Рис. 4).
Рис. 4. Грамотно пользуйтесь подсказками
22
Конечно, начинать нужно с первого задания, поэтому печатаем цифру 1 (Рис.
5).
Рис. 5. Можно начинать
По умолчанию все ваши проекты-решения будут сохраняться в папке
PascalABC.NET Projects, название которой напечатано в текстовом поле Каталог. Если вы хотите изменить место хранения своих проектов, то нажмите
кнопку с жёлтой папкой и укажите новый путь (Рис. 6).
Рис. 6. Пути выбирают
Все приготовления закончены, и мы нажимаем кнопку Загрузка или клавишу
ВВОД (Рис. 7).
В Редакторе кода появилась страница RBa1.pas с заготовкой кода для задания
а1 (Рис. 8).
23
Если у вас на то есть охота, то вы можете и самостоятельно набрать весь этот
код и сохранить его на диске под нужным именем.
Рис. 7. Всё готово
Рис. 8. Заготовительно-приготовительные работы закончены
Чтобы не выбирать каждый раз папку для хранения файлов, сохраните задание
на диске, закройте среду разработки, перейдите в папку с файлом и дважды
щёлкните по нему. Заготовка задания откроется в Редакторе кода, а при загрузке
нового задания в текстовом поле Каталог будет автоматически напечатан путь к
нужной папке.
Строчка
uses Robot;
24
подключает к проекту модуль Robot.pas, без которого Робот не появится.
В главной части программы записан вызов процедуры Task, которой мы передаём строку 'a1' с названием задания.
Вы можете запустить программу, нажав кнопку Выполнить на Панели инструментов или (что лучше) воспользоваться командой меню Программа > Выполнить без связи с оболочкой.
На экране появится окно с заданием, игровое поле и элементы управления
(Рис. 9).
Рис. 9. Конкретное задание
Всегда внимательно читайте верхнюю строку, в которой находится задание
для Робота.
25
В нижней части окна выводятся сообщения о текущем состоянии программы.
Сейчас вы можете прочитать там, что Робот готов к выполнению команд.
Кнопка Выход (клавиша Esc) закрывает программу.
Кнопка Справка (клавиша F1) открывает одноимённое диалоговое окно, в котором перечислены все команды Робота, а также условия, которые может проверять Робот по ходу выполнения задания (Рис. 10).
Рис. 10. Всегда держите под рукой!
Команды перемещения Робота вам уже известны, а новая команда Paint закрашивает клетку, в которой Робот находится.
26
При отладке команд следует пользоваться пошаговым перемещением Робота,
чтобы внимательно наблюдать за каждым его действием. При обнаружении
ошибки, нужно исправить исходный код и снова запустить программу.
Чтобы выполнить 1 шаг, нажмите кнопку Шаг или клавишу ПРОБЕЛ (Рис. 11).
Рис. 11. Пошагали?
Набравшись смелости, мы дерзко нажимаем на эту кнопку, но Робот не двигается с места, а мы получаем обидное сообщение, что Работа окончена, задание
не выполнено (Рис. 12).
Всё верно, ведь мы не дали Роботу ни одной команды!
27
Рис. 12. Работа стоит!
Возвращаемся в Редактор кода и после вызова процедуры Task аккуратно выписываем команды, которые придумали раньше:
uses
Robot;
begin
Task('a1');
//идём направо без закраски:
Right;
Right;
Right;
28
Right;
//поднимаемся вверх без закраски:
Up;
//идём налево с закраской:
Left; Paint;
Left; Paint;
Left; Paint;
Left; Paint;
//идём налево без закраски:
Left;
end.
Если вы внимательно читали журнальчик, то здесь для вас нет ничего нового,
поэтому запустите программу и нажимайте кнопку Шаг. Робот будет послушно переходить из одной клетки в другую, выполняя команды, пока, наконец, не
окажется на базе. Следующее нажатие на кнопку Шаг остановит программу,
которая порадует вас приятным сообщением, что Задание выполнено (Рис. 13).
Закройте программу, а затем снова запустите её. На этот раз нажмите кнопку
Пуск, и Робот самостоятельно и быстро выкрасит все заданные клетки и окажется на базе. Программа также сообщит нам, что Роботу потребовалось сделать 15 шагов для выполнения задания. Если вы пересчитаете команды, то их
окажется только 14. Лишняя команда появилась из-за того, что при запуске
программы считается, что Робот уже сделал 1 шаг, хотя он и не сдвинулся с
места.
Скорость перемещения Робота можно изменять ползунком Скорость. Двигайте его вправо, что Робот шёл быстрее, влево – медленнее.
Сохраните исходный код программы на диске и готовьтесь к новым испытаниям!
29
Рис. 13. С выполнением!
30
Задание а2
Получить заготовку для второго задания ещё проще, чем для первого!
Нажмите кнопку Создать шаблон программы и исправьте единицу на двойку
(Рис. 1).
Рис. 1. Идём дальше
Если вы сохраняете решения не в папке по умолчанию, то укажите её, как мы
это делали раньше, а затем нажмите кнопку Загрузка. В Редакторе кода откроется заготовка (Рис. 2).
Так как прежде чем браться за выполнение задания, его нужно увидеть, то запустите программу и внимательно посмотрите на картинку с заданием (Рис. 3).
31
Рис. 2. Новая заготовка
Рис. 3. Требуется особое внимание
Если вы не можете сразу найти решение, то скопируйте игровое поле на листочек в клеточку и нарисуйте путь Робота.
В данном случае понятно, что самый короткий путь для Робота такой:
• обойти клетки с точка по часовой стрелке или
32
• обойти клетки с точками против часовой стрелки
Что касается начальной клетки, то её можно закрасить сразу, а можно и в конце
выполнения задания, поскольку Робот всё равно в неё должен вернуться.
Я выбрал вариант движения по часовой стрелке без закраски начальной клетки, тогда Робот сначала идёт вправо, закрашивает клетку, опять идёт вправо и
закрашивает клетку.
И эти действия он повторяет по остальным направлениям – вниз, влево, вверх.
Вернувшись на базу, он закрашивает последнюю клетку – и задача решена!
Переписать команды в главную часть программы не составляет никакого труда:
Task('a2');
//идём направо:
Right;Paint;
Right;Paint;
//идём вниз:
Down;Paint;
Down;Paint;
//идём налево:
Left;Paint;
Left;Paint;
//идём вверх:
Up;Paint;
Up;Paint;
33
Задание а3
Получите заготовку для третьего задания, запустите программу и ознакомьтесь с игровой ситуацией (Рис. 1).
Рис. 1. Третье задание
Тут, как говорится, без вариантов. Робот обязательно должен закрасить
начальную клетку, потому что он в неё больше не вернётся. А дальше он двигается зигзагом: вниз – вправо – вверх – вправо, и так до базовой клетки. Каждую клетку Робот должен закрасить. Задание очень простое:
Task('a3');
//закрашиваем первую клетку:
Paint;
//идём вниз и закрашиваем вторую клетку:
Down; Paint;
//идём вправо:
Right; Paint;
34
//идём вверх:
Up; Paint;
//идём вправо:
Right; Paint;
//идём вниз:
Down; Paint;
//идём вправо:
Right; Paint;
//идём вверх:
Up; Paint;
Задание а4
И вот мы дошли до последнего задания в первом наборе (Рис. 1).
Рис. 1. Четвёртое задание
Задача чуть сложнее предыдущей, но тоже решается в уме.
35
Идём вверх до упора, переходим вправо, опускаемся до дна, закрашиваем там
клетку, выбираемся наверх, и так далее:
Task('a4');
//поднимаемся до верхней горизонтали:
Up;Up;
//идём вправо до второй колонки:
Right;
//опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
//поднимаемся до верхней горизонтали:
Up;Up;
//идём вправо до третьей колонки:
Right;
//опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
//поднимаемся до верхней горизонтали:
Up;Up;
//идём вправо до четвёртой колонки:
Right;
//опускаемся до дна и закрашиваем клетку:
Down;Down;Paint;
//задание выполнено //возвращаемся на базу:
Up;Up;
Left;Left;Left;
Down; Down;
36
Набор заданий с
Откройте диалоговое окно Загрузка задания, наберите в текстовом поле Задание волшебные буквы RBc – и вы увидите, что вам предстоит решить ни много
ни мало 16 заданий на цикл с параметром (Рис. 1).
Рис. 1. 16 циклов!
Вы, должно быть, решая первые задания, уже заметили, что одни и те же команды повторяются несколько раз. В исходном коде такие действия описываются совершенно одинаково. Чтобы уменьшить «писанину» и сделать исходный текст более наглядным, повторяющиеся куски кода сокращают за счёт
циклов. Если мы заведомо знаем, сколько раз повторяются действия, то вполне
разумно выбрать простой цикл for.
Вернитесь в диалоговое окно, допишите единицу и нажмите кнопку Загрузка
(Рис. 2).
Рис. 2. Перезагрузка
37
Задание с1
Заготовка кода для второго набора заданий отличается от первого только
названием самого задания (Рис. 1).
Рис. 1. По шаблону становись!
Вся прелесть – в игровом поле (Рис. 2).
Рис. 2. Становится интереснее!
38
Ни одной клетки в первом задании закрашивать не нужно – достаточно только
кратчайшим путём добраться до базы. Сворачивать некуда, поэтому идём
строго вправо. Давайте посчитаем на пальцах, сколько шагов должен сделать
Робот в этом направлении: один – два – три - . . . – десять.
Итак, Робот должен 10 раз выполнить команду Right. Это значит, что переменная цикла for должна последовательно принимать значения от 1 до 10:
uses
Robot;
begin
Task('c1');
//идём вправо 10 шагов:
for var i := 1 to 10 do
Right;
end.
Проверим теорию практикой. Всё верно: Робот благополучно добрался до базы и с честью выполнил задание (Рис. 3)!
Вы можете заменить цикл for циклом foreach, а значения переменной цикла
задавать с помощью функции Range, которая с указанными выше значениями
параметров вернёт последовательность целых чисел в диапазоне 1..10:
foreach var i in Range(1, 10) do
Right;
Можно обойтись и без функции Range:
foreach var i in [1..10] do
Right;
Результат вы, конечно, получите тот же самый, что и раньше, но тренировка с
циклом foreach тоже лишней не будет!
39
Рис. 3. Ушёл на базу
40
Задание с2
Переходим к следующему заданию (Рис. 1).
Рис. 1. Конца нет!
Оно очень похоже на первое задание, но теперь Робот по ходу движения должен ещё и закрашивать клетки. Обратите внимание, что базовая клетка
должна остаться чистой!
Ищем повторяющиеся команды. Десять раз мы должны закрасить клетку и десять раз перейти в правую клетку. Таким образом, «период» цикла такой: Paint
– Right (Рис. 2).
41
Рис. 2. Первый период
Всё остальное – дело программистской техники, то есть компьютера:
//10 раз закрашиваем клетку и
//идём направо:
for var i := 1 to 10 do
begin
Paint;
Right;
end;
42
Задание с3
Не правда ли, третье задание – почти второе, только крайние клетки поменялись местами по части закрашивания (Рис. 1).
Рис. 1. Чувствуете разницу?
«Период» цикла напрашивается сам собой: сначала идём вправо, затем закрашиваем клетку. И так 10 раз кряду:
//10 раз переходим вправо и
//закрашиваем клетку:
for var i := 1 to 10 do
begin
Right;
Paint;
end;
43
Задание с4
Здесь мы видим обобщение двух предыдущих задач: все клетки по ходу движения вправо нужно закрасить (Рис. 1).
Рис. 1. Красят все!
Мы можем действовать, как в Задании с2, но тогда у нас останется незакрашенной базовая клетка, и нам придётся приложить дополнительные усилия,
чтобы закончить задание:
//10 раз закрашиваем клетку и
//переходим вправо:
for var i := 1 to 10 do
44
begin
Paint;
Right;
end;
//закрашиваем базовую клетку:
Paint;
Задание с5
Легко и здесь увидеть Задание с2, но теперь Робот должен перемещаться не
только вправо, но и вниз – по диагонали (Рис. 1).
Рис. 1. Наклонная дорожка
45
Если Робот будет переходить только вправо, то закрасит верхнюю горизонталь. Значит, после каждого хода вправо он должен опуститься вниз на 1 клетку, чтобы перейти на диагональ (Рис. 2).
Рис. 2. Можно изобразить и другое колено
//10 раз закрашиваем клетку,
//идём направо и вниз:
for var i := 1 to 10 do
begin
Paint;
Right;
Down;
end;
46
Задание с6
А вот эта задача похитрей! Тут нужно закрашивать клетки через одну, двигаясь
влево, а затем победным маршем вернуться на базу (Рис. 1).
Рис. 1. Полевело
Таким образом, налицо 2 два цикла:
• двигаемся влево и закрашиваем клетки через одну
• двигаемся вправо без закрашивания клеток
Второй цикл слишком прост, чтобы тратить время на его обсуждение.
47
Чтобы найти «период» первого цикла, выполним команды: Left – Paint – Left.
Тогда мы закрасим самую правую клетку с точкой, а Робот окажется в той же
ситуации, что и в начале движения, но уже перед второй закрашиваемой клеткой. Всего он должен закрасить 8 клеток, значит, и цикл мы должны повторить 8 раз (Рис. 2).
Рис. 2. Несложный цикл
//8 раз переходим влево,
//закрашиваем клетку и
//снова переходим влево:
for var i := 1 to 8 do
begin
Left;
Paint;
Left;
end;
//возвращаемся на базу:
for var i := 1 to 16 do
Right;
48
Задание с7
В этом задании мы вновь встречаемся с зигзагом, но с весьма замысловатым
(Рис. 1).
Рис. 1. Зигзаг удачи?
Как всегда, в циклах важно ухватить минимальное число повторяющихся команд.
Давайте начнём выполнять задание:
Paint – Down - Paint – Left - Paint – Up – Paint – Left
49
Пока никаких повторяющихся действий мы не наблюдаем. Продолжаем: Paint –
Down - Paint – Left… Ура! Дальше всё то же самое. Считаем, сколько раз. – Пять, и
задача решена (Рис. 2).
Рис. 2. Длинный период
//5 раз выполняем зигзаг:
for var i := 1 to 5 do
begin
Paint; Down;
Paint; Left;
Paint; Up;
Paint; Left;
end;
Если присмотреться к условию задачи внимательнее, то вполне можно увидеть в ней усложнённый вариант Задания с2.
50
Задание с8
Здесь мы видим «гребёнку», подобную которой уже решали (Рис. 1).
Рис. 1. На гребне
Так как последнюю клетку также нужно закрасить, то нам потребуется ещё
одна, дополнительная команда Paint. А «период» цикла легко найти, начав решать задачу: Paint – Down – Left – Up. За 10 итераций мы закрасим 10 клеток и
попадём на базовую (Рис. 2).
51
Рис. 2. Слегка криво
Её нужно закрасить – и только: дальше команды «периода» не выполняются:
//10 раз закрашиваем клетку,
//а затем переходим:
//вниз - налево - вверх:
for var i := 1 to 10 do
begin
Paint; Down;
Left;
Up;
end;
//закрашиваем последнюю клетку:
Paint;
52
Задание с9
В этом задании мы видим настоящий «слалом» (Рис. 1).
Рис. 1. Слалом-зигзаг
Но если приглядеться, то мы опять найдём вариант Задания с2, поэтому период цикла выписать очень легко: Paint – Up – Right – Paint – Down- Right. Теперь
Робот окажется в той же позиции, что и в начале движения, но на 2 клетки
правее (Рис. 2).
53
Рис. 2. Виртуозно!
Всего Роботу предстоит совершить 5 переходов:
for var i := 1 to 5 do
begin
Paint; Up;
Right; Paint;
Down; Right;
end;
54
Задание с10
А в этом задании мы найдём и Задание с2, и Задание с3 - но в обратном направлении (Рис. 1).
Рис. 1. Слоёный путь
Первую часть задачи решаем, как в Задании с2, затем переходим на нижнюю
горизонталь и выполняем действия Задания с3, но влево:
//идём вправо по верхней горизонтали:
for var i := 1 to 10 do
begin
Paint;
Right;
55
end;
//спускаемся на нижнюю горизонталь:
Down;
//идём влево по нижней горизонтали:
for var i := 1 to 10 do
begin
Left;
Paint;
end;
Задание с11
В Задании с11 мы также без труда найдём пару Заданий с4 (Рис. 1).
Рис. 1. На 2 точки больше
56
Таким образом, сначала мы идём влево, как в Задании с4, затем переходим на
нижнюю горизонталь и идём в противоположном направлении:
//идём влево по верхней горизонтали:
for var i := 1 to 9 do
begin
Paint;
Left;
end;
Paint;
//опускаемся на нижнюю горизонталь:
Down;
//идём вправо по нижней горизонтали:
for var i := 1 to 9 do
begin
Paint;
Right;
end;
Paint;
57
Задание с12
Здесь мы снова найдём Задание с4, но из двух частей (Рис. 1).
Рис. 1. Туда-сюда-обратно
Сначала мы идём влево и закрашиваем по пути клетки, затем идём вправо до
первой незакрашенной клетки. Повторяем действия Задания с4 для оставшихся справа незакрашенных клеток и, наконец, возвращаемся на базу:
//делаем 5 шагов влево
//и закрашиваем клетки:
for var i := 1 to 5 do
begin
Paint;
Left;
58
end;
Paint;
//возвращаемся в исходную позицию + 1:
for var i := 1 to 6 do
begin
Right;
end;
//делаем 5 шагов вправо
//и закрашиваем клетки:
for var i := 1 to 4 do
begin
Paint;
Right;
end;
Paint;
//возвращаемся на базу:
for var i := 1 to 5 do
begin
Left;
end;
Попробуйте решить эту задачу другим способом!
59
Задание с13
А тут мы видим четыре Задания с2, которые «закольцованы» (Рис. 1).
Рис. 1. Ходим в квадрате по кругу
Квадрат можно обходить или против часовой стрелки, или по ходу её движения:
//идём вниз:
for var i := 1 to 8 do
begin
Paint;
Down;
end;
60
//идём налево:
for var i := 1 to 8 do
begin
Paint;
Left;
end;
//идём вверх:
for var i := 1 to 8 do
begin
Paint;
Up;
end;
//идём вправо:
for var i := 1 to 8 do
begin
Paint;
Right;
end;
61
Задание с14
Тот же самый квадрат, но повёрнутый ромбиком (Рис. 1).
Рис. 1. Квадратный ромб
//идём вверх вправо:
for var i := 1 to 4 do
begin
Paint;
Up;
Right;
end;
//идём вниз вправо:
62
for var i := 1 to 4 do
begin
Paint;
Down;
Right;
end;
//идём вниз влево:
for var i := 1 to 4 do
begin
Paint;
Down;
Left;
end;
//идём вверх влево:
for var i := 1 to 4 do
begin
Paint;
Up;
Left;
end;
63
Задание с15
Пара Заданий с12, расположенных крестиком (Рис. 1).
Рис. 1. Крестовый поход
Робот может начать свой поход в любую сторону. Например, можно сначала
закрасить левую ветвь креста:
//закрашиваем клетки и
//идём налево:
for var i := 1 to 5 do
begin
Paint;
Left;
64
end;
Paint;
Вернуться на первую незакрашенную клетку в горизонтальной части креста:
//возвращаемся в исходную позицию + 1:
for var i := 1 to 6 do
begin
Right;
end;
Закрасить правую горизонтальную ветвь:
//закрашиваем клетки и
//идём направо:
for var i := 1 to 4 do
begin
Paint;
Right;
end;
Paint;
Снова вернуться в исходную клетку:
//возвращаемся в исходную позицию:
for var i := 1 to 5 do
begin
Left;
end;
Аналогично закрасить клетки вертикальной части креста:
//идём вверх и
//закрашиваем клетки:
for var i := 1 to 5 do
begin
65
Up;
Paint;
end;
//возвращаемся в исходную позицию + 1:
for var i := 1 to 6 do
begin
Down;
end;
//закрашиваем клетки и
//идём вниз:
for var i := 1 to 4 do
begin
Paint;
Down;
end;
Paint;
//возвращаемся на базу:
for var i := 1 to 5 do
begin
Up;
end;
66
Задание с16
Похоже на Задание с8, но гораздо «хитрее» (Рис. 1).
Рис. 1. Хитро загнуто!
Здесь две «гребёнки» - нижняя и верхняя, причём «зубья» идут через один.
Это значит, что сначала Робот должен пройти нижнюю гребёнку вправо, подняться верхнюю гребёнку и пройти её в противоположном направлении.
Мы без труда подсчитаем, что Робот должен закрасить по 5 клеток в каждой
из гребёнок. Найти «период» цикла также не составляет труда:
67
//нижний зигзаг:
for var i := 1 to 5 do
begin
Paint;
Down;
Right; Right;
Up;
end;
//переход на верхний зигзаг:
Up; Left; Down;
//верхний зигзаг:
for var i := 1 to 5 do
begin
Paint;
Up;
Left; Left;
Down;
end;
//возвращаемся на базу:
Down; Right; Up;
68
Набор заданий if
Если в первых двух наборах заданий игровое поле однозначно определяло поведение Робота на поле, то в наборе заданий if поле может быть нескольких
видов, которые возникают на экране случайно, и мы не можем предугадать,
какое именно поле достанется Роботу. Это значит, что Робот должен на месте
самостоятельно определить вид поля и соответственно этому выбрать нужную последовательность команд. Для этого он использует условный оператор
if – else.
Чтобы перейти к новому набору заданий, откройте диалоговое окно Загрузка
задания и наберите в текстовом поле Задание: RBif1 (Рис. 1).
Рис. 1. Новый наборчик
Как вы видите, в этом наборе 11 заданий, и их выполнение предполагает использование в исходном коде условного оператора выбора if – else.
Задание if1
Так как нам заранее неизвестно, сколько разных полей может быть в задании,
то придётся несколько раз запустить программу, чтобы их «вычислить». Таким
нехитрым способом можно выяснить, что первое задание в этом наборе содержит 2 вида полей (Рис. 1).
69
Рис. 1. Их становится больше!
В первую очередь, Робот должен определить вид поля, на котором он находится. Для этого у него на голове имеется радар, который умеет находить стены по
всем четырём направлениям от клетки с Роботом. К сожалению, радар очень
слабый, поэтому может «видеть» только стены по границам клетки с Роботом.
В программе информацию от радара мы можем получать от следующих функций:
WallFromLeft – возвращает True, если слева от Робота стена
WallFromRight – возвращает True, если справа от Робота стена
WallFromUp – возвращает True, если сверху от Робота стена
WallFromDown – возвращает True, если снизу от Робота стена
Теперь давайте проанализируем информацию, представленную на Рис. 1⬆.
Вокруг клетки с Роботом нет ни одной стены, поэтому он пока не может определить вид игрового поля. Можно пойти вниз или вверх, тогда в обоих случаях
у Робота появится стена справа, что также не даст ему возможности определиться на местности. Остаётся шаг вправо. И в этом случае у Робота обязательно появится стена справа, но в первом случае (на Рис. 2, слева) вторая стена будет располагаться снизу, а во втором случае (на Рис. 2, справа) – сверху.
70
Рис. 2. Считаем стены
Таким образом, сделав шаг вправо, Робот сможет определить вид поля:
//поле может быть двух видов!
begin
Task('if1');
Right;
Если стена окажется ниже, то Робот должен выполнить команды: Up - Right Down – Paint. Если стена окажется выше, то Робот должен выполнить команды: Down - Right - Up – Paint.
Оставшуюся часть программы уже нетрудно написать:
//стена снизу:
if (WallFromDown) then
begin
Up;
Right;
Down;
Paint;
71
end
//стена сверху:
else
begin
Down;
Right;
Up;
Paint;
end;
Теперь нашего доблестного Робота никакое поле не поставит в тупик (Рис. 3)!
Рис. 3. Выход всегда есть!
72
Задание if2
Во втором задании необходимо закрасить клетки у соседних стен (Рис. 1).
Рис. 1. Будем красить
Стен может быть: 0..4. Если стены есть, но их меньше четырёх, то они могут
располагаться по-разному относительно клетки с Роботом. Вариантов получается слишком много, чтобы расписывать их каждый в отдельности. Нужно искать универсальный алгоритм!
Прежде всего, закрасим клетку, в которой стоит Робот:
//0..4 стен
begin
Task('if2');
//закрашиваем начальную клетку:
Paint;
Затем идём вверх и смотрим, есть ли стена в этом направлении. Если есть, то
закрашиваем клетку перед ней, а затем спускаемся в стартовую клетку:
//шаг вверх:
Up;
//если сверху стена
if (WallFromUp) then //то
73
Paint; //закрашиваем клетку
//возвращаемся в исходную позицию:
Down;
Дальше действуем аналогично во всех остальных направлениях:
//шаг вниз:
Down;
if (WallFromDown) then
Paint;
Up;
//шаг влево:
Left;
if (WallFromLeft) then
Paint;
Right;
//шаг вправо:
Right;
if (WallFromRight) then
Paint;
Left;
Независимо от числа стен и их расположения Робот всегда закрасит клетки,
которые находятся рядом с ними (Рис. 2)!
Рис. 2. Зелёный – любимый цвет роботов
74
Задание if3
Поле очень маленькое – всего 2 х 2 клетки, Робот находится в одном из углов
поля, а закрасить должен клетку в противоположном углу (Рис. 1).
Рис. 1. Противоположности сходятся
В первую очередь, Робот должен определиться, в каком углу поля он находится. Сделать это нетрудно, если внимательно посмотреть на все 4 стороны. Если
стена сверху и слева, то Робот находится в верхнем левом углу поля, а идти в
противоположную клетку от должен так: Right – Down или Down – Right.
75
Чтобы не выписывать сложные логические условия, можно обозначить
направление на стены степенями двойки, тогда по сумме направлений мы легко найдём положение Робота на поле:
//направление на стены:
var dir := 0;
if (WallFromUp) then
dir += 1;
if (WallFromDown) then
dir += 2;
if (WallFromLeft) then
dir += 4;
if (WallFromRight) then
dir += 8;
Зная начальную клетку, мы перегоняем Робота в противоположный угол:
if (dir = 5) then //верхний левый угол
begin
Down; Right;
end
else if (dir = 9) then //верхний правый угол
begin
Down; Left;
end
else if (dir = 6) then //нижний левый угол
begin
Up; Right;
end
else
begin //нижний правый угол
Up; Left;
end;
И закрашиваем единственную клетку:
//закрашиваем клетку:
Paint;
76
Алгоритм простой, но действует безотказно (Рис. 2)!
Рис. 2. Всё гениальное – просто!
77
Задание if4
Очень лёгкое задание (Рис. 1)!
Рис. 1. Полегчало…
Робот определяет, в каком направлении находится стена, делает шаг в противоположном направлении и закрашивает клетку:
//стена сверху:
if (WallFromUp) then
begin
Down;
Paint;
end
//стена снизу:
else if (WallFromDown) then
78
begin
Up;
Paint;
end
//стена слева:
else if (WallFromLeft) then
begin
Right;
Paint;
end
//стена справа:
else
begin
Left;
Paint;
end
Задание if5
Это задание развивает идею предыдущего (Рис. 1).
Рис. 1. Развивайте идеи!
Стена может находиться в одном из четырёх направлений.
Легко заметить, что для обеих вертикальных и для обеих горизонтальных стен
нужно выполнить одни и те же действия, поэтому в условном операторе if
нужно записать сложное логическое выражение с оператором or.
79
А действия Робота совершенно бесхитростные. Если, к примеру, стена горизонтальная, то он делает шаг налево и закрашивает клетку. Затем делает 2 шага вправо и закрашивает вторую клетку. Ещё 1 шаг влево – и Робот на базе.
Можно сначала закрасить правую клетку, а затем левую.
//стена слева или справа:
if (WallFromLeft or WallFromRight) then
begin
//закрашиваем верхнюю клетку:
Up; Paint;
//закрашиваем нижнюю клетку:
Down; Down; Paint;
//возвращаемся на базу:
Up;
end
else //стена сверху или снизу:
begin
//закрашиваем левую клетку:
Left; Paint;
//закрашиваем правую клетку:
Right; Right; Paint;
//возвращаемся на базу:
Left;
end;
80
Задание if6
Это задание отличается от предыдущих только тем, что место стены заняла
закрашенная клетка (Рис. 1).
Рис. 1. Анализируй всё!
На этот случай Робот имеет «цветоанализатор», который через функции
CellIsPainted – возвращает True если клетка, в которой находится Робот, закрашена
CellIsFree – возвращает True если клетка, в которой находится Робот, не закрашена
сообщает нам, в какой клетке находится Робот – в закрашенной или в чистой.
81
Робот последовательно делает шаги во всех четырёх направлениях. Если он
попадает на закрашенную клетку, то делает 2 шага в противоположном
направлении и закрашивает клетку.
Если он не обнаруживает закрашенной клетки, то возвращается в исходную
позицию, чтобы выполнить шаг в следующем направлении:
//шаг наверх:
Up;
//клетка закрашена?
if (CellIsPainted) then
begin
Down; Down; Paint;
end
else //возвращаемся на базу
Down;
//шаг вниз:
Down;
//клетка закрашена?
if (CellIsPainted) then
begin
Up; Up; Paint;
end
else //возвращаемся на базу
Up;
//шаг влево:
Left;
//клетка закрашена?
if (CellIsPainted) then
begin
Right; Right; Paint;
end
else //возвращаемся на базу
Right;
//шаг вправо:
Right;
//клетка закрашена?
if (CellIsPainted) then
begin
Left; Left; Paint;
end
82
Задание if7
Полностью повторяет Задание if3 (Рис. 1).
Рис. 1. Повторение – мать учения
//направление на стены:
var dir := 0;
if (WallFromUp) then
dir += 1;
if (WallFromDown) then
dir += 2;
if (WallFromLeft) then
dir += 4;
if (WallFromRight) then
dir += 8;
83
if (dir = 5) then //верхний левый угол
begin
Down; Right;
end
else if (dir = 9) then //верхний правый угол
begin
Down; Left;
end
else if (dir = 6) then //нижний левый угол
begin
Up; Right;
end
else
begin //нижний правый угол
Up; Left;
end;
//закрашиваем клетку:
Paint;
Задание if8
Робот находится между двух стен, которые могут быть вертикальными или
горизонтальными (Рис. 1).
Рис. 1. Между двух стен
84
Задание точно такое же, как if4, только закрасить нужно пару клеток:
//стена сверху:
if (WallFromUp) then
begin
Down; Paint;
Down; Paint;
end
//стена снизу:
else if (WallFromDown) then
begin
Up; Paint;
Up; Paint;
end
//стена слева:
else if (WallFromLeft) then
begin
Right; Paint;
Right; Paint;
end
//стена справа:
else
begin
Left; Paint;
Left; Paint;
end
85
Задание if9
Мудрёное задание со стенами (Рис. 1).
Рис. 1. У стены
Если стен меньше двух, то нужно закрасить исходную клетку (Рис. 1⬆ и 2).
Если же на поле 2 стены, то следует закрасить 2 клетки – одну выше исходной,
а другую – ниже (Рис. 3).
86
Рис. 2. Где стены?
Рис. 3. Крутите головой!
87
//число стен:
var nWall := 0;
//идём влево:
Left;
//есть стена?
if (WallFromDown
then nWall +=
//возвращаемся:
Right;
//идём вправо:
Right;
//есть стена?
if (WallFromDown
then nWall +=
//возвращаемся:
Left;
or WallFromUp)
1;
or WallFromUp)
1;
//сколько насчитали стен:
if (nWall < 2) then
begin
Paint;
end
else //2 стены
begin
//закрашиваем клетку выше:
Up; Paint;
//закрашиваем клетку ниже:
Down; Down; Paint;
//возвращаемся на базу:
Up;
end;
88
Задание if10
Вариации на тему «есть стены – нет стен», но с закрашенными клетками (Рис.
1).
Рис. 1. В зелени
Если закрашенных клеток слева и/или справа нет, то Робот должен закрасить
стартовую клетку, в противном случае – клеткой выше (Рис. 2).
Робот должен посчитать закрашенные клетки справа и слева от стартовой
клетки. Если ни одной закрашенной клетки он не обнаружит, то закрашивает
стартовую клетку. Если обнаружит, делает шаг вверх, закрашивает клетку и
возвращается на базу
89
Рис. 2. Выбирай – но осторожно
//число клеток:
var nCell := 0;
//идём влево:
Left;
//клетка закрашена?
if (CellIsPainted)
then nCell += 1;
//возвращаемся:
Right;
//идём вправо:
Right;
//клетка закрашена?
if (CellIsPainted)
then nCell += 1;
//возвращаемся:
Left;
//сколько насчитали закрашенных клеток:
if (nCell = 0) then
begin
90
Paint;
end
else // > 0
begin
//закрашиваем клетку выше:
Up; Paint;
//возвращаемся на базу:
Down;
end;
Задание if11
Последнее задание в этом наборе (Рис. 1).
Рис. 1. Это конец!
91
Справа от Робота может быть 0..2 закрашенные клетки (Рис. 2). Он должен
найти первую незакрашенную клетку в вертикали с этими клетками, которая
находится не выше стартовой, закрасить её и проследовать на базу.
Рис. 2. Могут быть варианты
Первый ход Робота очевиден – он должен сделать шаг вправо:
//шаг вправо:
Right;
Теперь Робот должен сосчитать закрашенные клетки и сохранить их число в
переменной nCell, чтобы потом попасть на базу:
//число закрашенных клеток:
var nCell := 0;
Если Робот сразу оказался на пустой клетке, то вниз он не пойдёт. Если же под
ним закрашенная клетка, то он считает её и шагает вниз:
92
//шагать вниз, пока Робот
//стоит на закрашенной клетке:
if (CellIsPainted) then
begin
nCell += 1;
Down;
end;
Затем он повторяет это действие ещё раз:
if (CellIsPainted) then
begin
nCell += 1;
Down;
end;
Независимо от числа закрашенных клеток сейчас Робот стоит на первой незакрашенной в текущей вертикали и закрашивает её:
//Робот закрашивает первую
//незакрашенную клетку в текущей
//вертикали:
Paint;
Основная часть задания выполнена, Робот переходит на следующую вертикаль и поднимается на nCell клеток:
//шаг вправо:
Right;
//и nCell шагов вверх до базы:
for var i := 1 to nCell do
Up;
Робот на базе!
93
Набор заданий w
Этот набор нацелен на отработку навыков применения цикла с условием
while.
В наборе 17 заданий, которые загружаются, как обычно (Рис. 1).
Рис. 1. Хорошее число!
Задание w1
В первом задании Робот должен идти вправо до базы, причём длина пути заранее неизвестна, поэтому мы не можем использовать цикл for (Рис. 1).
Цикл while выполняется до тех пор, пока верно некое условие. Так как в этом
задании отсутствуют закрашенные клетки, то Робот должен определить,
находится ли справа от него свободная клетка. Пока такая клетка имеется, Робот переходит на неё:
while (FreeFromRight) do
Right;
94
Другим признаком продолжения движения вправо может служить отсутствие
стены в текущей клетке:
while (not WallFromRight) do
Right;
В любом случае Робот благополучно доберётся до базы (Рис. 2).
Рис. 1. Вдоль по коридору
95
Рис. 2. На базе!
Задание w2
Задание, подобное предыдущему, но отягощённое необходимостью закрашивать клетки (Рис. 1).
Так как число команд Paint равно 11, а число команд Right – 10, то одну команду Paint необходимо выполнить до цикла while:
//закрашиваем первую клетку:
Paint;
while (FreeFromRight) do
begin
96
Right;
Paint;
end;
Рис. 1. Надо красить
Или после него:
while (FreeFromRight) do
begin
Paint;
Right;
end;
//закрашиваем последниюю клетку:
Paint;
97
Задание w3
Это задание отличается от первого только тем, что Робот должен определять
не пустые клетки, а стену под ним (Рис. 1).
Рис. 1. По стеночке
Робот переходит вправо, пока под ним стена:
while (WallFromDown) do
Right;
98
Задание w4
Практически такое же задание, что и предыдущее, но Робот должен определять закрашенные клетки (Рис. 1).
Рис. 1. Осторожно: окрашено!
Так как стартовая клетка чистая, то для начала Робот должен перебраться на
закрашенную клетку, а дальше двигаться, пока такие клетки не закончатся:
Right;
while (CellIsPainted) do
Right;
99
Задание w5
Теперь Робот находится не перед горизонтальным рядом закрашенных клеток, а в верхнем левом углу прямоугольника из таких клеток (Рис. 1).
Рис. 1. Прямо угольно!
100
Решение задачи распадается на две части.
Сначала Робот идёт вправо по закрашенным клеткам, а затем вниз. Но здесь
важно учесть, что после окончания цикла while Робот окажется за пределами
закрашенного прямоугольника, поэтому ему потребуется ещё 1 дополнительный шаг, чтобы вернуться на него:
//идём вправо по закрашенным клеткам:
while (CellIsPainted) do
Right;
//возвращаемся на закрашенную клетку:
Left;
//идём вниз по закрашенным клеткам:
while (CellIsPainted) do
Down;
//возвращаемся на базу:
Up;
Задание w6
В этом задании Роботу предстоит найти брешь в горизонтальной стене, которая находится ниже стартовой клетки, пройти через неё и добраться до базы в
правом нижнем углу (Рис. 1).
Нетрудно описать все четыре этапа долгого пути на базу:
1. Робот шагает вниз до стены.
2. Робот идёт вправо до прохода в этой стене.
3. Робот опять идёт вниз до стены поля.
4. Робот идёт до правой стены поля.
101
Рис. 1. Ищите бреши!
Или то же самое – в коде:
//Робот идёт вниз, пока нет стены:
while (FreeFromDown) do
Down;
//Робот идёт вправо, пока под ним стена:
while (WallFromDown) do
Right;
//Робот идёт вниз, пока нет стены:
while (FreeFromDown) do
Down;
//Робот идёт вправо до стены:
while (FreeFromRight) do
Right;
102
Задание w7
Робот должен проложить свой путь через закрашенные клетки (Рис. 1).
Рис. 1. По всем клеткам
Первая закрашенная клетка находится справа от начальной позиции Робота, и
он попадёт на неё, если будет шагать вправо, пока находится на чистой клетке:
//идём вправо до первой закрашенной клетки:
while (CellIsFree) do
Right;
103
Первый участок пути пройден: Робот стоит на первой зелёной клетке. Он
должен вернуться на чистую клетку, чтобы продолжить свой путь. Из условия
задачи известно, что вторая клетка находится выше первой, поэтому сначала
Робот делает 1 шаг вверх, а затем идёт в этом направлении, пока не окажется
на второй зелёной клетке:
//идём вверх ко второй закрашенной клетки:
Up;
while (CellIsFree) do
Up;
Здесь он должен изменить направление своего движения и пойти направо:
//идём вправо до третьей закрашенной клетки:
Right;
while (CellIsFree) do
Right;
Задание w8
В этом задании Роботу предстоит закрасить клетки, расположенные над стеной, причём длина стены заранее неизвестна (Рис. 1).
Для нас важно, что база всегда находится у левой стены поля!
Так как справа от Робота могут быть закрашиваемые клетки, то он сначала
должен пойти вправо. В принципе, он может сразу же закрашивать их, но при
движении влево Робот снова окажется на них. Чтобы не закрашивать клетки
дважды или не проверять, закрашены ли они уже раньше, Робот просто бодрым строевым шагом идёт вправо, пока не закончится стена под ним:
104
Рис. 1. Красим сверху
//идём вправо, пока внизу стена:
while (WallFromDown) do
Right;
Теперь он может идти на базу и по пути весело закрашивать все клетки, которые находятся над стеной:
//идём влево до стены и закрашиваем клетки
while (FreeFromLeft) do
begin
Left;
105
//если внизу стена,
//закрашиваем клетку:
if (WallFromDown) then
Paint;
end;
Задание w9
Эту задачу можно образно назвать так: переход Робота через стену (Рис. 1).
Рис. 1. Перевал
106
Стена всегда вертикальная, переменной высоты. Робот стартует от нижней
стены поля, а финиширует также у нижней стены, но через стенку.
Робот легко поднимется до самой верхней клетки с точкой:
//идём вверх, пока справа стена,
//и закрашиваем клетки
while (WallFromRight) do
begin
Paint;
Up;
end;
По ходу движения он уже закрасил все клетки, но не самую верхнюю – её он
должен закрасить дополнительно:
//закрашиваем самую верхнюю клетку:
Paint;
Робот переваливает через стену и закрашивает верхнюю клетку в следующей
вертикали:
//идём вправо над стеной:
Right;
//закрашиваем верхнюю клетку справа:
Paint;
Дальнейший его путь прост и прям: он идёт до границы поля и закрашивает
клетки:
//опускаемся до базовой клетки
//и закрашиваем клетки:
while (FreeFromDown) do
begin
Down;
Paint;
end;
107
Задание w10
Это задание – усложнённый вариант предыдущего (Рис. 1).
Рис. 1. Двойной перевал
Робот должен перебраться через две стены, закрашивая клетки. Стартовая
клетка находится в левом нижнем углу поля, а финишная – в правом нижнем.
Чтобы воспользоваться алгоритмом предыдущего задания, мы должны переместить Робота к первой стене:
//идём вправо до стены:
while (FreeFromRight) do
108
Right;
Перевал через стену наш Робот уже хорошо освоил:
//идём вверх, пока справа стена,
//и закрашиваем клетки
while (WallFromRight) do
begin
Paint;
Up;
end;
//закрашиваем самую верхнюю клетку:
Paint;
//идём вправо над стеной:
Right;
//закрашиваем верхнюю клетку справа:
Paint;
//опускаемся до базовой клетки
//и закрашиваем клетки:
while (FreeFromDown) do
begin
Down;
Paint;
end;
Легко заметить, что путь до второй стены и её преодоление в точности совпадает с его путём для первой стены. Это значит, что написанную нами часть кода нужно оформить в виде процедуры, чтобы не повторяться. Однако в этом
наборе заданий процедуры не предусмотрены, поэтому придётся скопировать
весь код.
Закончив покрасочные работы, Робот спешит на базу за моральным и увесистым материальным вознаграждением:
//Робот идёт вправо до стены //на базу:
while (FreeFromRight) do
Right;
109
Задание w11
Задание практически идентично w9, но два ряда клеток с точками разделяет
горизонтальная стена (Рис. 1).
Рис. 1. Разделительная стена
Робот обходит стену по уже известному вам алгоритму:
//идём вправо, пока внизу стена,
//и закрашиваем клетки
Right;
while (WallFromDown) do
begin
110
Paint;
Right;
end;
//закрашиваем самую правую клетку:
Paint;
//идём вниз:
Down;
//закрашиваем правую клетку снизу:
Paint;
//идём влево и закрашиваем клетки:
Left;
while (WallFromUp) do
begin
Paint;
Left;
end;
Но в этом задании он ещё должен вернуться на базу в стартовой клетке:
//возвращаемся на базу:
Paint;
Up;
Paint;
Задание w12
В этом задании Роботу предстоит закрасить 4 стороны прямоугольника (Рис.
1).
Робот может выбрать 2 направления обхода – по часовой стрелке и против
неё. Нам, конечно, более привычен первый вариант, поэтому закрашиваем
начальную клетку и делаем шаг вправо, чтобы под Роботом оказалась стена.
//закрашиваем верхнюю сторону прямоугольника:
Paint; Right;
111
Рис. 1. Прямоугольный обход
Теперь Робот идёт вправо и закрашивает клетки:
while (WallFromDown) do
begin
Paint;
Right;
end;
В результате этих действий Робот окажется в самой правой клетке верхней
стороны прямоугольника. Дальше он обходит стены по тому же сценарию, что
и раньше:
112
//закрашиваем правую сторону прямоугольника:
Paint; Down;
while (WallFromLeft) do
begin
Paint;
Down;
end;
//закрашиваем нижнюю сторону прямоугольника:
Paint; Left;
while (WallFromUp) do
begin
Paint;
Left;
end;
Когда Робот вернётся на базу, то попадёт на уже закрашенную клетку:
//закрашиваем левую сторону прямоугольника:
Paint; Up;
while (WallFromRight) do
begin
Paint;
Up;
end;
Задание w13
Невероятно простое задание, в котором Робот должен подниматься вверх, пока с двух сторон от него находятся стены (Рис. 1).
Решение просто повторяет условие задачи:
while (WallFromLeft and WallFromRight) do
Up;
113
Рис. 1. Между двух стен
Задание w14
Почти такое же задание, но Робот должен подниматься, пока слева и справа от
него имеется хотя бы одна стена (Рис. 1).
Опять достаточно переписать условие задачи на паскаль:
while (WallFromLeft or WallFromRight) do
Up;
114
Рис. 1. Разновысотные стены
Задание w15
Очередное задание на сложное логическое условие (Рис. 1).
Важно правильно сформулировать его. По условию задачи, Робот должен идти
вправо до тех пор, пока под ним стена или незакрашенная клетка:
//пока внизу стена или
//чистая клетка,
//идём вправо:
115
while (WallFromDown or CellIsFree) do
Right;
Рис. 1. Будет сложно
Когда условие, записанное в скобках, станет ложным, Робот будет стоять в
первой закрашенной клетке, под которой нет стены. Тогда он должен сделать
шаг вниз и закрасить базовую клетку:
//опускаемся на клетку ниже и
//закрашивае её:
Down; Paint;
116
Задание w16
На этот раз Робота ожидает сложная работа (Рис. 1)!
Рис. 1. Ещё сложнее
Было бы неразумно поочерёдно обходить все стены, чтобы найти последнюю.
Правильный способ передвижения такой. Поднимаемся вверх на 1 клетку (или
опускаемся) и обходим забор сверху – пока не упрёмся в правую стену поля:
//делаем шаг вверх:
Up;
//и идём до правой стены:
while (not WallFromRight) do
117
Right;
Возвращаемся на свою горизонталь и идём вправо до забора:
//опускаемся на горизонталь с забором:
Down;
//и идём влево до стены:
while (not WallFromLeft) do
Left;
Задание w17
По сравнению с предыдущим заданием изменился только вид забора (Рис. 1).
Исходный же код остался без изменений:
//делаем шаг вверх:
Up;
//и идём до правой стены:
while (not WallFromRight) do
Right;
//опускаемся на горизонталь с забором:
Down;
//и идём влево до стены:
while (not WallFromLeft) do
Left;
118
Рис. 1. Тех же щей, да погуще влей!
119
Набор заданий cif
В этом наборе 22 задания на циклы и условные операторы (Рис. 1).
Рис. 1. Придётся потрудиться
Задание cif1
Робот идёт вправо до упора и закрашивает клетки, над которыми нависает
стена (Рис. 1).
Робот проверяет в цикле while, не дошёл ли он до стены справа:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
И каждую клетке, над которой имеется стена, Робот закрашивает:
//если сверху стена,
//закрашиваем клетку:
if (WallFromUp) then
Paint;
120
end;
Рис. 1. Красим под стенами
Задание cif2
Это задание отличается от предыдущего только тем, что стены могут быть и
сверху, и снизу (Рис. 1).
Немного усложняем логическое условие в операторе if – и задача решена:
121
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если сверху или снизу стена,
//закрашиваем клетку:
if (WallFromUp or WallFromDown) then
Paint;
end;
Рис. 1. Двухстенник
122
Задание cif3
В этом задании мы встречаем старые стены, но теперь Робот должен закрашивать только те клетки, которые находятся между двух стен (Рис. 1).
Рис. 1. Простенки
Чтобы решить задачу, достаточно изменить логическое условие:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если сверху и снизу стена,
//закрашиваем клетку:
123
if (WallFromUp and WallFromDown) then
Paint;
end;
Задание cif4
Напряжение нарастает! Робот должен закрасить только те клетки, над которыми есть стена, а под ними стены нет (Рис. 1).
Рис. 1. Снизу пусто, а сверху - стена
И опять всё решает небольшое изменение в логическом условии:
124
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если сверху стена,
//а снизу нет,
//то закрашиваем клетку:
if (WallFromUp and FreeFromDown) then
Paint;
end;
Задание cif5
Ну очень «сложное» задание! Робот должен закрасить только такие клетки,
для которых не выполняется условие: если сверху есть стена, а снизу нет (Рис.
1).
Рис. 1. Очень сложно
125
Это условие уже не столь просто для понимания, как предыдущие, поэтому над
ним нужно подумать:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если неверно, что сверху стена,
//а снизу нет,
//то закрашиваем клетку:
if not (WallFromUp and FreeFromDown) then
Paint;
end;
Задание cif6
Задание такое: закрасить клетки, которые не лежат между двух стен (Рис. 1).
Рис. 1. Меньше двух стен
126
Условие закрашивания клеток такое: сверху или снизу от клетки свободно:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если сверху или снизу,
//нет стены,
//то закрашиваем клетку:
if (FreeFromDown or FreeFromUp) then
Paint;
end;
Задание cif7
Жуткая картина (Рис. 1)!
Здесь уже одним логическим оператором не обойтись – их потребуется пара.
Если клетка сверху свободна, то Робот делает шаг вверх и закрашивает её:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если сверху нет стены,
//то закрашиваем клетку сверху:
if (FreeFromUp) then
begin
Up;
Paint;
//возвращаемся на свою горизонталь:
Down;
end;
127
Рис. 1. Ужас!
Важно после каждого подъёма возвращаться на свою горизонталь!
Отсутствие стены снизу Робот обрабатывает аналогично:
//если снизу нет стены,
//то закрашиваем клетку снизу:
if (FreeFromDown) then
begin
Down;
Paint;
Up;
128
end;
end;
Задание cif8
Ещё одно задание на 2 логических условия (Рис. 1).
Рис. 1. Двойная логика
На Рис. 1⬆ хорошо видно, что:
1. Робот должен закрасить клетку сверху, если стена снизу.
129
2. Робот должен закрасить клетку снизу, если стена сверху.
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если снизу есть стена,
//то закрашиваем клетку сверху:
if (WallFromDown) then
begin
Up;
Paint;
//возвращаемся на свою горизонталь:
Down;
end;
//если сверху есть стена,
//то закрашиваем клетку снизу:
if (WallFromUp) then
begin
Down;
Paint;
Up;
end;
end;
Задание cif9
Это задание – усложнённый вариант предыдущего. Здесь Робот должен ещё
закрашивать клетки между двумя горизонтальными стенами (Рис. 1).
Чтобы справиться с заданием, Робот должен после каждого шага вправо проверять наличие двух стен – сверху и снизу:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
if (WallFromDown and WallFromUp) then
130
begin
Paint;
End
Рис. 1. Вариант!
Если стен меньше двух, Робот действует, как в Задании cif8:
//если снизу есть стена,
//то закрашиваем клетку сверху:
else if (WallFromDown) then
begin
Up;
Paint;
//возвращаемся на свою горизонталь:
131
Down;
end
//если сверху есть стена,
//то закрашиваем клетку снизу:
else if (WallFromUp) then
begin
Down;
Paint;
Up;
end;
end;
Задание cif10
Робот должен закрасить клетки, которые находятся ниже изначально закрашенных, если под ними нет стены (Рис. 1).
Алгоритм решения задачи простой и прямо вытекает из условия:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//Робот закрашивает клетку,
//которая находится ниже закрашенной
//и под которой чистая клетка:
if (CellIsPainted and FreeFromDown) then
begin
Down;
Paint;
Up;
end;
end;
132
Рис. 1. Красим снизу
Задание cif11
В этом задании Робот должен закрасить клетку, если одновременно выполняются 3 условия, поэтому логические выражения соединяются двумя операторами and (Рис. 1).
Добавляем в исходный код Задания cif10 ещё одно логическое условие – и задача решена:
//идём вправо до стены:
133
while (FreeFromRight) do
begin
Right;
//Робот закрашивает клетку,
//которая находится ниже закрашенной
//под которой чистая клетка,
//а сверху - стена:
if (CellIsPainted and FreeFromDown and WallFromUp) then
begin
Down;
Paint;
Up;
end;
end;
Рис. 1. И - И
134
Задание cif12
Нам необходимо хорошенько проанализировать ситуацию на поле, чтобы вывести логические условия для закрашивания клеток (Рис. 1).
Рис. 1. Анализируй всё!
1. Клетки закрашиваются только выше горизонтали Робота.
2. Над ними нет стены.
3. Клетка с Роботом закрашенная.
4. Если клетка с Роботом чистая, то под ней не должно быть стены.
На этом разработку алгоритма можно считать законченной, и мы просто записываем его на языке паскаль:
135
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//Робот закрашивает клетку сверху,
//если там нет стены:
if (FreeFromUp and (CellIsPainted or (CellIsFree and FreeFromDown)))
then
begin
Up;
Paint;
Down;
end;
end;
Задание cif13
Это задание также на составление сложного логического выражения (Рис.
1).
Рис. 1. Не бойтесь сложностей!
136
Анализируем позицию на поле:
1. Робот закрашивает клетку над собой.
2. Над клеткой с Роботом не должно быть стены.
3. Если он стоит в закрашенной клетке, то под ней должна быть стена.
4. В противном случае под ней не должно быть стены.
Условие 2 верно для всех клеток на горизонтали Робота, поэтому его можно
не проверять. Остаётся записать условия 3 и 4:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//Робот закрашивает клетку сверху,
//если он стоит в закрашенной клетке И
//под ним стена ИЛИ
//Робот стоит в незакрашенной клетке И
//под ним нет стены:
if (CellIsPainted and WallFromDown) or
FreeFromDown) then
begin
Up;
Paint;
Down;
end;
end;
(CellIsFree and
Задание cif14
Задание довольно простое, если правильно понять условие закрашивания клеток (Рис. 1).
Легко видеть, что Робот закрашивает клетки, которые находятся под закрашенными. Однако, находясь на своей горизонтали, Робот не может определить
цвет клетки ниже, поэтому он должен сделать шаг вниз, а это действие возможно только если под его клеткой нет стены.
137
Рис. 1. Проводим условные операции
Алгоритм готов:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если снизу нет стены,
//Робот делает шаг вниз:
if (FreeFromDown) then
begin
Down;
//если он оказался в закрашенной клетке,
//то делает ещё шаг вниз и
138
//закрашивает клетку:
if (CellIsPainted) then
begin
Down;
Paint;
//Робот возвращается на
//свою горизонталь:
Up;
end;
Up;
end;
end;
Здесь важно учесть, что после закрашивания клетки Робот должен сделать 2
шага вверх, а без закрашивания – только 1.
Задание cif15
Задача несложная, но требует внимания при прокладывании маршрута Робота
(Рис. 1).
Рис. 1. Прокладываем пути
139
Робот сначала делает шаг вверх (или вниз). Если там закрашенная клетка, то
он должен проверить и нижнюю клетку. Для этого он делает 2 шага вниз. Если
и вторая клетка закрашенная, то он поднимается в свою горизонталь и закрашивает клетку. Если же нижняя клетка чистая, то он просто поднимается в
свою горизонталь. И наконец, если верхняя клетка оказалась чистой, то он
возвращается в свою горизонталь, делая шаг вниз:
//идём вправо до стены:
while (FreeFromRight) do
begin
Right;
//если снизу и сверху закрашенные клетки,
//то Робот закрашивает клетку,
//на которой стоит:
Up;
if (CellIsPainted) then
begin
Down;
Down;
if (CellIsPainted) then
begin
Up;
Paint;
end
else
Up;
end
//Робот возвращается на свою горизонталь:
else
Down;
end;
Задание cif16
Подобную задачу мы уже решали в Задании if3, но там поле было маленькое и
одного размера. Сейчас же Роботу предстоит перейти в противоположный
угол на поле произвольного размера (Рис. 1).
140
Рис. 1. Поле произвола
Проще всего сначала определить угол, в котором находится Робот:
//направление на стены:
var dir := 0;
if (WallFromUp) then
dir += 1;
if (WallFromDown) then
dir += 2;
if (WallFromLeft) then
dir += 4;
if (WallFromRight) then
dir += 8;
141
А вот теперь его легко провести по стеночкам на базу.
Если он стоит у левой стены, то идёт вправо до упора. Если у правой, то влево:
//Робот у левой стены:
if ((dir = 5) or (dir = 6)) then
begin
while(FreeFromRight) do
Right;
end;
//Робот у правой стены:
if ((dir = 9) or (dir = 10)) then
begin
while(FreeFromLeft) do
Left;
end;
Затем Робот аналогично выбирает направление перехода в зависимости от того, у какой второй стены он находится – у нижней или у верхней:
//Робот у нижней стены:
if ((dir = 6) or (dir = 10)) then
begin
while(FreeFromUp) do
Up;
end;
//Робот у верхней стены:
if ((dir = 5) or (dir = 9)) then
begin
while(FreeFromDown) do
Down;
end;
Можно и не определять положение Робота, а сразу шагать в свободную сторону до стены:
142
//если справа свободно,
//идём вправо до стены:
if (FreeFromRight) then
while(FreeFromRight) do
Right
//если слева свободно,
//идём влево до стены:
else if (FreeFromLeft) then
while(FreeFromLeft) do
Left;
//если сверху свободно,
//идём вверх до стены:
if (FreeFromUp) then
while(FreeFromUp) do
Up
//если снизу свободно,
//идём вниз до стены:
else if (FreeFromDown) then
while(FreeFromDown) do
Down;
Задание cif17
Задание: пройти по коридору до конца (Рис. 1).
У коридора обязательно есть вертикальная часть, которую необходимо пройти в первую очередь:
//Робот идёт вверх до упора:
while (FreeFromUp) do
Up;
Затем коридор может повернуть направо или налево (или вообще не повернуть).
143
Рис. 1. Кривая дорожка
Направление поворота легко определить по отсутствию стены. Если стена отсутствует слева, то и Робот должен идти влево:
//в какую сторону поворачивает коридор?
if (FreeFromLeft) then //влево
while (FreeFromLeft) do
Left
Если же отсутствует стена справа, то и Робот марширует вправо:
else if (FreeFromRight) then //вправо
144
while (FreeFromRight) do
Right;
Если все стены на месте, то там же и Робот:
//не поворачивает
Задание cif18
Лёгкая прогулка для Робота (Рис. 1).
Рис. 1. Большая прогулка
145
Алгоритм простой!
1. Робот шагает строго направо.
2. После каждого шага определяет цвет своей клетки.
3. Если она белая, то верхний ряд закончился, и Робот на базе.
4. Если зелёная, то Робот делает шаг вниз, чтобы определить цвет нижней
клетки.
5. Если она белая, значит, закончился нижний ряд.
6. Если зелёная, то Робот поднимается на свою горизонталь и продолжает шагать вправо.
//Робот идёт вправо:
while (FreeFromRight) do
begin
Right;
//короткий ряд верхний:
if (CellIsFree) then
begin
//он уже на базе:
break;
end
//иначе он проверяет клетку снизу:
else
begin
Down;
if (CellIsFree) then
//он уже на базе:
break
//возвращается в свою горизональ:
else
Up;
end;
end;
Задание cif19
База находится сразу после окончания более короткой стены (Рис. 1).
146
Рис. 1. Измеряем стены
В этой ситуации Робот может действовать несколькими способами. Например,
каждый шаг проверять, не закончилась ли одна из стен.
Но наш Робот действует иначе.
Он идёт вправо, пока под ним нижняя стена. В итоге он окажется в первой свободной клетке своей горизонтали:
//Робот идёт до конца нижней стены:
while (WallFromDown) do
Right;
//нижняя стена закончилась
147
Если нижняя стена короче, то он будет на базе. Но Робот не умеет определять
клетку с базой, поэтому он должен проверить, не закончилась ли раньше верхняя стена.
Для этого он шагает вверх на 1 клетку и, если над ним нет стены, он идёт влево, пока она не появится. После этого он должен сделать шаг вправо, чтобы
оказаться на базе.
Если сразу после шага вверх над Роботом окажется стена, значит, верхняя стена длиннее, и он делает шаг вниз, чтобы вернуться на базу:
//проверяем верхнюю:
Up;
if (FreeFromUp) then
begin
while (FreeFromUp) do
Left;
//на базе:
Right;
end
//возвращаемся на базу:
else
Down;
Задание cif20
Предыдущее задание, но наоборот: Робот должен дойти до базы после длинной стены (Рис. 1).
Забота для Робота даже проще, чем предшествующая. Сначала он идёт до конца нижней стены, а затем поднимается вверх и проверяет верхнюю:
//Робот идёт до конца нижней стены:
while (WallFromDown) do
Right;
//нижняя стена закончилась
148
//проверяем верхнюю:
Up;
Рис. 1. Удлиняем
Если над ним стена, значит, верхняя стена длиннее, и он идёт вправо до базы:
if (WallFromUp) then
begin
while (WallFromUp) do
Right;
//на базе
end
149
Если же верхняя стена короче, то Робот спускается на базу:
//возвращаемся на базу:
else
Down;
Задание cif21
В горизонтали с Роботом находится закрашенная клетка – справа или слева от
него. Он должен найти её и идти вниз до второй закрашенной клетки (Рис. 1).
150
Рис. 1. Ищем вторую клетку
Робот может сначала пойти влево. Если он не найдёт закрашенную клетку, то
пойдёт вправо. В любом случае он найдёт первую закрашенную клетку и пойдёт вниз до второй закрашенной клетки:
//верное направление:
var dir := false;
//пока слева чистые клетки,
//Робот идёт влево:
while (FreeFromLeft) do
begin
Left;
if (CellIsPainted) then
begin
dir := true;
break;
end
end;
//первая закрашенная клетка - справа:
if (not dir) then
//Робот идёт вправо:
while (FreeFromRight and CellIsFree) do
Right;
151
//Робот идёт вниз до второй
//закрашенной клетки:
Down;
while (FreeFromDown and CellIsFree) do
begin
Down;
end;
Флаг dir показывает, нашёл ли Робот закрашенную клетку слева, чтобы не искать её справа.
Задание cif22
Самое сложное задание в этом наборе! Робот должен выбраться из коридора и
добраться до базы в левом верхнем углу поля (Рис. 1).
Рис. 1. Выход должен быть!
152
Выход может быть слева, справа, снизу или сверху (Рис. 2).
Рис. 2. Возможны варианты!
153
Так как выход может быть в четырёх направлениях, в зависимости от чего Робот должен проложить свой путь на базу, то ему предстоит большая работа по
исследованию «лабиринта»!
Прежде всего, нам потребуется переменная dir, в которую мы будем записывать направление выхода:
1 – выход слева
2 – выход снизу
3 – выход сверху
4 – выход справа
0 – выход не найден
//направление выхода:
var dir := 0;
В данном случае Робот может пойти сначала влево, потом вправо, а может и
наоборот.
Пусть он идёт влево. Тогда:
1. Если над ним и под ним нет стен, значит, выход слева.
2. Если под ним нет стены, значит, выход снизу.
3. Если над ним нет стены, значит, выход сверху.
И так он продолжает шагать влево, пока не упрётся в стену или не найдёт выход:
//Робот идёт влево:
while (true) do
begin
if (FreeFromDown and FreeFromUp) then
begin
dir := 1;
break;
end
else if (FreeFromDown) then
begin
154
dir := 2;
break;
end
else if (FreeFromUp) then
begin
dir := 3;
break;
end
else if (FreeFromLeft) then
Left
else
break;
end;
Если слева выхода нет, то Робот аналогично исследует правую часть коридора:
//Робот идёт вправо:
if (dir = 0) then
while (FreeFromRight) do
begin
Right;
if (FreeFromDown and FreeFromUp) then
begin
dir := 4;
break;
end
else if (FreeFromDown) then
begin
dir := 2;
break;
end
else if (FreeFromUp) then
begin
dir := 3;
break;
end
end;
Теперь Робот знает направление выхода и стоит как раз перед ним.
155
Если выход слева, то он идёт влево до стены поля, а затем поднимается вверх:
//выход слева:
if (dir = 1) then
begin
while (FreeFromLeft) do
Left;
while (FreeFromUp) do
Up;
end
Если выход снизу, то Робот опускается до нижней стены поля, идёт влево до
стены и поднимается на базу:
//выход снизу:
else if (dir = 2) then
begin
while (FreeFromDown) do
Down;
while (FreeFromLeft) do
Left;
while (FreeFromUp) do
Up;
end
Аналогично Робот действует и в тех случаях, когда выход сверху или справа:
//выход сверху:
else if (dir = 3) then
begin
while (FreeFromUp) do
Up;
while (FreeFromLeft) do
Left;
end
//выход справа:
156
else
begin
while (FreeFromUp) do
Up;
while (FreeFromLeft) do
Left;
end
157
Набор заданий count
В этом наборе – 17 заданий (Рис. 1).
Рис. 1. Считать – не пересчитать!
В них Роботу придётся считать свои шаги, а для этого ему потребуется переменная.
Задание count1
Самое простое задание на подсчёт шагов (Рис. 1).
Для подсчёта шагов Робот использует переменную step, значение которой
сначала равно нулю:
//число шагов:
var step := 0;
По условию задачи, Робот должен дойти до правой стены:
//Робот идёт вправо до стены и
//считает шаги:
while (FreeFromRight) do
158
begin
Right;
step += 1
end;
Рис. 1. Программирование любит счёт
Клетку у стены он закрашивает:
//Робот закрашивает клетку:
Paint;
159
Чтобы вернуться на прежнее место, Робот должен пройти влево столько же
шагов, сколько он сделал вправо:
//Робот возвращается на базу:
while (step > 0) do
begin
step -= 1;
Left;
end;
Задание count2
Более сложное задание на 2 счётчика: Робот должен дойти до правого нижнего угла, закрасить там клетку и вернуться на базу (Рис. 1).
Рис. 1. Двойной счётчик
160
Код программы легко написать, учитывая, что Робот последовательно перемещается в двух направлениях – вправо и вниз:
//число шагов вправо:
var stepRight := 0;
//число шагов вниз:
var stepDown := 0;
//Робот идёт вправо до стены и
//считает шаги:
while (FreeFromRight) do
begin
Right;
stepRight += 1
end;
//Робот идёт вниз до стены и
//считает шаги:
while (FreeFromDown) do
begin
Down;
stepDown += 1
end;
//Робот закрашивает клетку:
Paint;
//Робот возвращается на базу:
while (stepRight > 0) do
begin
stepRight -= 1;
Left;
end;
while (stepDown > 0) do
begin
stepDown -= 1;
Up;
end;
161
Задание count3
Задание, аналогичное предыдущему, но база расположена симметрично относительно нисходящей диагонали квадрата (Рис. 1).
Рис. 1. Симметрично
Робот всегда стартует с клетки, которая ниже и левее финишной!
Робот может выбрать направление движения – либо вправо, либо вверх.
Пусть он идёт вправо и считает шаги до закрашенной клетки:
//число шагов вправо:
162
var stepRight := 0;
while (CellIsFree) do
begin
stepRight += 1;
Right;
end;
Так как закрашенная клетка лежит симметрично относительно стартовой, то
Робот должен сделать столько же шагов вверх, сколько он сделал вправо:
//Робот идёт на базу:
while (stepRight > 0) do
begin
stepRight -= 1;
Up;
end;
Задание count4
Робот должен прийти на базу, которая находится под стартовой клеткой, но её
отделяет от стартовой клетки горизонтальная стена (Рис. 1).
Робот всегда обходит стену по часовой стрелке.
Это задание – лёгкая прогулка для нашего подопечного.
Он идёт вправо, пока под ним не закончится стена, добросовестно считая при
этом каждый свой шаг. Затем делает шаг вниз и делает столько же шагов в
противоположном направлении:
//число шагов вправо:
var stepRight := 0;
//Робот идёт вправо,
//пока под ним стена:
163
while (WallFromDown) do
begin
stepRight += 1;
Right;
end;
//Робот делает шаг вниз:
Down;
//Робот идёт на базу:
while (stepRight > 0) do
begin
stepRight -= 1;
Left;
end;
Рис. 1. За стеной
164
Задание count5
Роботу предстоит совершить «кругосветное» путешествие, закрашивая по ходу движения клетки (Рис. 1).
Рис. 1. Вокруг да около стены
Клетки по периметру квадрата мы уже закрашивали, но теперь Робот занимает случайную стартовую позицию на поле. Поэтому, прежде всего, Робота
нужно установить, например, в верхний левый угол поля, тогда он без труда
закрасит все нужные клетки, обходя их по часовой стрелке (или в обратном
направлении). Но ему ещё предстоит вернуться в начальную позицию, поэтому
при перемещении в угол Робот должен отдельно считать шаги влево и вверх:
165
var stepLeft := 0;
var stepUp := 0;
while (FreeFromLeft) do
begin
stepLeft += 1;
Left;
end;
while (FreeFromUp) do
begin
stepUp += 1;
Up;
end;
//Робот закрашивает верхнюю сторону:
while (FreeFromRight) do
begin
Paint;
Right;
end;
//Робот закрашивает правую сторону:
while (FreeFromDown) do
begin
Paint;
Down;
end;
//Робот закрашивает нижнюю сторону:
while (FreeFromLeft) do
begin
Paint;
Left;
end;
//Робот закрашивает левую сторону:
while (FreeFromUp) do
begin
Paint;
Up;
end;
166
Чтобы вернуться на место, Робот должен сделать столько шагов вправо,
сколько он сделал влево, и столько шагов вниз, сколько он сделал вверх:
//Робот возвращается на базу:
while (stepLeft> 0) do
begin
stepLeft -= 1;
Right;
end;
while (stepUp > 0) do
begin
stepUp -= 1;
Down;
end;
Задание count6
Робот мечется между двумя стенами в попытках найти ближнюю (Рис. 1).
Чтобы определить, какая из двух стен ближе к стартовой позиции, Робот идёт
сначала влево, а затем вправо, считая шаги:
//число шагов влево:
var stepLeft := 0;
//число шагов вправо:
var stepRight := 0;
//Робот идёт влево:
while (FreeFromLeft) do
begin
stepLeft += 1;
Left;
end;
//Робот идёт вправо:
while (FreeFromRight) do
begin
stepRight += 1;
Right;
end;
167
Рис. 1. Буриданов Робот
Так как он считает шаги вправо не от начальной клетки, а от левой стены, то
нужно вычислить расстояние от начальной клетки до правой стены:
//до левой стены stepLeft клеток,
//а до правой:
stepRight -= stepLeft;
Если правая стена окажется ближе, чем левая, то Роботу ничего не нужно делать, ведь он уже на базе.
Если ближе левая стена, то он сможет пройти до неё нужное число шагов:
168
//если левая стена ближе,
//Робот идёт к ней:
if (stepLeft < stepRight) then
begin
stepLeft += stepRight;
while (stepLeft > 0) do
begin
stepLeft -= 1;
Left;
end;
end;
//если ближе правая стена,
//то он уже на месте
Но теперь шаги считать необязательно, поэтому Робот может просто шагать
влево, пока не упрётся в стену:
if (stepLeft < stepRight) then
while (FreeFromLeft) do
Left;
Задание count7
Робот должен обогнуть крючкообразную стену и дойти до базовой клетки, которая находится под стартовой, но их разделяет горизонтальная стена (Рис. 1).
Весьма хитроумное задание, над которым придётся поломать голову!
Вертикальная стена может препятствовать победному шествию нашего Робота как справа, так и слева. Робот может начать поиск стены с любого направления. Например, он пошёл влево:
var step := 0;
//СТЕНА СПРАВА?
169
//Робот идёт влево:
while (FreeFromLeft) do
begin
step += 1;
Left;
Рис. 1. Стены разделяют
170
Если на каком-то шаге под ним не окажется стены, значит, слева стены тоже
нет, поэтому Робот шагает вниз на 1 клетку, затем делает step шагов вправо –
и он на базе:
//стены снизу нет -->
//стены слева нет:
if (FreeFromDown) then
begin
//Робот делает шаг вниз и
//идёт направо - на базу:
Down;
while (step > 0) do
begin
step -= 1;
Right;
end;
exit;
end;
end;
Если Робот упёрся в левую стену, то он идёт вправо, пока под ним не закончится стена:
//СТЕНА СЛЕВА
//Робот идёт вправо:
while (WallFromDown) do
begin
step -= 1;
Right;
end;
После этого он идёт вниз, а затем влево – до базы:
Down;
while (step < 0) do
begin
step += 1;
Left;
end;
171
Задание count8
Робот должен остановиться на пятой закрашенной клетке, которая находится
справа от стартовой позиции (Рис. 1).
Рис. 1. Клетки по пять считают
При разработке алгоритма важно учесть, что:
1. Робот может сразу стоять на закрашенной клетке, поэтому сначала он считает клетки, а затем идёт вправо.
2. Робот должен сразу же прекратить движение, если окажется на пятой закрашенной клетке:
172
//счётчик закрашенных клеток:
var n := 0;
//Робот идёт вправо и считает закрашенные клетки:
while (true) do
begin
if (CellIsPainted) then
n += 1;
//Робот стоит на пятой закрашенной клетке //задание выполнено:
if (n = 5) then
break;
Right;
end;
Задание count9
Задание, очень похожее на предыдущее, но Робот считает только соседние закрашенные клетки (Рис. 1).
Рис. 1. Считаем соседей
173
Код практически не изменился, но каждая незакрашенная клетка сбрасывает
счётчик:
//счётчик закрашенных клеток:
var n := 0;
//Робот идёт вправо и считает закрашенные клетки:
while (true) do
begin
if (CellIsPainted) then
n += 1
//обнуляем счётчик, если
//встретилась незакрашенная клетка:
else n := 0;
//Робот стоит на пятой закрашенной клетке //задание выполнено:
if (n = 3) then
break;
Right;
end;
Задание count10
Робот должен закрасить клетки, под которыми находится стена. Но если стена
закончилась, а клеток закрашено меньше пяти, то Робот «докрашивает»
оставшиеся (Рис. 1).
В этом задании важно правильно сформулировать условие перемещения Робота вправо:
Пока под ним стена ИЛИ закрашено меньше пяти клеток:
//счётчик закрашенных клеток:
var n := 0;
//Робот идёт вправо и считает закрашенные клетки:
while (WallFromDown or (n < 5)) do
174
begin
Paint;
n += 1;
Right;
end;
Рис. 1. Опять пять
Задание count11
Роботу предстоит определить длину тупика и, если его длина больше 4 клеток,
то закрасить стартовую клетку, (Рис. 1).
175
Рис. 1. Путь в тупик
Роботу не обязательно идти до конца коридора. Если он насчитает 5 клеток,
то дальнейшие его шаги вправо ничего не изменят:
//счётчик клеток:
var n := 0;
//Робот идёт вправо и считает клетки:
while (FreeFromRight and (n < 5)) do
begin
n += 1;
Right;
end;
176
Робот в любом случае должен вернуться в исходную клетку:
//Робот возвращается
//на первую клетку:
for var i := 1 to n-1 do
Left;
Если Робот насчитал в коридоре не менее 5 клеток, то он закрашивает первую
клетку:
//Робот закрашивает первую
//клетку коридора:
if (n > 4) then
Paint;
Задание count12
Робот идёт на базу в конце коридора и закрашивает клетки через одну (Рис. 1).
Рис. 1. Чередуем
177
Нам удобнее считать клетки, начиная с единицы, поэтому пусть Робот сначала
занимает первую клетку:
//счётчик клеток:
var n := 1;
Теперь Робот может смело шагать вправо по коридору, как Штирлиц в сериале
Семнадцать мгновений весны, и считать клетки. Все чётные клетки он добровольно и добросовестно закрашивает:
while (FreeFromRight) do
begin
Right;
n += 1;
//чётные клетки Робот закрашивает:
if (n mod 2 = 0) then
Paint;
end;
Задание count13
В этом задании Робот закрашивает нечётные клетки (Рис. 1).
Казалось бы, нужно просто изменить условие в операторе if, но на самом деле
задача коварнее! Робот сразу стоит в клетке, которую требуется закрасить:
//счётчик клеток:
var n := 1;
//Робот закрашивает стартовую клетку:
Paint;
А вот дальше он идёт вперёд, не ведая забот:
178
while (FreeFromRight) do
begin
//шаг вправо:
Right;
n += 1;
//нечётные клетки Робот закрашивает
if (n mod 2 = 1) then
Paint;
end;
Рис. 1. По нечётным
179
Задание count14
Задача перед Роботом стоит практически такая же, как и в Задании count13, но
он должен закрашивать каждую третью клетку (Рис. 1).
Рис. 1. Через две на третью
Код окончательный и обжалованию не подлежит:
//счётчик клеток:
var n := 1;
while (FreeFromRight) do
begin
180
Right;
n += 1;
//каждую третью клетку Робот закрашивает:
if (n mod 3 = 0) then
Paint;
end;
Задание count15
А это задание повторяет count14, но закрашивать Роботу нужно каждую третью клетку по ходу своего движения вправо (Рис. 1).
Рис. 1. Проторёнными путями
181
Код оставляем без дополнительных комментариев:
//счётчик клеток:
var n := 1;
//Робот закрашивает стартовую клетку:
Paint;
while (FreeFromRight) do
begin
//шаг вправо:
Right;
n += 1;
//нечётные клетки Робот закрашивает
if (n mod 3 = 1) then
Paint;
end;
Задание count16
Интересное задание, в котором Робот должен закрасить клетки нечётных
пролётов (Рис. 1).
Номер пролёта совпадает с числом пройденных Роботом закрашенных клеток.
Сначала идёт нулевой пролёт:
//счётчик пролётов:
var n := 0;
Когда Роботу встретится первая закрашенная клетка (а это может быть и
стартовая клетка!), счётчик пролётов увеличится, то есть после нулевого следует первый пролёт:
while (FreeFromRight) do
begin
182
//Робот на закрашенной клетке:
if (CellIsPainted) then
begin
n += 1;
Right;
end;
Рис. 1. Пролёты
Сейчас Робот стоит в клетке, следующей за закрашенной. Если номер пролёта
нечётный, то он закрашивает клетку:
//Робот идёт по нечётному пролёту:
if (n mod 2 = 1) then
183
begin
Paint;
end;
Затем он в любом пролёте делает шаг вправо:
Right;
Если очередная клетка – закрашенная, то изменяется номер пролёта, в противном случае Робот идёт по тому же пролёту, то есть в нечётном пролёте он
закрашивает клетки, а в чётном не закрашивает:
end;
Когда Робот дойдёт до конечной клетки поля, то её он также должен закрасить, если она заканчивает нечётный пролёт:
//последняя клетка нечётного пролёта:
if (n mod 2 = 1) then
Paint;
Задание count17
Простое логическое упражнение для Робота: он должен остановиться в клетке,
которая нарушает общую закономерность (Рис. 1).
Прежде всего, нужно найти закономерность в расстановке стен:
1. Под всеми нечётными клетками должна быть стена.
2. Под всеми чётными клетками стены быть не должно.
184
Рис. 1. Закономерно
Робот переступает одиночными шагами вправо и считает клетки:
//счётчик клеток:
var n := 0;
while (FreeFromRight) do
begin
n += 1;
Если под нечётной клеткой отсутствует стена, Робот останавливается:
185
if ((n mod 2 = 1) and FreeFromDown) then
break
Точно так же он поступает, если под чётной клеткой оказывается стена:
else if ((n mod 2 = 0) and WallFromDown) then
break;
Right;
end;
186
Набор заданий cc
Следующий набор состоит из 19 заданий на вложенные циклы (Рис. 1).
Рис. 1. Укладываем циклы
Задание cc1
Робот должен закрасить клетки, расположенные ступеньками (Рис. 1).
Размеры поля и ступенек постоянные, поэтому записать вложенные циклы
совсем нетрудно - достаточно посчитать число ступенек и число клеток в каждой из них:
//Робот шагает по ступенькам:
for var j := 1 to 6 do
begin
//Робот закрашивает ступеньку:
for var i := 1 to 5 do
begin
Paint;
Right;
end;
//Робот спускается на следующую ступеньку:
187
Down;
end;
Рис. 1. По ступеням
Задание cc2
Это задание сложнее – длина каждой следующей ступеньки увеличивается на
единицу (Рис. 1).
188
Рис. 1. Ступеньки удлиняются
Легко заметить, что длина ступеньки в точности равна её номеру, поэтому
нужно исправить только диапазон изменения переменной цикла i в предыдущем коде:
//Робот шагает по ступенькам:
for var j := 1 to 6 do
begin
//Робот закрашивает ступеньку:
for var i := 1 to j do
begin
Paint;
Right;
end;
189
//Робот спускается на следующую ступеньку:
Down;
end;
Задание cc3
И в этом задании ступеньки имеют переменную длину, но на этот раз они укорачиваются (Рис. 1).
Рис. 1. Короче!
190
Опять нужно исправить только заголовок второго цикла, чтобы Робот успешно справился с заданием:
//Робот шагает по ступенькам:
for var j := 1 to 6 do
begin
//Робот закрашивает ступеньку:
for var i := 7-j downto 1 do
begin
Paint;
Right;
end;
//Робот спускается на следующую ступеньку:
Down;
end;
Задание cc4
Задание cc4 предлагает Роботу пройти по извилистому пути и закрасить
очень много клеток (Рис. 1).
Первые клетки каждой горизонтали Робот закрашивает во внешнем цикле for
с переменной row:
for var row := 1 to 9 do
begin
//Робот закрашивает первую
//клетку горизонтали:
Paint;
191
Рис. 1. Объёмы растут
Остальные клетки горизонтали Робот должен пройти дважды, поэтому он
может сначала бодро и весело дошагать до правой стены, а при возвращении к
левой стене закрашивать клетки (или наоборот):
//Робот идёт до правой стены:
for var col := 1 to 10 do
Right;
//Робот возвращается к левой стене
//и закрашивает клетки:
for var col := 1 to 10 do
begin
Paint;
Left;
192
end;
//Робот переходит на горизонталь ниже:
Down;
end;
Задание cc5
И вот наш Робот добрался почти до настоящего лабиринта (Рис. 1)!
Рис. 1. Даёшь лабиринт!
193
В отличие от предыдущего задания, Робот возвращается по другой горизонтали:
for var row := 1 to 4 do
begin
//Робот идёт до правой стены:
for var col := 1 to 13 do
Right;
//Робот переходит на горизонталь ниже:
Down;
//Робот возвращается к левой стене:
for var col := 1 to 13 do
Left;
//Робот переходит на горизонталь ниже:
Down;
end;
Не ошибитесь: всего Робот должен выполнить 4 челночных прохода!
Задание cc6
Робот получает под покраску 5 комнат (Рис. 1).
Задание очень простое, но требует внимания. До первой двери Роботу нужно
сделать 3 шага вправо, а до остальных 4:
//Робот пройдёт по 5 комнатам:
for var n := 1 to 5 do
begin
//Робот идёт вправо до входа:
for var col := 1 to 3 do
Right;
//Робот поднимается до верхне стены:
for var row := 1 to 9 do
Up;
194
//и закрашивает клетку:
Paint;
//Робот возвращается вниз:
for var row := 1 to 9 do
Down;
Рис. 1. Пятикомнатное задание
Но этот добавочный шаг не следует выполнять у правой границы поля:
//и делает 1 шаг вправо:
if (n < 5) then
Right;
end;
195
Задание cc7
Вариант ступенек с возвратами (Рис. 1).
Рис. 1. Вниз по лестнице
Задача для устного счёта:
for var row := 1 to 9 do
begin
//Робот закрашивает клетки текущей горизонтали:
for var col := 1 to row do
begin
Paint;
Right;
196
end;
//Робот возвращается к левой стене:
for var col := 1 to row do
Left;
//Робот переходит на горизонталь ниже:
Down;
end;
Задание cc8
Те же ступеньки, но «вверх ногами» (Рис. 1).
Рис. 1. Держитесь крепче и цепче!
197
Самый простой алгоритм такой: Робот закрашивает клетки текущей горизонтали, а затем возвращается в её начало:
for var row := 1 to 9 do
begin
//Робот клетки текущей горизонтали:
for var col := 1 to 10-row do
begin
Paint;
Right;
end;
//Робот возвращается к левой стене
//и закрашивает клетки:
for var col := 10-row downto 1 do
Left;
Здесь он спускается на следующую горизонталь и повторяет в ней свои действия:
//Робот переходит на горизонталь ниже:
Down;
end;
Чтобы не гонять Робота порожняком, можно после закраски нечётной горизонтали опускать его на чётную горизонталь, чтобы он закрасил её, идя в обратном направлении:
for var row := 1 to 5 do
begin
//Робот клетки текущей горизонтали:
for var col := 1 to 11 - row * 2 do
begin
Paint;
Right;
end;
//Робот переходит на горизонталь ниже:
Down; Left;
//Робот возвращается к левой стене
//и закрашивает клетки:
198
for var col := 10 - row * 2 downto 1 do
begin
Left;
Paint;
end;
В самой нижней горизонтали это действие выполнять не нужно:
//Робот переходит на горизонталь ниже:
if (row < 5) then
Down;
end;
Задание cc9
Робота ждёт своеобразный слалом с закрашиваем клеток (Рис. 1).
Алгоритм легко составить, просто мысленно проведя Робота с первого уровня
на второй. Затем все эти действия повторяются. Нужно только учесть, что
длина коридора увеличивается на 1 клетку в каждой следующей горизонтали:
for var row := 1 to 9 do
begin
//Робот закрашивает клетку в
//текущей горизонтали:
Paint;
//идёт влево:
for var col := 1 to row do
Left;
//переходит на горизонталь ниже:
Down;
//идёт вправо до стены:
for var col := 1 to row do
Right;
end;
199
Рис. 1. Малярный слалом
Задание cc10
Вариант Задания сс7, только теперь в каждой горизонтали вдвое больше точек
(Рис. 1).
Исходный код нужно исправить всего в трёх местах:
for var row := 1 to 7 do
begin
//Робот закрашивает клетки текущей горизонтали:
for var col := 1 to row*2 do
200
begin
Paint;
Right;
end;
//Робот возвращается к левой стене:
for var col := 1 to row*2 do
Left;
//Робот переходит на горизонталь ниже:
Down;
end;
Рис. 1. Крутые ступени
201
Задание cc11
Практически такое же задание, что и предыдущее, но с нечётным числом клеток в горизонталях (Рис. 1).
Рис. 1. Невелика разница
В данном случае горизонтали удобнее считать, начиная с нуля, тогда число
клеток в горизонталях можно вычислить по простой формуле:
row*2 + 1
202
Весь остальной код остался без изменений:
for var row := 0 to 6 do
begin
//Робот закрашивает клетки текущей горизонтали:
for var col := 1 to row*2 + 1 do
begin
Paint;
Right;
end;
//Робот возвращается к левой стене:
for var col := 1 to row*2 + 1 do
Left;
//Робот переходит на горизонталь ниже:
Down;
end;
Задание cc12
Это задание продолжает развивать идеи нескольких предыдущих (Рис. 1).
В этом задании опять нужно найти формулу для вычисления длины ряда клеток в зависимости от его номера. Нетрудно заметить, что длина ряда выражается степенью двойки, причём показатель степени равен номеру ряда, если
считать с нуля:
2row
В паскале степени вычисляются с помощью функции Power, которая возвращает результат вещественного типа, и нам необходимо приложить дополнительные усилия, чтобы привести его к целому типу. Других проблем при решении этого задания вы не встретите.
203
Рис. 1. Огромные ступени!
for var row := 0 to 5 do
begin
//число закрашиваемых клеток в горизонтали:
var n := System.Convert.ToInt32(Power(2, row));
//Робот закрашивает клетки текущей горизонтали:
for var col := 1 to n do
begin
Paint;
Right;
end;
//Робот возвращается к левой стене:
for var col := 1 to n do
Left;
204
//Робот переходит на горизонталь ниже:
Down;
end;
Задание cc13
Слалом с изменяемой длиной горизонтальных отрезков (Рис.1).
Рис. 1. Опять петляем
205
Первая горизонталь явно выбивается из общей закономерности, поэтому Робот сначала переходит в начало второй горизонтали, чтобы все остальные
действия выполнялись циклически:
//Робот переходит в начало второй горизонтали:
for var col := 1 to 13 do
Right;
Down;
//Робот возвращается к левой стене:
for var col := 1 to 13 do
Left;
Теперь Робот должен 4 раза сделать вправо row * 2 шагов и закрасить клетку:
for var row := 1 to 4 do
begin
//Робот идёт вправо:
for var col := 1 to row * 2 do
Right;
//Робот закрашивает клетку:
Paint;
Потом вернуться в начало текущей горизонтали и сделать 2 шага вниз:
//Робот возвращается к левой стене:
if (row < 4) then
for var col := 1 to row * 2 do
Left;
//Робот опускается ниже:
Down;
if (row < 4) then
Down;
end;
Последние 2 горизонтали немного отличаются от прочих, поэтому действия
Робота необходимо скорректировать.
206
Задание cc14
А вот теперь наш Робот попал в самый настоящий переплёт и лабиринт (Рис.
1).
Рис. 1. Переплёт в лабиринте
В этом задании опять выпадает первая горизонталь, поэтому Робот занимает
исходную позицию в конце второй горизонтали:
//Робот переходит в конец второй горизонтали:
for var col := 1 to 13 do
Right;
Down;
207
Теперь Робот должен 4 раза выполнить сходные действия: идти влево, спуститься вниз, пойти вправо и снова сделать шаг вниз:
for var row := 0 to 3 do
begin
//Робот идёт влево:
for var col := 1 to 13 - row * 2 - 1 do
Left;
//Робот опускается ниже:
Down;
//Робот идёт вправо:
if (row < 3) then
begin
for var col := 1 to 13 - row * 2 - 1 - 1 do
Right;
//Робот опускается ниже:
Down;
end;
end;
Как и в предыдущем задании, последняя итерация выполняется не полностью,
что нужно учесть в алгоритме.
Когда поле имеет постоянные размеры, мы можем посчитать длину каждого
коридора на картинке, поэтому вполне естественно для перемещения Робота
использовать циклы с параметром. Однако более универсальный цикл while
правильно работает при любой длине коридоров, и алгоритм получается более
простым и понятным:
//число коридоров:
var n := 8;
//Робот идёт по всем коридорам:
while (n > 0) do
begin
//Робот идёт вправо до стены:
while (FreeFromRight) do
Right;
//Робот опускается вниз:
208
Down;
n -= 1;
//Робот идёт влево до стены:
while (FreeFromLeft) do
Left;
//Робот опускается вниз:
Down;
n -= 1;
end;
Задание cc15
Робот получил ответственное задание: закрасить равнобедренный треугольник (Рис. 1).
Рис. 1. Треугольные дела
209
Самый экономичный путь по части ходьбы: сновать вправо – влево, учитывая
прирост длины закрашиваемых клеток по мере приближения к основанию
треугольника:
for var row := 0 to 3 do
begin
//Робот идёт вправо и закрашивает клетки:
for var col := 1 to row * 4 + 1 do
begin
Paint;
Right;
end;
//Робот опускается ниже:
Down;
Последняя пара горизонталей отличается от прочих, поэтому её нужно проходить другим способом:
//Робот идёт влево и закрашивает клетки:
if (row < 3) then
begin
for var col := 1 to row * 4 + 2 do
begin
Paint;
Left;
end;
Paint;
Down; Left;
end
//нижняя горизонталь:
else
for var col := 1 to 7 do
Left;
end;
Можно заставить Робота выполнять другой алгоритм.
Действительно, он может закрашивать не горизонтальные ряды, а стороны
вложенных треугольников. Этот способ не менее забавный, чем первый:
210
for var n := 0 to 3 do
begin
//длина боковых сторон треугольника:
var size := 6 - n * 2;
//Робот закрашивает клетку на вершине треугольника:
Paint;
//Робот закрашивает левую боковую сторону:
for var sz := 1 to size do
begin
Down; Left;
Paint;
end;
//Робот закрашивает основание:
for var sz := 1 to size + 6 - n * 2 do
begin
Right;
Paint;
end;
//Робот закрашивает правую боковую сторону:
for var sz := 1 to size do
begin
Up; Left;
Paint;
end;
//Робот переходит на следующий треугольник:
Down;
end;
//Робот идёт на базу:
for var row := 1 to 3 do
Down;
211
Задание cc16
Робот должен закрасить зубатую пилу (Рис. 1).
Рис. 1. Попилили?
Мы без труда сосчитаем зубья пилы – их всего четыре:
//Робот закрашивает 4 треугольника:
for var n := 1 to 4 do
begin
212
Треугольные зубья можно закрашивать по-разному, но мы должны учитывать,
что в конце выполнения задания Робот должен оказаться в начале следующего, пятого треугольника. Поэтому Робот может закрашивать вертикальные
ряды, поднимаясь вверх, а затем спускаться до основания:
//в каждом 5 колонок:
for var col := 1 to 5 do
begin
//Робот закрашивает колонку,
//шагая вверх:
for var m := 1 to col do
begin
Paint;
Up;
end;
//Робот опускается до основания треугольника:
for var m := 1 to col do
Down;
//Робот переходит к следующей колонке:
Right;
end;
end;
Задание непростое, поэтому его можно решить далеко не единственным
способом!
213
Задание cc17
Более сложная пила, чем в предыдущем задании (Рис. 1).
Рис. 1. Суперпила
Число зубцов увеличилось до 6, а их размеры убывают справа налево, поэтому
во внешнем цикле удобнее использовать цикл с downto:
//Робот закрашивает 6 треугольников:
for var n := 6 downto 1 do
begin
//в каждом n колонок:
for var col := 1 to n do
214
begin
//Робот закрашивает колонку,
//шагая вверх:
for var m := 1 to col do
begin
Paint;
Up;
end;
//Робот опускается до основания треугольника:
for var m := 1 to col do
Down;
//Робот переходит к следующей колонке:
Right;
end;
Так как базовая клетка находится в непосредственной близости к последнему
треугольнику, то дополнительный шаг вправо Роботу делать не нужно:
//Робот переходит к следующему треугольнику:
if (n > 1) then
Right;
end;
Задание cc18
Коридорное воспитание Робота продолжается (Рис. 1)!
В условии задания явно указано, что мы должны использовать цикл while. Это
избавит нас от необходимости измерять длину каждого коридора.
Алгоритм получился простой и понятный:
//всего Робот должен пройти 7 коридоров:
for var n := 1 to 7 do
begin
215
//Робот идёт до правой стены и
//закрашивает клетку:
while (FreeFromRight) do
Right;
Paint;
//Робот возвращается в левой стене:
while (FreeFromLeft) do
Left;
Рис. 1. Коридоры, коридоры…
Единственная «изюмина» задания, которую мы должны учесть, - закончив беготню по нижнему коридору, Робот не делает шаг вниз – туда ему пути нет:
216
//Робот шагает вниз:
if (n < 7) then
Down;
end;
Задание cc19
Наконец-то! Изменчивое задание (Рис. 1).
Рис. 1. Что-то изменилось?
217
Дойти до правой стенки, закрасить там клетку и вернуться обратно – это Робот сделает без труда. Вопрос в том, когда он должен остановиться.
Ответ легко найти, если внимательно посмотреть на Рис. 1⬆: Робот переходит
вниз, пока под ним не появляется стена:
while (true) do
begin
//Робот идёт до правой стены и
//закрашивает клетку:
while (FreeFromRight) do
Right;
Paint;
//Робот возвращается в левой стене:
while (FreeFromLeft) do
Left;
//Робот шагает вниз,
//пока под ним нет стены:
if (WallFromDown) then
break;
Down;
end;
218
Набор заданий mix
Программистское тутти-фрутти на 10 заданий (Рис. 1).
Рис. 1. Всякая всячина
Задание mix1
Наши любимые задания на изменяемые поля (Рис. 1)!
Размеры закрашиваемого прямоугольника заранее неизвестны, но стартовая
клетка всегда находится в его левом верхнем углу, а финишная – в правом
нижнем (Рис. 2).
Робот быстрее закрасит прямоугольник, если будет закрашивать клетки, шагая и влево, и вправо. Но если вправо он может идти до стены, то влево ему
нужно пройти столько же шагав, сколько и вправо, поэтому Робот должен
считать шаги.
219
Рис. 1. Зыбкий прямоугольник
Рис. 2. Разноразмерные прямоугольники
220
Робот закрашивает прямоугольник парами горизонтальных строк. Так как он
не знает высоты прямоугольника, то работает без устали, то есть бесконечно.
Однако для нас важно, чтобы он остановился, когда окажется в закрашенной
базовой клетке. А её легко определить, когда Робот закрасит очередную горизонталь, идя вправо. Если он окажется в правом нижнем углу, то задание прерывается:
//Робот закрашивает прямоугольник:
while (true) do
begin
var width := 0;
//Робот идёт вправо:
while (FreeFromRight) do
begin
Paint; Right;
width += 1;
end;
Paint;
//Робот лошёл до базы:
if (WallFromDown and WallFromRight) then
break;
//Робот делает шаг вниз:
if (FreeFromDown) then
Down;
//и закрашивает клетки в обратном направлении:
for var w := 1 to width do
begin
Paint; Left;
end;
Paint;
//Робот делает шаг вниз:
if (FreeFromDown) then
Down;
end;
221
Задание mix2
Усложнённый вариант первого задания. Теперь Робот должен закрашивать
клетки в шахматном порядке (Рис. 1).
Рис. 1. Шах - не мат
Опять быстрее закрашивать пары горизонталей, шагая вправо, а затем влево.
Шаги следует считать в обоих направлениях, чтобы правильно закрашивать
клетки:
//Робот закрашивает клетки
//прямоугольника в шахматном порядке:
222
while (true) do
begin
//число шагов влево и вправо:
var step := 1;
//Робот идёт вправо:
Paint;
while (FreeFromRight) do
begin
Right;
step += 1;
if (step mod 2 = 1) then
Paint;
end;
Если Робот оказался в первой нижней клетке, идя вправо, то задание он уже
выполнил:
//Робот лошёл до базы:
if (WallFromDown and WallFromRight) then
break;
//Робот делает шаг вниз:
if (FreeFromDown) then
Down;
var back := step + 1;
//и закрашивает клетки в обратном направлении:
while (back < step * 2) do
begin
if (back mod 2 = 1) then
Paint;
back += 1;
Left;
end;
Если Робот закрасил последнюю горизонталь, идя влево, то ему ещё предстоит вернуться на базу:
//Робот делает шаг вниз:
223
if (FreeFromDown) then
Down
//Робот в нижней горизонтали
//и должен вернуться на базу:
else
begin
while (FreeFromRight) do
Right;
break;
end;
end;
Задание mix3
Роботу опять предстоит закрасить квадрат, но прежде он должен измерить его
(Рис. 1).
Рис. 1. Измеряем квадраты
224
Длину стороны квадрата можно найти так.
Робот идёт по диагонали вниз-влево и считает шаги:
//размеры квадрата:
var size := 1;
//Робот измеряет квадрат:
while (CellIsFree) do
begin
size += 1;
Down; Left;
end;
В переменной size теперь хранится длина сторон квадрата, и Робот может закрасить столько же клеток, идя вправо.
Чтобы не гонять Робота лишний раз, мы начнём работу с левого нижнего угла,
в котором он оказался после измерения квадрата:
//счётчик шагов:
var n := 0;
while (true) do
begin
//Робот идёт вправо:
for var col := 1 to size do
begin
Paint;
if (col < size) then
Right;
end;
Чтобы Робот не сделал лишний шаг вправо, мы дополнительно контролируем
его шаги!
Увеличиваем счётчик закрашенных горизонталей:
//Робот на базе:
n += 1;
225
Если Робот находится в верхней горизонтали, идя вправо, то он уже на базе:
if (n = size) then
break;
Иначе он поднимается в следующую горизонталь и закрашивает её, идя влево:
//Робот делает шаг вверх:
Up;
//Робот идёт влево:
for var col := 1 to size do
begin
Paint;
if (col < size) then
Left;
end;
Если Робот находится в верхней горизонтали, которую он уже закрасил до
начала, то он должен вернуться на базу, шагая вправо:
n += 1;
if (n = size) then
begin
//Робот идёт на базу:
for var col := 1 to size-1 do
Right;
break;
end;
Если Робот не в верхней горизонтали, то он опять поднимается вверх:
//Робот делает шаг вверх:
Up;
end;
226
Задание mix4
Намечаются поисково-разыскные работы (Рис. 1)!
Рис. 1. Ищем!
Закрашенная клетка может находиться в любом месте поля, поэтому поиски
следует вести систематически!
Для этого Робот сначала переходит в верхнюю левую клетку:
//Робот переходит в верхнюю левую клетку:
while(FreeFromUp) do
227
Up;
while(FreeFromLeft) do
Left;
А затем спускается зигзагами вниз.
Сначала он проверяет, не стоит ли уже на закрашенной клетке. Если это так,
то задание выполнено. Иначе он идёт вправо до стены и после каждого шага
проверяет это условие:
//Робот "сканирует" поле слева направо
//и сверху вниз:
while(true) do
begin
//Робот идёт вправо:
while (FreeFromRight) do
begin
//нашёл закрашенную клетку:
if (CellIsPainted) then
exit;
Right;
end;
//если внизу нет стены,
//то Робот делает шаг вниз:
if (FreeFromDown) then
Down;
//те же самые действия, но влево:
while(FreeFromLeft) do
begin
if (CellIsPainted) then
exit;
Left;
end;
if (FreeFromDown) then
Down;
end;
Понятно, что, пропахав всё поле вдоль и поперёк, Робот непременно найдёт
закрашенную клетку!
228
Задание mix5
Поиск закрашенных клеток продолжается (Рис. 1)!
Рис. 1. Танцуем от закрашенной клетки
Первая часть задачи – поиск закрашенной клетки – Роботу уже знакома по
предыдущему заданию:
//Робот переходит в верхнюю левую клетку:
while(FreeFromUp) do
Up;
229
while(FreeFromLeft) do
Left;
Но теперь нужно учесть, что на этом труды Робота не заканчиваются, поэтому
мы не можем использовать оператор exit, прерывающий выполнение программы.
Мы объявляем флаг found, который будет сигнализировать о «поимке» закрашенной клетки. Он необходим потому, что оператор break прервёт только
вложенный цикл while, и мы затем должны ещё выйти из внешнего цикла. В
таких случаях допускается применение оператора безусловного перехода goto,
но в данном случае без него легко обойтись:
var found := false;
//Робот "сканирует" поле слева направо
//и сверху вниз:
while(true) do
begin
//Робот идёт вправо:
while (FreeFromRight) do
begin
//нашёл закрашенную клетку:
if (CellIsPainted) then
begin
found := true;
break;
end;
Right;
end;
if (found) then
break;
//если внизу нет стены,
//то Робот делает шаг вниз:
if (FreeFromDown) then
Down;
//те же самые действия, но влево:
while(FreeFromLeft) do
begin
if (CellIsPainted) then
begin
230
found := true;
break;
end;
Left;
end;
if (found) then
break;
if (FreeFromDown) then
Down;
end;
Первая часть задачи выполнена –
//Робот стоит на закрашенной клетке
Чтобы закрасить вертикальный ряд клеток, Робот поднимается вверх, а затем
идёт вниз до стены и закрашивает клетки. Всё было так просто, если бы Роботу не нужно было бы после этого возвращаться на базу. Так как теперь все
клетки в его вертикали закрашены, то он не сможет распознать базовую клетку, поэтому нужен дополнительный счётчик, чтобы запомнить в нём нужную
горизонталь:
//счётчик горизонталей:
var row := 0;
//Робот идёт вверх до стены:
while(FreeFromUp) do
begin
Up;
row -= 1;
end;
//Робот идёт вниз и закрашивает клетки:
while(FreeFromDown) do
begin
Paint;
Down;
row += 1;
end;
Paint;
231
Все требуемые клетки закрашены, а в переменной row хранится число шагов
вверх, которые должен сделать Робот:
//Робот возвращается на базу:
for var r := 1 to row do
Up;
Задание mix6
Симметричные покрасочные работы. Робот закрашивает клетки справа, у которых имеется закрашенная пара слева (Рис. 1).
Рис. 1. Симметрично и симпатично
232
Алгоритм достаточно простой.
Если Робот стоит на закрашенной клетке у левой стены, то он идёт вправо до
упора, закрашивает там клетку и возвращается назад.
Пока снизу нет стены, Робот спускается на следующую горизонталь:
//Робот идёт вниз до стены:
while (FreeFromDown) do
begin
//если Робот стоит на закрашенной клетке:
if (CellIsPainted) then
begin
//Робот идёт вправо до стены:
while (FreeFromRight) do
Right;
//и закрашивает клетку:
Paint;
//Робот возвращается к левой стене:
while (FreeFromLeft) do
Left;
end;
//Робот делает шаг вниз:
Down;
end;
Задание mix7
Приключения продолжаются! Робот должен закрасить клетки во всех горизонтальных рядах, в которых имеются 2 закрашенные клетки (Рис. 1).
Задание несложное.
233
Если Робот стоит слева на закрашенной клетке, то он идёт до правой стены,
чтобы узнать, есть ли в этой горизонтали вторая закрашенная клетка.
Рис. 1. Попарно
Если такой клетки он не находит, то просто возвращается назад. В противном
случае он ещё и закрашивает клетки:
//Робот идёт вниз до стены:
while (FreeFromDown) do
begin
//если Робот стоит на закрашенной клетке:
if (CellIsPainted) then
begin
//Робот идёт вправо до стены:
234
while (FreeFromRight) do
Right;
Чтобы Робот мог правильно выполнить свои действия при возвращении к левой стене, мы запоминаем в переменной painted, нашёл ли он справа закрашенную клетку:
//если там закрашенная клетка:
var painted := CellIsPainted;
//Робот возвращается к левой стене
//и по пути закрашивает клетки:
while (FreeFromLeft) do
begin
Left;
if (painted) then
Paint;
end;
end;
//Робот делает шаг вниз:
Down;
end;
Задание mix8
Приключения Робота продолжаются, а задания усугубляются! Теперь Робот
должен ещё и считать закрашенные клетки по ходу своего движения (Рис. 1).
Алгоритм практически тот же самый, что и в предыдущем задании. Нужно
только подправить условие закрашивание клеток горизонтального ряда.
А оно простое: в нём должны быть закрашены ровно 3 клетки, из которых две
– крайние слева и справа.
235
Рис. 1. Сочтёмся!
//Робот идёт вниз до стены:
while (FreeFromDown) do
begin
//если Робот стоит на закрашенной клетке:
if (CellIsPainted) then
begin
//число закрашенных клеток:
var nPainted := 1;
//Робот идёт вправо до стены:
while (FreeFromRight) do
begin
Right;
if (CellIsPainted) then
nPainted += 1;
end;
236
//общее число закрашенных клеток
//должно равняться 3, а последняя клетка
//горизонтали также должна быть закрашена:
var painted := (nPainted = 3) and CellIsPainted;
//Робот возвращается к левой стене
//и по пути закрашивает клетки:
while (FreeFromLeft) do
begin
Left;
if (painted) then
Paint;
end;
end;
//Робот делает шаг вниз:
Down;
end;
Задание mix9
Задание напоминает mix3, но теперь Робот должен закрасить не квадрат, а
прямоугольник (Рис. 1).
Многосерийное задание, алгоритм которого можно построить, как из кирпичиков, из алгоритмов наших предыдущих заданий.
Чтобы найти закрашенную клетку, Роботу всё равно нужно дойти до верхнего
левого угла поля. При этом он может определить и координаты начальной/базовой клетки, которые потом понадобятся ему при вычислении размеров прямоугольника:
//координаты базы (0..):
var colBase := 0;
var rowBase := 0;
237
//Робот идёт влево:
while (FreeFromLeft) do
begin
colBase += 1;
Left;
end;
//writeln(colBase);
//Робот идёт вверх:
while (FreeFromUp) do
begin
rowBase += 1;
Up;
end;
//writeln(rowBase);
Рис. 1. Прямоугольник сложнее квадрата
238
Сейчас Робот находится в левом верхнем углу и знает координаты базовой
клетки.
Теперь он ищет на поле закрашенную клетку и заодно определяет её координаты:
//координаты закрашенной клетки (0..):
var colPainted := 0;
var rowPainted := 0;
var found := false;
//Робот "сканирует" поле слева направо
//и сверху вниз:
while(true) do
begin
//Робот идёт вправо:
while (FreeFromRight) do
begin
//нашёл закрашенную клетку:
if (CellIsPainted) then
begin
found := true;
break;
end;
Right;
colPainted += 1;
end;
if (found) then
break;
//если внизу нет стены,
//то Робот делает шаг вниз:
if (FreeFromDown) then
begin
Down;
rowPainted += 1;
end;
//те же самые действия, но влево:
while(FreeFromLeft) do
begin
if (CellIsPainted) then
begin
found := true;
239
break;
end;
Left;
colPainted -= 1;
end;
if (found) then
break;
if (FreeFromDown) then
begin
Down;
rowPainted += 1;
end;
end;
//Робот стоит на закрашенной клетке
//writeln(colPainted);
//writeln(rowPainted);
Робот стоит на закрашенной клетке и знает её координаты.
Размеры сторон прямоугольника легко вычислить как разность координат
базовой и закрашенной клеток:
//размеры прямоугольника:
var width := colBase - colPainted + 1;
var height := rowPainted - rowBase + 1;
Закрашивать квадрат Робот уже умеет. Прямоугольник закрашивается почти
так же, но с учётом того, что размеры сторон могут различаться:
//счётчик шагов:
var n := 0;
while (true) do
begin
//Робот идёт вправо:
for var col := 1 to width do
begin
Paint;
if (col < width) then
240
Right;
end;
//Робот на базе:
n += 1;
if (n = height) then
break;
//Робот делает шаг вверх:
Up;
//Робот идёт влево:
for var col := 1 to width do
begin
Paint;
if (col < width) then
Left;
end;
n += 1;
if (n = height) then
begin
//Робот идёт на базу:
for var col := 1 to width-1 do
Right;
break;
end;
//Робот делает шаг вверх:
Up;
end;
Задание mix10
Задание, очень похожее на предыдущее, но с усложнениями (Рис. 1).
Базовая и закрашенная клетки находятся в противоположных углах прямоугольника, но разными способами (Рис. 2).
241
Рис. 1. Будут осложнения!
Рис. 2. Разные противоположности
242
Размеры прямоугольника Робот может найти так же, как в предыдущем задании, то нужно взять абсолютную величину разности координат:
//координаты базы (0..):
var colBase := 0;
var rowBase := 0;
//Робот идёт влево:
while (FreeFromLeft) do
begin
colBase += 1;
Left;
end;
//Робот идёт вверх:
while (FreeFromUp) do
begin
rowBase += 1;
Up;
end;
//координаты закрашенной клетки (0..):
var colPainted := 0;
var rowPainted := 0;
var found := false;
//Робот "сканирует" поле слева направо
//и сверху вниз:
while(true) do
begin
//Робот идёт вправо:
while (FreeFromRight) do
begin
//нашёл закрашенную клетку:
if (CellIsPainted) then
begin
found := true;
break;
end;
Right;
colPainted += 1;
end;
if (found) then
break;
243
//если внизу нет стены,
//то Робот делает шаг вниз:
if (FreeFromDown) then
begin
Down;
rowPainted += 1;
end;
//те же самые действия, но влево:
while(FreeFromLeft) do
begin
if (CellIsPainted) then
begin
found := true;
break;
end;
Left;
colPainted -= 1;
end;
if (found) then
break;
if (FreeFromDown) then
begin
Down;
rowPainted += 1;
end;
end;
//Робот стоит на закрашенной клетке
//размеры прямоугольника:
var width := Abs(colBase – colPainted) + 1;
var height := Abs(rowPainted – rowBase) + 1;
Так как мы умеем закрашивать прямоугольник, начиная с левого нижнего угла, то перегоняем Робота туда:
//Робот идёт в левый верхний угол поля:
while (FreeFromLeft) do
Left;
while (FreeFromUp) do
Up;
244
//Робот идёт в нижний левый угол прямоугольника:
for var col := 1 to Min(colBase, colPainted) do
Right;
for var row := 1 to Max(rowBase, rowPainted) do
Down;
С этой частью работы Робот справляется без проблем:
//Робот закрашивает прямоугольник
//счётчик шагов:
var n := 0;
while (true) do
begin
//Робот идёт вправо:
for var col := 1 to width do
begin
Paint;
if (col < width) then
Right;
end;
n += 1;
if (n = height) then
break;
//Робот делает шаг вверх:
Up;
//Робот идёт влево:
for var col := 1 to width do
begin
Paint;
if (col < width) then
Left;
end;
n += 1;
if (n = height) then
break;
//Робот делает шаг вверх:
Up;
end;
245
И наконец, Робот должен вернуться на базу. Её координаты мы знаем, поэтому
действуем так.
Перегоняем Робота в верхний левый угол:
//Робот идёт в левый верхний угол поля:
while (FreeFromLeft) do
Left;
while (FreeFromUp) do
Up;
А затем отправляем его точно по адресу:
//Робот идёт на базу:
for var col := 1 to colBase do
Right;
for var row := 1 to rowBase do
Down;
Алгоритм получился не оптимальный, но зато надёжный и простой!
246
Набор заданий p
В программировании принято выделять повторяющиеся законченные части
кода в отдельные подпрограммы. В данном наборе заданий это процедуры
без параметров (Рис. 1).
Рис. 1. Пора на процедуры
Процедуры могут использоваться в разных программах. Это очень удобно, поскольку они уже написаны и отлажены. Таким образом, процедуры можно рассматривать как составные части, или детали какого-то сложного механизма.
Все без исключения серьёзные программы состоят из большого числа процедур.
Задание p1
В первом задании Роботу поручено важное задание: закрасить на поле 3 одинаковых креста (Рис. 1).
Понятно, что одинаковые фигуры и закрашиваются одинаково, то есть Робот
должен выполнить одну и ту же последовательность действий. Если он сумеет
закрасить один крест, то, действуя так же, сможет закрасить их сколько угодно.
247
Обращаем внимание на то, что базовая клетка находится в центре креста, поэтому в ней он и должен заканчивать выполнение процедуры.
Рис. 1. Или грудь в крестах…
Последовательность закрашивания клеток может быть разной. Например, Робот может закрасить центральную клетку, затем подняться вверх и закрасить
внешние клетки, обходя их по часовой стрелке или в обратном направлении:
procedure Cross();
begin
//закрашиваем центральную клетку:
Paint;
//закрашиваем остальные клетки:
248
Left; Paint;
Up; Right; Paint;
Down; Right; Paint;
Down; Left; Paint;
//возвращаемся в центральную клетку:
Up;
end;
Не забудьте вернуть Робота в центральную клетку!
В главной части программы мы сначала вызываем процедуру Cross, а потом
последовательно перегоняем Робота в центр остальных крестов и опять вызываем эту процедуру:
begin
Task('p1');
//закрашиваем первый крест:
Cross;
//идём ко второму кресту:
Up;
Right; Right; Right;Right; Right;
//закрашиваем второй крест:
Cross;
//идём к третьему кресту:
Up;Up;Up;
Left; Left; Left;
//закрашиваем третий крест:
Cross;
end.
Задание p2
Задание, подобное предыдущему, но менее мрачное – Роботу нужно закрасить
небольшие квадраты (Рис. 1).
249
Рис. 1. Квадратно-гнездовой закрас
Опять обращаем внимание, что Робот заканчивает выполнение программы в
верхней левой клетке закрашиваемого квадрата, поэтому в процедуре Square2
возвращаем его на место. Закрашивать квадрат можно в любую сторону:
procedure Square2();
begin
Paint;
Right; Paint;
Down; Paint;
Left; Paint;
//возвращаемся в исходную клетку:
250
Up;
end;
В этом задании квадраты располагаются регулярно, поэтому переходить от
одного квадрата к другому можно в цикле for:
begin
Task('p2');
//закрашиваем 6 квадратов:
for var n := 1 to 6 do
begin
Square2;
if (n < 6) then
begin
Right; Right;Right;
end;
end;
end.
Задание p3
Те же самые квадраты, но расположенные по диагонали (Рис. 1).
Процедура Square2 осталась без изменений (бережём силы и время!), а в
главной части программы нужно исправить только команды, отвечающие за
переход к следующему квадрату:
begin
Task('p3');
//закрашиваем 6 квадратов:
for var n := 1 to 6 do
begin
Square2;
if (n < 6) then
begin
251
Left; Left;
Up; Up;
end;
end;
end.
Рис. 1. Наискосок
Задание p4
А здесь маленькие квадраты сбились в плотную кучку, образовав БОЛЬШОЙ
квадрат (Рис. 1).
252
Рис. 1. Скучковались
В очередной раз пользуемся плодами своего труда и просто копируем процедуру Square2 из нашего предыдущего проекта:
Новая процедура Square4 вызывает процедуру Square2 для рисования «элементарных» квадратов и выполняет необходимые переходы между ними:
procedure Square4();
begin
Square2();
Right; Right;
Square2();
253
Down; Down;
Square2();
Left; Left;
Square2();
Up; Up;
end;
На долю основной программы достался только вызов новой процедуры:
begin
Task('p4');
Square4();
end.
Вот так, за счёт процедур и сокращают основную программу!
Задание p5
Размеры закрашиваемого квадрата ещё увеличились (Рис. 1)!
Теперь процедура Square4 уже сама оказалась в роли более «мелкой» процеду-
ры Square2.
Так как новую процедуру нам писать не нужно, то все вызовы процедуры
Square4 и переходы между квадратами 4 х 4 клетки мы выполняем в главной
части программы:
begin
Task('p5');
Square4();
Right; Right; Right; Right;
Square4;
254
Down; Down; Down; Down;
Square4;
Left; Left; Left; Left;
Square4;
Up; Up; Up; Up;
end.
Рис. 1. Увесистый квадрат!
255
Задание p6
На этом квадраты заканчиваются – пришло время горизонтальных рядов (Рис.
1).
Рис. 1. По горизонтали
Процедуру Row для закрашивания клеток горизонтального ряда можно написать несколькими способами. Самый универсальный и простой – отогнать Робота к правой стенке, а затем вернуть его к левой стенке, понуждая по ходу
движения закрашивать клетки:
procedure Row();
begin
//Робот идёт вправо до стены:
while(FreeFromRight) do
Right;
256
//Робот идёт влево до стены
//и закрашивает клетки:
while(FreeFromLeft) do
begin
Paint;
Left;
end;
Paint;
end;
Так как ряды расположены регулярно, то опять пользуемся циклом for для
перехода к следующим рядам:
begin
Task('p6');
//Робот закрашивает 4 ряда:
for var n := 1 to 4 do
begin
Row();
if (n < 4) then
begin
Down; Down;
end;
end;
end.
257
Задание p7
Горизонтальные ряды сменились вертикальными – вот и вся разница (Рис. 1)!
Рис. 1. Закраска по вертикали
Процедуру Column нетрудно переделать из процедуры Row:
procedure Column();
begin
//Робот идёт вниз до стены:
while(FreeFromDown) do
Down;
//Робот идёт вверх до стены
//и закрашивает клетки:
while(FreeFromUp) do
begin
258
Paint;
Up;
end;
Paint;
end;
То же самое относится и к главной части программы:
begin
Task('p7');
//Робот закрашивает 4 ряда:
for var n := 1 to 4 do
begin
Column();
if (n < 4) then
begin
Right; Right;
end;
end;
end.
259
Задание p8
А в этом задании Роботу нужно закрасить и горизонтальные, и вертикальные
ряды (Рис. 1).
Рис. 1. И те, и другие
Процедуры Row и Column уже написаны – слава процедурам! – поэтому мы сразу берёмся за код главной части программы, опять же копируя большую его
часть из предыдущих проектов – слава нашему труду!
begin
Task('p8');
260
//Робот закрашивает 4 горизонтальных ряда:
for var n := 1 to 4 do
begin
Row();
if (n < 4) then
begin
Down; Down;
end;
end;
//Робот переходит к вертикальным рядам:
while (FreeFromUp) do
Up;
Right;
//Робот закрашивает 4 вертикальных ряда:
for var n := 1 to 4 do
begin
Column();
if (n < 4) then
begin
Right; Right;
end;
end;
end.
261
Задание p9
Робот продолжает своё победное шествие с процедурами Row и Column (Рис. 1).
Рис. 1. Уголки
Правда, на этот раз обе процедуры необходимо поправить, потому что Робот
идёт не до стены, а делает вполне определённое число шагов:
procedure Row();
begin
//Робот идёт вправо:
for var r:= 1 to 8 do
262
Right;
//Робот идёт влево
//и закрашивает клетки:
for var r:= 1 to 8 do
begin
Paint;
Left;
end;
Paint;
end;
procedure Column();
begin
//Робот идёт вниз:
for var r:= 1 to 8 do
Down;
//Робот идёт вверх
//и закрашивает клетки:
for var r:= 1 to 8 do
begin
Paint;
Up;
end;
Paint;
end;
Стороны уголков можно закрашивать в любом порядке:
begin
Task('p9');
//Робот закрашивает 3 горизонтальных и
//вертикальных ряда:
for var n := 1 to 3 do
begin
Row();
Column();
if (n < 3) then
begin
Down; Down;
263
Right; Right;
end;
end;
end.
Задание p10
Ура! Пишем новую процедуру – для обхода квадрата по контуру (Рис. 1).
Рис. 1. Квадратный контур
Процедура, конечно, самая незамысловатая:
264
procedure Contour();
begin
//верхняя сторона:
for var n := 1 to 4 do
begin
Paint;
Right;
end;
//правая сторона:
for var n := 1 to 4 do
begin
Paint;
Down;
end;
//нижняя сторона:
for var n := 1 to 4 do
begin
Paint;
Left;
end;
//левая сторона:
for var n := 1 to 4 do
begin
Paint;
Up;
end;
end;
Да и главная часть программы не сложнее:
begin
Task('p10');
//Робот закрашивает 5 квадратов:
for var k := 1 to 5 do
begin
265
Contour();
//Робот переходит к следующему квадрату:
if (k < 5) then
for var n := 1 to 6 do
Right;
end;
end.
266
Набор заданий pp
Последний набор заданий также отдан процедурам, но на этот раз с параметрами (Рис. 1).
Рис. 1. Нас ждут параметры!
Процедуры без параметров менее универсальны. Например, все рассмотренные нами выше процедуры не смогли бы нарисовать крестик или квадратик
другого размера. А вот процедуры с параметрами могут гораздо больше, поэтому они интереснее и полезнее!
Задание pp1
Элементарное задание на закрашивание одной клетки в каждой горизонтали
(Рис.1).
Процедуры очень простые. Главное – не забыть, что, идя вправо, Робот закрашивает клетку, а возвращаясь влево, не закрашивает:
//РОБОТ ИДЁТ ВПРАВО n ШАГОВ
//И ЗАКРАШИВАЕТ КЛЕТКУ
procedure RightN(n: integer);
267
begin
for var i := 1 to n do
Right;
Paint;
end;
//РОБОТ ИДЁТ ВЛЕВО n ШАГОВ
procedure LeftN(n: integer);
begin
for var i := 1 to n do
Left;
end;
Рис. 1. По одной
268
В главной части программы мы вызываем процедуры с соответствующими
аргументами и аккуратно переводим Робота вниз после возвращения:
// ГЛАВНАЯ ПРОГРАММА
begin
Task('pp1');
RightN(6); LeftN(6); Down;
RightN(8); LeftN(8); Down;
RightN(4); LeftN(4); Down;
RightN(3); LeftN(3); Down;
RightN(10); LeftN(10); Down;
RightN(1); LeftN(1); Down;
RightN(6); LeftN(6);
end.
Обратите внимание, что, находясь в нижней горизонтали, Робот вниз не идёт!
Задание pp2
Роботу поручено закрасить вертикальные ряды клеток переменной длины
(Рис. 1).
Ну а нам поручено написать процедуру PaintDown для нашего милого Робота.
Так как базовая клетка находится у верхней стены, то после закраски вертикального ряда мы должны вернуть Робота на место:
procedure PaintDown(n: integer);
begin
//Робот идёт вниз и закрашивает клетки:
for var r := 1 to n do
begin
Paint;
Down;
269
end;
//Робот возвращается наверх:
for var r := 1 to n do
Up;
end;
Рис. 1. Вертикальные работы
Это приём облегчит нам и переход к следующим вертикальным рядам:
begin
Task('pp2');
270
PaintDown(7);
Right; Right;
PaintDown(4);
Right; Right;
PaintDown(9);
Right; Right;
PaintDown(6);
Right; Right;
PaintDown(8);
end.
Задание pp3
Спиральный штопор – задание на 4 процедуры (Рис. 1)!
Рис. 1. Вошли в штопор
271
Элементарные процедуры и написать элементарно просто:
procedure RightN(n: integer);
begin
//Робот идёт вправо:
for var i := 1 to n do
Right;
end;
procedure LeftN(n: integer);
begin
//Робот идёт влево:
for var i := 1 to n do
Left;
end;
procedure DownN(n: integer);
begin
//Робот идёт вниз:
for var i := 1 to n do
Down;
end;
procedure UpN(n: integer);
begin
//Робот идёт вверх:
for var i := 1 to n do
Up;
end;
А в главной части программы нужно только аккуратно подсчитывать клетки
в каждом витке спирали и записывать в вызовы соответствующих процедур:
begin
Task('pp3');
//Робот идёт по спирали:
DownN(8);
RightN(8);
UpN(8);
LeftN(7);
272
DownN(7);
RightN(6);
UpN(6);
LeftN(5);
DownN(5);
RightN(4);
UpN(4);
LeftN(3);
DownN(3);
RightN(2);
UpN(2);
LeftN(1);
DownN(1);
end.
Кстати говоря, в длине витков спирали имеется определённая закономерность, так что код главной части программы можно существенно сократить за
счёт использования цикла for.
Задание pp4
«Символическое» задание на закрашивание буквы Т различного написания
(Рис. 1).
По условию задачи, мы должны снабдить Робота процедурой SymbolT с двумя
параметрами.
Параметр m обозначает половину ширины буквы. Однако все буквы имеют нечётную ширину, поэтому под половиной мы будем понимать меньшую половину. Что касается параметра h, то про него ничего не говорится, но понятно, что
это высота ножки буквы Т. Мы будем считать, что это полная высота. Тогда
процедура SymbolT может быть такой.
273
Рис. 1. Три тэ
procedure SymbolT(m, h: integer);
begin
//Робот идёт влево:
for var i := 1 to m do
Left;
//Робот идёт вправо и закрашивает клетки:
for var i := 1 to m * 2 + 1 do
begin
Paint;
Right;
end;
274
//Робот возвращается в начальную клетку:
for var i := 1 to m+1 do
Left;
//Робот идёт вниз:
for var i := 1 to h-1 do
Down;
//Робот идёт вверх и закрашивает клетки:
for var i := 1 to h-1 do
begin
Paint;
Up;
end;
end;
Много лишней беготни, но зато всё просто и понятно!
В главной части программы мы вызываем нашу процедуру с соответствующими значениями параметров и переходим к следующей букве:
begin
Task('pp4');
//первый символ:
SymbolT(3, 4);
//переход:
for var i := 1 to 7 do
Right;
SymbolT(2, 5);
//переход:
for var i := 1 to 5 do
Right;
SymbolT(1, 6);
end.
275
Задание pp5
Прямоугольник мы уже закрашивали неоднократно, но без процедур (Рис. 1).
Рис. 1. Прямо угольник!
Процедура Rect получилась довольно простая, потому что высота прямоугольника выражается чётным числом. Это значит, что Робот может закрашивать
по 2 ряда за итерацию: сначала шагая вправо, а затем влево:
procedure Rect(w, h: integer);
begin
for var r := 1 to h div 2 do
begin
276
//Робот идёт вправо и закрашивает клетки:
for var c := 1 to w do
begin
Paint;
Right;
end;
Left;
//Робот делает шаг вниз:
Down;
//Робот идёт влево и закрашивает клетки:
for var c := 1 to w do
begin
Paint;
Left;
end;
Right;
//Робот делает шаг вниз:
Down;
end;
После трудов праведных Робота следует вернуть на базу для заслуженного
вознаграждения:
//Робот возвращается на базу:
for var r := 1 to h do
Up;
end;
Задание pp6
Робот должен закрасить 5 прямоугольников различных размеров (Рис. 1).
Так как нас никто не предупредил, что процедура Rect понадобится и в другом
задании, то мы написали слишком простую процедуру, которая не работает с
прямоугольниками нечётной высоты.
277
Рис. 1. Их стало больше!
Чтобы не писать процедуру заново, слегка усовершенствуем старую, изменив и
добавив несколько строк кода:
procedure Rect(w, h: integer);
begin
//число итераций:
var h2 := (h + 1) div 2;
for var r := 1 to h2 do
begin
//Робот идёт вправо и закрашивает клетки:
for var c := 1 to w do
begin
278
Paint;
Right;
end;
Left;
//если высота прямогольника чётная
//или итерация не последняя:
if ((h mod 2 = 0) or (r < h2)) then
//Робот делает шаг вниз:
Down;
//Робот идёт влево и закрашивает клетки:
for var c := 1 to w do
begin
Paint;
Left;
end;
Right;
//Робот делает шаг вниз:
Down;
end;
//Робот возвращается на базу:
for var r := 1 to h do
Up;
end;
Попробуйте оптимизировать эту процедуру!
В главной части программы, как обычно, мы вызываем процедуру с нужными
значениями параметров и пересылаем Робота от одного прямоугольника к
другому:
begin
Task('pp6');
Rect(5, 3);
279
for var i := 1 to 7 do
Right;
Up;
Rect(2, 6);
Right; Right; Right;
Rect(4, 6);
for var i := 1 to 7 do
Down;
Left; Left;
Rect(8, 3);
for var i := 1 to 7 do
Left;
Up;Up;
Rect(5, 5);
end.
Процедура закрашивания прямоугольника без лишних шагов Робота не столь
проста, как хотелось бы:
procedure RectEx(w, h: integer);
begin
//число итераций всегда чётное:
var h2 := h + h mod 2;
for var r := 1 to h2 do
begin
//если итерация нечётная,
//Робот идёт вправо и закрашивает клетки:
if (r mod 2 = 1) then
begin
Paint;
for var c := 1 to w - 1 do
begin
Right;
Paint;
end;
if (r < h) then
Down;
end
//если итерация чётная,
280
//Робот идёт влево и закрашивает клетки:
else
begin
Paint;
for var c := 1 to w - 1 do
begin
Left;
if (r <= h) then
Paint;
end;
//Робот делает шаг вниз:
if (r < h2) then
Down;
end;
end;
//Робот возвращается на базу:
for var r := 1 to h - 1 do
Up;
end;
Задание pp7
Робот ходит по кругу, который в этом задании называется периметром прямоугольника (Рис. 1).
Если вы помните процедуру Contour, то просто скопируйте её в проект и подправьте диапазоны изменения параметров циклов:
procedure Perimeter(w, h: integer);
begin
//верхняя сторона:
for var n := 1 to w-1 do
begin
Paint;
Right;
end;
//правая сторона:
for var n := 1 to h-1 do
begin
281
Paint;
Down;
end;
//нижняя сторона:
for var n := 1 to w-1 do
begin
Paint;
Left;
end;
//левая сторона:
for var n := 1 to h-1 do
begin
Paint;
Up;
end;
end;
Рис. 1. Путешествие по периметру
282
Главная часть программы и вовсе простая:
begin
Task('pp7');
Perimeter(5, 4);
for var i := 1 to 6 do
Down;
Left;
Perimeter(4, 3);
for var i := 1 to 7 do
Right;
for var i := 1 to 5 do
Up;
Perimeter(4, 5);
end.
Задание pp8
Последнее задание опять довольно символическое (Рис. 1).
Рис. 1. На-на?
283
Нарисовать букву Н можно разными способами, но важно, чтобы Робот возвращался в начальную клетку:
procedure SymbolH(w, h, t: integer);
begin
//левая ножка:
for var n := 1 to h do
begin
Paint;
Down;
end;
//правая ножка:
for var n := 1 to w - 1 do
Right;
for var n := 1 to h do
begin
Up;
Paint;
end;
//перекладина:
for var n := 1 to t - 1 do
Down;
for var n := 1 to w - 1 do
begin
Paint;
Left;
end;
//домой:
for var n := 1 to t - 1 do
Up;
end;
В главной части программы мы вызываем процедуру SymboH с соответствующими значениями параметров и выполняем переходы между буквами:
begin
Task('pp8');
284
SymbolH(4, 6, 3);
for var i := 1 to 5 do
Right;
Down;
SymbolH(5, 5, 4);
for var i := 1 to 6 do
Right;
Up; Up;
SymbolH(3, 7, 2);
end.
285
Набор заданий examen
В итоговом наборе 10 заданий, которые недоступны в диалоговом окне загрузки шаблонов, поэтому весь код придётся набирать вручную (или копировать из ранее выполненных заданий).
Задание examen1
Робот должен закрасить 5 рядов клеток через одну (Рис. 1).
Рис. 1. Чередуем
286
Самое простое решение – записать в процедуру Punktir код для закраски одного ряда клеток с возвратом к левой стене, а в главной части программы в цикле for вызвать эту процедуру 5 раз.
Более интересное решение – все действия поместить в процедуру Punktir, а
клетки закрашивать при движении Робота и слева направо, и справа налево. В
этом случае код получится, конечно, сложнее:
uses
Robot;
procedure Punktir();
begin
for var row := 1 to 6 do
begin
if (row mod 2 = 1) then
begin
for var col := 1 to 7 do
begin
Paint;
if (col < 7) then
begin
Right; Right;
end;
end;
Down; Down;
end
else
begin
for var col := 1 to 7 do
begin
if (row < 6) then
Paint;
if (col < 7) then
begin
Left; Left;
end;
end;
if (row < 6) then
begin
Down; Down;
end;
end;
287
end;
end;
begin
Task('examen1');
Punktir;
end.
Задание examen2
Усложнённая версия первого задания: Робот должен закрасить клетки в шахматном порядке (Рис. 1).
Рис. 1. Шашечки
288
Если вы написали простой вариант процедуры Punktir, то её вполне можно
использовать и в этом задании, а все изменения перенести в цикл for. Сложный вариант этой процедуры потребует небольшой доработки:
uses
Robot;
procedure Punktir();
begin
for var row := 1 to 10 do
begin
if (row mod 2 = 1) then
begin
for var col := 1 to 7 do
begin
Paint;
if (col < 7) then
begin
Right; Right;
end;
end;
Down;
end
else
begin
Right; Right;
for var col := 1 to 7 do
begin
Paint;
if (col < 7) then
begin
Left; Left;
end;
end;
if (row < 9) then
Down;
end;
if (row < 10) then
Left;
end;
end;
begin
289
Task('examen2');
Punktir();
end.
Задание examen3
От линейно-поступательного движения Робот переходит «периметрическому»
(Рис. 1).
Рис. 1. Закрутило
290
Обратите внимание, что Робот должен закончить работу в левом верхнем углу
самого «дальнего» прямоугольника. Поэтому сначала нужно закрасить верхний левый «периметр», затем перейти в нижний и только потом в «целевой».
Также следует учесть, что Робот должен вернуться в левый верхний угол прямоугольника.
Процедура Perimeter очень проста и в пояснениях не нуждается:
uses
Robot;
procedure Perimeter(n, m: integer);
begin
Paint;
for var col := 1 to n - 1 do
begin
Right;
Paint;
end;
for var row := 1 to m - 1 do
begin
Down;
Paint;
end;
for var col := 1 to n - 1 do
begin
Left;
Paint;
end;
for var row := 1 to m - 1 do
begin
Up;
Paint;
end;
end;
291
Переходы между прямоугольниками в главной части программы можно организовать в виде циклов, но это необязательно:
begin
Task('examen3');
Perimeter(5, 4);
Down; Down; Down; Down; Down; Down;
Left;
Perimeter(4, 3);
Right; Right;Right;Right;Right;Right;Right;
Up; Up; Up; Up; Up;
Perimeter(4, 5);
end.
Задание examen4
«Экзаменационные» задания на процедуры закончены. Все остальные задания
– на изменяемые поля. Это значит, что мы заранее не знаем, например, точных
размеров прямоугольника, как в этом задании (Рис. 1).
В таких случаях цикл с параметром for не годится, и следует использовать
цикл с условием while.
Условия движения вдоль стен очевидны, но мы ещё должны учесть, что в угловых клетках пути Робота стены отсутствуют, поэтому он просто делает 1 шаг в
нужном направлении.
292
Рис. 1. Идём в обход
uses
Robot;
begin
Task('examen4');
Paint; Right;
while (WallFromDown) do
begin
Paint; Right;
end;
Paint; Down;
while (WallFromLeft) do
293
begin
Paint; Down;
end;
Paint; Left;
while (WallFromUp) do
begin
Paint; Left;
end;
Paint; Up;
while (WallFromRight) do
begin
Paint; Up;
end;
end.
Задание examen5
После «кругосветного» путешествия это задание Роботу покажется очень простым (Рис. 1).
Чтобы не ошибиться, Робот может, например, считать шаги и закрашивать
клетки через 1 шаг:
uses
Robot;
begin
Task('examen5');
var step := 0;
//номер шага:
while(FreeFromRight) do
begin
Right;
step += 1;
if (step mod 2 = 1) then
Paint;
294
end;
end.
Рис. 1. Возвращение в коридор
Задание examen6
В этом задании условия закрашивания клеток более интересные (Рис. 1)!
Если внимательно проанализировать ситуацию на Рис. 1, то становится ясно,
что Робот закрашивает клетки именно в двух случаях:
295
1. Когда под ним стена.
2. Когда над ним стена.
Рис. 1. Вразброс
В первом случае он делает шаг вниз, закрашивает клетку, а затем возвращается восвояси. Второй случай очевиден и противоположен:
uses
Robot;
begin
Task('examen6');
while(true) do
begin
296
if (WallFromDown) then
begin
Up;
Paint;
Down;
end;
if (WallFromUp) then
begin
Down;
Paint;
Up;
end;
if (FreeFromRight) then
Right
else
break;
end;
end.
Задание examen7
Условия закрашивания клеток ещё усугубляются (Рис. 1)!
Тут уже нужно смотреть в оба и несколько раз запускать задание, чтобы высмотреть все детали в подробностях!
В итоге мы должны прийти к таким (умо)заключениям. Робот закрашивает
клетку сверху, если:
1. Он стоит на закрашенной клетке, и сверху нет стены.
2. Он стоит на незакрашенной клетке, и стен нет ни сверху, ни снизу.
Записать эти условия на языке, понятном всякому Роботу, не составит ни малейшего труда.
297
Рис. 1. Требования повышаются
uses
Robot;
begin
Task('examen7');
Right;
while(true) do
begin
if ((CellIsPainted and FreeFromUp) or (CellIsFree and FreeFromDown
and FreeFromUp)) then
begin
Up;
Paint;
298
Down;
end;
if (FreeFromRight) then
Right
else
break;
end;
end.
Задание examen8
Для выполнения этого задания нужна, в первую очередь, хорошая память (Рис.
1).
Рис. 1. Дежа-вю
299
Она поможет нам вспомнить задание cif16 (а), в котором Робот послушно ходил из одного угла в другой. Теперь он должен ещё прихватить с собой кисточку, чтобы закрасить угловую клетку:
begin
Task('examen8');
//если справа свободно,
//идём вправо до стены:
if (FreeFromRight) then
while(FreeFromRight) do
Right
//если слева свободно,
//идём влево до стены:
else if (FreeFromLeft) then
while(FreeFromLeft) do
Left;
//если сверху свободно,
//идём вверх до стены:
if (FreeFromUp) then
while(FreeFromUp) do
Up
//если снизу свободно,
//идём вниз до стены:
else if (FreeFromDown) then
while(FreeFromDown) do
Down;
Paint;
end.
Задание examen9
Здесь Робот, как таксист, работает на 2 счётчика (Рис. 1).
Счётчики понадобятся ему при возвращении на базу, или, говоря потаксистски, в парк.
300
Идя в угол, Робот наматывает пробег на счётчик, а идя на базу – сматывает:
Рис. 1. Задание на 2 счётчика
uses
Robot;
procedure Row(n: integer);
begin
end;
begin
Task('examen9');
301
var dx:= 0;
var dy:= 0;
while(FreeFromRight) do
begin
Right;
dx += 1;
end;
while(FreeFromDown) do
begin
Down;
dy += 1;
end;
//закрашиваем угловую клетку:
Paint;
//возвращаемся на базу:
while(dx > 0) do
begin
Left;
dx -= 1;
end;
while(dy > 0) do
begin
Up;
dy -= 1;
end;
end.
302
Задание examen10
А стену можно обойти и с одним счётчиком (Рис. 1).
Рис. 1. Огибаем
Задание простое и неутомительное. Как для нас, так и для Робота:
uses
Robot;
procedure Vert(w, h: integer);
begin
303
end;
begin
Task('examen10');
var dx := 0;
while(WallFromDown) do
begin
Right;
dx += 1;
end;
Down;
while(dx > 0) do
begin
Left;
dx -= 1;
end;
end.
На этом все задания закончились. Робот сделал своё дело и должен уйти…
304
Приложения
В этой части книги собрана дополнительная информация, которая может
пригодиться вам как при решении готовых заданий, так и при составлении
собственных.
Наборы заданий
Всего для Исполнителя Робота имеются такие наборы заданий:
а – система команд Робота (4)
c – циклы for с параметром (16)
if – условный оператор if (11)
w – циклы while с условием (17)
сif – циклы + логические выражения (22)
count – переменные-счётчики (17)
cc – вложенные циклы (19)
p – процедуры без параметров (10)
pp – процедуры с параметрами (8)
mix – разные задачи на управляющие структуры (10)
examen - задачи на процедуры с параметрами и изменяемые поля (10) (отсутствует в диалоговом окне)
Итого: 10 (11) наборов и 134 (144) задания.
305
Система команд Робота
Робот может выполнить 5 команд (Рис. 1).
Рис. 1. Команды для Робота
Right – идти вправо на 1 клетку
Left – идти влево на 1 клетку
Down – идти вниз на 1 клетку
Up – идти вверх на 1 клетку
Paint – закрасить клетку, на которой Робот стоит
306
Робот может с помощью «датчиков» определять наличие стен по границам
клетки, на которой он стоит (Рис. 2).
Рис. 2. Датчики Робота
WallFromLeft – возвращает True, если слева от Робота стена
WallFromRight – возвращает True, если справа от Робота стена
WallFromUp – возвращает True, если сверху от Робота стена
WallFromDown – возвращает True, если снизу от Робота стена
307
Эти же «датчики» сообщают Роботу, что стены вокруг его клетки отсутствуют
(Рис. 3).
Рис. 3. Датчики Робота
FreeFromLeft – возвращает True, если слева от Робота стена отсутствует
FreeFromRight – возвращает True, если справа от Робота стена отсутствует
FreeFromUp – возвращает True, если сверху от Робота стена отсутствует
FreeFromDown – возвращает True, если снизу от Робота стена отсутствует
308
Другой датчик Робота – цветовой – определяет, закрашена ли клетка, на которой Робот стоит (Рис. 4).
Рис. 4. Цветовой датчик Робота
CellIsFree – возвращает True, если клетка с Роботом не закрашена
CellIsPainted – возвращает True, если клетка с Роботом закрашена
309
Советы по решению заданий
• Заведите для решений отдельную папку, чтобы потом не искать файлы
на диске.
• Внутри этой папки вы можете создать папки для каждого решения.
• Чтобы при загрузке новых заданий они автоматически сохранялись в
нужной папке, сначала запишите в неё одно задание, а затем, приступая к
работе, запускайте среду двойным щелчком по файлу решения из этой
папки.
• Выполняйте задания последовательно, так вы лучше отработаете
навыки программирования.
• Внимательно читайте условия выполнения задания.
• Многие задачи можно решить несколькими способами. Некоторые из них
могут быть эффективнее, чем это необходимо. Но ваша задача – отработка вполне определённых конструкций языка, а не разработка эффективных алгоритмов, поэтому отдавайте предпочтение простым алгоритмам.
• С другой стороны, и в рамках предложенных условий задачу можно решить несколькими способами. Ищите их, это поможет вам в будущем не
останавливаться на первом пришедшем в голову способе решения, а искать различные подходы к решению проблемы.
• При разработке алгоритма очень удобно держать задание перед собой.
Для этого запустите программу командой Программа > Выполнить без
связи с оболочкой (Рис. 1).
• Набирая текст в Редакторе кода, вы сможете мысленно проверять его работу по изображению на экране.
310
Рис. 1. Отличный вид!
• Но перед запуском программы сначала закройте это окно!
• Разрабатывайте алгоритм частями и сразу проверяйте, как Робот выполняет команды. Для этого используйте пошаговый режим работы
программы. Если в действиях Робота обнаружатся ошибки, сразу исправляйте их и снова проверяйте написанный код.
• Если, например, Робот должен закрасить клетки по периметру прямоугольного поля, то сначала напишите часть кода для закрашивания клеток верхней стороны прямоугольника. Если он работает правильно, переходите к закрашиванию правой стороны, и так далее.
• Если алгоритм движения Робота трудно представить мысленно, то перерисуйте поле на бумагу и проведите его путь. Такой способ поможет вам
найти закономерности в его действиях.
• Если алгоритм почти отлажен, переходите на автоматический режим,
чтобы не нажимать многократно кнопку Шаг.
311
• По мере отладки алгоритма увеличивайте скорость движения Робота,
чтобы не тратить время понапрасну.
• В заданиях с изменяемыми параметрами проверяйте действие алгоритма на всех принципиально разных полях. Вполне возможно, что на
некоторых полях ваш алгоритм работает правильно, а на других с ошибками.
• Используйте в проектах уже готовый и отлаженный код из предыдущих заданий, так вы сэкономите время на разработку алгоритма и написание нового кода.
• Ещё лучше и правильнее завести «копилку» элементарных типовых действий, из которых потом можно составлять сложные алгоритмы.
1. Например, очень часто Робот должен дойти до стены. Стены могут быть в
любом направлении, поэтому для определённости будем считать, что стена
находится справа от Робота (Рис. 2).
Рис. 1. Идём до стены
312
После выполнения следующего кода Робот остановится возле правой стены
(Рис. 3):
//Робот идёт до правой стены:
while(FreeFromRight) do
Right;
Рис. 2. Тютелька в тютельку
313
2. Робот идёт до левого верхнего угла (Рис. 3).
Рис. 3. Пора в угол
В этом случае Робот сначала идёт до левой стены, а затем до верхней (или
наоборот) (Рис. 4):
//Робот идёт до левой стены:
while(FreeFromLeft) do
Left;
//Робот идёт до верхней стены:
while(FreeFromUp) do
Up;
314
Рис. 4. Нашёл своё место
315
3. Робот идёт вправо и закрашивает 5 клеток (Рис. 5).
Рис. 5. Раск-раск-а
В данном случае Робот останавливается на последней закрашенной им клетке
(Рис. 6):
//Робот идёт вправо и
//закрашивает 5 клеток:
for var i := 1 to 5 do
begin
Paint;
if (i < 5) then
Right;
end;
316
Рис. 6. Главное – вовремя останоновиться!
Если он после закрашивания клеток продолжает движение в том же направлении, то условный оператор if нужно убрать.
317
4. Робот идёт вправо до стены и закрашивает клетки (Рис. 7).
Рис. 7. Закрашиваем до упора в стену
Если Робот стоит на закрашиваемой клетке, то ему придётся дополнительно
закрасить клетку у самой стены, так как после окончания цикла while он только дойдёт до неё (Рис. 8):
//Робот идёт до правой стены
//и закрашивает клетки:
while(FreeFromRight) do
begin
Paint;
Right;
318
end;
//Робот закрашивает клетку у стены:
Paint;
Рис. 8. Сдадим в срок
Робот может сначала закрасить клетку, а затем пойти вправо. Тогда порядок
команд в цикле while необходимо изменить:
//Робот закрашивает первую клетку:
Paint;
//Робот идёт до правой стены
//и закрашивает клетки:
319
while(FreeFromRight) do
begin
Right;
Paint;
end;
Если Робот стоит на незакрашенной клетке, то первую команду Paint следует
убрать.
Понятно, что совершенно невозможно (да и не нужно!) перечислить все миниалгоритмы, которые могут понадобиться при решении заданий, но вы можете
самостоятельно пополнять этот список по ходу решения задач.
Разработка собственных наборов заданий
Если вы хотите придумать собственные задания, то нет ничего проще!
Это может быть и одиночное задание, и целый набор. Второй вариант предпочтительнее, так как не стоит плодить без нужды лишние файлы.
В любом случае для заданий потребуется отдельный модуль.
Создайте новый файл и запишите его в нужную папку под тем же именем, что
и название модуля.
Для примера, файл модуля:
RVRobotTasks.pas
Название модуля:
unit RVRobotTasks;
Для разработки заданий потребуется модуль RobotTaskMaker:
320
uses
RobotTaskMaker;
В главной части собственного модуля нужно зарегистрировать все задания и
группу заданий:
begin
RegisterTask('rvrobot1', RVRobot1);
RegisterTask('rvrobot2', RVRobot2);
RegisterTask('rvrobot3', RVRobot3);
RegisterTask('rvrobot4', RVRobot4);
RegisterGroup('rvrobot', 'Новые задания для Робота',
'RVRobotTasks', 4);
end.
В этом модуле 4 задания. Каждое задание нужно зарегистрировать, передав
процедуре RegisterTask название задания (любое – по вашему выбору) и имя
процедуры с заданием:
RegisterTask(name: string; p: TaskProcType);
Группа заданий регистрируется с помощью процедуры RegisterGroup:
RegisterGroup(name,description,unitname: string; count: integer);
Здесь сначала указывается название группы, затем короткое описание и
название модуля и, наконец, число заданий в наборе.
Несмотря на регистрацию, группа заданий не появляется в диалоговом окне выбора заданий, поэтому заготовку программы придётся создавать самостоятельно.
321
Лучше записать шаблон на диск, а затем копировать его для каждого нового задания.
Все задания оформляются в виде отдельных процедур:
procedure RVRobot1;
begin
TaskText('Задание rvrobot1. Закрасить помеченные клетки');
Field(11, 11);
RobotBegin(1, 1);
RobotEnd(11, 11);
for var row := 1 to 11 do
for var col := 1 to row do
Tag(col, row);
end;
procedure RVRobot2;
begin
TaskText('Задание rvrobot2. Закрасить помеченные клетки');
Field(11, 11);
RobotBegin(1, 1);
RobotEnd(1, 11);
for var row := 1 to 11 do
for var col := 1 to 12 - row do
Tag(col, row);
end;
procedure RVRobot3;
begin
TaskText('Задание rvrobot3. Закрасить клетки у стены');
Field(11, 11);
RobotBegin(1, 1);
RobotEnd(1, 11);
for var row := 1 to 11 do
begin
var col := Random(9) + 2;
VerticalWall(col, row - 1, 1);
Tag(col, row);
end;
end;
procedure RVRobot4;
322
begin
TaskText('Задание rvrobot4. Закрасить клетки за стеной');
Field(11, 11);
RobotBegin(1, 1);
RobotEnd(1, 11);
var col := 0;
for var row := 1 to 11 do
begin
var tmp := Random(8) + 2;
while (col = tmp) do
tmp := Random(8) + 2;
col := tmp;
VerticalWall(col, row - 1, 1);
Tag(col + 1, row);
end;
end;
Поскольку модуль для проверки правильности работы кода запустить нельзя,
то параллельно создавайте файлы с решениями задач. Они должны включать
список используемых модулей:
uses
Robot, RVRobotTasks;
А в главной части программы следует вызвать задание, указав его название:
begin
Task('rvrobot1');
end.
Если вы запустите этот код, то увидите задание в том виде, в котором его создаёт процедура RVRobot1 (Рис. 1).
323
Рис. 1. Тест
Если вы обнаружите неточности или ошибки в работе процедуры, то исправляйте их в модуле с заданиями и снова запускайте файл с решением.
Задания после отладки можно решать точно так же, как мы это делали раньше.
Откомпилированный модуль RVRobotTasks.pcu (он создаётся автоматически
при запуске файла с решением или при выполнении команды меню Программа
> Компилировать) можно скопировать в отдельную папку, в которой будут
храниться файлы с решениями задач или в системную папку на диске С PascalABC.NET/ Lib.
324
Новое задание, естественно, сначала нужно придумать, а затем написать соответствующую процедуру, используя команды из модуля RobotTaskMaker.
Напечатать текст задания:
TaskText(s: string);
s – поясняющая строка, которая появляется в верхней части окна с заданием.
Начертить поле заданных размеров:
Field(szx,szy: integer);
szx, szy – размеры поля в клетках: ширина/высота.
Начертить горизонтальную стену:
HorizontalWall(x,y,len: integer);
x, y – координаты начала стены на поле в клетках. Координата х на 1 меньше
номера клетки, в которой стена начинается. Координаты клеток отсчитываются от 1.
len – длина стены в клетках.
Начертить вертикальную стену:
VerticalWall(x,y,len: integer);
x, y – координаты начала стены на поле в клетках. Координата y на 1 меньше
номера клетки, в которой стена начинается. Координаты клеток отсчитываются от 1.
len – длина стены в клетках.
325
Начертить Робота в начальной позиции:
RobotBegin(x,y: integer);
x, y – координаты начальной клетки пути Робота.
Начертить конечную позицию Робота:
RobotEnd(x,y: integer);
x, y – координаты конечной клетки пути Робота.
Обозначить стартовую и финишную позицию Робота:
RobotBeginEnd(x,y,x1,y1: integer);
Объединяет процедуры RobotBegin и RobotEnd.
Обозначить точкой закрашиваемую клетку:
Tag(x,y: integer);
x, y – координаты клетки с точкой, обозначающей клетку, которую Робот должен закрасить.
Обозначить точками прямоугольник закрашиваемых клеток:
TagRect(x,y,x1,y1: integer);
x, y – координаты левого верхнего угла прямоугольника.
326
x1, y1 – координаты правого нижнего угла прямоугольника
Обозначить закрашенную клетку:
MarkPainted(x,y: integer);
x, y – координаты закрашенной клетки зелёного цвета.
Рис. 2. Все команды в наглядном виде
На всякий случай составим задание для проверки данных на Рис. 2⬆:
procedure tipps5;
327
begin
TaskText('Задание tipps5. Закрасить клетки');
Field(8, 11);
RobotBegin(7, 1);
RobotEnd(8, 3);
Tag(8,5);
TagRect(4,7,7,9);
MarkPainted(8,11);
HorizontalWall(0,2,5);
VerticalWall(1,5,5);
end;
На Рис. 3 вы можете видеть, что рисунок правильный!
Рис. 3. Успешная проверка
328
Набор RVRobot
Этот набор заданий преследует единственную цель: показать на примерах, как
создавать собственные задания для Исполнителя Робота.
Задание rvrobot1
Нехитрое, но увлекательное задание на закрашивание клеток треугольником,
подобное тому, что мы уже решали раньше (Рис. 1).
Рис. 1. Полная косынка
329
Решение задачи простое, но нужно учесть условия перемещения Робота вниз и
к левой стене:
uses
Robot, RVRobotTasks;
begin
Task('rvrobot1');
for var row := 1 to 11 do
begin
for var col := 1 to row do
begin
Paint;
if (col < row) then
Right;
end;
//Робот возвращается к левой стене:
while ((row < 11) and FreeFromLeft) do
Left;
if (FreeFromDown) then
Down;
end;
end.
330
Задание rvrobot2
Как предыдущее задание, но треугольник перевёрнут вверх основанием (Рис.
1).
Рис. 1. Вверх тормашками
Решение легко получить из предыдущего задания, исправив несколько строк:
uses
Robot, RVRobotTasks;
begin
Task('rvrobot2');
331
for var row := 1 to 11 do
begin
for var col := 1 to 12-row do
begin
Paint;
if (col < 12-row) then
Right;
end;
//Робот возвращается к левой стене:
while ((row < 11) and FreeFromLeft) do
Left;
if (FreeFromDown) then
Down;
end;
end.
Задание rvrobot3
В этом задании появляются стены (Рис. 1).
Рис. 1. Об стену
332
Чтобы не разбить лоб о стену, Робот вызывает процедуру FreeFromRight.
Дойдя до стены, Робот закрашивает клетку, а потом тем же макаром возвращается к левой стене:
uses
Robot, RVRobotTasks;
begin
Task('rvrobot3');
for var row := 1 to 11 do
begin
while(FreeFromRight) do
Right;
Paint;
//Робот возвращается к левой стене:
while (FreeFromLeft) do
Left;
if (FreeFromDown) then
Down;
end;
end.
333
Задание rvrobot4
За стеной всегда интереснее! Поэтому Робот должен закрасить клетки, которые «прячутся» за стеной (Рис. 1).
Рис. 1. Заглянем за стену
«Тонкость» решения заключается в том, что верхнюю стену Робот должен
обойти снизу, а нижнюю – сверху. Все остальные стены можно обходить в любом направлении. В программе Робот обходит их сверху:
uses
Robot, RVRobotTasks;
334
begin
Task('rvrobot4');
for var row := 1 to 11 do
begin
while(FreeFromRight) do
Right;
//первая горизонталь:
if (row = 1) then
begin
Down; Right;
Up; Paint;
Down;
Left; Up;
end
else
begin
Up; Right;
Down; Paint;
Up; Left;
Down;
end;
//Робот возвращается к левой стене:
while (FreeFromLeft) do
Left;
if (FreeFromDown) then
Down;
end;
end.
335
Литература
Журнал Смекайлик: занимательное программирование на языках Паскаль2015 и Си-шарп в среде PascalABC.NET.
336