Задача № 2
Робот находится где-то в коридоре высотой в одну клетку. Там могут быть проходы вверх и вниз. Робот должен покрасить все клетки справа от самой левой покрашенной клетки с нижней границей и остановиться в этой клетке. Если такой клетки нет, нужно остановиться в крайней справа клетке коридора.
move_left()
Сделать шаг влево
move_right()
Сделать шаг вправо
move_up()
Сделать шаг вверх
move_down()
Сделать шаг вниз
fill_cell()
Закрасить клетку
free_from_up()
Проверить, свободно ли сверху
free_from_down()
Проверить, свободно ли снизу
free_from_left()
Проверить, свободно ли слева
free_from_right()
Проверить, свободно ли справа
wall_from_up()
Проверить, есть ли стена сверху
wall_from_down()
Проверить, есть ли стена снизу
wall_from_left()
Проверить, есть ли стена слева
wall_from_right()
Проверить, есть ли стена справа
cell_is_filled()
Проверить, закрашена ли клетка
cell_is_clean()
Проверить, чиста ли клетка
Ниже детальное решение задачи №2 с пошаговым объяснением. Мы предполагаем общий подход (без привязки к конкретному предмету/классу), чтобы понять логику алгоритма.
Цель задачи
- Найти левойmost покрашенной клетку в коридоре (если такая клетка есть).
- Покрасить все клетки справа от неё до конца коридора.
- Остановиться в самой левой покрашенной клетке.
- Если покрашенных клеток нигде нет, остановиться в крайней правой клетке коридора.
Пояснение к подходу
- Поскольку коридор высотой в одну клетку, путь горизонтальный; у нас есть возможность перемещаться влево и вправо, а также проверять стены и состояние клеток.
- Сначала мы идём к самой левой границе коридора (чтобы начать поиск с самой левой клетки).
- Затем идём вправо и ищем первую покрашенную клетку. Эта клетка и будет самой левой покрашенной в коридоре.
- Если такой клетки не найдено (вдоль всей длины ни одна клетка не закрашена), мы остаёмся на самой правой клетке.
- Если нашли L (левую покрашенную клетку), мы двигаемся вправо и закрашиваем все последующие клетки до конца коридора.
- Чтобы остановиться в L, после окрашивания возвращаемся обратно к L (считаем количество шагов, необходимое, чтобы дойти до L, и вернемся обратно той же дорогой).
Пошаговый план (с объяснениями)
1) Перейти к левой стене коридора
- Действие: перемещаться влево, пока не упремся в стену слева.
- Команды: повторять move_left() пока не wall_from_left() вернёт true.
2) Найти левую покрашенную клетку (L)
- Локальная переменная dist = 0 будет хранить количество шагов вправо от левого края до найденной L (если найдена).
- Признак found = false.
- Движемся вправо и проверяем клетки на предмет того, закрашены ли они.
- Шаги:
- если current cell закрашена (cell_is_filled()), то найдено L: found = true; остановиться.
- иначе если достигли правой границы без находки (wall_from_right() на текущей клетке вернёт true), значит покрашенных клеток нигде нет; оставить found = false и остановиться.
- иначе передвинуться вправо (move_right()) и увеличить dist на 1, повторять цикл.
3) Обработка ситуации без покрашенных клеток
- Если found == false (не нашли ни одной покрашенной клетки):
- Мы сейчас на правой границе коридора от исходной точки; задача говорит остановиться в крайней правой клетке.
- Достаточно завершить выполнение. Остановка на текущей клетке.
4) Обработка ситуации с найденной левой покрашенной клеткой L
- У нас сейчас на позиции L (перв answered найденной клеткой).
- Необходимо покрасить все клетки справа от L до конца коридора:
- Пока нет стены справа (пока не wall_from_right()):
- move_right()
- fill_cell() // покраска текущей клетки (когда мы в ней после перемещения вправо)
- Теперь мы достигли правой границы и закрасили все клетки справа от L.
5) Вернуться к L и остановиться там
- Нам нужно вернуться к самой левой покрашенной клетке L.
- Воспользуемся сохранённым dist (кол-во шагов вправо от левого края до L):
- повторить dist раз: move_left()
- Сейчас мы на клетке L. Остановиться можно.
6) Примечания по реализации
- dist сохраняется как счётчик шагов вправо от левой стенки до L на момент нахождения L.
- Если L находится в самой левой колонке (dist == 0), после окрашивания мы остаёмся на L без дополнительных движений назад.
- Нулевой случай: если в начале мы сразу стояли на левой клетке и она оказалась закрашенной, dist будет 0 и шагов назад не потребуется.
Пример пошагового выполнения (иллюстративно)
- Пусть коридор длиннее, чем 4 клетки, и первая закрашенная клетка находится на позиции 2 (от левого края, нумерация от 0).
- Шаги:
- Перемещаемся к левой стене (до стены).
- Слева направо: проверяем клетки по порядку. В клетке 0 пусто, в клетке 1 пусто, в клетке 2 закрашено -> найден L, dist = 2.
- Painting: на клетке 2 мы начинаем движение вправо и закрашиваем клетки 3, 4, 5, ..., до конца коридора.
- Возвращаемся к L: сделать 2 шага налево, попасть снова в клетку 2.
- Останавливаемся на клетке 2 (L).
Полезные заметки
- Если во время сканирования слева направо мы встретили закрашенную клетку сразу на левой стене (dist = 0), то все последующие шаги выполняются без шага назад.
- Если изначально нигде не было закрашено (found == false), робот просто идёт до правой границы и останавливается там.
- В случае очень длинного коридора логика одинаково работает независимо от длины.
Итоговый набор команд (структура)
- Move к левой стене:
while not wall_from_left():
move_left()
- Поиск L (левой покрашенной клетки) и вычисление dist:
dist = 0
found = False
while True:
if cell_is_filled():
found = True
break
if wall_from_right():
break
move_right()
dist += 1
- Если не найдено (found == False):
// останемся на текущей правой клетке
завершить
- Если найдено (found == True):
// закрашиваем все клетки справа от L
while not wall_from_right():
move_right()
fill_cell()
// вернуться к L
for i = 1 to dist:
move_left()
// сейчас на L, задача выполнена
Если хотите, могу привести это же решение в виде более «псевдокода» или адаптировать под конкретную лекцию/формат экзамена. Также могу добавить тестовый пример с конкретной длиной коридора и начальным положением для наглядного разбора.