/
Автор: Данилов Ю.А.
Теги: программирование информатика компьютерные технологии
ISBN: 5-07—000049-7
Год: 1988
Текст
этюды О ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ ETUDOK SZEMELYI SZAMTlti-GEPEKRE
etudOk SZEMELYI SZAMtTO-GEPEKRE GONDOLAT BUDAPEST, 1984
этюды О ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ Перевод с венгерского Ю. А. Данилова Издательство "Знание Москва 1988
5БК 32.973—01 Э 93 Научный редактор В. С. Дубровин 93 Этюды о персональных компьютерах. Пер. с вен- герского.— М.: Знание, 1988.— 160 с., ил. 45 к. 70 000 экз. Небольшая по объему, но содержательная и актуальная книга венгерских авторов К. Фрид, Я. Кепеша, К. Строкая и Т. Терека адресована начинающим программистам и ориентирована на самый широкий круг пользователей, пред- ставляя, по существу, увлекательный самоучитель. Многочисленные игровые примеры, написанные на БЕЙСИКе, не только способствуют активному усвоению предлагаемого материала, но делают книгу пригодной для широкого использования на уроках программирования в сред- ней школе. а 2405000000—048 3_______________ КБ1-019-88 073(02) — 88 ISBN 5-07—000049-7 ББК 32.973-01 © Fried Katalin, Kepes^Janos, Sztrokay Kalman, Tor ok Turul, 1984. © Издательство «Знание», 1988 г. Перевод на русский язык, комментарии, предисловие.
ПРЕДИСЛОВИЕ К РУССКОМУ ИЗДАНИЮ В 1984 г. известное венгерское издательство «Гондо- лат» («Мысль») выпустило книгу четырех авторов -- Каталин Фрид, Яноша Кепеша, Калмана Строкая и Ту- рула Тёрёка — «Этюды для персонального компьютера^ с предисловием известного венгерского педагога мате- матика профессора Яноша Шурани. Очень и очень немногие книги, посвященные вычисли- тельной технике и технологии программирования, чита- ются с тем удовлетворением понимания и соучастия, с ко- торым я прочел «Этюды о персональных компьютерах». И хотя четверть века работы в сфере кибернетики и ин- форматики делают мою точку зрения позицией профес- сионала, тем не менее у меня есть достаточные основания рекомендовать эту книгу самым широким кругам читате- лей. Всеобщая «компьютеризация» из волны преврати- лась в девятый вал и уже не нуждается ни в защите, ни в поддержке. Задача состоит в правильном и эф- фективном использовании ее «энергии». В отличие от традиционного построения аналогичных пособий, обычно начинающихся с описания структурно- функциональных характеристик компьютера и его прог- раммного обеспечения, процесс знакомства и познавания персонального компьютера в «Этюдах...» предельно «оче- ловечен». Именно так мы знакомимся и начинаем об- щаться с ранее незнакомыми нам людьми на улице, на службе или в компании. Представившись, мы непосред- ственно приступаем к теме беседы, обычно не выясняя всех «параметров» собеседника (при необходимости мы познаем их в процессе общения). Точно так же для пре- одоления «языкового барьера» между пользователем и компьютером предлагается весьма эффективная про- цедура освоения основных функций и свойств языка про- граммирования одновременно с приобретением навыков решения конкретных задач. 5
В книге последовательно выдерживается ориентация на «среднего» читателя, занимающего промежуточное место между теми, кто уверенно программирует, и теми, кто в этом отношении стерильно чист. К этой средней наиболее массовой в настоящее время категории читате- лей относятся преподаватели, учащиеся и непрограмми- рующие специалисты. Последние обычно хорошо ориен- тируются в той или иной проблемной области (например, в архитектуре, медицине или организации кинопроизвод- ства), но за редкими исключениями не обладают специ- альными знаниями в области вычислительной техники, математических методов и языков программирования. Следует, однако, заметить, что излагаемые в книге эле- менты программирования скорее просвещают, чем обу- чают, в большей степени вооружая знаниями принци- пиальных возможностей персональных компьютеров, чем прививая навыки работы с ними. Поэтому для полного овладения компьютерным «инструментом» необходимы специальные пособия и длительный опыт. В «Этюдах...» реализован наиболее продуктивный принцип компьютерной педагогики — «учить, играя». К тому же некоторые из предлагаемых игр носят позна- вательный характер, а неигровые реалистические обучаю- щие задачи излагаются не только просто, но и зани- мательно. Ориентация книги на преподавателей и уча- щихся делает оправданным наибольший объем главы, посвященной применению персональных компьютеров в школе. Следующее по объему место в книге отведено компьютерной графике, конструирующей наглядные дисплейные представления промежуточных и конечных результатов человеко-машинного диалога. Предлагая в качестве основного языка программиро- вания (по крайней мере, в период начального освоения персонального компьютера) БЕЙСИК, авторы книги зна- комят нас также с двумя языками программирования более высокого уровня — ФОРТ и ЛОГО. Конечно, этот выбор может быть оспорен, но ни один из альтернатив- ных языков программирования (например, ПАСКАЛЬ, СИ или «старик» ФОРТРАН) защищенным от критики не является. Простота же освоения языков ФОРТ и ЛОГО почти очевидна. К тому же ФОРТ удобен для структурного программирования «снизу вверх» — одной из наиболее проверенных технологий накопления про- грамм для решения каждым специалистом того или иного 6
класса проблемно близких задач, а ЛОГО позволяет сравнительно просто программировать экранные изобра- жения, так необходимые, в частности, архитектору или дизайнеру. Уверен, что «Этюды для персонального компьютера» могут стать первым учителем многих желающих овла- деть если не компьютерной культурой, то хотя бы компьютерной грамотностью. Доктор технических наук И. В, САФОНОВ ПРЕДИСЛОВИЕ Еще каких-то десять лет назад только специалисты знали о том, что в области вычислительной техники воз- никло и бурно развивается новое направление. Никто да- же представить себе не мог, что после значительного уменьшения размеров и последовавшего за этим резкого снижения цен персональные компьютеры приобретут столь широкую популярность, что несколько лет спустя, в 1982 г., американцы в присущей им манере будут изби- рать не «человека года», а «компьютер года». Сегодня персональные компьютеры начинают постепенно прони- кать почти во все области человеческой деятельности. Все больше людей знакомятся с новыми компьютерами в учреждениях, клубах и просто в домашних условиях. Эта книга призвана помочь читателю совершить пер- вые шаги в программировании. Хотелось бы, чтобы он самостоятельно овладел во многом еще загадочным чу- дом новой техники — современной ЭВМ. Сам составил свою первую программу, отладил ее и принял боевое крещение, запустив свое творение на персональном компьютере. Главы книги предлагают идти по пути пер- вооткрывателей: сообщают лишь постановку задачи и ос- новные идеи соответствующей программы и программи- рования. Такой стиль не позволяет уклоняться от сотруд- ничества с книгой, и выбор его вполне понятен: все мы в той или иной мере являемся сторонниками активного обучения математике на решении задач. Надеюсь, что выпуск книги будет способствовать фор- мированию и распространению настоятельно необходи- мой сегодня вычислительной культуры. Янош ШУ РАН И
Глава I ЗНАКОМСТВО С КОМПЬЮТЕРОМ Каталин ФРИД Первая встреча с персональным компьютером может происходить по-разному. Одни садятся за пульт компью- тера после многочасовой теоретической подготовки, имея перед собой заранее написанную на бумаге программу. Другие удивляются рисункам, возникающим, словно по волшебству, на экране, стоит лишь искусной руке на- жать несколько клавиш на пульте, или играют с компью- тером в какую-нибудь игру по введенной в него програм- ме. Третьи начинают свое знакомство с компьютером, штудируя приложенное к нему описание. Во всех случаях любая помощь при овладении компьютерной грамот- ностью окажется нелишней. В этой главе мы попытаемся помочь читателю само- стоятельно овладеть начальной техникой программирова- ния для персонального компьютера, предлагая простые упражнения и игры, не требующие основательной пред- варительной подготовки. Однако следует сразу предупре- дить, что эта глава ни в коей мере не подменяет прила- гаемую к каждому компьютеру инструкцию по его экс- плуатации. ОБ ОСНОВАХ ПРОГРАММИРОВАНИЯ Приступая к написанию программы, проще всего раз- бить ее на структурные единицы (последовательность шагов), которые мы можем сформулировать и выразить на языке компьютера. Представим себе, что, взяв простое нераспространенное предложение, мы затем дополняем его всеми необходимыми подробностями и превращаем в распространенное. При составлении программы мы по- ступаем так же: сначала строим скелет программы, а за- тем наращиваем на него структурные единицы, содержа- щие все, о чем мы собираемся сказать. Это — очень важ- ный принцип, и его всегда следует иметь в виду. Такого 8
рода программирование на основе скелета, или структу- ры программы, получило название структурного про- граммирования. Прежде всего нам необходимо познако- миться с языком компьютера, а затем мы запишем на этом языке несколько игровых программ. МАШИННАЯ ЛОГИКА Включенный компьютер становится «внимательным»: по многу раз в секунду он проверяет, какие клавиши нажаты нами на пульте. Он ждет от нас команд* и «спрашивает», что требуется выполнить. По нажатым кла- вишам компьютер узнает, когда можно начать обработку поступившей информации, что именно требуется сделать и нужно ли вернуть управление. Чтобы информировать обо всем этом компьютер, можно нажать одну из кла- виш RETURN, NEW LINE, CR, BK, ВВОД и т. д., рас- положенных у большинства компьютеров на пулЪте справа. Для единообразия мы будем обозначать все эти клавиши буквой R. ПЕРВЫЕ ШАГИ ВЫДАЧА НА ЭКРАН ДИСПЛЕЯ: ИНСТРУКЦИЯ PRINT Любой персональный компьютер — вычислительная машина, он способен выполнять обычные арифметические операции. Если мы нажали клавиши, соответствующие взятию суммы 5 8, то компьютер произведет сложение (или укажет синтаксическую ошибку, совершенную нами при вводе информации). Но на экране дисплея мы не уви- дим ничего. Чтобы узнать, чему равно 5 + 8, необходимо потребовать от компьютера, чтобы он написал получен- ный результат на экране дисплея. Для этого используется английское слово PRINT (произносится: «принт», означа- * Команда—один из способов управления компьютером, она выполняется (в отличие от инструкции! немедленно. Инструкция лишь указывает на необходимость выполнения той или иной операции и реа- лизуется только после пуска программы. Инструкции могут частично состоять из команд и отличаются от них наличием номера в начале строки. Например, PRINT 4 -R 4 — команда, по выполнению которой на экране дисплея появится цифра 8, а 120 PRINT 4 4~ 4 — инструкция: цифра 8 появится на дисплее лишь после того, как программа будет запущена и дойдет до 120-й строки. Прим, одного из рецензентов венгерского издания Андраша Чабы (А. Ч.). 9
ет (букв.) «напечатай»). После команды PRINT 5 + 8 (не забудьте вернуть управление компьютеру!) на экране дисплея появится результат: число 13. Наряду с арифметическими операциями персональный компьютер умеет делать и многое другое. Он может опери- ровать «переменными» или обрабатывать символьные «тексты». Переменными, или параметрами, называются такие группы знаков, которым мы можем придавать раз- личные значения. В большинстве микрокомпьютеров, использующих язык БЕЙСИК, переменные обозначаются не более чем двумя символами, т. е. буквой, двумя буквами или комбинацией из одной буквы и одной цифры. На значе- ния переменных можно ссылаться, указывая переменную по имени — ее идентификатору. Значением переменной может быть число, но нередко бывает и «слово». Под сло- вом мы понимаем здесь любой упорядоченный набор знаков. Этот набор может состоять из букв или любых знаков, которыми может писать компьютер. Все эти зна- ки называются символами. К числу символов принадле- жат и кавычки. По-английски символьная переменная называется STRING (читается: «стринг», означает (в данном случае) «строка»). Это название указывает на то, что символы упорядочены, т. е. следуют друг за дру- гом в определенном порядке. Мы можем не только записывать численные результа- ты, но и присваивать значения переменным. Пусть I — переменное значение, равное 5 + 8. В языке БЕЙСИК присваивание значения записывается так: LET 1 = 5 + 8 (произносится: «лет», означает «пусть»), при работе на многих компьютерах слово LET можно опустить: 1 = 5 + 8. По команде PRINT 1 на экране дисплея появ- ляется результат. Командой PRINT можно воспользо- ваться и для выдачи на экран дисплея строк. В языке БЕЙСИК символьные и численные переменные различа- ются тем, что имя символьной переменной всегда оканчи- вается специальным знаком $ или Например, А$ = «ХОРОШО». По команде PRINT А$ на экране дисплея появится надпись: ХОРОШО (без точки!). Особую роль среди символов играют кавычки. Ведь одно дело PRINT «ХА» и совсем другое PRINT ХА. В первом случае мы требуем, чтобы на дисплее появилась надпись ХА, а во втором хотим, чтобы компьютер выдал на дисплей значение переменной ХА (если переменная еще не использовалась в программе («свободна»), то ее ю
значение равно 0, в некоторых компьютерах знак 0 ука- зывает на ошибку). Попробуйте, и вы убедитесь в этом сами! В большинстве персональных компьютеров в одну строку * разрешается включать две или даже больше инструкций, но их необходимо разделять двоеточием. Например: PRINT «ХА» : PRINT ХА. Строка, содержащая несколько инструкций, называет- ся строкой инструкций. Может случиться и обратное: нам понадобится задать очень много инструкций или выполнить много раз одну и ту же. Но программа для того и составляется, чтобы компьютер мог запомнить все наши инструкции и нам не требовалось бы вводить их с клавиатуры. КАК ИЗ ИНСТРУКЦИЙ СОСТАВИТЬ ПРОГРАММУ? В языке БЕЙСИК достаточно (и вместе с тем необхо- димо!) писать перед каждой строкой-инструкцией по од- ному числу. Эти числа (номера) одновременно задают и порядок строк. Числа не обязательно должны идти в порядке возрастания (после больших чисел могут идти меньшие). Строки принято нумеровать числами, крат- ными десяти: 10 PRINT «ХА» 20 PRINT ХА Если мы с помощью команды R введем эти строки в компьютер, на дисплее ничего не произойдет, но компью- тер запомнит, что ему следует делать дальше. Если нам понадобится увидеть строки на дисплее, то следует дать команду LIST (произносится «лист»; означает «список»), а для того чтобы запустить программу, т. е. привести ее в действие, мы должны дать команду RUN (произносится * Строка, видимая на экране, может не совпадать со структурны- ми единицами, перерабатываемыми компьютером как отдельные строки. Во всех таких случаях строка начинается с номера и состоит из упорядоченного набора инструкций, каждая из которых отделена от следуй щей точкой с запятой. Длина строки, вообще говоря, ограниче- на. В большинстве компьютеров предпочтение отдается структурным единицам (обрабатываемым как одна строка), состоящим из двух и ш трех строк. — Прим, А. Ч. 11
«ран»; означает (в данном случае) «пуск»). (Не следует путать с командами R!) Запущенная программа выдаст на дисплей ХА и 0, а может быть, и знак ошибки — в зависимости от того, как компьютер обрабатывает переменные. ЕЩЕ: РАЗ ОБ ИНСТРУКЦИИ PRIM Как мы уже знаем, у большинства компьютеров в одной строке могут стоять несколько инструкций. Но PRINT — особая инструкция: две такие инструкции могут стоять в одной строке даже у таких компьютеров, у которых другие инструкции не разрешается записы- вать по две в одну строку. Все, что необходимо для этого знать, заключается в следующем: в записи, задан- ной в форме PRINT... ; обе ближайшие к точке с запя- той инструкции (т. е. инструкции, стоящие перед и после точки с запятой) на дисплее будут записаны подряд, без пробела, причем после запятой достаточно лишь указать то, что требуется записать (не повторяя слово PRINT). Например: PRINT, «ХА»; ХА. Теперь обе последователь- ности символов будут выписаны на дисплее подряд. Если мы хотим, чтобы они были записаны не подряд, а с небольшим разрывом, то вместо точки с запятой следует воспользоваться запятой: PRINT «ХА», ХА. Рас- стояние между словами зависит от компьютера. А что получится, если вместо одной написать две запятые: PRINT «ХА»„ «ХА»? Выясните, сколько запятых нужно написать для того, чтобы результат получился таким же, как в уже встречавшемся нам случае PRINT «ХА»: PRINT ХА*. А что произойдет, если написать подряд два символь- ных слова? PRINT «ХОРОШО»; «ХОРОШО» приводит к результату: ХОРОШОХОРОШО. (Разумеется, и в та- кой записи есть свои преимущества.) Для того чтобы между двумя словами образовался единичный пробел, обычно бывает необходимо вставить пробел: либо специ- альный нижний индекс (PRINT, «ХОРОШО____»; «ХОРО- ШО»), либо особый символ (PRINT «ХОРОШО»; «______»; «ХОРОШО»). * Здесь также остается в силе предыдущее замечание о «свобод- ных» переменных. 12
ПОВТОРИМ ПРОЙДЕННОЕ Пусть А$ принимает в качестве значения имя Тибор Надь и пусть на конце этого имени стоит символ пробела: LET А$ = «Тибор Надь____». Если мы хотим, чтобы имя Тибор Надь было написано на дисплее дважды подряд, то достаточно воспользоваться точкой с запятой: PRINT «ТИБОР НАДЬ»; «ТИБОР НАДЬ». Но попробуем те- перь все же записать две инструкции PRINT не в одной, а в двух строках: 10 LET А$ = «ТИБОР НАДЬ_» 20 PRINT AS 30 PRINT AS Результат получится таким же, как и в случае, когда два слова «ТИБОР НАДЬ»* мы разделили при записи точкой с запятой: ТИБОР НАДЬ ТИБОР НАДЬ. Инструкции выполняются автоматически в порядке, задаваемом номерами строк. Но существуют так назы- ваемые инструкции с передачей управления, нарушаю- щие очередность выполнения инструкций. Такова ин- струкция GOTO (произносится: «гоуту», означает «пе- рейти к ...»). После GOTO должен стоять номер строки, которой передается управление. Если в приведенной выше программе вместо 30-й строки написать GOTO 10, то управление перейдет к 10-й строке, и все повторится сначала. Мы ожидаем, что результат окажется таким же, как и при работе прежней программы (10-я строка присваивает имя ТИБОР НАДЬ переменной А$, 20-я строка выдает А$ на экран дисплея, а 30-я строка вновь возвращает нас к 10-й). Но когда имя ТИБОР НАДЬ появится на экране в третий, четвертый, пятый и т. д. раз и, нако- нец, заполнит весь экран дисплея, нам станет ясно, что в действительности мы замкнули круг: после выдачи имени ТИБОР НАДЬ на экран дисплея управление пере- ходит к 30-й строке, откуда передается к 10-й, после чего имя ТИБОР НАДЬ снова выдается на экран дис- плея и т. д. В зависимости от компьютера прервать бес- конечное хождение по кругу можно по-разному: нажа- * Напомним, что словом называется любая упорядоченная по- следовательность символов из алфавита (полного списка допустимых символов) данного языка. «ТИБОР НАДЬ» — одно слово, а не два слова, как было бы по правилам грамматики.— Прим. пер. 13
тием либо клавиши со знаком ошибки, либо клавиши BREAK (произносится «брейк»; означает «прервать»). После нажатия клавиши компьютер остановится. УСЛОВНАЯ ПЕРЕДАЧА УПРАВЛЕНИЯ Сделаем так, чтобы компьютер сам считал, сколько раз он напишет на экране дисплея ТИБОР НАДЬ, и ос- тановился на тринадцатый раз. В качестве счетчика ис- пользуем переменную I. Пусть ее начальное значение равно 0 и пусть каждый раз, когда компьютер выдаст на экране дисплея А$, значение переменной возрастает на 1, т. е. вместо I получится I -|- 1:LET 1 = 1 + 1. По- скольку переменная I возрастает на единицу всякий раз, когда на экране появляется имя ТИБОР НАДЬ, значения, равного 13, она достигнет, когда переменная А$ будет выдана на экран дисплея в 13-й раз. Если I = 13, то конец. По-английски это «звучит» так: IF 1 = 13 THEN END. Запишем его буква в букву в качестве одной из строк программы. Если же значение переменной I еще не до- стигло 13, то мы вернулись бы к той строке, где оно увеличивается на единицу и где А$ выдается на экран дисплея. (Эти две инструкции потому и записаны в одной строке, что между ними существует логическая последо- вательность. В тех компьютерах, где запись инструкций I = I -|- 1 и PRINT в одной строке невозможна, 30-ю строку разбивают пополам: инструкцию I == I + 1 остав- ляют в 30-й строке, а инструкцию PRINT А$ записыва- ют как 31-ю строку.) Слово LET мы в дальнейшем опу- стим. Итак, мы получили программу: 10 10 1=0 20 А$ = «ТИБОР НАДЬ» 30 1 = 1 + EPRINT А$ 40 IF I = 13 THEN END 50 GOTO 30 цикл В языке БЕЙСИК периодически повторяющиеся ча- сти программы для большей простоты можно записать с помощью так называемой парной инструкции
FOR...TO — NEXT. После FOR следует указать началь- ное значение «переменной цикла», а после инструкции ТО — ее конечное значение: FOR I = 1 ТО 13. (В отличие от предыдущей программы начальное значение I равно здесь единице; в цикле, организованном в предыдущей программе, первый виток делался при 1 = 1.) Строки, следующие за инструкцией FOR...ТО... (так называемое ядро цикла), компьютер выполняет до тех пор, пока не дойдет до инструкции об окончании цикла NEXT I (произносится «некст»; означает «следующее» I, т. е. следующее за конечным значением в цикле значе- ние переменной I). Итак, у нас получилась программа: 10 А$ = «ТИБОР НАДЬ» 20 FOR 1 = 1 ТО 13 30 PRINT А$ 40 NEXT I Действие этой программы приводит к такому же результату, как и программы, приведенной в конце раз- дела об условной передаче управления. Единственное от- личие состоит в том, что по выходе из программы значе- ние I теперь равно 14, в чем мы можем убедиться с по- мощью инструкции PRINT I. Предыдущая программа при значении I больше 13 прекращает работу, поэтому по окончании ее 1=13. Структуры двух приведенных нами программ не оди- наковы. Во второй программе инструкция NEXT I уве- личивает значение I, а инструкция FOR проверяет, не достигла ли переменная цикла своего верхнего предела. Если нет, то управление передается следующей строке (30-й инструкции). (Впрочем, инструкция FOR сравни- вает текущее значение переменной I не в 20-й, а в 40-й строке. В этом вы можете убедиться с помощью инструкции TRC или TRON*.) Итак, циклу соответству- ет следующая структура программы: 10 А$ = «ТИБОР НАДЬ» 20 I = 1 30 PRINT А$ 40 1 = 1+ 1:IF 1<= 13 THEN GOTO 20 * TRC (аббревиатура от англ. TRACE — прослеживать) — инст- рукция, осуществляющая распечатку последовательности работы программы. TRON — разновидность инструкции TRC, используемая в некоторых компьютерах.— Прим. пер. 15
Если при составлении программы заранее не известно, каково значение А$, т. е. оно оставлено «на потом», на усмотрение того, кто его использует, то необходимо обратиться к инструкции INPUT. Таким образом, вво- дить как численные, так и символьные данные (и при- сваивать их соответствующим переменным) можно и «на ходу», когда программа уже работает. Действие инструкции INPUT (произносится «инпут»; означает «ввести») на программу сводится к следующе- му: выполнение программы приостанавливается в ожида- нии вводимых данных (ввод считается законченным пос- ле нажатия клавиши R), введенное значение присваива- ется стоящей после INPUT переменной, после чего дейст- вие программы возобновляется с того места, где оно бы- ло прервано: 10 INPUT А$ 20 FOR 1 = 1 ТО 13 30 PRINT А$ 40 NEXT 1 Теперь можно указать (во второй инструкции INPUT), сколько раз следует выписать данный текст: 10 INPUT А$ 1£ INPUT N 20 FOR 1 = 1 ТО N 30 PRINT А$ 40 NEXT I Работать с такой программой неудобно, поскольку мы не знаем, ни какой текст появится на экране дисплея, ни сколько раз он будет выписан. Поэтому перед ин- струкцией INPUT лучше указывать, какие данные необ- ходимы. С учетом этого пожелания первые две строки приведенной выше программы можно модифицировать так: 10 PRINT «КАКОЕ СЛОВО?»: INPUT А$ 20 PRINT «СКОЛЬКО РАЗ ВЫПИСАТЬ?:»: INPUT N ИГРЫ СО СЛОВАМИ СИМВОЛЬНЫЕ ПЕРЕМЕННЫЕ Опробуем следующую программу: 10 А$ =«ТЯНИ» 16
20 В $ = «ТОЛКАЙ» Зф PRINT А$ + В$ Нетрудно убедиться в том, что компьютер действи- тельно производит сложение слов, т. е. составляет из двух слов — «слагаемых» одно слово — «сумму». Сложе- ние — единственная из арифметических операций, кото- рую можно производить над символьными переменными. Что же касается вычитания символьных слов, то его заменяет инструкция, которая позволяет отрезать от сло- ва столько последних символов, сколько нам нужно (но, разумеется, не больше, чем во всем слове) *. Говоря о последних символах, мы имеем в виду сим- волы, стоящие в слове справа. RIGHT означает по- английски «правый» (произносится «райт»). В языке БЕЙСИК RIGHTS (А$, N) означает: N последних, т. е. стоящих справа, символов в слове А$. LEFT по-англий- ски означает «левый» (произносится «лефт»). В языке БЕЙСИК LEFTS (А$, N) означает: N стоящих слева, т. е. первых, символов в слове А$. Мы можем не только отрезать «хвост» слова, но и извлечь его середину. Если из середины слова А$ необходимо извлечь N символов, начиная с К-го, то следует задать MIDS (A$,K,N) **. В некоторых компьютерах предусмотрена лишь одна ин- струкция AS (К ТО N), позволяющая выделять из слова А$ символы от К-го до N-ro. Длина слова А$ во всех компьютерах обозначается LEN (А$) ***. Это обозна- чение позволяет указывать N первых и N последних символов в слове А$ так: А$(ТО N) и A$(LEN(A$) — — N+1TO). Мы будем пользоваться обозначением MID. ПОСТРОЕНИЕ СЛОВ Используя приведенные выше обозначения, попробуем составить программу, описывающую игру, в которую многие охотно играли в детстве: * Следует учитывать, что множества реализованных функций об- работки символов для разных компьютеров могут различаться. — Прим, ред. ** MID - - сокращенно от англ. MIDDLE — середина,— Прим. пер. *** LEN — сокращенно от англ. LENGTH — длина.— Прим. пер. 17
ы лы УЛЫ КУЛЫ И КУЛЫ НИ КУЛЫ АНИ КУЛЫ КАНИКУЛЫ 10 А$ = «КАНИКУЛЫ» 20 FOR I = 1 ТО LEN (А$) 30 PRINT RIGHTS (А$, I) 40 NEXT I Если мы хотим, чтобы все поместилось в центре эк- рана, то перед тем, как начать выписывать букву за бук- вой задуманное слово, следует поместить несколько зна- ков пробела: 30 PRINT «», RIGHT$(A$,I) Теперь уже нетрудно составить программу, которая с помощью инструкции INPUT затребует задуманное слово (неизвестное заранее значение символьной пере- менной А$), а затем буква за буквой выпишет его от конца к началу: 10 INPUT А$ 20 FOR I = 1 ТО LEN (А$) 30 PRINT MID$(A$, LEN(A$) + 1—I, 1) 40 NEXT I Строить слова можно не только справа налево, как это мы сделали со словом КАНИКУЛЫ, но и слева на- право. В игре, известной под названием «пирамида из слов», требуется найти такие слова, у которых несколько первых букв уже образуют осмысленное слово, а если пристроить к ним другое осмысленное слово, то вся груп- па букв вместе образует третье осмысленное слово. Условиям игры в пирамиду из слов удовлетворяет, на- пример, слово ДОКТОР (ДОК и ТОР). 10 А$ =« ДОКТОР» 20 FOR 1 = 1 ТО 6 30 PRINT, LEFTS!А$, I) 40 NEXT I Для построения «усеченной пирамиды» начнем выда- чу на дисплей слова КОЛБА сразу с двух букв: 18
10 А$ = «КОЛБА» 20 FOR I == 2 ТО 5 30 PRINT LEFTS (A$,I) 40 NEXT I КОДИРОВАНИЕ В описание компьютера среди прочего входит так на- зываемая кодовая таблица. Из нее мы узнаем, под ка- кими кодами «скрыты» различные символы. Например, букве А в большинстве случаев соответствует 65-й кодовый знак, а букве Z — 90-й. Остальные буквы английского алфавита поставлены в соответствие кодо- вым знакам, заключенным между 65-м и 90-м (по порядку): буква В—66-му кодовому знаку, буква С— 67-му и т. д. Этих знаний вполне достаточно для того, чтобы мы могли заняться тайнописью. Имеются две воз- можности. Первая из них состоит в том, чтобы просто заменить буквы их кодами, т. е. выписать в алфавитном порядке перечень чисел, поставленных в соответствие каждой из букв. Вторая возможность немного сложнее. Рассмотрим коды букв в алфавитном порядке и, напри- мер, увеличим все коды на единицу. Пробелы и в том, и в другом случаях обычно опускаются. Следует знать, что кодовый знак выдает функция ASC (в некоторых компьютерах CODE) —указывает в зави- симости от обрабатываемого текста соответствующий код. Например, ASC («А») == 65. В большинстве случаев функция ASC может выдавать коды не только отдельных символов («букв»), но и более длинных слов. Мы можем записывать слова любой длины, но ASC указывает код лишь первого символа, с которого начинается слово. Функцией, обратной функции ASC, является CHRS, кото- рая указывает, какой символ соответствует любому из кодовых знаков от 0-го до 255-го. Например, CHR$(67) =С. Таким образом, 1-й символ в слове А$ имеет код ASC (MID$(A$, I, 1)), а на единицу больший код соот- ветствует символу CHRS (ASC(MID$ (А$, I, 1)) + 1)« Зная все это, нетрудно составить нашу первую програм- му для кодирования: 10 PRINT «КАКОЕ CJIC)BO?»:INPUT А$ 20 FOR 1=1 ТО LEN(A$) 30 IF MID$(A$, I, 1) = » THEN GOTO 50 19
40 PRINT ASC (MID$(A$, I, 1); GOTO 60 50 PRINT 60 NEXT I. To же самое, но проще, выполняет программа: 10 PRINT «КАКОЕ СЛОВО?»: INPUT А$ 20 FOR I = 1 ТО LEN (А$) 30 IF MID$ (А$, I, 1) =«_» THEN PRINT «_»; : GOTO 50 40 PRINT ASC (MID$ (A$, I, 1); 50 NEXT I Программу, соответствующую второму, более сложно- му варианту кодирования, мы получим, заменив в лю- бой из двух приведенных программ (какая больше нра- вится) ASC(MID$(A$, I, 1) на CHR$ (ASC(MID$ (А$, I, 1)) + 1). птичий язык Овладев секретами кодирования, самое время занять- ся тайным говором: птичьим языком. (Вы ведь хотели бы научиться говорить по-птичьи?) Правило простое: если встречается гласная, то мы добавляем к ней букву В, после чего повторяем ту же гласную еще раз. Напри- мер, из «А» получается «АВА». Следовательно, програм- ма, осуществляющая перевод с обычного языка на «пти- чий», по существу, сводится к проверке того, есть ли в обрабатываемом слове гласные. Анализируемые сим- волы поступают по очереди (в том порядке, в каком они встречаются в слове) в В$. 10 PRINT «КАКОЕ СЛОВО?»: INPUT А$ 20 FOR I = ITO LEN (А$) 30 В$ = MID$ (А$, I, 1):PRINTB$ 40 IF В$ = «А» OR В$ = «Е» OR B$ = «Е» OR В$ = «И» OR В$ = «О» OR В$ = «У» OR В$ = «Э» OR В$ = «Ы» OR В$ = «Ю» OR В$ — «Я» THEN PRINT «В»; В$ 50 NEXT I Интересную и не очень трудную задачу — составить программу, которая осуществляла бы обратный «перевод» с птичьего языка, мы предоставляем читателю. 20
В трех последних программах было бы лучше, если бы кодируемое слово исчезало до того, как оно появится на экране дисплея в закодированном виде. Для этой цели во многих компьютерах предусмотрен специальный символ (например, код 12), стирающий при выдаче на дисплей предшествующую запись. Таким образом, инструкция PRINT CHR$(12) стирает с экрана дисплея все, что на нем было записано. В других компьютерах проще вос- пользоваться инструкцией CLS(CLear Screen = очистить экран дисплея). Ее можно вписать 15-й строкой. УЗОРЫ Последняя из игр с инструкцией PRINT — кодиро- вание символьных слов графическими знаками. Поставим в соответствие каждой букве некий графический знак из имеющегося запаса символов. Не обязательно, но хоро- шо, чтобы различным буквам соответствовали различные знаки. Ведь теперь наша цель состоит не в том, чтобы закодировать текст (подлежащий последующему декоди- рованию), а в том, чтобы составить с помощью графичес- ких знаков узор. В большинстве компьютеров достаточно сдвинуть коды букв алфавита на какую-то величину, чтобы преобразовать все буквы в графические знаки. Например, если коды букв алфавита начинаются с 65-го, а коды графических знаков — с 200-го, то к кодам алфавита достаточно прибавить 135. Если так просто не получает- ся из-за того, что графических знаков меньше, чем букв алфавита, то можно воспользоваться не сдвигом, а каким- нибудь простым соответствием, подходящим для нашей цели. Графическую программу мы получим из второй прог- раммы, предназначенной для кодирования текста. На этот раз ASC(MID$, (А$ I, 1)) нам придется увеличить не на единицу, а, например, на 135, или подвергнуть какому- нибудь простому преобразованию. Перекодировать в узоры можно не только текст, но и числа, например, магические* или латинские квадраты. Латинский квадрат обладает следующим отличительным * Магический квадрат — таблица, имеющая одинаковое число клеток по вертикали и горизонтали. Числа, вписанные в клетки, обладают следующим («магическим») свойством: суммы чисел, сто- ящих в клетках любых горизонтальных и вертикальных рядов, а также на главной и побочной диагоналях, равны одному и тому же числу — 21
свойством (для конкретности мы будем говорить о квадра- те 6-го порядка — размером 6X6 клеток): каждое из пер- вых шести натуральных чисел берется в шести экземпля- рах и вписывается в клетки квадрата так, чтобы в каждой строке и в каждом столбце оно встречалось ровно по одно- му разу. Вот, например, один из латинских квадратов 6-го по- рядка: 1 2 3 4 5 6 6 1 2 3 4 5 5 6 1 2 3 4 4 5 6 1 2 3 3 4 5 6 1 2 2 3 4 5 6 1 Пусть эти 6X6 чисел хранятся в А$ в таком порядке, в каком они бы встретились нам, если бы мы стали счи- тывать их по порядку строка за строкой: А$ = = «1234566123455612344 56123345612234561». Разложим А$ в «двойной цикл». Пусть переменная I нумерует строки, а переменная J — числа в I-м столбце. Обе переменные принимают значения от 1 до 6. J-й элемент I-й строки расположен в А$ на ((I—1) >(< 6 + J)-m месте, поскольку, прежде чем мы окажемся в I-й строке, нам придется пройти (I — 1) полных строк по 6 чисел в каждой, т. е. все- го (I — 1) >|< 6 чисел, а в I-й строке мы ищем J-й элемент. Для того чтобы выписать подряд 6 знаков, необходимо воспользоваться инструкцией типа PRINT. Затем мы нач- нем новую строку. Действие точки запятой в последней инструкции PRINT мы можем нейтрализовать, записав «пустую» инструкцию PRINT, после которой не указано никакой переменной. Она нужна лишь для того, чтобы начать новую строку. Наша программа (в предположении, что разность между кодами цифр и графических знаков равна 152) имеет следующий вид: так называемой магической постоянной квадрата. Например, для магического квадрата 7 12 1 14 2 13 8 11 16 3 10 5 9 6 15 4 постоянная равна 34. Что такое латинский квадрат, объясняется в тексте.— Прим. пер. 22
10 PRINT CHR$ (12) : A$ = «123456612345561234456123 345612234561» 20 FOR 1 = 1 TO 6 30 FOR J = 1 TO 6 40 N= (I—1) * 6 + J 50 PRINT CHR$ (ASC(MID$ (A$, N, 1)) + 152); 60 NEXT J 70 PRINT 80 NEXT I Аналогичным образом можно построить и «случайный узор». Например (рис. 1)*: 10 PRINT CHR$(12): 20 PRINT CHR$(RND(20 + 180); 30 GOTO 20 Используя в программе латинский квадрат 6x6, мы получим развернутый рисунок — наш узор. Данные можно хранить с помощью инструкции DATA (DATA означает по-английски «данные»). Прочитать их «на ходу», т. е. * О функции RND мы расскажем подробнее в разделе «Вероятность» гл. III и в разделе «Случайные элементы» гл. II. RND(X) —от англ. RANDOMIZE — рандомизировать, придавать случайный характер — генератор, порождающий при целом X =# 1 случайным образом целое число, заключенное между 0 и X, а при X = 1 — вещественное число, заключенное между 0 и [. Прим. пер. 23
по ходу действия программы, можно с помощью инструк- ции READ (произносится «рид»; означает «читай»). Прог- рамма может иметь следующий вид: 10 PRINT CHR$(12); :DATA «123456», «612345», «561234», «456123», «345612», «234561» 20 FOR 1 = 1 TO 6 30 READ A$ 40 FOR J = 1 TO 6 50 PRINT CHR$ (ASC(MID$ (A$, J, I)) + 152); 60 NEXT J 70 PRINT 80 NEXT I Инструкция DATA, как принято говорить, «не принад- лежит языку БЕЙСИК». Это означает, что в программе она может находиться где угодно. Например, в приведен- ной выше программе мы могли бы поместить DATA в 90-й строке. По инструкции READ компьютер проходит шаг за шагом всю строку DATA и считывает все содержа- щиеся в ней значения. Если бы возникла необходимость в повторном использовании данных, хранящихся в строке DATA, то нам пришлось бы обращаться к инструкции RESTORE (произносится «ристор»; означает «восстано- вить»). После слова RESTORE необходимо указать номер строки с инструкцией DATA. Следует внимательно прове- рить, какие данные нам требуется считывать повторно. Если, например, в приведенной только что программе мы вставим в качестве 35-й строки инструкцию RESTORE, то компьютер считает только «123456», а если бы переписа- ли программу до конца и с помощью инструкции GOTO 10 устроили бесконечный цикл, то в нашем распоряжении оказались бы все данные. ЗАГЛЯНЕМ В ПАМЯТЬ КОМПЬЮТЕРА! Заглянуть в память компьютера нам поможет ин- струкция РЕЕК (произносится «пик»; означает «загля- нуть, бросить взгляд») — несколько сложноватая, но весьма интересная функция. С ней тесно связана ин- струкция РОКЕ (произносится «поук»; означает «втол- кнуть») *. * Следует напомнить, что непосредственной записью в память компьютера надо пользоваться ( осторожностью, чтобы не разрушить всю систему.—Прим. ред. 24
Как именно, в каком порядке перенумерованы ячейки памяти, зависит от компьютера. В каждой ячейке (поме- ченной адресом) находится число, заключенное между О и 255. (Числа являются носителем информации в ком- пьютере.) Инструкция PRINT РЕЕК (10000) позволяет «заглянуть» в 10000-ю ячейку и выдает ее содержимое на дисплей. Инструкция РОКЕ 10000,65 «вталкивает» в 10000-ю ячейку содержимое 65-й ячейки. Эти две ин- струкции таят в себе поистине безграничные возмож- ности. По существу, они позволяют нам распоряжаться памятью компьютера по своему усмотрению. Например, они позволяют нам при желании подшутить над компью- тером: если известно, где хранится программа, то мы можем сделать так, что после одной из строк программы окажется строка с гораздо меньшим номером. Пусть исходная программа имеет следующий вид: 10 PRINT «ЭТО ДЕСЯТАЯ СТРОКА» 20 PRINT «А ЭТО ДВАДЦАТАЯ СТРОКА» Прежде всего по прилагаемой к компьютеру карте памяти выясним, где расположены ячейки, в которых хранится программа, с помощью команды PRINT РЕЕК установим содержимое каждой из них и, в частности, узнаем, где хранится номер 20-й ячейки, после чего (разумеется, с помощью команды РОКЕ) заменим число 20, например, на 1. В результате такой «подстановки» наша программа будет выглядеть так: 10 PRINT «ЭТО ДЕСЯТАЯ СТРОКА» 1 PRINT «А ЭТО ДВАДЦАТАЯ СТРОКА» Такая программа могла бы действовать, но 1-ю стро- ку нельзя было бы ни стереть, ни исправить. Мы можем написать другую 1-ю строку, даже новую 20-ю строку. Глава II ГРАФИКА Янош КЕПЕШ ВВЕДЕНИЕ В большинстве персональных компьютеров результа- ты, полученные в процессе работы программы, выводят- ся на экран дисплея. На нем появляются числа, слова, 25
относящиеся к введенным в компьютер данным, табли- цы и графики, которые можно использовать в различ- ных играх,— словом, много такого, что можно было бы использовать «не по назначению», а для других целей. Разве нельзя было бы заняться ради интереса построе- нием различных «картинок» на дисплее — ведь они так красивы? Можно! Соединенные с большими ЭВМ печа- тающие устройства и графопостроители уже давно ис- пользуются для создания компьютерной графики. Воз- никло даже особое направление, которое получило на- звание «компьютерного искусства». Некоторые персональные компьютеры открывают пе- ред графикой еще более широкие возможности, чем тра- диционные ЭВМ с их периферийным оборудованием: персональные компьютеры позволяют создавать на дис- плее многоцветные изображения с тонко проработанными деталями и движущиеся картины. В этой главе речь пойдет о графических программах для персональных компьютеров. В первой части мы рас- скажем о технике составления графических программ, сообщим необходимые для этого основные сведения и затронем некоторые более тонкие вопросы. Во второй части интересующиеся смогут ознакомиться с нескольки- ми конкретными примерами нестандартных графических программ. На протяжении всей первой части мы, по су- ществу, не выходим за рамки тех элементарных сведе- ний по программированию, которые были изложены в главе I. Во второй части мы немного поупражняемся в практическом составлении графических программ (для чего нам, возможно, понадобится кое в чем дополнить то, о чем говорилось в первой части). Те из читателей, кто при изучении этой главы проделают вместе с нами все графические упражнения, скорее приобретут и некоторый практический опыт программирования. Вместе с тем на- ши советы призваны помочь читателям научиться само- стоятельно составлять графические программы в соответ- ствии со своим вкусом и фантазией. Создание таких программ представляет интерес в несколько ином плане, чем широко известные языковые и логические игры, проводимые в диалоге с компьютером. В графических программах большее значение имеет не результат, а умение импровизировать и находить новые вариации. Если мы видоизменяем уже готовую «картину», то для переделки остается не так уже много возмож- 26
ностей — ровно столько, чтобы новое изображение не ут- ратило красоты и привлекательности. Такая экономия труда вполне понятна: ведь мы изрядно потрудились над созданием оригинала, а кто хорошо потрудился, мо- жет и отдохнуть. Разумеется, не велико удовольствие от программы, которая все время делает одно и то же, например, рисует одну и ту же картинку. Именно поэтому мы познакомим читателя с различными способами, позволяющими раз- нообразить программу изменениями отчасти случайными, отчасти умышленными. Еще более интересные программы получаются, если, придумывая различные вариации, при- держиваться единой схемы и отбирать лишь наиболее удачные, приводящие к самым красивым изображениям. Все приводимые ниже программы написаны на языке БЕЙСИК. К сожалению, различные компьютеры «гово- рят» на несколько отличающихся друг от друга «диалек- тах» БЕЙСИКа, причем наибольшие расхождения при- ходятся на долю графических инструкций. Мы не ста- вим перед собой цель снабдить читателя готовыми прог- раммами. Мы стремимся пробудить у него интерес к со- ставлению графических программ и вооружить началь- ными знаниями средств и методов, позволяющих гра- мотно эксплуатировать свой персональный компьютер и не бояться перехода на компьютеры других типов, в том числе и незнакомых. Итак, мы начинаем! ЭКРАН ДИСПЛЕЯ Каждый персональный компьютер позволяет выводить на экран дисплея символы (буквы, цифры, знаки препи- нания и математических действий, некоторые специаль- ные знаки). Запустив следующую краткую программу: 10 PRINT «А»; 20 GOTO 10, мы увидим, что весь экран покроется буквами «А», вы- строенными в правильные ровные строки и столбцы. Подсчитав число строк и столбцов, мы узнаем, сколько символов вмещает экран дисплея. Каждому символу в памяти отведена определенная ячейка, или 1 байт (т. е. 8 двоичных разрядов). В каждой такой ячейке хранится код. Общее число кодов, которые могут быть записаны в одной ячейке объемом 1 байт, равно 28 = 256. (Разу- 27
меется, далеко не все коды соответствуют различным символам — например, значительная часть кодов означа- ет символ «?».) Что именно будет на экране дисплея, зависит от того, что хранится в отведенном экрану участке памяти, состо- ящем из расположенных подряд ячеек объемом в 1 байт. Если известен адрес (номер) байта, с которого начинает- ся в памяти участок экрана, то нетрудно подсчитать ад- рес байта, стоящего, например, на 20-м месте в 5-м столбце. Например, если первый байт экрана дисплея имеет адрес 15360, то, прибавив к этому числу 4X64 + + 19 = 275, мы получим 15635. Воспользовавшись ин- струкцией РОКЕ 15635,65, мы впишем в ячейку с поряд- ковым номером (адресом) 15635 код 65. Следовательно, на 20-м месте в 5-й строке на дисплее появится буква «А» (соответствующая коду 65). Если же нам понадо- бится узнать код символа, который хранится в ячейке с адресом 15635, то следует воспользоваться инструк- цией РЕЕК (15635): значение этой функции выдает код символа, адрес которого указан в качестве ее аргумента. Инструкции РОКЕ и РЕЕК позволяют вносить из- менения и считывать содержимое любого байта памяти (а не только байтов, отведенных экрану дисплея) *. Впи- сать нужный символ в нужное место на дисплее можно и проще. Инструкция PRINT AT i, j; позволяет вписать нуж- ный символ на пересечении /-й строки и /-го столбца. В дальнейшем при обсуждении способа графическо- го изображения символов мы всегда будем иметь в виду такую конструкцию дисплея (разбиение экрана на строки и столбцы) и такие инструкции и команды, о которых шла речь в этой части. * Разумеется, речь идет лишь о тех участках памяти, в которые данные могут вводиться и из которых они могут извлекаться (так назы- ваемая оперативная память — RAM). Но существуют и другие участки памяти (так называемая внутренняя память — ROM), содержимое которых, записанное на языке БЕЙСИК, можно считывать, но нельзя изменять. Наконец, существуют и такие участки памяти, содержимое которых можно изменять, но при обращении к ним с помощью команды или инструкции РЕЕК мы неизменно получили бы на экране дисплея 0. В такие участки информацию можно вписывать, но извлекать ее из них невозможно.— Прим. А. Ч. 28
ТОНКОЕ РАЗБИЕНИЕ ЭКРАНА ДИСПЛЕЯ Во многих персональных компьютерах экран дисплея разбит на очень большое количество точек, что позволя- ет составлять из них изображения с хорошо прорабо- танными мелкими деталями. Для тонкого разбиения экрана дисплея используют- ся специальные инструкции, зависящие, вообще говоря, от выбора компьютера. С помощью одной-единственной инструкции можно, например, начертить на экране отре- зок прямой, выходящей из заданной точки и заканчиваю- щейся в точке, отстоящей от исходной на заданное рас- стояние по горизонтали и вертикали. Так, по инструкции DRAW 15,—40 мы проведем отрезок, соединяющий по- следнюю из поставленных компьютером точек с точкой, отстоящей от нее на 15 единиц вправо и на 40 единиц вниз. В качестве третьего параметра можно задать угол в радианной мере. Тогда компьютер вычертит на экране дугу окружности с заданными концами, стягивающую заданный центральный угол (начальную точку необхо- димо задать с помощью инструкции PLOT). Так, ин- струкция DRAW 150, — 40, если ее предварить инструкци- ей PLOT 50, 100, позволит вычертить на экране дугу окружности, а инструкция CIRCLE — описать окруж- ность заданного радиуса вокруг точки с двумя заданны- Р LOT 50, 100 DRAW 150,-40,-.52 CIRCLE 160,128,40 Рис. 2 29
ми координатами (например, CIRCLE 160, 128, 40 задает окружность радиуса 40 единиц с центром в точке (160, 128)) (рис. 2). Разумеется, по инструкциям DRAW и CIRCLE и от- резок прямой, и окружность будут изображены не точно, а лишь приближенно: и в том, и в другом случае компьютер «постарается» построить требуемые линии из 256 X 176 квадратных «точек», на которые разбит экран. Но если начало и конец отрезка расположены не слиш- ком близко или если радиус окружности не слишком мал, то ошибка в построении отрезка и окружности почти не ощутима и, как мы увидим в дальнейшем, еще менее ощутима мелкая структура изображения при составлении графических программ. ЭЛЕМЕНТЫ ИЗОБРАЖЕНИЯ точки Точками мы будем называть маленькие квадраты, появляющиеся на экране по инструкции PLOT или SET в зависимости от типа компьютера*. Как известно, изме- няя координаты точек, заданных в инструкции PLOT, мы можем перемещать точки по экрану. Это весьма существенно с точки зрения графических программ, так как большинство рисунков состоит из точек. Нарисуем точку на экране с координатами (25, 21): 10 PLOT 25,21 Выполним затем инструкцию 20 PLOT 35,21 Она выбрана так, чтобы вторая точка располагалась на 10 единиц правее первой. На языке координат это соответствует тому, что первая координата (возрастаю- щая при движении по горизонтали слева направо) вто- рой точки на 10 больше, чем координата первой точки. Если бы в 20-й инструкции первая координата осталась * В других компьютерах поставить точку на экране можно с по- мощью инструкций SET(X,Y), DOT(X,Y), SETDOT(X,Y). В большин- стве персональных компьютеров X означает номер строки (отсчиты- ваемый от 0 и сверху вниз), a Y — номер столбца (отсчитывае- мый от 0 и слева направо), на пересечении которых требуется поста- вить точку. Прим. А. Ч. 30
такой же, как у первой точки, а вторая координата, например, уменьшалась бы на 7, т. е. если бы 20-я инструкция имела вид 20 PLOT 25,14, то вторая точка оказалась бы ниже первой на 7 еди- ниц (вторая координата задает положение точки по вертикали). Варьируя координаты, мы можем перемещать точки не только по горизонтали и вертикали, но и в любом направлении: 3 6 10 20 INPUT А INPUT В PLOT 25,21 PLOT 25 + А,21 + В В начале этой программы мы задаем величину перемещений А по горизонтали и В по вертикали. Поло- жительные значения А соответствуют сдвигу вправо, отрицательные — влево, положительные значения В соот- ветствуют сдвигу вверх, отрицательные — вниз. Величина перемещения определяется абсолютными значениями А и В (рис. 3). Расстояние между точками можно растягивать и сжи- мать. Для этого необходимо указать центр преобразова- А=20 В=6 Рис. 3 31
ния подобий и коэффициент сжатия или растяжения. Предположим, что за центр преобразования подобия выбрана уже встречавшаяся нам точка (25, 21). Введем коэффициент преобразования подобия координаты то- чек А и В (рис. 4): А«35 В=26 С=2-5 РиС 4 2 INPUT С 3 INPUT А 6 INPUT В 10 PLOT А, В 20 PLOT 25 +С * (А—25), 21 +С * (В—21) Если выбрать С = 2, то программа выдаст точку, от- стоящую от центра вдвое дальше, чем исходная. При С — 0,5 исходная точка окажется на половине расстояния от центра, а при С = —1 перейдет в точку, симметричную относительно центра. Если в 20-й инструкции изменить лишь одну из коор- динат точки (А, В), то мы получим растяжение или сжатие относительно горизонтальной или вертикальной оси, проходящей через центр. Коэффициент С = —1 соот- ветствует в этом случае зеркальному отражению относи- тельно горизонтальной или вертикальной оси. Заданную точку можно повернуть на прямой угол вокруг центра следующим образом: 32
3 INPUT A 6 INPUT В 10 PLOT A,В 20 PLOT 25+ (B—21), 21— (A—25) или в противоположном направлении 20 PLOT 25— (В—21),21 + (А 25) Таким образом, координаты новой точки мы получим, прибавив к первой координате центра разность вторых координат заданной точки и центра, а по второй коорди- нате центра — разность первых координат заданной точ- ки и центра (предварительно изменив знак одной из разностей) (рис. 5). А=27 В=39 Рис. 5 Если точку требуется повернуть вокруг центра (про- тив часовой стрелки) на произвольный угол Т, то вы- полнить такой поворот можно с помощью следующей программы: 3 LET С = COS Т 6 LET S = SIN Т 10 INPUT А 20 INPUT В 25 PLOT А,В 30 PLOT 25 + С * (А—25) — S* (В—21), 21 + S * (А—25) + С * (В—21) зз
А«35 В«11 Рис. 6 На рис. 6 изображен поворот точки вокруг центра на 30°. Сложные выражения, входящие в инструкцию PLOT, можно интерпретировать как известные из курса средней школы формулы сложения синуса и косинуса. Однако, действуя по аналогии с приведенным нами примером, точку вокруг центра можно поворачивать, не интересуясь тем, как именно действует программа. НЕ ВЫХОДИТЬ ЗА ГРАНИЦЫ ЭКРАНА! Иногда при попытках отодвинуть одну точку от дру- гой, получить проекцию какой-нибудь точки или повер- нуть ее вокруг заданного центра может случиться так, что компьютер выдаст на экран дисплея знак ошиб- ки: вычисленные координаты новой точки окажутся за пределами экрана. Присмотревшись внимательнее, мы обнаружим, что при выходе точки за пределы экрана вверх или вправо компьютер выдает сообщение об ошиб- ке, а при выходе влево или вниз — «отражает» точку, заменяя ее значения координат их абсолютными вели- чинами. Об этом не следует никогда забывать при со- ставлении графических программ и вводить в них соот- ветствующие «предохранители», или «защитные устрой- ства». 34
Если точку на экране «ставит» инструкция вида PLOT выражение \, выражениеъ, то вместо нее целесооб- разнее написать сначала инструкцию LET Х = выраже- ние\ и LET X = выражение2, и лишь после проверки значений X и Y написать инструкцию PLOT X,Y. Проще всего проверить, не выходят ли значения X и Y за до- пустимые пределы, и лишь затем приступать к выпол- нению инструкции PLOT, т. е. действовать следующим образом: IF 0< = Х AND Х< = 63 AND 0< = Y AND Y<==43 THEN PLOT X,Y Точку, ускользнувшую с экрана через правую грани- цу, можно вернуть через левую границу, а «провалив- шуюся» вниз — через верхнюю границу и соответственно точку, оказавшуюся за правой границей,— через левую границу, а «взмывшую» над верхней границей — через нижнюю границу, рассматривая вместо значений коорди- наты X лишь остатки от деления их на 64, а вместо значений координаты Y — остатки от деления их на 44, т.е.: LET X - X — 64 * INT (Х/64) LET Y = Y—64 * INT (Y/44) Тогда X автоматически будет принимать значение от 0 до 63, a Y — от 0 до 43, и инструкцию PLOT X, Y можно бу- дет записывать без предварительной проверки (рис. 7). 35
Можно сделать так, что точка, выбрасываемая за пределы экрана, остается на той границе, через которую она «намеревалась» ускользнуть. Для этого можно вос- пользоваться следующим «предохранителем»: X * (0 < X AND X < 64) + 63 * (X > 63) У $ (0 < Y AND У <44) + 44 * (У > 44) Выражения в скобках, как и раньше, принимают зна- чения + 1 или 0 в зависимости от того, выполняются или нет стоящие в них отношения (=, <, <= и т. д.). Сле- довательно, после преобразования значение X окажется равным 0, если до преобразования оно было меньше О, и станет равным 63, если было больше 63, а все осталь- ные значения X (от 0 до 63) останутся неизменными. Аналогичным образом ведут себя при указанном преоб- разовании значения У. Таким образом, наш «предохрани- тель» позволяет пользоваться инструкцией PLOT без предварительной проверки значений X и У. ПОСТРОЕНИЕ ГРАФИКОВ ФУНКЦИЙ Персональные компьютеры позволяют с помощью од- ной-единственной инструкции вычислять значения неко- торых «вмонтированных» функций (SIN, COS, TAN, LOG, EXP, SQR и т. д.), а с помощью DEF FN нахо- дить значения и других задаваемых программистом функций. Графические инструкции позволяют выводить эти функции на экран в виде кривых, или графиков. График функции состоит из точек с координатами (X, 1(х)).Ясно, что такую кривую можно построить с по- мощью инструкции PLOT. Однако для большинства функций столь простое решение задачи приводит к разо- чаровывающим результатам. Например, если мы попы- таемся изобразить график функции SIN на экране дис- плея персонального компьютера с помощью программы* 100 FOR Х = 0 ТО 255 110 PLOT X, SIN X 120 NEXT X то в самом низу экрана получим штриховую кривую, которая к тому же из-за отражения будет графиком функции не sinx, a |sinx|. Кроме того, и самих волн * Для экрана с разрешением 250 точек по горизонтали.— Прим. ред. 36
на экране уместится слишком мало, и ничего хорошего не будет в том, что располагаются они так низко. Учиты- вая все это, график синуса следует сдвинуть вверх и рас- тянуть по вертикали и горизонтали. Если желательно, например, поднять синусоиду до горизонтальной оси экрана, растянув ее по вертикали и горизонтали в 50 раз, то мы можем воспользоваться 110-й инструкцией: 110 PLOT X, 88 + 50 * SIN (X/50) Ясно, что при умножении второй координаты на 50 мы получаем 50-кратное «увеличение» синусоиды по вертика- ли, а от прибавления числа 88 она сдвигается вверх, и ось ее совпадает с горизонтальной осью экрана дисплея. Возможно, некоторым читателям покажется непонятным, почему, говоря о 50-кратном растяжении по горизонталь- ной оси, мы записали SIN(X/50). Им было бы понятнее, если бы мы записали 110-ю инструкцию так: PLOT 50 >К X, SIN X. Но тогда в записи цикла FOR... нам пришлось бы изменять граничные значения (и вы- бирать шаг) так, чтобы переменная 50 >К X принимала те же значения, которые принимает переменная X в ис- ходной записи цикла (FOR Х = 0ТО 5.1 STEP.2). Под- ставив в инструкцию PLOT вместо X два раза пере- менную Х/50 и умножив на 50 все значения (границы и шаг) в инструкции, мы сохраним исходную запись 100-й инструкции, а в 110-й инструкции после SIN по- явится выражение Х/50 В общем случае, если требуется построить на экране дисплея график функции FN f(x), необходимо выбрать отрезок, принадлежащий области определения (допусти- мых значений X) функции f(X), который необходимо показать на экране (рис. 8). Предположим, что мы вы- брали отрезок 15, 32 (следовательно, левый край экрана соответствует значению Х=15, а первый Х = 32). За- тем необходимо установить нижнюю и верхнюю границы значений функции на этом отрезке. Предположим, что эти границы равны соответственно —500 и 1000. Так как столбцы экрана можно перенумеровать целыми числами от 0 до 255, всегда удобно начинать с 100-й инструкции, а инструкцию PLOT записывать в виде PLOT X... Вме- сто аргумента в f(...) следует подставить такое выра- жение, чтобы его значения были заключены между 15 и 32. Нетрудно видеть, что f (15 + Х 17/255) удовлет- воряет этому условию, так как 17 = 32—15 (весь отрезок 37
укладывается на экране). С другой стороны, если ко всем значениям функции прибавить 500, то они заведомо не будут отрицательными (так как будут заключены между 0 и 1500). Если затем их умножить на 175/1500, то вто- рое выражение, входящее в инструкцию PLOT, будет принимать значения от 0 до 175, т. е. график функции f(x) уместится на экране и по вертикали. Окончательно наша программа будет иметь следующий вид: 100 FOR Х = 0 ТО 255 110 PLOT X, (500 4- FNf (15 + 4- 17 * X/255)) * 175/1500 120 NEXT X КАК ПРОВЕСТИ ПРЯМУЮ Когда мы проводим различные кривые, гораздо удоб- нее строить их не по многим точкам, а определять лишь некоторые из них, соединяя затем полученные точки от- резками прямых. Следовательно, нам необходима такая 38
программа, которая могла бы вычерчивать отрезки пря- мых с помощью графических символов. В качестве одного из возможных решений можно было бы предложить задавать прямые как графики соот- ветствующей линейной функции (например, задав ин- струкцию DEF FN Е(Х) =2 Х/3 4-1, в дальнейшем можно ссылаться на FN Е(Х) или вместо FN Е(Х) всюду просто записывать выражение 2 >|< X/3 + 1). Плохо лишь, если угловой коэффициент прямой (коэф- фициент при X во второй координате в инструкции PLOT) значительно отличается от единицы. Например, программа 10 FOR Х = 0 ТО 21 20 PLOT X, 2 $ X 30 NEXT X «проведет» такую прямую, от которой на экране останется лишь каждая вторая точка. Дело в том, что, когда коорди- ната X возрастает на 1, координата У (вторая координата) возрастает на 2. Нам же необходимо, чтобы с каждым ша- гом обе координаты возрастали не более чем на 1, т. е. чтобы на экране зачернялись два соседних квадратика («точки»). Например, в последней из приведенных нами программ мы могли бы дописать в конце 10-й инструкции STEP. 5. Тогда с каждым шагом координата X увеличи- валась бы на 0,5, а координата У — на 1. Существенно, чтобы по крайней мере одна из координат возрастала ров- но на 1, так как в противном случае вычерчиваемая прямая оказалась бы слишком «жирной»: зачерненными были бы смежные квадратики. Кто не верит, может убедиться, за- пустив следующую программу: 10 FOR Х = 0 ТО 63 STEP. 5 20 PLOT X, X $ 2/3 30 NEXT X После этих предварительных замечаний мы уже готовы по достоинству оценить программу, дающую решение за- дачи — «умеющую» проводить прямолинейный отрезок: 1000 LET R —С — А 1010 LET S = D — В 1020 LET E = ABS R 1030 IF ABS S> —E THEN LET E — ABSS + (S = 0) 1040 FOR X = 0 TO 1 STEP 1/E 39
1050 PLOT A + R * X, В + S * X 1060 NEXT X 1070 RETURN Эта программа проводит отрезок прямой, соединяю- щей точки А, В и С, D. Благодаря тому, что в программу включена инструкция RETURN, мы из любой программы с помощью инструкции GOSUB 1000 можем обратиться к нашей программе (с соответствующими значениями координат А, В и С, D), а после того, как нужный отре- зок будет построен, вернуться с помощью RETURN к тому месту большой программы, откуда мы обратились к 1000-й инструкции. Обращение к процедуре (под- программе) с помощью инструкции GOSUB и возвраще- ние в то место, где было прервано последовательное выполнение программы, с помощью инструкции RETURN позволяют значительно сократить такие программы, в ко- торых требуется неоднократно производить какое-либо действие. ОКРУЖНОСТЬ* Коль скоро мы знаем, как строить на экране дисплея графики любых функций, нам не составит особого труда построить и окружность. Сделать это можно многими способами. Построим окружность как график кривой. Пусть требуется провести на экране вокруг точки 32, 22 окружность радиуса 15. Функция 22 + SQR (225 — (X — 32) >К (X — 32)) позволяет построить толь- ко верхнюю полуокружность (SQR — от англ. SQUARE ROOT — означает «квадратный корень»). Нижнюю полу- окружность мы получим, изменив знак перед SQR на минус. При выдаче точек полуокружностей на экран возникает проблема: при X, принимающем значения от 32—15=17 до 32+ 15 = 47 у краев полуокружностей точки встречаются редко и лишь в средней части скапли- ваются достаточно густо. Учитывая неравномерность распределения точек, окружность целесообразно строить на экране дисплея следующим образом: прорисовать центральную часть верхней полуокружности и трижды * Более «быстрые» алгоритмы построения отрезков и окружно- стей, требующие меньших вычислительных затрат, можно найти в книге: Абрамов В. А., Дубровин В. С. Прикладное программное обеспечение микро-ЭВМ.— М.: Высшая школа, 1987. 40
в одну сторону повернуть вычерченную дугу на 90°. Для того чтобы прорисовать центральную часть верхней полу- окружности, достаточно взять значения X, заключенные в пределах от 32—15/SQR 2 22 до 32 + 15/SQR 2 42. Поворот на 90° описан в разделе «Точки», поэтому мы воспользуемся уже известным рецептом и включим его в программу, позволяющую вычертить на дисплее полную окружность радиуса 15 с центром в точке 32, 22: 100 FOR Х = 22 ТО 42 110 LET А — SQR(225—(X—32) * (X —32)) +22 120 PLOT X, А 130 PLOT 10 +А, 54—X 140 PLOT 64—X, 44—А 150 PLOT 54—А, X—10 160 NEXT X ПАРАМЕТРИЧЕСКИЕ КРИВЫЕ При построении графиков функций с помощью ин- струкции PLOT первой входящей в нее координатой всег- да была переменная X. Это означает, что инструкция PLOT просто пересчитывает один за другим все столбцы экрана от первого до последнего и в каждом столбце рисует на экране точку, вторая координата которой опре- деляется данной функциональной зависимостью. Однако может представиться случай, когда обе координаты точ- ки будут заданы какими-то функциями (вообще говоря, более сложными, чем функция у = х) общего переменно- го параметра. Кривые, описываемые движением точки при изменении параметра, называются параметрически заданными кривыми или просто параметрическими кривыми. Они позволяют вычерчивать на экране более сложные кривые, поскольку при параметрическом зада- нии совсем не обязательно, чтобы в каждом столбце график имел лишь одну точку. В качестве самого простого примера построения пара- метрической кривой можно привести вычерчивание на дисплее верхней полуокружности. Этот пример тем более полезен, что нам уже известно, как строить верхнюю полуокружность, соединяя отдельные точки отрезками прямых. Итак, предположим, что на экране дисплея требуется провести окружность радиуса 20 с центром в точке 31, 21. Задать окружность нам помогут функ- 41
ции cos t и sin t: координаты точек окружности опреде- ляются параметрическими зависимостями 31 + 20 * * cos Т и 21 + 20 * sin Т, параметр Т принимает значе- ния от 0 до 2 * PI. Шаг (угол поворота между двумя соседними точками окружности) выберем равным PI/10, т. е. вместо окружности построим на дисплее правильный двадцатиугольник. Сделаем это с помощью программы 10 LET А = 31 20 LET В = 21 30 FOR Т = PI/10 ТО 2 * Р1 STEP PI/10 40 LET С = 31 + 20*COS Т 50 LET D = 21 +20* SIN T 60 GOSUB 1000 70 LET A = C 80 LET В = D 90 NEXT T (с 1000-й инструкции начинается процедура построения отрезка прямой с заданными концами). В А и В всегда хранятся координаты начала отрезка, инструкции 40 и 50 вычисляют координаты его конца, после чего процедура с меткой 1000 соединяет начальную и конечную точки отрезком прямой. Затем точка, которая была концом отрезка, становится началом следующего отрезка, вычисляются координаты конца нового отрезка и т. д., пока параметр Т не достигнет значения 2*Р1, т. е. не опишет полную окружность. Введя совсем незначительные изменения в приведен- ную выше программу, мы получаем возможность изобра- зить на дисплее спираль. Для этого достаточно увеличи- вать радиус пропорционально углу поворота и одновре- менно увеличивать сам угол поворота: ведь спираль пото- му и спираль, что она виток за витком «обвивается» вокруг центра. Видоизменения, позволяющие перейти от параметрического задания окружности к параметричес- кому заданию спирали, имеют вид: 10 LET А = 34 30 FOR Т = PI/10 ТО 8*Р1 STEP PI/10 (а в 40-й и в 50-й инструкциях вместо радиуса, равного 20 единицам, следует подставить, например, радиус (З + Т)). 42
СЛУЧАЙНЫЕ ЭЛЕМЕНТЫ В языке БЕЙСИК предусмотрена возможность вклю- чения в программу случайных элементов и тем самым осуществлять заранее непредсказуемые вариации*. Функция RND (от англ. RANDOM — случайный) задает случайные числа в интервале от 0 до 1. (Таким образом, всякий раз, когда в программе встречается инструкция RND, порождается некоторое число, относительно кото- рого заранее известно лишь, что оно с равной вероят- ностью примет значение, заключенное между 0 и 1.) Ясно, что 10*RND означает случайное число, заключен- ное между 0 и 10, a INT(10 * RND) — какое-то (наугад выбранное) из чисел 0, 1,2, ..., 9. Как можно использовать случайные числа при состав- лении графических программ? Так же, как вычисленные значения других функций. Изображение на дисплее зави- сит от вычисленных программой значений функций, среди которых могут быть и случайные числа. Например, нам может понадобиться поместить в случайно выбранном месте на экране какой-нибудь символ (хотя бы букву «О»): 10 PRINT AT INT (RND*22), INT (RND *32); «О» 20 GOTO 10 В инструкции PRINT АТ... первая координата задает случайно выбранную строку, а вторая — случайно^ вы- бранный столбец, т. е. тем самым производится случайный выбор места (на пересечении строки и столбца) для буквы «О» на экране дисплея. Затем программа повторя- ется сначала. Наблюдая за экраном, мы увидим, что (по крайней мере сначала, когда символы не покрывают его слишком густо) буквы «О» появляются на нем в пол- ном беспорядке, как капли дождя на мостовой. Но рано или поздно буквы покроют весь экран и выстроятся в строки и столбцы, хотя первоначальное распределе- ние их было случайным. * В действительности в персональных компьютерах используются не случайные, а псевдослучайные числа, которые по своим статисти- ческим свойствам служат хорошим приближением к случайным чис- лам.-- Прим. Л. Ч. 43
СЛУЧАЙНОЕ ЗАПОЛНЕНИЕ Если мы хотим сохранить случайный характер рисун- ка распределения символов на дисплее, то можно по- ступить иначе, например, обойти все позиции символов, каждый раз случайным образом выбирая, какой символ должен находиться в данном месте. Проще всего выби- рать один из двух символов, например, «>|<» и «О» (пусть, например, им присвоены коды 23 и 52). Тогда вы- ражение 23 + 29 (RND С.5) позволит случайным об- разом и равновероятно выбирать один из двух символов, а программа 10 FOR I = 1 ТО 704 20 PRINT CHR£(23 4- 29 * (RND >.5)) ; 30 NEXT I обеспечит случайное заполнение дисплея двумя симво- лами. В 20-й инструкции выражение (RND>>.5) принимает (как и уже встречавшиеся нам другие логические выра- жения) значение 1 или 0 в зависимости от того, больше RND, чем 0,5, или меньше. Функция CHR$ восстанавли- вает по коду соответствующий символ. Частота появле- ния каждого из двух символов одинакова, так как отно- шение (RND>*.5) выполняется с вероятностью 0,5. СЛУЧАЙНОЕ БЛУЖДАНИЕ Если символы располагать на экране дисплея не в строку, а начав с центра экрана, каждый следующий шаг совершать в случайно выбранном направлении, то получится движение, известное под названием случайно- го блуждания. Выражение INT(RND>|<4) позволяет слу- чайным образом выбирать одно из значений 0, 1, 2 и 3 и тем самым перемещаться на одну «клетку» направо, налево, вверх и вниз (рис. 9): 10 LET 16 20 LET Y = 11 30 PRINT AT Y, X; «*» 40 LET R = INT(RND*4) 50 LET X == X + (R == Q) — (R = 1) 60 LET Y = Y + (R = 2) — (R - 3) 70 GOTO 30 44
В инструкциях 50 и 60 использован уже хорошо из вестный прием: выражения в скобках (R = a), где а = 0, 1, 2, 3, принимает значение 1, если R = а, и 0, если R Ф а. Значение X увеличивается на 1 при R — 0 и убывает на 1 при R= 1. Аналогичным образом, значе- ние Y увеличивается на 1 при R=2 и убывает на 1 при R= 1. От приведенной программы не будет особой радости до тех пор, пока мы не включим в нее «предохранители», не позволяющие изображаемой точке выходить за преде- лы дисплея (с некоторыми из них мы познакомились в разделе «Точки»). Более простой разновидностью случайного блуждания на плоскости является случайное «дрожание», когда случайным образом изменяется только координата X, а координата Y каждый раз увеличивается на 1. Приве- денная выше программа для случайного блуждания пос- ле незначительных переделок порождает и случайное «дрожание»: для этого начальное значение Y нужно вы- брать равным 0, в 40-й инструкции RND умножить не на 4, а на 2 (поскольку теперь имеются только две возмож- ности для случайного выбора направления — направо или налево), а в 60-й инструкции заменить выражение на более простое LET Y = Y4-1. После внесения этих незначительных переделок программа вычертит на экране дисплея дрожащую линию, напоминающую более всего извилистую реку. 45
СЛУЧАЙНОЕ БЛУЖДАНИЕ С ИНЕРЦИОННЫМ ЗАПАЗДЫВАНИЕМ Случайное блуждание можно запрограммировать и так, что линия будет изменять свое направление не совершенно беспорядочным образом, а как бы испыты- вать своего рода «инерционное запаздывание»: начав двигаться в каком-нибудь направлении, она будет «пово- рачивать» в другом направлении не сразу, а постепенно, по мере изменения скорости. При таком движении точки на дисплее появится не зигзагообразная ломаная, а плав- ная кривая, состоящая из скругленных дуг. В разделах «Случайное заполнение» и «Случайное блуждание» координаты точки задавались случайно. Теперь же мы будем изменять случайно скорость точки (изменение координат за один шаг). Такое движение можно было бы назвать случайным движением второго рода — случайны не изменения координат, а изменения изменений координат. Если раньше нам достаточно было только двух переменных X и Y, обозначающих координа- ты точки, то теперь нам понадобятся еще две переменные (обозначим их и и v) для запоминания скорости точки по горизонтали и вертикали. Программу для случайного блуждания с инерционным запаздыванием можно запи- сать следующим образом: 100 LET Х= 128.LET Y = 100 110 PLOT х, у 120 LET u = 0:LET v = 0 130 LET u = u + SGN (RND — .5) 140 LET v = v + SGN(RND — .5) 150 DRAW u, v : LET x = x + u: LET у = у + v 160 GOTO 130 Точно так же, как и прежде, необходимо решить проб- лему «удержания» точки на экране: если не предусмот- реть никаких ограничителей, то блуждающая точка ока- жется рано или поздно за пределами экрана. Однако ввести «предохранители» здесь оказывается сложнее, чем при случайном блуждании без инерции, так как заданные границы нарушаются теперь при выполнении инструк- ции DRAW, строящей отрезок. Если условиться, что в случае выхода точки за экран изображение продол- жается с его противоположной стороны, то перед обра- 46
щением к инструкции DRAW необходимо проверить, укладываются ли координаты конечной точки в допусти- мые пределы. Если же координаты конца отрезка выхо- дят за допустимые пределы, то следует провести лишь часть линии, вычислить координату «повисшего» конца, поставить (с помощью инструкции PLOT) точку на про- тивоположной стороне экрана и продолжить от нее остав- шуюся часть линии. Можно поступить еще проще: предоставить програм- ме выполняться до тех пор, пока она не выдаст ошибку, а затем начать все сначала. Описанная в конце этого раздела процедура случайного блуждания с инерцион- ным запаздыванием не только легко программируется, но и дает на экране красивую плавную линию. КАК УПРАВЛЯТЬ РАСПРЕДЕЛЕНИЕМ ВЕРОЯТНОСТИ Во всех приведенных до сих пор примерах инструкция RND использовалась таким образом, что порождаемые ею случайные значения всегда были равновероятными. Например, при случайном заполнении экрана дисплея символы «>|о> и «О» в любой позиции появлялись с веро- ятностью -g-, а прй случайном блуждании шаг вправо, влево, вверх или вниз совершался с вероятностью . Однако может представиться случай, когда вероятности получаемых случайных значений не автоматически рав- ны, а распределены неравномерно — например, зависят от позиции на дисплее, времени, прошедшем с момента пуска программы, и т. д. Если в программе, задающей случайное заполнение, в 20-й инструкции сравнение в RND производить не с 0,5, а с каким-нибудь другим числом, например 0,67, то про- порция между двумя символами на экране изменится. Например, буква «О» будет появляться с вероятностью 1 , 2 . -к-, а символ «:ж»— с вероятностью (т. е. соотно- о о шение между числом букв «О» и символов «^» на экра- не изменится и станет равным 1:2). Если перед началом программы записать инструкцию 5 INPUT Y, и в функ- ции RND производить сравнение с Y, то, как нетрудно понять, соотношение между буквами «О» и символами «^» будет зависеть от заданного значения Y 47
Измененная таким образом программа будет по-преж- нему обладать тем свойством, что в любой части экрана соотношение между двумя символами окажется посто- янным по величине. Но если при обходе экрана сохранять номер столбца и строки, в котором (или в которой) мы оказались, то появляется возможность сделать так, чтобы вероятность, с которой встречаются символы, зави- села от позиции на экране. Рассмотрим, например, следующую программу: 10 FOR 1 = 0 ТО 21 15 FOR J = 0 ТО 31 20 PRINT AT I,J;CHR$(23 4-29 * условие) 25 NEXT J 30 NEXT I Если вместо слова «условие» записать (RND>*J/31), то в левой части экрана «перевес» будет за буквой «О», а в правой — за символом «й<»; в среднем по экрану оба символа будут встречаться одинаково часто. (Действи- тельно, при малых J значение RND с большой вероят- ностью превышает J/31, а когда J стремится к 31, эта вероятность постепенно убывает до нуля.) Аналогичным образом условие (RND>*I/22) позволяет создать избы- ток одного из двух символов соответственно в нижней и в верхней половинах экрана. Если знак «>>» в обоих условиях (и в (RND>J/31), и в (RND>J/22)) заме- нить на знак «О, то распределение знаков изменится на обратное: там, где раньше было больше знаков «>|<», станет больше знаков «О», и наоборот. При условии (RND> ABS(I/11 — 1) * ABS (J/16— 1)) мы получим в центре дисплея скопление букв «О». Интересно попробовать внести в рассмотренные нами примеры еще одно изменение: заменить функцию RND функцией RND>|<RND. Проделав эту операцию, нетруд- но заметить, что переходы (например, от области, «засе- ленной» преимущественно символом «>|о>, к области с за- метным преобладанием буквы «О») станут более резки- ми, чем до замены: соотношение между количеством символов «>(<» и букв «О» подвержено резким колеба- ниям. Но если функцию RND заменить функцией SQR(RND), то произойдет обратное: переходы станут более мягкими (впрочем, разница между RND и SQR(RND) часто едва заметна). 48
Приведем пример программы, в которой вероятность появления символа зависит от позиции на экране дисплея. Воспользуемся для этого программой, приведенной в са- мом начале раздела «Случайные элементы» (эта про- грамма расставляла случайным образом на экране буквы «О»), и переделаем ее так, чтобы, когда букв «О» набе- рется достаточно много, программа начинала вписывать пустые символы и, следовательно, постепенно очищала экран, после чего все повторялось бы сначала. Вместо буквы «О» в исходной программе введем теперь два сим- вола: букву «О» с кодом 52 и пустой символ «□» с ко- дом 0. Если символы требуется расставить случайным об- разом на N местах, то необходимо сделать примерно LogN шагов для того, чтобы все позиции оказались занятыми по крайней мере одним символом. При N = 704 это составляет около 5000 шагов. Таким образом, нам необходимо выбрать такое выражение, чтобы функция RND от него сначала принимала значение 0, затем при- мерно через 5000 шагов достигала значения 1, после чего примерно через еще 5000 шагов убывала до 0. Удобнее всего в качестве такого выражения взять (1 + SIN (L/1500 — PI/2)) /2, где L — номер шага. Прог- рамма при этом выглядит следующим образом*: 10 FOR L = 1 ТО 1000000 20 PRINT AT INT (RND * 22), INT (RND *32); CHR£(23 + 29 * (RND > (1 4-SIN (L/1500 —PI/2))/2) 30 NEXT L При всех своих достоинствах эта программа имеет один весьма существенный недостаток: пропорция между символами изменяется медленно, примерно за десять ми- нут. «Ускорить» программу раз в 10 можно, если су- зить размеры «засеиваемого» символами поля до прямо- угольника 9X10. Для этого необходимо следующим об- разом видоизменить 20-ю инструкцию: 20 PRINT AT INT (RND*9) 4-5, INT (RND* 11) 4-6; CHR£(23 4~29* (RND>(1 4- SIN(L/150 4- 1- 5))/2) * He следует забывать, что максимальное значение целого числа на вашем компьютере может быть ограничено. Для 16-разрядных ма- шин это меньше 32676. 49
Входящее в 10-ю инструкцию значение 100(/000 выбрано с таким расчетом, чтобы за время работы (достаточно большое) требуемые изменения можно было наблюдать сколько угодно раз. Управлять распределением вероятности можно также и в случайном блуждании (и, разумеется, в его частном случае — случайном «дрожании»). Неудобство программ, задающих как случайное блуждание, так и случайное дро- жание, состояло в том, что нам приходилось вводить в них специальные «предохранители», не дающие изображаю- щей точке выходить за пределы экрана. Следующее простое соображение позволяет так модифицировать про- грамму, чтобы обойти эту трудность. Зададим распределе- ние вероятности на правой и левой, верхней или нижней половинах экрана так, чтобы она зависела от того, на каком расстоянии от левого или правого (верхнего или нижнего) края экрана находится изображающая точка. Чем ближе точка подходит к краю экрана, тем с мень- шей вероятностью она продолжает двигаться к нему! Для того чтобы удержать точку на экране, достаточно записать 50-ю и 60-ю инструкции следующим образом: 50 LET X = X + SGN(RND — X/31) 60 LET Y = У 4-SGN(RND — Y/21) (необходимость в инструкции 40 при этом отпадает). Функция SGN(Z) означает знак числа Z. В нашем случае если RND Х/31 (координата X с большой вероятностью принимает малые значения, случай Х = 31 невозможен), то выражение SGN(RND — Х/31) принимает значение 4-1, а при RND<X/31 —значение —1. В принципе мо- жет случиться и так, что RND = Х/31, тогда SGN (RND — Х/31) принимает значение 0 (координата X не возрастает и не убывает), однако вероятность равенства RND = = Х/31 мала. Следовательно, малые значения X с большой вероятностью возрастают, а большие значения X с боль- шой вероятностью убывают. Аналогичным образом об- стоит дело и с новыми значениями Y. Характер движения изображающей точки по экрану несколько изменится по сравнению с прежним, поскольку элементарные квадратики соприкасаются теперь в основ- ном вершинами (поскольку на каждом шаге, вообще го- воря, изменяются значения как координаты X, так и ко- ординаты Y). Предоставляем читателю в качестве упраж- нения самостоятельно составить такой вариант модифи- 50
цированнои программы, при котором элементарные квад- ратики примыкают друг к другу «по-старому», т. е. не вершинами, а сторонами. Но основная новизна состоит в том, что случайно движущаяся на экране точка избегает выхода за его край весьма интересным способом: она описывает при- чудливые зигзаги в центре экрана, но стоит лишь ей приблизиться к краю, как размах скачков уменьшается, а затем она снова возвращается в центр экрана. Еще проще управлять распределением вероятности при случайном блуждании «с инерционным запаздывани- ем». Основная идея, позволяющая упростить решение за- дачи для случайного блуждания, состоит в следующем: скорость точки убывает или возрастает в зависимости от того, насколько близко или далеко находится изобра- жающая точка от края экрана. Например, стоит только точке приблизиться к правому краю экрана, как вероят- ность убывания ее горизонтальной скорости возрастает до тех пор, пока эта скорость не обратится в нуль и не станет отрицательной, после чего точка начнет двигаться в противоположную сторону — к центру экрана. В уже знакомом нам примере из раздела «Случайное блужда- ние с инерционным запаздыванием» мы обозначили горизонтальную скорость через и. Если точка начинает тормозиться, имея горизонтальную скорость и, то до пол- ной остановки она успевает пройти путь и + (и— 1)4- 4- (и — 2) 4- ... 4- 2 + 1 = и (и — 1) /2. Если же точка не тормозится, то ей предстоит совершать еще по крайней мере (u-f-l) (u4-2)/2 шагов. (Если и отрицательна и точ- ка приближается к левому краю экрана, то в формулу надлежит подставить ABS(u).) Следовательно, если, на- пример, х4-и> 255—(и 4- 1) (и + 2)/2, то непременно происходит торможение, т. е. величина и уменьшается, а при х< (—и 4“ 1) * (—и 4- 2) /2 горизонтальная ско- рость и непременно возрастает. Для этого в программу из упомянутого выше примера необходимо ввести следующие изменения «в окрестности» 130-й инструкции: 130 LET w = (ABS(u) 4- 1) * ((ABS(u) 4- 1) + 1)/2 135 LET u = u4- SGN(RND* (225—2* w) 4-w — x 140 LET z = ((ABS(v) 4- I) * (ABS(v4- 1) + l))/2 145 LET v = v 4- SGN (RND * (175—2* z) 4-z —y) В 135-й инструкции выражение RND (255—2>f< $ w) 4-w производит случайный выбор между значения- 51
ми w и 255—w (и сравнивает выбранное значение с ве- личиной х). Аналогичный «секрет» запрятан и в 145-й инструкции. Приведенные выше «ухищрения» позволяют движу- щейся точке вовремя «затормозить» и никогда не ока- заться за пределами экрана. КОДИРОВАНИЕ По существу, искусство составления графических программ состоит в умении задать требуемые изменения в «картинке» с помощью чисел, т. е., иначе говоря, зако- дировать вносимые в изображение изменения. Можно сказать, что вся вторая глава посвящена проблеме коди- рования. Почему же тогда мы сочли необходимым уде- лить кодированию еще и специальный раздел? Да по- тому, что иногда бывает необходимо закодировать не воображаемую «картинку» при программировании, а вполне реальную картинку или какую-то часть ее, возник- шую на экране в ходе работы программы. Эту картинку (или любую ее часть) программа «рассматривает» как заданную. КОДИРОВАНИЕ ЛОМАНОЙ В ВИДЕ СИМВОЛЬНОЙ ПЕРЕМЕННОЙ а$ Если на экране с тонким разбиением чертить один за другим несколько отрезков прямой с помощью инструк- ции DRAW, то для того, чтобы «запомнить» получившую- ся ломаную, достаточно сохранить параметры инструкций DRAW в том порядке, в каком эти инструкции выполня- лись. Перед первой из инструкций DRAW необходимо выполнить инструкцию PLOT, чтобы задать начальную вершину ломаной. Упорядоченные пары чисел, восстанав- ливаемых с помощью функции CODE и занимающих каждое по 1 байту, можно свести в одну переменную символьного типа (например, в переменную А$) с по- мощью функции CHR$*. Заполнив до конца переменную А$, мы можем реконструировать закодированную лома- ную с помощью следующей программы: * Функции преобразования байтов строки символов в коды CODE и набором кода в символ CHRS в различных вариантах при- сутствуют в большинстве компьютеров.— Прим. ред. 52
100 FOR 1 = 2 TO LEN A$ STEP 2 110 IF 1=2 THEN PLOT CODE A$(I — 1), CODE A$(I) 120 IF I >2 THEN DRAW CODE A$(I — 1), CODE A$(I) 130 NEXT I По аналогии с ломаной мы можем закодировать лю- бую кривую, что, впрочем, имеет смысл лишь при условии, если она «извивается» не слишком часто, так как в про- тивном случае в А$ понадобилось бы записать координаты очень большого числа точек. Несвязную кривую (состоящую из нескольких «кус- ков», не имеющих попарно ни одной общей точки) невоз- можно закодировать в виде одной символьной перемен- ной. В этом случае необходим специальный знак, кото- рый бы отделял одну связную часть кривой от другой. Например, таким разделителем может быть символ с ко- дом 200, записанный в качестве второй координаты точ- ки: на этом месте может стоять код, не превышающий 175. Инструкции НО и 120 должны были бы теперь зави- сеть от другого условия: например, переменная С прини- мает значение 1, если необходимо начать новую линию, а в остальных случаях ее значение равно 0. Инструкция НО должна была бы начинаться так: IF С = 1..., а ин- струкция 120 так: IF С = 0. В приведенную выше про- грамму необходимо было бы ввести три новые инструкции: 90 LET С = 1 105 IF CODE А$ (I) =200 THEN LET C= 1:GOTO 130 125 LET C = 0 Обращение к инструкции DRAW при построении изображения обладает тем преимуществом, что с изме- нением первичных двух байтов в символе А$ (координат начальной точки) вся линия на экране начинается с но- вой точки. Если линия, которую требуется закодировать в сим- воле, имеет очень много изломов, то кодирование коорди- натами вершин недостаточно экономично, поскольку на каждую вершину приходится затрачивать по два байта. Каждую точку кривой можно закодировать с помощью всего лишь одного байта, если хранить лишь направле- ния выхода из предыдущей вершины, которые можно 53
Рис. 10 закодировать числами от 0 до 7 (0 будет означать шаг направо, 1 — шаг направо и вверх, или шаг по диагона- ли, 2 — шаг вверх и т. д.) (рис. 10). Первые два байта, как и раньше, отводятся для координат начальной точки. Если кривая закодирована символом А$, то построить ее можно с помощью следующей программы: 10 LET 1 = CODE А$ (I) :LET J = CODE A$ (2):PLOT I, J 20 FOR K = 3 TO LEN A$ 30 LET Q = CODE A$ (K) , 40 LET 1 = 1+ (Q = 0) + (Q=l) + (Q = 7) - (Q = 3) - (Q = 4) - (Q = 5) 50 LET J = J+ (Q=l) + (Q = 2) + (Q = 3)~ (Q = 5)-(Q = 6)-(Q = 7) 60 PLOT I, J 70 NEXT К Важное преимущество описанного способа кодирова- ния состоит в том, что он позволяет поворачивать кривую на угол, кратный 45°. При любом начальном значении Q (показывающем, сколько раз угол 45° содержится в угле поворота) в инструкции 30 выражение CODE А$ (К) имеет смысл относительного угла поворота. Инструкция- вставка и видоизмененная 30-я инструкция имеют сле- дующий вид: 5 LET R = 30 LET Q = R + CODE А$(К): LET Q = Q -8* (Q>7) Более простой вариант предлагаемого способа кодирования возникает в том случае, когда соседние точ- 54
ки примыкают друг к другу лишь сторонами, а не верши- нами: Q принимает при этом только значения 0, 1, 2 или 3. ГРАФИКА После того как мы познакомились с основными прие- мами компьютерной графики, рассмотрим хотя бы бегло несколько графических программ целиком — от начала и до конца. Так как речь идет о сравнительно больших («длинных») программах, мы не можем приводить всю их распечатку, а сосредоточим внимание на алгоритмах, на основе которых читатель сможет самостоятельно со- ставить такие или аналогичные программы. В первой части мы расскажем о статичных «картинках», т. е. о программах, позволяющих создать на экране какое- нибудь одно интересное и красивое изображение. Во вто- рой части мы познакомим читателя с программами, позволяющими воспроизводить на экране движение, т. е. резко или постепенно изменять изображение. СТАТИЧНЫЕ ИЗОБРАЖЕНИЯ 1. Шахматная доска Это самая простая графическая программа. На ней обычно пробуют силы все начинающие. Будем перебирать по очереди все строки и столбцы экрана. Если сумма номеров строки и столбца четна, то стоящий на их пере- сечении квадрат зачерйим, а если сумма номеров нечет- на — оставим белым. Если I — индекс, нумерующий стро- ки, J — столбцы, 0 — код белого квадрата и 128 — код черного квадрата, то по инструкции PRINT (CHR$ (128 (I + J — INT ((I + J)/2) 2))); на пересечении I-й строки и J-oro столбца всегда будет изображен квадрат нужного цвета. Действительно, выражение I + J — INT((I + J)/2) *2 принимает значение 1, если сумма I -j-J четна, и значение 0, если сумма I + J нечет- на, а функция CHR$ выдает соответственно либо код 128, либо код 0, и на экране появляется либо черный, либо белый квадрат. Черными и белыми клетками ока- жется покрытым весь экран, а не только шахматная доска 8X8. Если нам все же требуется изобразить на экране 55
именно шахматную доску, то поля (черные и белые квад- раты) имеет смысл выбрать покрупнее. Например, если мы захотим остановиться на полях размером 2X2 (каж- дое такое поле состоит из 2 X 2 элементарных квадрати- ков), то I и J должны принимать значения от 0 до 15 и в первую инструкцию PRINT должны входить перемен- ные К и L, где K = INT(I/2), L = INT(J/2). 2. Построение графиков функций на экране «в клеточку» и «в полосочку» В разделе «Построение графиков функций» мы научи- лись вычерчивать на экране дисплея графики функций, составленные из отдельных точек. Для многих целей такого «поточечного» графика вполне достаточно, но с чисто изобразительной точки зрения он не слишком интересен. Более красивое изображение кривой можно получить следующим образом. а) В программе из примера «Шахматная доска» за- менить везде сумму I 4- J выражением I + J + (J > функции (J)), где функция (J) означает функциональ- ную зависимость, задающую закон изменения номера столбца J. Это небольшое «нововведение» позволит изме- нить рисунок «в клеточку» над кривой на обратный (черные квадратики станут белыми, а белые — черными), но чередование квадратиков «в шахматном порядке» останется таким же правильным, как и под кривой. Вбли- зи самой кривой элементарные квадратики «приходят в'замешательство»: черные и белые квадратики скапли- ваются, и именно их скопление «вырисовывает» кривую, которая раньше состояла из точек. б) Другая возможность придать графику функции большую зрелищность состоит в том, чтобы заполнить часть экрана, лежащую под кривой, графическими сим- волами « и», а над кривой — графическими символами «Л». Границей между двумя частями, разрисованными «в полосочку», и будет наша кривая. Если в персональ- ном компьютере квадраты с зачерненными половинами (левой и правой) имеют коды 5 и 133, то соответствую- щая инструкция PRINT выглядит так: PRINT AT I, J; CHR$ (5 4- 128 * (\> функция (J))*. * Коды графических символов приводятся в инструкции по эк- сплуатации, прилагаемой к данному компьютеру.— Прим. ред. 56
3. Интерференционные картины Построенные на экране с тонким разбиением отрезки прямых, строго говоря, не являются прямыми, посколь- ку состоят из «точек», имеющих форму маленьких квад- ратиков. Если смотреть на дисплей издали, то мелких «зазубрин» не видно, но если «нарисовать» один рядом с другим много прямолинейных отрезков, то мелкие не- правильности, как бы сложившись, усилятся, и на экране возникнут интерференционные картины. Рассмотрим не- сколько примеров таких картин. а) Пройдем от начала и до конца по самой нижней и самой верхней строке, помечая, например, каждую четвертую точку (с помощью инструкции PLOT), а за- тем с помощью инструкции DRAW соединим прямо- линейными отрезками каждую из помеченных точек верх- ней строки с концами нижней строки, а каждую из по- меченных точек нижней строки — с концами верхней строки (т. е. каждую из помеченных точек — с двумя наиболее удаленными от нее углами экрана). б) Соединим прямолинейными отрезками с верхним и нижним концом вертикальной оси экрана каждую третью или четвертую точки самой нижней и самой верхней строки. Аналогичным образом соединим каждую третью или четвертую точку верхней или нижней строки с кон- цами горизонтальной оси экрана. в) Каждую из точек нижней и верхней строки соеди- ним с одной из точек вертикальной оси экрана, определя- емой следующим образом. Для определенности будем исходить из нижней строки. Зададим на ней половину волны синусоиды высотой в половину ширины экрана с нулями на концах: 87 SIN (I PI/255) *, где I — номер столбца или горизонтальная координата точки в нижней (или верхней) строке, и будем откладывать на вертикальной оси экрана отрезки, равные значению этой синусоиды в 1-й точке. Концы этих отрезков и будут той точкой, с которой требуется соединить I-ю точку нижней строки. Таким образом, требуется соединить прямоли- нейными отрезками пары точек (I, 0) и (127,87 >|с SIN (I >|с PI/255) для нижней строки ( (I, 175) и (127, 175— 87 SIN (I PI/255) для верхней строки). Для верхней * Числовые значения приведены для экрана с разрешением 256 X 256 точек.— Прим. ред. 57
строки отрезок на вертикальной оси откладывается от ее верхнего конца, поэтому вторую координату мы находим, вычитая из 175 соответствующее значение синуса, т. е. точку (I, 175) требуется соединить с точкой (127, 175— 87 * SIN (I * PI/155). г) Точки нижней строки соединим прямолинейными отрезками с точками верхней полуокружности, прове- денной радиусом 40 единиц вокруг центра экрана так, чтобы при движении в нижней строке слева направо дру- гой конец отрезка двигался по верхней полуокружности справа против часовой стрелки. д) Введем с помощью инструкции INPUT в начале программы число п. Пусть I принимает значение от 0 до 2 PI с шагом PI/60. Точку со второй координатой 88 4-80 SIN I в левом столбце соединим отрезком пря- мой с точкой со второй координатой 88-f-80>|cSIN (I-f-PI/n) в правом столбце. Запустим программу при значениях п, равных 1, 2, ..., 8. е) При тех же значениях параметра п, как и в пре- дыдущей задаче, и I, принимающем значения от 0 до 2 * PI, проведем окружность радиуса 60 с центром в точ- ке 68,88 и каждую ее точку соединим прямолинейным отрезком с точкой окружности, смещенной на 120 еди- ниц вправо, выбрав эту точку так, чтобы она была повернута относительно центра второй окружности боль- ше, чем исходная точка относительно центра первой ок- ружности, на угол PI/п (таким образом, каждый отре- зок имеет начало в точке с координатами (COS I, SIN I), а конец — в точке с координатами (COS (I -f- PI/n), SIN(I + PI/n)). ж) Соединим прямолинейными отрезками точку на вертикальной и горизонтальных осях экрана по следую- щему «рецепту»: нижний конец вертикальной оси соеди- ним с правым концом горизонтальной оси, затем отступя на одинаковое расстояние вверх по вертикальной оси и влево — по горизонтальной оси проведем через новые точки еще один отрезок и так будем приближаться к центру экрана, всякий раз проводя отрезок прямой через соответствующие точки. з) Вариант предыдущей интерференционной картины: соединим нижнюю точку вертикальной оси отрезком прямой с серединой горизонтальной оси, после чего нач- нем двигаться с постоянной скоростью вверх по верти- кальной оси и влево по горизонтальной, соединяя соот- 58
ветствующие точки отрезками прямых, и будем продол- жать построение до тех пор, пока не дойдем до середины вертикальной оси и левого конца горизонтальной оси. Затем повторим построение, начав снова с нижней точки вертикальной оси и середины горизонтальной оси, но двигая второй конец отрезков не влево, а вправо. Так бу- дем продолжать до тех пор, пока не покроем штриховкой все четыре квадранта плоскости. Разумеется, можно построить бесчисленное множест- во аналогичных «интерференционных картин». Более интересны те из них, в которых (как в «картинках» д и е) вносимые вариации зависят от параметров задачи. 4. Узоры на ткани В некоторых персональных компьютерах предусмотре- на возможность конструирования специальных символов, хотя для создания узоров на ткани пригодны и любые «готовые» символы, позволяющие неодноцветно запол- нить поле дисплея, т. е. допускающие раскраску в основ- ной и вспомогательный цвета. Выберем один из таких символов (если мы конструи- руем его сами, то пусть это будет символ, у которого по диагонали расположены два треугольника, разделен- ных одним квадратом) и заполним им весь экран. Обой- дем затем строка за строкой экран дисплея, и для всех стоящих в строке символов зададим один и тот же слу- чайно выбранный основной цвет, после чего пройдемся по всем столбцам и для всех символов в каждом столбце зададим один и тот же случайно выбранный вспомога- тельный цвет. Если обход экрана совершать с помощью двух циклов (наружного — по строкам и внутреннего — по столбцам), то вспомогательный цвет, единый для всех элементов каждого столбца и устанавливаемый с по- мощью функции RND в начале программы, необходимо записать в виде соответствующего элемента массива из 32 элементов (по числу столбцов), а одинаковый для всех элементов каждой строки основной цвет достаточно устанавливать перед перебором элементов строки и хра- нить как одну переменную. Описанная нами необычайно простая программа поз- воляет составлять очень красивые и разнообразные узо- ры, которые практически никогда не повторяются. Эту программу можно использовать и на черно-белом экране, 59
поскольку различным цветам соответствуют различные оттенки черного и белого. 5. Лабиринт Многим, вероятно, приходилось встречаться с компью- терными играми, в которых требовалось пройти лабиринт насквозь, выбраться из лабиринта или, наоборот, про- никнуть в него. В этой связи нельзя не вспомнить то, о чем мы уже говорили в самом начале главы. Например, лабиринт, который позволяет построить описываемая ни- же программа, настолько красив сам по себе, что по- строить его интересно просто так, «из любви к искусст- ву». Разумеется, это отнюдь не исключает того, что наш красивый лабиринт может быть использован для увлека- тельной игры. Программа, о которой мы сейчас расскажем, ориенти- рована на компьютер, в котором предусмотрена прямая запись на экран (точнее, в отведенные экрану дисплея ячейки памяти) и прямое считывание с экрана (т. е. с соответствующего участка памяти). При построении лабиринта используются символы только двух типов: «чистые», или «пустые», символы и, наоборот, полностью зачерненные квадраты. Из черных квадратов «сложены» стенки лабиринта, а пустые символы образуют проходы между ними. И стенки, и проходы имеют в ширину один символ, следовательно, длина и ширина лабиринта (измеряемая по наружным границам наружных стенок) должны быть равны нечетному числу символов. Присту- пая к построению лабиринта, мы прежде всего обнесем экран (точнее, прямоугольник максимальных размеров с нечетной длиной и шириной) стенкой, в которой оста- вим лишь два прохода: вторую клетку в верхней строке и вторую клетку справа в нижней строке. Наш лабиринт будет таким, что его всегда можно будет пройти на- сквозь, войдя слева вверху и выйдя справа внизу. Будем возводить стенки в каждой второй строке и каждом втором столбце. Для этого, выбрав наугад стро- ку или столбец, примем случайным образом решение, откуда начинать строить стенку: слева или справа (если мы выбрали строку), снизу или сверху (если выбран столбец). Может случиться, что с выбранной стороны мы уже начинали строить стенку раньше. Тогда, оставаясь в выбранной строке (выбранном столбце), мы продви- 60
гаемся удвоенным шагом до тех пор, пока не дойдем до свободного места. Оттуда мы начинаем строить новую стенку и продвигаемся вперед до тех пор, пока до попе- речной стенки не останется проход шириной в один сим- вол. Это позволит избежать глухих стен: территория ла- биринта не будет разбита на две изолированные области. Иначе говоря, лабиринт останется связным: в какой бы его точке мы ни находились, из нее всегда можно по- пасть в любую другую точку (рис. 11). Если поперек возводимой нами стенки встанет одна из наружных стен лабиринта (их нетрудно распознать по 61
тому, что по крайней мере одна из их координат достига- ет максимального значения), то в массиве, где хранятся данные о всех строках и столбцах, мы делаем пометку о том, что пройденная нами строка (или столбец) запол- нена до конца (это делается для того, чтобы, если при очередном случайном выборе номер этой строки (или этого столбца) выпадет снова, не заниматься ее обследо- ванием). После того как строка или столбец пройдены до конца, мы увеличиваем на единицу показания пере- менной, подсчитывающей, сколько строк и столбцов уже заполнено. Поиск такого места, откуда можно было бы построить новую стенку, мы продолжаем до тех пор, пока перемен- ная — счетчик не достигнет своего максимального значе- ния, т. е. пока не будут пройдены до конца все подлежа- щие «застройке» строки и столбцы. Завершив возведе- ние стенок, мы получим лабиринт, в котором можно прой- ти из любого места в любое другое, но нельзя достроить более ни одной стенки. Описанный выше лабиринт можно усложнять и даже управлять его сложностью, варьируя значения парамет- ров. Предыдущий алгоритм всегда выстраивает стенку максимально возможной длины — пока та не упирается в поперечную стенку (оставляя проход единичной длины). Представим себе теперь, что в начале программы с по- мощью инструкции INPUT вводится переменная, напри- мер принимающая значения от 0 до 1, и что каждый квадрат мы зачерняем лишь с вероятностью Y, т. е. прежде, чем положить в стенку очередной «кирпич», справляемся, выполняется ли соотношение RND<Y, и, если не выполняется, прекращаем наращивание возво- димой нами стенки. При Y = 1 мы получаем лабиринт описанного выше типа, а при Y = 0,5 гораздо более извилистый. Выбирать значения Y меньше 0,5 не имеет смысла, поскольку это значительно увеличило бы время построения лабиринта, но не слишком сказалось бы на его сложности. 6. Дерево I В первом варианте мы «нарисуем» на экране дерево несколько абстрактного вида, подверженное случайным изменениям, с ветвями, растущими под прямым углом друг к другу. Несмотря на это, наше дерево очень деко- ративно. 62
От одних ветвей дерева отходят другие, поэтому вет- ви подразделяются на поколения. Все ветви одного поко- ления либо только горизонтальны, либо только верти- кальны, так как новые побеги отходят под прямым уг- лом от ствола или от ветвей предыдущего поколения и могут расти либо только вправо и влево (горизонталь- ные ветви), либо только вверх и вниз (вертикальные вет- ви). Необходимо каким-то образом позаботиться о том, чтобы ветви не перепутывались: дерево с перепутанными ветвями, нарисованное грубыми штрихами, выглядит не очень красиво. Одна переменная символьного типа отводится для хранения координат почек ветвей одного поколения (т. е. точек, от которых отходят ветви следующего поко- ления). В программе можно предусмотреть специальную процедуру, совершающую обход всех ветвей одного по- коления, отыскивающую все почки, из которых могли бы вырасти ветви следующего поколения, производящую случайный отбор части почек и записывающую их коор- динаты. Перед тем как нарисовать ветви нового поколе- ния, необходимо проверить, умещаются ли они на экране, и убедиться, что из четырех ближайших соседей (пози- ций, примыкающих к почке справа, слева, сверху и сни- зу) занята, т. е. принадлежит ранее проведенной ветви, лишь одна позиция. После того как новая ветвь построе- на, направление роста необходимо изменить на противо- положное (умножением на —1). Завершив обход всех почек целого поколения, координаты которых хранились в символьной переменной, направление роста необходимо изменить с вертикального на горизонтальное, и наобо- рот. Описанная нами процедура, рисующая на экране все ветви целого поколения и производящая все необходимые действия, повторяется до тех пор, пока в очередном поколении на ветвях не окажется ни одной новой почки. Как и в задаче о построении лабиринта, мы можем ввести перед началом программы с помощью инструкции INPUT переменную, принимающую вероятностное зна- чение (число, заключенное между 0 и 1), что позволит регулировать рост ветвей: ветви растут лишь до тех пор, пока выполняется условие (RND < заданное значение). Разумно задавать значения, близкие к 0. Тогда деревья получаются более красивыми, чем те, которые не выдер- живают такой проверки. 63
7. Дерево II На экране с тонким разбиением программа, основан- ная на аналогичном принципе, позволяет рисовать де- ревья, гораздо больше похожие на «настоящие». Ветви не должны теперь отходить от ствола или ветви преды- дущего поколения под прямым углом. Все ветви можно закодировать одной символьной переменной из четырех байтов, из которых первые два отводятся координатам начальной точки, а два следующих — расстоянию до ко- нечной точки по горизонтали и вертикали. Рисунок дей- ствительно получается гораздо более сложным, чем в предыдущем случае, даже если на каждой ветви окажет- ся не более чем по одной почке, «всхожесть» которых определяется случайным образом. По четырем данным, определяющим ветвь (двум координатам начала и двум координатам конца ветви), всегда можно вычислить угол, образуемый ветвью с горизонталью, и, выбрав для большей красоты случайным образом (в заданных преде- лах) угол, под которым будет расти новая ветвь, вы- числить и записать в память координаты конца или рас- стояние до него по горизонтали и вертикали. Вычерчивание ветвей на экране производится с по- мощью инструкции DRAW. Следовательно, перед тем как ее выполнить, необходимо проверить, умещается ли ветвь целиком на экране. Для того чтобы дерево не раз- расталось больше, чем нужно, можно ввести ограниче- ния на число новых поколений и максимальную длину ветвей (в самом неблагоприятном случае крона дерева не должна выходить за рамки экрана). Другая возмож- ность состоит в том, чтобы длина каждой ветви составля- 2 ла, например, — от длины ветви предыдущего поколения. <5 Тогда наибольший диаметр кроны не превзойдет трое- кратную длину первой ветви, т. е. ствола (рис. 12). 8. Одуванчик Мы уже знаем, как произвести поворот на заданный угол вокруг заданной точки, и используем теперь эти знания при составлении программы, позволяющей изоб- разить на дисплее одуванчик (в программу включены случайные элементы). Всякий, кому приходилось когда-нибудь видеть оду- 64
Рис. 12 ванчик, знает, что его семена прикрепляются к основа- нию соцветия (которое без особой погрешности можно считать точкой) и что у каждого семени есть свой «пара- шют» — тонкая нить, идущая в радиальном направле- нии от основания, на свободном конце которой, как спи- цы в зонтике, расходятся короткие пушистые волокон- ца. Выглядит головка одуванчика примерно так, как это показано на рис. 13. Именно из такого схематического представления о головке одуванчика мы и будем исходить. Выберем какую-нибудь точку в пространстве (основание соцветия) 65
Рис. 13 и начнем поворачивать «парашютик» вокруг нее, как вокруг центра, в различных направлениях (в пространст- ве). До сих пор нам не приходилось говорить о поворо- тах в пространстве, но каждый такой поворот сводится к двум последовательно выполняемым плоским поворо- там. Точку пространства, от которой расходятся «пара- шютики», мы зададим тремя координатами: положение по горизонтали — координатой %, положение по вертика- ли — координатой у и положение по «глубине» — коорди- натой z. Если длина «ножки» поворачиваемого «парашю- тика» составляет 20 единиц, а длина пушинок, образую- щих «спицы зонтика»,— 10 единиц, то характерные точки парашютика имеют следующие координаты*: центр (основание соцветия) (128, 88, 0), свободный конец «ножки» (148, 88, 0), конец одной из пушинок (148, 88 + 10 * SIN и, IOCCOS и), где и — переменная, принимающая значе- ния от 0 до 2>}сР1, например равная К>КР1/4, где К = 0,1, 7. Если мы захотим повернуть «парашютик» в пространстве так, чтобы свободный конец его «ножки» оказался, например, в точке (140, 100), то сначала нам нужно повернуть «парашютик» в плоскости ху (причем поворачивать до тех пор, пока первая координата свободного конца «ножки» не станет равной 140), а за- Числовые значения даны для экрана 256 X 256 точек.— Прим. ред. 66
тем в плоскости yz от оси z к оси у, т. е. вверх (пока координата у свободного конца не станет равной 100). Для того чтобы «нарисовать» на экране одуванчик, совсем необязательно поворачивать «парашютик» вокруг центра. Возможны и другие варианты. Назовем хотя бы следующие. а) Два плоских поворота, к которым сводится любой пространственный поворот, можно производить на слу- чайно выбранный угол от 0 до л. б) Углы двух плоских поворотов будем считать слу- чайными величинами с вероятностью равномерно распре- деленной от 0 до л. Повороты на эти два угла организу- ем в виде двух циклов. Прежде чем производить любой из них, проверим, выполняется ли условие (RND < чис- ло). Если это неравенство выполнено, то мы производим поворот. Если же оно нарушено, то от поворота мы воз- держиваемся. Во втором варианте и каждый из двух плоских пово- ротов, и сравнение RND с заданным значением необходи- мо производить более искусно для того, чтобы, с одной стороны, получить достаточно много «парашютиков» и их зонтики были достаточно густыми, а с другой стороны, чтобы «парашютиков» не было очень много (иначе их будет трудно различить) и программа не занимала слиш- ком много времени. ДВИЖЕНИЯ Когда мы «рисуем» (с помощью программы) что- нибудь на экране дисплея, на нем в каждый момент времени появляется какая-то новая точка (либо отдель- ная, либо принадлежащая какому-нибудь прямолинейно- му отрезку или дуге окружности), но до сих пор эволю- ция во времени изображения на экране была несущест- венна, так как нас интересовал лишь конечный резуль- тат наших графических построений. Между тем вновь появляющиеся (и исчезающие) точки можно использо- вать для построения на экране изображений, существен- ным элементом которых является движение. В заключи- тельной части этой главы мы расскажем о нескольких программах, позволяющих создавать движущиеся изобра- жения. 67
1. Змея Случайное блуждание открывает широкие возможно- сти для изменения изображений на экране. Зачернив несколько квадратиков в средней строке, получим гори- зонтальную полоску. Ближайший к ней квадратик слева пометим обращенной (белой на черном фоне) звездочкой «Н<», а ближайший квадратик справа — обращенной буквой «X». Это и будет «змея». Голова змеи совершает случайные блуждания, которые передаются ее телу. Куда бы ни поползла змея, за ней всюду остается след из спе- циальных символов. На каждом шаге необходимо сле- дить, не выходит ли голова змеи за пределы экрана, не касается ли тела змеи в какой-нибудь еще точке, по- мимо «шеи» (т. е. не принадлежит ли телу змеи новая точка, выбираемая при случайном блуждании; разумеет- ся, ничто не мешает змее пересекать свой собственный след). Если змея достаточно длинная (например, состоит из десяти квадратиков), то рано или поздно она совьет- ся в кольцо вокруг своей головы и не сможет двинуться дальше, но до того успеет поползать вдоль и поперек по всему экрану. Случайными движениями головы нашей змеи можно управлять программой, описанной в разделе «Случайное блуждание», несколько усложнив ее ограничителями, не позволяющими змее «высовывать» голову за пределы экрана и касаться головой собственного тела. Как стирать шаг за шагом хвост змеи, заменяя его символами, изображающими ее след, и как переносить тело змеи? Ответы на эти вопросы мы получим, решив интересные задачи кодирования. Необходимо на каждом шаге знать, где находится голова змеи, вторая, третья, ... , последняя точки ее тела, и все время управлять движением этого массива. Считывать всю эту информа- цию с экрана было бы слишком сложно. Сравнительно простое решение задачи состоит в следующем: одна пере- менная отводится для координат головы, другая — для координат хвоста змеи и еще одна символьная пере- менная хранит информацию о точках туловища змеи (их относительном расположении), закодированную чис- лами от 1, 2, 3 и 4 (по числу направлений: вправо, влево, вверх и вниз). Всякий раз, когда голова змеи перемещается на новую позицию, в компоненты этой символьной переменной вносятся соответствующие изме- 68
нения — старые коды относительного расположения то- чек тела заменяются новыми. Когда хвост змеи «пере- езжает на новое место», то, вычислив его новые коорди- наты, мы записываем их в отведенную для этого пере- менную, освобождая одновременно ту позицию на экране, которую перед этим занимал конец хвоста. При таком способе передвижения длина змеи остается постоянной. Интересно отметить, что скорость перемещения змеи по экрану вообще не зависит от ее длины, поскольку на каждом шаге независимо перемещаются только голова и хвост змеи. 2. Игра «Жизнь» Один из вариантов этой известной игры можно за- программировать для персонального компьютера. Дела- ется это так. Экран случайным образом заполняется черными и белыми квадратами. Затем каждая клетка (за исключением строк и столбцов, образующих наруж- ную рамку дисплея) преобразуется по вполне опреде- ленному правилу — перекрашивается в тот цвет, который имеют большинство клеток в области, состоящей из са- мой клетки и четырех ее ближайших соседей. Преобра- зование следует производить так, как если бы мы нахо- дились одновременно во всех клетках сразу (иначе гово- ря, при преобразовании не разрешается принимать во внимание цвет уже перекрашенных клеток). Поэтому при обходе строки преобразование выполняется не сразу: сначала необходимо выяснить (и записать где-нибудь «в сторонке»), в какой цвет предстоит перекрасить каж- дую из клеток, а с выполнением преобразования подо- ждать до тех пор, пока цвет данной клетки не будет уч- тен при преобразовании строки, проходящей «одним эта- жом» ниже. Одно из возможных решений задачи о перекраске клеток состоит в следующем. Если при рассмотрении ка- кой-то клетки (и ее четырех ближайших соседей) выяс- нится, что на следующем ходу ее придется зачернить, пометим ее знаком, соответствующим основному цвету (например, «перечеркнем» буквой «X»). Тогда при про- верке клеток, расположенных справа и сверху от данной, можно принимать во внимание только ближайших со- седей, окрашенных в основной цвет. После того как будет проверена клетка, расположенная снизу от данной, на- 69
добность в последней при проверке других клеток отпа- дает, и ее можно будет зачернить, если она помечена буквой «X», и выбелить в противном случае (рис. 14). >т<х итаи №$ II гп Ьгтп Рис. 14 3. Фигуры Лиссажу Дисплей с тонким разбиением экрана позволяет создать простую и вместе с тем интересную программу, порож- дающую целое семейство замечательных кривых. Функ- ции cos t и sin t параметрически задают окружность. Если в программу, вычерчивающую на дисплее окружность, подставить COS(a>|<t) вместо COS t и SIN (b >|< t) вместо SIN t, то в зависимости от значений а и b мы получим целое семейство кривых самого различного вида. Эти кривые называются фигурами Лиссажу. Если а и b принимают дробные значения, то кривые не замыкаются, когда t изменяется от 0 до 2 PI. В этом случае проще всего ввести верхнюю границу для t, и «гонять» программу до тех пор, пока COS(a>}ct) не примет значения, доста- точно близкого к 1, a SIN(b>|<t) —к 0. 4. Космические орбиты Расположим случайным образом на экране несколько звезд, а затем запустим из какой-нибудь точки косми- ческий корабль. Под влиянием гравитационных сил скорость и направление полета космического корабля будут все время изменяться, и он опишет довольно при- чудливую траекторию между звездами. Положение космического корабля в пространстве всегда задается шестью параметрами: двумя координа- тами мгновенного положения, горизонтальными и верти- кальными составляющими скорости и ускорения. Уско- 70
рение все время изменяется. В случае одной звезды (которую удобно выбрать за начало координат) гори- зонтальная составляющая ускорения пропорциональна расстоянию от космического корабля до звезды по гори- зонтали, деленному на некоторую степень полного расстояния от космического корабля до звезды. (Из за- кона всемирного тяготения следует,. что делить нужно 3 на полное расстояние в степени , т. е. что горизон- тальная составляющая ускорения пропорциональна ве- личине х/(х2 + i/2)3/2, так как сила притяжения изменяется обратно пропорционально квадрату полного расстояния. Но из-за ограниченных размеров экрана траектория кос- мического корабля в поле «настоящего» тяготения может оказаться недостаточно «выразительной», поэтому, воз- можно, нам придется поискать какую-нибудь другую зависимость, которая давала бы более красивые кривые.) В случае нескольких звезд необходимо отдельно просум- мировать все горизонтальные и все вертикальные состав- ляющие ускорения. Вычислив мгновенную скорость, мы увеличиваем (или уменьшаем) ее горизонтальную составляющую на гори- зонтальную составляющую мгновенного ускорения, а вер- тикальную составляющую скорости — на вертикальную составляющую мгновенного ускорения и тем самым находим новые значения горизонтальной и вертикальной составляющей скорости (какими они будут через едини- цу времени). Аналогичным образом мы изменяем гори- зонтальную координату космического корабля на величи- ну горизонтальной составляющей его скорости, а верти- кальную координату — на величину вертикальной состав- ляющей скорости и в результате получаем новую точку на траектории космического корабля. Так точка за точкой мы построим всю его траекторию. Может случиться, что в какой-то точке космический корабль разовьет слишком большую скорость и «выле- тит» за пределы экрана или что два соседних участка траектории (которые мы приближенно считаем прямоли- нейными) образуют между собой острый угол. Такого рода неприятностей можно избежать, если сле- дить, например, за тем, чтобы скорость космического корабля была постоянна по величине (для этого доста- точно к£к горизонтальную, так и вертикальную состав- ляющие скорости разделить на квадратный корень из 71
суммы их квадратов). При этом сила тяготения должна была бы изменяться обратно пропорционально не квадра- ту, а меньшей степени расстояния (т. е. мы опять ввели бы «поправку» в физическую реальность). Интересно проследить за тем, по каким траекториям движется космический корабль, запускаемый из разных мест или из одного и того же места с различными скоро- стями. Очень красивая картина получается, если сохра- нить на экране все траектории, которые получатся при запуске космического корабля со «стартовых позиций», расположенных по определенному закону. При выборе места запуска можно руководствоваться различными правилами, например: а) расположить стартовые позиции на равных рас- стояниях вдоль вертикальной прямой в левой части экра- на и запускать космический корабль с одной и той же горизонтальной скоростью; б) запускать космический корабль из левого верхнего угла экрана со скоростями, равными по величине, но раз- личными по направлению; в) запускать космический корабль из середины верх- ней строки со скоростями, равными по величине, но раз- личными по направлению; г) запускать космический корабль из центра экрана в различные стороны с постоянной по величине ско- ростью. Глава III КОМПЬЮТЕРЫ И ПРЕПОДАВАНИЕ В ШКОЛЕ Ту рул ТЕРЕК ВВЕДЕНИЕ Роль и назначение компьютеров в школе различные авторы представляют себе по-разному. По мнению одних, компьютер как нельзя лучше подходит для роли учебно- го пособия («дешевый» физический кабинет), другие ви- дят в нем своего рода тренажер, третьи усматривают в компьютере «рабочую силу» для выполнения админи- стративных функций (например, для составления расписаний). Перечень возможных приложений компью- тера в школе легко можно было бы продолжить. Горяч- ность, с которой каждый из авторов отстаивает свою вер- 72
сию наиболее целесообразного использования компьюте- ров в средней школе, варьируется в зависимости от про- фессиональной принадлежности и степени личной за- интересованности. В общих чертах суть дела можно было бы сформули- ровать так: важно, чтобы доступ к компьютеру имело как можно больше людей (как учащихся, так и препода- вателей). Только при этом условии компьютер, применяе- мый в самых различных целях, рано или поздно обретет подобающий ему статус в школе. Но прежде чем это произойдет, необходимо развеять два довольно распро- страненных заблуждения относительно компьютеров. Мы сформулируем «опровержения» в виде двух утверж- дений. 1. Вычислительная техника (в частности, компьюте- ры) не является составной частью ни математики, ни естественных наук. 2. В умении обращаться с персональным компьюте- ром нет ничего сверхъестественного. Научить работать (с требуемой степенью совершенства) на персональном компьютере можно любого желающего. Эти два утверждения заслуживают того, чтобы оста- новиться на них подробнее. 1. О принадлежности вычислительной техники. Лет двадцать назад первые программисты состояли почти исключительно из лиц, получивших физико-математиче- ское образование, с незначительным «вкраплением» инженеров. Объяснялось это отчасти тем, что представи- тели физико-математических специальностей больше дру- гих испытывают необходимость в использовании компью- тера и по складу мышления ближе других к формально- му «мышлению» компьютеров. Но главная причина, по которой быстродействующие вычислительные машины снискали широкое признание у представителей точных наук, состояла в том, что с появлением компьютеров пе- ред физиками, математиками и инженерами открылись новые, неслыханные ранее возможности. Разумеется, ни у кого нет сомнений в том, что знания, необходимые для работы с вычислительной техникой (для программи- рования), по своему характеру ближе всего к естествен- ным наукам и математике. Можно сказать, что вычисли- тельная техника покоится на точных науках так же, как, например, физика опирается на математику. Возможности применения вычислительной техники да- 73
леко не исчерпываются математикой и естественными науками. По всеобщему признанию, компьютеры все шире вторгаются во все сферы жизни. Против тезиса об универсальной применимости современной вычислитель- ной техники трудно что-нибудь возразить, его необхо- димо просто принять к сведению. Некоторые специалисты склонны считать столь важное и значительное явление, как массовое распространение знаний, результатом пере- ворота в электронике. Нам бы хотелось, помимо прочего, убедить читателя в том, что независимо от той области, в которой лежат его интересы, он всегда найдет в компьютере надежного партнера и помощника: Ясно, что ни один творчески мыслящий человек не вправе ос- тавлять без ответа интеллектуальный вызов, бросаемый нам вычислительными машинами, хотя ответ на него может варьироваться в достаточно широких пределах. 2. О том, как обучать «компьютерной грамоте». На вопрос о том, какой ценой можно научить человека об- ращаться с компьютером, трудно дать однозначный от- вет: цена зависит от уровня общеобразовательной подго- товки, заинтересованности, возраста и многих других факторов. Опыт, накопленный в процессе обучения около 1000 людей различных занятий, возраста и образова- ния, позволяет утверждать следующее: а) Учащиеся средних и старших классов общеобразо- вательной школы (12—18 лет) в большинстве своем (85%) осваивают принцип и основные приемы програм- мирования на языке БЕЙСИК за 4—6 часов, после чего самостоятельно решают так называемые учебные задачи (составляют программы в 10—15 инструкций), могут ра- зобраться в распечатке более сложных программ и, внося в них надлежащие изменения, приспособить к ре- шению нужной задачи. б) Такой же степени владения компьютером 40—60% «стерильно чистых» (т. е. абсолютно несведущих в про- граммировании) взрослых достигают за 3—12 часов. в) В кружках юных программистов школьники, всерь- ез интересующиеся компьютерной техникой, овладевают за несколько месяцев (100—200 часов, в основном в сво- бодное от уроков время) с минимальной помощью приемами и методами программирования настолько, что умеют находить почти оптимальные решения задач на программирование. К наиболее выдающимся личным ре- кордам мы еще вернемся. 74
Все сказанное позволяет нам в дальнейшем заботить- ся об интересах «среднего читателя», каковы бы ни были его возраст, образование и интересы. Весь излагаемый ниже материал расположен по «предметоцентрическому» принципу. Отдавая предпочтение такой форме подачи материала, мы исходили из следующих соображений. Во-первых, каждый из читателей ходил или ходит в шко- лу, следовательно, все темы предлагаемых ниже задач на программирование должны быть хорошо ему известны. Во-вторых, как показывают приведенные выше данные, школьники весьма восприимчивы к компьютерной науке и легко усваивают ее. Наконец, на выбор школьной тематики не в последнюю очередь повлияло сложившееся у многих мнение, что появление долгожданных школь- ных компьютеров в наибольшей мере удовлетворяет запросам детей среднего и старшего школьного возраста. Как уже упоминалось, вокруг вопроса о том, какую роль призван сыграть компьютер в школе, не утихают споры. Что важнее: научить программировать школьни- ков или научить преподавателей использовать компьютер на уроке? В дальнейшем мы умышленно не разделяем эти два вопроса. Учить чистописанию, вероятно, лучше всего обучая одновременно правописанию: любой первокласс- ник знает, что переписать каллиграфическим почерком 10—20 раз какое-нибудь трудное слово куда полезнее, чем переписать 100 раз простое слово. Если говорить более конкретно, то мы имеем в виду переход от нескольких выстроенных в определенной по- следовательности учебных программ (программ-упражне- ний) к разносторонним, составленным на высоком про- фессиональном уровне программам-курсам по целым разделам школьной программы. Перед мысленным взо- ром оптимиста в такие «сверхпрограммы-курсы» выстраи- ваются многие сотни программ, написанных учащими- ся. Каждая такая программа-звено несет на себе отпеча- ток личности своего составителя, и в этом — ее главное достоинство и ценность. Для тех, кто сомневается в осу- ществимости такого замысла, скажем лишь, что самая известная из таких программ-курсов американская программа ПЛАТОН, рассчитанная примерно на 10 000 часов учебного времени, на 95% составлена учащимися. В этой главе мы, опираясь на собственный опыт, стремились излагать материал так, чтобы большая часть его была доступна среднему школьнику. В начале каж- 75
дой задачи интересующийся найдет общие замечания, а после того как он убедится, что в решении задачи нет ничего сверхъестественного, ничто не помешает ему продвигаться дальше быстрее. Наконец, мы хотели бы заметить, что компьютер в школе — это не только техническое средство, позволяю- щее быстро получить таблицу значений функции или проверить степень готовности учащихся к уроку, но и хо- роший «товарищ», с которым можно играть в интересные игры и у которого можно многому научиться. Мы надеем- ся, что в школе компьютер ожидает блестящее будущее. КОМПЬЮТЕР — ЧАСЫ И РЕГУЛИРОВЩИК ДВИЖЕНИЯ Как ни странно, в роли хронометров и регулировщи- ков движения могут выступать почти все компьютеры, «говорящие» на языке БЕЙСИК. INKEY$ означает функцию, позволяющую вводить один-единственный сим- вол. Ту же операцию, но более «хитрым» образом можно выполнить и с помощью инструкции INPUT. Действи- тельно, по инструкции INPUT компьютер упрямо и без- деятельно «ждет», пока мы не сообщим, что он должен делать. Функция INKEY$ позволяет более разумно ис- пользовать машинное время: даже если ответ на вопрос, что делать, еще не получен, компьютер продолжает вы- полнять другие операции (производить вычисления, стро- ить изображения и т. д.). Программа 10 FOR 1 = 1 ТО 1000 20 IF INKEY$ = «S» THEN PRINT «S»;:GOTO 40 30 PRINT «С»; 40 NEXT I выдаст на экран дисплея столько букв «S», сколько раз мы нажмем на клавишу, а вся остальная часть будет заполнена буквами «С». Интересно отметить, что как бы быстро мы ни нажимали клавишу, букв «С» на экране окажется раз в 10 больше, чем букв «S». Это означает, что компьютер обладает раз в 10 лучшей (т. е. более быстрой) реакцией, чем мы. Следует подчеркнуть, что функция, позволяющая вво- дить один-единственный символ, сильно варьируется от компьютера к компьютеру (INKEY$, INP, РЕЕК и т. д.), поэтому узнать, как именно надлежит ее записывать и 76
каковы особенности ее применения, можно только из опи- сания, прилагаемого к каждому компьютеру. Функцию INKEY$ можно использовать для измере- ния времени. Именно так («как часы») работает, напри- мер, программа* 5 К = 0 10 FOR 1 = 1ТО 26 20 IF INKEY$< >CHR$(64+ 1) THEN K=K + 1 : GOTO 20 30 PRINT CHR$ (64 + 1) 40 NEXT I Она измеряет (в каких-то единицах) время К, которое тре- буется компьютеру, чтобы выдать на экран весь алфавит. Результат К <300 следует считать выдающимся (можно устроить даже увлекательное состязание: кто сумеет за- программировать компьютер так, чтобы выдать алфавит на экран за рекордно короткое время). Не менее увлекателен и другой цикл задач, связанных с невидимыми манипуляциями. Строить изображение («чертить») на экране можно, например, следующим об- разом. Поставим на экране точку. Предположим, что мы установили между символами соответствие А о f, Во*—, Со Do |. Тогда при нажатии клавиш с буквами „А“, „В“, „С“, ,,D“ на экране будут загораться точки, соседние с начальной и расположенные от нее соответственно сверху, слева, справа и снизу, что позволяет вычертить на экране весьма эффектную ломаную линию: 90 X = 20 : Y = 20 : PLOT X, Y 100 В$ = INKEY$ 110 IF В$ = “ “THEN 100 120 А = ABS(B$) —64 130 ON A GOSUB 200, 300, 400, 500 140 PLOT X, Y : B$ = “ “ : GOTO 100 200 Y = Y — 1 : RETURN 300 X = X—1 : RETURN 400 X = X + 1 : RETURN 500 Y = Y + 1 : RETURN Можно сделать так, что клавиши А, В, С и D будут «заведывать» невидимыми перемещениями точки, кото- * Принимается, что символы алфавита имеют подряд идущие коды, начинающиеся с 65.— Прим. ред. 77
рая будет загораться на экране после нажатия на дру- гую клавишу (например, клавишу F). Манипулируя с точкой-невидимкой, мы получаем возможность вычерчи- вать на экране любые, а не только непрерывные кривые. Заметим, что вся подготовительная работа происходит незаметно, никак не отражаясь на экране. С инструкцией INPUT это было бы невозможно! Еще изящнее вычерчивание линии осуществляется в том случае, если с помощью клавиш А 4- D «запускать» точку в нужном направлении, в котором она будет дви- гаться до тех пор, пока мы не остановим ее нажатием другой клавиши. КОДИРОВАНИЕ Кодированием принято называть операцию, состоя- щую в замене (обозначении) некоторого свойства опре- деленным символом (обычно числом). Например, пятерка в классном журнале и дневнике — это код, означающий, что ученик безупречно знает заданный урок. Обеспечить однозначность кодов — дело нелегкое, и мы не будем заниматься этой задачей, а выскажем несколько идей относительно того, как на малом числе «мест» записать как можно больше информации. Представим себе, что нам нужно выставить некоторо- му классу (30 учеников) оценки по 5 предметам. На первый взгляд кажется, что для этого нам потребуется 150 чисел: ровно столько чисел от 1 до 5 следует ввести в компьютер, и эти числа займут в памяти 150 мест. Те же данные допускают более компактную (и простую) запись в памяти, если оценки, полученные учеником по 5 предметам (например, 4, 3, 5, 4, 4), хранить в виде еди- ного пятизначного числа 43544. При такой записи по- требуется всего 30 чисел, правда, «более длинных»— не однозначных, а пятизначных. Для того чтобы по достоин- ству оценить преимущества предложенного способа коди- рования, представим себе класс, в котором учатся не 30, а 1000—1200 учеников. Редкий калькулятор смог бы вместить в свою память 5000—6000 данных об их успе- ваемости по 5 предметам. Как «устроены» пятизначные оценки? Несколько обобщая, тот же вопрос можно сформулировать иначе: как установить К-й знак многозначной оценки А? Знаки целесообразно располагать справа налево (в нижней 78
строке указаны «номера» предметов, в верхней — оценки) : 4 3 5 4 4 5 4 3 2 1 Тогда К-й знак произвольного многозначного числа А будет определяться выражением INT(A/10f (К — 1)) - 10* INT(A/10|K) Предположим, что в приведенном выше примере мы хо- тим узнать оценку по третьему предмету (К = 3). Тогда INT (43544/100) = 435, 10 * INT (43544/1000) = 430 и разность между первым и вторым членом действитель- но равна 5. Предлагаемая нами формула реализуема на компьютерах любого типа (возведение в степень может быть обозначено не стрелкой f, а каким-нибудь другим символом). Следовательно, декодирование может быть осуществлено с помощью быстро вычисляемого выраже- ния. Если в компьютере предусмотрена возможность за- дания функций двух переменных, то обращение к FN (А, К) позволяет еще быстрее получить требуемый результат. Еще одна (более сложная) возможность «пятизнач- ной» оценки возникает, если мы воспользуемся пятирич- ной системой счисления. Десятичное число 43544 не мо- жет быть оценкой в пятиричной системе счисления (в ко- торой нет цифры 5), поэтому его необходимо преобразо- вать либо в 32433, либо в 43044. Записав пятиричные числа 32433 или 43044 в десятичной системе, получим еще более короткие коды: 2243 и 2899. Предлагаемый способ кодирования обладает вполне ощутимыми преиму- ществами, если речь идет о переборе небольшого числа возможных вариантов. Если же выбирать приходится более чем из десяти возможностей, то удобнее кодиро- вать буквами, а декодирование осуществлять с помощью символьных функций. Два числа А и В (средней «длины») часто бывает удобно «слить» в одно число С, целую часть которого образует число А, а дробную — число В (т. е. С = А.В, где А и В разделены «десятичной точкой»). Тогда, как нетрудно видеть, A = INT(C) и В = С-А Суть всех предложенных выше способов «уплотнения» информации можно сформулировать следующим обра- 79
зом: уместить в каждой «единице хранения» (ячейке па- мяти) как можно больше информации. Это позволяет экономно использовать ограниченную память компьюте- ра, но требует дополнительных усилий. Необходимо пом- нить, что рано или поздно записанную в памяти важную информацию придется восстанавливать в исходном виде. Следует иметь в виду, что компьютер может хранить зна- чения лишь с определенной точностью, т. е. с ограничен- ным числом (обычно 6—10) знаков. С каким бы компьюте- ром вы ни работали, определить обеспечиваемую им точ- ность можно легко и просто: по инструкции PRINT 2/3 на экране дисплея появится после десятичной точки сколько-то шестерок и одна семерка. Число знаков после точки указывает, сколько знаков вы можете спокойно вводить в компьютер, чтобы в случае необходимости за- писанную в его памяти информацию можно было пол- ностью восстановить. ВЕРОЯТНОСТЬ В компьютере, точнее, в языке БЕЙСИК предусмотре- на возможность представления «непрогнозируемых» зна- чений. Речь идет не о неожиданных реакциях компьюте- ра на нажатие той или иной клавиши, а о «случайных» элементах, возникающих в ходе алгоритмически заданной деятельности. 1. Почти во всех компьютерах (соответственно почти во всех вариантах языка БЕЙСИК) известна функция RND(x). В большинстве случаев эта функция «выдает» случайные числа, заключенные между 0 и 1. Под случайными числами мы понимаем здесь значе- ния достаточно сложных арифметических выражений, не предсказуемые заранее, с нераспознаваемым алгоритмом их получения. Вообще говоря, такие числа принято на- зывать псевдослучайными (т. е. почти случайными). Этот термин подчеркивает, что речь идет не об абсолютно слу- чайных числах (между значениями RND(x) существует функциональная зависимость). Тем не менее псевдослу- чайные числа, как мы увидим в дальнейшем, достаточно удобны в тех случаях, когда мы сталкиваемся с необхо- димостью получить в требуемых местах программы «не- ожиданные», «не прогнозируемые заранее» элементы. Особенно полезны псевдослучайные числа при изучении некоторых случайных закономерностей. Весьма интерес- 80
ная задача — составление такой программы, которая действует как генератор псевдослучайных чисел, точнее, проверка того, насколько случайны порождаемые генера- тором числа. Функция RND(x) встречается почти во всех персо- нальных компьютерах (с весьма небольшими различия- ми). Как правило, она принимает значения, лежащие в интервале (0, 1) (круглые скобки означают, что интер- вал открытый, т. е. не содержит своих концов — точек О и 1). Значения функции RND(x) распределены на ин- тервале (0, 1) равномерно, т. е. какой бы подынтервал мы ни выбрали, значение функции RND(x) рано или поздно непременно попадет в него. Иначе говоря, если мы с помощью функции RND(x) генерируем подряд не- сколько псевдослучайных чисел, то они достаточно равно- мерно покроют интервал (0, 1). Более точно это означает, что какой бы подынтервал интервала (а, Ь) мы ни выбра- ли, доля псевдослучайных чисел, попавших в этот подын- тервал, равна отношению его длины к длине всего интер- вала b — а (при условии, что генератор выдал достаточ- но много псевдослучайных чисел). За редким исключе- нием аргумент функции RND(x) (т. е. значение х) не оказывает непосредственного влияния на принимаемое ею значение. Следовательно, порождаемое функцией RND(x) псевдослучайное число, вообще говоря, не зави- сит от выбора аргумента х, а зависит от числа предыду- щих обращений к этой функции, и иногда ее даже за- писывают, не указывая значение аргумента в явном виде. В дальнейшем мы всегда будем записывать RND(0), хотя встречаются и такие персональные компьютеры, где подобная запись может привести к самым неожиданным последствиям. Во избежание неприятностей «реакцию» компьютера на запись генератора псевдослучайных чисел необходимо проверять заранее по описанию языка БЕЙ- СИК для данного компьютера. Наряду с многими преимуществами использование генератора псевдослучайных чисел сопряжено и с одним незначительным неудобством: оно затрудняет отладку программы, т. е. ту фазу работы программиста, когда программа уже составлена и производится ее опробова- ние. Программист окажется в затруднительном положе- нии, если программа при каждой прогонке будет выда- вать все новые и новые числа. Во многих компьютерах имеются генераторы псевдо- 81
случайных чисел двух типов. Генераторы одного типа при каждой прогонке выдают одни и те же последователь- ности, как бы считывая построчно элементы одной и той же таблицы «случайных» чисел (причем всякий раз счи- тывание начинается с самого начала). В генераторах второго типа значения переменной «перемешиваются», т. е. первый элемент выбирается при каждой прогонке заново и, вообще говоря, оказывается иным, чем в предыдущей прогонке,— зависит от текущего состояния компьютера. Нам нет необходимости вдаваться в детали работы и использования генераторов псевдослучайных чисел. Заметим лишь, что для наших целей «случай- ность» порождаемых генератором чисел оказывается вполне достаточной. (Некоторые сведения об использова- нии генераторов псевдослучайных чисел читатель может почерпнуть из раздела «Случайные элементы» гл. II.) Необходимо, однако, подчеркнуть, что если в компьютере имеются оба варианта генераторов, то отладку несомнен- но следует производить «табличным» генератором и лишь в том случае, если он работает исправно, переходить к работе с генератором, перемешивающим псевдослучай- ные числа (разумеется, если в этом есть необходимость). В повседневной жизни потребность в использовании случайных дробей возникает сравнительно редко, поэтому случайные числа, заключенные в интервале от 0 до 1, обычно приходится преобразовывать. Выражение А + (В - А) * RND(0) позволяет получать псевдослучайные числа, заключенные в произвольном (открытом) интервале (А, В). Если мы хотим получить псевдослучайные целые числа, заключен- ные в интервале от М до N, то следует воспользоваться выражением INT(M + RND(0) * (N - М + 1)) Оно позволяет получать с равной вероятностью все целые числа от М до N, включая границы интервала М и N. О получении неравномерно распределенных псевдо- случайных чисел мы расскажем ниже. ПЕРЕМЕШИВАНИЕ Предположим, что нам требуется решить следующую задачу: расположить N элементов (чисел, имен, вопросов 82
и Т/ д.) в случайном порядке и записать их в образо- вавшейся последовательности. Первое, что приходит в го- лову,— получить набор псевдослучайных чисел (номе- ров) и расположить элементы в том же порядке, в кото- ром идут их «номера»: 110 FOR I = I ТО N 120 А - INT(RND(0) * N + 1) 130 PRINT U (А) 140 NEXT I Сначала дело спорится, но вскоре одни элементы на- чинают повторяться, а другие куда-то исчезают. Беде можно помочь, если ввести в программу «вставку» 122 FOR J = 1 ТО I — 1 124 IF А = V(J) THEN 120 126 NEXT J 128 V(I) = A, отчего ход программы замедлится (при N > 100 время, затрачиваемое на выполнение программы, становится не- позволительно большим). Мы воспользуемся поэтому другим, весьма быстрым способом, который, хотя и несовершенен, позволяет тем не менее достигать конечной цели — «перемешивания» элементов. Предположим, что речь идет о N элементах. Выберем произвольное число M<N, удовлетворяющее условию (М, N) = 1 (числа М и N имеют общий дели- тель, равный 1, т. е. взаимно простые). Затем выберем любое целое число K<CN: 90 К = INT(RND)(0) * N Нетрудно видеть, что программа 110 FOR I = 1 ТО L 120 К = К + М : IF К > N THEN К = К- N 130 PRINT А$(К) 140 NEXT I располагает L^CN элементов в достаточно «случайной» последовательности, без повторений. В качестве М удоб- но выбирать простые числа. Необходимо лишь следить за тем, чтобы выполнялось условие M<N. Обычно хорошие 2 результаты дает выбор М в интервале ) N<M< 83
(У \ — \ N. Условие взаимной простоты чисел М и N суще- ственно, так как в противном случае мы получили бы не все элементы. Например, выбрав М = 3 при N = 15, мы получили бы лишь треть элементов, а выбрав М = 5— лишь пятую часть элементов (независимо от того, ка- кой элемент был бы выбран за начальный). Единствен- ный недостаток предлагаемого быстрого метода состоит в том, что он не позволяет получить некоторые последо- вательности. Если же наша цель состоит не в получении всех N! перестановок из N символов (распределенных с одинаковой вероятностью), а лишь любую из них, то предлагаемый метод дает простое и быстрое решение задачи. Гораздо более «равномерное» решение мы получим, если выберем случайным образом два элемента и пере- ставим их. При N/5 — N/2 перестановках символы ока- жутся распределенными достаточно «случайно», а при N перестановках беспорядок будет полным. Для сравнения приведем данные, характеризующие возможности трех способов: Случайные номера Переста- новки Взаимно простые числа Продолжительность работы 2 мин 8 4- 40 с 2 4- 7 с Количество псевдослучайных чисел 870 200 2 Всем требованиям удовлетворяет способ получения случайной последовательности символов, промежуточный между двумя последними. Это означает, что их разумно комбинировать: сначала производить несколько попар- ных перестановок (~ N/10), а затем переходить к быстро- му способу. ЭЛЕМЕНТЫ ТЕОРИИ ВЕРОЯТНОСТЕЙ Разумеется, в почти необъятном круге тем, связанных со случайностью и вероятностью, можно выделить множе- ство степеней и оттенков. В простейшем случае речь идет лишь о «моделировании» случайного явления на компью- 84
тере, т. е. о «массовом производстве» некоторых резуль- татов. Например, программа 100 DIM А$(2) 110 А$ (0) = „1“ : А$ (1) = „F“ 120 FOR I = 1 ТО 20 130 А= INT(RND(0) * 2): В = INT (RND(0) *6+1) 140 PRINT A$(A); В 150 NEXT за несколько секунд производит 20 бросаний монет и игральных костей и выдает на экран («выписывает») ис- ходы этих бросаний (или, как принято говорить в теории вероятностей, испытаний). Программа будет работать еще быстрее, если исходы испытаний выводить на экран не «поштучно», а накапливать до конца программы*: 105 DIM Р(2) : DIM К(6) 140 Р(А) = Р(А) + 1 : К(В) = К(В) + 1 160 PRINT Р(0); А$(0), Р(1); А$(1) 170 FOR I = 1 ТО 6 : PRINT I, K(I); : NEXT I Такой вариант программы позволяет производить 100 и более бросаний. На дисплей выдается сразу вся после- довательность исходов испытаний, причем ждать прихо- дится всего лишь несколько секунд. Аналогичные про- граммы (позволяющие вычислять исходы бросания не- скольких игральных костей одновременно, извлечения шаров из урн, вероятности выигрыша в лото, таблицы стрельб и т. д.) часто используются при решении раз- личных задач теории вероятностей. Интересно сравнить три следующих варианта одно- временного бросания двух игральных костей (все три ва- рианта по-разному «встряхивают» игральные кости): а) 30 A = INT(RND(0) *11+2), б) 30 А = 2 * INT(RND(0) *6+1), в) 30 А = INT(RND(0) *6+1): B = INT(RND(0) *6+1) 35 С = А + В * Инструкция DIM указывает место массива, где хранятся пере- менные. 85
Рис. 15
С одной стороны, такое сравнение — нетривиальная задача по теории вероятностей для начинающего, с дру- гой стороны — хорошее упражнение для пользователя генератором псевдослучайных чисел. Те, кто хотя бы не- много сведущ в теории вероятностей, смогут проверить высокое качество генератора, вычислить вероятности и распределение вероятностей порождаемых им чисел. Программа, имитирующая бросание кости, открывает новые возможности в преподавании элементов теории вероятностей в начальной, средней и высшей школе, спо- собствует более глубокому пониманию учащимися веро- ятностных зависимостей. На рис. 15 показаны различ- ные варианты применения задачи об исходах бросания монеты. ДОСКА ГАЛЬЮНА Симметричное одномерное случайное блуждание (см. раздел «Случайное блуждание» в гл. I) можно промоде- лировать с помощью так называемой доски Гальтона (рис. 16). На n-м уровне на одинаковом расстоянии друг от друга вбито п шпеньков. Шарик, падающий на каждый шпенек сверху, с одинаковой вероятностью от- клоняется вправо и влево. Под промежутками между шпеньками самого нижнего уровня находятся специаль- ные отсеки, в которые попадают скатившиеся вниз шари- ки. Сколько шариков окажется в каждом отсеке, если всего сверху было пущено N шариков? Программа, моделирующая доску Гальтона, после за- 87
проса о размерах доски (количестве уровней, на которых вбиты шпеньки) и числе пропущенных шаров начнет медленно и красиво пускать один за другим точечные «рисованые» шары, и те, пройдя все препятствия, будут под аккомпанемент мелодичного звукового сигнала «шле- паться» в отсеки. В течение какого-то времени будут слышны только «удары» скатывающихся шаров, и число их в отсеках будет быстро расти. Если какой-нибудь отсек наполняется доверху, то происходит изменение масштаба: пять прежних точек «идут» за одну новую, что позволяет существенно увеличить емкость отсека. С доской Гальтона тесно связан известный треугольник Паскаля: 1 1 2 1 13 3 1 14 6 4 1 1 5 10 10 5 1 К каждому шпеньку (или развилке) ведут два пути: из промежутка между шпеньками предыдущего уровня яруса, расположенного справа, и из промежутка слева. В свою очередь, из каждой развилки шарик с вероят- 1 1 ностью покатится вниз влево и с вероятностью вниз вправо. Если р (fe, N) — вероятность того, что шарик достиг fe-ro (считая слева направо) шпенька (или попал в fe-ю урну) /V-го уровня, то p(fe, V) = P(fe + 1./V+ n + p(fe,/v+ I) t или после суммирования вероятностей в правой части р(4. A') = (t)/2". Величина (Jk') стоит на fe-м месте в /V-й строке треуголь- ника Паскаля, т. е. вероятности p(fe, N) при k — 1, 2, ..., N с точностью до множителя 2А совпадают с биномиаль- ными коэффициентами. Распределение вероятностей p(fe, У) заведомо не равномерное, так как в центре бино- миальные коэффициенты больше, чем по краям. На рис. 17 приведено распределение вероятностей для шариков на доске Гальтона при N — 8 и У = 12. Биномиальное распределение показывает, что можно рассматривать распределения вероятностей, отличные от 88
рк О ->N»8 X -> N» 12 Рис. 17 равномерного. Сведений, которыми мы располагаем, вполне достаточно для моделирования доски Гальтона: запускать сверху шарик и на каждом уровне, «бросая монету», решать, куда он отклонится (вправо или влево). Такое решение безупречно, точно и наглядно, но требует достаточно большого времени. (При 100 шарах компью- теру на это требуется не менее 10 с. Ясно, что такое занятие рано или поздно наскучит.) Так как вероятность попадания шарика в каждую из развилок известна, мы можем, исходя непосредственно из нее, оценить, сколько шариков окажутся в том или ином отсеке в конце пути. Ошибку моделировала бы ве- личина INT(RND(0) * N) + 1, поскольку, как мы уже упоминали, N/2 развилок в сере- дине каждого яруса находятся в «привилегированном» положении по сравнению с JV/2 развилками, располо- женными по краям. Мы поступим «справедливо», если на интервале (0, 1) пометим в порядке возрастания величи- ны вероятности p(fe, Af) и, породив на (0, 1) равномерное распределение случайных чисел, выберем соответствую- щий отсек (рис. 18). Например (при W = 8), 89
01 2 3 4 5 6 78 H-Ч—I------------1------------1----------1--Ш .035 .145 .364 .636 .855 .965 1 Puc. 18 0,5 -4; 0,2 -3; 0,85 5 и т. д. Прежде всего зададим точки разбиения интервала (0, 1): Q(fe) = Р(0) + Р(1) + ... +Р(&), где P(k) = p(k, 8). Тогда программа 10 FOR К = 1 ТО 100 20 А = RND(0) 30 FOR I = 0 ТО N 40 IF А>Q(I) THEN 60 50 V(I) = V(I) + I : 1 — N + 1 60 NEXT I 70 NEXT К позволит нам осуществить бросание на доске Гальтона 100 шаров. Это — более быстрое решение задачи, и опи- рается оно на приближенные значения биномиальных коэффициентов. В чисто педагогических целях полезно сравнить вероятности, получаемые при первом и втором способе моделирования с теоретическими значениями р. ДНИ РОЖДЕНИЯ Кто не знает, как удивительно легко решается следую- щая задача. В классе учатся 35 учеников. Какова веро- ятность того, что двое из них родились в один и тот же день? Пусть рп — вероятность того, что по крайней мере двое из п людей родились в один и тот же день. Если исключить високосные годы, то, как нетрудно видеть: 364 363 365 ‘ 365 ’ 364 363 (365 — п+0 365 ’ 365 ” ’ 365 90
(произведения дробей, вычитаемые из единицы, задают вероятность того, что все п человек родились в раз- личные дни). Зная эту зависимость, мы можем с помощью персо- нального компьютера подсчитать вероятность того, что двое из 35 учеников класса родились в один и тот же день, или ответить на вопрос, сколько людей нужно взять для того, чтобы с вероятностью 0,98 двое из них родились в один день. Программа для компьютера прежде всего «позаботит- ся» о дискретной функции P(N): необходимо оценить значения этой функции, соответствующие различным N. Если интуиция вводит в заблуждение, то программа «начертит» на экране дисплея кривую или укажет точные значения, попадающие в любой интересующий нас ин- тервал. После этого все готово к моделированию явле- ния: для группы лиц, численность которой введена с помощью инструкции INPUT, мы с помощью генератора псевдослучайных чисел порождаем даты — дни рожде- ния членов группы. Их мы помечаем светлыми пятныш- ками на предварительно начерченном на экране календа- ре. Всякий раз, когда чьи-то дни рождения совпадают, раздается звуковой сигнал, загорается условный знак и появляется комментарий. ВОПРОСЫ — ОТВЕТЫ ПРОГРАММИРОВАННОЕ ОБУЧЕНИЕ 1. Этот круг задач чаще всего предлагают начинаю- щим, которые не имеют предварительной подготовки. В самом простом случае от начинающего требуется лишь знание условной инструкции IF. Начальный этап обуче- ния строится по линейной схеме (рис. 19). Как показывает опыт, N вопросов такого рода дают возможность составить и обсудить программу, состоя- щую примерно из 5N инструкций. Это позволяет в какой- то мере оценить уровень начинающего программиста. Вместе с тем бросаются в глаза и уязвимые места такого способа обучения: несколько утомительное «косноязы- чие» большого числа однотипных инструкций, легкость, с которой угадывается правильный ответ и чрезмерная чувствительность оценки к форме ответа (например, если мы, отвечая на вопрос, употребим вместо слова «боль- 91
Рис. 19 шой» подходящие по смыслу слова «огромный» или «крупномасштабный», то наш ответ не будет признан правильным, так как в программе не предусмотрены си- нонимы). Весьма удобно, что при оценке ответов мы мо- жем не очень заботиться о выборе тем: инструкция по- зволяет без особого труда вводить в качестве исходных данных исторические даты, сведения по географии, дву- язычные словари, формулы химических соединений, пер- сонажей литературных произведений, орфографические правила и т. д. 2. Вопросы и ответы удобно хранить в памяти ком- пьютера в одинаковых по объему массивах так, чтобы вопрос и ответ на него входили в эти массивы под одинаковыми номерами. Например, если речь идет об исторических датах, то массив «вопросов» (названия исторических событий) и массив ответов могли бы вы- глядеть так: 92
А$ (1 )= «ЗОЛОТАЯ БУЛЛА», А$(2) = «МОХАЧСКАЯ БИТВА»,.... А(1) = 1222, А(2) = 1526,... С помощью цикла FOR существенно более короткая (по сравнению с предыдущей) программа позволяет «распоряжаться» уже массивом из 20—200 элементов. Вопросы и (правильные) ответы — именуемые в дальней- шем множеством данных—удобно хранить в операторе DATA и в случае необходимости заменять на новый набор вопросов и ответов. 100 PRINT «НАПИШИТЕ ДАТУ ИСТОРИЧЕСКОГО СОБЫТИЯ ПОСЛЕ ВОПРОСИТЕЛЬНОГО ЗНАКА» 120 FOR I = 1 ТО N 130 READ A$(I), B(I) : NEXT I 135 FOR I = 1 ТО N 140 PRINT A$ (I) 150 INPUT X 160 IF X = B(I) THEN PRINT «МОЛОДЕЦ» : H = H + 1 : GOTO 180 170 PRINT «НЕПРАВИЛЬНЫЙ ОТВЕТ»; В (I); «ПРАВИЛЬНЫЙ ОТВЕТ» 180 NEXT I 190 PRINT N; «ВОПРОС»; H; «ПРАВИЛЬНЫЙ ОТВЕТ» 3. Предыдущий вариант вопросов и ответов можно усовершенствовать так, чтобы вопросы задавались в слу- чайной последовательности. Вопросы можно «перемеши- вать» тремя известными нам способами (см. раздел «Пе- ремешивание» в этой главе), после чего выбирать любой из них. Наиболее быстрый вариант перемешивания (ос- нованный на использовании взаимно простых чисел) луч- ше всего подходит для наших целей. 4. Наряду со случайным выбором вопросов мы можем сделать так, чтобы компьютер выдавал на дисплей не- сколько «ответов», из которых требовалось бы выбрать правильный (т. е. пройти своеобразный тест). Такой вариант особенно привлекателен в том случае, когда на вопросы нельзя ответить просто «да» или «нет», а тре- буется дать более развернутый ответ, поскольку вместо того, чтобы вводить длинную строку символов, достаточ- но указать одно-единственное число (номер правильного ответа). Хорошо (но, разумеется, не обязательно), если правильный ответ появится на экране дисплея вместе с 93
2—5 случайно выбранными правдоподобными, но непра- вильными ответами. Следует иметь в виду, что 3-й и 4-й варианты вопро- сов и ответов могут быть включены в одну программу. Дело в том, что при случайном выборе из одного и того же множества данных вопросы могут быть двоякого рода: а) СТОЛИЦА ФРАНЦИИ — ??? (Вместо вопроси- тельных знаков испытуемый должен вписать название столицы Франции. Компьютер «ждет», какое значение будет придано переменной В$(1).) б) РИМ — СТОЛИЦА ??? (Вместо вопросительных знаков испытуемый должен вписать название страны. Компьютер «ждет», какой номер мы выберем — от 1-го до 4-го): 1. ШВЕЙЦАРИИ 2. ИТАЛИИ 3. ВЕЛИКОБРИТАНИИ 4. ВАТИКАНА Еще одна возможность состоит в том, чтобы в случае неправильного ответа предлагать испытуемому новый во- прос другого типа. Например, если в ответ на просьбу назвать столицу Швеции испытуемый назовет Осло, то компьютер, отметив специальным знаком, что ответ не- правильный, может задать вопрос: «Осло — столица ??? (какого государства?) либо вопрос «Столица Швеции — ??? (какой город?)». 5. Новая задача возлагается на программиста, если оценку правильности ответа требуется производить не по двухбалльной (правильный ответ — неправильный ответ) системе, а по более сложной шкале. Например, ясно, что тот, кто утверждает, будто восстание Дьердя Дожи (в действительности происшедшее в 1514 г.) произошло в 1524 г., ошибается меньше, чем тот, кто датирует восста- ние 1912 г. Правильность числовых данных сравнительно легко оценивать по величине отклонения. Что же каса- ется чисто качественных («словесных») данных, то оце- нивать степень их правильности гораздо труднее. Мы можем выделить некоторые свойства (атрибуты) вопросов и ответов и на основе их оценивать, между сколькими свойствами опрашиваемый установил пра- вильное соответствие. Например, если кто-нибудь при- пишет авторство «Моны Лизы» Бетховену, то тем самым он неверно определит не только вид искусства, но и 94
эпоху и страну происхождения. Аналогичным образом из двух химических веществ СН2О2 и Са(ОН)2 первое яв- ляется органическим соединением, кислотой и не содер- жит атомов металлов, в то время как второе вещество не обладает ни одним из этих трех свойств. Вместе с тем и СН2О2 и Са(ОН)2 содержат кислород, водород и даже гидроксильные радикалы. Хранение атрибутов требует больших объемов памяти, а их использование — известного опыта в преподавании предмета. Этот вариант вопросов и ответов разумно ис- пользовать при условии, если множество данных содер- жит 20—50 элементов. «БАР-КОХБА’» Возможен лишь один вариант: вопросы задает ком- пьютер и на основе полученных ответов выбирает соот- ветствующую «отгадку» из имеющегося у него в памяти запаса заранее заготовленных «отгадок». В простейшем случае поиск задуманного предмета осуществляется с помощью обхода вершин так называемого двоичного де- рева — графа. Например, предположим, что компьютер «задумал» какой-нибудь четырехугольник. Тогда двоич- ное дерево имеет такой вид, как показано на рис. 20. Рис. 20. * Распространенная игра, состоящая в отгадывании одним парт- нером того, что задумал другой партнер, с помощью вопросов, которые должны допускать только два ответа: либо «да», либо «нет».— Прим. пер. 95
Правда, каждая «партия» заканчивается всего лишь за три вопроса, но следует иметь в виду, что число возможных вариантов ответа достигает семи (если не различать симметричную и несимметричную трапеции). Для множества из N элементов такая программа долж- на состоять примерно из 5W инструкций. Нетрудно ви- деть, что игра «Бар-Кохба» во многом аналогична простейшему варианту игры в вопросы и ответы. Разли- чие состоит лишь в том, что поиск правильного ответа в игре «Бар-Кохба» носит нелинейный характер, и из-за огромного числа переходов GOTO программа становится труднообозримой: уже при 20—30 элементах требуется некоторый опыт. Ситуация отнюдь не упрощается, если компьютер оце- нивает ответы на второй и третий вопросы не порознь, а вместе: для того, чтобы различить варианты ответов — —, — +, + — и + +, в программе необходимо предусмотреть лишь 5 вопросов, но оценка правильности ответов при этом усложняется. Попарное оценивание от- ветов не всегда стоит затраченного труда, но может быть использовано в качестве упражнения в процессе обучения. Искусный игрок в «Бар-Кохбу» имеет шанс отгадать задуманный элемент множества из N элементов за INT (log (N)/log (2)) + 1 вопросов, «отсекая» каждым вопросом половину оставшегося множества элементов. Компьютеры редко достигают такого совершенства, но, например, следующие три вопроса позволяют во всех случаях отгадать любой из приведенных выше 8 четырех- угольников. 1. Обе ли пары противоположных сторон параллель- ны? 2. Есть ли у четырехугольника ось симметрии? (Этот вопрос мы задаем лишь при утвердительном ответе на первый вопрос. При отрицательном ответе на первый вопрос второй вопрос ставится иначе: обладает ли четы- рехугольник двумя осями симметрии?) 3. Входит ли в название четырехугольника буква «о», после которой не идет буква «м»? Если 1 обозначить утвердительный ответ («да»), а 0 — отрицательный («нет»), то различные четырехуголь- ники можно закодировать следующим образом: 96
Четырехугольник Ответы Двоичный номер Десятичны й номер Четырехугольник общего вида 000 0 1 Трапеция 001 1 2 Дельтоид* 0'0 10 3 Симметричная трапеция 0П 11 4 Параллелограмм 100 100 5 Квадрат 101 101 6 Ромб 110 но 7 Прямоугольник 111 111 8 Эта последовательность автоматически выбирает че- тырехугольник, соответствующий полученным ответам. Более того, в сложных случаях та же последовательность позволяет устанавливать, где именно при ответе на воп- рос нами была допущена ошибка. Например, если мы задумали ромб, а компьютер «выдал» дельтоид, то диаг- ноз причины сбоя однозначен: на вопрос «Обе ли пары противоположных сторон параллельны?» нам следовало ответить «Да» (тем самым мы изменили бы код с оши- бочного 010 на правильный 110). Как вопросы, так и элементы множества удобно хранить в виде символьных векторов. Если не считать этих данных, то предлагаемый вариант более «хитроумный», чем предыдущий, хотя и несколько длиннее. Гораздо интереснее, что принцип, положенный в осно- ву оптимальной стратегии игры «Бар-Кохба» (последо- вательное деление множества пополам), позволяет, на- пример, установить название любого европейского госу- * Дельтоид—четырехугольник, составленный из двух равно- бедренных треугольников, имеющих общее основание. 97
дарства (множество из 36 элементов) за 6 вопросов (программа из 50 инструкций), тогда как при обычном подходе для этого потребовалась бы программа, состоя- щая более чем из 100 инструкций, не говоря уже о том, что сама структура программы была бы гораздо сложнее. Перечень элементов множества, один из которых под- лежит угадыванию, следует приводить в самом начале работы программы (на что уйдет еще 5 инструкций). Это позволит избежать многих разочарований. Приведем несколько достаточно широких примерных тем: художники, писатели, деятели искусства, исторические личности; объекты на географической карте; персонажи литературных произведений; химические элементы, соединения, реакции; виды растений и животных; буквы, слова, выбранные по определенному признаку; геометрические фигуры и тела, преобразования, функ- ции; физические величины и единицы их измерения. В решении задачи на распознавание задуманного эле- мента множества следует выделить предварительную об- работку материала (кодирование) и написание програм- мы. Последний этап гораздо проще: по существу, речь идет о записи одного и того же алгоритма, производя- щего разбиение множества на две части в соответствии с заданными критериями, изменяются от программы к программе только исходные данные. Составление вопро- сов и кодирование предъявляют несравненно более высо- кие требования к познаниям в той или иной области нау- ки или другой человеческой деятельности. В случае мно- жеств, состоящих из 15—25 элементов, предварительная подготовка осуществляется легко, но когда число элемен- тов достигает 50, возникают серьезные трудности. Несколько выходя за рамки первоначально поставлен- ной задачи, более подготовленные читатели могут попы- таться составить программу, осуществляющую или по крайней мере облегчающую предварительную обработку материала. Входя с помощью инструкции INPUT по оче- реди в каждый вопрос, такая программа оценивала бы, насколько хорошо сгруппированы вопросы, после чего (снова с помощью инструкции (INPUT) позволяла бы, используя избыточность имеющихся данных, вносить соответствующие изменения. Более того, компьютер мо- 98
жет предлагать, какие еще элементы следовало бы вклю- чить в предварительную обработку, чтобы с помощью дополнительных вопросов проще разделить возможные варианты ответов. Отсюда лишь один шаг до создания рациональной си- стемы поиска (каталога), например, составления про- граммы-каталога. В частности, с помощью игровой про- граммы, составленной группой учащихся 7—8-х классов, можно найти интересующую тему по биологии: в ответ на вопрос компьютер приводит на дисплее несколько назва- ний и указывает ссылку для дальнейшего поиска. Один особый случай стоит того, чтобы рассмотреть его отдельно. Речь идет о варианте распространенной игры в вопросы и ответы «Бар-Кохба», в котором круг возможных вопросов ограничен вопросами типа: «Верно ли, что х меньше Л?» В простейшем случае (несравненно более простом, чем игра «Бар-Кохба» с отгадыванием задуманных слов) компьютер «задумывает» случайным образом выбранное целое число, например, какое-нибудь из чисел от 1 до 100. Играющий называет какое-то число. Если компьютер отвечает «Да», то это означает, что задуманное число меньше названного (ответ «Нет» означал бы, что заду- манное число больше названного или равно ему). Мы ви- дим, что, по существу, речь действительно идет об игре «Бар-Кохба», только не со словами, а с числами. Несколько сложнее вариант игры «Бар-Кохба» в том случае, если играющий задумывает какое-нибудь целое число, заключенное между числами А и В, а компьютер должен его найти. Опытный игрок определит задуманное число не более чем за f(B—А) = INT (LOG (В — А)/ /LOG (2)) 4- 1 вопросов. Нетрудно составить программу, которая не будет уступать самому искусному игроку. До- биться этого можно следующим образом: интервал, в ко- тором находится задуманное число, нужно как можно точнее делить пополам и, задавая очередной вопрос, сравнивать задуманное число с найденной серединой ин- тервала. Особенно эффектно игра протекает в том случае, ког- да компьютер и человек состязаются на равных, т. е. когда оба партнера по очереди меняются ролями (один партнер задумывает число, а другой отгадывает задуман- ное). Несколько исхитрившись, мы можем написать та- кую программу, что компьютер никогда не сможет про- 99
играть. При «задумывании» числа будем придерживать- ся следующей тактики: не будем ничего задумывать с самого начала, а на вопросы партнера условимся отве- чать так, чтобы всячески затруднять его задачу. Напри- мер, если в данный момент рассматривается интервал [X, Y] и наш партнер спрашивает: «Задуманное число меньше Z?», то в случае Z — X>*Y— Z мы отвечаем «Да» (задуманное число меньше Z, т. е. принадлежит интервалу [X, Z—1]). При такой тактике мы заведомо не впадаем в противоречие и в конце концов (когда речь может идти лишь об «интервале» [X, X]) объявляем X «задуманным числом». Избранная тактика полностью устраняет из игры случайный успех и гарантирует, что число вопросов совпадает с приведенной выше оценкой f(B—А). Другая сторона (когда играющий задумывает число), т. е. компьютер, может действовать успешнее и отгадать задуманное число за меньшее количество проб. Еще один вариант игры в вопросы и ответы (отличный от игры «Бар-Кохба») встречается в том случае, если требуется отгадать сразу два числа, и ответы могут быть трех типов (названное число меньше задуманных чисел, заключено между ними или больше их). Установить числа можно, задав не более чем f(B — А) = INT (LOG(В — — A)/LOG(3)) + 1 вопросов. ПОИСК НА ЭКРАНЕ ДИСПЛЕЯ Игра состоит в следующем. Компьютер «прячет» что- то на экране дисплея. Задача играющего состоит в том, чтобы найти спрятанное. Для этого он может либо зада- вать координаты точки, либо перемещать по экрану све- тящуюся точку (или символ). Для того чтобы пере- местить точку вправо-влево, вверх-вниз, в большин- стве персональных компьютеров предусмотрены специ- альные клавиши (соответствующие инструкциям INKEY$, INP, РЕЕК и т. д.). В тех компьютерах, где таких удобств нет, можно воспользоваться инструкцией INPUT. Компьютер оценивает, насколько удачна предпринятая попытка,— показывает, как близко мы подошли к спря- танной точке. Сделать это можно по-разному, например: 1) чем ближе мы подходим к спрятанной точке, тем крупнее цифра появляется на экране: 2) с помощью специального указателя направления; 100
3) указывая сумму отклонений от спрятанной точки по горизонтали и вертикали; 4) задавая расстояние до спрятанной точки. Игры такого рода позволяют реализовать бесчислен- ное множество идей (известно около 20—25 различных вариантов игры). Особенно благодарна тема «сцени- ческих перевоплощений», но немалые возможности таит в себе и обработка информации. В качестве примеров мы рассмотрим более подробно три программы, стремясь продемонстрировать в них в концентрированном виде многие идеи. Тепло — холодно (игра для детей от 6 до 12 лет) Где-то на экране (квадратной решетке размером не более 40X60) «спрятан» символ. В исходном положении в левом нижнем углу находится звездочка. При нажатии клавиш I, J, К, М звездочка начинает перемещаться соответственно вверх, вниз, вправо и влево. Движется она с регулируемой скоростью до тех пор, пока играющий не остановит ее, нажав на клавишу. Когда, по мнению играющего, звездочка совместится с точкой, в которой находится спрятанный символ, он нажимает клавишу Р. Вместо звездочки можно использовать какую-нибудь цифру: чем ближе мы подходим к месту, где спрятан символ, тем крупнее становится сигнальная цифра. Мухи (игра для детей среднего и старшего школьного возраста) На квадратной сетке 10X10 прячутся 4 мухи. Их не- обходимо найти, набрав на клавиатуре координаты тех точек, где они находятся. После каждой попытки на эк- ране появляются расстояния (с точностью до одной деся- той) между точкой, координаты которой были набраны, и мухами (точками, в которых «прячутся» мухи). Если координаты мухи угаданы верно, то игрок заслуживает поощрения, и на экране в том месте, где «пряталась» муха, появляется особый знак — своего рода отличная оценка. Когда на экране останутся расстояния до двух последних мух, игра станет несколько труднее. Искусные игроки обнаруживают все 4 мухи за 6 попы- ток. Для того чтобы добиться успеха за меньшее число попыток, необходимо известное «везение». Если число по- 101
пыток превышает 10, то над незадачливым игроком мож- но и поиронизировать. В обучающем варианте программы компьютер может сигнализировать после промаха (неверно указанных ко- ординат мухи) о том, что игрок действует непоследова- тельно. Предположим, например, что на сетке остались только две мухи, и после попытки обнаружить одну из них в точке с координатами (5, 5) выяснилось, что рас- стояние до одной из них составляет 1,4 а расстояние до другой 1. Компьютер можно запрограммировать так, чтобы он в этом случае «разрешал» производить только такие попытки, при которых координаты новой точки отличались бы от координат предыдущей не более чем на 1, т. е. от точки (5, 5) можно было переходить к точ- кам (4, 5), (5, 6), (6, 4) и т. д. Более точную оценку можно производить, если при каждой попытке (начиная с третьей) заранее указывать, за какой из мух мы предпочитаем охотиться. В этом слу- чае компьютер должен принимать лишь такие ходы, ко- торые (в соответствии с выбранной мухой) приближают нас к цели. Компьютер может задавать и более трудные задачи. Например, гораздо сложнее попасть в точку, если она медленно движется в некотором заданном направлении. Направление целесообразно выбрать с самого начала. Даже в одномерном случае попасть в движущуюся точку довольно трудно. Предположим, что кто-нибудь задумы- вает целое число между 0 и 30 и при каждой попытке отгадать задуманное число увеличивает его по следующе- му правилу: если названное число меньше задуманного, то к задуманному прибавляется разность, а если названное число больше задуманного, то — удвоенная разность. Например, если задумано число 17, а названо число 13, то новое значение задуманного числа равно 21; если же задумано число 17, а названо число 21, то новое значение задуманного числа равно 25. Играть в эту игру нелегко. Не стоит допускать, чтобы подвижное число выходило за пределы 100, так как при этом «попадание» становится почти безнадежным. В этой игре существует выигрышная стратегия, позволяющая отгадать задуманное числб не более чем за 6 ходов. Описанную выше «охоту на мух» можно усложнить, если предусмотреть в программе отве- ты не «да-нет», а четырех типов или если выводить каждый раз на Дисплей не всю информацию (например, 102
сначала показывать расстояние только до 1-й мухи, затем только до 2-й, 3-й и т. д.). В пространственном случае «регистрировать» мух и корректировать попадания ста- новится труднее, отчего игра приобретает особый инте- рес. Если играющий прячет мух, а компьютер их отыски- вает, то для составления программы требуется знать аналитическую геометрию, и программа получается не- простой. В этом случае удобно предусмотреть подпро- граммы для определения коэффициентов прямых раз- личного вида и решения соответствующих уравнений. Если мишень (области, где прячутся мухи) достаточно мала или поиски сосредоточены на достаточно узкой части экрана, разумно производить предварительную оценку очередного хода, т. е. проверять, согласуется ли будущая точка с уже имеющейся информацией. Действуя методом исключений, мы рано или поздно попадем в нуж- ную точку, но число шагов при этом может быть доста- точно велико. Программу можно записать гораздо про- ще. Немая карта Одно из применений, которое находит в учебном про- цессе поиск по экрану, связан с вычерчиванием карт, точнее, построением немых карт. Речь идет о тех же приемах, которые были описаны в гл. II при построении графиков, с тем лишь отличием, что теперь мы имеем де- ло с рисунками, состоящими из 100 и более точек. По существу, возможны два варианта построения карт: с тонким и грубым разбиением экрана дисплея. При тонком разбиении (линия состоит более чем из 100 точек) мы выбираем несколько (от 10 до 30) харак- терных точек перелома и только эти координаты и вво- дим в память компьютера. Запись 86.29 означает, что заданные концы отрезка: 86; 29; необходимо лишь со- единить точки. Рисунок легко увеличить, не составляет особого труда и повернуть его (см. раздел «Элементы изображения» в гл. II). Разумеется, при выборе точек излома следует соблюдать «верность» рисунку: чем боль- ше опорных точек и чем удачнее они расположены, тем сильнее будет сходство копии на экране с оригиналом. Иначе строится изображение при грубом разбиении экрана. В этом случае любую точку можно записать в память в виде следующего массива: ' 103
8 1 2 7X3 6 5 4 «Соседи» позиции, обозначенной X, закодированы по часовой стрелке, начиная с цифры 1, стоящей «на Г2 часах». Каждая цифра показывает, куда надлежит сде- лать следующий шаг (рис. 21). Например, отрезок линии кодируется последовательностью цифр 3, 4, 4, 3, 3, 5, 6. Ее можно «сжать», записав в виде отрезка десятичной дроби 0,3443356. При такой записи 100 точек можно хра- нить в памяти в виде 12—13 данных. Необходимо также позаботиться о начальной точке. Чтобы как-то выделить ее, удобно воспользоваться отрицательными числами. Рис. 21 Возможно, что кто-нибудь сочтет увеличение изобра- жения не слишком простой операцией. Зато поворот изображения на угол, кратный 90°, осуществляется весь- ма просто: стоит лишь обратить внимание, что подстанов- ка 1оЗ, 2о4, ..., 7о1, 8о2 соответствует повороту на прямой угол по часовой стрелке. Ясно, что при поворо- те нужно особо позаботиться о выборе начальной точки. Повернуть изображение на угол, не кратный прямому, несколько сложнее. Описанные выше средства позволяют без особого тру- да составить программу для проверки знаний по геогра- фии: построить на экране дисплея немую карту с несколь- кими мерцающими точками и списком названий городов, из которых требуется выбрать правильные. Для того что- бы усложнить задачу, карту можно случайным образом повернуть и даже убрать часть линий (стереть их после появления на дисплее). Например, при среднем знании 104
карты каждый элемент, представленный на ней, можно стирать с вероятностью 0,1, а при отличном знании кар- ты — с вероятностью 0,5. Следует заметить, что идея, заложенная в такой про- грамме, допускает дальнейшее развитие. Можно попы- таться, например, самому нарисовать карту (см. управле- ние!), хранящуюся в памяти компьютера, чтобы тот за- тем сравнил нарисованную карту с эталонной. Оценивать нарисованную карту необходимо «по справедливости». Разумеется, вполне можно представить себе, что опытный художник или картограф вычертит на экране дисплея идеальный рисунок, который в точности соответствует данным, хранящимся в памяти компьютера. Однако нельзя забывать и о том, что «глупый» компьютер весьма остро воспримет малейшие отклонения от эталона и со- чтет их ошибкой. Целесообразно поэтому выделить зара- нее несколько точек — ориентиров и выставлять за нари- сованную карту тем более низкую оценку, чем больше на ней ошибок. При этом на начальной стадии построения карты следует обращать внимание рисующего на откло- нения от ориентиров с помощью звуковых или каких- нибудь других сигналов и оценивать лишь (более серьез- ные) ошибки, допущенные на завершающих этапах. ФИЗИКА Попытаемся показать, что компьютеры имеют в пре- подавании школьных предметов широчайшую область применения. Практически необозримые возможности под- час весьма хитроумного использования компьютера от- крываются и перед теми, кто лишь недавно приступил к изучению предмета, и перед теми, кто уже успел при- обрести основательные познания. Мы отнюдь не стремимся к подробному изложению многообразных связей между преподаванием физики и использованием персональных компьютеров, а вместо этого попытаемся привести несколько примеров, выбрав их на свой вкус. Попутно мы обрисуем в общих чертах несколько идей относительно того, каким образом можно придать наглядность физически значимой детали (фор- муле или зависимости) или изложить соответствующий раздел в игровой форме. Разумеется, эти идеи адресованы главным образом тем, кто любит предмет. Для реализации приводимых 105
ниже программ и рекомендаций необходимы кое-какие познания из области физики, а для понимания некото- рых вещей (изменения потенциала, механики полетов космических кораблей) существен определенный опыт. ЗАКОН АРХИМЕДА «Всякое тело, погруженное в жидкость, теряет в своем весе столько, сколько весит жидкость в объеме погружен- ной части тела». Хотя это «заклинание» знает всякий школьник, физи- ческое содержание закона Архимеда понятно далеко не всегда и не каждому. Прежде всего уточним формулиров- ку закона: речь идет не о любой жидкости. После первоначального ознакомления с законом Ар- химеда можно составить программу, позволяющую по- практиковаться в его примененйи на вполне наглядных примерах. В ванну постоянного объема помещено геомет- рическое тело постоянного объема. Предварительно в компьютер необходимо ввести данные о весе тела и удельном весе вытесняемой жидкости. По этим данным (в том или ином варианте) программа определяет усло- вие плавучести. Для простоты и большего удобства при оперировании с графикой жидкость наливается в ванну не непрерывно, а определенными количествами (порция- ми). После добавления каждой такой порции программа проверяет, выполняется ли условие плавучести. По зако- ну Архимеда для этого требуется, чтобы выполнялось равенство XF = G, где G — вес тела, F — удельный вес вытесняемой жидкости, X — объем погруженной части тела. Последнюю каждый раз необходимо вычислять за- ново, так как по мере прибавления жидкости в нее погружается все большая часть объема тела. Вычислять объем прямоугольного параллелепипеда («кирпича») очень легко, но на картинке можно взять тело несколько более сложной формы. Составленная программа «Физи- ка» может иметь, например, следующий вид: 200 FOR J = 1TO J9 210 V = V+ 1 :X = X+ 1 220 IF F * X> = G THEN PRINT «ПЛАВАЕТ» END 230 IF V = A(J) THEN V == 0 GOTO 250 106
240 GOTO 210 250 NEXT J где J9 — вместимость ванны, A(J)—число порций жид- кости, заполняющих ванну до J-ro уровня. Более поучительны активные варианты программы. Например, жидкость наливается в ванну десятикратными порциями, и на экране дисплея каждый раз возникает вопрос: будет ли тело теперь плавать или нет? Возмо- жен и другой вариант. Учащийся наливает в ванну лю- бое количество жидкости, после чего должен ответить на вопрос, всплывет ли тело, затем наливает снова неко- торое количество жидкости и т. д. Цель состоит в том, чтобы за меньшее число проб налить в ванну такое количество воды, при котором вес тела будет уравнове- шен выталкивающей силой, и тело всплывет. В качестве курьеза упомянем о пространственном ва- рианте задачи (до сих пор речь шла в действительности о плоских фигурах). Сама программа не претерпит из- менений (модифицировать придется только значения A(J)), но иллюстрации к закону Архимеда станут более интересными! ИЗМЕНЕНИЕ ПОТЕНЦИАЛА Эта программа вычерчивает эквипотенциальные ли- нии электростатического поля. Силовые линии электро- статического поля (аналогичные силовым линиям маг- нитного поля, вдоль которых выстраиваются мелкие же- лезные частицы) перпендикулярны эквипотенциальным линиям в точках пересечения. Эквипотенциальная ли- ния — это линия постоянного потенциала. Программа начинается с того, что в центре экрана появляется светящаяся точка. Как уже хорошо известно, ее можно передвигать нажатием клавиш I, J, К, М. Действуя таким способом, расположим на экране не- сколько точечных зарядов (величина каждого заряда задана), а затем, начиная с произвольно заданной точки, компьютер нарисует эквипотенциальные линии. Нажатием клавиши вычерчивание эквипотенциали можно прервать и продолжить из начальной точки в противоположном направлении. Построение эквипотен- циальной линии также завершается после нажатия кла- виши, после чего на экране появится светящаяся точ- ка — начало новой эквипотенциальной линии и т. д. 107
Механизм вычерчивания заключается в следующем. Достроив линию до какого-то места, компьютер переби- рает пять ближайших соседей последней точки кривой (рис. 22) и выбирает из них ту точку, в которой значение потенциала ближе всего подходит к значению потенциала, вычисленному в начальной точке. Для большей скорости продвижения компьютер может просматривать значения в точках (их снова пять), расположенных на один шаг дальше, чем ближайшие соседи (рис. 23). • • Рис. ‘23. Для ускорения эквипотенциальная линия заменяется ломаной с вершинами в выбранных точках. Процесс по- строения можно замедлить, рассматривая ближайших со- седей. О точности быстрого или медленного способа по- строения эквипотенциальной линии можно судить только по более тонкому графику. Приведенный выше чисто демонстрационный вариант вычерчивания эквипотенциалей нетрудно превратить в учебный. После того как на экране компьютера засветит- ся начальная точка кривой, можно «зажечь» еще одну произвольную точку. Выбирать ее так, чтобы она оказа- лась на одной эквипотенциальной линии с начальной точ- кой, следует только с помощью клавиш I 4- М (или J -~ 4-К). Компьютер оценивает, насколько удачной была предпринятая попытка. В исключительных случаях уча- щийся может попытаться построить целиком всю эквипо- тенциальную линию (см. раздел «Немая карта»). Про- верка (оценка) правильности построения—особо труд- ная задача. Следует отметить, что эта программа по своей слож- 108
ности, многосторонности, возможно, несколько выходит за пределы обычных школьных программ. Решаемая за- дача под силу лишь сведущему в физике человеку, и даже облегченный вариант ее достаточно трудно пред- ставить графически. В некоторое оправдание скажем, что такая программа была составлена школьниками второго (!) класса, причем совершенно самостоятельно. Они сами нашли задачу, разобрались, как построить линии равного потенциала, и составили программу. СВОБОДНО БРОШЕННОЕ ТЕЛО— ПЛАНЕТЫ — КОСМИЧЕСКИЕ КОРАБЛИ Начнем с (графического) моделирования настоятель- но рекомендуемой задачи о свободно брошенном теле. Точку пространства, в котором будет находиться в мо- мент времени Т свободно брошенное тело, нетрудно вы- числить и представить на графике как функцию от угла А к горизонту и начальной скорости V: 100 Cl = V* COS (A) :C2 = V* SIN(A) 110 FOR T= 1 TO 60 120 X = T* Cl : Y = C2*T — 9.81 *T*T/2 130 PLOT X, Y 140 NEXT T где X и Y — горизонтальная и вертикальная координаты точки. Ясно, что необходимо особо позаботиться о том, чтобы тело «не вылетело» за пределы экрана (см. гл. II). Программу можно использовать при изучении темы «движение свободно брошенного тела» не только для по- строения траектории. Можно «научить» программу попа- дать в случайно выбранную точку с помощью надлежа- щего выбора угла А и начальной скорости V. Задачу можно также усложнить, поставив перед целью преграду или приняв во внимание свойства среды, в которой дви- жется свободно брошенное тело. Более сложные механические зависимости возникают при моделировании траекторий планет и искусственных спутников Земли. Например, с какой начальной ско- ростью следует запускать искусственный спутник для того, чтобы он мог вернуться на Землю, начал обращать- ся по околоземной орбите или покинул Солнечную систе- му (т. е. для того, чтобы орбита спутника была параболи- ческой, эллиптической или гиперболической)? В школь- 109
ный курс физики входят законы движения планет Кеп- лера. Для их иллюстрации также подходит учебная про- грамма. Весьма интересно и поучительно пространствен- ное движение тел. Более сложная игра (и, разумеется, более сложная программа) связана с прослеживанием траектории кос- мического корабля, совершающего полет на Луну. Для того чтобы космический корабль не разбился, а совер- шил мягкую посадку, он должен при подлете к поверх- ности Луны затормозить. Наряду с силой лунного притя- жения и энергетическим балансом при расчете мягкой посадки необходимо учитывать и ту часть энергии, кото- рая расходуется на торможение. Выбор рациональной стратегии, которой следует придерживаться при мягкой посадке, описывается достаточно сложными зависимостя- ми. Один из возможных вариантов программы состоит в том, что компьютер задает (случайным образом) пара- метры траектории космического корабля, его массу и ко- личество топлива, предназначенного для полета. В опре- деленные моменты времени в программу можно вмеши- ваться: варьировать энергию, затрачиваемую на тормо- жение, изменять скорость космического корабля и зави- сящие от нее параметры, смотреть, к чему приводят вводимые поправки. Наконец, программа должна дать ответ на вопрос, какого размера кратер образуется на поверхности Луны, если наш космический корабль не сумеет погасить скорость. Сейчас мы продемонстрируем программу, позволяю- щую воспроизводить на экране дисплея траекторию ис- кусственного спутника. Составили ее школьники для стандартного компьютера, которым оснащены многие венгерские школы. Прежде чем мы перейдем к распечатке программы, необходимо сделать несколько предварительных замеча- ний*. Во 2-й строке под действием инструкции PRINT CHR$ (23) компьютер пишет в разрядку. Действие этой инструк- ции прекращается при стирании экрана (по инструкции CLS). * При записи программы на языке БЕЙСИК для отечественных школьных компьютеров при определении порции ввода символа на экран можно использовать функцию АТ, а для рисования изображений операторы DRAW, RSET и PRSET. — Прим. ред. 1 10
В инструкции типа PRINT NNN... после @ стоит чис- ло, указывающее место, где должен быть напечатан в первой строке символ от 0-го до 63-го, во второй стро- ке— от 64-го до 127-го и в последней, 16-й строке — от 960-го до 1023-го. Основным «изобразительным средством» служит инст- рукция SET(X, Y), по которой на экране дисплея появ- ляется заданный элемент изображения (координатная сеть делит экран на 48 квадратных клеток по вертикали и 128 клеток по горизонтали). По инструкции RESET (X, Y) элемент изображения, введенный инструкцией SET, исчезает с экрана. При изменении траектории впи- сываемое значение программа может прочитать как сим- вол (до символа NEWLINE). Введенный в компьютер символ не появляется на экране сам собой: для этого после инструкции INKEY$, необходимо воспользоваться командой PRINT. Не рекомендуется пользоваться ин- струкцией PAUSE в тех случаях, когда по ходу програм- мы требуется подождать,— для этого лучше воспользо- ваться пустым циклом. В инструкции NEXT не нужно указывать переменную цикла. Если в инструкции NEXT выписать переменную цикла, то одна инструкция NEXT может означать оконча- ние нескольких циклов, как это происходит в 12-й строке. 2 CLS : PRINT CHR$ (23) : PRINT© 276, «ТРАЕКТОРИЯ ИСКУССТВЕННОГО СПУТНИКА ЗЕМЛИ» 6 PRINT @516, «ЭТА ПРОГРАММА ТРАЕКТОРИИ ИСКУССТВЕННОГО СПУТНИКА ЗЕМЛИ»: PRINT @ 590, «ВЫЧИСЛЯЕТ И ВЫЧЕРЧИВАЕТ» 7 PRINT @ 704, «ТРАЕКТОРИЮ СПУТНИКА МОЖНО ИЗМЕНИТЬ» 8 PRINT @ 768, «НАЖАТИЕМ КЛАВИШИ М» 11 FOR Л = О ТО 3000 : NEXT 15 CLS : PRINT @ 716, «ПРОГРАММА ВЫПИСЫВАЕТ СЛЕДУЮЩИЕ ДАННЫЕ:» 16 PRINT @ 832, «КООРДИНАТЫ X, Y; СКОРОСТИ ПО ОСЯМ X, Y» 17 PRINT @ 896, «СКОРОСТЬ ВЫСОТА ВРЕМЯ» 18 FOR Л = 0 ТО 2000 : NEXT : CLS 19 PRINT @ 776, «НОВАЯ СКОРОСТЬ VX ПО ОСИ X»;: PRINT 916, «ПРИ ИЗМЕНЕНИИ 111
ТРАЕКТОРИИ» FOR Л =0 ТО 2000: NEXT 20 DATA 40, 300, 0, 6500, 9.5, 0, 398000 25 READ DT, KT, X, Y, VX, VY, К 40 FOR SZ = 0 TO 6.23818 STEP. 3142 42 SET (63+ 12* COS(SZ), 10 — 6 + SIN(SZ)) 44 NEXT 46 PRINT© 221, «ЗЕМЛЯ» 48 R = SQR (X + X + Y * Y) 50 FOR T = 0 TO 10000 STER KT 60 PRINT @ 960, „Х=“; X; ,,Y=“; Y- VX=“- VX- VY=“- VY 65 PRINT @ 2, ,,V=“; V; «КМ/ 4» „М=“; M; «ТОНН=»; T; «СЕК» 70 XK = X/500 + 63 : YK= 10 —Y/1000 72 IF XK<0 OR XK> 127 OR YK<0 OR YK>47 THEN 79 75 SET(XK, YK) 79 V = SQR (VX + VX + VY + VY) 87 IF R < 6370 PRINT @ 659, «КАТАСТРОФА»;: GOTO 87 90 A$ = INKEYS: IF A$ < > ,,M“ THEN !00 91 SET (62, 12): PRINT @768, «ИЗМЕНЯТЬ ТРАЕКТОРИЮ?»; 92 C$ = „ “ 93 B$ = INKEY$: IF B$ = „ “ THEN 93 94 C$ = C$ + B$: PRINT B$ 95 IF ASC(B$)<10 OR ASC(B$) > 13 THEN 93 97 VX = VX + VAL(C$) : RESET (63, 12) 100 FOR I = 0 TO KT STEP DT 110 X = X + VX * DT : Y = Y + VY + DT R==SQR(X * X + Y * Y) 115 VX = VX— K/R f 3 + X + DT VY = VY — K/R f 3 * Y * DT 118 M = SQR (X * X + Y * Y) — 6370 120 NEXT I, T 130 END Перечислим еще несколько возможных тем для про- граммирования на школьном компьютере. Силы и их равнодействующие. 112
Моделирование столкновений. Бильярд, не обязательно на прямоугольном столе. Статика. Например, выстраивание пирамиды из N кирпичей, каждый из которых «нависает» над предыду- щим, но не опрокидывается. Оптика. Отражение, преломление, дифракция, интер- ференция света, фотоэлектрический эффект и т. д. Кинетическая теория газов. Модель идеального газа. Поверхностное натяжение, образование поверхност- ной пленки в жидкостях, образование капель. Постоянный и переменный электрический ток. Моделирование процесса заряда конденсаторов. Графическая интерпретация законов Кирхгофа. Действие осциллографа. Строение атома, а-, р- и у-излучение. МОДЕЛИРОВАНИЕ Думаю, что вряд ли найдется хоть один программист, у которого при этом слове не забилось бы учащенно сердце. Моделированию (на аналоговых и цифровых) ЭВМ посвящена обширная литература, и в действитель- ности математическое моделирование различных процес- сов представляет собой поистине наиболее волнующую и разнообразную область применения компьютеров. Зани- маться моделированием можно на всех уровнях, но спра- ведливости ради следует заметить, что чем выше мастер- ство программиста, тем более широкие возможности от- крываются перед ним и тем большее удовлетворение приносит ему моделирование. Вместо того чтобы пытаться сформулировать общие определения, относящиеся к математическому моделиро- ванию, мы приведем несколько примеров, из которых станет ясно, чем оно занимается. Необходимо упомянуть о том, что существуют так называемые языки программирования, специально пред- назначенные для математического моделирования (CLS, GPSS, SIMSCRIPT, SIMULA 67 и т. д.), вообще говоря, рассчитанные на большие ЭВМ. Использование этих языков предъявляет достаточно высокие требования не только к знанию алгоритмического языка, но и к компью- теру. Поэтому в дальнейшем речь пойдет лишь о приме- рах использования для нужд математического моделиро- 113
вания только весьма простого языка БЕЙСИК. Такой подход позволяет нам познакомить начинающих с наибо- лее существенным в моделировании, акцентируя особое внимание на приложениях. Среди приведенных выше примеров немало таких, в которых речь шла о модели- ровании — от бросания монеты до полета свободно бро- шенного тела. Теперь мы продемонстрируем несколько программ, позволяющих моделировать биологические и экономические явления. хищники и жертвы Программа моделирует конфликт, возникающий при взаимодействии трех популяций (лисы (хищники), зайцы (жертвы) и трава (пищевой ресурс для жертв). В биоло- гии популяцией называют группу особей одного вида, между которыми существуют тесные взаимосвязи. Про- грамма описывает поведение сложной системы, в кото- рой виды каждой из популяций существуют во взаимо- действии: зайцы поедают траву, лисы поедают зайцев, умирая, зайцы и лисы удобряют почву, на которой рас- тет трава. Кроме того, без лис зайцы начинают чрезмер- но размножаться. Число особей животных каждого из двух видов изменяется в зависимости от произведения численностей популяций зайцев и лис. Изменение числен- ности каждой из таких «взаимодействующих» популяций обычно описывают дифференциальными уравнениями, задающими рекуррентные зависимости Nk+i = Nk (a — bRk\ Rk+\ = Rk (с — bNk), где Ni — численность популяции зайцев, Ri— числен- ность популяции лис в z-й момент времени. Величины Ni и Ri зависят от значений M-i, Ri-\, принимаемых теми же величинами в предыдущей (т. е. i— 1-й) момент времени и от параметров а, b и с, определяющих рождае- мость и смертность каждой из популяций. Рекуррентные соотношения позволяют по известным начальным значениям Ro и No вычислить шаг за шагом численность популяций Rk и Nk в k-й момент времени. При достаточно больших k становится ясной суть проис- ходящего процесса: вымирает ли при заданных значени- ях параметров один из видов (например, при fe>0,3; а = 0,8; с = 1 популяция зайцев исчезает довольно 114
быстро) или между видами устанавливается равновесие. Для большей наглядности можно поступить следую- щим образом. Разделим экран дисплея К строками и М столбцами на К X М клеток. С помощью инструкции INPUT зададим начальные численности зайцев (N) и лис (R), изобразив в N клетках по зайцу и в R клетках по лисе (на всем поле из КХМ клеток «растет» трава). Зададим также «аппетит» каждого из видов животных, оценив его числами Ei и Е2. Выбрав случайным образом клетку, изменив ее флору и фауну по следующим пра- вилам: трава с вероятностью Ei превращается в кролика; кролик с вероятностью Е2 превращается в лису; оба вида животных превращаются в траву, если в од- ной из соседних клеток для них нет корма. В более сложном (но и более реалистическом) вари- анте вероятности Еь Е2 зависят от «окружающей среды». Например, трава «превращается» в кролика, если в со- седней клетке уже был крольчонок (который, таким обра- зом, размножился). «Пейзаж» (распределения заселенности) изменяется достаточно быстро, причем вместо довольно загадочных параметров в приведенной выше формуле мы имеем дело с удобообозримыми и понятными факторами. Особенно интересно записать в виде массива числа N(K) и R(K) при различных значениях К и потом воспроизвести чис- ленность зайцев и лис как функции времени. Поучитель- но сравнить две модели: рекуррентные соотношения и клетки КХМ. Такое сравнение позволит уяснить смысл параметров а, Ь, с. Интересно также построить функции N(K) и R(K) при различных значениях N, R, Ei и Е2, а также оценить влияние случайных изменений при одина- ковых параметрах. ЖИВОТНОВОДЧЕСКАЯ ФЕРМА Это типичная экономическая игра. Она аналогична рассмотренной нами задаче о хищниках и жертвах, но носит более активный и игровой характер. Играющий как бы становится владельцем животноводческой фермы, на которой вначале имеется 100 голов молодняка, 100 голов взрослых животных и 100 голов старых животных. Жи- вотные размножаются по определенным правилам. В на- чале игры фермер заключает контракт с торговцем скота 115
сроком на N лет, по которому обязуется ежегодно прода- вать тому определенное число голов молодняка, взрослых и старых животных. Эти числа вводятся в компьютер. Для того чтобы выбрать их, необходимо иметь в виду рождае- мость и смертность животных. Изменение в поголовье на ферме графически можно представить в виде схемы, приведенной на рис. 24. b Рис. 24 Численность поголовья молодняка, взрослых и старых животных определяется соотношениями Xi (k 4- 1) = ах2 (k) 4- Ьхз (&) х2 (k + 1) = Xi (k) Хз(Ь + 1) = Х2 (k) + схз (£), (где а, b — рождаемость у взрослых и старых животных, (1 —с) — смертность старых животных). Рентабельность ведения хозяйства оценивается по результатам за N лет. Фермер плохо ведет хозяйство, если в какой-то год у него не окажется нужного числа голов скота на продажу, если животные чрезмерно раз- множатся (для их содержания потребуется слишком много корма!) или если произойдет сильный падеж ско- та. Главная цель состоит в получении наибольшей прибы- ли от продажи обусловленного в контракте числа голов молодняка, взрослых и старых животных (животные раз- ного возраста идут по различной цене). В этой игре «фермеру» приходится действовать в рам- ках известных, но достаточно сложных зависимостей и достигать в том или ином смысле оптимума. В общем случае решение задачи может быть найдено «методом проб и ошибок». Особенно труден вариант, когда в начале периода из W лет устанавливается посто- янная доля поголовья, ежегодно продаваемая торговцу скотом. 116
В начале первого раздела мы высказали уверенность в том, что персональный компьютер может найти самое разнообразное применение в преподавании школьного курса физики. Но, пожалуй, не менее широкое примене- ние персональный компьютер может найти в преподава- нии других естественных наук. Точнее говоря, персональ- ный компьютер позволяет познакомить учащихся с таким математическим аппаратом (например, дифференциаль- ными уравнениями, статистикой, моделированием), ко- торый находит применение при описании химических или биологических явлений и их моделировании. В качестве примера назовем лишь несколько таких задач: химическое равновесие, динамика равновесных хими- ческих систем; изменение концентраций реагирующих веществ; химическая кинетика, моделирование хода реакций р-го порядка во времени; стехиометрия, решение задач типа масса-масса, объем-объем, масса-объем; действие ферментов, скорость ферментативных реак- ций; изменение скорости фотосинтеза в зависимости от концентрации двуокиси углерода и интенсивности света; диффузия, осмос; моделирование процессов образования облаков; формирование климатических условий; экономические игры, выбор оптимальной стратегии. ПРОЦЕССЫ ПОИСКА Давайте теперь познакомимся с составными програм- мами, рисующими графики. Части этих программ пред- ставляют самостоятельный интерес. Затем мы подробно изложим известный метод ветвей и границ. Наконец, на нескольких примерах мы покажем, как применяется этот процесс поиска. ГРАФЫ Программа прежде всего рисует на экране дисплея 4—10 точек, после чего соединяет их случайным образом отрезками прямых. Получается некоторый граф. Опреде- лим порядок каждой его вершины, т. е. число «торчащих» из нее отрезков, называемых ребрами графа, после чего 117
компьютер задаст нам вопрос: можно ли вычертить граф на экране дисплея «единым росчерком пера», т. е. не отрывая «перо» и не обходя ни одно ребро графа дваж- ды? В зависимости от того, каким будет ответ и как он соотносится с правильным, возможны четыре случая. 1. Ответ дан отрицательный, правильный ответ отри- цательный. Тогда компьютер задает новый вопрос: «Ка- кое из ребер графа следует стереть или добавить, чтобы новый граф можно было обвести единым росчерком пе- ра?» Над графом на экране дисплея производится со- ответствующее действие, после чего компьютер снова задает свой вопрос: «Можно ли вычертить этот граф единым росчерком пера?» 2. Ответ дан отрицательный, правильный ответ утвер- дительный. Компьютер «горд» одержанной победой и с помощью алгоритма демонстрирует правильное решение, стирая на экране дисплея одно за другим ребра графа. Стирать очередное ребро компьютер всегда начинает с той вершины, которой заканчивается ребро, стертое на предыдущем этапе (о самом алгоритме пойдет речь в сле- дующем разделе). 3. Ответ дан утвердительный, правильный ответ отри- цательный. Компьютер передает управление отвечавшему на вопрос, с тем чтобы тот мог убедиться в неправильно- сти своего ответа: перенумеровав вершины графа, попы- таться стереть одно за другим ребра. После безуспешных попыток на экране появляется объяснение: связный (т. е. не распадающийся на отдельные, не связанные хотя бы одним ребром части) граф может быть вычерчен единым росчерком пера, если он содержит не более двух вершин нечетного порядка (т. е. либо 0, либо 2 такие вершины). Затем компьютер снова задает исходный вопрос. 4. Ответ дан утвердительный, правильный ответ ут- вердительный. В этом случае необходимо попытаться на- чертить граф единым росчерком пера. Если попытка ока- жется успешной, то программа похвалит за правильное решение и попрощается с нами. В противном случае нужно предпринять еще одну попытку. Разумеется, компьютер следит за возможными ошиб- ками, подает условный сигнал, если какое-нибудь ребро нельзя провести или стереть. Необходимо иметь в виду, что графики с 8 или более вершинами вычерчивать быва- ет трудно, поскольку ребра начинают сливаться. Во избе- жание этого мы рекомендуем некоторые ребра проводить 118
штриховой линией, в особенности вблизи вершин. Обход графа удобно описывать «словами», указывая номера проходимых вершин. ПОИСК ПУТИ ОБХОДА ГРАФА Выясним, каким образом можно вычертить соответ- ствующий граф единым росчерком пера, не обводя ни од- ного ребра дважды. Известный способ состоит в том, чтобы упорядочить все маршруты обхода ребер графа по номерам вершин. Например, для простого графа, изображенного на рис. 25, пути обхода ребер могут быть следующими. Обход начинается из 1-й вершины: 1 — 2, 1—3 — 4— 1—2, 1 —4 — 3— 1 —2. Обход начинается из 2-й вершины: 2— 1 — 3 — 4— 1, 2 — 1 — 4 — 3 — 1 ит. д. Точный алгоритм мы рассмотрим подробно на более сложном графе (рис. 26). Выберем начало обхода в одной из вершин графа. Например, начнем с вершины 1 (или с вершины 2; все остальные вершины для наших целей подходят меньше). 119
Следующей выберем вершину с наименьшим номером, достижимую из начальной: 1 — 2. Далее из вершин, дости- гаемых из 2-й вершины, выбираем ту, которая имеет наи- меньший номер: 1—2 — 3. Так продолжаем до тех пор, пока это возможно: 1 — 2 — 3 — 4 — 2. Если мы застрянем прежде, чем обойдем по одному разу все ребра графа, то номер последней вершины следует попытаться изменить (разумеется, если такое изменение возможно). Если выбор другой вершины невозможен (из 4-й вершины можно попасть только во 2-ю вершину), то следует попытаться отступить назад, с тем чтобы изменить маршрут обхода. (К сожалению, вернувшись в 3-ю вершину, мы будем вынуждены снова отступить из нее.) Дойдя до вершины, откуда можно еще продвигаться вперед, последуем по но- вому пути (в нашем примере мы, отступив на 2 ребра, последуем по маршруту 1—2 — 4). Будем продвигаться вперед до тех пор, пока это возможно: 1 — 2 — 4 — 3 — 2, после чего перед нами окажется уже пройденное ребро графа. Отступив на 4 ребра, мы снова сможем продолжить обход: 1 — 5 — 6 — 1 — 2 — 3 — 4 — 2. Итак, один марш- рут, позволяющий обойти все ребра графа ровно по одному разу, найден. Если угодно, то. поиск других маршрутов можно продолжить. Оказывается, что обойти по одному разу все ребра графа можно по маршрутам 1 — 5 — 6 — 1 — 2 — 4 — 3 — 2 (с двумя «отступлениями» назад), 1 — 6 — 5 — 1 — 2 — 3 — 4 — 2 (с шестью «отступления- ми») и 1 — 6 — 5 — 1 — 2 — 4 — 3 — 1 (с двумя отступ- лениями. Если исходную точку нельзя было бы изменять (т. е. если бы запрещалось переходить из 1-й вершины в какую-нибудь другую), то это означало бы, что мы перебрали все возможные маршруты, позволяющие пройти по всем ребрам графа, побывав на каждом из них ровно один раз. Разумеется, число таких маршрутов может оказаться равным нулю. В нашем случае существуют 4 различных маршрута, начинающихся с 1-й вершины (ес- ли бы мы начали со 2-й вершины, то маршрутов было бы столько же). Описанный выше процесс поиска маршрута для одно- кратного обхода всех ребер графа происходит так, как если бы мы выписывали все последовательности чисел от 1 до 6 (маршруты), в которых числа 1 и 2 входят дважды, а все остальные числа только по одному разу. Речь идет о сочетаниях из 8 элементов, в которых 2 элемента повто- ряются дважды. Число таких сочетаний составляет 8! 120
/2! • 2! ~ 10 000. Из этого огромного количества сочета- ний в дело идет ничтожно малая доля. Например, ни один из маршрутов, начинающихся 1 — 4 — ..., не пригоден для обхода ребер графа. Наш метод позволяет за несколько десятков шагов извлечь из всех последовательностей вер- шин (маршрутов) те, которые дают возможность совер- шить однократный обход всех ребер (если такие последо- вательности для данного графа существуют). В чем состоит основная идея предложенного метода поиска? По существу, речь идет о систематическом перебо- ре всех порождаемых в определенной последовательности маршрутов и в отыскании тех из них, которые удовлетво- ряют всем заданным условиям. Сделать это можно многи- ми различными способами, по сравнению с которыми из- бранный нами метод отличается двумя преимуществами. Во-первых, в процессе поиска маршрута последователь- ность проходимых вершин изменяется с конца. Например, в случае последовательности вершин 1 — 2 — 4 — 5 — 6 — 4 изменению подлежат лишь три последние вершины, тогда как начальный отрезок маршрута остается прежним. Во- вторых, если выясняется, что начатая последовательность вершин непригодна для наших целей, имеется возмож- ность существенно сократить поиск, так как из дальней- шего рассмотрения исключается не только эта последова- тельность вершин, но и все другие последовательности, имеющие с ней общее начало. Например, из примерно 10 000 вариантов мы рассмотрели до конца лишь 8 марш- рутов, а около 100 элементарных (состоящих лишь из одного ребра) графов были сразу отброшены за непри- годностью. АРИФМЕТИКА НА БУКВАХ Изложенный в предыдущем разделе алгоритм поиска пути обхода графа находит весьма широкое применение, хотя, разумеется, вопрос о целесообразности его примене- ния не следует упускать из виду. Ответ на него опреде- ляется в первую очередь удобством ввода условий задачи в компьютер и тем, насколько быстро компьютер переби- рает варианты. Обычно чем ближе мы к выполнению од- ного из этих двух требований, тем дальше отходим от другого. Приведем лишь один новый пример. Хорошо известны так называемые криптарифмы — задачи типа 121
SEND ’ MORE MANEY Вместо каждой буквы следует написать цифру так, чтобы пример на сложение имел смысл. Различным буквам соответствуют различные цифры, а одинаковым бук- вам — одинаковые. По существу, речь идет о решении системы уравнений с восемью неизвестными при одном, хотя и довольно сложном, условии: сумма двух четырех- значных чисел есть число пятизначное. Решить такое уравнение можно было бы подбором чисел, но такое ре- шение заняло бы слишком много времени. Если бы мы породили все числа из 8 цифр, отобрали из них по два четырехзначных и одному пятизначному и проверили, вы- полняется ли сложение, то нам пришлось бы перебрать их 1 OS/2! > 1,8 • 106 (перебор удалось бы значительно сократить, если заметить, что М = 1). На решение такой задачи среднему компьютеру понадобилось бы немало часов. Гораздо удобнее разделить задачу на четыре части: производить сложение поразрядно. Такая операция из-за переноса между разрядами нетривиальна, но попытаться стоит! 20 FOR S=0 ТО 9 30 FOR Е = 0 ТО 9 90 FOR Y = 0 ТО 9 100 GOSUB 500 102 01 = 1000 * S + 100 * Е + 10 * N + D 104 02 = 1000 * М + 100 * О + 10 * R + Е 106 03 = 10000 * М + 1000 * О : 10 * N + 10 * Е + Y 110 IF 01 + 02 = 03 THEN PRINT S, E, N, D, M, O, R, E, M, O, N, E, Y 120 NEXT Y 130 NEXT R 190 NEXT S Подпрограмма с номером 500 проследит за тем, чтобы различные буквы соответствовали различным цифрам. Программа работает несколько быстрее (хотя и этот вариант требует нескольких часов), если мы будем обра- 122
щаться к подпрограмме 500 после начала каждого цикла FOR: 20 FOR S =0 ТО 9 : U(l) = D 30 FOR E = 0 TO 9:U(2) = E: M = 2 : GOSUB 500 40 FOR N = 0 TO 9 : U (3) = N : M = 3: GOSUB 500 Сама подпрограмма 500 выглядит так: 500 FOR J = 1 ТО М — 1 510 IF U(J) <>U(M) THEN 530 520 ON M GOTO к циклу FOR... NEXT, стоящему в строке, из которой произошло обращение к 500-й подпрограмме 530 NEXT J 540 ON М GOTO к строке, следующей за строкой, из которой произошло обращение к 500-й подпрограмме. 550 RETURN. Гораздо труднее одновременно учесть четыре условия, но тем интереснее! Стоит добавить лишь 10—12 дополни- тельных инструкций (число их зависит от конструкции компьютера и искусства программиста), и программа начинает работать ощутимо быстрее (весь перебор зани- мает около 15 с). Мы вычеркиваем строки 102—ПО и заменяем их следующими: 10 DEF FNA(X) = (SGN(X - 9.5) + 1)/2 45 А = FNA (D + £): В = D + Е - Y - А * 10: IF В<0 THEN 160 65 Al = FNA(N + R):B = N + R-E- A1 * 10 : IF В < 0 THEN 140 75 A2 = FNA(E + О) : В = + О - N - A2 * 10: IF B<0 THEN 130 85 АЗ = +M - О - 10 : IF В < 0 THEN 120 Дальнейшее (не тривиальное) ускорение работы про- граммы может быть достигнуто, если строки 40—45 за- писать в более компактном виде: 40 А = FNA(D + Е) : Y = D + Е - 10 * А: U(3) = Y : М = 3 : GOTO 500 Записать строки 60—65 в более компактном виде несколько труднее, так как новая переменная не входит в сумму: 123
60 B = O:R = E — A — N:IFR<0 THEN R = 10+ R : В < 1 65 U(5) = R : M = 5 : GOSUB 500 Аналогичным образом преобразуются строки 70—75 и 80—85: 70 C = 0:O = N- E + B:IF О<0 THEN 0 = О + 10 : С = 1 75 U (6) = 0 : М = 6 : GOSUB 500 Строки 120, 130, 140, 160 излишни, но их номера не- обходимы для передачи управления в строках 520 и 540. Модифицированная указанным образом программа нахо- дит решение примерно за 2 с! По достоинству оценить этот результат сможет тот из читателей, кто вздумает состязаться с программой, ре- шая задачу с карандашом и бумагой в руках: на реше- ние у него уйдет 10—30 с. Создавая программу, мы стави- ли перед собой задачу продемонстрировать самую суть метода ветвей и границ, пояснить ход решения и добить- ся глубокого понимания его. Наша программа обладает еще и тем преимуществом, что позволяет решать любую аналогичную задачу (для перевода ее в «новый режим» необходимо лишь переставить несколько строк, в первую очередь строки 40, 60, 70, 80 и, может быть, изменить число циклов FOR). В школе учат складывать «столбиком». Следующая программа решает криптарифмы, производя сложение по столбцам, примерно за 2 с (необходимо лишь вписать буквы) (рис. 27). 10 DIM А(10) 20 FOR D = 0 ТО 9 30 A(D) = 1 40 FOR Е = 0 ТО 9 50 IF А(Е) = 1 THEN 410 ELSE А(Е) = 1 60 FOR Y = 0 ТО 9 70 IF A(Y) = 1 THEN 390 ELSE A(Y) = 1 80 IF Y < > D + E AND Y<>D + E-10 THEN 380 90 IF Y = D + E THEN XI = 0 ELSE XI = 1 100 FOR N = 0 TO 9 110 IF A(N) = 1 THEN 370 ELSE A(N) = 1 124
Рис. 27 120 FOR R = 0 TO 9 130 IF A(R) = 1 THEN 350 ELSE A(R) = 1 140 IF E < > N + R + XI AND E < > N + R + XI - 10 THEN 340 150 IF E = N + R + XI THEN X2 = 0 ELSE X2 = 1 160 FOR О = 0 TO 9 170 IF A(O) = 1 THEN 330 ELSE A(O) = 1 180 IF N < > E + О + X2 AND N < > E + О + X2 - 10 THEN 320 190 IF N = E + О + X2 THEN X3 = 0 ELSE X3 = 1 200 FOR S = 0 TO 9 210 IF A(S) = 1 THEN 310 ELSE A(S) = 1 220 FOR M = 0 TO 9 230 IF A(M) = 1 THEN 290 ELSE A(M) = 1 240 IF О < > M + S + X3 AND 0<>M + S + X3 — 10 THEN 280 250 IF О = M + S + X3 THEN X4 == 0 ELSE X4 = 1 260 IF M < > X4 THEN 280 270 PRINT 1000 * S + 100 * E + 10 * N + D: 125
’ PRINT 1000 * M + 100 * О + 10 * R + E: PRINT 10000 * M + 1000 *O+100*N + 10 * E + Y : PRINT 280 A(M) — 0 290 NEXT M 300 A(S) =0 310 NEXT S 320 A(O) = 0 330 NEXT О 340 A(R) =0 350 NEXT R 360 A(N) =0 370 NEXT N 380 A(Y) =0 390 NEXT Y 400 A(E)=0 410 NEXT E 420 A(D) = 0 430 NEXT D МУЗЫКА Большинство персональных компьютеров может стать «музыкантами», если существует какое-нибудь устрой- ство, способное звучать под действием компьютера, или если компьютер использовать в качестве «играющего ав- томата». Звуковая шкала может меняться в зависимости от компьютера. Начать с того, что интервалы между зву- ками должны быть кратны полутону (т. е. если один звук соответствует ноте «до», то другой должен соответ- ствовать ноте «до диез», третий — ноте «ми» и т. д.). Диапазон звучания определяется физическими возмож- ностями звучащего устройства. Начнем с формализации нотной записи. Каждый, ис- ходя из возможностей своего персонального компьютера, решает, что именно следует сделать ему и что предоста- вить делать компьютеру. Выберем (низкий) звук, который заведомо не может встретиться в нотах (от мелодии к мелодии он может ме- няться), и обозначим его А. Пусть В — звук, который уже встречается в нотах и на полтона выше звука А (таким образом, В — самый низкий из встречающихся в нотах звуков). Так мы продолжаем до тех пор, пока не дойдем до Z. Всего мы используем 26 знаков. Так как октава содержит 12 полутонов, мы получаем интервал, несколь- 126
ко превышающий две октавы. В большинстве случаев этого вполне достаточно. Если же для исполняемого про- изведения требуется более широкий диапазон, то запас символов можно пополнить, включив в него обозначения для более высоких или более низких нот. Например, гамма «ля мажор» после кодирования примет вид: В, D, F, G, I, К, М, N. Поскольку (к счастью) каждому звуку соответствует один символ, запятые между символами можно опустить и рассматривать всю гамму как одно слово в выбранном алфавите: А$ — ,,BDFGIKMN“. При считывании очередной символ в строке запрашивается в цикле: FOR I = 1 ТО LEN (А$) : U = ASC (MID$(A$, I, 1)) -65 NEXT Под кодом 65 значится символ «А». В зависимости от компьютера коды могут быть другими. Например, самый низкий, не встречающийся в нотах звук может иметь код 0. Имеются компьютеры, в которых длительность и вы- соту звука можно задавать одновременно с помощью инструкции ВЕЕР X, У. Пока нас будет интересовать лишь одна проблема: как задать высоту звука. В неко- торых компьютерах приходится указывать частоту или период колебаний, что несколько сложнее. В подобных случаях следует воспользоваться замечательной машин- ной моделью звуковой шкалы (в основном соответствую- щей шкале, применяемой в европейской музыке). По- скольку период колебания любого звука вдвое меньше периода колебания звука, который выше его на одну октаву, а образующие октаву 12 полутонов в логарифми- ческом масштабе соответствуют равноотстоящим точкам, период колебания данного звука равен периоду колеба- ния на полтона более низкого звука, умноженному на Что такие «точки, равноотстоящие в логарифмическом масштабе»? Пусть t — период колебания самого низкого звука и мы движемся вверх, шагая через полтона. Тогда периоды колебаний наших звуковых ступеней соответст- венно равны /, t In/2, t t При логарифмиро- вании мы получаем последовательность 1g Л lg t + (712)lg 2, lg t + (2/I2) 1g 2, lg t + ( /12) lg 2 и t. д. 127
Каждый член этой последовательности отличается от предыдущего на одну и ту же величину (1/i2)lg2. В та- ких компьютерах величину т. е. 2$ $ (712), рекомендуется записывать в виде переменной (например, переменной X). Это означает, что звук с наименьшим кодом самый высокий, поэтому всю шкалу необходимо обратить: вместо U следует писать 255/Х >|с U. Тогда меньшему коду будет соответствовать более низкий тон. Для большинства компьютеров с внешней генерацией звука, перед тем как исполнять музыкальное произведе- ние, нам придется проделать более громоздкие, хотя по существу достаточно простые, операции — заняться со- ставлением специальной подпрограммы (такую подпро- грамму придется составлять всякий раз, когда нам за- хочется помузицировать). Для компьютера других типов достаточно перед исполнением музыкального произведе- ния заглянуть в описание. Перейдем теперь к ритму. Ритм кодируется по анало- гии с высотой звучания: поставим единицу в соответ- ствие самой малой из встречающихся в нотах долей. Сна- чала речь пойдет о мелодиях, в которых звучат ноты длительностью в целую, половину, четверть и восьмую (или половину, четверть, восьмую и шестнадцатую). Присвоим им коды 1, 2, 4, 8 (код 1 соответствует самым коротким по длительности нотам — восьмым, код 2 — четвертым, код 4 — половинкам и код 8 — целым). Так же как и высота звучания, ритм записывается в виде слова. Например, ритм «ти-ти-та-ти-ти-та» можно записать одним словом: В$ = «112112» Итак, составим подпрограмму, в которой переменная U будет означать высоту тона, а переменная V — дли- тельность звучания. Чем меньше значение U, тем ниже звук. Теперь мы уже располагаем всем необходимым, чтобы зазвучала «музыка». Выберем несколько простых мелодий и попробуем их варьировать. «Мне пахать охота»: А$ = „BDFGGGGFDFFFFDB DDDDFDBBB“, В$ = „ 112211112211112211112211“ «Телушка, телушка, пестрая»: А$ = „BDBFIIBFBFII NMKIGKIGFDBB“, В$ = «111122111122111122111122». «Цып-цып, галка» А$ = „IKIFIKIFIIIKIIFBIIFIIIKIFI 11 KIF“, В$ = «2222222211111111112111122111122». Пусть 100 — начальный адрес подпрограммы и пусть 128
все строки до 30-й заняты заданием величин А$ и В$. Тогда,, начиная с 40-й строки наша программа имеет сле- дующий ^ид: 40 FOR I = 1 ТО LEN(A$) 50 U = ASC (MID$(A$, I, 1)) -65 60 V = ASC(MID$ (А$, I, 1)) -48 70 IF A < = 0 THEN FOR P = 1 TO V * 100 : NEXT P : GOTO 90 80 GOSUB 100 90 NEXT I 95 END Интересные музыкальные вариации возникают, если изменить переменную U. В перечисленных выше мелоди- ях переменная U принимает значения от 1 до 12 (диапа- зон каждой мелодии не превышает одной октавы). Преж- де всего попытаемся обратить мелодию: превратим высо- кие ноты в низкие, а низкие в высокие, т. е. зеркально отразим мелодию в зеркале, край которого параллелен нотным линейкам, а плоскость перпендикулярна нотному листу. Если значение U вычесть из 13, то из 1 получится 12, а из 12 — единица. Такую операцию мы запишем в 55-й строке: 55U = 13 — U. Другое преобразование со- стоит в том, чтобы уменьшить текущее значение U вдвое (55U = U/2) или увеличить вдвое (55U = U$2). Мелодию можно сдвинуть («транспонировать»): 55U = =U + 15. (Сдвиг в сторону меньших значений нежелате- лен, так как могут получиться отрицательные числа, но если перейти к абсолютным величинам, например 55U = =ABS(U — 4), то эффект получается весьма интерес- ный.) Сдвинув мелодию на семь полутонов, мы транспони- руем ее на квинту (квинта — интервал, равный 7 полуто- нам). Интересно отметить, после каких трансформаций ме- лодия останется узнаваемой и после каких искажается. Зеркальное отражение мелодии можно производить не только по высоте, но и по времени: исполняя мелодию от конца к началу. При таком обращении самый послед- ний звук исходного варианта становится первым. Для отражения по времени символы, входящие в слова А$ и В$, необходимо прочитать в обратном направлении, т. е. воспользоваться циклом 40 FOR I = LEN (А$) ТО 1 STEP - 1 Возможность трансформировать мелодию представ- 129
ляет интерес не только в связи с использованием персо- нальных компьютеров: компьютеры представляют собой лишь достаточно простые средства преобразования ис- ходной мелодии. Множество примеров вариаций, осно- ванных на такого рода преобразованиях музыкальной темы, мы находим в творчестве великих композиторов И. С. Баха и Б. Бартока. Вряд ли найдется хотя бы одно произведение Бартока, в котором не было бы «преобра- зований». Небольшое произведение И. С. Баха «Ракоходный канон» звучит одинаково, если его исполнять от начала к концу или от конца к началу (рис. 28). Канон написан для двух голосов. Партия второго голоса, так же как и партия первого, обратима. Поэтому достаточно задать партию первого голоса — второй обратится «сам собой». Алфавит символов «нижнего» голоса состоит из знаков 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ; , <, ^=. >,@ . А$ = «69 = > 50 = < ; : 9876516; 9869 = ; = В = 989; = ? АВ 9; => 89; = ; 989; = >@> = ; = >@ BS@> = ? ABDEBA? ABDEGD = DBDEGEDBAB = 96» В$ = «444424444422222224444111111111111111111111111 11111111111111111111111111111111111111112222» Если мы захотим исполнить двухголосое произведе- ние, то наряду с циклом, который придает все допусти- мые значения переменной U (ведущей партию первого голоса), нам понадобится определить еще одну перемен- ную S = ABS (MID$ (А$, LEN(A$)-I + 1, 1). Она бу- дет вторым голосом канона. С ритмом дело несколько сложнее, так как первые ноты в партии первого голоса (верхняя строка) по длительности отличаются от первых нот в партии второго голоса (нижняя строка). Для того чтобы преодолеть эту трудность, мы и разделяем все произведение на наименьшие ритмические единицы (так же, как при записи ритма), но всю информацию записы- ваем непосредственно в переменной А$. Каждая нота входит в А$ столько раз, во сколько ее длительность превышает длительность наименьшей доли, встречаю- щейся в музыкальном тексте. (Если наименьшей длитель- ностью была восьмая, то четверть следует записать, повторив соответствующую ноту дважды, три восьмых — 130
трижды и т. д.) «Ракоходный канон» записывается следу- ющим образом: А$ = «66669999 = == =>>>> 555500 131
= = = = <<<<;;;;:::: 9999 8877 66551166;; 9999888866669999 = ; = В = 989; = ? АВ9; = > 89; = ; 989;= >@> = ; = >@ ВС@> = ? ABDEBA? ABDEGD = DBDEGEDBABB = = 9966» Необходимость в В$ при этом отпадает. Может возникнуть вопрос: к чему связывать себя нот- ным текстом? Почему бы нам не заняться «импровиза- цией»— исполнением случайной музыки? Воспользуемся, например, программой: 40 U = RND(26) : V = RND(5) + 1 50 IF U = 0 THEN FOR P = 1 TO 100* V: NEXT P : GOTO 70 60 GOSUB 100 70 GOTO 40 Получается дикая какофония. (Исполнить ее можно в лучшем случае потому, что мы сами ее сочинили, но даже авторская гордыня не позволяет слушать эту «музыку» более десяти минут.) Если удачно сформулировать не- сколько правил, которым должна удовлетворять сочиняе- мая с помощью компьютера музыка, то она звучит более гармонично. Иначе говоря, речь идет о формализации процесса сочинения музыки. (Если бы такая формализа- ция была возможна, то это означало бы, что музыка как искусство умерла.) Еще никому не удалось придумать формулу, позволяющую определять, будет ли данное му- зыкальное произведение доставлять слушателям наслаж- дение или оставит их равнодушными. Восприятие музыки во многом определяется традициями. Обратимся к более примитивной, основанной на меньшем числе тонов музы- ке. Например, старинные венгерские народные песни основаны на пентатонике, т. е. на пяти тонах: ля, до, ре, ми, соль и снова ля. (Длительность звучания каждого тона может быть выбрана случайным образом или посто- янной.) Попытаемся теперь составить программу, сочи- няющую случайную пентатоническую мелодию. Шесть ос- новных тонов запишем в виде массива DIM А(6) и будем генерировать случайные числа (общим количеством до 6). Поскольку сейчас не существенно, что каждый из шести тонов имеет свою характерную длительность, при- сваиваем им случайные значения 1, 4, 6, 8, 11, 13. Наша программа имеет вид: 132
40 DIM A(6): A(0) = 0: A(l) = 1: A(2) =4: A(3) =6: A(4) =8: A(5) = 11 : A(6) = 13 50 V = 5 60 U = A(RND(6)) 70 IF U = 0 THEN FOR P = 1 TO 100* V: NEXT P:GOTO 60 80 GOSUB 100 90 GOTO 60 «Сочиненная» такой программой музыка звучит го- раздо приятнее и даже несколько напоминает некоторые старинные венгерские мелодии. Следует заметить, что, запомнив сочиненную компьютером мелодию, мы можел варьировать ее, например, транспонируя на квинту вни; (По существу, у нас будут работать две программы: одна — генерирующая случайную пентатоническую по- следовательность и другая — «сочиняющая» вариации на тему сочиненной мелодии.) Очень красива основа румынских народных мелодий (ля, си, до, ми) или ее расширенный вариант (ля, си, до, ре, ми, фа) (хотя это уже почти полная октава, тем не менее мелодия звучит совершенно иначе — приподнято). В качестве примера приведем одну подлинную румынскую песню (закодированную числами 1—9): А$ - «888413331484111148413338884111888 4133331484111114841333388841111» В$ =«31211114222211422211114222211 43121111312222113122211113122221131» Слова (каждая строка повторяется дважды): Кого поп отпоет, Тот уже не вернется. А солдат домой Может возвратиться. В заключение хотелось бы высказать два замечания. 1. Наглядное изображение мелодической линии. Для большей наглядности «мелодическую линию» можно изо- бразить, если каждому звуку сопоставить точку на экра- не дисплея. Координатами точки могут быть, например, величины I и U. Их можно комбинировать тем или иным образом с ритмом. 2. Случайное генерирование ритма. В случайно гене- рированной музыке ритм также может быть случайным. Предположим, что наименьшая единица длительности — 133
восьмая. В одном такте мы записываем восемь восьмых. Все восьмые, входящие в один такт, включаем в перемен- ную S и генерируем случайные числа до 8—S (начальное значение S = 0). На каждом шаге проверяем, сколько восьмых уже вошло в переменную S. Как только их число достигнет восьми, начинаем новый такт. Приведенные выше задачи-примеры были в основном составлены в процессе обучения работе на персональ- ном компьютере самими учащимися и охватывают зна- чительную часть предметов, входящих в школьную про- грамму, в том числе и гуманитарных. Не подлежит сомнению, что появление персональных компьютеров в школе не может не сказаться на препо- давании учебных предметов. Разумеется, сейчас еще трудно увидеть, в чем именно оно скажется, поскольку заранее не известно, какие новые компьютеры и какие новые задачи появятся в будущем. В этой связи нельзя не упомянуть о программах, составленных победителями олимпиады для учащихся, которые работали на стан- дартных школьных компьютерах образца 1980—1981 гг. Как правило, эти программы были далеки от школьной программы, но зато они наметили ясную перспективу в использовании компьютеров. Глава IV МОДЕЛИРОВАНИЕ ИГР НА ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ Каталин ФРИД Не подлежит сомнению, что игровые программы — од- на из наиболее увлекательных возможностей, открывае- мых перед нами персональными компьютерами. В этой главе мы собрали игры и на нескольких примерах даем читателю практические рекомендации по составлению иг- ровых программ. КОМПЬЮТЕР КАК ПАРТНЕР В ИГРЕ Прежде всего поговорим о таких играх, в которые может «играть» компьютер. Составление большинства игровых программ такого рода позволяет найти пути к решению сложных математических задач, поскольку превзойти стратегию, разработанную в игровой ситуации, 134
не так-то просто. В качестве примеров сошлемся хотя бы на программы, играющие в шахматы или бридж. Разумеется, существуют очень простые игровые програм- мы, например «вечный календарь» или вычисление био- ритмов. Но, пожалуй, наибольшую популярность сниска- ла программа, умеющая играть в Ним (см. раздел «Бар- Кохба» в гл. III). Более сложные программы позволяют нам отказаться от роли судьи или постороннего наблюдателя за игрой компьютера и превратить его в полноправного партнера. Рассмотрим один пример: игру в слова («словесный по- кер»). Правила игры состоят в следующем. Один из играющих задумывает слово из пяти букв. Другой пыт<- - ется отгадать задуманное слово, называя различные (имеющие смысл) слова из пяти букв. Если какая-нибудо буква названного слова совпадает со стоящей на том же месте буквой задуманного слова, то отгадывающему за- считывается попадание. Задумавший слово после каждо- го названного слова отмечает число ' попаданий вслух. Исходя из этой информации, второй игрок должен отга- дать, какое слово задумано первым игроком. Ясно, что написать программу, которая позволила бы компьютеру отгадать любое задуманное слово, было бы трудно. Одна- ко достаточно просто написать программу, позволяющую компьютеру «думать» (т. е. отгадывать, например, одно из пятидесяти выписанных заранее слов), накапливать информацию по мере увеличения числа попыток и, нако- нец, указывать конечный результат. Пятьдесят слов за- писано в программе последовательно в виде символьной переменной D$, длиной в 250 символов. Выглядит эта программа следующим образом: 10 D$ = «....» 20 X = INT (RND (50)) + 1 : A$ = MID$ (D$, 5 * X —4,5) 30 CLS: PRINT «ДУМАЮ, ЧТО СМОГУ УГАДАТЬ. ЕСЛИ РЕШУ ОТКАЗАТЬСЯ, ТО НАПИШУ ’СДАЮСЬ’» : S = 0 40 INPUT B$:S = S + 1:U = 0 50 IF В$ = «СДАЮСЬ» THEN PRINT А$ : FOR Q = 1 ТО 100 : NEXT Q: GOTO 100 60 FOR Q = 1 TO 5 : IF MID$(A$, Q, 1) = MID$(B$, Q, 1) THEN U = U + 1 70 NEXT Q 135
80 IF U = 5 THEN PRINT «УГАДАЛ С»; S; «ПОПЫТОК»: GOTO 100 90 PRINT „ U; «ЧИСЛО ПОПАДАНИЙ»: GOTO 40 100 PRINT «ПРОДОЛЖАЕМ? (ДА —HET)» INPUT V$ 110 IF V$ = „1“ THEN GOTO 20 При игре в словесный покер многие пытаются обма- нуть компьютер, называя вместо осмысленных слов не имеющие смысла сочетания из пяти букв. Такая тактика дает им заметное преимущество, облегчая игру и ускоряя перебор вариантов. Интересно было бы поэтому пред- усмотреть в программе специальную подпрограмму, кото- рая в случайно выбранные моменты времени заменяла бы одно из слов, входящих в его стандартный словарный запас, на слово, названное партнером. (Если названное «слово» было бессмысленной комбинацией из пяти букв, то в том случае, когда компьютер «задумает» его, партне- ру придется изрядно поломать голову над разгадкой.) Проще всего новое слово вписывать на место слова, отга- данного партнером компьютера: 82 U = RND(1) 84 TF U > .8 THEN D$ = MID$ (D$, 1, (X- 1) * 5) +B$ +MID$ (D$, X*5+l, 250 — X* 5) К той же группе, что и приведенные выше простые игры, естественно отнести и игру в кости «Кто смеется последним». Обучить компьютер правилам этой игры не- сложно, но по-настоящему интересной она становится только в том случае, если вся имеющаяся информация выводится на экран дисплея в виде таблицы1 и доступ к этой информации получают и играющие, и компьютер. Однако чрезмерно длинные партии в кости могут при- вести к тому, что игра быстро наскучит. Для упрощения программы «бросание игральной кости» поручим датчику случайных чисел. Игра станет интересной, если в ней участвуют несколько человек, компьютер «бросает» за каждого из них игральную кость и определяет, кому и сколько очков выпало. Вместо одного бросания можно брать среднее по нескольким бросаниям. Прежде чем начать игру, программа задает несколько вопросов, на которые необходимо ответить: сколько всего участников 136
и входит ли в их число компьютер? Эта часть программы (предоставляющая возможность выбора одного из имею- щихся вариантов) называется меню. Она занимает стро- ки с 10-й по 90-ю. Затем в дело вступает генератор слу- чайных чисел (функция RND), имитирующий бросание кости, и число очков, выпавших при каждом бросании, записывается в память. 10 CLS : PRINT «БРОСАНИЕ КОСТИ» 20 PRINT: «Я ИГРАЮ? (ДА—НЕТ)» 30 PRINT: «СКОЛЬКО ИГРОКОВ? (1-6)» 40 PRINT «ОТВЕТЫ ПИСАТЬ ЗДЕСЬ»: INPUT А$, N 45 IF А$ = „1“ AND N = 0 THEN GOTO 100 50 IF N < I OR N >6 THEN PRINT «НЕПРАВИЛЬНЫЙ ОТВЕТ НА ВОПРОС О ЧИСЛЕ ИГРОКОВ»: GOTO 10 60 DIM K$(N + 1) 70 FOR I = 2 TO N 80 PRINT «КТО ТАКОЙ ИГРОК» I; «?»: INPUT K$(I) 90 NEXT I 100 IF A$ = „1“ THEN N = N + 1: K$(N) = «КОМПЬЮТЕР» 110 FOR Q = 1 TO N: S (Q) = 0: NEXT Q: J = 1 120M = 0;G$ = „ “: CLS 130 FOR Q = 1 TO N 140 D(Q) = INT(RND(6)) + 1 145 IF D(Q) >M THEN M = D(Q): G$ = K$(Q): GOTO 155 150 IF D(Q) =M THEN G$=GS+ „ “ + K$(Q) 155 PRINT K$(Q): «БРОСАНИЕ КОСТИ»: D(Q):S(Q)=S(Q) +D(Q) 160 PRINT K$(Q): «СРЕДНЕЕ»: » ; S(Q)/J 165 PRINT 170 NEXT Q 175 PRINT «ПОБЕДИЛ»; G$; M; «ОЧКОВ» 180 PRINT «ПРОДОЛЖАЕМ? (ДА —HET)»: INPUT V$ 190 IF A$„I“ THEN J = J+ 1: GOTO 120 137
200 PRINT «НАЧНЕМ СНАЧАЛА? (ДА —НЕТ)»: INPUT У$ 210 IF A$ = „I“ THEN GOTO 10 Эта программа уже «узурпирует» права игроков, которые, по существу, сведены до положения «поставщи- ков имен». Среди автоматически играющих программ с точки зрения их составления программа «Волшебный экран»— одна из приятнейших задач, а сам «Волшебный экран» с полным основанием может быть назван одной из инте- реснейших игр. Напомним, что в первоначальном вариан- те этой игры без использования компьютера рисунок на серебристой поверхности экрана вычерчивала пишущая головка, перемещением которой по горизонтали и верти- кали можно было управлять, вращая две ручки. Если в компьютере имеется инструкция PLOT, то экран дисплея можно превратить в «Волшебный экран». Прежде всего необходимо очистить экран дисплея, установить «пишущую головку» в точке (0, 0) и с по- мощью инструкции INKEY$ выяснить, в какую сторону следует двигаться. Мы приводим лишь простейший ва- риант, поэтому вместо того, чтобы проверять, не вышла ли изображающая точка за пределы экрана дисплея, наша программа в случае выхода сигнализирует просто знаком ошибки. Символы „А“ и ,,Z“ соответствуют перемеще- ниям вверх-вниз, символы „М“ и ,,N“ — перемещениям вправо-влево. Соответствующий фрагмент программы имеет вид: 10 CLS:X = 0: Y = 0 20 А$ = INKEY$ : IF А$ = “ “ THEN GOTO 20 30 IF A$ = ,,A“ THEN Y = Y — 1: GOTO 70 40 IF AS = ,,M“ THEN X = X + 1: GOTO 70 50 IF A$ = ,,N“ THEN X = X- 1: GOTO 70 60 IF A$ = ,,Z“ THEN Y = Y + 1 70 PLOT X, Y 80 GOTO 20 Если символам A, M, N, Z соответствуют коды 65, 77, 78, 90, то функция INT((ASC(A$ — 54) /12) прини- 138
мает на них значения 0, 1,2, 3. Вычисляя их, мы получа- ем возможность упростить программу, передавая управ- ление с помощью инструкции GOTO строке с вычисля- емым, а не известным заранее номером: 20 PLOT X, Y 25 А$ = INKEY$ : IFA$ = “ “ THEN GOTO 25 30 GOTO INT((ASC(A$-54)/12) * 10 + 40 40 Y = Y— 1: GOTO 20 50 X = X+ 1: GOTO 20 60 X = X— 1: GOTO 20 70 Y = Y + 1: GOTO 20 Один из недостатков нашей программы для игры «Волшебный экран» состоит в том, что рисовать на экра- не дисплея можно только непрерывно. Этот недостаток вполне исправим: необходимо лишь вместе с клавишей SHIFT нажать клавишу с соответствующей буквой. Тог- да «пишущая головка» переместится в нужном направле- нии, не оставляя следов на экране. К аналогичному типу относятся не менее интересные игры на проверку реакции (см. раздел «Компьютер — часы и регулировщик движения» в гл. III). Свою память каждый желающий может проверить с помощью следую- щей игры. На экране дисплея появляется двузначное число и через какое-то время исчезает. Играющий дол- жен восстановить исчезнувшее число. Если это удается с первого раза, то число разрядов увеличивается на единицу, а время, в течение которого число экспониру- ется на экране дисплея, уменьшается. Если восстановить число играющему удастся только со второй попытки, то увеличивается только число разрядов, а время экспози- ции остается прежним. Если же играющий сможет вос- становить число только с третьей попытки, то и число разрядов, и время экспозиции остаются без изменений. Если играющий не сумеет восстановить число, то ком- пьютер показывает его на экране дисплея и спрашивает, не желает ли играющий испытать свою память еще раз. 10 N=-2: Р = 500 20 А$ = “ “ : FOR I = 1 ТО N 30 А$ = А$ + STR$(INT(RND(9)) + 1) 40 NEXT I 50 CLS : PRINT A$ 139
60 FOR T = 1 TO P : NEXT T : V = 0 : CLS 70 INPUT B$ 80 IF A$<>B$ THEN V = V+ 1 90 IF V = 1 THEN GOTO 200 100 IF V = 2 THEN GOTO 210 110 IF V = 3 THEN GOTO 220 120 PRINT A$ : FOR T = 1 TO 3000 NEXT T 130 PRINT «НАЧНЕМ СНОВА? (ДА —НЕТ)»: INPUT Q$ 140 IF Q$ = „I“ THEN GOTO 10 150 END 200 P —P —5 210 N = N + 1 220 GOTO 20 Приведенную программу можно упростить, например, передавая управление по вычисляемому адресу. НЕСКОЛЬКО СЛОВ О «ПРИКЛЮЧЕНЧЕСКИХ» ИГРАХ Не приходится сомневаться в том, что наибольшей по- пулярностью пользуются так называемые «приключен- ческие» игры. Часть из них известна давным-давно — еще с тех пор, когда для игры достаточно было только карандаша и бумаги. Назовем хотя бы такие игры, как «Морской бой» или «Автогонки». Последняя игра состо- ит в следующем. На клеточной (лучше всего миллиметро- вой) бумаге рисуется трасса, изобилующая крутыми ви- ражами. На одном конце трассы находится старт, на дру- гом — финиш. Гоночной машине соответствует точка (узел квадратной решетки, образуемой клетками). Правила гонки несложны. Прежде всего нужно сле- дить за тем, чтобы не вылететь за пределы трассы. Если такое все же случится, то гонщик должен вернуться в то место, где его машина пересекла границу трассы. У каж- дой точки имеется восемь ближайших «соседей»: восемь точек решетки, расположенных к ней ближе всего. Делая ход, игрок отмечает продвижение своей машины стрел- кой, соединяющей исходную точку с конечной. Первым ходом он соединяет исходную точку с любой из соседних. При следующих ходах игрок всякий раз проводит «почти такую же» стрелку, какая была нарисована на предыду- щем ходу, но конец стрелки также должен совпадать с одной из соседних точек. 140
Во время гонок траектории машин не должны пересе- каться (во избежание столкновений машин). Выигрыва- ет тот, кто первым достигнет финиша. Программа строится почти исключительно на графи- ческом решении задачи. «Судейская коллегия» (специ- ально предусмотренные фрагменты программы) выполня- ет свои обычные обязанности: 1) проверяет, выполним ли ход, который совершает очередной игрок; 2) штрафует гонщика, по вине которого произошло столкновение, или любого другого нарушителя правил; 3) оценивает результаты. Составлять программы приключенческих игр — дело не легкое. Это задача, решение которой становится по плечу лишь наиболее активным учащимся через несколь- ко месяцев после того, как они приступают к изучению компьютера. Приводить здесь какие-нибудь подробности было бы поэтому трудно. По своему духу приключенче- ские игры (в компьютерном исполнении) всегда графич- ны. Обучение им лучше всего начинать с программиро- вания перемещений простых графических символов по экрану дисплея и на более позднем этапе переходить к программированию случайных перемещений символа. На третьем этапе можно, например, заняться предотвраще- нием столкновений двух символов. О программировании приключенческих игр трудно го- ворить «вообще», так как графика меняется от компьюте- ра к компьютеру. Поэтому мы ограничимся лишь не- сколькими рекомендациями для тех, кто захочет написать приключенческую программу. 1. Продумайте заранее и составьте перечень графи- ческих фигур и их движений (на первых порах проще всего использовать символы, имеющиеся в алфавите компьютера, например, буквы). 2. Составьте меню возможных вариантов ходов в зависимости от выбранного варианта адресов, которым может передаваться управление. Существенного упроще-’ ния программы можно добиться, если воспользоваться инструкцией GOTO с вычисляемым по ходу действия адресом или воспользоваться каким-нибудь другим трю- ком, например логическими функциями. (Так, инструкция GOTO 100 +(100 AND М = 3) передает управление 100-й строке, если М 3, и 200-й строке, если М = 3.) Следует позаботиться и о том, чтобы программа отвер- гала неправильные варианты. 141
3. Настоятельно рекомендуем обратить внимание на варианты использующие инструкцию INKEY$ даже в тех случаях, если ожидается ввод численных данных (с помощью инструкции INPUT). Значения при этом за- даются функцией AL. 4. Значения (например, число очков), важные для игрока в ходе игры, до конца партии имеет смысл выво- дить на экран дисплея. Следовательно, полностью сти- рать экран не целесообразно. 5. Наконец, можно предусмотреть оценку качества иг- ры, т. е. определять, кто ведет игру: игрок высокого класса или безнадежно проигрывающий новичок. Глава V БЕЙСИК — ЛОГО — ФОРТ? Калман СТРОКАЙ История языка программирования БЕЙСИК начина- ется с 60-х годов. Именно тогда появились большие ЭВМ, способные работать в режиме разделения времени, т. е. одновременно считать на одном компьютере несколь- ко. программ. Быстродействие ЭВМ уже тогда стало столь большим, что позволяло делить «рабочее время» машин на совсем малые промежутки («доли времени») и отдавать их нескольким пользователям, работающим на одной и* той же машине одновременно и полностью независимо друг от друга, причем у каждого пользовате- ля создавалось впечатление, будто компьютер занят ре- шением только его задачи. Система разделения времени позволила человеку, ис- пользующему компьютер, через терминал вступать в пря- мую и непосредственную связь с ЭВМ: следить за ходом действия программы, вводить данные по ходу действия программы и выводить полученные результаты. Первым языком программирования, использовавшим новые воз- можности, стал язык БЕЙСИК, разработанный сотрудни- ком Дартмутского колледжа венгром по происхождению Джоном Кемени* и его сотрудниками. * Математик и философ, Джон Кемени родился 31 мая 1926 г. в Будапеште. С 1940 г. проживает в США. Преподаватель, декан математического факультета и впоследствии ректор Дартмутского кол- леджа. Разработал (вместе с Томасом Куртцем) язык программирова- ния БЕЙСИК. Один из создателей Дартмутской системы разделения времени. Перу Джона Кемени принадлежат несколько монографий. 142
В 1963 г. в Дартмутском колледже вступила в строй большая ЭВМ с разделением времени, позволявшая об- служивать одновременно сто пользователей. Джон Кеме- ни с сотрудниками на основе многолетнего опыта работы с языком ФОРТРАН создали новый язык, которым легко овладели миллионы пользователей. Так на основе ФОРТРАНа родился новый язык программирования БЕЙСИК, который наряду с простотой обладал еще одним важным преимуществом: он позволял осуществ- лять непосредственную связь между человеком и компью- тером. Возможность свободного диалога между челове- ком и компьютером и была основным достоинством ново- го языка. Ныне в связи с появлением во всем мире дешевых интерактивных персональных компьютеров эта особенность языка БЕЙСИК, возможно, несколько утра- тила свою исключительность, но в то время она была весьма существенной, поскольку в 60-е годы существова- ли только дорогие большие ЭВМ, издержки на покупку и эксплуатацию которых покрывались лишь при использо- вании их в системе разделенного времени. БЕЙСИК — язык гораздо более простой, чем ФОРТ- РАН. Например, в языке БЕЙСИК, вводя или выводя информацию с помощью инструкций INPUT и PRINT, нет необходимости подробно указывать размеры массива, как это требуется при использовании инструкции FOR- MAT в языке ФОРТРАН. Отличительные особенности БЕЙСИКа — простота и возможность установления не- прерывного диалога человек — компьютер — открывает перед каждым человеком возможности самого непосред- ственного ознакомления с применением компьютеров. Роль и значение языка БЕЙСИК еще более возросли с появлением персональных компьютеров, так как при использовании этого языка программа-транслятор требу- ет меньших объемов памяти, чем при использовании дру- гих языков программирования. Однако за компактность БЕЙСИКа приходится пла- тить довольно высокую цену. Интерпретатор языка БЕЙСИК, занимающий малый объем памяти (и требую- щий в отличие от программ-трансляторов знания машин- ных кодов не до того, как программа приходит в дейст- вие, а по ходу действия программы — при переходе от одной инструкции к другой), работает, вообще говоря, медленно. Следовательно, программа, записанная на языке БЕЙСИК, может потребовать гораздо больше вре- 143
мени, чем необходимо для решения той же задачи про- граммам, записанным на других языках. Язык БЕЙСИК позволяет решать весьма многие зада- чи программирования и очень удобен в качестве первого языка при обучении программированию. Однако возмож- ности языка БЕЙСИК не безграничны: более длинные программы, написанные на языке БЕЙСИК, превраща- ются в почти непроходимый лабиринт инструкций GOTO. Написать удобообозримую программу сколько-нибудь значительного объема на языке БЕЙСИК трудно. В слу- чае более сложных задач язык БЕЙСИК не позволяет записать красивое, с четкой структурой решение. Почти безраздельное господство БЕЙСИКа как языка персо- нальных компьютеров мотивировано не с точки зрения человека, а с «точки зрения» компьютера: БЕЙСИК — язык, удобный для компьютера. Однако нельзя не упомя- нуть и о том, что за прошедшие годы было разработано несколько языков программирования, более близких че- ловеческому мышлению и позволяющих составлять более «прозрачные» программы, чем язык БЕЙСИК. С развитием вычислительной техники (созданы ми- ниатюрные персональные компьютеры с памятью 16 Кбайт, появилось много компьютеров с памятью 32 и даже 64 Кбайт) расширились возможности персональ- ных компьютеров. Для них стали создаваться транслято- ры других языков программирования: ФОРТ, ЛОГО, ПАСКАЛЬ, ЭПЛ, АДА, С и т. д. В этой главе мы познакомимся с двумя языками программирования, реализованными на персональных компьютерах. ФОРТ и ЛОГО — современные процессорные языки. Решение задач программирования на любом из них сво- дится не к написанию длинной программы, а к разбиению задачи на малые части, составлению для каждой из них отдельной небольшой программы-процесса, выделению в них новых подпроцессов и созданию на основе элементар- ных процессов надпроцесса, дающего решение задачи. Иначе говоря, мы определяем новые слова (новые про- цессы) и включаем их в словарный запас нашего языка программирования (тем самым расширяя его), затем дополняем расширенный словарный запас снова и снова до тех пор, пока решение задачи программирования нельзя будет описать одним описываемым этим словом процессом. При таком подходе решение исходной слож- 144
ной задачи программирования сводится к решению серии более простых задач и сама задача оказывается пред- ставленной в весьма компактном виде. Во многих традиционных языках программирования структура программы не зависит от процессов, но БЕЙ- СИК не принадлежит к числу таких языков. В языке БЕЙСИК допустима только организация процедур (под- программ), а это — гораздо более слабое средство, чем процесс. Действительно, в языке БЕЙСИК процедура не является самостоятельной программой (в языках ФОРТ и ЛОГО процессы самостоятельны), и, кроме того, в языке БЕЙСИК ввод данных в процедуру возможен только из основной программы с помощью инструкций, задающих значения соответствующих переменных. Модульная структура программы, обеспечиваемая процессорными языками, делает возможным хранить не- которые процессы в заранее транслированном виде, что позволяет в ходе программы значительно меньше экс- плуатировать транслятор, чем в программах, написанных на языке БЕЙСИК. Следовательно, при решении одних и тех же задач программы на языках ФОРТ и ЛОГО в 2—3 раза компактнее программ на языке БЕЙСИК и «считают» в 5—10 раз быстрее. Знакомя читателя с программированием на языке ФОРТ, мы остановим свой выбор лишь на простых ариф- метических задачах, а из программирования на языке ЛОГО выделим только графическую систему. ВВЕДЕНИЕ В ФОРТ В языке ФОРТ основным способом хранения чисел служит «стек» (stack). Например, если в компьютер тре- буется ввести по порядку числа 10 4 5, то стек состоит из трех чисел, первое из которых распо- ложено в самом низу, а последнее — на самом верху стека. Над числами, образующими стек, можно произво- дить различные операции. Например, под действием сло- ва DUP (от англ, duplicate — читается «дупликейт» — удваивать) образуются два экземпляра самого верхнего числа стека, и новый (второй) экземпляр накладывается поверх первого, т. е. два верхних элемента нового стека одинаковы и совпадают с верхним элементом старого 145
стека. Под действием слова DROP (от англ, drop — чи- тается «дроп» — отбросить) отбрасывается верхнее число стека. Под действием слова SWAP (от англ, swap — чи- тается «свап» — переставить) происходит перестановка двух верхних чисел в стеке, а под действием слова OVER (от англ, over — читается «овер» — поверх) новый эк- земпляр второго сверху числа в стеке «кладется» поверх стека. Таким образом, применив к выписанному выше стеку слово DUP, мы получим числа 10 4 5 5 . Подействовав на новый стек словом DROP, мы отбросим верхний элемент и снова получим исходный стек: 10 4 5. Введя в компьютер слово SWAP, преобразуем этот стек в новый 10 5 4, из которого под действием слова OVER получим стек 10 5 4 5. Можно представить себе, что числа, образующие стек, выписаны на карточках, а слова на языке ФОРТ указы- вают, куда поместить новые карточки или как переста- вить старые. Для выполнения четырех арифметических действий над числами стека в языке ФОРТ предусмотрены специ- альные слова: -|--X / (означающие соответственно сло- жение, вычитание, умножение и деление). Например, под действием слова + на языке ФОРТ два верхних числа суммируются, а их сумма становится верхним элементом стека. Так, стек 10 5 4 5, оставшийся от предыдущего примера, под действием сло- ва + перейдет в стек 10 5 9. Подействовав на него еще раз словом +, мы получим стек 10 14, а при следующем применении слова + — стек 146
24, состоящий лишь из одного элемента. Несколько чисел и слов на языке ФОРТ разрешается задавать одновре- менно. Например, если первоначально стек пуст, то, вво- дя числа и слова 10 4 5, мы получим тот же результат, который раньше был полу- чен шаг за шагом. Инструкции PRINT в языке БЕЙСИК соответствует слово . в языке ФОРТ, под действием ко- торого верхний элемент стека выписывается на экране дисплея и стирается из стека. Следовательно, если мы хотим узнать, какое число находится на вершине стека, но не желаем портить сам стек, то нам следует восполь- зоваться словами DUP., под действием которых выписываемое на экране слово будет размножено в двух экземплярах, один из которых останется на вершине стека, а второй исчезнет после то- го, как мы выпишем его на экране. Если мы хотим вы- писать на экране дисплея два верхних элемента стека, не нарушив при этом сам стек, то следует воспользовать- ся словами OVER. DUP. Если стек состоял из чисел 10 4 5, то под действием слов OVER. DUP. на экране появятся числа 4 и 5, а сам стек останется неизменным. По- действовав затем словами -j- DUP, мы выпишем на экра- не сумму двух верхних элементов стека, т. е. 9, а в стеке останутся числа 10 9. Сумму двух чисел, например, 10 и 4, в языке БЕЙ- СИК можно выдать на экран дисплея по команде PRINT 10 + 4, а в языке ФОРТ для этой же цели надлежит ввести в компьютер следующие числа и слова: 10 4 + . 147
Обратный порядок, возможно, менее привычен, но зато он более логичен, чем принятый в языке БЕЙСИК тра- диционный порядок записи, так как показывает, в какой последовательности действительно работает компьютер: сначала помещает в память два числа, затем суммирует их и, наконец, выдает полученную сумму на экран дис- плея. Из слов языка ФОРТ можно образовывать (опреде- лять) новые слова. Определение каждого нового слова начинается со знака : и заканчивается знаком ; Если нам нужно выписать на экране дисплея квадрат какого- нибудь одного числа, например числа 10, то это можно сделать, набрав следующие слова: 10 DUP *. Но если мы хотим вычислить квадраты нескольких чи- сел, то неразумно каждый раз выписывать последова- тельность команд из трех слов на языке ФОРТ. Гораздо удобнее определить новое слово и «обучить» компьютер, что слово КВАДРАТ эквивалентно по своему значению трем приведенным выше словам: :КВАДРАТ DUP * .; Аналогично при выписывании двух верхних элементов стека удобно ввести какое-нибудь новое слово, например ВЕРХ, определив его следующим образом: : ВЕРХ OVER. DUP.; Расширенный вариант языка ФОРТ действует на стек 10 4 5 из самого первого примера следующим образом. Опреде- ленное нами новое слово ВЕРХ позволяет выдать на экран дисплея два верхних числа 4 и 5, а слова КВАДРАТ ВЕРХ выдают на экран сначала квадрат верхнего числа, т. е. число 25, а затем два верхних из оставшихся в стеке чисел, т. е. числа 10 и 4. Если мы хотим выяснить, какое соотношение выпол- няется между двумя верхними числами в стеке, то из слов ВЕРХ или OVER языка ФОРТ следует выбрать соответствующее и воспользоваться им. Под действием выбранного нами слова два сравниваемых числа извлека- 148
ются из стека, и сверху в стек вводится число 1, если предполагаемое соотношение истинно, и число (3, если оно ложно. Например, если сначала стек пуст и мы запишем 2 3 =, то в стек будет вписано число 0, а если написать 2 3 <, то в стек будет вписано число 1. Если слова 0 = 0 <0>* языка ФОРТ сравнить с верхним числом 0 стека, то ре- зультат будет таким, как если бы мы поместили в стеке число 0 и, выбрав из слов = <> языка ФОРТ соответ- ствующее, воспользовались им. Слова IF, ELSE, THEN языка ФОРТ оказывают такое же действие, как инструкция IF в языке БЕЙСИК, но в соответствии с принятым в языке ФОРТ обратным по- рядком записи означают следующее: если верхнее число стека истинно (не нуль), то следу- ют слова, стоящие после IF; если верхнее число стека не истинно, то следуют слова, стоящие после ELSE; после выполнения условия (слов), стоящего после IF (или ELSE), следуют слова, стоящие после THEN. В качестве примера определим такое слово языка ФОРТ, которое, сделав копию (второй экземпляр) верх- него слова стека, устанавливает, отрицательно это число или не отрицательно, и выписывает результат на экран: : КАКОЕ ЧИСЛО? DUP 0< IF . «ОТРИЦАТЕЛЬНОЕ» ELSE . «НЕ ОТРИЦАТЕЛЬНОЕ» THEN Слово .» на языке ФОРТ, входящее в определение слова КАКОЕ ЧИСЛО?, ставит следующие кавычки за стоящим за ним словом. Ветви IF и ELSE встречаются со словом THEN. Непосредственно после THEN слово КАКОЕ в нашем примере заканчивается. Прежде чем приводить пример на применение слова КАКОЕ ЧИСЛО?, вернемся к определенному выше слову КВАДРАТ и изменим его следующим образом: 149
: КВАДРАТ DUP * DUP.; (различие с прежним определением состоит в том, что теперь один экземпляр квадрата числа остается верхним числом стека). Набрав 5 КАКОЕ ЧИСЛО?, мы увидим на экране дисплея слово НЕ ОТРИЦАТЕЛЬНОЕ, а набрав —5 КАКОЕ ЧИСЛО?, слово ОТРИЦАТЕЛЬНОЕ. Если набрать —5 КВАДРАТ КАКОЕ ЧИСЛО?, то на экране появится слово НЕ ОТРИЦАТЕЛЬНОЕ. Воспользовавшись тем, что язык ФОРТ позволяет определять новые слова, т. е. «объяснять» компьютеру новые процессы, мы можем научить компьютер «разгова- ривать на русском языке»: для этого достаточно пере- определить заново все слова языка ФОРТ, например, так: : ПЕРЕСТАВИТЬ SWAP; ; ОТБРОСИТЬ DROP; : ЕСЛИ IF; : ИНАЧЕ ELSE; : ТО THEN; и т. д. Такой «перевод» облегчит знакомство с компьютерной техникой тем, для кого оно затруднено из-за незнания английского языка. «Русификация» языка ФОРТ пред- ставляет собой, как мы убедились, весьма простую, не требующую значительных затрат труда, вполне разреши- мую задачу. Перевод языка БЕЙСИК на русский язык был бы несравненно более трудной задачей. В следующем примере мы определим такое слово на языке ФОРТ, которое вычисляет факториал верхнего чис- ла стека. (Входящее в определение слово ? DUP размно- жает в двух экземплярах верхнее число стека, если оно отлично от нуля. Если верхнее число равно нулю, то 150
слово ?DUP ничего не делает. Слово 1 — вычитает единицу из верхнего числа стека.) :ФАКТОРИАЛ ?DUP IF DUP 1 —ФАКТОРИАЛ ELSE 1 THEN Отметим, что слово ФАКТОРИАЛ входит в свое соб- ственное определение. Такой способ определения нового слова называется рекуррентным. В языке ФОРТ про- цессы могут содержать ссылки на самих себя, что позво- ляет свести сложную задачу к ее более простому вариан- ту. В ходе рекуррентного процесса стек может заполнить- ся и действие программы приостановится. При использо- вании слова ФАКТОРИАЛ, если только не задавать слишком большое число, такого не будет. В других слу- чаях в рекуррентное определение вводится слово R > DROP, по которому (запись в стек стирается и про- цесс продолжается) производится стирание записи. Цикл DO... LOOP в языке ФОРТ устроен аналогично инструкции FOR... NEXT в языке БЕЙСИК. Например, слово, определяемое в языке ФОРТ как : ЦИКЛ 100 0 DO LOOP; соответствует в языке БЕЙСИК инструкциям 10 FOR I = 1 ТО 100 20 NEXT I, а слово : ЦИКЛ 100 0 DO I. LOOP; в языке БЕЙСИК соответствует инструкциям 10 FOR I = 1 ТО 100 20 PRINT I 30 NEXT I Язык ФОРТ открывает перед пользователем много и других возможностей, останавливаться на которых в этой главе, где наша задача состоит лишь в общем обзоре его особенностей, было бы неуместно. 151
Тем, кто уже знаком с каким-нибудь языком неструк- турного программирования, изучение языка ФОРТ дается труднее, чем изучение языка БЕЙСИК. Но те, кто не испугаются трудностей и разберутся в общей схеме языка ФОРТ, легко усваивают этот язык. Неструктурные про- граммы на языке БЕЙСИК можно писать, сидя непо- средственно за клавиатурой компьютера почти без пред- варительного обдумывания задачи. Программы на языке ФОРТ требуется планировать заранее, расписывать по словам, а затем «собирать» программу из уже действую- щих частей в единое слово. Те, кто овладел языком ФОРТ, уже без труда переучиваются на другие ныне существующие структурные языки программирования для больших вычислительных систем. Нельзя не упомянуть о компактности и быстродей- ствии, достигаемых при программировании на языке ФОРТ. Как уже упоминалось, программа на языке ФОРТ считает ту же задачу примерно в 5—10 раз быстрее, чем программа на языке БЕЙСИК, что весьма важно при работе с компьютером в режиме диалога в различного рода игровых программах, где играющему приходится ждать ответного хода. Язык ФОРТ требует небольшого объема памяти, поэтому естественно, что на большинстве персональных компьютеров можно использовать язык ФОРТ. ВВЕДЕНИЕ В ЛОГО Язык ЛОГО аналогичен языку ЛИСП. Это — совре- менный язык программирования, разработанный для учебных целей. Подобно языку ФОРТ, ЛОГО — язык структурный, саморасширяющийся. В ходе программиро- вания он допускает введение новых слов, задаваемых определениями, т. е. возможность расширения своего словарного запаса. Графическая система языка ЛОГО особенно пригодна для быстрейшего ознакомления с образом мышления со- временной вычислительной техники. Одно из средств по- строения изображения на экране дисплея в графической системе ЛОГО — так называемая черепаха представляет собой треугольную фигурку, которую можно передвигать по экрану с помощью нескольких простых команд. На- пример, по команде FORWARD черепаха движется в ту сторону, в которую направлен ее «нос» (вершина тре- 152
угольника). По команде FORWARD 50 черепаха про- двигается вперед (по носу) на 50 черепашьих шагов. По команде RIGHT черепаха поворачивает на заданный угол вправо, а по команде LEFT — на заданный угол влево. Основание черепахи снабжено «пером», оставля- ющим след на экране. Черепаха опускает перо (т. е. оставляет след на экране) по команде PENDOWN и под- нимает перо (т. е. перестает оставлять след на экране) по команде PENUP. Рисуя, мы можем убрать («спря- тать») черепаху по команде HIDETURTLE и вновь «про- явить» ее, если это необходимо, по команде SHOWTUR- TLE. На рис. 29 показано, как, повинуясь уже известным нам командам, черепаха вычерчивает на экране дисплея след той или иной формы. Черепаха в исходной позиции FORWARD 150 LEFT 45 FORWARD 100 BACK 100 LEFT 45 PENUP FORWARD 50 PENDOWN FORWARD 50 HIDETURTLE Puc. 29 Рисование с помощью черепахи, выполняющей прос- тые команды,— игра, несомненно, увлекательная, но по- настоящему интересной она становится лишь после того, как мы начнем обучать персональный компьютер новым словам. С помощью уже известных нам стандартных команд квадрат можно нарисовать следующим образом: FORWARD 50 RIGHT 90 FORWARD 50 153
RIGHT 90 FORWARD 50 RIGHT 90 FORWARD 50 Сколь ни скучно и малопривлекательно такое построе- ние квадрата, построение, например, 24-угольника таким способом еще скучнее. Поэтому черепаху можно научить вычерчивать квадрат четырехкратным повторением по- следовательности команд FORWARD 50 RIGHT 90. На языке ЛОГО это записывается так: ТО SQUARE REPEAT 4 [FORWARD 50 RIGHT 90] . END Иначе говоря, для того, чтобы построить квадрат, не- обходимо четыре раза повторить продвижение на 50 ша- гов с поворотом на 90° в конце отрезка. Тем самым процесс на языке ЛОГО будет определен. Определение начинается как в языке ФОРТ. На его начало указы- вает слово ТО. Стоящее после ТО слово (в нашем при- мере SQUARE) — это имя, или название процесса, кото- рое заносится теперь в словарь компьютера. Если в даль- нейшем мы «скажем» черепахе: SQUARE, то она без вся- ких пояснений вычертит квадрат. Затем в определении указано, какие инструкции должен выполнять компьютер по команде SQUARE. Конец определения помечен словом END. (Все английские слова, входящие в определение, значимы: SQUARE — квадрат, REPEAT — повторить, FORWARD — вперед, RIGHT — вправо, END — конец.) Можно было бы назвать процесс каким-нибудь другим словом, не входящим в словарь языка ЛОГО, например, КВАДРАТ или даже CIRCLE (англ.— окружность) — все равно при обращении к процессу по закрепленному за ним имени результат был бы одним и тем же, т. е. на экране появился бы квадрат. Определение процесса можно было бы сформулировать и в виде просьбы: «Скажи мне, как построить квадрат». По команде SQUARE черепаха всякий раз будет рисовать на экране квадрат со стороной в 50 шагов. Чтобы варьировать продвижение черепахи вперед на раз- личное расстояние, за словом FORWARD можно указать параметр. Например, процесс SQUARE можно видоизме- нить следующим образом: 154
TO SQUARE : SIZE REPEAT 4 [FORWARD: SIZE RIGHT 90] END В такой записи мы можем (и, более того, должны) ука- зывать, какого размера (размер по-английски — SIZE) квадрат необходимо нарисовать на экране. Например, по команде SQUARE 100 черепаха нарисует квадрат со стороной в 100 шагов. Двоеточие в заголовке процесса стоит перед именем SIZE и означает, что всякий раз, когда это слово встре- чается (вместе с двоеточием) в определении процесса, при обращении компьютера к процессу должны быть вве- дены соответствующие размеры. Ранее определенные слова можно использовать в оп- ределении новых процессов, например: ТО ОБРАЗЕЦ REPEAT 6 [FORWARD 20 RIGHT 60 SQUARE 75] END Следующий процесс, как и SQUARE, позволяет строить квадрат со стороной заданной длины: ТО КВАДРАТ : SIZE FORWARD : SIZE RIGHT 90 КВАДРАТ : SIZE END Хотя результат выполнения команд SQUARE и КВАДРАТ одинаков (на экране дисплея черепаха рисует квадрат), эти команды существенно отличаются. По команде SQUARE черепаха вычерчивает квадрат и затем отдыхает. По команде КВАДРАТ она будет снова и сно- ва обходить одну за другой все стороны квадрата. Дей- ствительно, по команде КВАДРАТ 100 черепаха пройдет вперед 100 шагов, повернет под пря- мым углом направо, затем снова получит команду КВАД- РАТ 100 и т. д., т. е. будет безостановочно обходить стороны квадрата, пока мы не вмешаемся и не остано- вим ее. 155.
Если процесс построения квадрата видоизменить так, . чтобы можно было задавать не только длину стороны, но и угол поворота, то получится процесс, позволяющий ри- совать не только выпуклые, но и звездчатые многоуголь- ники: ТО POLYPSI : SIZE : ANGLE FORWARD : SIZE RIGHT : ANGLE END (ANGLE — угол). Обратиться к этому процессу можно, например, сле- дующим образом: POLYPSI 80 144 На рис. 30 показано, какой формы многоугольники получаются при введении различных длин сторон и вели- чин углов. Процессы КВАДРАТ и POLYPSI повторяют без изме- нений один цикл. С более сложным случаем рекуррент- 156
ного определения мы встречаемся в следующем процессе: ТО POLINE : SIZE : ANGLE FORWARD : SIZE RIGHT : ANGLE POLINE : SIZE + 3 : ANGLE END Например, по команде POLINE 1 120 черепаха движется так: FORWARD 1 RIGHT 120 FORWARD 4 RIGHT 120 FORWARD 7 RIGHT 120 FORWARD 10 RIGHT 120 t. e. вычерчивает на экране дисплея треугольную спи- раль, каждое последующее звено которой на 3 шага длиннее предыдущего. На рис. 31 показано несколько Рис. 31 образцов спиралей, вычерчиваемых по команде POLINE. Если в определение процесс POLINE вместо команды FORWARD вписать процесс, рисующий квадрат, то по- лучится следующее: 157
ТО ВРАЩАЮЩИЙСЯ КВАДРАТ : SIZE : ANGLE SQUARE:ANGLE ВРАЩАЮЩИЙСЯ КВАДРАТ : SIZE + 3 : ANGLE END Например, по команде ВРАЩАЮЩИЙСЯ КВАДРАТ 1 10 черепаха построит последовательность квадратов, первый из которых имеет сторону длиной в 1 шаг, а сторона каждого следующего квадрата на 3 шага длиннее сторо- ны предыдущего, и сам квадрат повернут на угол 10° от- носительно предыдущего. Если несколько изменить про- цесс, то черепаха будет двигаться лишь до тех пор, пока сторона квадрата не достигнет предельных размеров, на- пример длины в 100 шагов: ТО ВРАЩАЮЩИЙСЯ КВАДРАТ : SIZE : ANGLE IF : SIZE > 100 THEN STOP SQUARE : SIZE RIGHT : ANGLE ВРАЩАЮЩИЙСЯ КВАДРАТ : SIZE + 3 : ANGLE END В некоторых вариантах языка ЛОГО (например, в ТИ ЛОГО) наряду со всем известной черепахой действуют «лилипуты». Они могут находиться в определенной точке экрана или перемещаться с заданной скоростью в ука- занном им направлении, но не могут рисовать (т. е. оставлять за собой след). На экране можно создавать и размещать где угодно различные фигурки (например, мальчиков, девочек, собак, супружеские пары, лодки, автомашины, домики, самолеты, звезды, дубы, ели и т. д.). Неодушевленные предметы и живые существа мо- гут перемещаться медленно или быстро, плыть, лететь, увеличиваться или уменьшаться в размерах, окрашивать- ся в цвета 16 различных оттенков. С помощью «лилипу- тов» на экране можно создать поистине сказочный мир. Возможности графической системы языка ЛОГО по достоинству признаны и получили широкое распростране- ние в мире вычислительной техники.
ОГЛАВЛЕНИЕ Предисловие к русскому изданию.............................. 5 Предисловие................................................. 7 Глава I. Знакомство с компьютером. Каталин Фрид ... 8 Об основах программирования................................. 8 Машинная логика......................................... 9 Первые шаги................................................. 9 Выдача на экране дисплея: инструкция PRINT.............. 9 Как из инструкций составить программу?................. 11 Еще раз об инструкции PRINT............................ 12 Повторим пройденное.................................... 13 Условная передача управления .......................... 14 Цикл................................................... 14 Игры со словами............................................ 16 Символьные переменные.................................. 16 Построение слов........................................ 17 Кодирование............................................ 19 Птичий язык............................................ 20 Узоры.................................................. 21 Заглянем в память компьютера!.............................. 24 Глава II. Графика. Янош. Кенеш............................. 25 Введение................................................... 25 Экран дисплея.......................................... 27 Тонкое разбиение экрана дисплея ....................... 29 Элементы изображения....................................... 30 Точки.................................................. 30 Не выходить за границы экрана!......................... 34 Построение графиков функций............................ 36 Как провести прямую.................................... 38 Окружность........................................’. 40 Параметрические кривые................................. 41 Случайные элементы......................................... 43 Случайное заполнение .................................. 44 Случайное блуждание.................................... 44 Случайное блуждание с инерционным запаздыванием ... 46 Как управлять распределением вероятности............... 47 Кодирование............................................ 52 Кодирование ломаной в виде символьной переменной АЗ 52 Графика.................................................... 55 Статичные изображения.................................. 55 1. Шахматная доска................................. 55 2. Построение графиков функций на экране «в клеточ- ку» и «в полосочку»................................ 56 3. Интерференционные картины....................... 57 4. Узоры на ткани.................................. 59 5. Лабиринт........................................ 60 6. Дерево I........................................ 62 7. Дерево II....................................... 64 8. Одуванчик....................................... 64 Движения............................................... 67 1. Змея............................................ 68 2. Игра «Жизнь».................................... 69 3. Фигуры Лиссажу.................................. 70 4. Космические орбиты.............................. 70 159
Глава III. Компьютеры и преподавание в школе. Турул Тёрёк 72 Введение................................................... 72 Компьютер-часы и регулировщик движения................. 76 Кодирование............................................ 78 Вероятность................................................ 80 Перемешивание.......................................... 82 Элементы теории вероятностей........................... 84 Доска Гальтона......................................... 87 Дни рождения........................................... 90 Вопросы — ответы........................................... 91 Программированное обучение............................. 91 Бар-Кохба.............................................. 95 Поиск на экране дисплея................................. 100 Тепло-холодно (игра для детей от 6 до 12 лет) . . 101 Мухи (игра для детей среднего и старшего школьного возраста)......................................... 101 Немая карта....................................... 103 Физика...................................................... 105 Закон Архимеда........................................ 106 Изменение потенциала ................................... 107 Свободно брошенное тело — планеты — космические корабли 109 Моделирование............................................... 113 Хищники и жертвы................................" . . 114 Животноводческая ферма.................................. 115 Процессы поиска............................................. 117 Графы................................................. 117 Поиск пути обхода графа................................. 119 Арифметика на буквах.................................... 121 Музыка.................................................. 126 Глава IV. Моделирование игр на персональных компьютерах. Каталин Фрид.............................................. 134 Компьютер как партнер в игре................................ 134 Несколько слов о «приключенческих играх».................... 140 Глава V. БЕЙСИК — «ЛОГО — ФОРТ? Калман. Строкой . 142 Введение в ФОРТ............................................. 145 Введение в ЛОГО............................................. 152 ЭТЮДЫ О ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ Главный отраслевой редакюр .7 /1. Ерлыкин. Редактор Г. Карпове кий. Мл. редак- тор //. /1 Сергеева Ху дож редактор М. А. Бабичева. Художник А. Е. Григорьев. Техн, редактор И Е. Жаворонкова. Корректор Н. Д. Мелешкина. И Б № 8084 Сдано в набор 04.02.88. Подписано к печати 26.07.88. Формат бумаги 84Х Ю8‘/ы- Бума! а офсетная № 2. Гарин гура Дитера i урная Печать офсетная. Усл. нем. л. 8,40. Усл кр -огт. 17,22. Уч.-изд. л. 8,11. Тираж 70 000 экз. Зака! Л-85 Цена 45 коп. Издательство «Знание». 1018.35, ГСП. Москва. Центр, проезд Серова, д. 4. Индекс заказа 887722. Типография издательства Татарского ОК КПСС. 420066. Казань, ул. Декабристов. 2.
45 коп. ЭТЮДЫ О ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ Эта книга, по замыслу ее авто- ров и составителей, призвана прмсчь 'читателю совершить,пер- вые и потому особенно трудные шаги к овладению техникой ра- боты с персональным компьюте- ром. Не требуя ни особой теоре- тической подготовки, ни даже элементарной компьютерной гра- мотности, книга предполагает со стороны читателя только готов- ность к сотрудничеству. Само- стоятельное обдумывание пред- лагаемых идей, поиск новых ва- риантов решений задач, выиг- рышных стратегий и, разумеется, самый активный диалог с персо- нальным компьютером будут способствовать скорейшему обретению навыков и умений, - необходимых для наиболее пол- , ногСг- рспользования всех зало- женныхе-персональный компью- ’ тер возможностей.
А ПЕРЕВОДНАЯ НАУЧНО-ПОПУЛЯРНАЯ ЛИТЕРА ТУРА ЭТЮДЫ О ПЕРСОНАЛЬНЫХ КОМПЬЮТЕРАХ -Г,' Гч .• ETUDOK S7H\1ELY! SZAMITO-GEPEKRE