Мы все знаем, что работа программиста зачастую заключается в модификации уже существующих программ (исходного кода) для исправления какого-то их некорректного поведения в некоторых ситуациях или для реализации новой функциональности для пользователей. В любом случае тот, кто считает себя хорошим программистом, должен быть готов что-то изменить или дополнить в своей или даже в чужой программе самым эффективным способом.
Мне кажется, у меня получилось придумать интересную задачу для проверки такой способности у программистов. Мне кажется, ничего подобного я никогда не видел, или, по крайней мере прямо сейчас не помню, может кто-то напомнит.
Кто-то в коментариях нашел очень интересные аналогии для изложенного в статье решения задачи: https://triztrainer.ru/theory/principles/principle13/
По результатам критики, мне очень интересно было узнать что существует:
Метод инверсии или методика проектирования «от противного», абсурдной перестановки. Такой подход к проектированию основан на развитии гибкости мышления, поэтому он позволяет получить совершенно новые, порой парадоксальные решения
Изначально статья имела другое название и формат публикации. Насколько я понимаю, из-за неадекватности, может даже, в какой-то степени, из-за грубости допущенной в том изначальном названии и грубой ошибке с изначальным форматом публикации, статья получила резко отрицательную оценку. Все это исправлено в текущей версии.
Насколько я могу судить по комментариям, по содержанию критических претензий не было. Поэтому теперь особенно рекомендую к прочтению.
Задание для программирования
Задача состоит из двух элементарных частей, и вся загвоздка, естественно, отнесена ко второй части.
Итак, первая часть задачи. Нужно написать программу, которая будет проверять знание таблицы умножения второклассником,
для этого должны случайным образом генерироваться два числа от 2 до 9 (фактически цифры);
выводить такой случайный пример на умножение для решения второклассником;
ждать ответа, или команды на завершение программы, если решили зациклить программу (пускай по нажатию клавиш "Enter" и "Esc" соответственно, суть совершенно не в этом);
похвалить в случае правильного ответа или сообщить правильный результат в случае ошибки.
Можно вывести статистику по завершении программы, но это не обязательное требование, это так сказать на пять с плюсом, в статистику можно включить среднее время на ответ, например, но это уже на 6+ (на шесть с плюсом по пятибалльной системе, но это все еще не суть, это не имеет отношения к заковырке запланированной во второй части задачи :).
Часть вторая, заковыристая
Тут мы подходим, неожиданно(!), к возможности расширения программы. А ведь, казалось бы, что же можно расширить в программе, которая уже может быть написана на "Шесть с плюсом" по пятибалльной системе?
И тут следует вот такое задание для второй части задачи:
необходимо расширить пункт 2 первой части задания разбивкой на подпункты, следующим образом:
2. выводить пример для решения второклассником
a. на умножение
b. на деление (целочисленное, по той же таблице умножения, все также для второклассника)
Но в таком виде разбор задания и его решения было бы через чур сложным для данной статьи. Разбор такого расширения требований к программе вместе с требованиями на оценку выше 5 баллов потребует еще одной статьи. Здесь я предлагаю разобрать простую замену пункта 2 на пункт 2 в виде:
2. выводить пример на деление для решения второклассником
Было бы очень интересно узнать какой процент людей, считающих себя программистами или даже опытными программистами, сможет сформулировать адекватное решение для такой в общем то элементарной задачи. К сожалению, мы вряд ли получим объективный результат из опроса поскольку не все согласятся объективно отнести себя к группе не справившихся даже анонимно, более того с тем решением, которое я ниже распишу, не все согласятся как с лучшим.
Но надо, конечно, описать проблему, которая возникает при таком, в общем то тривиальном, изменении требования к программе. Рассмотрим, как работает программа для примера с умножением и что не так с этим алгоритмом при переходе к примеру с делением.
Итак, по заданию из первой части,
1. программа генерирует два случайных числа Х и У в заданных пределах, в любом языке есть соответствующая библиотечная функция генерации случайных чисел, с этим нет проблем!
2. Запоминаем произведение (Х * У) в переменную Res;
3. Программа выводит на экран переменные Х и У с помощью форматированной строки, например как-то так:
«7 * 3 = введите ответ ниже»
4. Введенный ответ сохраняется в переменную Z и сравнивается с Res,
5. По результатам сравнения выводим либо поздравление, либо правильный результат из Res.
При попытке замены операции умножения на операцию деления там, где мы запоминаем произведение чисел, теперь это будет(?) частное от деления – то есть вместо
Res = (Х * У)
Кажется, нам просто нужно сделать
Res = (Х / У),
но, оказывается, так это работать не будет (неожиданно?), потому что дроби второклассник знать совершенно не обязан! К тому же нам все равно придется изменить то, что называется гордо «интерфейс взаимодействия с пользователем» - заменить знак умножения на знак деления в строке, отображающей задание. Оказывается, программу (функцию) надо как-то переписывать, нельзя просто поменять умножение на деление! В этот момент начинающий программист (или некомпетентный?) понимает, что он пока еще (по крайней мере!) не совсем программист и начинает барахтаться в поисках подходящего варианта. В этой необходимости изменить программу и заключается заковырка, которая позволяет оценить способность программиста найти нетривиальное решение.
Я бы не заметил этой самой нетривильности этого решения, если бы не старшекласники, которым я предложил решить эту задачу на факультативе информатики. Я припоминаю попытки что-то изобретать с процедурой генерации случайных чисел, и это было абсолютно ложное направление решения проблемы для них, потому что у них не было опыта, чтобы завершить эти попытки с каким-то результатом. Это были школьники, которые только начинали интересоваться программированием. Меня поразила их реакция, когда я показал самое простое решение, которое было им вполне доступно для реализации. Мне кажется у меня получилось, тогда, открыть для тех школьников дверку (пусть маленькую, локальную) к пониманию процесса разработки программ.
Правильное решение
Очевидным является то, что не надо особо придумывать, как известно. Если не менять формулу:
Res = (Х * У)
А просто вывести на экран вместо переменных Х и У, переменные Res и У (например, можно использовать Х) с помощью чуть измененной форматированной строки (заметим еще раз форматированную строку все равно придется менять!), например это будет выглядеть как-то так:
21 / 3 = введите ответ ниже
То далее еще придется изменить переменную для сравнения, вместо:
4. Введенный ответ сохраняется в переменную Z и сравнивается с Res,
Надо переписать (заменить переменную Res на Х)
4. Введенный ответ сохраняется в переменную Z и сравнивается с Х,
И все опять будет работать, но уже для примеров с делением.
Далее, если вы знакомы с указателями или со ссылками вы можете поупражняться с соответствующим способом параметризации алгоритма, но, как я уже заметил ранее, это могло бы быть темой для еще одной статьи, так же, как и необходимость дополнительных потоков для измерения времени или тайм-аута, за которое второклассник вводит ответ.
Интересно было бы прочитать описания чего-то подобного (условно заковыристых задач и их решений) из чужой практики.
Материалы
А еще мне кажется, что описанная здесь задача была бы хорошей проверкой даже для искусственного интеллекта, чтобы проверить насколько он, собственно, интеллект в области способностей к программированию. Интересно возьмется ли кто-нибудь сформулировать такую задачу для ИИ. Возможно ли это?