Чемпионат ИТ-сферы Ульяновской области по программированию среди школьников

О задачах проекта "Управление новогодней иллюминацией"

Что дают задачи проекта

Проект встраивается в зимний тренировочный турнир, когда многие новички чемпионата, пришедшие осенью, уже получили начальные навыки. Именно поэтому в проекте все задачи требуют организации циклов. Несмотря на довольно простые сюжеты задач, проект дает довольно многое.

Во-первых, задачи проекта показывают, каким образом с помощью адресной светодиодной ленты с последовательным доступом к светодиодным узлам организовать интересные световые эффекты. Более того, некоторые, возможно, доведут свое умение программировать такие эффекты до реализации дома или в школе – нужно только приобрести ленту и средства сопряжения компьютера с ней.

Во-вторых, задачи проекта позволяют немного попрактиковаться с двумя распространенными представлениями цвета с помощью трехбайтной комбинации RGB – десятичной и шестнадцатеричной. При этом появляется потребность в преобразовании десятичного представления в шестнадцатеричное.

В-третьих, содержание задач дает возможность поупражняться с разными представлениями одних и тех же данных. Последовательный поток данных (сигнатура), передаваемый на вход ленты – удобно представляется векторами или одномерными массивами, а совокупности из двух и более полосок ленты – это матрицы, для которых естественно использовать двумерный массив. Впрочем, двумерный массив можно даже не использовать, если программировать либо сдвиг данных в одномерном массиве, либо генерацию одномерных массивов, различающихся местоположением цветового кода RGB. Можно вообще не использовать массив, осуществляя непосредственный вывод кодов с вычислением значений номеров тех светодиодов ленты, которые нужно зажигать. Любителям разнообразия здесь можно "порезвиться" – одну задачу решить с использованием массивов, другую – без использования.

В-четвертых, проект является простым примером реальной системы автоматизации проектирования (САПР). В трех первых задачах проектируются иллюминационные узлы, а в остальных – наборы сигнатур, которые на празднике будет прокручивать достаточно примитивная управляющая программа.

В-пятых, задачи проекта являются простым способом освоения школьниками широко распространенной в ИТ-сфере практики последовательного изменения функциональности программ. Например, развитие функциональности по мере перехода от одних версий к другим. В наборе задач имеется несколько случаев, когда следующая задача достаточно легко реализуется через модификацию кода предыдущей.

В-шестых, задачи проекта тренируют способность разбираться в объемных описаниях объекта управления и постановках задач. Первый раз читать механизмы доставки данных в нужные светодиодные узлы адресной ленты довольно муторно. Однако, разобравшись с этим механизмом, Вы получаете возможность доставлять нужные цвет и яркость в любую точку ленты. Во всех других задачах механизм тот же самый, что позволяет сразу сконцентрироваться на логике размещения RGB-кодов в сигнутурах. Повторение описания механизма в задачах P5-P10 сделано только для того, чтобы можно было выбирать для решения любую из этих задач, не обращаясь к самому первому описанию.

В реальной жизни программиста объемные описания делятся на два типа: описания от заказчика и внутрифирменные описания, позволяющие ускорить процесс разработки. В проекте "Управление новогодней иллюминацией" роль описаний первого типа играют встроенные в модель процесса тексты постановок задач. Описания второго типа фигурируют в проверяющей системе Contester. Эти описания сформулированы разработчиками тестов. Чтобы ваше решение прошло тестирование, нужно его строить на описаниях именно от разработчиков тестов. Вы можете заметить небольшие, но значимые отличия в постановках задач P1-P3 в этих двух описаниях. Умение видеть различия в разных описаниях и выбирать их этих описаний то, что используется при тестировании программы, является частью квалификации программиста. Аргументы и документы, обосновывающие различие в этих двух типах описаний, обычно находятся в сфере деятельности таких специалистов ИТ-компаний, как менеджеры, системные аналитики, постановщики задач.

В-седьмых, набор задач хорошо тренирует способность организовать вложенные циклы. Даже для одной полоски с бегущими огнями напрашивается решение с двумя циклами – внутренний для генерации одной сигнатуры, а внешний для генерации набора сигнатур. А вывод в матрицу светодиодов может потребовать третий уровень вложенности, хотя можно обойтись всего двумя или даже только одним уровнем.

В-восьмых, проект является достаточно наглядным примером осуществления широко распространенной технологии проектирования программ – Model-View-Control (MVC). Эта технология предполагает отделение представления (View) объектов на экране и в распечатках от модели обработки данных (Model) и управления этой обработкой (Control).

