Программа-матрица (пасьянс «Турецкий платок»)
Рассмотрим эту особенность на такой занимательной задаче.
Очень часто, решая ту или иную проблему, мы оказываемся в шкуре буриданова осла. Задача может иметь два альтернативных решения, как две охапки сена слева и справа от упомянутого животного. Все доводы «за» и «против» уравновешены. Как в этом случае поступить? Ехать или не ехать в командировку? Покупать или не покупать еще один винчестер? Поистине, гамлетовские вопросы задает нам жизнь!
Некоторые в таких ситуациях бросают монетку, другие загадывают мужчину или женщину и смотрят в окно, ожидая, кто первый появится. Но все это ненаучные методы. Монетка может куда-нибудь закатиться, а по улице как назло за целый час только кошка и пробежит...
Есть проверенный столетиями метод принятия подобных решений. Достаточно разложить пасьянс. Сошелся – решение принято и все сомнения прочь. Можно подыскать дополнительные доводы в его пользу, и начать воплощать в жизнь. Пасьянс психологически нас на это настраивает.
Но принять решение подобным образом иногда бывает трудно, так как не всегда под рукой есть колода карт, да и не совсем удобно раскладывать их на рабочем месте. Но это можно сделать и на экране дисплея. В среде Windows, например, есть игры-пасьянсы («Солитер» и «Косынка»), но мы придумаем что-нибудь новенькое, а, главное, более занимательное и поучительное – разложим в среде Mathcad старинный пасьянс «Турецкий платок». На это есть три причины:
1.Чтобы лучше освоить программную среду, нужно постараться решить в ней задачу, для этого крайне неподходящую. Да, это своего рода программистское извращение, но – см. этюд 3.
2.В детстве каждый нормальный человек, наигравшись, ломал игрушку, чтобы посмотреть, как она устроена. Посмотрим и мы, как тасуется колода и раскладывается пасьянс.
3.По традиции гадать на картах и раскладывать пасьянсы разрешается только в святки[16]. Наш пасьянс можно считать числовой головоломкой, которую позволительно решать круглый год.
Mathcad-документ (см. рис. 6.9) позволяет разложить пасьянс «Турецкий платок» по следующим правилам. Из одной перетасованной колоды в 52 листа выкладывают картинкой вверх пять рядов по 10 карт в каждом. Последние две карты кладут в шестой неполный ряд на любое место, как правило, к первому и второму столбцам. Требуется распустить этот «платок», снимая из разных столбцов за один ход по две нижние одинаковые карты – тройки, дамы, тузы и т.д.
Для снятия карт нужно скопировать правую часть оператора П = ... (саму матрицу) на свободное место, подвести курсор к нужной текстовой константе (к карте), щелкнуть по левой кнопке мыши и нажать клавишу Delete. Вместо числа появится пустой квадратик.
Из разложенного пасьянса сняты две двойки. Теперь можно снять две восьмерки, два короля или две десятки (вопрос – какие из трех открытых). После этого откроются новые карты. Если удастся снять все 52 карты, то это означает, что в командировку все-таки ехать придется, а винчестер покупать надо.
Составление программы, формирующей матрицу П (раскладка пасьянса) – прекрасное и, что не менее важно, занимательное средство изучения таких базовых понятий линейной алгебры, как вектор и матрица. Так, при формировании матрицы П транспонируется матрица Масть (она ставится «на попа» – матрица с одной строкой превращается в матрицу с одним столбцом, то есть в вектор). Далее с помощью функции stack составляется новая нерастасованная колода карт, где одна отсортированная масть идет за другой (вектор Колода). Затем в цикле с параметром (for...) с помощью цикла while[17] и функции rnd идет формирование перетасованной колоды – вектора Тасованная_колода, который в конце программы двойным циклом с двумя параметрами (for... for...) складывается слоями в матрицу П.
Программу, формирующую матрицу П, можно развить: заставить программу отбраковывать явно нерешаемые раскладки – такие, например, где в одном столбце оказались три или даже четыре одинаковые карты. Еще одна тупиковая ситуация – две пары карт крест накрест закрывают друг друга. Это будет хорошим упражнением, закрепляющим навыки работы с «матричными» операторами и функциями в среде Mathcad. А вот более сложное задание читателю: доработать программу так, чтобы она сама раскладывала пасьянс, либо на худой конец сообщала, что его можно решить, просто снимая снизу первые подвернувшиеся одинаковые открытые карты. Более умная стратегия подразумевает выбор карты из трех или четырех одинаковых открытых карт.
Кроме линейной алгебры, наша программа затрагивает и другие интересные разделы математики – теорию вероятностей, статистику (см. функцию rnd, генерирующую псевдослучайные числа). Интересный вопрос: можно ли составить программу, высчитывающую вероятность сходимости того или иного пасьянса? Считается, что пасьянс «Солитер», входящий в стандартную поставку Windows, раскладывается при любых начальных раскладках. Но это только гипотеза…
Часто бывает так, что человек прекрасно делает то, чему он учился играючи и с большим удовольствием: ходит, говорит, плавает, катается на велосипеде и т.д. и т.п. Автор, например, задолго до школы научился считать, играя в карты: валет – двойка, дама – тройка и т.д. И сейчас, обращаясь к своим студентам, не устает повторять, что главное, что нужно получать от учебы, – это не знания, не практические навыки, а... удовольствие. Не получая радости от учебы, от повседневного труда, человек тратит свою жизнь впустую... Например, если тяжело идет освоение линейной алгебры – расслабьтесь и постарайтесь получить удовольствие.
Начинать изучение векторов и матриц (массивов данных) в курсе программирования (информатики) можно со знакомства со встроенными функциями и операторами конкретной программной среды. А можно раскладывать пасьянсы.
Как уже отмечалось ранее, переменные в Mathcad могут быть локальными, самообъявляющимися в программах (как, например, переменные Случайное_число, Колода, Карта, Столбец и Ряд в программе на рис. 6.9). Значение локальных переменных пропадает по выходу из программы. Разработчики языка Mathcad посчитали лишним обязательное объявление переменных до их использования (как это делается при работе с языком Pascal, например). Наверное, переменные не объявляются из-за того, что они все однотипные[18]. Но необъявление переменных может приводить к ошибкам, которые трудно выявить, так как язык Mathcad не имеет средств отладки
(debugging). Ввел программист в программу переменную dаy, а через пару операторов написал dey (что по произношению более соответствует английскому слову day (день); можно умудриться написать и dаy, где вторая буква будет из русского алфавита) – программа выдает неверный ответ. Опечатки в программе часто бывают намного страшней в плане отладки, чем ошибки алгоритма. Кроме локальных и глобальных переменных, значения которых заданы вне программы и автоматически в нее проникают, в среде Mathcad есть и системные (предопределенные) переменные и константы. Пример – числа e и p, значение которых определено самой системой (математикой), а не пользователем (см. приложение 4).
Мы уже не первый раз используем буквы кириллицы в именах переменных и функций. В программе на рис. 6.9 впервые все переменные прописаны по-русски. Pro и Contra этого приема.
Pro[19]:
Полные имена переменных (Столбец, Ряд вместо i, j) делают программу более простой для понимания, но более сложной для написания (рекомендуется длинные переменные писать один раз, а потом копировать в нужных местах). Конечно, можно было написать и английские термины в качестве имен переменных, но они будут выглядеть чужеродными в пасьянсе, программу которого для русскоязычного читателя написал человек, считающий себя русским. Да и автор, честно говоря, не знает, как будет по-английски «Масть», «Колода». Лезть же в словарь не с руки. Проще написать Мast, Коloda. Проще, да некрасиво (см. ниже).
Contra:
- Русские имена переменных порождают «смешенье языков французского с нижегородским»: for Столбец?! Правильнее и грамотней писать for Солбца[20] (для Столбца); на многих программистов русское имя объекта программирования (файла, переменной, функции и т.д.) действует как красная тряпка на быка[21].
- В латинском и русском алфавитах многие буквы (например, а, с) совпадают по написанию. Из-за этого в программе могут оказаться переменные, одинаковые для человека, но разные для Mathcad.
- Выбор для переменных шрифта с окончанием Cyr приводит к перекодировке символов. Из-за этого, например, может пропасть восклицательный знак в факториале и др.