В проекте "Управление новогодней иллюминацией" компоненты Model разрабатывают участники тренировочного турнира – именно они программируют всю требуемую обработку данных. Компоненты View предоставляются участникам в готовом виде – это изображение лент и представление перемещения светодиодов.

Только благодаря применению технологии MVC, созданы условия для того, чтобы компоненты Model можно было создавать на различных языках программирования, как это делается в программистских турнирах.

В-девятых, решение задач проекта предоставляет участникам возможность легко отвечать на вопросы близких типа: "А что интересного умеют делать твои программы?". Показывать входные и выходные данные консольных программ обычных турнирных задач непосвященным бесполезно. А показать процесс, содержание которого определяется результатом своей программы – это обычно впечатляет. Если кто-то при этом с чувством превосходства покажет Вам бегущие огни в адресной ленте с купленным контроллером, то Вы смело можете ответить ему: "Купить всякий сможет, а вот запрограммировать самому – попробуй! Программы для таких котроллеров пишут нехилые программисты с очень хорошей зарплатой, а я уже часть подобных программистских задач решать научился. У тебя 'Made in China', а благодаря таким как я, могут появиться 'Made in Russia'".

В-десятых, сам факт решения задач проекта переводит того, кто это сделал, в более высокую категорию. Вокруг нас много людей, говорящих про цифровую экономику и автоматизацию процессов с надеждой на светлое будущее. И вот среди этих людей появляется школьник, который умеет решать практические и зачастую прозаические для него задачи автоматизации. Для окружающих его мечтателей такой школьник становится реальным творцом этого самого светлого будущего.

Технологические аспекты автоматизируемого процесса

Процесс доставки цветовых RGB-кодов к светодиодам в задачах нисколько не упрощен. Спрятаны только детали кодировки битов сигнутуры – там широтно-импульсный код (0 – короткий импульс в начале периода, 1 – длинный импульс), который реализуется обычно на аппаратном уровне, хотя вполне может быть реализован и программно, например, передачей четверок бит "1000" и "1110" в качестве кодов нуля и единицы на вход ленты. Спрятаны также все детали обеспечения заданной частоты ленты, поскольку это делается в драйверах вывода и на аппаратном уровне, а не в программах формирования выводимых данных.

В реальных адресных лентах не обязательно сначала задется байт R, затем G и B. Например, у автора проекта "Управление новогодней иллюминацией" в распоряжении оказалась лента с порядком BRG (WS2812B). Однако на практике манипуляции в задачах управления иллюминацией удобнее строить на базе привычного порядка RGB, а нужный порядок реализовать непосредственно в функции вывода в порт данных, к которому подключается лента.

Наклеивание ленты на алюминиевые подложки требуется для предотвращения перегрева только в случаях, когда состояние максимальной заженности отдельных светодиодов занимает большую долю времени их работы. В реальной новогодней иллюминации доля времени, когда конкретный светодиод горит с максимальной амплитудой, составляет единицы процентов. Если предотвратить "глюки" управляющей программы и генерацию сигнатур с высокой плотностью полностью зажженных светодиодов, то перегрева не будет и теплоотводной подложки не требуется.

Соединение нескольких горизонтальных отрезков между собой змейкой используется совсем не для того, чтобы усложнить жизнь участникам турнира – это технологическая необходимость. Если мы протянем длинный сигнальный провод от правого конца одного отрезка ленты к левому концу следующего отрезка, то на этом втором отрезке в реальной жизни получим световой мусор. При частоте 800 килогерц, на которой работают адресные ленты, длинный отрезок становится антенной и паразитной емкостью (это про микрофарады, а не про литры).

Задача 1. Подбор отрезков ленты для однорядных пластин

Эта задача изначально кажется довольно простой. Нужно сначала рассчитать число светодиодов в максимально длинном отрезке, который поместится на пластине заданного размера. Затем найти первый в списке отрезок с данным числом светодиодов. Однако задача усложняется ситуацией, при которой отрезка с требуемой длиной нет. Если эта задача сразу не поддается, то лучше продолжить решение с задачи P4, которая попроще.

Задачи, подобные P1-P3, достаточно часто встречаются в практике профессионального программирования. Особенно это касается программирования средств автоматизации проектирования.

Задача 2. Подбор отрезков ленты для двухрядных пластин

Тот, кто справился с решением первой задачи проекта, достаточно легко справится со второй. Здесь относительно небольшой прирост сложности.

Задача 3. Подбор кусков ленты для квадратных пластин

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

Задача 4. Бегущий огонь слева направо в одном ряду

Эта задача является наиболее простой и практически значимой. Чисто технологически очень легко натянуть ленту между двумя крепежными крючками и подключить к контроллеру.

Для начинающих изучать программирование первой проблемой может оказаться необходимость преобразовать десятичные коды RGB в шестнадцатеричные. Однако прелесть языков программирования в том, что такая функциональность уже встроена в средства форматирования выходных данных в процедурах вывода. Например, из двух десятичных чисел 255 и 7 легко можно получить в распечатке объединенное шестнадцетиричное представление FF07 с помощью формата "02X". На языке Си/C++ это достигается вызовом printf("%02X%02X",255,7), а на языке Python – вызовом:

print("{:02X}".format(255)+"{:02X}".format(7))

Второй проблемой для начинающих программистов может быть неумение программировать вложенные циклы. Кажется естественным создать два цикла: во внутреннем генерируется одна сигнатура, а во внешнем   серия сигнутур, различающихся местоположением заженного светодиода. Для опытного бойца нашего чемпионата решение задачи P4 на основе этого решения с отладкой займет единицы минут. Но можно обойтись только одним циклом. Для этого нам поможет операция по модулю n % m, результат которой является остатком от деления n на m. Например, рассмотрим цикл на языке Си:

for(n = 1; n <= 25; n++) { printf(" %d", n); if(n % 5 == 0) printf("\n"); } Этот цикл обеспечит вывод 5 строк по 5 чисел в каждой. Здесь величина n % 5 определяет номер позиции числа в выводимой строке, но для 5-й позиции в силу свойств деления по модулу дает 0. Аналогично получим для позиций 10, 15, 20, 25.

Если нам нужно было бы вывести значения переменной n только в позиции k каждой k-й строки, а в остальных позициях вывести нули, то нам каким-то образом нужно выделять эту k-ю позицию. Это можно сделать по-разному. Можно, например, сравнивать значение операции по модулю n % 5 с номером строки, меняя этот номер в ветви, где выводится разделитель строк. А можно вычислять значение следующего номера, который должен попасть в вывод. Очевидно, что этот номер в нашем примере после каждого вывода номера увеличивается на 6, т.е. на величину, которая на 1 больше количества чисел в строке. Второму способу соответствует код:

for (n = k = 1; n <= 25; n++) { if (n == k) { printf(" %d", n); k += 6; } else printf(" 0"); if (n % 5 == 0) printf("\n"); }

Осмысление приведенного выше примера существенно облегчает решение четвертой задачи начинающими программистами.

Задача 5. Бегущий огонь справа налево в одном ряду

Решение этой задачи может быть легко получено простой трансформацией решения предыдущей. Нужно только поработать с механизмом использования индекса k, выделяющего позицию вывода цвета светодиода.

Задача 6. Бегущие пары слева направо в двух рядах

Здесь полезно зарисовать змейку с номерами светодиодов, например: 1 2 3 4 5 10 9 8 7 6 На основе такого рисунка достаточно легко догадаться, как должны меняться индексы зажигаемых светодиодов. Ясно, что здесь уже потребуется два по разному изменяющихся индекса.

Задача 7. Бегущие пары справа налево в двух рядах

Используя рисунок змейки с номерами светодиодов, легко получить нужную трансформацию решения предыдущей задачи, чтобы быстро достичь успеха в задаче P7.

Задача 8. Бегущие колонки слева направо в квадрате

Для этой задачи полезно нарисовать змейку, охватывающую квадрат светодиодов, например: 1 2 3 4 8 7 6 5 9 10 11 12 16 15 14 13 Достаточно продвинутые участники могут попробовать построить отображение между номерами светодиодов в змейке и индексами двумерного массива i, j (номера строки и столбца матрицы). На основе этого отображения легко создавать генераторы сигнатур, которые обеспечивают самое разнообраное перемещение огней матрицы: по горизонтали, по вертикали, по диагоналям, по спиралям, пробегающие, нарастающие по группам светодиодов, разнонаправленные по направлениям движения, именяющие цвет по ходу перемещения и т.п.

Задача 9. Бегущие колонки справа налево в квадрате

Решение достигается достаточно легкой трансформацией решения предыдущей задачи.

Задача 10. Бегущие огни в диагонялях

Если при решении задачи P8 удалось построить отображение между номерами светодиодов и индексами матрицы, то задача решается за пару минут. Иначе нужно строить правила изменения значений пары индексов зажигаемых светодиодов. Впрочем, для разработки таких правил также потребуется не очень много времени после решения двух предыдущих задач.