Как Петя Бейсиков Тоню Соображалкину программировать учил [Бруно Янович Мартузан] (fb2) читать онлайн


 [Настройки текста]  [Cбросить фильтры]
  [Оглавление]

О программировании вообще и о языке Бейсик в частности

Перевод с латышского языка с дополнениями

В. MARTUZANS

КА PECIS BEISIKANS MAIJU SAPRATINU PROGRAMMEТ MACIJA

Izdevnieciba «Zinatne»

Riga 1987

Рисунки Р. Р. ВИТКОВСКОГО

Рецензенты: канд. физ. — мат. наук М. О. ЭГЛАЙС, канд. физ. — мат. наук И. Э. СТРАЗДИНЬШ

Печатается по решению Редакционно-издательского совета Академии наук Латвийской ССР

@ IzdevniecTba «Zinatne», 1986 © Перевод на русский язык с дополнениями Издательство «Зинатне», 1987

О ЧЕМ ГОВОРИЛИ ТОНЯ И ПЕТЯ, ПРОЧИТАВ ВСЕ ПОСЛЕДУЮЩЕЕ

— Я тебе, Тоня, скажу, что книжка получилась ничего…

— Ну конечно! Ведь ты там такой умный, такой умный, прямо дрожь берет! А я? Понадобилась глупышка, так сразу: где эта Соображалкина опять запропастилась?!

— Не преувеличивай, совсем не такой уж глупой ты там изображена. Но какое-то представление о программировании книжка должна дать…

— Конечно, должна, конечно, даст! Таким, как ты, кто уже программирует и даже других обучает. А тем, кто начинает с самого начала? Тем трудные места придется по нескольку раз изучать.

— А в других местах простые вещи мусолятся и мусолятся…

— Скажу откровенно: это твоя привычка, так что в этом отношении все правильно, раз уж описывать наши беседы.

— Между прочим, мне кажется, что совсем необязательно старательно изучать непонятное место. Можно попробовать читать дальше, вдруг что-то напутано и непонятное будет объяснено потом. И вообще в программировании хорошо понять начало можно только тогда, когда понимаешь конец, а конец, естественно, нельзя понять без начала. Поэтому, читая середину, есть смысл иногда полистать и начало. А если во время чтения встречаешь такое понятие программирования, которое уже успела забыть, то посмотри в конце книги предметный указатель, чтобы узнать, на какой странице о нем шла речь.

— А будет ли толк от всего этого чтения? Электронную вычислительную машину человек может увидеть, только случайно попав в Вычислительный центр. «Да, милые дети, это наша замечательная эвээм, эту кнопочку можете нажимать, а больше ничего не трогайте. Ой! К тому шкафчику не прислоняйтесь, и ты, малышка, не засовывай палец в ту щелочку!» Скажешь, что не так?

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

— Нашелся прорицатель! Что же может измениться за несколько лет?

— Вот увидишь!

— А сейчас? Кому нужны такие книжки, если свою программу сможешь пропустить только через несколько лет, и притом совсем не на той машине, о которой здесь речь?

— Мне трудно судить, так как я сам попал на машину с самого начала. Но все-таки мне кажется, что в программировании не самое важное знать, что какая клавиша на каждой машине означает и как свою программу запустить. Самое важное — сообразить, что вообще можно и нужно делать и как.

— Сообразить, что вообще надо делать…

— Ну да! И для этого никакая машина не нужна. Сиди и соображай, пока не сообразишь.

— Вполне возможно. Мы же тоже не только на машине работали. Еще и дома изучали готовые программы.

— А программы для упражнений ты ведь писала, спокойно сидя за столом.

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

— Ясное дело, просветлялись. Но только потому, что до этого ты слышала мои пояснения, как бы ты их не называла! Таким же образом стоит поизучать эту книжку до того, как попадешь на машину. Самое важное, чего, не пропуская программу на ЭВМ, нельзя будет понять, — это то, что программирование в самом деле одно сплошное исправление ошибок. Что массу ошибок содержат даже те программы, которые их авторам кажутся чуть ли не идеальными.



— Да… Эти ошибки… Но все-таки ты не прав, что программы состоят только из ошибок. В конце концов ведь каждая программа работать начинает! Конечно, большие программы, в которых тысячи строк, действительно трудно составить, в особенности если с самого начала плохо спланирована вся работа… Этими вопросами я интересовалась, так как, кажется, подамся на физмат. Могу тебе открыть такой секрет.

— Я-то еще не решил окончательно. Физмата я немножко боюсь. Что-нибудь попроще…

— …и полегче. А зачем тебе программирование, если легкой жизни хочется? Между прочим, это высказывание в книжке цитируется как твое.

— Я от него не отказываюсь. Но ведь избежать легкой жизни можно в любой профессии, а кроме того, у физмата уже нет никакой монополии на программирование. Ты же понимаешь, что персональный компьютер скоро станет обыденным орудием труда, первым помощником и советчиком каждого человека. Так сказать, лучшим другом несобранного человека.

— Похоже, камушек в мой огород. А Петя Бейсиков, заманив Тоню Соображалкину на физмат, видимо, собрался в писатели…

— Чтобы в своем первом романе отразить процесс компьютеризации Тони Соображалкиной и влияние этого процесса на гармоническое развитие ее личности. Прекрасная идея!

— Ну-ну! Я тебе не подопытный кролик. А жертвовать своим талантом программиста и стать сомнительным инженером пусть и человеческих душ — ой, Петя Бейсиков, опомнись!

— Сама спровоцировала. Ну ладно, считай это шуткой. Все-таки хотелось бы достигнуть вершин программирования…

— Ну, тогда до встречи на физмате?

— Чао!

1. КАК ВСЕ НАЧАЛОСЬ

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

И вдруг… Тоня Соображалкина из параллельного класса! Идет навстречу! Петя быстро взглянул направо. Стена дома! Обычная стена и ни одного входа в магазин или в подъезд. Налево и смотреть было нечего. Там была улица, ехали машины, а Петя еще с детского сада презирал людей, переходящих улицу в неположенном месте.



Делать нечего, надо продолжать идти. И Петя пошел! Конечно, чуть склонил голову, наморщил лоб и вообще напустил на себя вид человека глубоко задумавшегося. Может быть, удастся проскочить… Не удалось.

— Чао, Бейсиков! — услышал Петя. Пришлось вздрогнуть, вроде бы от неожиданности. — А-а! Это ты. Привет!

— Куда путь держишь?

— Я?… Я вот… Да вот в Центр хочу поехать.

— Куда это в центр? Прошвырнуться или в кино махнуть?

Не собирался Петя Бейсиков Тоню Соображал-кину в свои планы посвящать. Соврать что ли? Петя смог бы и соврать, это ему приходилось делать и получалось ничего, вполне сносно. Однако, чтобы врать, нужна была веская причина, а так, с ходу, серьезную причину найти не удалось.

— Да нет… Я вот… Я еду в Вычислительный центр. Я там немножко иногда программирую на ЭВМ.

— Да-а?! А что, тебе в школе мало задают, или ты в математики собрался?

— Я еще не знаю, куда я собрался, — Петя действительно не знал, — а задают мне, я думаю, как всем. Многие же ходят на плавание или там на занятия кружка филателистов, а я вот — на программирование. Ведь сейчас программировать должен уметь каждый человек.

Тут Тоня возмутилась.

— Вот загнул, Бейсиков! Если я не учусь в физматклассе, то я… то я не человек что ли?!

Такой бурной реакции Петя не ожидал, но спокойствия не потерял и стал объяснять:

— Ну что ты! Ты тоже можешь научиться. Это не сложно, а ты по математике хорошо сечешь.

Петя Бейсиков это знал, потому что приходилось с Тоней встречаться на школьных математических олимпиадах и — что тут скрывать — Тоня, как правило, выступала лучше его, хотя учителям и приходилось минут по десять тратить на успокоение Тони, которая то заявляла, что задача неправильная, то искала ручку по всему классу, то громко требовала успокоить своего соседа по парте и тому подобное.

Чуть подумав, Петя добавил:

— Правда, мне кажется, что математику можно и не знать очень хорошо, чтобы научиться программировать.

— Э-э! — воскликнула Тоня — знаю я это программирование. У соседки по лестничной клетке такие занятия уже были. Сначала все они ждали-гадали, что это такое, а потом оказалось — такая скучища, что-то там пишут, что-то придумывают и все время эти разговоры о том, как это великолепно, как это грандиозно, как это потрясающе… было бы действительно поработать на настоящей ЭВМ. Ты тоже так занимаешься? — съехидничала Тоня.

— Совсем не так! Извини, но я работаю по-настоящему — составляю программу, которая действительно будет нужна. Конечно, если что-то путное получится.

— Ну да! Так уж я и поверила! Станут тебе доверять что-нибудь действительно нужное.

— Почему бы и нет?! Я же не первый год работаю и не одну программу составил. Были, конечно, и учебные, но были и совсем настоящие, которые вполне можно использовать. А если честно, то это занятие мне нравится и я просто не могу дождаться возможности посидеть за дисплеем.

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

— Ого! Можно сказать, что ты хорошо устроился. На настоящей ЭВМ поработать, это, пожалуй, неплохо… Но нам, простым смертным, на это рассчитывать не приходится.

— Нет ничего проще! — воодушевился Петя. — Можешь поехать со мной. Поиграешь с машиной в игры, посмотришь, как я работаю, а если захочешь, я и тебя научу.

— Ха-ха-ха! Петя Бейсиков в роли училки! Тут любой компьютер со смеху умрет. Но посмотреть-то можно. Поехали!

Вот так Тоня Соображалкина оказалась в Вычислительном центре.

2. ПЕРВОЕ ЗНАКОМСТВО

— Ну вот, смотри! Это и есть электронная вычислительная машина, или компьютер, называют ее СМ-4. Это такое же название, как для автомобилей «Москвич» или «Жигули». К сожалению, разных типов компьютеров куда больше, чем типов автомобилей, и притом, если человек освоил какой-нибудь один тип, то это не означает, что он с ходу сможет работать на другом.

КОМПЬЮТЕРЫ БЫВАЮТ ВСЯКИЕ
— Тогда какой же смысл браться за изучение, если не знаешь, на каком компьютере придется потом работать.

— Да нет! Это не так страшно. По существу, они все одинаковы, и если освоен какой-то один компьютер, то другой освоить будет намного проще. Ну придется освоить десяток-второй новых слов или пару новых понятий.

— Это-то ничего.

— Мне, правда, рассказывали и о других отличиях. Например, в возможностях компьютера. Один компьютер может сделать больше, другой — меньше.

— Это-то ясно. Чем машина больше, тем она лучше. Эта машина же намного меньше других. Я по телеку видела совсем большие…

— Ты неверно рассуждаешь. Скажем, у больших машин большая память — намного больше, чем тебе надо. И что тебе от этого? Быстродействие тоже у разных машин разное. Большие машины, в отличие от маленьких, выполняют больше арифметических операций в секунду, например несколько миллионов. А если тебе надо выполнить только сто тысяч операций? На большой машине затратишь одну десятую секунды, на маленькой — всю секунду. Какая тебе разница, ждать секунду или десятую секунды?

— Сто тысяч операций в секунду… Сто тысяч… Жуткое количество! Кому это может понадобиться выполнить сто тысяч операций?

— Это еще мелочь. Обычно люди здесь, в Вычислительном центре, считают часами. Правда, нужно еще учесть, что выполняются не только арифметические операции, но и другие тоже. Например, пересылка различных данных с одного места на другое.

— Ну, про это потом. Скажи лучше: что где находится в этом компьютере?



ИЗ ЧЕГО СОСТОИТ КОМПЬЮТЕР
ОПЕРАТИВНАЯ ПАМЯТЬ

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

— И все это происходит в этих шкафах?

МАГНИТНЫЕ ДИСКИ

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



— Насколько могу судить, запись на эти диски происходит совершенно так же, как на магнитофонную ленту.

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




— Почему же нельзя обойтись одними дисками?

— Почему? Может быть, потому, что магнитная лента дешевле магнитного диска.

— Хорошо, оставим ленты в покое. Пока я ничего на них не собираюсь писать. А это что за устройство?

— Это печать. На ней можно выпечатать тексты программ и результаты их работы. Видишь, здесь что-то напечатано.



ЯБВГДЕЖЗИЙКЛИНОПРСТУФХЦЧШЩЫЫЬЭЮЯ1234567890

— Выглядит совсем неплохо. И буквы, и цифры составлены из симпатичненьких точечек.

— Поэтому-то такие устройства печати называют мозаичными устройствами. Точечки, из которых составлены буквы, цифры и специальные знаки, одним словом — символы, выбираются из 35 точечек, расставленных в виде прямоугольника 7x5.


Печатаем так!


ДИСПЛЕЙ — КОМПЬЮТЕРНОЕ ОКНО В МИР
— А уж этот телевизор, наверняка, самый главный?

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

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

— Ну вот! Это же то же самое, и нечего придираться.

КОМПЬЮТЕР — СУЩЕСТВО БЕЗМОЗГЛОЕ
— Нет, не то же самое. Важно понять, что компьютер сам ничего не решает. Он делает только то, что программист запрограммировал. Конечно, действия компьютера иногда выглядят вполне разумно, но сам — я говорю, сам! — он может не больше, чем трактор или… или стиральная машина.



— Но ведь говорят же: трактор пашет, стиральная машина стирает или, иногда, не стирает.

— Да… Пожалуй, так действительно говорят, и действительно трактор никто не толкает, он едет сам. Но ты же не будешь отрицать, что всеми этими машинами управляет человек, на самом-то деле пашет тракторист — ему же дают премию за хорошую работу, а не трактору. То же самое и со стиральной машиной и с компьютером. Как бы не казалось, что компьютер что-то делает сам, фактически это делает программист, который когда-то составил программу. Мы сейчас эту программу пускаем, восторгаемся, как она здорово работает, а кто ее составил, мы и не знаем, и сам этот программист не знает про нас ничего. Но именно он определил, как будет сейчас работать машина. Ну, может быть, через сто лет машины и достигнут какой-нибудь самостоятельности…

— Ладно, я смотрю, ты в философию ударился. Давай ближе к делу.

КЛАВИАТУРА

— Садись тогда перед дисплеем и посмотри на клавиатуру. Клавиши с буквами здесь расположены так же, как на любой пишущей машинке. Надеюсь, ты видела пишущую машинку.


Таким видится компьютер начинающему


— Машинку я, конечно, видела, но, как там буквы расположены, не помню. Я, откровенно говоря, как-то и не знала, что у всех пишущих машинок буквы расположены одинаково.

— Это уж точно! Но клавиатура дисплея все-таки посложнее клавиатуры пишущей машинки. Вот смотри, на каждой клавише нарисована и русская, и близкая по звучанию латинская буква, хотя попадаются и совсем разные. Видишь, русская А и латинская А, русская Б и латинская В, а вот здесь русская Ж и латинская V. Так получилось потому, что в латинском алфавите почему-то две буквы «вэ» — V и W. Буква W находится вместе с русской В. Можешь понажимать на клавиши, только учти, что русские буквы будут печататься только тогда, когда нажата еще и эта большая клавиша со стрелкой. Любая из двух — правая или левая. И еще: если напечатала неправильно, то нажми клавишу с буквами ИСКЛ — здесь справа — и последняя напечатанная буква исчезнет. Еще раз нажмешь, еще одна буква исчезнет.



ТОНЯ УЖЕ НАЧИНАЕТ ДЕЙСТВОВАТЬ
— Да, клавиши нажимаются легко и приятно. Дай-ка, наберу я какое-нибудь слово.



— Странно, почему это, когда люди печатают «какое-нибудь слово», выходит именно «дурак».

— Да ну тебя! Не нравится, могу набрать вот такое:

>ДУРАКИНТЕЛЛИГЕНТ_

— Намного лучше!

— Послушай, а я хотела, чтобы «интеллигент» печатался на следующей строке.

КУРСОР

— Одного желания мало, нужно еще и все правильно сделать. Посмотри на конец строки. Видишь там маленькую горизонтальную черточку чуть ниже строки? Это курсор. Там, где находится курсор, будет печататься символ при нажатии клавиши. Когда ты напечатала первое слово, курсор остался в конце слова, поэтому нечего удивляться, что второе слово напечаталось сразу после первого. Если хочешь попасть на следующую строку, можешь нажать клавишу ввода.




MCR — TASK NOT IN SYSTEM_

>


— Ой-ой! Я, наверно, что-то сломала!

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

— А что же произошло?

— Видишь перед курсором знак «больше»— «>»? Этот знак, появившись в начале строки, означает — машина ждет команды, что ей делать. Таких команд можно было бы сейчас дать несколько, но все они строго определены, и если хотя бы один символ неправилен, то и вся команда неправильна и машина ее, так сказать, «не понимает». Такой же знак был в начале той строки, которую ты ввела в машину.


Программирование, или дрессировка компьютеров, — дело безопасное


— Ой, верно! Я его и не приметила!

— Так вот. Тот «дуракинтеллигент», что ты ввела в машину, не является, как легко догадаться, командой для машины. И машина просто вывела сообщение, которое означает, что ввод неправильный.

ЧТО ЕЩЁ ВИДНО НА КЛАВИАТУРЕ
Давай осваиваться с клавиатурой дальше. Запомни, где находятся точка и запятая, они на пишущих машинках расположены иначе. А вот специальные знаки чуть не забыл! Их вообще на пишущих машинках нет. Кроме знака процента «%», который все знают.

— А этот, рядом с ним, такой рогатый?

— Этот знак «¤» называется знаком денежной единицы, но программисты его обычно называют «солнышком». Он нам будет нужен. А этот знак «#» — «знак номера»— в программировании нужен меньше.

— Так, так. Вроде бы все знаки видела, кроме вот этого «&».

— Это, это… Я, кажется, забыл. Но мне такой знак еще не был нужен. Еще, наверно, ты не видела и другие знаки — например «\», который называется «обратная косая черта», так как есть еще просто «косая черта» — «/» для обозначения деления. А для обозначения умножения используется «звездочка» — «*». Но вряд ли все эти мелочи тебя интересуют.

ТОНЕ ЗАХОТЕЛОСЬ ПРОГРАММИРОВАТЬ
— Ничего, ничего. Рассказывай. Сдается мне, что можно было бы это программирование и немножко поизучать. Совсем напрасным такой труд наверняка бы не был. Но только можно ли будет попасть на машину?

— Думаю, что можно. Но об этом надо поговорить с Алгоритмычем.

— С кем, с кем?

— С руководителем нашего кружка программистов. Теперь, когда мы что-то о программировании знаем, он дает только руководящие указания, а работаем мы самостоятельно. А Алгоритмычем мы его прозвали потому, что он про алгоритмы только и говорит: «Главное— это алгоритм, придумайте алгоритм, не вижу алгоритма, хороший алгоритм, плохой алгоритм».

— Ну и поговорим с этим Алгоритмычем. Сегодня же, как только кончим. А сейчас продолжай.

— На сегодня, считай, хватит. О клавиатуре уже почти все. Нужно только сказать о цифрах. Смотри, они на верхнем ряду основной клавиатуры, но для того, чтобы их вводить, надо переключаться на русские буквы. Так как в основном работают с латинскими буквами и цифрами, то для того, чтобы не надо было все время переключаться туда-сюда, имеется еще одна маленькая клавиатура для цифр. Вот здесь, справа. И еще обрати внимание, что нуль выводится перечеркнутым — «Ø». Чтобы не путать с буквой «О». Ну вот и все.

— Э-э! Подожди! Поговорил и хватит! Да!? Надо же что-нибудь с машиной и поделать.

— Можешь поиграть с машиной, или, правильнее сказать, — с программой, в игры. Ну, например, погонять удава. Тебе, как начинающей, это может быть интересно, мне-то эти игры уже надоели.

— Не понимаю, как это игры могут надоесть. Вперед!

3. ТОНЯ УЗНАЕТ, ЧТО ТАКОЕ АЛГОРИТМ

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

Переговоры с Алгоритмычем действительно были успешными. Для обучения Тони выделили дисплейное время — когда можно работать на ЭВМ, а учителем назначили Петю. При этом Алгоритмыч добавил, что речь может быть только о серьезном изучении, а не о каком-нибудь там баловстве, как некоторые себе представляют освоение программирования. Тоне это замечание показалось докучливо педагогическим, но при Алгоритмыче этого она не сказала.

Став учителем, Петя к разговору тщательно подготовился, все, что знал, обдумал, а знал он не так уж мало.

Начал он, правда, слишком заумно.

В ОСНОВЕ ПРОГРАММ ЛЕЖАТ АЛГОРИТМЫ
— Прежде чем дискутировать о секундарных понятиях программ и программирования, необходимо проанализировать фундаментальное понятие алгоритма.

— Чего, чего?

— Я говорю, вначале надо понять, что такое алгоритм.

— Извольте, господин учитель. Интересно будет узнать.

АЛГОРИТМ

— Так, как на уроке требуют, я это понятие объяснить не могу. А если просто, то это набор правил, которым надо следовать, чтобы что-то сделать. Или может быть так… Алгоритм — это изложение того, что нужно делать, чтобы что-то заранее известное сделать. Но изложение это должно быть очень строгим и четким. Каждый раз, когда что-то делается, нужно предусмотреть все, что может получиться и чгс делать дальше в зависимости от того, что получилось. Не очень понятно?

— Почему же? Иди туда, не знаю куда, сделай то, не знаю что. Очень даже понятно получилось.

— Х-м-м-м. Разберем, может быть, пример алгоритма — алгоритма возвращения первоклассника Петеньки из школы домой.

— Тебя, что ли?



— Неважно. Этот алгоритм получился бы очень сложным, если его рассматривать подробно, а если так, в общих чертах, для понимания, то изложить можно легко. Кратчайший путь Петеньки домой по адресу бульвар Программистов, 38 изображен на этом рисунке. Вся сложность в том, что дом номер 36 нельзя обходить слева, если там бегает собака Бармалей, которую хозяева часто оставляют без присмотра. Бармалей по причинам, которые обсуждать нет необходимости, сильно не любит Петеньку и попросту его не пропустит. Итак, если Бармалей бегает, то дом 36 нужно обходить справа. Но тут тоже могут возникнуть сложности: у правого подъезда часто играет задира и мучитель Борька-хулиган. Это еще хуже Бармалея.

АЛГОРИТМЫ ИЗОБРАЖАЮТ В ВИДЕ БЛОК-СХЕМ
То, что я рассказал словами, можно изобразить схематически. Это будет называться блок-схемой алгоритма. Посмотри на этот рисунок.

БЛОК-СХЕМА

На блок-схеме в прямоугольных клеточках — блоках описаны действия Петеньки, не требующие никаких рассуждений, никакого решения, а в ромбических клеточках — блоках отражены вопросы, на которые Петенька должен ответить «Да» или «Нет», исходя из информации, получаемой по ходу действия. Как видишь, имеются два таких ромбика с вопросами «Бегает ли Бармалей?» и «Играет ли Борька-хулиган?»

— Да-а, схема интересная, в особенности Борька-хулиган меня впечатляет. Но, скажи, правильно ли я понимаю, что если и Бармалей бегает, и Борька-хулиган играет, то Петенька так и будет вращать головой то вправо, то влево.




ВАЖНОЕ ПОНЯТИЕ — «ЦИКЛ»
— Именно так. Он будет вращать головой до тех пор, пока на один из этих вопросов можно будет ответить «Нет» либо пока не упадет от изнеможения. А по-научному можно сказать, что в алгоритме имеется цикл. Судя по вопросу, ты его уже заметила. Цикл получается потому, что если Бармалей бегает и Борька-хулиган играет, то стрелка от последнего ромбика снизу возвращается наверх и попадает в блок «Посмотри налево». Цикл имеет два выхода по условию. Вот здесь на схеме я их отметил. Других выходов из цикла нет, следовательно, другим образом цикл прекратиться не может. Вот и все.

ЦИКЛ

— Хорошо. Излагаешь ты не бог весть какие премудрости, но привыкнуть надо. И еще вот что. Когда мне удается решить задачку по математике, я иногда ее «проразмысливаю» — а что будет, если это условие изменить, а что, если этот угол не прямой, как в задаче, а острый, а что, если… и так далее. Давай «проразмыслим» и твой алгоритм.

— Ну?

— Например, если Петеньке пришлось бы петлять — делать всякие повороты, то ничего существенного в твоем алгоритме не прибавилось бы: ты бы добавил сколько надо прямоугольных клеток и все.

— Да, конечно.

— Дальше. Если бы у Петеньки была возможность пойти не только направо или налево, но и прямо, и там он мог бы встретиться, скажем, с дворничихой, которая опять же, по некоторым причинам, могла бы Петеньку начать перевоспитывать, чего он просто не выносит, то что делать в этом случае?

В этом случае добавились бы прямоугольна клетка — «Посмотри прямо» и ромбическая клетка с проверкой условия — «Работает ли дворничиха?». Вот здесь внизу сразу после блока с Борькой-хулиганом.

— Я так и думала. Но скажи мне вот что. Обязательно ли, чтобы из клеток с проверкой условия, как ты их хитро называешь, выходили именно две стрелки — одна для ответа «Да», другая для ответа «Нет»? А что будет, если задавать вопрос, на который возможно дать больше чем два ответа, и совсем не такие простые, как «Да» или «Нет»? Такой вопрос может быть в алгоритме или нет? Ну, скажем, если я спрашиваю «Сколько тебе лет?» или «Куда направился, Петенька?»

— Так… Минуточку… Глубоко копаешь… Ясно! И в этом случае все можно изобразить ромбическими клетками! Но может потребоваться целая последовательность таких клеток с проверкой условий типа «Идет ли Петенька домой?», «В школу?», «На кружок?» и так далее, перечисляя все возможные варианты. На все эти вопросы уже можно ответить «Да» или «Нет». Получается не так уж плохо: даже довольно сложные действия можно описать вопросами, на которые нужно ответить «Да» или «Нет». В алгоритмах, как это ты скоро поймешь, могут быть только такие вопросы.

— Понятно. А скажи — почему ты в самом начале говорил, что настоящий алгоритм движения Петеньки домой намного сложнее?

ВВЕДЕНИЕ В РОБОТОТЕХНИКУ
— А как же! Представь себе робота, который вместо Петеньки ходил бы в школу, ну и, конечно, из школы домой…

— Охо! Вот такого-то робота я бы хотела!

— И был бы этот робот совсем похож на Петеньку, даже в его сложных отношениях с Бармалеем и Борькой-хулиганом. Что он должен был бы уметь? Если говорить о приходе из школы домой, то перво-наперво он должен был бы уметь выходить из школы. А что означает выходить из школы? Самое первое — открыть дверь, то есть найти дверную ручку, нажать ее, потом дернуть дверь с нужным усилием, раскрыть ее, насколько нужно, потом протиснуться в образовавшуюся щель и закрыть дверь, притом достаточно тихо, чтобы не вступить в конфликт с представителями коллектива педагогов.


Нажать?… Не нажать?… Нажать?…


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

— Какие же здесь могут быть аварии?

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

— Да-а… Становится ясно, почему до сих пор нет роботов, ходящих в школу вместо ребят. А жаль…

— Ладно. На сегодня хватит.

— Да, хватит. Хорошего понемножку.

4. ЕЩЁ ОДИН АЛГОРИТМ

Когда на следующий день Тоня и Петя опять встретились, чтобы продолжить занятия по программированию, Петя предложил:

— Сегодня рассмотрим еще один алгоритм.

— Слушай, может быть, хватит алгоритмов и общих рассуждений, давай поближе к ЭВМ и к тому, как на них работать.

— Мм-м… Я все-таки думаю, что этот алгоритм нужно посмотреть. Там имеется один важный, на мой взгляд, нюанс. Я быстро.

— Ну ладно…

АЛГОРИТМ ДЛЯ НАЧИНАЮЩИХ УЧИТЬСЯ


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

— Ну, ну!

— Сейчас посмотрим блок-схему алгоритма.

СЧЕТЧИК

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

— Но очень странно, что сразу после того, как этот счетчик стал равным нулю, проверяется, не равен ли он десяти. Чего же там проверять?

— В самый первый раз это действительно излишне, хотя и никакой ошибки в том нет. Но если ты изучишь эту схему до конца, то заметишь, что в этот блок нужно возвращаться после окончания каждого класса и проверять, не стал ли счетчик К равным десяти, то есть не окончила ли ты школу? Зачем же зря стараться и еще ходить в школу, если она уже закончена?!


…а счетчик каждый раз отмечает


РАБОТА СО СЧЕТЧИКОМ КЛАССОВ
— Но скажи, не ошибся ли ты, написав такое странное равенство К=К+1? Ведь этого никогда не может быть!

— Так-то оно так, но К=К+1 здесь не означает, что число К равно себе плюс единица. Это означает следующее: к теперешнему значению величины К прибавить единицу и полученный результат объявить новым значением К. Еще программисты говорят: присвоить величине К ее значение, увеличенное на единицу, или совсем коротко: увеличить значение К на единицу. На самом деле здесь знак «=» означает не «равно», а «присвоить значение». В программировании такие отличия от привычного для школьника встречаются довольно часто.

— Ничего, привыкнем и к программированию. Но как мы могли бы «проразмыслить» твой новый алгоритм? Конечно, он неполный, как ты и признавал. Но особенно мне не нравится, что ты не предусмотрел возможность уйти из школы после восьмого класса. Дай-ка, я добавлю эту возможность, посмотрим, что из этого получится.

ТОНЯ УЛУЧШАЕТ АЛГОРИТМ
Думаю, что проверку на выполнение условия «Равно ли К восьми?» нужно поставить перед проверкой на равенство десяти. Тогда, если восемь классов не окончено, ничего особенного не происходит, идем дальше проверять условие «Равно ли К десяти?». А если восемь классов окончены?… Тогда проводим проверку условия «Желаешь ли уходить в ПТУ?». Если желаешь, то, конечно, уходи, а если нет…, а если нет… то вот как! Иди прямо на прямоугольный блок «Учиться серьезно 1 год в К+1-м классе», так как нет никакой необходимости возвращаться и проверять, равно ли К десяти, когда только что этот К исследовали и нашли, что он равен восьми и, значит, никак не может быть равен десяти.

— Кстати, можно было бы и проверить, никакой ошибки не возникло бы, просто лишняя работа. На мой взгляд, лучше было бы проводить проверку насчет ПТУ не тогда, когда окончено розно 8 классов, а когда окончено больше или ровно 8 классов. Ведь человек может захотеть уйти в ПТУ и после девятого класса. Но, конечно, может быть и такой алгоритм, как ты сочинила. Сейчас изобрази его графически.

— Я нарисую только небольшой кусок блок-схемы. Зеленым цветом я нарисовала добавки, а черным то, что было раньше.



— Нарисовано великолепно. Особенно красиво выделяется эта зелень. Но, увы, в твоем алгоритме имеется грубейшая ошибка, которая делает весь алгоритм совершенно непригодным, несмотря на изумительное оформление.

ОШИБКА!
Да ну! И нечего издеваться, даже если и имеются ошибки… Хм… я ничего такого ошибочного не вижу.

— А ты посмотри сюда: стрелка приходит снизу в блок с проверкой условия «Равно ли К десяти?» сразу после увеличения значения К. Именно эта стрелка фактически создает цикл, и сейчас получилось…

— А-а-а!…получилось, что проверка условия «Равно ли К восьми?» осталась снаружи цикла и проводится только один раз в жизни, когда К еще равно нулю и человек только что начал учебу. Получилось, что добавление нового условия ничего не дает. Да-а-а…

— Ничего страшного. Эту ошибку легко исправить: надо стрелку, входящую в блок с условием «Равно ли К десяти?», поднять, чтобы она входила в блок с условием «Равно ли К восьми?». Вот так, как я сейчас исправил.

— Ясно. Сейчас все правильно.

— Никогда нельзя точно знать, все ли правильно. Ошибки случаются всегда, и глупые тоже. Но могу тебя обрадовать: программисты это знают очень хорошо и никого за ошибки не ругают. Программировать — это совсем не то же самое, что контрольную писать. Программист должен уметь искать ошибки, готовиться их искать и учиться искать, насколько уж можно научиться. Главное, не надо воображать, а надо серьезно работать и стараться, а не…

— Не кажется ли тебе, что ты здорово увлекся моим воспитанием? А я должна заметить, что имею полный набор воспитателей, и не каких-нибудь там бездельников и халтурщиков, а честных тружеников, работающих в поте лица, и притом весьма успешно.

Пете так не казалось, но спорить он не стал, а предложил еще раз просмотреть всю блок-схему целиком и на сегодня кончить.



Выловить ошибки в программе нелегко

5. ЯЗЫКИ, ЯЗЫКИ, ЯЗЫКИ…

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

Однако по дороге Петя все еще продолжал говорить об алгоритмах.

МИР СОСТОИТ ИЗ АТОМОВ И АЛГОРИТМОВ
— Знаешь, Тоня, сами эти алгоритмы ты, конечно, можешь забыть хоть сейчас. Но чтобы работать с ЭВМ, на мой взгляд, надо проникнуться духом алгоритмизации. Понять, что всюду вокруг нас одни только алгоритмы, алгоритмы и ничего, кроме алгоритмов. Сложные и простые, жутко глупые и восхитительно остроумные. Что каждое утро, проснувшись, ты начинаешь выполнять алгоритмы — алгоритм одевания, алгоритм уборки постели, алгоритмы умывания, причесывания, алгоритм подогрева воды для чая, алгоритм хождения и так далее и тому подобное. В общем всегда, когда мы что-то делаем, мы выполняем какой-то алгоритм.


Нас ведут наши алгоритмы


— Так уж и всегда? Может быть, ты слышал про такое явление природы, как любовь? У тебя имеется уже алгоритм на тот случай, если вдруг, совершенно случайно, тебе придется решать подобные проблемы?

— Ну, насчет всегда я преувеличил малость. Это должно было быть ясно. Кроме твоего, можно привести и другие примеры, когда алгоритма нет. Например, вряд ли можно было бы предложить алгоритм мышления.

— Да? Но говорят же про мыслящие машины, про искусственный интеллект. Разве ты не читал?

— Ой, знаешь, мне кажется, что это сплошное запудривание мозгов! Правда, я пока мало что знаю по этим вопросам, но одно мне совершенно ясно: мышления ни в одной машине нет и интеллекта тоже. Дело в том, что люди, говорящие про искусственный интеллект, придают этим словам совсем другой смысл, чем ты, и тогда их бывает трудно понять. Хотя бывают и такие, кто этими словами пользуется для обмана простачков.

Чуть подумав, Петя добавил:

— Если ЭВМ иногда и в состоянии делать что-то достойное разумного существа, то проявляется при этом совсем не какой-то там мистический искусственный интеллект, а самый что ни на есть естественный интеллект программиста. И первое, где интеллект программиста должен проявиться, это создание алгоритма. Нужно четко описать все, что надо делать, как я уже тебе говорил.



Точность! Точность превыше всего!


— Что-то не верю я в эти твои алгоритмы. Вот мучился ты, мучился и создал великий алгоритм прихода Петеньки из школы домой. А что толку? Кому нужен этот алгоритм?

ЕЩЁ ОБ АЛГОРИТМАХ
— Это-то верно, любой школьник доберется до дома и без точного алгоритма. А представь себе, что ему нужно пересекать улицу? Тут он должен следовать достаточно четким правилам уличного движения. Правила, конечно, не такие уж сверхсложные. Красный свет — прохода нет, зеленый свет — вперед, Петь! Но ведь никто не рождается со знанием этих правил или, по-нашему, по-программистски, алгоритмов, их надо выучить, а всегда легче выучить то, что ясно и точно сформулировано. Разве не так?

— Конечно, так, но я не понимаю, к чему ты все это говоришь?

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

— Хэ-хэ! «Машины подъезжают», «дальнейшее поведение машин»— и это говорит человек, который совсем недавно выступил спламенной речью о том, что машины сами ничего не могут делать.

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

— Кажется, совсем просто.

— Именно, что кажется, а когда начнешь делать, то соберется столько мелочей, которых надо учесть, что немудрено запутаться.

— Это кому как. Мне иногда труднее всего начать работу, а как начнешь…! Сразу все становится легко… Странно получается, что я всю жизнь выполняла всякие алгоритмы и даже не подозревала об этом. Как-то и не верится. Единственное, что меня немножко в этом убеждает, так это твои примеры с утренними алгоритмами школьницы, варящей чай… Но самого главного ты все-таки не сказал. Как работает компьютер, как он понимает, что надо делать?

— Ничего он не понимает! Я же сказал, что на самом деле он понимает не больше, чем… чем телевизор, показывающий очень умную передачу!

— Но все-таки, как это получается, что выглядит, будто он понимает?

— Если честно, то до конца я этого не постиг. Меня этому не учили, сказали, что тогда надо осваивать машинные команды, двоичную арифметику, математическую логику и бог знает что еще. Все это можно и освоить, науки хоть и непростые, но понятные. Однако совсем необязательно знать, как работает двигатель, чтобы ездить на автомобиле без аварий. Я тебе могу рассказать только ту часть, что нам рассказал Алгоритмыч. Он утверждал, что этого достаточно, чтобы составлять программы для ЭВМ, имеющие смысл и пользу. И похоже, что не обманул, действительно достаточно, но иногда и меня мучает мысль: что же там внутри машины происходит?

— Что же делать, раз ты такой недообразованный. Расскажи тогда то, что ты так блестяще усвоил.

ЯЗЫКИ ДЛЯ ОБЩЕНИЯ С КОМПЬЮТЕРАМИ
— Речь идет об алгоритмических языках, или языках программирования. Точнее, об одном из них — Бейсике, который я знаю и на котором составляю программы, какие уж умею. Об этом языке я тебе скоро расскажу.

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

— Зачем ты так. Я же честно говорю, что я знаю и чего не знаю.

— Это для профилактики, Бейсиков. Чтоб не зазнавался.

— Но немножко о языках программирования вообще придется поговорить. А то ты освоишь один только Бейсик и покажется тебе, что ты стала такой умной, такой умной, ну прямо как директор школы.

— Ладно, ладно. Можешь продолжать, счет один — один.


Язык программирования — это что-то вроде заклинаний


— Так вот, ЭВМ обрабатывают информацию, только и всего. Это означает, что в них вводят какую-то информацию и от них получают какую-то информацию. Более просто, в них вводят какие-то символы — цифры или буквы и получают в ответ тоже какие-то символы. Разумеется, крайне желательно, чтобы полученные символы имели какой-то смысл.

— Что-то тебя все тянет к философствованию. Объясни глупой девчонке как-нибудь попроще. На примерах, на простых примерах.

— На примерах? Знаешь ли, ты получишь целую кучу разнообразных примеров, когда доберемся до работы на машине. А пока такой пример. Представляешь машину, играющую в шахматы?

— Ну, представляю.

ВХОДНАЯ И ВЫХОДНАЯ ИНФОРМАЦИЯ
— Даже не важно, в шахматы или в какую-нибудь другую игру. Сначала в машину надо ввести исходную позицию — это будет для нее входная информация, или входные данные. После этого, чтобы получилась игра, нужно ввести в машину свой ход. Это тоже входная информация. А машина, получив ход играющего с нею, должна эту информацию обработать, конечно, учитывая текущую позицию. Результатом такой обработки информации будет ответный ход, который она должна вывести, иначе никто его не узнает. Этот ход и будет выходной информацией, или выходными данными. Вот и все про входную и выходную информацию. Самое важное, как ты понимаешь, происходит между вводом и выводом информации, когда полученная информация обрабатывается по определенному алгоритму. В действительности этот алгоритм определяет не только то, что произойдет с информацией в машине, но-и то, какую еще информацию нужно ввести и какая будет выведена. И все эти действия нужно тщательно описать в алгоритме, и притом в форме, приспособленной для работы на машине, или, другими словами, написать программу.ИНФОРМАЦИЯ ВВОДА

ИНФОРМАЦИЯ ВЫВОДА

— Наконец-то мы и добрались до понятия, из-за которого весь сыр-бор и разгорелся.

ПРОГРАММЫ КТО-ТО ДОЛЖЕН СОСТАВЛЯТЬ
ЯЗЫКИ ПРОГРАММИРОВАНИЯ

— Что и говорить, программы нужны. Без программы компьютер будет так же полезен, как испорченный телевизор. Многие считают, например, что правильнее говорить не «компьютер играет в шахматы», а «программа играет в шахматы» или же «программа обрабатывает информацию». С ними можно было бы согласиться, так как именно программа претворяет в жизнь алгоритм игры в шахматы. Можно было бы согласиться, если не знать, что без самого компьютера программа будет только бессмысленными каракулями. Далее, ты должна понять, что программы пишут на языках программирования. Так как программа — это описание алгоритма, то можно эти языки называть и алгоритмическими языками. Еще можно сказать, что программа — это алгоритм, записанный в форме, понятной для человека и ЭВМ.

ПРОГРАММА

— Ха-ха! Опять попался! Ты же говорил, что машина ничего не понимает и тот, кто говорит, что понимает, круглый дурак.

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

— Программа — это алгоритм, записанный в форме, понятной человеку и… и…

—…приспособленной для выполнения на ЭВМ. Так можно было бы сказать. Но это не определение, можешь наизусть не учить, никто тебя не спросит.

— Неужели! А я собиралась вызубрить все твои разглагольствования.



В шахматы играет программа, а не машина!


— Тем не менее запомни: для решения какой-нибудь задачи на ЭВМ мы сперва должны придумать алгоритм. Потом, для ясности, должны нарисовать блок-схему этого алгоритма, как мы уже делали, потом написать программу и, наконец, ввести эту программу в машину. Считай, что я тебе изложил алгоритм решения задач на ЭВМ, так сказать, супералгоритм. Этот алгоритм тоже можно изобразить в виде блок-схемы, правда, совсем простой:




Ясно?

— Ну… Ясно.

ЯЗЫКИ — СРЕДСТВО ОБЩЕНИЯ
— Языков программирования очень много. Для одного типа задач лучше подходят одни, для другого типа — другие. Это прямо как в жизни. Мы с тобой говорим на языке слов, а, скажем, музыканты общаются между собой на языке нот, конечно, если дело касается исполнения музыкальных произведений. Смело можешь считать, что композитор записывает алгоритм исполнения своего сочинения на алгоритмическом языке нот. В свою очередь, и сама музыка — я имею в виду не записанную нотами, а уже звучащую — является языком — языком музыкальных звуков. Тем, кто ее понимает, она же что-то выражает.


Бейсик понимают все!


— Только музыка выражает не словами, а «образными средствами».

— Да-да. А вот другой случай. Автоинспекция программирует уличное движение на языке дорожных знаков и сигналов светофора. Вот тебе еще один алгоритмический язык, ибо как дорожные знаки, так и сигналы светофора определяют алгоритмы действий автоводителей в конкретной ситуации. Если же немножко подумать, то становится ясным, что, в принципе, и композитор, и автоинспекция могли бы все необходимое сообщить словами русского языка. Можно было бы написать: «стукни что есть силы по 27-й справа белой клавише рояля», а вместо «кирпича» повесить надпись «проезд запрещен». Понимаешь, какие это создало бы трудности?

— Чего уж тут не понять? Особенно трудно было бы тем, кто не понимает русского языка.

— Ситуация же с языками программирования такова. Каждый язык или, по крайней мере, большинство их можно считать универсальными, и как-то можно запрограммировать почти все задачи на каждом из них. Однако хорошо получится только для некоторого класса задач. Лично я знаю только один язык программирования — Бейсик. Этот язык не считается самым лучшим, может быть, потому, что проще других. Не берусь судить, насколько серьезен этот недостаток, но знакомый студент Костя Фортранкин, который программирует на языке Фортран, смотрит свысока на мои занятия. Правда, о нем самом нелестно отзывается его воображалистый однокурсник Витя Пээлло, который работает на языке PL-1.

6. НАЧИНАЕТСЯ РАБОТА

И вот Тоня и Петя опять у ЭВМ. Тоня сразу устроилась у дисплея и заявила, что работать будет она, а Петя пусть наблюдает и дает ценные указания.

— Хорошо. Пусть будет так. Но должен сказать, что пока ничего на машине произойти не может. Сначала нужно вызвать интерпретатор Бейсика.

ВСЕ ДЕЛАЕТ ИНТЕРПРЕТАТОР
— Что это такое?! Про это ты ничего не говорил!

— Это программа, которая уже составлена и хранится на магнитном диске. А предназначена она для обработки программы, написанной на Бейсике, — расшифровки, какие действия эта программа поручает машине выполнять, и более того — в самом деле эти действия исполнить. Одним словом — интерпретировать программу на Бейсике.

— Так что? Получается, что одна программа обрабатывает другую?



— Да. Так и получается, что программа на Бейсике является входными данными для интерпретатора.

— Ну и как же вызвать этот ин-тер-пре-та-тор? Ты, кажется, так сказал?

— Да. Вызвать — это означает списать программу с диска в оперативную память и запустить ее. А делает это еще одна программа…

— Да ты что! Сколько же здесь этих программ?

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

— Но что же, в конце концов, нужно делать с этим твоим интерпретатором?

ВЫЗОВ ИНТЕРПРЕТАТОРА
КОМАНДА

— Сначала обрати внимание на последнюю строчку экрана. Там ты видишь знак «больше» и рядом с ним курсор. Это означает, как я тебе уже говорил, что сейчас операционная система ждет команду. Раз ты хочешь вызвать интерпретатор Бейсика, то, разумеется, нужно ввести команду вызова. Она очень проста — BAS. Три буквы латинского алфавита. Ну, можешь вводить.

>BAS_

Все в порядке. Найди сейчас клавишу ввода и нажми.

И Тоня нажала. В одно мгновение все строки экрана переместились вверх, в том числе и введенная Тоней строчка, а снизу показался текст

IAS/RSX BASIC V02-01M

READY

— «Рэди», — прочла Тоня, — готово.

— И верно. Интерпретатор готов к работе. А строка выше означает, что работает именно интерпретатор Бейсика.

— Слушай, а что машина и впредь только по-английски будет изъясняться? Мои предки, честь им и хвала, старались изо всех сил и водили меня на растерзание к одной «англичанке», но я не могу сказать, что наши с нею мучения дали какие-то плоды.

— Тебе повезло. А что делать тем, кто в школе изучает немецкий язык и притом не очень преуспевает? Но не расстраивайся, английского языка при изучении Бейсика надо не очень много. Твоих знаний вполне хватит, раз уж ты знаешь, что «рэди» это «готово».

— Хватит болтать, ведь интерпретатор уже готов к работе. Что сейчас можно сделать?



Интерпретатор приводит в действие команда BAS


РАБОТА В НЕПОСРЕДСТВЕННОМ РЕЖИМЕ
— Сейчас можно работать с интерпретатором в непосредственном режиме, то есть почти так же, как с микрокалькулятором: все, что задашь, будет сразу выполнено.

— Например?

— Например, можешь образовать переменную А и присвоить ей значение, ну, скажем, 12. Просто введи А=12.

A=12

READY

— Ну, и что дальше? Ничего не произошло.

— Сейчас введи В=20.

— Опять ничего не произошло!

— Ничего и не должно было произойти. Пока ты только образовала две переменные и присвоила им значения. Сейчас с этими значениями, то есть с числами 12 и 20, ты можешь, например, совершить любое арифметическое действие. И какое именно ты бы хотела?

— Я хочу сделать все — и сложить, и вычесть, и умножить, и поделить тоже, раз уж такая прекрасная возможность появилась.

— Тогда поступай так. Введи С=А+В. Это означает, что интерпретатор должен образовать переменную С и ее численное значение взять равным сумме значений переменных А и В.

— Сделано. Результата нет.

РЕЗУЛЬТАТЫ ВСЕГДА НУЖНО ВЫВЕСТИ!
— Результат уже есть, но чтобы его узнать, надо вывести его на экран. Для этого существует оператор вывода — PRINT. Просто напиши это слово и после него список тех переменных, значения которых ты хочешь вывести, отделяя в списке каждую переменную запятой. Ах да! «Принт», если ты не знаешь, означает «печатать». Ну, выведи значения переменных А, В и С.



— Хорошо.

Теперь Тоня на экране видела



— Да, все-таки получилось!

— Очень удобно, что после PRINT совсем не обязательно писать одни только переменные — можно писать сразу их сумму А+В или произведение А*В, знак «*» здесь означает умножение, или частное A/В, где дробной чертой «/» обозначаем деление. Хорошо запомни обозначения арифметических действий. По-другому писать нельзя.

— А ты ничего не сказал про вычитание.

— Вычитание обозначается, как всегда, знаком минус. Итак, в операторе вывода можно писать любое арифметическое действие и, более того, любое арифметическое выражение, состоящее из большого количества арифметических действий, например (А*В+С)/С+20. Важно, чтобы длина этого выражения не превышала длину одной строки дисплея, то есть содержала бы не более 80 символов. Выведи, пожалуйста, результат расчета какого-нибудь арифметического выражения!

— Ладно. Введу я вот что.

PRINT 24/A*2

4

— Фи! Машина совсем не умеет считать. Результат должен быть 1, а не 4!

— Не может быть! Ясно. Я тебе не сказал, как в Бейсике использовать скобки. Если в знаменателе имеется произведение, оно обязательно должно быть в скобках. Если скобок не будет, то интерпретатор разделит только на первый сомножитель, а на последующие сомножители умножит. Если ты, например, напишешь 6/2*3, то шесть будет разделено на два, получится три, после умножения еще на три результат будет девять. А расчет выражений 6/(2*3) или 6/2/3 даст единицу. Повтори этот пример.

PRINT 24/(A*2)

1

READY

— Теперь правильно.

— Правильно было и в предыдущий раз: машина же честно выполнила то, что ты ей задала. А если ты задала неправильно, вини себя… Еще могу сказать, что в Бейсике имеется специальный знак для возведения в степень — стрелка вверх «!». На клавиатуре он находится здесь слева, на той же клавише, что и буква «Ч».

— Это надо попробовать.

PRINT 2^2

4

Интересно, а так получится?

PRINT A^A

8.91610E+12

Бейсиков! А это что за чепуха!

ДВЕ ФОРМЫ ЧИСЛА В БЕЙСИКЕ
— Что такое? A-а! Результат выведен в экспоненциальной форме.

— Опять новое понятие!

— А что делать? Ты лучше внимательно слушай и старательно мотай на ус. Кстати, ничего сложного здесь нет. Алгоритмыч в таких случаях говорит: это просто, как программировать на Бейсике. Чтобы определить, какое число выведено, используй такой алгоритм. Например, машина вывела в экспоненциальной форме такое число: —1.23456Е +07. Для превращения в обычную форму в этом числе сначала нужно найти букву Е и выписать символы, находящиеся слева от этой буквы, —1.23456. Получившееся число называется мантиссой исходного числа. Символы справа от буквы Е, то есть +07, в свою очередь, дадут так называемый порядок числа. И еще одна мелочь. В Бейсике при записании чисел с дробной частью вместо привычной запятой пишется точка. Запятая используется, чтобы отделить одно число от другого. Сейчас мантиссу числа нужно умножить на десять в степени, равной порядку числа, —1.23456.107, и ты получишь число в обычной записи —12345600. Еще могу добавить, что знак порядка числа выводится всегда, а знак самого числа, или, что то же самое, знак мантиссы, интерпретатор выводит только для отрицательных чисел.

ЭКСПОНЕНЦИАЛЬНАЯ ФОРМА



А сейчас передвинем точку…


— Бейсиков! Из тебя порядочный педагог никогда не получится. Как можно так долго и нудно долдонить о таких простых вещах!

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

— Ну и мстительный же ты тип! В школе — домашние работы, дома — домашние работы, так и концы отдашь, не узнав, что же такое программирование.

СКОЛЬКО БУДЕТ ДВЕНАДЦАТЬ В СТЕПЕНИ ДВЕНАДЦАТЬ!
— Ничего, ничего. Домашние работы — крайне полезное дело. А теперь напиши, какое число в последний раз выводилось на экран.

— Пожалуйста! 8916100000000.



— Правильно. Я надеюсь, ты не думаешь, что это число в точности равно двенадцати в степени двенадцать. Машина арифметические действия выполняет с точностью в шесть знаков и выводит те же шесть знаков. Нули в конце числа на самом деле не настоящие нули, а неизвестные цифры числа.

— Хоть ты и очень умный, Бейсиков, но все-таки попался. Первый нуль слева совсем настоящий нуль, потому что он был в выведенном числе. Ненастоящие нули — это те семь, которые я приписала в конце числа.



— Твоя правда. Тот нуль действительно намного более настоящий, чем другие. Но полностью за него ручаться нельзя, так как при проведении вычислений с шестью знаками шестой получается неточным. Еще запомни, что числа можно также и вводить в экспоненциальной форме. При вводе между точкой и буквой Е не обязательно должно быть ровно пять цифр, а перед точкой не обязательно писать ровно одну цифру. Например, ты можешь писать так: А=—12.3Е+04.

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

— Я это и так знаю. Когда в результате получится больше шести знаков.

— Тогда попробуй что-нибудь другое. Сегодня я тебе больше ничего рассказывать не буду, так как наше время скоро кончается и на машину придут работать другие.

7. ПЕРВАЯ ПРОГРАММА ТОНИ

В следующий раз Тоня и Петя пришли на машину с твердым намерением программировать. Тоня потребовала прекратить бесполезные разговоры и приступить к делу.

— Разговоры не так уж бесполезны, как тебе кажется. Просто ты, как и все маленькие дети, плохо понимаешь, что для тебя хорошо и что плохо.

— Давай, дедушка, кончай болтать и говори, что еще нужно, чтобы начать программировать.

КИРПИЧИКИ ПРОГРАММ — ОПЕРАТОРЫ
— Нужно совсем немного. Сперва запомни, что языки программирования состоят из операторов и каждый оператор — это просто приказ машине что-то сделать. Операторы являются составными частями языков программирования, примерно так же, как слова в русском языке. Только операторов намного меньше, чем слов. Основу программирования составляют четыре оператора. В прошлый раз ты уже познакомилась с двумя из них и мы уже употребляли слово «оператор». Так что осталось всего два.

ОПЕРATOP


Команды операторов для машины — закон


— Я в прошлый раз те два оператора как-то не заметила. Один это — PRINT. Да?

ПРИСВОЕНИЕ

— Да. Один из них оператор вывода PRINT. А другой — это оператор присваивания. Когда ты писала А=12, ты на самом деле вводила оператор присваивания — давала машине команду присвоить переменной А значение 12. Можно сказать, что оператор присваивания обозначается знаком равенства «=», слева от которого нужно писать ту переменную, которой присваиваем значение, а справа — само это значение в виде числа или арифметического выражения, которое надо вычислить. Помнишь, мы говорили об арифметических выражениях в операторе вывода PRINT. Полностью то же можно сказать и о выражениях, которые разрешается писать справа от знака равенства.

ВСЕ О ПЕРЕМЕННЫХ
ПЕРЕМЕННАЯ

Наверно, следовало бы сказать, что такое переменная, но я затрудняюсь это сделать. Ну… просто это нечто, имеющее значение и участвующее в каких-нибудь операциях или действиях, в которых это значение может измениться, а может и не измениться. И еще переменная имеет обозначение, или, как часто говорят, имя. Например, в последнем примере переменная имеет обозначение— букву «А», а значение — число 12.

— Этого я не понимаю. У тебя получается нечто такое — переменная А имеет обозначение «А». Это же какая-то бессмыслица.

— А это ты понимаешь: «ученица Соображалкина имеет фамилию Соображалкина»?

— Это-то я понимаю.

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

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




БЕЙСИК МОЖНО ПЕРЕВОДИТЬ НА РУССКИЙ
Сейчас наш знаменитый оператор присвоения А=12 переведем с Бейсика на русский язык. Получится что-то такое:

А = 12
Переменной с обозначением «А» присвоить значение двенадцать
Правда, обычно программисты не говорят «переменная с обозначением «А», а просто «переменная А».

Что еще? Могу рассказать, что переменные могут обозначаться любой буквой латинского алфавита и цифрой после нее — двумя знаками либо только буквой. Таковы правила игры Бейсика. Если подсчитать все возможности, то получается, что всего может быть 286 различных обозначений переменных.

— Не мало ли?

— Тебе хватит. Сейчас вернемся к оператору вывода и посмотрим, как его перевести на русский язык.

PRINT А, В, С
Вывести значения переменных А, В, С
— Этот перевод совсем простой.

— Какой уж есть. Про оператор вывода еще важно знать, что этим оператором можно выводить не только числа, но и другие знаки, например буквы. Можно выводить любой текст. Надо делать так: после слова PRINT написать нужный текст в кавычках или в апострофах. Ну, пиши. Ой, погоди, мы еще не вызвали интерпретатор Бейсика.

Ну вот, все в порядке. Интерпретатор готов к великим свершениям.

— Что бы такое вывести на экран?…

PRINT "ПРИВЕТ"

ПРИВЕТ

— Ты должна понимать, что вот так, в непосредственном режиме, нет никакого смысла выводить что-нибудь на экран при помощи оператора вывода. Ты же могла бы просто на экране написать слово ПРИВЕТ, и никакой возни с Бейсиком. Обычно текст на экран выводят во время работы программы, чтобы сообщить что-то о результатах ее работы.

— Интересно! Как я это могу понять, если ты еще ни слова не сказал о программах!

КАК ПОЛУЧИТЬ ПРОГРАММУ
— Уже говорю. Программа получается, если писать операторы с номерами в начале строки. Их так и называют — номера строк. Понимаешь, если ты пишешь оператор без номера, то он выполняется сразу — это непосредственный режим, с которым ты уже знакома. Но если оператор ввести с номером в начале строки, то этот оператор запоминается и вместе с другими, подобным образом пронумерованными операторами, создает программу в оперативной памяти. Запомни крепко-накрепко — в памяти! Начинающий плохо представляет, где у него программа — в памяти машины или на диске.

— Надо бы попробовать с этими номерами… Скажи, пожалуйста, любое ли число может быть номером?

— Любое целое число не больше 215-1=32767. И перед тем как начинать вводить программу, нужно ее как-то назвать и название сообщить интерпретатору — пишешь слово NEW и название программы.

— «Нью» по-русски «новый», я полагаю.

— Разумеется. Вводи.



СТРОКА ПРОГРАММЫ


NEW SUPER_

— Так будет хорошо?

— Умопомрачительно! Да, название программы может содержать до девяти букв и цифр, но первый знак должен быть буквой.

— Послушай, a NEW — это новый оператор?

ДИРЕКТИВА

— Не совсем. Это не оператор, а директива языка Бейсик. Отличие от оператора в том, что директивы что-то делают с самими программами и выполняются только в непосредственном режиме. А операторы работают в программах с входными данными и значениями переменных.

— Хорошо. Программа названа, можешь начинать ее вводить. Сначала напиши номер строки…

1 A_

А почему начинаешь с единицы?!

— Как же иначе? Раз, два, три… Так и буду нумеровать.

КАК НУМЕРОВАТЬ СТРОКИ
— Видишь ли, так, конечно, можно, но так не делают. Программисты считаются с тем, что программу потом придется переделывать, и притом не один раз: что-нибудь будет неправильно, что-нибудь придумаешь нового, и может оказаться, что нужно вставлять еще одну строку между, скажем, строками с номерами 2 и 3. А ты не сможешь, потому что дробных номеров не существует. Поэтому строки обычно нумеруют не подряд, а с каким-то шагом, например так: 10, 20, 30 и так далее. При выполнении программы закон такой — операторы выполняются в порядке возрастания номеров строк, кроме случаев, когда специально указывается номер строки, которую требуется выполнять следующей. Если имеются строки с номерами 10 и 20, а нет строк с промежуточными номерами, то никакого шума интерпретатор не поднимает, и если потом появляется необходимость вставлять строку с промежуточным номером, то это спокойно можно сделать, просто вводя строку с желаемым номером. Совершенно все равно, в каком порядке вводятся строки программы.

— Хорошо, могу и так вводить. А что делать с этой недовведенной строкой?

— Эту строку можно погасить, но лучше это вместо тебя сделаю я.

— Начну тогда с номера 10.

10 A=12

20B=20



Ой, после номера 20 я забыла оставить пробел! Надо опять погасить строку.

— Собственно говоря, не было речи о том, что после номера нужен пробел.

— Мне кажется, так было бы естественнее.

— Для интерпретатора естественно то, что правильно. Но можешь не волноваться, пробел после номера интерпретатор поставит сам. Более того, ты можешь в любом месте вставлять пробелы и можешь не вставлять, все равно лишние интерпретатор выбросит и нужные добавит. Так что продолжай.

3 °C=A+B

40 PRINT A,B,C



— Вот и все.

— Еще желательно добавить оператор END. Что это означает по-русски?

— «Энд» означает «конец» или «кончать».

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


Программу останавливает оператор STOP


50 END

— Оператор END так надо вводить?

— Именно так. В этом простейшем случае логический конец и физический конец программы совпадают.

ПРОВЕРКА ВВОДА…
— Итак, программа введена. Хотя ты и видишь на экране все введенные строки, но лишняя проверка правильности ввода не повредит. Имеется возможность посмотреть всю программу, которая находится в памяти, при помощи директивы LIST. «Лист» означает «составлять список», но это по словарю, у нас же это означает «показать программу». Это будет у тебя вторая директива языка. Директива потому, что работает с самой программой.

LIST


SUPER 21-NOV-86 14:35:20


10 A=12

20 B=20

3 °C=A+B

40 PRINT A,B,C

50 END


— Да, ты был прав. Сейчас после номера 20 пробел уже есть.

— Никто не сомневался. Еще, как ты видишь, перед текстом программы выведены название программы, сегодняшнее число и текущее время. Чтобы эта строка не показывалась, нужно использовать директиву LISTNH.

…И ЗАПУСК ПРОГРАММ
— Раз все хорошо, запускаем программу. А делается это директивой RUN.



Все за работу!


— Ха! «Ран» — это же «бежать».

— Не только бежать, но и работать — так говорят о машинах и программах. Вводим эту директиву.

RUN


SUPER 21-NOV-86 14:46:30


12 20 32


READY


Как видишь, все в порядке. Сначала интерпретатор выводит название программы, а потом результаты работы самой программы. Если выводить название программы тебе не надо, то можешь использовать вариант директивы RUNNH. Сейчас программа свою работу уже кончила: ты видишь сообщение интерпретатора READY, но значения переменных находятся в своих ящичках, и до них еще можно добраться. Их можно проверить и даже изменить, используя возможности непосредственного режима.

— Интересно, какие это возможности я бы могла использовать?

— Например, вывести произведение А и С.

— Оператором PRINT?

— Разумеется.

PRINT A*C

384

— Так, дай подумать. Результат правильный. — Еще бы! — Постой! У меня есть идея!

A=10


READY

PRINT A,C

10 32

Я подумала, что, возможно, при изменении значения А будет меняться и значение С. Ведь С — это же сумма А и В.

— Ну нет! Для того чтобы получить новую сумму, нужно заново пропустить программу, и притом с новым значением А, а так как значение этой переменной присваивается в строке 10, то эту строку нужно поменять. Менять строку крайне просто: нужно с тем же номером ввести новую, нужную строку.

10 A=10

А сейчас можно запускать. Запускай, используя RUNNH.

RUNNH

10 20 30


READY

— Не очень-то удобно делать такие замены строк, когда необходимо просчитать с другими числами.

ВВОД ВО ВРЕМЯ РАБОТЫ ПРОГРАММЫ
— Разумеется. Если нужно пропускать программу на Бейсике многократно, всякий раз с другими числами, то пользуются оператором ввода INPUT. Это будет новый — третий — основной оператор.

ОПЕРАТОР ВВОДА

— «Инпут», «инпут»… что же это значит?


Данные с экрана забирает INPUT


— Это значит — «ввод» или «вводить», еще и «положить». Каждый раз, когда интерпретатор в программе встречает оператор ввода, он заставляет машину ждать ввод с дисплея и, чтобы ты знала, что машина чего-то ждет, на экран выводится вопросительный знак. А что именно она должна ждать, значение какой переменной, это программист должен написать сразу после слова INPUT. Если ты собираешься в этом месте ждать ввод нескольких переменных, то их имена ты должна записать через запятую. Конечно, и строку с оператором ввода можно перевести на русский.

INPUT A, B
Дождаться ввода с дисплея значений переменных А и В
— В моей программе этот оператор ввода должен быть, я думаю, в десятой строке. Я будто бы вместо присвоения значения переменной А вставляю оператор ввода… Так?

— Присвоение значения переменной А у тебя происходит в первой, а не в десятой строке. В твоей программе вообще нет десяти строк.

— Ладно. В строке с номером десять. Ты хочешь, чтобы я так говорила?

— Да. Думаю, что так будет точнее; еще можно говорить — в строке 10. Но вообще ты права, действительно вместо этой строки можно вставить оператор ввода.

10 INPUT A

Сейчас запусти программу.

RUNNH

?_

Так. Появился вопросительный знак — машина стоит и ждет значения переменной А. Можешь вводить нужное значение.

?500

500 20 520


READY

— Ясно. Теперь, конечно, эту программу можно пускать много-много раз, но я должна признать, что ее интеллектуальный уровень оставляет желать лучшего. Вряд ли она будет нужна народному хозяйству.

ЗАПИСЬ ПРОГРАММЫ ИЗ ПАМЯТИ НА ДИСК
— Ничего-ничего. У тебя еще все впереди. А теперь, пока наше время не кончилось, я хочу тебе рассказать, как сохранить программу на диске.

— Вот это надо! Эта историческая программа должна храниться вечно.

ФАЙЛ

— Это не так быстро делается. Сначала нужно найти свободное место на диске для записи программы. А сейчас запомни новое слово: место на диске, имеющее название и отведенное для хранения чего-то, хотя бы программы, называется файлом. Откровенно говоря, я не сразу понял, что такое файл, да, может быть, и ты не сразу освоишь это понятие, но истина такова: хочешь программировать — знай, что такое файл. А программы на диске сохраняются директивой SAVE.




Программу на диске сохраняет SAVE


— «Сейв», по-моему, означает «спасать». Кого тут спасать?

— «Спасать» у нас «сохранять», но и «спасать» не так уж и плохо — спасать от исчезновения. После SAVE идет описание файла, то есть сведения о нем: как ты обозначаешь файл, в котором собираешься писать программу, и где он должен быть образован. С обозначением просто. С местом, где хранить файл, потруднее, здесь надо знать, как эти места принято описывать в операционной системе. Сегодня, чтобы сохранить эту программу, тебе хватит самого простого описания, которое я сейчас и покажу:

ОПИСАНИЕ ФАЙЛА



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

— Ух, как сложно!

— Совсем не сложно. Это просто, как программировать на Бейсике! Покажу-ка я тебе несколько примерчиков.

Будут ли правильными следующие описания файлов?

DK0:C

— Вроде правильно.

— В самый раз! Учти, что нулевой номер устройства можно и не писать.

DK3:PAPA

— Правильно.

— Если машина имеет четыре дисковых устройства: нулевое, первое, второе и третье.

LP:

— Тут я молчу. Что это значит?

— Не мудрено, что не знаешь. Ведь я тебе про такой код устройства ничего не говорил. Но о том, что это именно код устройства, ты могла бы и догадаться — по двум буквам и двоеточию. Это код печатающего устройства.

ЗАПИСЬ ПРОГРАММЫ ИЗ ПАМЯТИ НА БУМАГУ
Этот код нужно задавать в директиве SAVE, если хочешь сохранить свою программу на бумаге, то есть напечатать ее. Нужно указать только код печатающего устройства и больше ничего. Попробуй напечатать свою программу.

SAVE LP: _

— Это, очевидно, все. Я поняла, что больше ничего писать не надо.

— Конечно, нет! При записи на диск нужно было бы указывать еще и обозначение файла, чтобы операционная система в другой раз смогла найти его. А на печатающем устройстве ничего такого делать не придется, да и сделать нельзя, ибо напечатанную программу ты унесешь домой. На мой взгляд, директива SAVE LP: очень похожа на директиву LIST, только первая программу записывает на бумаге, а вторая — выводит на экран.

— Все! Нажимаю клавишу ввода.

10 INPUT А

20 В=20

3 °C=А+В

40 PRINT А, В, С

50 END

Ой, как красиво напечатала!

— Сохрани это на память. Внукам покажешь, на каких машинах в молодости работала. А теперь живо запиши программу на диск, и бежим домой, уже поздно. Вместо LP: укажи устройство и обозначение файла.

— А номер диска? Все равно какой указывать?

— Нет, нет! Можно указывать только тот, на котором имеется свободное место и тебе разрешают писать. На сей раз никаких проблем нет, так как на дисковом устройстве номер 1 стоит выделенный для меня диск, на котором свободного места много. Так что пиши на мой диск.

SAVE DK1:_

— Какое же обозначение файла я должна сейчас написать?

— Как какое? Какое хочешь, такое и пиши! Только постарайся его не забыть, чтобы в следующий раз, когда захочешь, смогла бы найти свою программу.

— И как я ее найду?

— Об этом узнаешь, когда нужно будет искать. Придумывай же обозначение файла!

SAVE DK1:PERVAJA_

— Файл с моей первой программой логично назвать PERVAJA.



Отдохни немножко!


— Нормально. Нажми клавишу ввода, и твоя программа запишется на диск. И под занавес запомни еще одну директиву — BYE — «бай», что я перевожу «Пока!». Работу всегда нужно заканчивать этой директивой, чтобы интерпретатор Бейсика передал управление обратно операционной системе.

8. НЕБОЛЬШАЯ ПОЛЬЗА ОТ ПРОГРАММИРОВАНИЯ

— Ну что, Тоня? Пока ты знаешь только несколько операторов, но этого достаточно, чтобы написать маленькую полезную программу. Конечно, польза будет совсем небольшая, но начинать надо с небольшого. Ты Джека Лондона читала?

— Я? Да… а зачем тебе это?

— Я сейчас его читаю, рассказы о приключениях на Аляске. Между прочим, температуру воздуха он всегда дает в градусах Фаренгейта. Я знаю, что эти градусы превратить в привычные градусы Цельсия совсем несложно, но запомнить нужные числовые константы никак не могу. Напиши небольшую программу для таких, как я. Алгорит-мыч как-то смеялся, что во всех книжках по программированию приводят такую программу.

— С удовольствием, но что же эта программа должна делать?

ГРАДУСЫ ФАРЕНГЕЙТА И ЦЕЛЬСИЯ
— Эта программа должна, получив при помощи оператора ввода температуру в градусах Фаренгейта, вывести на экран температуру в градусах Цельсия. Формулу перевода из градусов Фаренгейта F в градусы Цельсия С я для тебя выписал из книги:



— Немножко подумаю… Мне кажется, что это очень простая программа. Я ее мигом введу.

— Не спеши. Сначала придумай название и сообщи интерпретатору о своем желании вводить новую программу директивой NEW.

— Я назову эту программу CELS.

NEW CELS


READY

10 INPUT F

2 °C=(5/9)*(F-32)

30 PRINT C

40 END

Вот и все. Можно запускать?

— Пускай, пускай.

RUNNH


?_

Введи —50. Знаешь, почему меня интересует это значение? Джек Лондон пишет, будто бы при этой температуре плевок превращается в лед еще до того, как достигнет поверхности снега.

— Бр-р-р. Ну и интересы у тебя!

? -50

-45.5556


READY

— Ясно. Я думал, температура будет ниже. А что касается твоей программы, то ее даже можно назвать первоклассной в том смысле, что такие делают первоклассники.

— Ты что! Чего тебе еще надо?

— Спокойно. Если посмотреть на текст программы, то совершенно непонятно, что она делает…

— А ты что, не знаешь?

ПРОГРАММА ДОЛЖНА БЫТЬ ПОНЯТНОЙ ДЛЯ ВСЕХ!
— Я-то знаю, но пойми, программы почти всегда делаются для других, а если кто-тодругой посмотрит на эту программу, то ничего не поймет. Конечно, ты можешь здесь целыми днями сидеть и всем объяснять, что к чему, но это же не выход, долго ты не выдержишь. Если же ты и сделала программу только для себя, то через пару месяцев напрочь забудешь, что же она делает. Таков горький опыт всей истории программирования… А во время работы программы? Показывается вопросительный знак, нужно что-то ввести, а что именно, догадайся сам! Ладно еще, что в твоей программке предусмотрен ввод только одного числа, А если нужно будет вводить разные числа в разное время? Ты со своими вопросительными знаками запутаешь любого пользователя. В общем, с юных лет привыкай создавать удобства пользователю.


Подсказывать обязательно!


— Совершенно не понимаю, чего ты хочешь! Ты же сам говорил, что без вопросительных знаков не будет ясно — нужно ли уже вводить или еще нет, а сейчас издеваешься над ними и надо мной тоже. Ничего же другого сделать нельзя. По крайней мере, ты ничего другого мне не рассказывал.

— Если ты умеешь выводить текст оператором PRINT, то ничего другого и не надо. Сначала выведи на экран что-нибудь такое: Работает программа, переводящая градусы Фаренгейта в градусы Цельсия. Потом подсказку пользователю — мол, введите градусы Фаренгейта, а результат выводить будешь — не одно голое число выводи, а добавь текст, что же это за число, а именно что градусы Цельсия.

— Да-а-а?… Так это в два раза больше работы будет!

— Возможно, что и во все четыре. Но позволь спросить, зачем тебе программирование, если легкой жизни хочется?

— Ух, язва! Намучаюсь же я с тобой!

Роптала Тоня, роптала, но в конце концов сделала, как ей Петя говорил. Получилось не очень быстро — и подумать пришлось, и кое-какие ошибки исправлять, потому что нет-нет да и нажмет она не ту клавишу. Но когда все было готово, ввела она директиву LISTNH, и на экране появилась ее программа.

5 PRINT "ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ"

6 PRINT "ФАРЕНГЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ"

7 PRINT "ВВЕДИТЕ ТЕМПЕРАТУРУ"

8 PRINT "В ГРАДУСАХ ФАРЕНГЕЙТА"

10 INPUT F

2 °C=(5/9)*(F-32)

25 PRINT "ЭТО БУДЕТ"

30 PRINT C

35 PRINT "ГРАДУСА ЦЕЛЬСИЯ"

40 END

— Ну, посмотри, мучитель, на этот шедевр программирования!

— Колоссально! Но надо посмотреть, как она работает. Запусти ее и задай перевести те же самые —50 градусов Фаренгейта.

RUNNH


ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ

ФАРЕНТЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ

ВВЕДИТЕ ТЕМПЕРАТУРУ

В ГРАДУСАХ ЦЕЛЬСИЯ

? -50

ЭТО БУДЕТ

-45.5556

ГРАДУСА ЦЕЛЬСИЯ


READY

— Результат тот же самый, следовательно, ты, по крайней мере, ничего не испортила. Ну и как, красивей сейчас выводятся результаты?

ТОНЯ ЕЩЁ УЛУЧШАЕТ ВЫВОД
— Красивей-то красивей, но можно было бы еще краше. Не нравится мне, что основное сообщение о работе программы и просьба ввести температуру идут сплошным текстом. Я бы хотела, чтобы эти сообщения разделяла пустая строка, это же совершенно разные сообщения. Но так, наверно, сделать нельзя.

— Почему же. Ты можешь вставить просто PRINT без ничего, и выведется пустая строка.

— Ясненько… Но подожди! Я там ничего не могу втиснуть между строками с номерами 6 и 7. Так что же делать? Все заново вводить с другими номерами?

ПЕРЕНУМЕРАЦИЯ

— Разумеется, нет. В таких случаях нужно применять директиву RESEQ. Я это слово произношу «рисек», и, по-моему, оно является сокращением от английского слова resequence, что должно означать «заново упорядочить последовательность». В словаре я этого слова не нашел, хотя искал. Так вот, эта директива вызывает перенумерацию всех строк программы, начиная с первой, с шагом десять —10, 20, 30 и до конца.

— Интересно было бы попробовать.

RESEQ

LISTNH

10 PRINT "ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ"

20 PRINT "ФАРЕНГЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ"

30 PRINT "ВВЕДИТЕ ТЕМПЕРАТУРУ"

40 PRINT "В ГРАДУСАХ ФАРЕНГЕЙТА"

50 INPUT F

6 °C=(5/9)*(F-32)

70 PRINT "ЭТО БУДЕТ"

80 PRINT C

90 PRINT "ГРАДУСА ЦЕЛЬСИЯ"

100 END

Да, кое-что из твоих обещаний выполняется. А скажи мне вот что. Я хотела, чтобы у меня получилось красиво в одну строку: ЭТО БУДЕТ —45.5556 ГРАДУСА ЦЕЛЬСИЯ, а все напечаталось в три строки. Можно что-нибудь сделать?

— Без сомнений. Во-первых, одним и тем же оператором ты можешь выводить строки символов и числа, так что смело могла писать PRINT «ЭТО БУДЕТ»,С.

— Понятно. И через запятую — «ГРАДУСА ЦЕЛЬСИЯ».

— Опять спешишь. Дело вот в чем. Если оператор PRINT имеет список единиц вывода, в котором они, как и в этом примере, написаны через запятую, то происходит вот что: строка экрана разделяется на зоны длиной 14 знаков. И в каждой зоне появляется значение одной единицы вывода. Или в нескольких — если одной не хватает. Надеюсь, ты понимаешь, что значения числовых переменных всегда разместятся в одной зоне и только сообщения программы…

ЗОНА ВЫВОДА

— Надейся, надейся.

— Вывод размещается в левой части зоны, и если он короче 14 знаков, то правая часть зоны остается пустой. Помнишь, в первой твоей программе при выводе значений переменных А,В,С между ними получилось довольно большое расстояние?

— Да! Я еще удивилась, но спрашивать не стала.

— Если отделять запятыми, то у тебя получится много пустого места между числом —45.5556 и текстом ГРАДУСА ЦЕЛЬСИЯ. Этого легко избежать: единицы вывода нужно отделять не запятыми, а точкой с запятой, тогда их значения будут выводиться сплошной стеной, одно за другим.

— Тогда я введу такой оператор, как и хотела, но только эти, как ты их называешь, единицы вывода отделю не запятыми, а точками с запятыми.

— Только учти, что никаких пробелов между единицами вывода машина сама вставлять не будет, ты сама должна нужные пробелы спланировать и запрограммировать. На сей раз ты должна предусмотреть пробел после ЭТО БУДЕТ, так же как и перед ГРАДУСА ЦЕЛЬСИЯ.

— Очень уж хлопотно, но я попробую.

70 PRINT "ЭТО БУДЕТ";C;" ГРАДУСА ЦЕЛЬСИЯ"

Можно пускать?

— Нет, нельзя. Хотя… пускай, посмотрим, что получится.

RUNNH

ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ

ФАРЕНТЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ

ВВЕДИТЕ ТЕМПЕРАТУРУ

В ГРАДУСАХ ЦЕЛЬСИЯ

? -50

ЭТО БУДЕТ -45/5556 ГРАДУСА ЦЕЛЬСИЯ

-45.5556

ГРАДУСА ЦЕЛЬСИЯ

— Ерунда какая-то… Лишнее что-то вывела…

ОПЯТЬ ОШИБКА!
— Все получилось так, как предусмотрено в программе. Ты перенесла весь вывод результатов на строку 70, а строки 80 и 90 со старым выводом оставила нетронутыми, и они, конечно, были выполнены. Можешь на них посмотреть при помощи директив LIST или LISTNH. Кстати, в этих директивах предусмотрена такая возможность: если после директивы идет номер строки, то покажется только эта строка; если два номера, разделенные тире, — то покажутся строки с номерами в этих границах. Так, например, LIST 70 покажет строку 70, a LIST 70–90 — строки с номерами между 70 и 90. Именно такую директиву ты сейчас должна ввести.

— Пожалуйста!

LISTNH 70–90

70 PRINT "ЭТО БУДЕТ";C;" ГРАДУСА ЦЕЛЬСИЯ"

80 PRINT C

90 PRINT "ГРАДУСА ЦЕЛЬСИЯ"

— Посмотри внимательно. Оператор вывода в строке 70 выведет тебе все, что нужно. А операторы в строках 80 и 90? Добавят еще вывод. Совершенно лишний и ненужный. Эти строки надо убрать. Ах да! Я же еще не сказал, как это делают. Просто набираешь номер строки и нажимаешь клавишу ввода. Строка стирается. Нельзя только ошибиться, а то не ровен час сотрешь самую свою любимую и нужную строку.

— Хорошо, я это буду делать чрез-вы-чай-но осторожно.

80

90

Все в порядке. Я запускаю.

ПРОГРАММИСТЫ И ИХ ОШИБКИ
— Никогда не спеши пускать программу. Посиди, подумай, может быть, сможешь что-то улучшить или найдешь ошибку. Какой смысл пускать программу с ошибками?! Речь здесь не о том, что за ошибки тебя кто-то будет ругать. Совсем нет. В программировании ошибки считаются естественным явлением, и никто тебя не спросит, сколько в программе было ошибок. Спрашивают, идет ли программа, и если идет, то все в порядке.

— Насчет отношения программистов к ошибкам не берусь судить, но хочу возразить по существу рассматриваемого вопроса. Почему программу не запустить? Будет работать правильно — хорошо, а если неправильно, тогда и начну думать, что и как. Неправильная программа же машину не испортит.


Размышление — наилучшее средство против ошибок в программах


— Разумеется, нет. Но речь не о том. Важно, сколько времени ты потратишь — и своего, и машинного. Могу открыть секрет — машинное время тоже деньги. А если деньги тебя не интересуют, то остается спортивная сторона: лучше тот программист, кто быстрее работает — быстрее исправляет свои ошибки. А быстрее получится, если думать, а не пускать программы на авось.

— Хватит разглагольствовать, я пускаю. А там посмотрим.

RUNNH

ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ

ФАРЕНТЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ

ВВЕДИТЕ ТЕМПЕРАТУРУ

В ГРАДУСАХ ЦЕЛЬСИЯ

? -50

ЭТО БУДЕТ -45/5556 ГРАДУСА ЦЕЛЬСИЯ

— Тебе повезло. Все получилось, как надо.

— Это не везение, а высокое мастерство.

— Как же! А сейчас мы должны записать твою программу на диск, поскольку наше время истекает.

— Ой, прости! Я совершенно забыла, как это делают.

— Не переживай! Вначале все забывается. Позже, когда привыкнешь, прекрасно будешь помнить и Бейсик, и операционную систему, и особенности других компьютеров, если придется с ними познакомиться. Но для сохранения программы нужно ввести директиву SAVE с описанием файла — кодом устройства и названием файла.

— Мне лень выдумывать новое название для файла. Пусть будет такое же, как у программы.

SAVE DK1:CELS_

— Все правильно. Нажми клавишу ввода, и программа запишется на первый диск.

9. ВЕТОК МНОГО-МНОГО, НО НЕ ДЕРЕВО

В начале следующего занятия Петя был настроен довольно высокомерно.

— Ну что тебе, Соображалкина, сказать? Программа, которую ты в прошлый раз с такими муками сделала, конечно, жутко тривиальна, но все-таки немножко похожа на настоящую программу. Она имеет кусок… ой, что я говорю… кусочек!… ма-аленький кусочек… который вводит данные, такой же маленький, маленький кусочек вывода результатов и еще меньше кусочек, который перерабатывает данные в результаты.

— Я возмущена до глубины души! Что ты вообще от меня хочешь?

— Тихо, тихо. Это я для того, чтобы ты не подумала, что уже все постигла. И еще я хотел отметить, что всякая программа эти три части будет иметь, и можно нарисовать такую вот схему работы всех программ:



— Ну, знаешь…

— Знаю, знаю, но давай быстрее вызовем твою программу и сделаем в ней одно улучшение, чтобы она перестала быть такой прямой, как палка, и заимела бы какую-то логику.

— Опять! Я же не умею вызывать программы из диска.

— Сейчас, сейчас. Вызывают их директивой OLD. «Оулд» по-русски что?

— Старый.

— А после OLD описываешь файл, в котором программа хранится. В точности, как в прошлый раз, когда программу записывала на диск директивой SAVE.

OLD DK1:CELS


READY

READY показался, значит, всё в порядке. Сейчас переделаем программу, чтобы ее можно было использовать для превращения нескольких значений градусов Фаренгейта подряд.

— Как это сделать?

— Можно по-всякому. Я предлагаю такой вариант. После того как одно значение переведено, программа выдает запрос: «Желаете ли продолжить работу?» и ждет ввод числа. Если пользователь вводит нуль, то работа прекращается, а если другое число — то продолжается. Разумеется, пользователю нужно объяснить, что от него требуется.



Как вывести запрос о продолжении работы, ты должна понимать: оператором PRINT. Так же ясно, как вводить число — оператором INPUT. Это число придется как-то обозначить, допустим буквой Z.

СЕЙЧАС ОБ ОПЕРАТОРЕ ВЕТВЛЕНИЯ
А вот, чтобы узнать, является ли нулем какое-то число или нет, известных тебе операторов недостаточно. Для этого нужен новый оператор — оператор условного перехода, или оператор ветвления IF…THEN. Ты понимаешь, что это означает?



— «Иф» значит — «если», а «зен»… может быть — «тогда»?

— Да, так эти слова переводятся. А сам оператор условного перехода, или, кратко, оператор IF, будет труднее понять, чем предыдущие, так что задержи дыхание, пока я не кончу.

Сначала пишется IF, потом логическое условие, в нашем случае это будет выражение Z=0, затем пишется THEN, а после того — номер строки, с которой продолжать работу, если… ты заметила, я сказал «если»… если выполняется указанное условие, то есть значение Z действительно равно нулю. А если не выполняется, то работа продолжается со следующей строки.

— Фу-у-у… Слушай, я чуть не задохнулась, но поняла крайне мало. Объясни поподробнее.

— Я нарисую тебе такую схему:



Я сам тоже не сразу освоился с логическим условием, потому что иногда оно мне казалось вроде оператора присвоения. Отличие тут такое: при выполнении оператора ветвления значение переменной Z не станет равным нулю, а останется таким, как было, — два, десять и, в конце концов, оно могло бы и быть нулем.




А на русский язык этот оператор можно перевести так:

IF M=0 THEN 600
Если значение переменной М равно нулю, то перейти на строку с номером 600
Вот что получается: знак «=» в операторе присвоения мы читали «присваивается значение», а в логическом условии оператора IF читаем «равно», как и полагается.

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

На Бейсике По-русски
= < > <= >= <> равно меньше больше меньше либо равно больше либо равно не равно
Так что оператор ветвления «если А меньше В, то иди на строку 600» можно и нужно записывать так: IF А<В THEN 600. Этот оператор еще может заморочить голову и своими многими названиями. Вот еще одно — его можно называть и оператором сравнения.

У ТОНИ ПОЛУЧАЕТСЯ ДИАЛОГ С МАШИНОЙ


— Пора начинать действовать, дело покажет, что и как. Этот твой нововведенный оператор придется вставлять… там, где была уничтоженная строка 80. Интересно, сколько новых строк понадобится?… Много не должно быть — буду их нумеровать через 5. Сначала запрос о продолжении работы:

90 PRINT "ЕСЛИ КОНЧАЕТЕ, ВВЕДИТЕ 0"

Поймет это твой пользователь?

— Кто его знает? Можно было и больше написать — что-нибудь вроде того, что можно вводить любое число, если есть желание продолжать. Вообще Алгоритмыч говорил, что при выдумывании пояснений очень важно найти золотую середину: мало выведешь — пользователь не поймет; много выведешь — экран будет забит текстом, вывод будет ненаглядным и человек устанет его читать.



Вот результат слишком пространного вывода программы


— Сейчас предусмотрим ввод числа Z. Это просто.

85 INPUT Z

Теперь пресловутый оператор ветвления. Так, так. Записать «если Z=0, то уходи…»? Неизвестно, куда надо уходить… Да это и неважно, потому что так писать нехорошо. Переходить надо как раз тогда, когда Z не равен нулю! А это, если верить корифею Бейсикову, надо записывать так:

90 IF Z<>0 THEN 30

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

25 PRINT

— Что ж. Выглядит вполне прилично. Поставь еще только оператор STOP после оператора ветвления. Нужен, конечно, он исключительно ради порядка, так как интерпретатор, достигнув последней строки программы, все равно кончит работать.

95 STOP

— Сейчас я перенумерую строки программы.

RESEQ


READY

Потом ее посмотрю. Но всю смотреть нет необходимости, достаточно посмотреть конец с изменениями. Я начала вводить изменения с восьмидесятой строки, прости, со строки с номером 80, но так как я еще добавила строку 25, то после перенумерации строка 80 стала строкой 90.

LISTNH 90-200

90 PRINT" ЕСЛИ КОНЧАЕТЕ, ВВЕДИТЕ 0"

100 INPUT Z

110 IF Z<>0 THEN 40

120 STOP

130 END



ОСОБЕННОСТИ ПЕРЕНУМЕРАЦИИ
Смотри сюда! Какой ужас! Строка 110! Когда я ее вводила, то после THEN писала 30, и это еще на экране видно. А после перенумерации машина 30 превратила в 40. Что же делать, если она все портит?!

— Несмышленыш ты несчастный! Сама же рассуждала, что, вставив строку 25 и перенумеровав строки, ты все номера сдвинула. Значит, и номер 30, который стал 40. По этой причине и интерпретатор после THEN поставил 40.

— Потрясающе мудро сделано.

— А как же иначе! Ты просто не представляешь, как трудно было бы самому в большой программе найти и исправить все операторы ветвления, не допустив ни одной ошибки.

— Других претензий у меня нет. Я запускаю.

RUNNH


ПРОГРАММА ПРЕОБРАЗУЕТ ГРАДУСЫ

ФАРЕНТЕЙТА В ГРАДУСЫ ЦЕЛЬСИЯ


ВВЕДИТЕ ТЕМПЕРАТУРУ

В ГРАДУСАХ ЦЕЛЬСИЯ

? -50

ЭТО БУДЕТ -45/5556 ГРАДУСА ЦЕЛЬСИЯ

ЕСЛИ КОНЧАЕТЕ, ВВЕДИТЕ 0

? 0_

И закончим работу.

STOP AT LINE 120


READY

— Посмотри, если работа прекращается по оператору STOP, то интерпретатор об этом сообщает и еще показывает, на какой строке это произошло. Увы, по-английски. Но делается это для того случая, когда у тебя в программе имеется много операторов останова и ты можешь запутаться, который из них сработал. Ну, с этой программой покончено, можешь ее записать на диск.

SAVE DK1:CELS_

— Интересно бы узнать, можно ли с таким же названием файла записывать программу на диск второй раз.

— Можно, можно.

— А та, ранее записанная программа забудется?

— Ты хотела сказать — стирается ли старый файл. Так правильно говорить. Нет, он не стирается. Ты даже его могла бы списать, если бы знала больше об операционной системе. Директивой OLD ты умеешь списывать только последний вариант.

— Ума не приложу, зачем мог бы понадобиться предыдущий вариант? Мне лично нужен будет только последний. Я просто так спросила, ради интереса. Заговорил ты меня, я и забыла, что еще не ввела эту последнюю строку.

ЧТО ТОНЯ УЖЕ УМЕЕТ
— Порядок. Теперь мы могли бы эту твою последнюю программу «проразмыслить». Смогла бы ты сейчас написать такую программу, которая делала бы наоборот — переводила градусы Цельсия в градусы Фаренгейта?

— Конечно. Там, где написано ФАРЕНГЕЙТА, я написала бы ЦЕЛЬСИЯ, вместо ЦЕЛЬСИЯ написала бы ФАРЕНГЕЙТА.

— К сожалению, самого главного ты не сказала. Нужно изменить формулу для расчета значения переменной С.

— Ах, да! Такой формулы пока нет, но ее же легко получить из старой.

— Конечно. Она получается такой:



Но это совсем не важно, поскольку мы ее сейчас не собираемся программировать. Скажи, ты смогла бы сейчас составить программу, которая переводила бы, например, километры в сантиметры?

— О чем речь, товарищ профессор! Я даже знаю формулу, которую здесь нужно использовать. Если желаешь, я могу тебе написать программу, которая сантиметры будет переводить в километры или даже дюймы в миллиметры.

— Прекрасно! А секунды — в годы?

— Вы меня обижаете, товарищ академик!

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

— Вряд ли это так уж важно, что мы одни единицы переводим в другие…

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

— С таким же успехом это могло бы быть и вычисление площади.

— Другой пример. Проявив чудеса изобретательности, ты решила какую-то очень сложную задачу по математике. Например, такую: из пункта А в пункт В со скоростью V1 мчится поезд, ему навстречу со скоростью V2 мчится другой поезд. Через какое время они налетят друг на друга, если расстояние между А и В равно т километров.

— Лучше бы автомашины, они смогли бы разминуться.

— Это совершенно все равно. Если тебе нравится, пусть это будут лягушки. Важно то, что с обеих сторон кто-то несется друг другу навстречу. Если решишь эту задачу, то сможешь запрограммировать формулу для расчета времени встречи



и тебе останется только ввести какие-нибудь значения скоростей V1, V2 и расстояния т, чтобы получить время встречи. И так будет с любой похожей формулой. И с непохожей тоже. Лишь бы была формула.

— Однако есть и различия. В нашей первой программе нужно было ввести только одно число — градусы Фаренгейта. А чтобы считать по твоей формуле встречи поездов, нужно ввести 3 числа.

— Да, такое различие имеется. Но все равно, мы сейчас можем запрограммировать любую формулу на свете.

Понимаешь, блок-схемы этих программ будут почти одинаковы, а программы будут делать нечто вроде бы совсем разное.

— Почему же «вроде бы»?

— Потому что различия появляются только тогда, когда ты начинаешь вникать в существо дела: что это такое считается по этой формуле? что вводят? что выводят? Когда ты хочешь понять, какой во всем этом смысл. Машина же не может ни хотеть, ни понимать, она только рассчитывает по заданной формуле. И тогда между формулами большого различия нет. Поняла?

— Нет, не совсем. Но ничего, до следующего раза пойму. Сейчас все равно нужно уходить, так как уже прибыли жаждущие программировать.

10. ТОНЯ УЖЕ ЗНАЕТ О ПРОГРАММИРОВАНИИ ВСЕ

Весело насвистывая, Тоня появилась у машины. Петя ее уже ждал.

— Опоздала. А за это время здесь был Алгоритмыч. Спросил, как дела, я рассказал, и он высказался, что твои занятия пора кончать.

Нельзя сказать, чтобы Тоня очень увлеклась новым делом, но она предполагала, что это будет она, кто скажет, что все уже надоело, когда это ей действительно надоест. Но так! Вдруг! Ее отстранить! Нет, к такому Тоня не привыкла.

— Что это за новости! Кому я здесь мешаю. Я что, кого-нибудь тут обидела?! Или этого твоего Змея-Алгоритмыча оскорбила? Или…

— Не шуми. Он просто сказал: раз человек освоил четыре кита программирования — оператор ветвления, операторы ввода и вывода и плюс еще оператор присвоения, то в программировании он знает все существенное и ему осталось освоить только мелочи, несущественные детали. Одним словом, сейчас ты можешь уже учить других.



— Ну знаешь ли, Бейсиков! Ты меня не дразни. Лучше поведай, неужели в программировании больше ничего нет, кроме этих четырех операторов?

— Да уж нет! Еще будет масса различных приемов, условий и правил, и интересных, и не очень, но ничего принципиально нового не будет. Если вот только понятия подпрограммы и функции, но и их легко освоить. Ах да, осталось еще понятие массива чисел, и его мы как раз сегодня и разберем.

О МАССИВАХ ЧИСЕЛ
МАССИВ

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

ЭЛЕМЕНТ МАССИВА

Если, допустим, мы создали массив с именем М, то первое число этого массива, или первое значение переменной М, или — как чаще всего говорят — первый элемент массива, обозначают M(1), второй — M(2), третий — M(3) и так далее. Такими обозначениями, как ты понимаешь, нужно пользоваться в том случае, если необходимо соответствующее значение элемента использовать в каком-нибудь арифметическом выражении или хочется присвоить новое значение этому элементу. Например, запись М(6)=18 означает, что шестому элементу массива М присваивается значение 18. Выражение В=5*М(6) означает, что для получения нужного результата значение шестого элемента массива М умножается на 5.

— А ты не смог бы дать хоть один пример, где бы эти массивы пригодились?

— Конечно, могу. Но пока не забыл, скажу, что в скобках после обозначения массива не обязательно писать число, чтобы иметь номер элемента. Можно писать, например, М(К), тогда интерпретатор найдет элемент с номером К, разумеется, если до этого переменной К было присвоено значение. Можно сложнее: М(К+1) или М(5*К+3) и вообще в скобках может быть любое арифметическое выражение. Интерпретатор это выражение вычислит и найдет требуемый элемент массива.

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


Небольшой массив с шестью элементами


— Да, эти примеры уже надоели. Говори, что еще надо знать, и начинаем работу.

КАКОЙ НУЖЕН МАССИВ, ДОГАДАЙСЯ САМ
— До начала работы нужно описать массив — определить его обозначение и длину. Как обозначать массивы, я уже говорил, добавлю, что обозначения простых переменных и массивов могут совпадать. Например, может быть массив А и переменная А. Имена одни и те же, а значения, конечно, разные. А длина массива, как легко догадаться, это максимальное количество элементов в массиве.

Описывают массив специальным оператором описания массивов DIM. Эти три буквы являются сокращением английского слова dimension — размерность. После DIM пишут имя массива и в скобках задают длину массива, или, как я говорил, максимальное количество элементов.

— А что это такое — максимальное количество элементов?

— Сейчас скажу. Закончим только об операторе DIM. Он может быть, например, таким.




Объем массива нужно представлять заранее


Как видишь, после DIM можно писать несколько массивов сразу, разделяя их описания запятыми. А теперь о максимальном количестве элементов. Может статься, что в программе нужен массив, но точная его длина тебе неизвестна. Тогда этот массив можно описать, задав максимальное количество элементов заведомо большим, чем тебе может понадобиться. Если ты и описала более длинный массив, чем тебе надо, — невелика беда, важно, чтобы он не получился короче.

— А если я совсем, совсем не представляю, сколько нужно будет элементов?

— Тогда тебе еще рано составлять программу. Обычно все-таки можно предвидеть, сколько элементов понадобится. Например, ты хочешь создавать массив оценок по контрольной, и притом такой, чтобы был пригоден для любого класса. Сразу видны трудности — в каждом классе количество учеников различно. Тогда можно описать массив так:

20 DIM А(50)

Я думаю, что ни в одном классе не будет больше пятидесяти учеников. В этом случае 50— это максимальное количество элементов в массиве, а фактическое ты введешь в память отдельно во время работы программы.

— А почему бы не взять 100?

— При выполнении оператора описания массивов интерпретатор выделяет в памяти место для хранения значений элементов массива. Чем больше элементов, тем больше памяти уйдет на хранение. Конечно, в память нашей машины запросто войдет десять тысяч чисел, так что жадничать нечего—50 или 100, все равно мелочь. Но в больших программах приходится думать и об экономии места.

МАЛЕНЬКАЯ ПРОГРАММА ДЛЯ ВВОДА ОЦЕНОК
Так как машину сейчас ремонтируют и работать нельзя, составь, пожалуйста, программу, которая вводила бы оценки в какой-нибудь массив. Такая программа большой самостоятельной ценности не будет иметь, но ее можно представлять как составную часть большой программы.

— Пожалуйста.

10 DIM А(50)

20 PRINT «ВВЕДИТЕ ОЦЕНКУ»

30 INPUT А(1)

40 PRINT «ВВЕДИТЕ ОЦЕНКУ»

50 INPUT А(2)

Послушай! Что это такое? Мне так и надо будет писать все эти PRINT и INPUT пятьдесят раз?

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

— Да-да, я вспомнила. Ага! Если писать 15 Н=1, то значение счетчика Н становится равным 1. Далее строкой 40 Н=Н+1 я увеличу номер школьника на единицу. И это почти все.

— Не забудь в строке 30 заменить А(1) на А(Н).

— Да. А то все время будет вводиться только первый элемент. А вот сейчас мне нужно, чтобы после увеличения значения счетчика опять выполнялась строка 20.

ОПЕРАТОР, ВСЕГДА ПЕРЕДАЮЩИЙ УПРАВЛЕНИЕ
— Раз уж ты хочешь делать именно так, то можешь использовать оператор безусловной передачи управления GO ТО, что произносится «гоу ту».

— И что означает «иди на», но был уговор, что больше новых операторов не будет.

— Такого уговора не было. Речь шла о том, что не будет ничего существенно нового, так что несущественно новые операторы могут еще быть. Закончим про оператор GO ТО. После него надо писать номер той строки, которая должна быть выполнена следующей. Например, 50 GO ТО 20 означает, что следующей будет выполнена строка 20 и потом по порядку строки, следующие за нею, до тех пор, пока не встретится строка с оператором IF или оператором GO ТО. А вот доказательство, что оператор GO ТО не является существенно новым. Его можно записать при помощи давно известного оператора ветвления. Например, таким образом:

50 IF Н=Н THEN 20

Этот оператор сравнивает значение переменной Н со значением той же переменной, и если они равны — а они, конечно, всегда равны, — то управление передается на строку 20.

— Зачем же тогда такой оператор нужен?

— Для краткости, только для краткости. И яснее будет, если запишешь GO ТО, а не какой-то оператор IF, в котором еще надо разбираться.



Он же никогда не остановится!


— Тогда программа готова!

10 DIM А(50)

15 Н=1

20 PRINT «ВВЕДИТЕ ОЦЕНКУ»

30 INPUT А(Н)

40 Н=Н+1

50 GO ТО 20

60 END

Совсем неплохо. Правда?

— Да, неплохо, но кое-чего не хватает. Машина все будет и будет спрашивать оценки.

— Ой, да! Этот цикл же никогда не кончится.

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

КАК ЗАКОНЧИТЬ ВВОД!
— Что же мне делать? Может быть, поступать так же, как при переводе градусов Фаренгейта в градусы Цельсия? После каждого ввода оценки еще дополнительно вводить либо нуль, либо не нуль для выяснения, кончается ли работа?

— Да, так можно было бы. Но так ты фактически удвоишь работу пользователя. Ему придется вводить и оценку, и кроме того указание, кончать или не кончать работу. Сколько оценок, столько указаний. А если оценки перепутаются с указаниями?

— Не перепутаются. Напишем на экран информацию, что именно надо вводить.

— Как пить дать перепутаются. В таких случаях пользователь всегда хочет вводить все быстрее и быстрее и кончается это тем, что он все перепутывает.

— Сам виноват.

Это еще неизвестно. Может быть, виноват программист, который так нескладно запрограммировал. Лучше здесь делать так: в самом начале вывести сообщение, что сигналом конца ввода служит ввод нуля вместо оценки. Ясно, что оценки могут меняться только в пределах от 1 до 5. А в программе проверяем введенную оценку — нуль это или не нуль. Еще может быть и другой способ: в самом начале спрашиваем, сколько в классе учеников и каждый раз до увеличения — я подчеркиваю, до, а не после увеличения счетчика Н в строке 40— проверяем, стал ли Н равным количеству учеников. Если не стал, продолжаем ввод. Если стал, кончаем.

— А почему ты так усиленно подчеркивал, что эту проверку нужно выполнять до увеличения Н?

— До увеличения Н нужно проверять, равно ли значение счетчика количеству учеников, а после увеличения — больше ли оно количества учеников. Отличие только в этом.

— Ну, а какой же вариант ввода данных лучше?

— Может быть, второй, когда после увеличения счетчика в строке 40 мы делаем сравнение «не больше ли Н количества учеников», и если не больше, то уходим на строку 20.

— Насколько я помню, такого логического условия «не больше» в Бейсике не было.

— Да, не было. Но что такое «не больше»? Это меньше или равно. А такое условие у нас было. Если обозначать количество учеников буквой К, то новая строка 50 будет такой.

50 IF Н<=К THEN 20

— И значение переменной К нужно ввести где-то в начале программы?

ОПЕРАТОР-СЧЕТЧИК
— Да, но, до того как это делать, расскажу про оператор цикла, который придуман специально для описания подобных операций со счетчиком. Только счетчик здесь называется переменной цикла.

ПЕРЕМЕННАЯ ЦИКЛА

— Подожди, подожди! Чтобы получился счетчик, нужно знать, с какого числа начинать и каким числом кончать?!

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

Посмотрим на пример оператора цикла:

FOR Н=1 ТО К STEP 1

Это, правда, только первая его часть; но сначала — что означает «фор»?



— Это означает «для», а «ту», который следует за Н=1, мог бы означать «к» или «на».

— Да. Но здесь он означает скорее «до». Сразу после FOR идет имя переменной, в нашем случае — Н. Это и будет та знаменитая переменная цикла. Потом за знаком равенства пишется первое значение переменной цикла. В этом операторе знак «=» нужно читать «с», то есть совсем иначе, чем в операторе присвоения. Кстати, как там мы его читали?

— «Присваивается значение», а в операторе ветвления мы его читали так, как надо, — «равно». Вот так! Кое-что и мы помним.

— Молодец! После ТО пишется конечное значение переменной цикла. В этом примере — значение переменной К. А за словом STEP — «стэп», что означает «шаг», «ступенька», указывают значение шага.

И еще один трюк, который я сам придумал. Пустое место в самом конце оператора читается «выполнить последующие операторы». Так, сейчас мы этот пример оператора цикла можем перевести на русский язык:

FOR н = 1 ТО К STEP 1
Для значений переменной Н, начиная с 1 ДО к с шагом 1 выполнить последующие операторы
И ЧТО ВСЕ ЭТО ОЗНАЧАЕТ
Теперь поговорим о второй части оператора цикла, которая в программе может находиться совсем в другом месте и в нашем примере будет выглядеть так:

NEXT H

— «Нэкст» означает «следующий».

— Запомни, что после слова NEXT должно быть имя переменной цикла. Между этими двумя частями оператора цикла, совсем как между скобками, находятся те операторы, которые необходимо выполнить при всех допустимых значениях переменной цикла.

— Все допустимые значения цикла — это те, которые получаются, если прибавлять и прибавлять значение шага к первому значению переменной цикла?

— Да, но не забудь, что прибавление закончится тогда, когда значение переменной цикла станет больше конечного значения. Может случиться, что уже первое значение будет больше конечного, и тогда операторы внутри цикла не выполнятся ни разу.

Сейчас я тебе еще раз поясню оператор цикла такой схемой:



Поизучай эту схему, кое-что станет яснее. Схема упрощена, ибо на самом деле вместо переменных В, С и Т может быть любое арифметическое выражение. В то же время возможен и более простой вариант оператора цикла: если шаг приращения равен единице, то STEP 1 можно и не писать. В такой сокращенной форме наш оператор цикла из первого примера будет иметь вид: FOR Н=1 ТО К


Программа для начинающих закройщиков


NEXT Н

Это обеспечивает выполнение операторов внутри цикла для значений Н, начиная с 1, потом 2, 3 и так далее до К включительно. Разумеется, и в этой сокращенной форме вместо единицы и К можно писать арифметические выражения.

ПРАВИЛЬНЫЕ И НЕПРАВИЛЬНЫЕ ОПЕРАТОРЫ ЦИКЛА
Пора переходить к примерам. Правилен ли такой оператор цикла?

FOR Н=100 ТО 200 STEP К

….

NEXT Н

— Думаю, что правилен. Переменная Н будет пробегать значения, начиная с сотни, с шагом К до тех пор, пока очередное значение не станет больше 200.

— Каково будет последнее значение Н, если К равен шести?

— Шести? У меня получается, что последнее значение будет 100+96, то есть 196.

— А сейчас посмотри на такой оператор цикла. Правилен ли он?

FOR К=6+А*В/С ТО ((Х + К)/А — Х*С)*2

….

NEXT К

— Нет, неправилен.

— Почему?

— Не знаю, но правильных операторов ты больше показывать не станешь. Что я учителей не знаю?

— Надо признать, где-то ты права, но все-таки посмотри и скажи, какой недостаток имеет этот оператор.

— Арифметические выражения быть могут… шаг, если он равен единице, указывать необязательно…

— Спору нет. Дело в другом.

— Не знаю. Сдаюсь.

— В этом примере для определения конца цикла используется выражение, содержащее переменную цикла К. Это плохой стиль. Не скажешь, что это неправильно, так как интерпретатор рассчитывает конечное значение переменной цикла в самом начале работы оператора цикла. Первым будет рассчитываться первое значение переменной цикла К, то есть 6+А*В/С, а конечное значение будет рассчитано с использованием именно этого значения К, так что фактически конечным значением будет ((Х + (6+А*В/С))/А-Х*С)*2. Позже, при выполнении оператора цикла, когда переменная К будет приобретать новые значения, никакого пересчета не будет.

— Все ясно. Но что же здесь плохого?

— Видишь, Бейсик имеет один серьезный недостаток: на разных машинах он разный. Конечно, кажется, что существенных различий нет, различие только в мелочах, но в программировании мелочей нет. Так что вполне может случиться, что на другой машине интерпретатор пересчитывает конечное значение цикла каждый раз. И тогда наш последний цикл будет выполняться совсем по-другому. Заруби себе на носу общий принцип программирования: программировать по возможности проще, без выкрутасов, так, чтобы программа подходила для всех машин и ее легко могли бы понять другие, да и ты сама.

— О других машинах думать еще рано. Разобраться бы с этой.

И ЕЩЕ РАЗ ТА ЖЕ САМАЯ ПРОГРАММА
— Посмотри сейчас на нашу программу ввода оценок. Теперь, когда ты знаешь оператор цикла, строку 15 можно заменить первой частью оператора, а вместо строк 40 и 50 вставить NEXT Н. И тогда программа будет выглядеть так:

10 DIM А(50)

12 PRINT «ВВЕДИТЕ КОЛИЧЕСТВО УЧЕНИКОВ»;

13 INPUT К

15 FOR Н=1 ТО К

20 PRINT «ВВЕДИТЕ ОЦЕНКУ»;

25 PRINT «УЧЕНИКА НОМЕР»;Н

30 INPUT А(Н)

40 NEXT Н

60 END

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

— Одного я не понимаю —стоило ли так возиться, чтобы сэкономить одну строчку? Если раньше, чтобы сделать цикл, нужно было написать три строчки, то теперь только две. Мелочь.

— Как посмотреть. Я лично думаю, что оператор цикла изобрели не из экономии. Он необходим человечеству по другим причинам. Важна сама идея цикла! Важно понять, что программы состоят из циклов. Что в задачах их надо искать и находить. И что в программах они должны быть ясно видны. Программист должен думать циклами, как говорит наш Алгоритмыч. Это понимай так, что циклы должны лежать в основе алгоритмов и программ. Ну и экономия все-таки есть. Настоящие программы очень длинны, и если их можно укоротить, то это надо делать, но ни в коем случае не за счет ясности программы.

ПРОГРАММА СУММИРОВАНИЯ ЧИСЕЛ
А сейчас составь программу суммирования чисел от единицы до ста, конечно, используя оператор цикла.

— Ха! Не на ту напал! Каждый знает формулу для расчета такой суммы. Это будет 10100, деленное на два… 5050!

— Все равно составь программу, но бери не конкретное число 100, а произвольное N, которое введет пользователь.

— Ладно уж, хотя и для этого случая имеется формула: сумма равна N(N+1)/2. Так что программу я пишу только из уважения к тебе. Учти.

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

Тоня взялась за работу, и в результате появилась следующая программа.

10 PRINT «ПРОГРАММА СУММИРУЕТ ЧИСЛА»

15 PRINT «ОТ 1 ДО N»

20 PRINT «ВВЕДИТЕ ЧИСЛО N»

30 INPUT N

40 S=0

50 FOR 1 = 1 ТО N

60 S=S+1

70 NEXT I

80 PRINT «СУММА РАВНА»; S

90 STOP

— Ух и намучилась, пока сообразила, что переменной для суммы вначале надо присвоить нуль, а потом добавлять числа по одному. Ну как?

— Ничего. Программа работать будет.

Прождав еще некоторое время, ребята попали на машину.

— Ну, Тоня, вызывай интерпретатор!

>BAS

READY

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

NEW SUMMA

— Ты доволен?

БЫСТРО И ПЛОХО! ЭТО НЕ СТИЛЬ ПРОГРАММИСТОВ!
— Да, вполне. Начинай вводить программу, и побыстрее. У нас сегодня мало времени.

Тоня взялась за работу и вскоре сообщила:

— Готово. Пускаем.

— Сначала посмотрим.

— Нечего смотреть. Какие могут быть ошибки при вводе такой коротенькой программки!

RUNNH


ПРОГРАММА СУММИРУЕТ ЧИСЛА ОТ 1 ДО N

ВВЕДИТЕ ЧИСЛО N


SYNTAX ERROR AT LINE 30

Это что за шуточки!

— Ну, конечно! В строке 30 синтаксическая ошибка, то есть такая строка в Бейсике невозможна. Скорее всего перепутаны буквы. Сумеешь посмотреть эту строку?

— Конечно, нужно использовать директиву LIST.

— Лучше LISTNH и номер строки.

LISTNH 30

30 INPT N

— Да, действительно, там почему-то появился INPT, где должен быть INPUT.

— Появился, появился… и почему-то.

— Не страшно. Введу эту строку заново.

30 INPUT N

RUNNH


ПРОГРАММА СУММИРУЕТ ЧИСЛА ОТ 1 ДО N

ВВЕДИТЕ ЧИСЛО N

? 100


?FOR WITHOUT NEXT AT LINE 60

— Опять чушь какая-то!

— Ошибка, дитя, ошибка. Интерпретатор не смог найти соответствующее NEXT для какого-то FOR. В какой строке должен был быть NEXT?

— В строке номер 70.

— Посмотрим ее.

LISTNH 70

70 NXT I

Ну вот! Эта строка тоже ошибочно введена.

— Так, исправила.

— Тогда пускай еще раз.

RUNNH


ПРОГРАММА СУММИРУЕТ ЧИСЛА ОТ 1 ДО N

ВВЕДИТЕ ЧИСЛО N

? 100

СУММА БУДЕТ 5050


STOP AT LINE 110

READY

— фу-у-у… Наконец-то все в порядке.

— Теперь быстро сохрани свою программу на диске.

— Все в порядке. Бежим домой.

11. ДЕЛАЙ КАК Я, ДЕЛАЙ ЛУЧШЕ МЕНЯ!

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

— Знаешь, совсем не вредно посмотреть программы, составленные другими. Думаю, ты потом почувствуешь, что смогла бы сделать не хуже.

— Ну уж! Куда мне тягаться с такими корифеями программирования, как Петя Бейсиков.

— Хорошо, хорошо. Вот программа, которая решает уравнение АХ=В, А и В — известные коэффициенты, X — неизвестная величина.

ПРОГРАММА РЕШЕНИЯ САМОГО ПРОСТОГО УРАВНЕНИЯ
— Чтобы решить такое уравнение, институты кончать не надо.

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

— Да, приятно вспомнить молодость, когда это все казалось непостижимой премудростью.

— Программа составлена по такой простой блок-схеме:



Контрольную всегда начинай с блок-схемы




А сама программа выглядит так:

10 PRINT “ПРОГРАММА РЕШАЕТ УРАВНЕНИЕ А*Х=В"

20 REM ПЕРЕМЕННАЯ А-КОЭФФ. А; В-КОЭФФ. В

30 PRINT \ PRINT "ВВЕДИТЕ КОЭФФИЦИЕНТ А";

40 INPUT А

50 PRINT "ВВЕДИТЕ КОЭФФИЦИЕНТ В"; \ INPUT В

55 \

60 REM ПОСЛЕ ВВОДА А И Б СРАВНИВАЕМ А С 0

70 RЕМ ЕСЛИ А=0, ТО ВЫВОДИМ РЕЗУЛЬТАТ

80 RЕМ В ЗАВИСИМОСТИ ОТ ТОГО B=0 ИЛИ НЕТ

90 IF А<>0 THEN 150

100 IF B<>0 THEN 130

110 PRINT "ОТВЕТ: X ПРОИЗВОЛЬНОЕ ЧИСЛО"

120 60 ТО 160

130 PRINT "ОТВЕТ: РЕШЕНИЯ НЕТ"

140 60 ТО 160

150 PRINT "ОТВЕТ: Х=";В/А

155 \

160 PRINT \ PRINT "КОНЕЦ РАБОТЫ — ВВЕДИТЕ 0"

170 INPUT К

180 IF К<>0 THEN 30

190 STOP

200 END

Смотри, в блок-схеме я у каждого блока приписал номер строки, с которой начинается выполнение этого блока в программе.

— Ну что ж. Начинаем изучать твою программу. В первой строке я ничего особенного не вижу. Выводится на экран сообщение, и все дела. А вот вторая строка начинается странно…

КАК ПОЯСНИТЬ СВОЮ ПРОГРАММУ
— Там появляется новый оператор — оператор примечаний, который записывается буквами REM, что является сокращением слова remark — «римак» — «примечание». Работа этого оператора крайне проста — он ничего не делает.

— Да, ничего не делать просто. А зачем же тогда нужен такой оператор?

— После REM в программе можно записать все, что хочется. Почти все, как ты поймешь из следующей строки программы. Это могут быть пояснения работы программы: что она делает, каков ее алгоритм. В отдельных местах, посложнее, можно пояснить, что делается.

— Это что, опять для пользователя? Но пользователь же сам программу не видит.

— Всякие бывают пользователи. Однако такие примечания нужны не только пользователю, но и самому программисту, когда через некоторое время он изрядно позабудет свою программу. Поэтому так важно, чтобы в программе были примечания. Не столь важно, чтобы их было много, но важно, чтобы они давали что-то новое по сравнению с самой программой. Например, без толку писать что-нибудь такое:

10 REM ПРИСВАИВАЕМ ПЕРЕМЕННОЙ А ЗНАЧЕНИЕ 7

20 А=7

Здесь в примечании описан оператор Бейсика. И все.

— И как же было бы лучше?

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



Записанное в примечаниях всегда пригодится


В следующей строке появляется символ «\». Как я тебе уже говорил, это обратная косая черта. Ею отделяют один оператор от другого, если хотят записать в одной строке несколько операторов. В этой строке я сначала записал оператор PRINT без ничего — он выведет на экран пустую строку. А за ним следует другой оператор PRINT с текстом. Сейчас должно быть ясно, что в тексте примечания после оператора REM эта обратная косая черта не должна появиться. Ее появление означало бы, что примечание кончается и начинается следующий оператор. Обратную косую черту я использую еще для отделения одной части программы от другой, как, например, в строке 55.

— Строку 40 можешь не пояснять, но следующая… Там тоже два оператора — PRINT и INPUT. Ничего страшного, понять можно. Однако хорошо, что в одной строке можно писать несколько операторов.

— Хорошо-то хорошо, но увлекаться этим не советуют, потому что теряется наглядность программы. И еще, управление можно передать только на начало строки. На середину нельзя. Если бы мне когда-нибудь попозже понадобилось при помощи операторов IF или GO ТО передавать управление на оператор INPUT в строке 50, то пришлось бы эту строку переделать в две строки. Но я знаю, что этого мне не придется делать, так как и PRINT, и INPUT в строке 50 тесно связаны между собой.

— Далее идут примечания. Целых три строки. Там ты пишешь о том, как программа делает свое дело.

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

— Ага! Теперь значение А сравниваешь с нулем. Если А не нуль, и это было бы естественно, ты идешь на строку с номером 150, но ее я смотреть не буду. Буду смотреть следующую строку, а там у тебя опять ветвление. Ну да, так это предусмотрено в блок-схеме. Если, например, В=0, то выводится одно сообщение, а если не так, то другое. Думаю, это понять можно. После вывода обоих сообщений ты идешь на строку 160, в которой…

— Сначала, может быть, надо посмотреть строку 150, на которую попадаем, если А не равно нулю.

— Чего там смотреть, выводится частное В/А, и все. А потом прямым ходом на строку 160! Как же иначе, ведь и в блок-схеме после всех работ предусмотрен переход на блок с вопросом: что делать, продолжать работу или нет? Значит, сейчас должна решаться эта проблема. Что и делается в строках с номерами от 160 до 190. Прекрасная программа, Петушок! Поздравляю!

— Смотрим следующую программу.

12. НЕБОЛЬШОЙ ЭКСКУРС В БУХГАЛТЕРСКОЕ ДЕЛО

— Эта программа рассчитывает подоходный налог по заданной величине зарплаты.

— Ужас, какие серьезные дела! Я, например, и знать не знаю, сколько мои предки получают и какие налоги платят.



— Могла бы и поинтересоваться. Правда, я и сам, только работая с этой программой, узнал, по какому алгоритму рассчитывается подоходный налог. И этот алгоритм выглядит так: с зарплаты, меньшей 70 рублей, никаких налогов не удерживают — это так называемый необлагаемый минимум. Налог не удерживают и с копеек. Если тебе положены 71 руб. 99 коп., то налог будешь платить только с 71 рубля. Для сумм 71,72 или 73 рубля налог N рассчитывается по формуле:

N=0.34A—23.89,

где через А обозначена зарплата. Для следующих сумм формулы будут такими:

N=0.35A—24.60, если 74<А<76;

N=0.34A—23.79, если 77<А<90;

N=0.12А—3.80, если 91 <А<100.

Наконец, начиная с 101 рубля налог платят как со ста рублей плюс еще 13 % от суммы выше ста рублей. Для этого случая получается такая формула:

N=0.1 ЗА—4.80.

— Поняла я не так уж много.

— Тогда посмотри еще блок-схему.

А теперь текст программы.

10 PRINT "ПРОГРАММА СЧИТАЕТ ПОДОХОДНЫЙ НАЛОГ"

20 REM А — ДОХОД / N — НАЛОГ

30 М=70 \ \ RЕM НЕОБЛАГАЕМЫЙ МИНИМУМ ЗАРПЛАТЫ

40 R1=.34 \ \ REM КОЭФФ. В ФОРМУЛЕ N=R1*A-Z

56 R2=.35

60 R3=.12

70 R4=.13

80 S1=73 \ \ RЕM КОНСТАНТЫ ДЛЯ СМЕНЫ ФОРМУЛ

90 S2=76 \ \ S3=90

100 Z1=23.39 \ \ RЕМ КОЭФФ. В ФОРМУЛАХ

110 Z2=24.6

120 Z3=23.79

130 Z4=3.8

140 Z5=4.8

150 S4=100

155 \

160 PRINT \ PRINT "ВВЕДИТЕ ЗАРПЛАТУ В РУБЛЯХ"

170 INPUT A1

180 A=INT(A1) \ REM НАЛОГ НАСЧИТЫВАЮТ ТОЛЬКО С РУБЛЕЙ

185 \

190 RЕМ НАЧАЛО РАСЧЕТА НАЛОГА жжжжжжжжжжжжжжжжжжжжжжжжжжж

200 IF А>М THEN 220

210 PRINT "ЗАРПЛАТА";А;" РУБ. НЕ ОБЛАГАЕТСЯ" \ GO ТО 350

220 IF А>S1 THEN 240

230 N=R1*A-Z1 \ GO ТО 310 \ \ REM 0.34*А-23.89

240 IF А>S2 THEN 260

250 N=R2*A-Z2 \ GO ТО 310 \ \ РЕМ 0.35*А-24.60

260 IF А>S3 THEN 280

270 N=R1*A-Z3 \ GO ТО 310 \ \ РЕМ 0.34*А-23.79

280 IF А>S4 THEN 300

290 N=RЗ*А-Z4 \ GO ТО 310 \ \ REM 0.12*А-3.80

300 N=R4*A-Z5 \ \ РЕМ 0.13*А-4.80

305 \

310 REM НАЛОГ РАССЧИТАН жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж

320 K=INT(N*100+.5) \ N=K/100

330 R=INT(N) \ K=K-R*100 \ REM ОТДЕЛЯЕТ РУБ. ОТ КОП.

340 PRINT \ PRINT “НАЛОГ БУДЕТ ”;R;” РУБ. ”;к;" КОП”

350 PRINT \ PRINT “ВВЕДИТЕ 0 ДЛЯ ОКОНЧАНИЯ РАБОТЫ”

360 INPUT Z

370 IF Z<>0 THEN 160

380 STOP

390 END



— Давай сюда эту программу, сейчас я ее разнесу в пух и прах. Так, так… Первая строка выпечатывает, что программа собирается делать. Очень хорошо. Во второй строке примечания — зарплата, налог…

— В следующих строках я определяю необходимые для счета постоянные. Например, через М обозначаю необлагаемый минимум. Когда этот минимум повысят, в программе нужно будет поменять только строку 30 и не придется по всей программе искать, где стоит число 70 и что именно это 70 там означает. То же самое и с другими постоянными.

— Понято! Это происходит в строках с номерами с 30 по 150. Потом пользователь вводит величину зарплаты. Это происходит в строке 170. А в строке 180? Что там делается?

НУЖНЫЕ ВСЕМ ФУНКЦИИ
ВСТРОЕННЫЕ ФУНКЦИИ

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

— А почему их называют встроенными?

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



Целую часть находит встроенная функция INT


— И что бы это I NT значило?

— INT — это сокращение английского слова integer, которое произносится «интэджер» и означает «целый», конечно, если речь идет о числах, а не о горшках. Функция I NT находит целую часть числа, точнее, целую часть того арифметического выражения, которое записано в скобках за словом INT. Например, если А=4.56789, то INT(A) будет 4. Разве не просто?

— Великолепная вещь — программирование! Человек совершенно незаметно для себя повторяет и закрепляет арифметику.

— Возвратимся к строке 180. Как ты уже знаешь, налог начисляют только из рублей, копейки отбрасываются, что на языке математики означает: взять целую часть зарплаты.

— Блестяще! А это что за звездочки в строке 190?

— Да просто для красоты: отделяют вводную часть программы от основной. Оператор примечаний можно использовать и в таких целях.

— А в строке 200 зарплату уже сравнивают с необлагаемым минимумом. Если зарплата оказалась больше, то перепрыгивают строку с номером 210, которую надо бы было выполнить, если бы зарплата оказалась меньше минимума. Так оно и есть! В этой строке выводится сообщение, что зарплата не облагается, и управление передается куда-то вперед. Потом увидим, куда именно.

Дальше. В строке 220 проверяют, не будет ли зарплата, случаем, больше 73 рублей. А на строку 230 попадают только тогда, когда зарплата больше необлагаемого минимума, то есть 70 рублей, и, кроме того, не больше 73 рублей. Кажется, все идет по формулам.

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

— А вот когда налог рассчитали, происходит что-то необыкновенное. Я имею в виду строку 320.

ОШИБКИ ОКРУГЛЕНИЯ В КОМПЬЮТЕРЕ НЕИЗБЕЖНЫ
— Видишь, при расчетах в машине возникают ошибки округления и, скажем, вместо правильного результата 5 может получиться 4.99999, что, конечно, весьма близко к 5. Но, если машина выведет, что налог равен 4.99999 рубля, любой бухгалтер со смеху умрет. К сожалению, первые варианты программы так и делали, и поэтому понадобилась строка 320. Здесь я делаю следующее. Сначала, умножив на сто, превращаю рубли в копейки и потом добавляю полкопейки, чтобы в случае, если вместо 500 копеек расчет дал 499.999 копейки, я получил бы 500.499 копейки, взяв целую часть которых, я получу 500 копеек, как и надо. А если результат и так был правильным, то добавление полкопейки и взятие целой части его не испортят.


Стой! Копейки округляют не так!


Еще я хотел в рассчитанном налоге отделить рубли от копеек: например, если получилось 5.42 рубля налога, то я хочу отдельно вывести 5 и 42. Понять это отделение рублей и копеек не так-то просто. Смотри, здесь в строке 330 я от общего количества копеек К вычитаю количество полных рублей, помноженное на 100. В результате будет…

— Количество копеек! Это совсем не сложно!

— Еще остались вывод результатов и запрос, хочет ли пользователь работать с этой программой. Я эту программу проверял для всех значений зарплаты от 71 до 90 рублей, для некоторых — между 90 и 100, а также для некоторых, больших 100. И всегда значение рассчитанного налога совпадало с тем, которое получается по таблицам, используемым настоящими бухгалтерами. Те таблицы и составлялись по этим формулам. Это я тебе рассказываю, чтобы ты поняла, как важно показать, что твоя программа действительно всегда считает то, что требуется.

— Ну ладно. Вообще мне кажется, что можно твои программы и вправду посмотреть — кое-что проясняется. Может, завтра другие посмотрим, если у тебя еще есть.

— Есть, есть. Посмотрим.

13. КОМПЬЮТЕР ИЛИ УЧИТЕЛЬ!

На следующий день Петя принес программы посложнее.

— Ты, конечно, уже слышала, что, как считают некоторые, компьютер может не хуже учителя обучать детей и что скоро всех учителей заменят машинами. Другие тут возражают, думают, что машина ничему толковому не научит. Пока они спорят, изучим одну обучающую программу. Разумеется, совсем простую. Да обучающие программы и не бывают особенно сложными. Считается, что самое важное не запрограммировать, а все продумать, как программа будет обучать, чтобы чему-то научить.



НАУКА ОБУЧАТЬ НАЗЫВАЕТСЯ МЕТОДИКОЙ
Моя программа обучает таблице умножения, точнее, повторяет ее. И методика обучения такова. Берутся два целых случайных числа. Потом о случайных числах расскажу поподробнее. Если первое равно единице, то заменяем его на 7. Если же второе — то на 8. Оба числа показываем обучаемому, он их должен в уме перемножить и ввести результат. Если результат оказался правильным, то хорошо, если же нет, то отмечаем в памяти, что ученик ошибся. Так делаем столько раз, сколько ученик желает. В самом конце выводим оценку.

— А где тут методика?

— Методика в том, что мы совсем не даем примеры умножения на единицу, такие все умеют решать. Зато мы увеличиваем количество примеров с умножением на 7 и 8.

— Значит, ты считаешь, что примеры с девяткой легче решить, чем примеры с семеркой или восьмеркой.

— Я в этом не сомневаюсь. Умножая на девять, нужно число умножить на десять и отнять само число, например:

7Х9=7Х(10—1)=7Х 10—7=63.

— Да ладно уж, что я таблицу умножения не знаю?

— Теперь можешь посмотреть программу.





— Посмотрим, посмотрим, как ты собираешься детей мучить. Этот последний оператор REM мне очень нравится, в нем легче легкого разобраться. А вот этот оператор цикла — в строке 40—вот он-то потруднее будет. Ого! И целых три оператора в одной строке!

— Ничего особенного! Этот цикл выводит на экран 24 пустые строки. Так сказать, очищает экран, потому что на экране имеются ровно 24 строки.

— Дальше идет милое сюсюканье. Усыпляешь бдительность ребенка. Так и надо! Что-то существенное начинается в строке 80: вводится количество примеров. И сразу в следующей строке его сравнивают с 5…

— Это для проверки ввода. Ввод всегда нужно проверять. Мало ли где человек может ошибиться. Я считаю, что правильное количество примеров от 5 до 100. Если пользователь по ошибке или нарочно вводит другое число, я это число заменяю либо на 5 в строке 100, либо на 100 в строке 130.

— Прекрасно! Ты, мол, «дружок», введи сколько хочешь, а мы скажем, сколько «берем». Вот это действительно смахивает на педагогику.

— Но ведь это же разумно: брать больше одного или двух примеров и не брать слишком много!

— Разумно, разумно. Я просто дурачусь. Здесь не класс, где нужно сидеть спокойно. Смотрим дальше. Строку 140 я понимаю полностью — она для запугивания ребенка. В строке 150 ты какой-то переменной К присваиваешь значение нуль. Что такое К? Смотрим примечания в начале программы. Количество ошибок. A-а! В самом начале этот бедняга еще никаких ошибок не наделал, поэтому их количество и равно нулю. Дальше цикл… начинается в строке 160… Интересно, а где он кончается? В строке 280. И очевидно, все происходит именно в этом цикле. А это что такое — в строке 170? Ничего не понимаю.

ГЕНЕРАТОР СЛУЧАЙНЫХ ЧИСЕЛ — ФУНКЦИЯ RND
— Это ты увидела новую встроенную функцию, которая выдает случайные числа. Ее обозначение RND получено сокращением' английского слова random — его произносят «рэндом», и означает оно «случайный». Сейчас самое время поговорить о случайных числах. Наиболее простой способ их получения — бросать игральную кость. Если бросать много раз, то все числа от единицы до шести выпадут примерно одинаковое количество раз. А то, какое число выпадет в следующий раз, предугадать нельзя. Единственное, что можно сказать, — вероятность выпадения каждого числа равна одной шестой.



СЛУЧАЙНЫЕ ЧИСЛА

— А случайные числа? Что же это такое?

— Если, бросая кость, ты будешь записывать выпадающие числа, то и получишь равномерно распределенные случайные числа: 2, 3, 1, 5, 4, 3, 2, 1 и так далее.

А сейчас представь себе игральную кость с двадцатью гранями, и на гранях написаны числа от 1 до 20. Бросая эту кость, ты получишь равномерно распределенные натуральные случайные числа от 1 до 20.

Но вернемся к функции RND, которая, кстати, отличается от других функций тем, что не имеет аргумента. Обращаясь к этой функции, получаем случайные действительные числа, равномерно распределенные в интервале [0;1].



Выбор случайного числа


— Нет, этого я не понимаю.

— Хорошо, попробую попроще. Когда я обращаюсь к этой функции, она закрывает глаза и острым карандашом тычет в интервал от нуля до единицы. И попадает в какое-то число, например в 0.76812. В следующий раз, когда я обращаюсь к ней, она попадает совсем в другое число, например в 0.38631. При этом попасть в любое место у нее равная вероятность. Ее совсем не тянет тыкать ближе к концам или к середине интервала. Это и означает, что получаемые числа — «равномерно распределенные». Если же выражаться совсем просто, для детей, то можно сказать, что при помощи функции RND компьютер «задумывает» одно число от нуля до единицы.

— Наконец я начинаю понимать.

— Может быть, поймешь еще лучше, когда узнаешь, зачем мне это.

ЗАЧЕМ НУЖНЫ СЛУЧАЙНЫЕ ЧИСЛА
Представь, что я хочу сделать игральную кость с девятью гранями, чтобы иметь случайные числа от 1 до 9, которые я буду давать ученику перемножать. А такой кости нет и вообще быть не может. Поэтому я интервал от 0 до 1 разбиваю на девять одинаковых частей и даю функции RND тыкать в этот интервал. Если она попадает в пятую часть, то я говорю, что мне выпала пятерка, если в третью, то тройка и так далее. На самом деле мне функция RND дает только число С между нулем и единицей и мне самому надо определить, в какую из частей оно попадает. Это делается так: полученное число делим на одну девятую и узнаем, сколько девятых оно содержит. Например, если С=0.76812, то, деля на 1/9, или, что то же самое, умножая на 9, получим 6.91308. Значит, это число находится за шестью девятыми, но ближе семи девятых, то есть в седьмой части.


RND выбрасывает кости


Как найти эту семерку или, в крайнем случае, шестерку? Здесь неоценимую помощь оказывает наша знакомая — функция INT. Скажи, чему равна целая часть 6.91308?

— Да шести же!

— Осталось немного. Чтобы рассчитать, в какую часть интервала попала функция RND, нужно добавить единицу к этой целой части. Все это делается в строке 170. И в строке 200, где выбирается второе число. Подчеркну, что, повторно обращаясь к функции RND, мы всякий раз получаем другое случайное число. Почти так же мы поступили бы и в случае, если нужно было бы иметь целое случайное число от 1 до произвольного числа М. Тогда вместо 9 в строке 170 подставили бы переменную М.

— Ты слишком далеко умчался. Я так и не поняла, что происходит в строке 180… Так-так, ты полученное число сравниваешь с единицей, и поскольку единицы тебе не нравятся, то ты переделываешь значение А с единицы на семерку.

— И подобным образом я поступаю с переменной В. Смотри строки 200, 210 и 220.

— Ладно. И строка 230 хочет у бедного ребенка узнать, какое же все-таки получается произведение.

— Да, действительно. Но остановись, эту строку полезно поизучать. Видишь пробелы после слов СКОЛЬКО БУДЕТ и также после и перед УМНОЖИТЬ НА? Они нужны потому, что значения переменных выводятся сразу после этих текстов — видишь точки с запятыми после А и В? И еще одна мелочь: после значения В выводим пробел, так как следующим идет оператор INPUT, который в той же строке покажет вопросительный знак. И будет красивей, если значение В и вопросительный знак отделим пробелом.

Кстати, этот вопросительный знак оператор INPUT показывает всегда, и отменить его показ нельзя, поэтому я в выводе перед вводом обычно задаю вопросы. Как в этом случае: СКОЛЬКО БУДЕТ, а не НАЙДИ или как-то еще по-другому.

— Прекрасно. Ученик ввел ответ, и ты в строке 250 сравниваешь этот ответ с правильным результатом.

— Если все правильно, я сочиняю следующий пример. При этом, как видишь, я ухожу на оператор NEXT, чтобы увеличить значение переменной цикла — счетчика примеров и вообще чтобы цикл работал как надо.

— А если ответ неправильный, увеличиваешь счетчик сделанных ошибок и выводишь неприятное сообщение.

— Еще и правильный ответ, чтобы человек знал.

— Сейчас цикл уже закончен, все примеры рассмотрены и мы находимся на строке 290. Что такое было К? Количество ошибок. Проверяем, не нуль ли количество ошибок?.. Если нуль, то идем на строку 360, А если не нуль… A-а! Выводится количество правильных и неправильных ответов. Да?

— Совершенно верно.

— И что это за Р1 в строке 310? Оценка? И так ты вычисляешь оценку?!

ОЦЕНКИ — ВЕЩЬ НУЖНАЯ
Да. Я делю количество правильных ответов на общее количество примеров и узнаю долю правильных ответов. Моя система оценок такая: если ты правильно ответил на 4/5 вопросов, то получаешь четверку, если на 3/5, то тройку, и так далее до единицы. Поэтому я должен узнать, сколько пятых из всех ответов были правильными. Чтобы это узнать, я делю долю правильных ответов на одну пятую — так же, как я делал, когда искал случайное число от 1 до 9. Таким способом я получаю оценку, но с десятичными дробями за запятой, например 2,8 или 4,6. Целую часть этого числа в качестве оценки брать нельзя, потому что оценка получится заниженной: при 2,8 вместо тройки, что было бы более справедливо, ученик получит двойку, при 4,6— четверку. Чтобы так не произошло, я добавляю 0,5 и только потом беру целую часть.


Какую оценку я получу?…


— Ты очень любезен.

— И еще что. Если правильных ответов очень мало или даже нет ни одного, то может получиться оценка нуль, что в наших школах не предусмотрено. Поэтому в строках 320 и 330 этот возможный нуль переделывается в единицу. И потом…

— И потом вывод оценки. Это прекрасно! Я говорю о предложении «Могло быть лучше!». Оно может служить неопровержимым доказательством, что компьютер может быть учителем. Если кто и сомневался, то, увидев эту фразу на экране, бесспорно согласится, что машина может полностью заменить учителя.

— Не знаю, но мне кажется, что компьютер может только чуточку помочь учителю, подучивая школьника каким-то мелочам.

— Ну знаешь ли, Бейсиков! Я сама отлично понимаю, что ни в коем случае нельзя заменять учителей машинами. Кто же захочет дразнить машину? И разве ты сможешь машине втемяшить, что вчера вечером жутко болела голова и ты не смог выучить таблицу умножения и ставить тебе пару бессердечно!

— Вернемся к программе.

— А там ничего не осталось. Строка 360 выводит… Что же она выводит? A-а! На эту строку приходят, если ошибок вообще не было. И потом запрос о продолжении работы. Это как всегда.

— И теперь…

— Теперь надо отдохнуть. Было совсем не так легко изучать творения твоего гения. Пошли во двор, порезвимся. Я только прихвачу ракетки для бадминтона.

14. ГЛАВНОЕ — ЭТО УЧЕТ

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

— Лучше не будем спешить. Не кончим сегодня, продолжим завтра.

— Знаешь что, Бейсиков, твое образцовое мышление иногда дает позорные сбои. Любой классный руководитель, и электронный, и этот… э… физиологический, тебе скажет, что начатое дело нельзя откладывать на потом.



ЧЕМУ ЕЩЕ МОЖНО УЧИТЬ ДЕТЕЙ?
— В любом случае нечего терять зря время. Давай «проразмыслим» последнюю программу обучения таблице умножения. Берешься ли ты составить, например, программу, которая обучала бы первоклашек сложению в объеме первой десятки?

— А эту твою программу с таблицей умножения можно смотреть?

— Отчего же нет?! Это же не контрольная. В программировании ты можешь смотреть все что хочешь. Главное, чтобы программа работала как надо. Хотя, нет, по программированию тоже могли бы быть контрольные, но на сей раз это не контрольная.

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

— Хорошо, но как со сложением в пределах сотни?

— В пределах сотни? Это будет потруднее. Тут надо понимать, как работать с функцией RND.

— Как же иначе! Но если все-таки не понимаешь, то запомни: когда нужно случайное действительное число в пределах от нуля до X, пиши так:

X*RND

Ну, а когда нужно целое число в пределах от единицы до N, пиши так:

INT(N*RND)+1

— Значит, случайные числа в пределах сотни я смогу получить, написав выражение

A=INT(100*RND)+1

— Без сомнения.

— Тогда я такую программу составить берусь! Более того, я берусь с этими бедными детьми повторить вычитание в пределах сотни.



— А это уже будет не столь просто! Как ты поступишь, если разность случайных чисел окажется отрицательной? Маленькие дети про отрицательные числа ничего не слыхали!

— Что же делать?… Может быть, в таком случае поменять числа местами?

— Меняй смело. Сейчас расскажу, как это делать. С ходу можно и не догадаться. Поменять местами значения двух переменных А и В можно только при помощи третьей переменной, например С. Это будет выглядеть так.

С=А

А=В

В=С

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

— Что-то можно было бы предпринять и с делением.

— Еще бы! Например, пусть ученик определяет, сколько раз второе число входит в первое и каков остаток.

— Вычислить остаток при делении я не берусь…

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

— Ну, ну… Все равно немножко надо подумать.

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

— Похоже, такие программы превращения были бы даже проще, так как для них нужно только одно случайное число.

— Точно! А если бы и понадобились даже три, то ничего ужасного не произошло бы. Функция RND выдала бы их без замедления.

Еще стоило бы подумать об улучшении методики обучения. Программа могла бы следить за тем, какие примеры для школьника самые трудные: если, например, он путается в уножении на 7, то чаще давать такие примеры. Или через некоторое время повторить те примеры, в которых он ошибался. Такая программа была бы намного сложнее.

— Кажется, у тебя была еще какая-то программа, которую стоило бы посмотреть?

МАГАЗИН В ПАМЯТИ КОМПЬЮТЕРА
— Да, есть. И эта программа решает совсем другую проблему. Представь себе магазин тканей, и в нем какая-то ткань имеется в нескольких рулонах, или, как говорили в старину, штуках. Продавщицы отрезают ткань от всех штук, и им важно знать, сколько ткани в каждой штуке осталось, чтобы в конце не остались от штук маленькие куски, которые никому продать будет нельзя и придется списывать или уценивать.

— Что же продавщица может сделать?

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



— Очевидно, ты редко бываешь в магазинах. В таких случаях продавцы говорят: вот вам метр восемьдесят, покупайте целиком, резать мы не будем.

— Мы играем в магазины высокой культуры обслуживания, выражаясь по-научному, их моделируем.

— Пусть будет так. Но чем можешь помочь ты со своим компьютером?

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




— Вот это да! Такая большая программа, прямо программища!

— Куда уж! Очень большая программа должна была бы быть в тысячу раз больше.

— Неужели! Почему ты этого не сказал в самом начале?! Я бы не ввязалась в эту программистскую кутерьму. В тысячу раз больше! На такие подвиги я не способна.

— Никто не способен. Очень большие программы делают несколько программистов. Говорят, бывают бригады с сотнями программистов и все они составляют одну большую программу.

— Ты меня успокоил, спасибо.

— Как всегда, в начале программы идут примечания, чтобы знать имена наиболее важных переменных. Собственно программа начинается в строке 40, где описан массив G, содержащий длины штук. Я принимаю, что в магазине не больше пятидесяти штук, и — что очень важно — они пронумерованы.

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

— Речь идет не о штуках одной ткани, здесь могут быть и разные ткани. Если учет надо вести для большего количества штук, то в строке 40 число 50 заменяется на нужное в скобках у имени G и справа от знака равенства в операторе присвоения.

— Да, я уже вижу, что в следующей строке ты вводишь действительное количество штук и сразу сравниваешь его с D1. И если штук оказалось больше, то выводишь сообщение о заменах в строке 40.

— Потом начинается вывод основных сообщений. Пользователь узнает, какие существуют режимы работы, и получает предложение выбрать нужный режим — другими словами, ввести номер нужного режима. Надеюсь, что все это ты хорошо понимаешь. Неясности начнутся со строки 150. Здесь используется незнакомый оператор — оператор вычисляемого перехода ON. Это слово произносят «он», оно означает «на», хотя мы будем его переводить иначе — «в соответствии с».

ЕЩЕ ОДИН ОПЕРАТОР ПЕРЕХОДА
Запись самого оператора выглядит так:

ON Р GO ТО 160, 220, 370, 460
В соответствии со значением арифметического выражения Р идти на строки с номерами 160,220,370, и 460
Оператор вычисляемого перехода работает просто. Сначала проверяется значение арифметического выражения, в нашем примере — значение переменной Р. Если Р=1, то управление передается на строку, номер которой идет первым после GO ТО, в нашем примере—160; если же Р получилось равным 2, то на строку, номер которой указан вторым, и так далее.

Если же значение Р получится таким, что столько номеров строк в операторе нет, как, например, для нашего случая 5 или —2, то выводится сообщение об ошибке и — что намного печальнее — программа прекращает работу. По этой причине ты сразу можешь указать серьезнейший недостаток моей программы: она не проверяет, ввел ли пользователь правильное значение Р между 1 и 4. Если же проверка была бы, то неправильный ввод можно было бы повторить и работа программы не прекратилась бы.



Чтобы ты не подумала, что этот оператор существенно новый, попробуй написать его старыми операторами IF.

— Надо по-по-по-по-думать… Этот самый переписывать?

— Конечно. Не стану же я новый придумывать.

— Хорошо, хорошо. Сейчас. Начну со строки 150.

150 IF Р=1 THEN 160

151 IF Р=2 THEN 220

152 IF Р=3 THEN 370

153 IF P=4 THEN 460

— Совершенно верно. И вот теперь мы можем изучать первый режим — задание начальных длин штук.

ЧТО ДЕЛАТЬ В НАЧАЛЕ РАБОТЫ
— В тексте программы ты его выделил. Начальное задание длин происходит в строках начиная со 160 и кончая 210.

— И представляет собой один цикл по всем штукам. В этом цикле вводится длина каждой штуки и засылается в массив G.

— И куда передается управление в конце ввода длин? Ага, ясно! На выбор нового режима. А что же тут выбирать? Надо переходить на ввод длин отрезов.

— Чаще всего, действительно, на второй режим. А если что-то случилось — может быть, пользователь хочет повторить ввод, потому что все здорово перепутал, или хочет посмотреть, что введено, а может быть, ему все надоело и он хочет закончить?

ЧТО ДЕЛАТЬ ПОСЛЕ КАЖДОЙ ПОКУПКИ
— Второй режим начинается со строки 230 и кончается строкой 360. Длинный.

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

— Почему такой странный вывод в строках 230 и 240?

— Представь себе ситуацию: человек все вводит и вводит длины отрезов и тут ему захотелось посмотреть, сколько в каждой штуке осталось, чтобы решить, от какого отреза сейчас резать. И тогда он введет нулевую длину отреза, что означает переход на показ длин штук. А чтобы этот секрет пользователь узнал, надо ему об этом сообщить. Что я и делаю в строках 230 и 240.

— Далее следует вопрос: каков номер штуки? Очевидно, той, от которой только что отрезали. Ввели… И тут номер штуки сравнивается с собственной целой частью! Интересно бы знать, кому это надо?

— Это уже проверка. Номер штуки должен быть целым числом. А целая часть целого числа совпадает с самим числом. Так можно убедиться, что ввели целое число.

— А зачем проверять такую мелочь? Кто станет вводить нецелый номер?

— Опытные программисты уверяли, что в этом месте такое запросто может случиться. Человеку хочется вводить все быстрее и быстрее, и впопыхах он может ввести вместо номера штуки длину отреза.

— Потом номер штуки сравнивается с нулем. Чтобы узнать, не надо ли уходить на показ. Если не надо, то вводится длина отреза,рассчитывается остаток ткани в штуке и сразу сравнивается с нулем. Ясно! Чтобы напечатать в строке 320 «так много нельзя отрезать», если захотели отрезать больше, чем было в штуке.


Алгоритм должен уметь исправлять ошибки


— Вот что еще может случиться: человек ошибочно ввел длину отреза не для той штуки, для которой надо было, или ошибся при вводе длины отреза. Надо было вводить 1,45 метра, а он ввел 1,54 метра. И тут же спохватился. Исправление внести очень легко: надо от той же штуки отрезать минус 1,54 метра, то есть в самом деле добавить эту длину, а потом можно и вычесть нужные 1,45. Не будь такой возможности, мне пришлось бы делать еще один режим — режим исправления.

— Общий принцип ясен. Программист должен признавать за пользователем общечеловеческое право ошибаться и должен предвидеть в своих алгоритмах, что делать, если он действительно ошибся.

— Далее проверяю, не равна ли нулю длина этой штуки, то есть не продана ли уже вся штука. Если так, то сообщаю об этом пользователю. Если не так, то в строке 350 присваиваю новое значенйе длине соответствующей штуки. И запрашиваю следующий номер штуки для обработки.

— Этим режим кончается, и можем смотреть режим показа в строках 380–450. Что это за максимальная длина показываемых штук М в строке 380?



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

— Прекрасно. Дальше написан цикл по всем штукам, и похоже, что ты не собираешься показывать нулевые длины проданных штук.

— Да, именно поэтому я в строке 410 длину каждой штуки сравниваю с нулем.

— А в следующей строке ты сравниваешь длину штуки с этой максимальной длиной и обходишь показ в строке 430, если он не нужен.

И, когда все показано, уходишь на выбор нового режима.

— Это тоже спорное место. Раз я ухожу на показ длин во время ввода отрезов, то возвращаться надо было бы обратно тоже на второй режим. Но тогда пользователь не сможет закончить работу. Сейчас он может из основного режима ввода длин отрезов перейти на режим показа, потом на выбор режимов и выбрать четвертый режим — окончание работы.

О ДАННЫХ И ИХ ОБРАБОТКЕ
Не хочу хвастаться, но эта программа уже намного ближе к настоящим нужным программам, чем предыдущие. Она может сойти за программу обработки данных. Здесь данными являются и длины штук, и длины отрезов.

— А еще что-нибудь похожее на твои штуки можно придумать?

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



— А что в этом ужасного? В машину загрузят остаток, подъедут к следующему вагону и там догрузят, сколько надо.

— А ты подумала о потерях рабочего времени? Машина должна переезжать, ждать, пока подъедет погрузчик, пока откроют вагон и, кто знает, что еще!

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

— Ну нет! Так я делать не буду. Я все истрачу, а потом видно будет.

— Верю. Но если бы ты все-таки все распределила, то, купив что-то, сразу могла бы побежать к машине и ввести сведения, сколько истрачено.

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

— Вот видишь! И таких примеров можно было бы придумать еще и еще. Существенно то, что мы имеем массив с числами, которые что-то для нас означают, не важно что, и мы с этими числами что-то делаем…

— … не важно — что. Здорово у тебя выходит. Что-то делаем, не важно — что. Чем-то, не важно — чем. Как-то, не важно — как. Где-то, не важно — где.

— Я, наверно, говорю непонятно, но при изучении программирования важно понять его сходство с математикой. Иначе получится, как с Ванечкой, который пришел из школы домой и рассказывает папе, что сегодня проходили сложение. Папа хочет узнать, какие у Ванечки успехи: «Смотри, Ванечка, здесь у меня два апельсина, и я добавляю еще два. Сколько получается вместе?» Ванечка думает, думает и говорит: «Не знаю. В школе мы складывали яблоки».

— Это старый анекдот.

— Старый-то старый, но от этого не менее поучительный. Посмотри сейчас на наш массив в программе! Важно ли, что в нем хранятся именно длины штук? Ясно, что не важно. Или то, что программа из элементов массива что-то именно вычитает? А если было бы сложение, существенно ли это все поменяло? Никак нет! Как говорят: логическая структура программы осталась бы неизменной. Или так: блок-схема программы не поменялась. В программировании не только не важно, апельсины или яблоки, но и какие с ними проводят действия: складывают, вычитают или что-либо другое.



— Не понимаю, зачем говорить о сложении, когда у нас вычитание.

— Если ты собираешься всю свою сознательную жизнь решать только эту задачу, то, конечно, не нужно. А если хочешь что-то усвоить, то придумай пример, где к элементам массива нужно было бы прибавлять.

— Да, хватку опытного педагога ты имеешь! Как только ученик «возникает», так сразу, шлеп, придумывай пример. Сиди и думай. И не чирикай.

— Думай, думай. И не чирикай.

ЕЩЕ ОБ ОБРАБОТКЕ ДАННЫХ
— Запросто придумаю… Готово! В зоопарке живут слоны, львы, зайцы и другие звери?! Живут. Их кормить надо? Надо. Это денег стоит? Да. И немалых. Я предлагаю составить такую программу. Присваиваем каждому зверю номер и соотносим с ним соответствующий элемент массива. Два слона — два элемента. Четыре тигра — четыре элемента. И так далее. Купили зверю что-то пожевать, сразу в этом массиве отмечаем, сколько потратили, то есть добавляем сумму денег к элементу массива. Так что наша программа позволит узнать, сколько с начала года каждый зверь съел, то есть сколько на это потрачено. И если он съел слишком много, то больше есть ему не даем.



— С точки зрения программирования твой пример безупречен. А с точки зрения зверей могли бы быть и возражения.

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

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

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

— Нет, такую «трагедию» я даже представить не могу.

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

15. ВЫЧИСЛИТЕЛЬНАЯ МАШИНА НЕ ТОЛЬКО ВЫЧИСЛЯЕТ

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

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

— Позвольте, сударь, заметить, что мое знакомство с этим достижением человеческого гения не дает возможности обнаружить те существенные отличия, о которых вы намедни изволили выразиться.

— Надеюсь, это станет яснее сегодня, когда мы рассмотрим символьные переменные.

СИМВОЛЬНЫЕ ПЕРЕМЕННЫЕ
СИМВОЛЬНЫЕ ПЕРЕМЕННЫЕ



— Когда же кончатся эти новые понятия!

— Никогда, сударыня. Программист должен учиться всю жизнь. А символьные переменные ничего нового собой не представляют — переменные уже были, символы тоже, сейчас будут символьные переменные, а старые переменные впредь будут называться «числовыми переменными». Если честно, то определенное отличие имеется; большое или маленькое — увидишь сама.

СИМВОЛЬНАЯ СТРОКА

— Ну что ж, начинай.

— Начну с того, что символьные переменные обозначают буквой и «солнышком», а посередине может быть цифра, но не буква! Например, А¤, В¤, С1¤ — это правильные обозначения символьных переменных, а неправильные…

— Неправильных не надо. Продолжай.

— Символьная переменная имеет еще и значение — один или несколько символов. Так сказать, строку символов. Кстати, символьные переменные называют еще и строковыми. Имеет ли какой-нибудь смысл эта строка, машине все равно, об этом знает только программист. Немножко потерпи, станет яснее, когда покажу, как выглядит оператор присвоения в случае символьных переменных. Хотя бы так: А¤=«А». Такая строка означает: символьной переменной с обозначением А¤ присваивается значение — строка символов, состоящая из одной только буквы А. Итак, значения символьных переменных в операторе присвоения ставят в кавычках.

— Что-то похожее делали в операторе PRINT.

ВЫВОД СИМВОЛОВ
— Совершенно верно! Об этом операторе ты вспомнила в нужный момент. Значения символьных операторов можно и выводить. Если бы сейчас ввести операторы… А чего же нет? Так и сделаем.

А¤="A"

PRINT A¤

A

Вот видишь, с символьными переменными можно работать в непосредственном режиме. Это во-первых. А во-вторых, все получилось как надо: на экране появилось значение переменной А¤, то есть буква А, но, ясное дело, без кавычек. Попробуем еще.

А¤="ТОНЯ"

PRINT A¤

ТОНЯ

Следовательно, и вправду значение символьной переменной может быть строкой, а не только одним символом. В операторе вывода можно писать одновременно и числовые, и символьные переменные.

A=5

PRINT A¤

ТОНЯ

Теперь ты должна понимать: если буква А используется для имени переменной А¤, это не означает, что ее нельзя использовать в той же самой программе для имени переменной А. Это разные переменные. Совсем разные.


Строка символов может содержать только 255 символов


А скажи — почему между словом ТОНЯ и цифрой 5 такое большое расстояние?

— Ты что-то говорил о зонах.

— Именно так. Значения переменных А и А¤ выведены в разных зонах, так как в операторе PRINT между именами стояла запятая.

ЕДИНСТВЕННОЕ ДЕЙСТВИЕ С СИМВОЛАМИ
КОНКАТЕНАЦИЯ

В отличие от числовых переменных, для которых имеются целых четыре действия, с символьными переменными можно совершать только одно действие. Это единственное действие называется конкатенацией. Если это слово тебе трудно произнести, называй это действие сцеплением. А само действие очень простое: значения символьных переменных записываются друг за другом и результат становится значением другой символьной переменной. Обозначают это действие плюсом «+». Вот пример.

B¤="СООБРАЖАЛКИНА"

T¤=A¤+B¤.

PRINT T¤

ТОНЯСООБРАЖАЛКИНА

— Ха-ха! Трюк не получился.



Потихонечку-полегонечку и сцепим целую книгу


— Сейчас получится.

C¤=" "

PRINT B¤+C¤+A¤

СООБРАЖАЛКИНА ТОНЯ

Значением переменной CQ является особый символ — пробел. Правду сказать, в этом примере конкатенация особенно нужна не была — то же самое можно было сделать и без нее.

PRINT A¤;C¤;B¤

ТОНЯ СООБРАЖАЛКИНА

Но в других случаях это действие бывает очень полезным.

КАК СРАВНИВАЮТ СТРОКИ СИМВОЛОВ
Остается рассказать, как используют символьные переменные в операторе условного перехода. Условный переход может быть, например, таким:

40 IF А¤=«БОМ» THEN 500

В этом примере логическое условие считается выполненным и управление передается на строку 500, если значение переменной А¤ состоит ровно из трех букв, и притом именно БОМ.

— Для числовых переменных можно было определить, которое из них больше или меньше, а для символьных это бессмысленно, не так ли?

— Да. Для значений символьных переменных, действительно, не существует таких понятий, как «больше» или «меньше», можно только определить, которое из них будет первым при расположении в алфавитном порядке. Для такого дела приспособлены те же самые знаки: «<», «>», «=<», «=>».— Ничего не понять! Что там приспособлено?

— Допустим, мы выполнили операторы А¤ = «АНЯ» и В¤ = «ЯНА» и переменные А¤ и В¤ теперь имеют положенные значения. Тогда условие А¤<В¤ будет правильным, или, выражаясь точнее, истинным. А истинным это условие будет потому, что при расположении в алфавитном порядке слово АНЯ будет первым, а слово ЯНА вторым. Условие А¤>В¤ в этом случае не будет, истинным, зато В¤>А¤ опять будет.

И для символьных переменных можно написать подобный Бейсико-русский словарик, как для числовых переменных:



— Эти «первый» и «второй» пригодятся, если понадобится какие-то слова расставить в алфавитном порядке. И еще?

ПРОГРАММА УПОРЯДОЧЕНИЯ ДВУХ СЛОВ
— Думаю, что это все. Попробуй составить программу, которая два введенных в произвольном порядке слова вывела бы на экран в алфавитном порядке.




Я только собираю — обрабатывают другие


— Попробую… А как вводить символьные переменные?

— Тем же оператором INPUT. Запиши в нем, значения каких переменных ты хочешь ввести, и — вперед. Мы пока использовали оператор INPUT для ввода только одного значения переменной, но с таким же успехом можно вводить и несколько. Надо только написать имена всех вводимых переменных по порядку, отделяя друг от друга запятыми. Так что те два слова можешь ввести одним оператором INPUT S1¤, S2¤, где S1¤ — имя переменной для первого слова, а S2¤— для второго слова.

— Так сразу я этого не сделаю. Надо присесть и подумать.

Тоня села за стол и начала размышлять. Но размышляла она недолго.

— Знаешь, я поняла, как тут надо делать! Вот мое предложение.

10 PRINT «ПРОГРАММА РАССТАВИТ ДВА СЛОВА ПО АЛФАВИТУ»

20 PRINT «ВВЕДИТЕ ДВА СЛОВА»

30 INPUT S1¤, S2¤

40 IF S1¤ > S2¤ THEN 60

50 PRINT S1¤, S2¤

60 PRINT S2¤, S1¤

70 STOP

80 END

— Расскажи, что ты тут делаешь?

— Сначала сообщаю, что программа делает, потом прошу ввести два слова. Потом эти слова ввожу. В строке 40 их сравниваю, и если первое будет по алфавиту вторым, то ухожу на строку 60, где оба слова вывожу — второе перед первым. Но если при сравнении оказалось, что первое и по алфавиту первое, то в строке 50 вывожу их, так сказать, в порядке поступления…

— А потом? Что будет потом?

— Да, что будет потом?… Потом еще какой-то вывод.

— Точно, какой-то вывод.

— Ха! Я втисну еще одну строчку:

55 STOP

— Теперь все в порядке.

— Послушай, а как эти два слова во время работы ввести, и главное, как интерпретатор сможет их друг от друга отделить?

— Можно делать двояко. Первый способ: как только показался вопросительный знак, введи первое слово; сразу покажется еще один вопросительный знак, и тогда, конечно, введи второе слово. Больше вопросительных знаков не будет, разумеется, если все запрограммировано правильно. Второй способ: оба слова введи сразу, друг за другом, отделяя запятой.



— Мне все ясно. Я хочу вводить свою программу.

— Хорошо. Только не забудь дать директиву NEW, чтобы очистить память.

На сей раз Тоня вводила программу очень тщательно и даже просмотрела текст при помощи директивы LIST. Все выглядело правильно.

— Ну что, я пускаю!

RUNNH


ПРОГРАММА УПОРЯДОЧИВАЕТ 2 СЛОВА ПО АЛФАВИТУ

ВВЕДИТЕ ДВА СЛОВА

?ЯНА

?АНЯ

АНЯ

АНЯ ЯНА

STOP AN LINE 70

— Ур-р-р-ра! Программа работает!

— Почему ты так считаешь?

— Какие могут быть сомнения? Посмотри же, она все вывела правильно!

— Но ты же не знаешь, что будет, если слова ввести в правильном порядке.

— Зачем?! Что с ними может случиться?

— Все равно нужно проверить. Каждый оператор нужно проверить, и не только просматривая программу, но и в работе. Пускай, пускай еще раз.

— Раз уж ты хочешь…

RUNNH


ПРОГРАММА УПОРЯДОЧИВАЕТ 2 СЛОВА ПО АЛФАВИТУ

ВВЕДИТЕ ДВА СЛОВА

?АНЯ

?ЯНА

АНЯ ЯНА

STOP AN LINE 55

Ну, что я говорила! Все правильно.

16. РАБОТА СО СЛОВАМИ

— Чем ты порадуешь меня сегодня?

— Сегодня хорошо бы поработать с символьными переменными побольше.

— Фу! Они же очень неинтересны. И что там может быть интересного, если их можно только кон… конкан… Мне жутко понравилось это слово, и если бы еще его запомнить!

— Со значениями символьных переменных можно проделать конкатенацию.




— Вот я и говорю — их можно конкатенировать.

— Так никто не говорит.

— Как это никто, если я только что сказала?

— Ну ладно, пусть. Думаю, что конкатенацию приходится делать даже реже других действий.

— Ты же говорил, что других действий вообще нет.

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

— И какие?

КАК СТАТЬ ХОЗЯИНОМ СВОИХ СЛОВ
— Знаешь что! Придумай хоть одно действие со значениями символьных переменных. Каким действием тебе хотелось бы осчастливить человечество?

— Ты меня застал врасплох. Как в школе говорят, нам этого не задавали.

— Тогда, может быть, так. Что ты делаешь со словами, когда говоришь?

— Я их… произношу…

— Я надеялся, ты ответишь, я их склоняю — «слово», «слова», «слову» и так далее. Вот и получились действия со словом «слово».

— Непривычно… Действия со словами…

— Каким будет алгоритм склонения слова «слово»?

— Надо начинать с именительного падежа — «слово». Дальше — родительный. Заменяем окончание: вместо «-о» ставим «-а» — «слова». Так ведь?

— Не сомневался, что ты додумаешься. А теперь скажи: что это такое — заменить окончание? Какие действия требуются?

— Сперва отбрасываем старое окончание и затем добавляем новое.

— Согласен. И вот в Бейсике имеются действия со значениями символьных переменных, позволяющие запрограммировать замену окончаний и подобные мероприятия. Если ты поняла идею программирования, то догадаешься, что таких действий не будет много, но их хватит, чтобы сделать все нужное. Кстати, замена окончания совсем не простое дело. Надо знать, что такое окончание, надо уметь его найти и отделить. Главное, надо иметь алгоритм.

— А что-нибудь поконкретнее об этих действиях не можешь сказать?

— В Бейсике действия с символьными переменными проводят функции. Как они на самом деле работают, посмотрим на машине. Пока скажу только самое важное. Часто приходится из символьных строк выделять подстроку. Конечно, ты спросишь, что такое подстрока.

ПОДСТРОКА



— Может быть, часть строки?

— Да, но, так сказать, непрерывная часть строки. Например, строка СТРОКА имеет подстроки СТР, СТРО, РОК, ОК, А и еще кучу других. Но строка СОК не является подстрокой, хотя и состоит из символов первоначальной строки.

— Я бы сказала, что СОК это кон-ка-те-на-ция подстрок С и ОК.

— Действительно! Я об этом не думал.

— Вот так! Знай наших!

— Имеется функция, которая из строки символов вытаскивает подстроку, и другая функция, которая сообщает, где в данной строке можно найти другую строку. Например, если даны две строки СТРОКА и РОК, эта функция определит, начиная с какого символа вторая строка входит в первую. Какое число должно в этом случае получиться?

— СТРОКА и РОК? Думаю, что три.

— Так оно и будет.

— А если вторая строка вообще не входит в первую. Скажем, она не РОК, а СРОК?

— Тогда значение той функции будет нуль. На машине увидишь.

На машине первым делом Тоня вызвала интерпретатор Бейсика.

— Все в порядке. С какой функции начнем?

СКОЛЬКО СИМВОЛОВ В СТРОКЕ?
— Начнем с простейшей. О ней я пока ничего не говорил. Имя этой функции LEN, и она находит длину значения символьной переменной.

LEN, кстати, сокращение английского слова length — «ленгс» — «длина». Так как эта функция находит длину строки, то есть количество символов в строке, то эта строка должна быть ее аргументом. И вызывают эту функцию таким образом:

A=LEN(A¤)



Переменной А будет присвоено значение, равное длине значения переменной А¤ — количеству символов в нем.

— Прекратить разговоры. Машина ждет примера.

— Сперва посмотрим в непосредственном режиме.

A¤="СООБРАЖАЛКИНА"

A=LEN(A¤)

PRINT A

13

— Теперь я.

A¤="БЕЙСИКОВ"

PRINT A

13

О-хо-хо! Эта функция же не умеет считать!

— Минуточку! Три, пять, восемь. Что-то действительно не так. A-а! Переменной ты присвоила новое значение, а переменной А нет. Поэтому было выведено старое значение. В непосредственном режиме надо работать осторожно. Например, так:

A=LEN(A¤)

PRINT A

8

или так

PRINT LEN(A¤)

8

Сейчас все выводится как надо, а ты, не знаю, что подумала.

— Радуюсь, что не придется ничего менять в программировании.

ЧТО НАЙДЕШЬ В СИМВОЛЬНОЙ СТРОКЕ
— Теперь можем перейти к другой функции, имя которой POS, сокращение от position — «позишн», что означает «позиция». Эта функция находит местоположение подстроки. Таким вот образом:



A=POS(A¤,В¤,М)

Как видишь, она имеет целых три аргумента: первые два — символьные переменные, а третий — числовая. Работает эта функция так: берет значение первого аргумента, ищет в нем значение второго, но начинает поиск с символа, номер которого равен значению третьего аргумента. Значение функции будет равно номеру символа, с которого начинается значение второго аргумента в значении первого, либо нулю, если значение второго аргумента в значение первого не входит вообще. Посмотри работу этой функции на примере!

PRINT POS(A¤,"Ей",2)

2

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

— Таких функций у нас еще не было.

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

РАЗБИЕНИЕ НА ЧАСТИ СИМВОЛЬНОЙ СТРОКИ
Теперь о функции SEG¤. Как видишь, последний знак в ее имени — «солнышко». Значит, результатом работы функции будет символьная строка. Вот тебе и пример долгожданной функции, дающей в результате символьную строку. Возможно, что SEG — это сокращение английского слова segment, но точно этого никто не знает. Эта функция выделяет подстроку из значения первого аргумента, второй аргумент указывает, с какого символа это выделение начинать, а третий — на каком кончать. Вот пример для изучения:

X¤ = SEG¤(A¤,M,N)

Сейчас попробуем что-нибудь на машине.

A¤="СООБРАЖАЛКИНА"

PRINT "B"+SEG¤(A¤,2,13)

ВООБРАЖАЛКИНА

Ну, усекла, как из СООБРАЖАЛКИНА вышло ВООБРАЖАЛКИНА?

— Я тебя так усеку, что весь Бейсик забудешь!

— Посмотрим быстро одну из моих старых программ SIMBO. Она разделяет на отдельные буквы введенное слово.

OLD DL1:SIMBO

Выпечатай эту программу!




SAVE LP:


10 REM ПРОГРАММА РАЗДЕЛЯЕТ ВВЕДЕННУЮ СТРОКУ

20 REM НА ОТДЕЛЬНЫЕ СИМВОЛЫ

30 PRINT \ PRINT “ВВЕДИТЕ СТРОКУ СИМВОЛОВ"

40 INPUT А¤

50 N=LEN(A¤) \ REM находит длину строки

60 FOR I=1 ТО N

70 В¤=SЕG¤(A¤, I, I) \ REM ВЫДЕЛЯЕТ СИМВОЛ

80 PRINT I; "СИМВОЛ — "; B¤

90 NEXT I

100 STOP \ END

— Первые четыре строки я полностью понимаю, ведь не начинающая же! Труднее со строкой 50, но ты по доброте своей поясняешь, что здесь происходит: значение переменной станет равным количеству букв в слове. Потом начинается цикл. От единицы до N! Только что нашли этот N и уже суем границей цикла! Э-э-э! Цикл будет по всем буквам введенного слова, так ведь?

— А как же! Я же хочу все буквы отделить и вывести на экран!

— И отделяешь в строке 70. Это надо посмотреть подробно. Функция SEG¤ выделяет подстроку введенного слова начиная с 1-го символа и кончая тем же самым 1-м символом, то есть одну букву. Прекрасно! Далее выводишь… Сперва выводишь значение I или, что то же самое, номер буквы и хитрым образом добавляешь остальной текст и саму букву. Все это делается в цикле. Ничего сложного в этой программе нет! Запустим ее ради интереса.

RUNNH


ВВЕДИТЕ СТРОКУ СИМВОЛОВ

? СЛОВО

1 СИМВОЛ — С

2 СИМВОЛ — Л

3 СИМВОЛ — О

4 СИМВОЛ — В

5 СИМВОЛ — О


STOP AN LINE 100



Жаловаться не могу. Работает правильно.

Слушай, а введенное число ты на цифры разделить можешь?

— Программа работает с символами. С сим-во-ла-ми! И ей совершенно все равно, какую строку символов ты введешь. Введешь строку «123» — программа разделит ее на символы без задержки. Не сомневайся. Ты же видишь, что А¤ — символьная переменная.

СВЯЗЬ МЕЖДУ ЧИСЛАМИ И СИМВОЛАМИ
Задаю вопрос на засыпку. Выполняется такой оператор:

Т¤ = «1»+«2»

Каково будет значение переменной Т¤?

— Ты, может быть, думал, что я скажу «три»? Ничего подобного. Значением переменной Т¤ будет двенадцать.

— Неточно! Значением переменной будет символьная строка «12», что нужно читать скорее — «один, два». Символьные строки «12» или там «1234» — это никакие не числа, с ними арифметические действия проводить нельзя. Но если надо, такие строки можно в числа превратить. Для этого нужна функция VAL, имя которой получено сокращением слова value — «вэлью», по-русски — «значение». Ее можно назвать функцией расчета числового значения символьной строки. Вот пример ее использования:

К=VАL(В¤)

Значение символьной переменной В¤ будет превращено в число, и это число станет значением переменной К. Понятно, что значением В¤ должна быть такая строка, которую в число превратить можно. Например, строки «123», «6789», «3.1414», «0.68Е—06» можно превратить в числа, а строку «ТОНЯ» нет, это такая неполноценная строка.


Вводим символы, работаем с числами, выводим символы


— Ты особенно не выступай! Функция полезная, слов нет, а мы говорили о том, как найти цифры заданного числа.

— Раз уж ты жить не можешь без этих цифр, то запомни функцию STR¤, которая работает противоположно функции VAL. Она превращает число в строку символов. Полностью STR пишется string, произносится как пишется и означает — «символьная строка», но только в программировании, в поэзии это означает «струна». Эта функция получается как бы обратной к VAL.

A¤ = STR¤(X)

— Ясно. Значение переменной X она превращает в символьную строку и объявляет значением А¤.

— Да, и превращает число совершенно так же, как при выводе, то есть может превратить в экспоненциальную форму, если надо. Можно сказать, что она выпечатывает значение X в значении А¤. Может быть, нелишне добавить, что вместо X может быть арифметическое выражение.

— Не надо добавлять. Будет лишне.

КАЛЕНДАРЬ В КОМПЬЮТЕРЕ
— А вот еще две функции, значения которых символьные переменные, а аргументов вообще нет. Первая функция СLK¤ выдает текущее время по часам, а вторая DАТ¤ — сегодняшнее число. Сначала о числе. Проще всего его узнать так:

PRINT DAT¤

12-FEB-87

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

— А мне лучше нравится, когда вместо названия месяца стоит его номер: 12-02-87.

— Госстандарт предусматривает вот такую форму записи числа: 87 02 1 2. А хочешь другую, составь программу, превращающую число с формы Бейсика в твою форму.

— А как это сделать?

— Во-первых, надо из DAT¤ выделить название месяца.

— Ага! Функцией… забыла название.

— Функцией SEG¤.

— Хорошо. Посмотри, что у меня получится.

— Чуть потерпи. Введем директиву NEW, чтобы очистилась память.

Теперь можешь вводить свою программу.

— Программы пока нет, есть только одна строчка.

10 A¤=SEG¤(DAT¤,4,6)



Будет правильно?

— Кажется, да. Сейчас надо по названию найти номер месяца в году. Для этого я предлагаю ввести такую переменную:

20 B¤="JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"

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

— Нет! Я скорее поняла бы, если бы ты ввел массив с сокращением месяцев.



— Можно было бы и так. Сделать цикл сравнений всех элементов этого массива со значением А¤. Но с этой переменной будет короче. Мы должны, используя функцию POS, определить, где в значении В¤ начинается значение переменной А¤ — с первой, четвертой, седьмой или другой позиции.

— Ну… Я начинаю догадываться о твоей идее. Но только догадываться.

— Тогда давай запиши обращение к этой функции.

30 N=POS(B¤,A¤,1)



— Последний аргумент у меня 1, потому что проверку совпадения надо начинать с первого символа в значении В¤.

— Думаю, все в порядке. Но точно это узнаем, когда запустим программу. Сейчас напиши, как по числу N определить номер месяца.

— Ой, такие задачи для меня всегда были трудными. Здесь надо… Нет, не так. Выразим N через номер месяца I.

N=3(I-1)+1=3I—2

А сейчас, наоборот, выражаю I через N.

N=(l+2)/3

Проверим эту формулу: если N=1, то I = 1. Берем N=4, I = 2. Правильно! Можем вводить в память:

40 I=(N+2)/3

Теперь название месяца в значении А¤ надо заменить значением I.

— Ничего подобного. Значение I надо превратить в символьную строку, и только эту строку можно подставлять в значение А¤. При этом функция STR¤ здесь малопригодна, так как она из единицы делает символ «1», из двойки — «2», а из двенадцати, естественно, «12». А нам нужно так, чтобы получаемые символьные строки всегда состояли ровно из двух символов — не «1» или «2», а «01» или «02».

— Так, конечно, было бы красивее. А как туда этот нуль запихнуть?

— Подобное мы только что делали. Введем еще одну переменную.

60 J=2*I-1

7 °C1¤=SEG¤(C¤,J,J+1)

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

— Получаем задачу, обратную задаче поиска номера месяца. Как-нибудь уж справлюсь.

5 °C¤="010203040506070809101111"

А сейчас бы сделать новую форму сегодняшнего числа.

80 D¤=SEG¤(DAT¤,1,3)+C1¤+SEG¤(DAT¤,7,9)

90 PRINT D¤

100 END

— Посмотрим, что получилось.

RUNNH

12-02-87

— Ур-р-р-ра! Работает как часы!

ЧАСЫ В КОМПЬЮТЕРЕ
— Теперь функция CLK¤. Она выдает время по часам в форме… Нет, лучше посмотрим!

PRINT CLK¤

17:21:26

Сначала часы, двоеточие, минуты, опять двоеточие и, наконец, секунды. Иногда программисту надо знать, сколько секунд прошло с начала суток.

— А зачем?

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

— Рассчитать, сколько секунд прошло с начала суток, сущая мелочь. Я это берусь сделать.



— Раз берешься, сделай.

— Из символьной строки, которую выдает функция СLК¤, нужно выделить количество часов и умножить его на 3600, потом так же выделить минуты и умножить на 60. И наконец, выделить секунды и сложить с обоими этими числами.

— А как это будет выглядеть в программе?

Продолжай эту же самую программу для переделки формы даты.

— Тогда смотри.

100 A1=VAL(SEG¤(CLK¤,1,2))

Подсчитываем количество часов. Видел, как ловко я воспользовалась функцией VAL для превращения символьной строки в число?!

— Видел. Это и в самом деле было ловко. Твердо различать символьные и числовые переменные не так уж и легко.

— Дальше.

110 A2=VAL(SEG¤(CLK¤,4,5))

120 A3=VAL(SEG¤(CLK¤,7,8)

130 A=A1*3600+A2*60+A3

140 PRINT CLK¤,A

Так будет хорошо?

— Меня не спрашивай. Спрашивай машину.

RUNNH


12-02-87

17:30:40 63040

— Машина говорит, что такую прекрасную программу она давно не видела.

ФУНКЦИИ ПРОГРАММИСТА — САМОДЕЛЬНЫЙ ИНСТРУМЕНТ
— Это хорошо. Я сейчас подумал, что проще было бы с использованием функций программиста. Для своих нужд программист может определить функции таким образом. Сначала пишет DEF, что является сокращением английского слова define, которое произносится «дифайн»…


Присваиваю тебе звание функции программиста


— … и совершенно точно означает «определять».

— После DEF пишут FN и какую-нибудь букву, например М. Цифру нельзя. Получается обозначение, или имя, функции. После него в скобках аргумент, причем аргумент должен обязательно быть. А за знаком равенства и само выражение функции. Это об определении функций. Сейчас об их использовании.

— Подожди, подожди. Я еще не поняла определения. Напиши-ка какой-нибудь пример!

— Пожалуйста. Пишу уже для нужд нашей программы.

5 DEF FNA¤(X,Y)-VAL(SEG¤(CLK¤,X,Y))

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

6 DEF FNP(I)=FNA(1,2)*3600|FNA(4,5)*60+FNA(7,8)

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

И еще одна строка в конце программы.

150 PRINT FNP(I)

Выпечатается значение FNP, конечно, совершенно независимо от значения лишнего аргумента I. То есть количество секунд с начала суток.

— Ладно. Проверим сейчас твои премудрости запуском программы.

RUNNH


12-02-87

16:46:12 63792

63793

Интересно, почему твое количество секунд отличается от моего?

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

— Вообще-то и действительно нужно. При нахождении отрезка времени по крайней мере два раза.

— Что верно, то верно. А сейчас сделаем так. Ты составляешь программу, которая склоняет русские имена существительные первого склонения, кончающиеся на «-а». А я в это время позанимаюсь своими программами.

17. МАШИНА ОСВАИВАЕТ РУССКИЙ ЯЗЫК

Полученной задачей Тоня занималась довольно долго. Даже рисование блок-схемы заняло много времени, потому что у Тони появились кое-какие соображения относительно родительного падежа.



ПРОГРАММИРОВАТЬ НАДО УМЕЮЧИ


Программа должна была выводить родительный падеж с окончанием «-ы», за исключением слов с предпоследней буквой к, г, ш,щ, х или ж, когда надо «-и». Но запрограммировать это…

— Такую программу составить… Это же настоящая мыслящая машина получится.

Петя ничего не ответил. Отдав машину в распоряжение Тони, он умчался консультироваться по своим делам. Тоня начала вводить составленную программу, но, увы, допустила ошибки. Программа со всеми ошибками выглядела так:

10 REM ПРОГРАММА СКЛОНЯЕТ ИМЕНА СУЩЕСТВИТЕЛЬНЫЕ

15 РЕM ПЕРВОГО СКЛОНЕНИЯ С ОКОНЧАНИЕМ — А

20 PRINT \ PRINT \ PRINT \ PRINT

30 PRINT "ВВЕДИТЕ ИМЯ СУЩЕСТВИТЕЛЬНОЕ ПЕРВОГО"

40 PRINT "СКЛОНЕНИЯ НА — А ИЛИ СЛОВО КОНЕЦ,"

50 PRINT "ЕСЛИ КОНЧАЕТЕ"

60 INPUT S¤

70 IF S¤<>"КОНЕЦ" THHEN 90

80 PRINT "КОНЕЦ" \ SТОР

90 REM ПРОВЕРКА ПРАВИЛЬНОСТИ ВВОДА

100 D=LEN(S¤)

11 °C¤=SEG¤(S¤,D,D) \ \ REM ПОСЛЕДНЯЯ БУКВА

120 IF С¤="А" THEN 140

130 PRINT "ЭТО СЛОВО НЕ КОНЧАЕТСЯ НА — А" \ SТОР

14 °C1¤=SEG¤(S¤, D-1, D-1) \ \ REM ПРЕДПОСЛЕДНЯЯ БУКВА

190 P¤="ы" \ GO TO 210

200 P¤="и"

210 Z¤=SEG¤(S¤,1,D-1) \ \ REM СЛОВО БЕЗ ОКОНЧАНИЯ

230 PRINT

240 PRINT "ИМЕНИТЕЛЬНЫЙ КТО? ЧТО?"; S¤

250 PRINT "РОДИТЕЛЬНЫЙ КОГО? ЧЕГО?";Z¤+P¤

260 PRINT "ДАТЕЛЬНЫЙ КОМУ? ЧЕМУ?";Z¤+"E"

270 PRINT "ВИНИТЕЛЬНЫЙ КОГО? ЧТО?";Z¤+"y"

280 PRINT "ТВОРИТЕЛЬНЫЙ КЕМ? НЕМ? "Z¤х+"0й"

290 PRINT "ПРЕДЛОЖНЫЙ О КОМ? О ЧЕМ?";"О "+Z¤+"E"

300 PRINT \ PRINT

310 GO ТО 30

320 END

Тоня решилась и запустить программу самостоятельно, без Пети. Было боязно, но очень хотелось узнать, что же получилось.

RUNNH


ВВЕДИТЕ ИМЯ СУЩЕСТВИТЕЛЬНО ПЕРВОГО

СКЛОНЕНИЯ НА — А ИЛИ СЛОВО: КОНЕЦ,

ЕСЛИ КОНЧАЕТЕ

? ПАПА


?SYNTAX ERROR AT LINE 70

— Что же это такое? Строка 70… Синтаксическая ошибка? Посмотрим.

LISTNH 70

70 IS S¤<>"КОНЕЦ" THHEN 90

Так… Все ясно. THEN введен с двумя Н. Это не моя вина, клавиша часто выдает два знака. Сейчас надо исправлять.

70 IS S¤<>"КОНЕЦ" THEN 90

Запустим еще раз.

ВВЕДИТЕ ИМЯ СУЩЕСТВИТЕЛЬНО ПЕРВОГО

СКЛОНЕНИЯ НА — А ИЛИ СЛОВО: КОНЕЦ,

ЕСЛИ КОНЧАЕТЕ

? ПАПА

ЭТО СЛОВО НЕ КОНЧАЕТСЯ НА — А


?SYNTAX ERROR AT LINE 130

Какая чушь! Как же не кончается, когда кончается! Кончается «мама» на «-а» и бесспорно является самым натуральным именем существительным первого склонения. Наверно, машина испортилась.

ОШИБКА ИЛИ СБОЙ МАШИНЫ?
Тоня решила подождать Петю.

— Куда ты исчез? Болтаешься где-то, а за это время машина испортилась. Совсем не то выдает.

— Почему ты так считаешь?

— Смотри сюда! Вывела, что «мама» не кончается на «-а». Представляешь!

— Запомни на всю жизнь. Машина портится намного реже, чем ошибается программист. Давай искать ошибку. Программа ушла по неправильной ветке — значит, первое, что можно заподозрить, это операторы перехода. Как ты проверяешь, что введенное слово кончается на «-а»?

— Это я проверяю в строке 120.

— Смотрим эту строку.

LISTNH 120


120 IF C¤="A" THEN 140

Ничего плохого тут нет. Раз оператор перехода правильный, то должно быть неправильным значение переменной C¤. Сейчас мы увидим, что оно не «А».

PRINT C¤

A

— Получил, провидец! Машина отдала концы, чего там рассуждать!

— Ничего не понимаю… Больше-то и смотреть нечего… A-а! Вот что будет. Дело в том, что интерпретатор отлично различает русские илатинские буквы одинакового начертания — А, М, Т, О или другие. И если ты в строке 120 в кавычках вписала не русскую А, а совершенно с нею совпадающую при изображении на экране латинскую А, то все. С русской А она совпасть не сможет.



— Я этого не знала!

— Не знала, так не знала. Впредь будешь знать. Исправляем, посмотрим, что это даст.

120 IF C="A" THEN 140

Сейчас запускай.

ВВЕДИТЕ ИМЯ СУЩЕСТВИТЕЛЬНО ПЕРВОГО

СКЛОНЕНИЯ НА — А ИЛИ СЛОВО: КОНЕЦ,

ЕСЛИ КОНЧАЕТЕ

? ПАПА


ИМЕНИТЕЛЬНЫЙ КТО? ЧТО? ПАПА

РОДИТЕЛЬНЫЙ КОГО? ЧЕГО? ПАПЫ

ДАТЕЛЬНЫЙ КОМУ? ЧЕМУ? ПАПЕ

ВИНИТЕЛЬНЫЙ КОГО? ЧТО? ПАПУ

ТВОРИТЕЛЬНЫЙ КЕМ? ЧЕМ? ПАПОЙ

ПРЕДЛОЖНЫЙ О КОМ? О ЧЕМ? О ПАПЕ


ВВЕДИТЕ ИМЯ СУЩЕСТВИТЕЛЬНОЕ ПЕРВОГО

СКЛОНЕНИЯ НА — А ИЛИ СЛОВО: КОНЕЦ,

ЕСЛИ КОНЧАЕТЕ

? КОНЕЦ

КОНЕЦ


STOP AT LINE 80

— Уф-ф. Теперь-то все правильно. Надо записать программу на диск.



— Что записала программу на диск, хвалю. Но что считаешь все правильным, показывает только твое…

— Что, что показывает?!

ГОРЬКАЯ ПРАВДА, А НЕ МОРАЛЬ
— Ладно, пусть остается секретом. Я как-то говорил, что программист должен быть уверен, что его программа работает правильно. Но чем опытнее программист, тем меньше у него такой уверенности. Ты еще не знаешь, что вначале программы долгое время не работают и почти все рабочее время программист тратит на исправление ошибок — отладку программы. Это дело надо полюбить, если желаешь программировать. А поиск ошибок вовсе не такое скучное занятие, как кажется сначала. Здесь нужна железная логика и, конечно, хорошее знание работы машины, того, как ведет себя интерпретатор в каждой ситуации. К сожалению, поиск ошибки всегда кончается ударом по самолюбию — как ты смог так глупо ошибиться!

ОТЛАДКА

— Да, откровенно говоря, такие удары случаются.

— Ну вот! Умнеешь на глазах. Возвращаясь к твоей программе, надо сказать, что ее отладка только началась. Программа правильно сработала со словом «мама».

— Со словом «папа» она тоже правильно сработает!




Как пройти все пути в программе?



— Не спорю. Сработает правильно. Но программист должен быть уверен, что его программа сработает правильно с любыми входными данными. Не думай, что я тебе предлагаю проверить программу на всех именах существительных первого склонения, какие только есть в русском языке. Я предлагаю провести проверку программы — тестирование таким образом, чтобы заставить сработать все операторы ветвления как на выполнение логического условия, так и на невыполнение. Другими словами, я хочу пропустить программу с такими входными данными, или тестами, чтобы она прошла по всем возможным путям.

— По всем возможным путям? А говоришь только об операторе ветвления. Разве оператор вычисляемого перехода ON не надо учитывать при рассмотрении этих путей?

— Ах да! Про него я забыл. Он, конечно, тоже создает ветвление в программе. Подай, пожалуйста, программу с блок-схемой и посмотрим теперь, какие слова надо программе задавать, чтобы все логические операторы сработали как на выполнение, так и на невыполнение логического условия.

ПЕРЕД ТЕСТИРОВАНИЕМ ПОЛЕЗНО ПОДУМАТЬ
— Я, пожалуй, здесь не все еще понимаю, но разве пуск программы со словом «мама» не считается?

— Считается, считается. Это пример на стандартное слово с окончанием родительного падежа «-ы». Нам нужно подобрать слова, родительный падеж которых оканчивается на «-и», и притом должны быть учтены все возможности — все возможные здесь предпоследние буквы. Найди слово, оканчивающееся на «ка».

— Это я могу. «Рука».

— А сейчас слово, оканчивающееся на «га», чтобы проверить уход при выполнении условия в строке 160. Заодно будет проверено, пропускает ли оператор ветвления в строке 155, если предпоследняя буква не «к».

— «Нога».

— И дальше?

— «Каша», «теща», «муха» и «рожа».

— Итак, для тестирования нам надо пропустить программу со словами «мама», «рука», «нога», «каша», «теща», «муха», «рожа» и с каким-нибудь непригодным словом, например «слово», чтобы проверить, остановится ли программа, если ввести что-то неподходящее. Да, и еще одно слово.

— Какое же? Больше не должно быть.

— А окончание работы программы? Правильно ли она ответит на слово «конец»?

— Нет сомнений. Мы уже ей это слово давали.

— Да, действительно. Но все равно в списке для тестирования это слово должно быть.

— Должно быть. Должно. Давай введем все эти слова, чтобы ты успокоился и мы могли двинуться дальше.



Ошибки отыскиваются тестами


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

— Будь аккуратной, приучайся к порядку. Без конца мне это твердят и твердят.

Однако все слова ребята проверили и действительно никаких ошибок не обнаружили.

ЯЗЫКИ И ПРОГРАММИРОВАНИЕ
— Ошибок нет, но это не означает, что программу нельзя улучшить. Сразу видно, что программа стала бы короче, если воспользоваться оператором ON. Сначала нужно ввести символьную переменную, содержащую все выделенные согласные: Т" = «КГШЩЖЧХ». И после того как найдена предпоследняя буква введенного слова, следует искать ее в значении переменной Т" при помощи функции POS. Равенство значения этой функции нулю означает, что в родительном падеже надо использовать окончание «-ы». Тогда не понадобятся эти сравнения в строках 150–180.

Еще надо сказать, что программа ведь не охватывает все первое склонение. Есть еще слова, оканчивающиеся на «-я». Главное, программу легко изменить, чтобы учесть и этот случай. После строки сравнения последней буквы слова на совпадение с «-а» ставим строку сравнения с «-я», и если оказалось, что слово действительно кончается на «-я», переходим на строку 200 с присвоением переменной РД значения «И», потому что в этом случае слово в родительном падеже всегда оканчивается на «-и». И все.

— Так уж и все? А винительный падеж от «земля», что вижу? «Землю», а вовсе не «землу».

— Да, верно. Придется иметь еще одну символьную переменную наподобие РД, в которую засылать либо «у», либо «ю» в зависимости от того, какой буквой оканчивается слово.

— И это еще не все! В творительном падеже тоже другое окончание — «-ей», а не «-ой», и так просто получается только тогда, когда мы в этом окончании не пишем букву «ё», как надо было бы, скажем, в слове «землёй» или «судьёй». А слова на «-ия»?! У них ведь в дательном и творительном падеже окончание не «-е», а «-и». Плохо знаешь грамматику родного языка, Бейсиков!




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

— Это-то я сумею. А как быть со словами, о которых я только что вспомнила? Существительные среднего рода, оканчивающиеся на «мя»— время, знамя, имя и так далее.

— Они относятся, кажется, к третьему склонению.

— Да, к третьему. Но вот, представь себе, приходит какой-нибудь шутник и вводит в программу вместо слова первого склонения слово «знамя», и мы начинаем его склонять — «знамя», «знами», «знаме», «знаму»… Представляешь, сколько смеху это вызвало бы? И ничего не сделаешь.

— Почему же нет. Можно проверять не одну, а две последние буквы — «мя» они или не «мя»? Нужно все эти слова запомнить в особом символьном массиве и введенное слово со всеми сравнивать — не совпадет ли.

— Все запомнить! И все сравнить! Это же страшная работа!

— Так уж оно получилось. Когда древние славяне создавали русский язык, то совершенно опрометчиво не учли потребности своей «потомочки» Тони, которая захочет заняться программированием. Слов на «мя» раз-два и обчелся, а что ты сказала бы, если бы понадобилось различить такие существительные, как «день» и «ночь», которые оканчиваются на «ь» и относятся к разным склонениям и родам. Опять другого выхода нет, и приходится все их запоминать в массивах, которые на сей раз получились бы куда больше.



— Жуть! Что и говорить.

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

— Слушай! Что я подумала! А одушевленные и неодушевленные существительные во втором склонении? Как же их различить? Опять все запоминать?

— Можно у пользователя спрашивать — одушевленное это существительное или нет, а если по-честному, то надо запоминать. Многое пришлось бы запоминать, если хочешь сделать программу, склоняющую все имена существительные. Ведь мы же ничего не говорили о склонении во множественном числе. Один только именительный падеж множественного числа чего стоит. Например: сук — сучья, котенок — котята. Так что на быстрый успех не рассчитывай. Лучше подумай о том, как твою программу переделать в обучающую, чтобы она проверяла, как ученики усвоили склонение существительных первого склонения.

— Да? А как сделать, чтобы… ну, чтобы нельзя было заранее знать, какое слово машина будет, например, давать склонять.

— Опять нужно использовать символьные массивы. Ничего не поделаешь, придется в следующий раз о них поговорить.

18. ЕЩЁ О ТОМ, КАК КОМПЬЮТЕР УЧИТ ДЕТЕИ

В следующий раз, как и договорились, Тоня и Петя изучали обучающую программу, которая использует символьные массивы.

— Эта программа изучает с детьми столицы союзных республик. Думаю, ты еще помнишь те времена, когда их зубрила.

— Помню даже время, когда я зубрила названия самих союзных республик.

УЧИМ ГЕОГРАФИЮ!
— Названия республик пользователь программы, пожалуй, должен знать. А что касается программы, то в ней предусмотрены четыре режима. В первом режиме на экран выводятся все республики и их столицы. Этим можно пользоваться в самом начале обучения, когда ребенок еще мало что знает. По-настоящему программа обучает во втором режиме — режиме повторения, когда ученик должен назвать столицу по республике или, наоборот, — республику по столице. Третий режим — экзамен.

— Ну как же без экзаменов!

— А как иначе человек сможет узнать, что все освоил? Последний режим — окончание работы. Простой режим. А вот и сама программа.

10 REM ПРОГРАММА ОБУЧАЕТ СТОЛИЦАМ СОЮЗНЫХ РЕСПУБЛИК

20 REM R¤ — МАССИВ С НАЗВАНИЯМИ РЕСПУБЛИК

30 REM G¤ — МАССИВ С НАЗВАНИЯМИ СТОЛИЦ

40 DIM R¤(15), S¤(15)

50 REM ПРОГРАММА МОЖЕТ ЗАПРАШИВАТЬ РЕСПУБЛИКУ ДЛЯ

60 REM ИЗВЕСТНОЙ СТОЛИЦЫ ИЛИ НАОБОРОТ

70 REM U1 — ВЕРОЯТНОСТЬ, ЧТО БУДЕТ СПРАШИВАТЬ СТОЛИЦУ

80 REM СООТВЕТСТВУЮЩЕЙ РЕСПУБЛИКИ

100 DIM Е(15) \ \ U1=.5

110 REM U1 УЧИТЕЛЬ МОЖЕТ МЕНЯТЬ

120 \

130 DATA "РОССИй","МОСКВА","УКРАИН","КИЕВ”

140 DATA "БЕЛОРУС","МИНСК","КАЗАХ","АЛМА-АТА"

150 DATA "МОЛДАВ","КИШИНЕВ","ГРУЗИН","ТБИЛИСИ"

160 DATA "АРМЯН","ЕРЕВАН","АЗЕРБАйДЖАН","БАКУ"

170 DATA "ЛАТВИй","РИГА","ЛИТОВ","ВИЛЬНЮС"

180 DATA "ЭСТОН","ТАЛЛИН","УЗБЕК","ТАШКЕНТ"

190 DATА "ТАДЖИК","ДУШАНБЕ","ТУРКМЕН","АШХАБАД"

200 DATA "КИРГИЗ","ФРУНЗЕ"

205 \

210 REM СЧИТЫВАЕТ НАЗВАНИЯ СТОЛИЦ И РЕСПУБЛИК

220 FOR 1=1 ТО 15 \ READ R¤(I),S¤(I)

250 NEXT I

255 \

260 PRINT \ PRINT \ PRINT \ PRINT

270 PRINT "жжжжжжжжжжжжжжжжжжжжж СЕЙЧАС БУДЕМ УЧИТЬ"

280 PRINT " СТОЛИЦЫ СОЮЗНЫХ РЕСПУБЛИК жжжжжжжжжжжжжжжж"

290 PRINT \ PRINT \ PRINT

300 PRINT "ВВЕДИ 1 — СПРАВКА О СТОЛИЦАХ"

310 PRINT "ВВЕДИ 2 — ПОВТОРЕНИЕ ПРОЙДЕННОГО"

320 PRINT "ВВЕДИ 3 — ЭКЗАМЕН"

330 PRINT "ВВЕДИ 4 — КОНЕЦ РАБОТЫ"

340 PRINT "ТВОЙ ВЫБОР"; \ INPUT М

345 \

350 ON М GО ТО 360,450,780,990

355 \

360 REM ПОКАЗ 111111111111111111111111111111111111111111

365 \

370 PRINT \ PRINT

380 PRINT "В СОВЕТСКОМ СОЮЗЕ ИМЕЕТСЯ 15 СОЮЗНЫХ":

390 PRINT " РЕСПУБЛИК" \ PRINT

400 FOR I=1 ТО 15

405 А¤=«ССР" \ IF I<>1 THEN 410 \ А¤=" СФСР"

410 PRINT I;" ";R¤(I) + "CKAЯ"+A¤+" ЕЕ СТОЛИЦА";S¤(I)

420 NEXT I

430 GO TO 290

435 \

440 REM ПОВТОРЕНИЕ 2222222222222222222222222222222222222

445 \

450 PRINT \ PRINT \ PRINT

460 PRINT "ПОВТОРИМ СТОЛИЦЫ СОЮЗНЫХ РЕСПУБЛИК"

470 PRINT

480 PRINT "КОГДА ТЕБЕ НАДОЕСТ, ВВЕДИ #"

530 J=0 \ К=0 \ REM КОЛИЧЕСТВА ВОПРОСОВ И ОШИБОК

540 \

550 REM НАЧАЛО ПОВТОРЕНИЯ

560 R=RND

570 IF R>U1 THEN 670

580 REM ДАЕТСЯ СТОЛИЦА, НАЗВАТЬ РЕСПУБЛИКУ —---

590 PRINT "КАКАЯ РЕСПУБЛИКА ИМЕЕТ СТОЛИЦУ

600 GOSUB 1000 \ \ REM НАХОДИТ НОМЕР РЕСПУБЛИКИ

610 PRINT S¤(I);

620 INPUT R`¤ \ \ REM ВВОД ОТВЕТА — НАЗВАНИЯ РЕСПУБЛИКИ

630 IF R1¤="#" THEN 750 \ REM МОЖЕТ БЫТЬ, НАДОЕЛО?

635 A¤=" ССР" x IF I<>1 THEN 640 \ A¤=" СФСР"

640 N¤=R¤(I)+"СКАЯ"+А¤ \ REM ПОДГОТОВКА N¤ ДЛЯ ПОДПРОГ.

650 GOSUB 2000 \ \ REM ПРОВЕРКА ОТВЕТА

660 GO TO 560

665 \

670 REM ДАЕТСЯ РЕСПУБЛИКА, НАЗВАТЬ СТОЛИЦУ —---

680 GOSUB 1000

685 А¤=" ССР" \ IF I<>1 THEN 690 \ A¤=" СФСР"

690 PRINT "НАЗОВИ СТОЛИЦУ";R¤(I)+"СКОй"+А¤;

700 INPUT R1¤

710 IF R1¤="#" THEN 750

720 N¤=S¤(I)

730 GOSUB 2000

740 GO TO 560

750 PRINT "ВСЕГО ОТВЕТОВ, ИЗ НИХ

755 PRINT J-K;" ПРАВИЛЬНЫХ"

760 GO TO 290

765 \

770 REM ЭКЗАМЕН 333333333333333333333333333333333333333.

775 \

780 PRINT \ PRINT \ PRINT

790 PRINT " НАЧНЕМ ЭКЗАМЕН"

800 REM В МАССИВЕ E ОТМЕЧАЕТ РЕСПУБЛИКИ, ПО КОТОРЫМ

802 REM ОТВЕТ УЖЕ ПОЛУЧЕН

810 FOR 1=1 ТО 15 \ E(I)=0 \ NEXT I

820 0=0 \ К=0

830 N=INT(RND*15)+1

840 IF E(N)<>0 THEN 830

845 А¤="СКОй ССР" \ IF I<>1 THEN 850 \ А¤="СКОй СФСР"

850 PRINT "НАЗОВИ СТОЛИЦУ "R¤(N)+A¤;

860 INPUT S1¤

870 IF S1¤<>S¤(N) THEN 890

880 PRINT "ОТВЕТ ВЕРНЫЙ" \ GO TO 900

890 PRINT "ОТВЕТ НЕВЕРНЫЙ" \ K=K+1

900 J=J+1 x E(N)=1 \ REM ОТМЕЧАЕТ РЕСПУБЛИКУ

910 IF J<15 THEN 830 \ PRINT

920 IF K<>0 THEN 940

930 PRINT "ОЦЕНКА — ОТЛИЧНО (5)" \ GO TO 290

940 IF K<>I THEN 960

950 PRINT "ОЦЕНКА — УДОВЛЕТВОРИТЕЛЬНО (3)" \ GO TO 290

960 PRINT "НУЖНО ПОВТОРИТЬ — ТЫ ДОПУСТИЛ"; К;

965 IF К<5 THEN 980

970 PRINT " ОШИБОК" \ GO ТО 290

980 PRINT " ОШИБКИ" \ GO ТО 290

985 \

990 PRINT "жжжжжжжж КОНЕЦ РАБОТЫ жжжжжжжжж" \ STOP

995 \

1000 REM ПОДПРОГРАММА НАХОДИТ СЛУЧАЙНЫЕ НОМЕРА

1010 I=INT(RND*15)+1

1040 IF 1=9 THEN 1010 \ REM РИГУ ЗНАЮТ ВСЕ

1060 RETURN

1900 \

2000 REM ПОДПРОГРАММА ПОВТОРЯЕТ ОТВЕТЫ

2010 IF R1¤<>N¤ THEN 2030

2020 PRINT "ОТВЕТ ВЕРНЫЙ" \ GO ТО 2060

2030 PRINT "НЕПРАВИЛЬНО!!! ПРАВИЛЬНЫЙ ОТВЕТ"; N¤ \ К=К+1

2060 J=J+1 \ RETURN

2070 END

— Ужас, какая программища! Такую длинную программу придется сутки разбирать.



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

— Начало уже поняла. До строки 70. Там ты пишешь о какой-то вероятности.

— Видишь, программа в режиме повторения может задавать вопросы двух типов. Например: Кишинев — столица какой республики? Либо — назови столицу Молдавской ССР. Ответы ты знаешь. Вопросы этих двух типов чередуются случайным образом. И значение переменной D1 определяет, какого типа вопросы будут чаще. В строке 100 учитель может значение D1 менять. Если он, например, хочет, чтобы ученик называл только столицы, то должен присвоить переменной D1 значение 0. Или другое какое-то значение.

— А здесь в строке 130 и дальше, что это за необыкновенный оператор DATA? Если это оператор.

ХРАНЕНИЕ ДАННЫХ В ПРОГРАММЕ
— Это действительно оператор. Оператор хранения данных. «Дейта» означает «данные». Этот оператор только хранит данные. И все. Интерпретатор, встретив такой оператор в программе, перескочит его. В значения переменных данные переносятся другим оператором — READ.

— «Рид» — это «читать». Выходит, что это оператор чтения…

— Или считывания. Из хранилища в операторах DATA он считывает данные в значения переменных. В программе оператор READ появляется в строке 220, где начинается цикл от 1 до 15, то есть по всем республикам. В этом цикле считываются все названия республик и их столиц.


Кто пришел за данными ко мне?


Само чтение происходит так. Проходя цикл первый раз, когда 1 = 1, интерпретатор, натолкнувшись на оператор READ с элементами символьных массивов R¤(I) и S¤(I) — сейчас R¤(1) и S¤(1), начинает искать, где в программе встречается оператор DATA. Находит, что в первый раз в строке 130 и что первые две символьные строки, там хранящиеся, это «РОССИИ» и «МОСКВА». Они и становятся значениями элементов R¤(1) и S¤(1). Можешь сказать, как узнать, где в операторе DATA кончается одна символьная строка и начинается другая?

— Они же отделены запятыми!

— Ну да. Если нужно было бы считывать значения не символьных переменных, а числовых, то никаких существенных изменений не произошло бы. Их записали бы таким же образом, отделяя запятыми. Проходя цикл второй раз, свои значения получают элементы R¤(2) и S¤(2). Оператор READ их считывает из хранилища по порядку. Так что на сей раз это будет «БЕЛОРУС» и «МИНСК». И так до конца цикла. Конечно, все должно быть согласовано. В операторах DATA все данные должны храниться в таком порядке, в каком они понадобятся оператору READ.

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

Иногда данные, хранящиеся в операторе DATA, могут понадобиться программисту несколько раз. Тогда надо привлечь оператор RESTORE. «Ристор» — это «восстановить». Когда интерпретатор найдет в программе этот оператор, он заставит следующий READ считывать данные с самого первого оператора DATA.


Данные собирайте с самого начала!



— Меня все время гложет вопрос, почему ты во всех операторах DATA так странно пишешь — «РОССИЙ», «ЛАТВИЙ»?

— Мне потом понадобится вывод названий республик в различных падежах. И поэтому я держу в массиве только основы слов, к которым буду добавлять окончания. Скоро увидишь. Сейчас смотри выбор режима в строках 270–340.

— Самый простой, наверно, режим показа.

— Нет, режим окончания проще, но показ в строках 370–430 тоже несложен: на экран столбиком выводятся порядковые номера республик, их названия и столицы. Фокус здесь в том, что мы к основе названия республики, которая хранится в массиве R¤, добавляем окончание. Это происходит в самом операторе печати в строке 410. А чуть раньше, в строке 405, мы вычислили, какое сокращение будет нужно: СФСР для Российской федерации или ССР для остальных республик.

— Неглупо. Стало яснее, зачем ты хранишь только основы названий республик.

— Потом идет режим повторения. Строки 440–480 ты, надеюсь, понимаешь?

— В особенности строку 480. Хоть один бы разочек за всю мою долгую жизнь сказали бы: когда тебе надоест заниматься, то… Поверь мне, ни разу!

ВАЖНОЕ ПОНЯТИЕ — ПОДПРОГРАММА
ПОДПРОГРАММА

— Прежде чем смотреть дальше, поговорим об одном важном понятии программирования. О понятии подпрограммы. Подпрограмма — это вроде узкого специалиста по какому-то конкретному делу. О подпрограммах надо думать, если в программе что-то надо сделать несколько раз, и всякий раз с другими значениями переменных. Скажем, в этой программе мне нужно было несколько раз определить, какой республике соответствует выбранное случайное число, но каждый раз в другом месте программы и с другими значениями переменных. Определить функцию не могу, так как весь алгоритм в одно выражение не ужать. Поэтому я этот алгоритм запрограммировал отдельно — подпрограммой, начав нумеровать строки с тысячи, хотя мог быть и другой номер. А там, где надо выполнить этот алгоритм, пишу оператор GOSUB и номер строки, с которой начинается подпрограмма:

GOSUB 1000

— Теперь, конечно, выясним, что это английское слово означает и как его произносить.

— Произносят его «гоусаб», и оно является сокращением английских слов go to subroutine, что означает «иди на подпрограмму». Это еще не все. Очень важно, что этот оператор передает управление так же, как и оператор GO ТО. Выполнение программы продолжается с той строки, на которую было передано управление, до появления оператора RETURN.

— «Ритэн» означало… означало…

— …возвращаться. Интерпретатор возвращается на оператор, который был после GOSUB. Итак, чтобы какую-то часть программы можно было бы считать подпрограммой, там должен быть оператор RETURN. Скажи четко, чем GO ТО отличается от GOSUB?

— Ну…если GO ТО передает управление куда-то, то это насовсем, а если GOSUB передает управление, то оно вернется назад, как только встретит RETURN. Но, по-моему, пора наконец возвратиться к твоей суперпрограмме.

— Где мы остановились?

— На строке 530.



Тоня Соображалкина в роли подпрограммы

АВТОМАТИЗАЦИЯ ПЕДАГОГИКИ
— Здесь мы начинаем режим повторения присваиванием нулей переменным, которые означают количество заданных вопросов и ошибочных ответов.

— Сначала выбираем случайное число. Странно, что с ним ничего не делаем. Обычно на что-то умножали и брали целую часть…

— На сей раз нужно случайное число как раз из отрезка [0; 1]. Оно определяет, какой зададим вопрос: назовем ли республику и спросим столицу или наоборот. При этом используется значение U1, о котором уже говорили.

— Это ничего. Можно еще поговорить. Хочу разобраться, что здесь произойдет. У тебя значение U1 было 0,5?

— Это означает, что оба типа вопросов будут встречаться одинаково часто.

— Хорошо. А если U1=0… Тогда полученное случайное число R из отрезка [0;1] обязательно будет больше 1 и мы уйдем на строку 670.

— То же самое было бы, если задали значение U1 меньше нуля.

— Другой случай. Если число R больше U1. Тогда управление всегда перейдет на следующую строку —580. А если это значение, например, 0,9, то почти всегда будет выполняться следующая строка, и только в одном случае из десяти перейдем на строку 670. Думаю, что в этих трюках разобраться можно. Продолжим.

— Если оператор ветвления в строке 570 пропускает на следующую строку, то мы сразу выводим вопрос и обращаемся к подпрограмме, начинающейся со строки 1000. Она сделает случайный выбор номера республики.

— Посмотреть бы эту подпрограмму.

— Она совсем простая. Выбираем случайное число между 1 и 15. Если оно 9, то есть придется спрашивать про Латвийскую ССР, выбираем еще раз, так как человек, живущий в Риге, должен знать, столицей какой республики она является.

— И в конце оператор RETURN, как это положено в подпрограммах.

— На сей раз этот оператор передаст управление назад на строку 610, где оператор PRINT выведет нужную столицу, и оператор INPUT в следующей строке обеспечит ввод ответа.

— Последующее сравнение тоже достаточно обычное. Смотрим, не ввел ли ученик знак номера, и если ввел, то переходим на 750. А что там? Ага! Выводим результаты труда и возвращаемся на выбор режима. А если ему еще не надоело? Если не надоело, то почему-то переменной N¤ присваиваем… что же присваиваем?

— N¤ — это переменная, значение которой — правильный ответ. В данном случае название республики, которое ученик должен ввести. Опять приходится использовать старый фокус с добавлением окончания в названии республики. Конечно, я считаю, что ученик должен ввести полное название, например: ЛИТОВСКАЯ ССР, а не только основу слова, которую я храню в массиве R¤: ЛИТОВ.

— Потом опять уходим на подпрограмму?

— Да, но сейчас это другая подпрограмма. Она сравнивает введенный ответ с правильным и сообщает, что получилось. Можешь посмотреть текст программы. Если ответ неправильный, приходится работать дополнительно — нужно увеличить количество допущенных ошибок на единицу.

— И, возвратившись из подпрограммы, идем на строку 560, чтобы все начать сначала.

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

МАШИНА — ЭКЗАМЕНАТОР
— Теперь уж перейдем на прием экзамена.

— Перед экзаменом расскажу, как он будет проходить. Выбираем одну из 15 республик и спрашиваем ее столицу, потом одну из оставшихся 14, потом из 13 и так далее до конца. В отличие от повторения, на экзамене один и тот же вопрос не может быть задан два раза. В специальном массиве Е отмечаем те республики, о которых уже спрашивали. В начале экзамена в этот массив засылаем нуль, и после каждого вопроса засылаем единицу в элемент массива с номером республики, о которой спрашивали.

— Вижу. Цикл засылки нулей имеется в строке 810. В следующей строке ты присваиваешь нули двум переменным.

— Это количество вопросов J и ошибочных ответов К. А что в следующей строке 830?

— Здесь обычный выбор случайного числа от 1 до 15. А потом какой-то странный оператор ветвления.

— Этот оператор как раз выясняет, была ли уже эта республика или нет. Если была, то берем следующее случайное число, а потом, если надо, еще и еще, пока не выпадет такая республика, о которой еще не спрашивали.

— Так ведь эти случайные числа можно брать и брать до бесконечности. Если, допустим, осталась только одна республика…

— Критику признаю справедливой. Придумай алгоритм без этого недостатка.

— Опять педагогические трюки!

— Никакие не трюки, а предоставление возможности роста. Теперь смотри строку 850.

— Там ничего интересного нет! Заставляют вводить столицу выбранной республики, и если бедняга-мученик вводит неправильно, программа ругается. Что там другое может быть?

— И вовсе она не ругается. Мои программы никогда не ругаются. Нам таких делать не разрешали. Конечно, начинающему кажется забавным, если программа обзывает пользователя олухом, мол, — какие это компьютеры умные, даже ругаться могут. А потом, когда понимаешь что к чему, ничего интересного и удивительного не находишь. Одно только расстройство, потому что, как бы ни понимал, что у машины никакой злости к тебе нет, все равно неприятно, когда тебя ругают. В обучающих программах этого уж никак не должно быть — ученик должен получать одни только радости от общения с компьютером.

— Радости? А посмотри, что происходит дальше. После каждого вопроса в строке 900 отмечается, о какой республике спрашивалось, и когда названы все 15, начинаются радости: если человек не знал всего одну только столицу — ему трояк, а если две — то уже пара. Ты, Петька, предатель общего дела учеников! Надо было делать так: если знает хоть одну — тройка.

— Столицы нетрудно выучить. И какой от тебя толк, если даже столицы республик не знаешь? Алгоритмыч меня заставлял ставить либо пятерку, либо двойку. Троечка уже моя самодеятельность. Лучше «проразмыслим» нашу программу. Как ее можно было бы толково переделать?

КАК МАШИНА МОГЛА БЫ ПОМОЧЬ В ИЗУЧЕНИИ ГЕОГРАФИИ…
— Легче всего было бы сделать программу, обучающую столицам автономных республик. Там даже менять ничего особенно не надо было бы.

— Кое-что все-таки пришлось бы: заменить все содержание операторов DATA и всюду, где идет речь о союзных республиках, написать об автономных. И еще другие, более мелкие изменения. Подобным же образом можно было бы создать программу обучения столицам государств мира.

— Это уже получилась бы капитальная работа! В мире же более двухсот государств. Только ввести названия всех столиц и государств…!

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



— Не двадцати, а ввести постоянную — и пусть учитель ее задает какую хочет. Подобно тому, как ты поступал с постоянной U1. И систему выставления оценок нужно переделать. Она вообще должна быть переделана.

— Здесь тоже можно было бы ввести постоянные. Со столькими-то ошибками ставим четыре, со столькими-то — три, а со столькими-то уже двойку. И эти постоянные учитель может менять как ему вздумается. Можно и так сделать, чтобы программа чаще спрашивала о тех республиках, на которых ученик чаще всего ошибается.

…ЯЗЫКОВ…


А вообще похожими получились бы и программы освоения слов какого-нибудь иностранного языка. В один массив загони тысячу-другую слов, во второй массив — их переводы — и пожалуйста! Правда, одним русским словом перевести слово иностранного языка не всегда можно, так что пришлось бы ограничиться основным значением. Можно было бы учить не только значения слов, но и различные правила, например формы неправильных глаголов в английском языке, да, я думаю, и в других что-то похожее нашлось бы.

— С неправильными глаголами не так-то просто. Они имеют три формы, например, gо — went — gоnе, а у тебя только два массива.

— Невелика наука добавить еще один массив, но можно и без этого обойтись. В одном массиве я размещаю неопределенную форму до, а во втором — две другие went и gone. Программа никогда не догадается, что это два слова. Это символьная строка, да и только.

— Что это мы все про языки, а как с другими учебными предметами? Здесь такие программы могли бы оказаться полезными?

— Какой предмет ты имеешь в виду?

— Например, литературу.

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

…ИСТОРИИ…
Другое дело история. Здесь могла бы помочь программа, которая бы повторяла с учеником важнейшие события и годы, когда они происходили. Опять в одном массиве год, в другом — событие.

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

— Почему бы и нет? Но при повторении истории имеет смысл называть только события и спрашивать год. Если делать наоборот, то будет очень трудно догадаться, что именно произошло, скажем, в 1890 году. В этом году произошло много чего, и совершенно неизвестно, что имел в виду составитель программы.

— Я совсем не могу вспомнить, что произошло в этом году.

— Это я так, для примера. Но если бы и удалось правильно догадаться, то описание нужно было бы ввести совершенно в такой же форме, как оно дано в соответствующем операторе DATA.

— Придумала, как переделать эту программу!

— Как?

…И ЕЩЕ КОЕ-ЧЕГО
— Но только это не совсем для школы. Можно было бы повторить мировые рекорды по легкой атлетике. В одном массиве дисциплина, в другом — рекорд. Если кто желает покрасоваться своими знаниями, может выучить.

— Можно было бы. Но кто же не знает рекорды легкой атлетики?! Лучше бы названия популярных песен и ансамблей, которые их исполняют.

— Вот это-то все знают. Ведь популярный ансамбль — это такой, который все знают.



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

— Долго мы провозились с этой твоей программой! А началось все с вопроса, как использовать мою программу склонения существительных для обучения детей! Получается, что в памяти в операторах DATA нужно хранить уйму существительных первого склонения, потом считывать их в массив, случайным образом оттуда извлекать и предлагать ученику просклонять.

— Думаю, можно было бы получить еще одно случайное число от 1 до 6, которое бы означало номер падежа, и именно этот падеж спрашивать. Разумеется, опять нужно было бы создавать массив с названиями падежей и вопросами; кроме того, другой массив с окончаниями, ну, чтобы построить правильный ответ. Тогда пришлось бы проверять, не выпал ли предложный падеж, потому что в этом случае не только меняется окончание, но и нужно добавить предлог «о» перед словом. Ой, пора кончать! Я еще должен учить русский, и совсем не склонение существительных первого склонения.

19. ТОНЯ УЗНАЕТ О ФАЙЛАХ

Уже не раз Тоня возмущалась, что результаты работы ее программ можно видеть только на экране, а она их охотно бы выпечатала, чтобы можно было бы их сохранить и дома показать. А Петя почему-то ее этому не учит. Петя же все время отнекивался, говорил, что еще рано и что лучше всего эти дела осваивать одним махом — выучить сразу все о файлах. Поэтому Тоня обрадовалась, услышав:

— Сегодня начнем углубляться в науку о файлах, или, как я ее называю, файлологию.

— Наконец-то! Давно пора.

— Конечно, можно было бы и раньше, но, на мой взгляд, до того как браться за файлы, тебе нужно было привыкнуть к программированию, к машине. Теперь ты эти файлы, может быть, мгновенно поймешь, но только потому, что твой мыслительный аппарат настроился на формальное мышление, то есть на такое мышление, какое нужно программисту. А работать с файлами нужно уметь. Бывают такие программы, притом очень важные, которые работают почти только с файлами.

— Да ладно. Ближе к делу! Воспитатель нашелся!

— Я тебе уже как-то говорил, что файл можно понимать как место на внешнем носителе информации — так называют диски и ленты. Это место имеет обозначение, или имя, по которому его и записанные в нем данные в любой момент можно легко найти.

ФАЙЛ = КНИГА?
Каждый файл может быть либо открыт, либо закрыт. Конечно, никто на внешнем носителе информации ничего не закрывает и не открывает. Это такой способ выражения. Открыть файл означает разрешить с ним что-то делать — записывать в него данные или считывать их с него. А закрыть файл означает временно о нем забыть.

ОТКРЫТИЕ ФАЙЛА


Чтобы попасть к данным, OPEN должен открыть файл


До него нельзя добраться, его будто нет, и пока он не открыт, с ним делать ничего нельзя.

— И как же его открывают?

— А как по-английски «открыть»?

— «Оупен».

— Вот и файлы открывают оператором OPEN.

Например, так:

OPEN «DK1:FAIL» FOR INPUT AS FILE 3

Как видишь, это самый длинный оператор Бейсика. Переведем его на русский язык.

OPEN «DK1:FAIL» FOR INPUT AS FILE 3
Открыть файл с таким описанием для ввода в качестве файла номер 3
— Непонятно, почему здесь вылез какой-то «номер 3»?

ЛОГИЧЕСКИЙ НОМЕР ФАЙЛА
ЛОГИЧЕСКИЙ НОМЕР ФАЙЛА

— Я это понимаю так. Интерпретатор, сам будучи программой, обрабатывает этот оператор. У интерпретатора в памяти предусмотрено место для хранения сведений об открытых файлах, можно сказать, массив, содержащий символьные строки — описания файлов. А элементы массива положено нумеровать. Вот этот номер и будет номером файла. Еще его называют логическим номером файла. Просто в операторе открытия файла мы указываем номер элемента этого массива, куда надо поместить описание открываемого файла.

— Так что в каждый момент могут быть открытыми несколько файлов?

— Именно так. И притом файл с логическим номером 3 отнюдь не обязательно открывать третьим, его можно открывать и первым, до того как будут открыты файлы с логическими номерами 1 и 2. Открывая файл, интерпретатор проверяет, существует ли на указанном устройстве такой файл, и если существует, то не открыт ли он уже. Если удается обнаружить какое-то несоответствие, об этом сразу сообщается.

Помнишь ли, что означало, например, такое описание файла «DK1:FAIL»?

— Да, помню. DK1 означает дисковое устройство и его номер, a FAIL — имя файла.

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

100 PRINT «ВВЕДИТЕ НОМЕР ДИСКА»

110 INPUT N¤

120 PRINT «ВВЕДИТЕ ИМЯ ФАЙЛА»

130 INPUT F¤

140 OPEN «DK»+N¤+«:»+F¤ FOR INPUT AS FILE 1

Сперва вводим номер диска. Как символ! Потом вводим имя файла.

— Как символы!

— Естественно. А потом сцепляем полное описание файла.

Сейчас о слове INPUT в операторе OPEN. Вместо него может быть и OUTPUT.

— «Аутпут»… что бы это значило? Может быть, «вывод»? «Ввод» уже был.

— Да, в этом случае файл будет открыт для вывода. Одновременно для ввода и вывода на нашей машине файлы открыть нельзя. Интерпретатор это не позволяет. Чтобы в одном и том же файле сначала записать, а потом считать, нужно: во-первых, файл открыть для вывода; во-вторых, записать в нем; в-третьих, закрыть; в-четвертых, открыть для ввода и, наконец, в-пятых, считать необходимое.




— Как сложно!

— Дело в том, что считывать данные с файла можно только по порядку. И записывать в файл тоже. Когда мы считываем с файла, интерпретатор знает, сколько мы считали — до какого места в файле. И когда записываем в файл, то тоже известно, где находимся. А если в какой-то файл захотим и записывать, и с него же считывать, то может случиться, что мы захотим в один и тот же момент находиться в двух местах. А этого никто не может. Или представь, что мы считываем файл с магнитной ленты. Мы же сможем считать только с того места, где остановили перемотку ленты. Или если мы читаем данные из обычной книги, то ясно, что читать можно только с того места, где кончили листать.

— Ясно, что можно считывать с начала файла, если его закрыть и потом снова открыть. Но ты же не собираешься рассказывать, как закрыть файл.



ДЕЙСТВИЯ С ФАЙЛАМИ
— Нет, собираюсь. Его закрывают оператором CLOSE.

— Еще бы! «Клоуз» же означает «закрыть».

— Этот оператор намного проще оператора OPEN. Нужно только после него написать логический номер того файла, который хочется закрыть:

CLOSE 3

А если номера после CLOSE нет, то закроются все открытые в этот момент файлы. Вот и все про закрытие.

— Прекрасно. Еще один кирпичик в здание Дворца знаний Тони Соображалкиной. Или же будки знаний.

— Еще один очень важный, но чрезвычайно опасный оператор.

KILL «DK1:FAIL»

— «Кил»… Не знаю.

— «Убивать»! Оператор, пожалуй, никого не убивает, он просто стирает файл. После выполнения этой строчки на диске номер 1 файла с таким именем не будет. Как видишь, стираемый файл указывается после слова KILL. Либо в явном виде — в кавычках, либо как символьная константа, значение которой — описание стираемого файла.



— Стирает… Просто так — берет и стирает. А если потом опять понадобится?

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

— Бр-р-р. Дрожь берет.

ЗАПИСЬ В ФАЙЛ
— Еще следовало бы поговорить о том, как в файл записать и как с него считать. Это делают теми же старыми, добрыми операторами INPUT и PRINT, которые ты хорошо знаешь. Они только чуть дополнены. Смотри, как я пишу:

PRINT #3,А,В

После слова PRINT идут знак номера «#», номер файла, запятая и список переменных. Этим можно обеспечить запись значения переменных А и В в файл, который в настоящий момент уже открыт для вывода как файл с логическим номером 3. Подобно делается и с оператором INPUT:

INPUT #4,В¤

Если напишешь так, получишь значение переменной В¤ с файла, который открыт для ввода с логическим номером 4. Подчеркну, что ввод произойдет с того места файла, где мы в настоящий момент находимся. С выводом то же самое.

— Это все про ввод и вывод?

— Нет, не все. Еще ты должна знать, что в этих операторах после знака номера можно писать номер файла не только в явном виде, но и как числовую переменную. Если там написать нуль или значение числовой переменной будет нуль, то ввод или вывод будет проходить на дисплее. Так, как было тогда, когда мы знак номера еще не писали. Получается, будто на дисплее всегда открыт файл с номером нуль. Теперь-то все.

— Вроде бы поняла. Только этот логический номер файла неясен немножко. Но как же все, если ты ничего не сказал про вывод на печать.

— На устройстве печати надо открыть файл с описанием, состоящим только из кода устройства, — подобно тому, как мы делали при печати программ:

OPEN «LP:» FOR OUTPUT AS FILE 4

азумеется, если для этого файла ты выбрала четвертый логический номер.

Про печать все. Про файлы все. И про программирование тоже все. Сейчас ты, Тоня, в программировании знаешь все существенное, и менее существенное тоже, — считай, все. Теперь посмотрим еще кой-какие примеры программ — и за работу.

— Так точно! Программировать, программировать и еще раз программировать! Таков пусть будет наш девиз!

class="book">КОМПЬЮТЕР ПОЗДРАВЛЯЕТ С ПРАЗДНИКОМ — Займемся сейчас программой печати поздравлений. Что она должна делать и что она делает? Она должна красиво напечатать поздравление с днем рождения или с каким-то другим праздником. Красиво — на сей раз означает, что вокруг текста поздравления должна быть выпечатана рамочка из какого-то символа. Он называется декоративным символом.

В начале поздравления следует поставить обращение, состоящее из слов «Дорогой», «Уважаемый» и т. п. и из имени поздравляемого человека. Конечно, указывать именно имя необязательно. С таким же успехом может быть имя и отчество или фамилия. Еще программа узнает у пользователя, как обращаться к поздравляемому человеку — на «ты» или «вы», ученик он или взрослый. Может, начнем смотреть программу, тогда и увидишь, что там происходит.

10 REM ПРОГРАММА ПЕЧАТАЕТ ПОЗДРАВЛЕНИЯ

20 R=16 \ REM КОЛИЧЕСТВО СТРОК

30 N=30 \ REM КОЛИЧЕСТВО ЗНАКОВ В СТРОКЕ

40 S¤="*" \ REM ДЕКОРАТИВНЫЙ СИМВОЛ

50 S1¤="C ДНЕМ РОЖДЕНИЯ. " \ S2¤=”12"

60 DIM L1¤(2,2), Т¤(10)

70 L1¤(1, 1)="ДОРОГОй" \ L1¤(1,2) = ”ДОРОГАЯ"

80 L1¤(2,1)="УВАЖАЕМЫй" \ L1¤(2,2)="УВАЖАЕМАЯ"

90 DIM L2¤(2) \ L2¤(1)="ТЕБЯ" \ L2¤(2)="BAC"

100 DIM L3¤(2) \ L3¤(1)="ТЕБЕ" \ L3¤(2)=“BAM"

105 \

110 DATA “ ",“ПОЗДРАВЛЯЮ"," ","ЖЕЛАЮ "

120 DATA "БОЛЬШОГО СЧАСТЬЯ,",“ХОРОШЕГО НАСТРОЕНИЯ"

130 DATA " “," “," "," ПЕТЯ"

135 \

140 PRINT "ПРОГРАММА ПЕЧАТАЕТ ПОЗДРАВЛЕНИЯ"

150 PRINT " ВЫВОД НА ЭКРАН — 1"

160 PRINT " НА БУМАГУ — 2" \ INPUT F¤

165 IF POS(S2¤,FX,1)=0 THEN 150 \ F=VAL(F¤)

170 F=F-1 \ REM СЕЙЧАС F НОМЕР ФАЙЛА

180 IF F=0 THEN 200 \ REM ВЫВОД НА ЭКРАН

190 OPEN "LP: " FOR OUTPUT AS FILE 1 \ REM ПЕЧАТЬ

195 \

280 PRINT \ if POS(S2¤,U¤,1)=0 THEN 260

290 PRINT " ИМЯ"; \ INPUT U¤

295 PRINT \

300 L=LEN(U¤) \ REM ДЛИНА СЛОВА

310 Px=SEG¤(U¤,L,L) \ REM ПОСЛЕДНЯЯ БУКВА

320 \

325 REM НАЧАЛО ОПРЕДЕЛЕНИЯ ПОЛА

330 IF Px<>"A" THEN 370

340 IF SEG¤(U¤,L-1,L-1)="Ш" THEN 380

350 IF V¤="ВАЛЕРА" THEN 375

351 IF V¤="CEPEWA" THEN 375

352 IF V¤="СЛАВА" THEN 375

353 IF V¤="BOBA" THEN 375

354 IF V¤="CEBA" THEN 375

355 IF V¤=”ЛЕВА" THEN 375

356 IF V¤="ЮРА" THEN 375

357 IF V¤="ДИМА" THEN 375

360 D=2 \ GO TO 470 \ REM ЖЕНСКОЕ ИМЯ

370 IF Р¤="Я" THEN 380

375 D=1 \ GO TO 470 \ REM МУЖСКОЕ ИМЯ

380 PRINT "ПОЗДРАВЛЯЕТЕ МУЖЧИНУ — 1"

390 PRINT " ЖЕНЩИНУ — 2" \ INPUT D¤

400 D=VAL(D¤) \ IF POS(S2¤,D¤,1)=0 THEN 380

440 \

450 REM НАЧИНАЕТСЯ ПОДГОТОВКА ТЕКСТА

460 \

470 RESTORE \ FOR J=1 TO 10 \ READ T¤(J) \ NEXT J

475 REM СНАЧАЛА ФОРМИРУЕТСЯ ОБРАЩЕНИЕ

480 T¤(1) =L1¤(VAL(C¤), D) +" " +V¤+"!"

490 T¤(2)=T¤(2)+L2¤(VAL(T¤)) \ REM ТЕБЯ ИЛИ ВАС

500 T¤(3)=S1¤ \ REM В СВЯЗИ С ЧЕМ ПОЗДРАВЛЯЕМ

510 T¤(4)=T¤(4)+L3¤(VAL(T¤)) \ REM ТЕБЕ ИЛИ ВАМ

520 IF U¤="1" THEN 540

530 Т¤(7)="И КРЕПКОГО ЗДОРОВЬЯ!" \ GO ТО 560

540 Т¤(7)="И УСПЕХОВ В УЧЕБЕ!"

545 \

550 REM НАЧИНАЕТСЯ ВЫВОД =============================

555 \

560 GOSUB 1000 \ REM ПЕРВАЯ СТРОКА РАМКИ

570 R1=INT((R-10)/2) \ REM СКОЛЬКО СТРОК БЕЗ ТЕКСТА?

580 GOSUB 2000 \ REM И СТОЛЬКО ВЫПЕЧАТЫВАЕТ

585 \

590 REM СЕЙЧАС ТЕКСТ В РАМКЕ

600 FOR J=1 ТО 10 \ REM ЦИКЛ ПЕЧАТИ ТЕКСТА

610 N1 = INT((N-2-LEN(T¤(J)))/2) \ REM СКОЛЬКО ПРОБЕЛОВ?

620 PRINT #F, TAB(5);S¤;TAB(N1+6);T¤(J);TAB(N+4); S¤

630 NEXT J

635 \

640 GOSUB 2000 \ REM ПЕЧАТЬ СТРОК БЕЗ ТЕКСТА

650 GOSUB 1000 \ REM И ПОСЛЕДНЕЙ СТРОКИ

66 °CLOSE \ PRINT \ REM ЗАКРЫВАЕТ ВСЕ ФАЙЛЫ

665 \

710 INPUT I1

715 \

720 F=0 \ ON I1 GO TO 740,290,150,730

725 \

730 STOP

740 F=1

750 OPEN ”LP:” FOR OUTPUT AS FILE 1

760 GO TO 560

770 END

775 \

1000 REM ПЕЧАТЬ СТРОКИ ДЕКОРАТИВНЫХ СИМВОЛОВ

1010 PRINT #F,TAB(5);

1015 FOR 1 = 1 TO N \ PRINT #F,S¤; \ NEXT I

1020 PRINT #F \ RETURN

1025 \

2000 REM ПЕЧАТЬ РАМКИ БЕЗ ТЕКСТА

2010 FOR 1=1 ТО R1

2020 PRINT #F,TAB(5);S¤;TAB(N+4);S¤

2030 NEXT I

2040 RETURN

3000 END

Ой, совсем забыл! У меня же есть образец выпечатанного поздравления.

*********************************

* *

* *

* *

* УВАЖАЕМАЯ ТОНЯ! *

* ПОЗДРАВЛЯЮ ТЕБЯ *

* С ДНЕМ РОЖДЕНИЯ. *

* ЖЕЛАЮ ТЕБЕ *

* БОЛЬШОГО СЧАСТЬЯ, *

* ХОРОШЕГО НАСТРОЕНИЯ *

* И УСПЕХОВ В УЧЕБЕ! *

* *

* ПЕТЯ *

* *

* *

* *

*********************************



— Потрясающе! Почему ты мне не прислал на день рождения такое поздравление?

— Как я это мог сделать! А на следующий свой день рождения сама сможешь напечатать хоть сотню.

— Так будет неинтересно.

— Теперь о самой программе. В самом начале присваиваю значение двум переменным R и N.

Эти переменные определяют длину и высоту декоративной рамочки. Потом присваивается значение декоративному символу S¤ — обычно я беру звездочку. Далее задается праздник, с которым поздравляем — значение переменной S1¤.

— И это значение придется менять, если захочу поздравить не с днем рождения, а, например, с окончанием школы?

О ДВУМЕРНЫХ МАССИВАХ
— Совершенно верно. В следующей строке начинается кое-что новое. Описывается двумерный символический массив L1¤. Двумерные символические и числовые массивы появляются, если значения переменных имеют два номера, например оценка в табеле — номер предмета и номер четверти. Предметы, конечно, должны быть заранее пронумерованы. Другой пример — оценки фигуриста в протоколе соревнований с номером судьи и номером фигуриста. Опять же и фигуристы, и судьи должны быть пронумерованы. Обычно двумерные массивы в программах описывают какие-нибудь списки со строками и колонками. Таким списком является и табель, и протокол соревнований.

Представь себе еще такой список: в строках — звери зоосада, а в колонках — сколько какого продукта они в день должны съесть. Если захочешь составить программу, которая обрабатывает такие данные, придется вводить двумерный массив.

— Не верю, что звери смогут прожить на твои нормы; и вообще — что тут считать!

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



— А зачем тебе понадобился двумерный массив именно в этой программе?

— В моей программе он предельно прост. Сначала нумерую степень уважения: 1 — дорогой; 2 — уважаемый. Потом род: 1 — мужской род; 2 — женский род. Потом выписываю двумерный массив:

Степень уважения
1 2
Род 1. мужской дорогой уважаемый
2. женский дорогая уважаемая
— Потом еще определяешь двумерные массивы и присваиваешь их элементам те значения, которые могут понадобиться при печати поздравления.

— Да, да. Притом в обоих массивах L2¤ и L3¤ первые элементы соответствуют обращению «ты», а вторые — «вы». Можно сказать, что возможные способы обращения я перенумеровал так: 1—«ты»; 2—«вы».

— Не понимаю, почему ты так много об этом говоришь? Какие значения хотел, такие присвоил.

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

СОСТАВИТЬ ПОЗДРАВЛЕНИЕ НЕЛЕГКО
— Ладно. Далее следуют операторы DATA, в которых, судя по всему, ты хранишь текст поздравления.

— Я бы сказал, заготовку текста. Потом, когда все символьные строки из операторов DATA перекочуют в значения переменных, я их дополню и получу окончательный текст.



— Интересно, почему в строке 150 упоминается вывод на экран, если ты собираешься печатать.

— Это нужно для проверки. Не думай, что такую программу я могу сделать в один присест, не допустив ни одной ошибки. Программу надо было отлаживать, и во время отладки все лучше выводить на экран, чтобы зря не тратить бумагу. Но вернемся к программе. Ты ввела свое пожелание, куда выводить поздравление: оно содержится в значении переменной F¤.

— А почему для хранения чисел 1 или 2 ты выбираешь символьную переменную? С числовой переменной было бы проще.

— Ничего не проще. Это для тебя привычнее числа, чем символы, а машине, что числа, что строки символов, все одно. А вношу я ответ пользователя в значение символьной переменной для удобства проверки ввода. После ввода мне остается только проверить, входит ли введенный символ в строку символов S2¤, которую я загодя определил в строке 50. Этим я и занимаюсь в строке 165.

— А поскольку ты все равно потом хочешь иметь число, тебе приходится символ превращать в число при помощи функции VAL. Правильно ли я понимаю?

— Ты понимаешь правильно. Мы получаем число F и сразу вычитаем из него единицу. Зачем? Чтобы получить номер файла. Номер файла вывода на экран всегда должен быть нулем, а файлу печати можем присваивать такой номер, какой хотим. На сей раз лучше всего хотеть единицу.

— Лучше захоти объяснить, на что этот оператор ветвления здесь в строке 180!

— Здесь мы вычисленный номер файла сравниваем с нулем. Если он оказался нулем, это означает, что пользователь желает выводить на экран и мы спокойно уходим дальше на ввод данных. Если же номер файла не нуль, то надо в строке 190 открыть устройство печати — как файл с номером 1.

— Дальнейшее понятно. Пользователь вводит все, что от него требуется.

— Но правильность ввода все время проверяется.

— Это ты делаешь всегда одинаково, потому что и ввод у тебя практически всегда одинаков. Ищешь введенный символ в значении переменной S2¤, и все.

— Да, что-то поинтереснее начинается, когда введено имя поздравляемого и мы приступаем к его анализу. Сначала находим длину имени и его последнюю букву в строках 300 и 310. А потом выясняем, кого надо поздравлять — мужчину или женщину.

— Это же просто!

— Тебе просто. А для компьютера это неразрешимая задача, потому что нет алгоритма, как по имени определить, мужское это имя или женское.

— Ну, женские имена оканчиваются на «-а»…

— Оканчиваются-то оканчиваются, да не все. И не каждое имя, оканчивающееся на «-а», будет женским. Более того, существуют же одинаковые имена и для мужчин, и для женщин.

— Ну да!

— Например «Саша» может быть и юношей и девушкой.

— Так это же, ну… сокращение.

— Не важно. Программа должна была бы работать для всех случаев. Но алгоритм, который я запрограммировал, сможет уверенно отличить мужчину и женщину только при обращении по имени и отчеству. Конечно, по окончанию — оно «-а» или нет. Если оканчивается на «а», а не на «ша», то программа сама пытается выяснить, не мужчина ли это, сравнивая введенное имя с мужскими именами на «-а» — Слава, Савва, Сережа и другими. А в случаях, когда обращение оканчивается на «я» или «ша», программа сдается и просит пользователя самого ввести, кого он поздравляет. Вот такой алгоритм.

— И запрограммирован он в строках 330–400…

— Да. И в результате работы этих строк переменная D получает значение 1, если поздравляем мужчину, и 2, если женщину.

— Об этом хватит. Перейдем к подготовке текста поздравления, которая начинается в строке 470. И сразу вся заготовка текста считается в массив Т¤. А в следующей строке…

— В следующей строке выясняется, почему всюду вводили либо 1, либо 2.

— Смотрим. Переменная С¤! Ее значение… «1», если надо обращаться «дорогой», и «2», если — «уважаемый». Переменная D указывает пол поздравляемого.

— Важно то, что значения этих переменных…

— … используются для получения нужного элемента массива L1¤: «дорогого» или «уважаемого»— в мужском или женском роде.

— Ты мне не даешь похвастаться хорошо сделанным куском. Тебе надо было спокойно все прослушать и в конце воскликнуть: «Ой, Петя, как ты хорошо придумал с этими переменными С¤ и D!»

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

— Пробел можно было бы и не ставить, но тогда в массив L1¤ нужно было бы заносить не просто «УВАЖАЕМЫЙ», а «УВАЖАЕМЫЙ» с пробелом в конце.

— Я же говорю, что это сногсшибательно!

— Можешь смеяться, но я тебе скажу, что программировать интересно хотя бы потому, что пусть и мелочь, но можно хорошо придумать.

— И это дает «творческое удовлетворение».

— Одному дает творческое удовлетворение работать, другому — издеваться.

— Ну не надо обижаться! Я же просто пошутила.

— Лучше посмотри, как образуются третий и четвертый элементы массива T¤. Здесь я сцепляю две символьных строки, а пробел между ними не ставлю, потому что в операторах DATA уже хранятся слова «поздравляю» и «желаю» с пробелом в конце.

— А что ты вытворяешь в строках 520 и дальше! Опять пренебрежительное отношение к ученикам! Взрослым ты желаешь доброго здоровья, а ученикам — «успехов в учебе». Успехов в учебе, детка! Зачем тебе доброе здоровье, лишь бы были успехи в учебе.

— Не верю, чтобы кто-то потерял здоровье из-за успехов в учебе.

— Бедный Петя! Если бы ты не был так смешон, то от твоего серьезного вида мухи бы дохли!

— Не понимаю, будем продолжать или отложим?

СОВСЕМ ПРОСТАЯ ПОДПРОГРАММА
— Все. Кончаю. Продолжаем. Смотрим строку 550. Начинается вывод. Строка 560 отсылает к подпрограмме, начинающейся со строки 1000… Что это за подпрограмма?



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

— Вижу цикл. А что это за PRINT перед ним?

— Ах да! О функции TAB ты еще ничего не знаешь. Эту функцию можно вызывать только в операторе PRINT, и она указывает позицию строки, с которой надо продолжать печать. Поясню ее работу на примерах.

PRINT «ПРИВЕТ»;ТАВ(40);«ТОНЯ»

Такой оператор слово ПРИВЕТ выведет, начиная с первой позиции, а слово ТОНЯ — с сороковой.



PRINT ТАВ(40); «ПРИВЕТ»; «ТОНЯ» Этот оператор текст ПРИВЕТТОНЯ выведет, начиная с сороковой позиции.

В аргументе функции не обязательно указывать число, там может быть любое арифметическое выражение. А сейчас скажи — что делает такой оператор?

PRINT ТАВ(5);

— Не знаю. По-моему, он… ничего не делает.

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

— Но тогда же и другие строки нужно будет печатать, начиная с шестой позиции.

— Так я и поступлю.

— А на что этот одинокий оператор PRINT после цикла?

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

— А возвратившись из подпрограммы, натыкаемся на какой-то сложный расчет в строке 570.

— Здесь рассчитываем, сколько пустых строк оставить между верхней декоративной строчкой, которую только что напечатали, и текстом поздравления. Пустые строки будут еще и после текста. Их количество я рассчитываю так. Значение переменной R — общее количество строк в поздравлении — мне известно: 16. Отнимаем от него 10 — количество строк в тексте поздравления. Получаем общее количество пустых строк. А сколько из них оставить вверху над текстом? Считаю, что половину. Потом беру целую часть частного (R—10)/2 просто потому, чтобы R1 получилось целым числом, поскольку в дальнейшем я эту переменную собираюсь использовать в местах, где нужны целые числа, ты увидишь.

— Где я это увижу?

ЕЩЁ ОДНА ПОДПРОГРАММА
— Например, во второй моей подпрограмме в строке 2010 я это число использую как границу цикла, которая, конечно, должна быть целым числом. Правда, интерпретатор прекрасно сам понимает, когда нужны именно целые числа, и сам берет целую часть в случае необходимости.

— И где эта твоя вторая подпрограмма? Опять функция TAB! Но оператор PRINT на сей раз куда сложнее. Хотя нет… Понять можно. Сначала ты отступаешь на пять позиций от края бумаги, потом выпечатываешь декоративный символ, потом прыгаешь на конец строки, где выпечатываешь еще один декоративный символ. Всего-то?

— А ты что еще хотела? Больше ничего и не надо. Раз вывели пустые строки, можно начинать выводить текст. Это делает цикл в строках 600–630. Сперва нужно рассчитать, сколько пробелов будет между декоративной рамочкой и первым символом текста. Это приходится делать перед выводом каждой строки, так как длины строк текста поздравления разные.

— Посмотрим, как это делается. Из общей длины строки вычитается длина текста, результат делится на двойку и берется целая часть. Да, почти как при нахождении количества пустых строк сверху и снизу.




— Но есть и небольшое отличие. В том случае верхняя и нижняя строки рамки в количестве строк не учитывались: R было количеством строк между строками рамочки, а N — количеством символов в одной строке, включая и декоративные символы слева и справа.

— Разве это так уж важно. Все равно я подберу такие значения R и N, чтобы поздравление выглядело хорошо. Но давай вернемся к печати текста! Меня интересует сам оператор печати в строке 620. Сначала он передвигает место печати на пять позиций, в шестой выводит декоративный символ, как это уже было, потом перепрыгивает на место, где надо печатать символы текста… Это ты хорошо придумал!

— Вообще… вообще это не я придумал, мне Алгоритмыч рассказал.

— Вот тебе на! Но TAB действительно ценная вещь. Совсем не надо заранее знать, сколько символов в строке текста поздравления, чтобы напечатать ровно посередине между декоративными символами.

— Еще выводятся пустые строки под текстом, потом нижняя строка рамочки, и это все о выводе поздравления. Далее оператором CLOSE закрываем все файлы, чтобы действительно началась печать. Нужно учитывать ту особенность, что наша машина печать на бумаге не начинает, пока файл на печатном устройстве открыт.

— После печати программа выясняет у пользователя, что делать дальше.

— Поговорим о первой возможности — выпе-чатать все как есть. В этом случае переходим на строку 740 и первым делом присваиваем значение 1 переменной F — номеру файла для вывода. Потом нужно открыть печатающее устройство, потому что все файлы закрыты. Помнишь строку 660?

— А почему ты в строке 720 до выполнения оператора ON присвоил 0 переменной F, чтобы потом сразу присвоить 1?

— А если оператор ON отправил бы нас на строку 290? Тогда не смогли бы выполниться последующие операторы PRINT #F, так как все файлы закрыты, кроме нулевого. Получается, что только в случае, если значение F равно нулю, все выполнится нормально и произойдет вывод на экран.

ПРОВЕРКА ПРАВИЛЬНОСТИ ПРОГРАММЫ
Вот что еще надо сказать об этой программе. Когда она была написана, нужно было ее тестировать — убедиться, что она действительно работает со всеми входными данными. Скажи — какие имена мне надо ввести, чтобы убедиться, что пол определяется, как было задумано.

— Во-первых, надо пройти весь список имен, конкретно указанных в программе, — Валера, Сережа, Слава и другие. Потом… Имя, не входящее в этот список, — оканчивающееся на «а», но не на «ша». Например, Антонина. Потом, конечно, и оканчивающееся на «ша» — Саша. И еще имя, оканчивающееся на «я», — Тоня. Вроде, ничего не забыла.

— Забыла. Имя, оканчивающееся не на «а». Например, Петр. Сколько всего вариантов получится?

— Восемь плюс четыре. Двенадцать. Значит, для тестирования пришлось бы пропустить программу 12 раз.



— Это для тестирования определения пола поздравляемого. Но еще до ввода его имени нужно четыре раза вводить единицу или двойку. Тестируя сложную программу, пришлось бы проверить любую комбинацию из этих четырех чисел — единиц или двоек и двенадцать имен. Так что всего надо было бы пропустить 12.2.2.2.2=192 варианта.

— Ужас!

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

— Ты, видимо, хочешь сказать, что достаточно проверить комбинации «ученик» — «Антонина» и «взрослый» — «Антонина», чтобы все считать в порядке, и не проверять варианты «ученик» — «Петр» и «взрослый» — «Петр»?

— Хочу сказать больше: достаточно проверить варианты «ученик» — «Петр» и «взрослый» — «Антонина», то есть можно объединить проверку определения пола и проверку обработки ввода «ученик» — «взрослый», — другими словами, обработки значения переменной U¤. Это значение мало на что в программе влияет — оно участвует только в одном операторе ветвления в строке 520. Если же это значение и введенное имя участвовали бы в разнообразных вычислениях, то нужно было бы пропустить все возможные варианты — два варианта ввода переменной U¤ и двенадцать вариантов ввода имени.

— По-моему, о значении переменной СД можно сказать то же самое. Эта переменная отвечает за то, дорог ли нам поздравляемый или просто уважаем. И эта переменная тоже используется только один раз — там, где из массива выбираются слова «дорогой» или «уважаемый» в нужном грамматическом роде. Если программа правильно выберет слово для Антонины, то и для Тони тоже.

— И опять, если бы это значение участвовало в каких-нибудь сложных расчетах, то пришлось бы проверить все возможные варианты.

— Очевидно, и о переменной ТД, которая содержит нужное обращение, можно сказать то же самое. И в еще большей степени это можно сказать о переменной F¤, отвечающей за вывод на экран или бумагу. Если один раз запрашивали вывод на бумагу и программа действительно на бумагу вывела, то, запрашивая то же самое в следующий раз, также получим вывод на бумагу.

— Можно надеяться.

— Я запуталась. Сколько всего вариантов получилось?

— Всего двенадцать. Мы должны проверить обработку всех имен и дополнительных переменных. Так как проверка обработки этих дополнительных переменных весьма проста — нужно только ввести два набора чисел: 1,1,1,1 и 2,2,2,2, то ее можно объединить с проверкой имен. Ведь чтобы ввести любое имя, нам придется сначала ввести и значения дополнительных переменных.

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

— Да ну тебя! Какая же тут халтура! Мы обстоятельно рассудили, что взаимного влияния нет: если один раз программа слово «уважаемый» выбрала правильно, то и в следующий раз тоже выберет правильно. Все логично.

ВОЗМОЖНЫЕ ОШИБКИ
— Все логично с правильной программой. Но программа может быть и неправильной, и притом работать неправильно только при отдельных комбинациях входных данных, а при всех остальных изображать правильно работающую программу.

— Не верю, что такие ошибки могут быть.

— Труднее всего найти ошибки, которых не может быть. Так говорил Алгоритмыч.

— Придумай тогда в этой программе такую ошибку!

— Я не говорю об этой программе, а вообще. Здесь, может быть, и не удастся придумать достаточно «естественную» ошибку, но попробовать можно. Например, для отыскания последней буквы в имени поздравляемого человека мы пишем не

Р¤ = SEG¤(V¤,L,L)




а по рассеянности вводим букву G не только в имени функции, но и в аргументах

P¤ = SEG¤(V¤,G,G)

Что произойдет?

— Что произойдет? Если обращаемся «дорогой», будет найдена первая буква, а если «уважаемый»— вторая.

— Вот представь: ты вводишь имя АНТОНИНА и если хочешь к ней обратиться «дорогая», то все правильно — первая буква совпадает с последней, и наш алгоритм срабатывает правильно. Если же хочешь обратиться «уважаемая»— не тут-то было — получишь УВАЖАЕМЫЙ АНТОНИНА. С именем КАТЯ будет наоборот — она станет мужчиной, когда будет дорогой. А если такая ошибка:

P¤ = SEG¤(V¤,5,5)

— Тогда в имени будет найдена пятая буква. И только с пятибуквенными именами программа сработает правильно, с другими — как бог на душу положит.

— Нужно признать, что наша система тестирования не обеспечивает обнаружения таких ошибок. Скажем, мы могли случайно для тестов взять как раз пятибуквенные слова. Или случайно пропустить вариант «дорогая Антонина», а уважаемым считать Петра. Ведь мы же договорились не перебирать все возможные комбинации входных данных. Тестирование — это сложная наука.

— Ну а если все-таки обнаружили, что программа делает не то. Как найти, где именно ошибка?

— Ой, это нелегко! Если программа вдруг начинает путать, можно подумать, что какой-то из операторов сравнения срабатывает неправильно. Можно их просмотреть и убедиться, что они записаны верно. Если так, то неверны данные, используемые этими операторами. В нашем случае самое подозрительное данное — это последняя буква РД, которая присутствует во многих операторах сравнения. Чтобы проверить это значение, можно поступить так. После строки 310 с нахождением РД вставляем дополнительную строку 315 STOP и пропускаем программу еще раз с теми же входными данными, которые до того давали ошибку. Когда произойдет останов на строке 315, можем в непосредственном режиме посмотреть значения P¤, D и другие, какие захотим. Если обнаружится что-то подозрительное, то посмотрим программные строки, ответственные за это. В конце концов и обнаружим ошибку.

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

20. ТОНЯ ПРОДОЛЖАЕТ ОСВАИВАТЬ ФАЙЛОЛОГИЮ

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

— Давай кончим это печатание и поговорим о программировании. Неужто компьютеры изобретены только для печатания?

ЧТО ЕЩЕ МОЖНО НАПЕЧАТАТЬ?
— Конечно, нет, но красиво и наглядно выпечатать тоже надо уметь. Какой толк, если машина что-то интересное рассчитает, а программист не позаботится о том, чтобы результаты были выведены доходчиво.

— Знаешь что, в порядке «проразмысливания» последней программы скажу, что подобным образом можно было бы программировать печатание разных объявлений. Например, такого-то числа, в таком-то кабинете состоится комсомольское собрание или пионерский сбор. Явка строго обязательна. И в конце — подпись. Программа потребует ввод — где и когда; сами мы изменим значение символьной переменной, которое определяет, что за собрание, — и вперед. Напечатаем столько, что для всей школы хватит.

— Это ты правильно говоришь. Но ты была права и в том, что компьютеры изобретены не только для печатания. Не велико достижение — что-то ввести и сразу выпечатать. Конечно, и это какие-то работы облегчит. Наверно, в любом учреждении приходится печатать, например, приказы о приеме на работу, мало отличающиеся друг от друга. Или приказы об объявлении выговоров.

— Ты считаешь, что выговора так часто объявляют?



— Понятия не имею. Если не нравится, то, пожалуйста, другой пример. Человек хочет ехать в пионерский лагерь и идет к врачу за справкой. Врач смотрит: да, здоров, пускай едет. И запускает свой персональный компьютер, который выпечатывает справку.

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

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

— В таком случае другое дело.

СПИСОК УЧЕНИКОВ НА ДИСКЕ
— Хотя и нельзя считать, что только программы, работающие с диском, самые серьезные, но уметь считывать данные с диска и записывать их туда-обратно очень важно, поэтому посмотрим еще и программу, которая работает с файлом, содержащим список учеников одного класса. Эта программа может создать первоначальный список учеников на диске, может в этот список добавлять сведения о новом ученике или же исключить ученика из списка. Список, хранящийся на диске, содержит фамилию, имя, отчество и дату рождения ученика. Программа, на мой взгляд, несложная, поэтому блок-схему рисовать не стану, давай смотреть текст.

10 REM ПРОГРАММА ДЛЯ РАБОТЫ С ФАЙЛОМ: СПИСОК УЧЕНИКОВ

20 REM F¤ — НАЗВАНИЕ ФАЙЛА, КОТОРОЕ САМА ПРОГРАММА

30 REM ФОРМИРУЕТ ИЗ НОМЕРОВ КЛАССА И ДИСКА

40 REM F И F1 — НОМЕРА ОТКРЫТЫХ ФАЙЛОВ

50 REM U¤ — ФАМИЛИЯ, I¤ — ИМЯ, U¤ — ОТЧЕСТВО

60 REM D¤ — ДАТА РОЖДЕНИЯ В ФОРМЕ: ДД.ММ.ГГ

70 REM R — УКАЗАТЕЛЬ ВЫБРАННОЙ РАБОТЫ

80 REM N — НОМЕРА ШКОЛЬНИКОВ

85 \

90 PRINT "НАЧИНАЕМ РАБОТУ СО СПИСКОМ УЧЕНИКОВ" \ PRINT

100 PRINT "НОМЕР ДИСКА, НА КОТОРОМ НАХОДИТСЯ ФАЙЛ"

110 INPUT D¤

120 PRINT "ВВЕДИТЕ КЛАСС/ НАПРИМЕР: 6А"

125 PRINT "БУКВА ОБЯЗАТЕЛЬНО LATINSKAJA I!! " \ INPUT К¤

130 PRINT \ F¤="DK"+D¤+":"+"FUCH"+K¤

135 \

190 PRINT " ВАШ ВЫБОР \ INPUT R

200 F=1 \ F1=2 \ \ \ REM НОМЕРА ФАЙЛОВ

205 \

210 ON R 60 TO 230,300,370,370,220

215 \

22 °CLOSE \ PRINT "РАБОТУ КОНЧАЮ" x STOP

225 \

230 OPEN F¤ FOR OUTPUT AS FILE F

240 PRINT \ PRINT "НАЧИНАЕТСЯ ВВОД; ЧТОБЫ ЕГО"

250 PRINT "КОНЧИТЬ/ ВВЕДИТЕ # ВМЕСТО ФАМИЛИИ"

260 GOSUB 1000 \ REM ВВОД СВЕДЕНИЙ О ШКОЛЬНИКЕ

270 IF U¤<>"#" THEN 260 \ \ REM КОНЧАТЬ ВВОД?

28 °CLOSE \ GO ТО 140 \ \ REM КОНЧАЕТ ВВОД

285 \

290 REM ПРОСМОТР ФАЙЛА 22222222222222222222222222222

300 OPEN F¤ FOR INPUT AS FILE F1

310 N=0 \ REM N ЭТО НОМЕР ШКОЛЬНИКА

320 GOSUB 2000 \ N=N+1 \ REM СЧИТЫВАЕТ СВЕДЕНИЯ

330 IF U¤="#" THEN 280 \ REM КОНЧАТЬ СЧИТЫВАНИЕ?

340 PRINT N;ТАВ(3);U¤;ТАВ (15);I¤;ТАВ(25);O¤;TAB(35);D¤

350 GO TO 320

355 \

360 REM ЗАНЕСТИ ИЛИ ВЫЧЕРКНУТЬ УЧЕНИКА 34343434343434

370 IF R=4 THEN 400

380 PRINT "ЗАНЕСТИ ПОСЛЕ КАКОГО НОМЕРА";

390 INPUT N \ GO TO 420

400 PRINT " КАКОЙ НОМЕР ВЫЧЕРКНУТЬ"; \ INPUT N

410 N=N-1

420 OPEN F¤ FOR INPUT AS FILE F1

430 OPEN "DK1:RABOT" FOR OUTPUT AS FILE F

440 FOR 1=1 TO N

450 GOSUB 2000 \ \ REM СЧИТЫВАЕТ СВЕДЕНИЯ

460 IF U¤<>"#" THEN 480

470 PRINT "НОМЕР СЛИШКОМ ВЕЛИК" \ GO TO 670

480 GOSUB 3000

490 NEXT I

500 IF R=3 THEN 540 \ REM УХОД НА ЗАПИСЬ

510 GOSUB 2000 \ \ REM СЧИТЫВАЕТ БЕЗ ЗАПИСИ

520 IF U¤="#" THEN 470

530 GO TO 550 \ \ REM ЕЩЕ СЧИТЫВАТЬ ОСТАТОК

540 GOSUB 1000 \ \ REM ВВОД НОВЕНЬКОГО

550 GOSUB 2000 \ \ REM СВЕДЕНИЯ О СЛЕДУЮЩЕМ

560 IF U¤="#" THEN 580

570 GOSUB 3000 \ GO TO 550

580 PRINT #F,U¤ \ \ CLOSE \ \ REM ВСЕ СЧИТАНО

585 \

590 REM С РАБОЧЕГО ФАЙЛА ПЕРЕПИСЫВАЕТ

600 OPEN F¤ FOR OUTPUT AS FILE F

610 OPEN "DK1:RABOT" FOR INPUT AS FILE F1

620 GOSUB 2000 \ \ REM СЧИТЫВАНИЕ С РАБОЧЕГО ФАЙЛА

630 IF U¤="#" THEN 660

640 GOSUB 3000 \ \ REM ЗАПИСЬ В НОВЫЙ ФАЙЛ

650 GO ТО 620

660 PRINT #F,U¤

67 °CLOSE \ KILL "DK1:RABOT" \ GO TO 140

675 \

680 \

1000 PRINT " ФАМИЛИЯ ШКОЛЬНИКА"; \ INPUT U¤

1010 IF U¤<>"#" THEN 1030

1020 PRINT #F, U¤ \ RETURN

1030 PRINT " ЕГО ИМЯ"; \ INPUT l¤

1040 PRINT " ОТЧЕСТВО"; \ INPUT O¤

1050 PRINT " ДЕНЬ РОЖДЕНИЯ"

1090 D¤=D3¤+"."+D2¤+". "+D1¤

1100 IF LEN(D¤)=8 THEN 1120

1110 PRINT " ДЕНЬ РОЖДЕНИЯ НЕПРАВИЛЬНЫЙ" \ GO TO 1050

1120 GOSUB 3000

1130 RETURN

1135 \

1140 \

2000 REM ПОДПРОГРАММА СЧИТЫВАНИЯ ДАННЫХ

2010 INPUT #F1,U¤

2020 IF U¤<>“#“ THEN 2040

2030 RETURN

2040 INPUT #F1,I¤, O¤,D¤

2050 RETURN

2055 \

2060 \

3000 REM ЗАПИСЬ ДАННЫХ НА ДИСК

3010 PRINT #F,U¤ \ PRINT #F,I¤

3020 PRINT #F, 0¤ \ PRINT #F, D¤

3030 RETURN

Сперва, наверное, надо пояснить, как в начале работы программа образует описание файла. Пользователь вводит номер устройства, на котором он поставил диск с файлами классов. Потом он должен ввести номер того класса, со списком учеников которого он хочет работать. Показываем ему и образец, как может выглядеть этот номер, — 6А, но если он введет его в виде А6 — дело хозяйское, главное, чтобы он всегда вводил одинаково. Потом в строке 130 образуется описание файла. Так как описания файлов могут состоять лишь из букв латинского алфавита, мы должны строго предупредить пользователя использовать только эти буквы.

— Что это такое — FUCH?



Файл находят по имени


— Только что об этом хотел говорить. Это сокращение слов «файлы учеников». По этим буквам можно будет в списках файлов уверенно определить, какие из них содержат сведения об учениках. Если пользователь укажет, что диск находится на первом устройстве, и речь идет о классе 581 А, то получится такое описание файла:

DK1:FUCH581A

— Ха-ха-ха! Класса 581 в школе быть не может!

— Ты же должна понимать, что программа не может иметь ни малейшего представления о классах. Только пользователь может придавать этому классу 581А какой-либо смысл, например: это 1а класс 58 средней школы.

Посмотрим дальше, как образуется список. Делается это в подпрограмме, начинающейся со строки 1000.

— Смешно. Вводишь фамилию и сразу сравниваешь с решеткой «#». У кого может быть такая фамилия?

— Этот знак, введенный вместо фамилии, означает конец ввода, или, что то же самое, конец списка учеников. Его мы тоже записываем на диск, чтобы потом, получив при считывании с диска такой знак вместо фамилии, знать, что файл на диске кончился. По этой причине всегда при вводе фамилии или считывании ее с диска мы сразу проверяем, не равна ли она символу «#». Ввод остальных данных попроще. Год рождения или, точнее, его последние две цифры. Месяц рождения. День. Потом эти данные собираем в таком виде, как они будут храниться на диске. Интересно, что эта подпрограмма сама вызывает другую подпрограмму для записи данных на диск. Это допускается.

РАБОТА СО СПИСКОМ
Сейчас о другой возможности — посмотреть список. Это делается, чтобы узнать, что в этом файле хранится. Просто показываются фамилии и другие данные. Никакая обработка не производится. Поэтому и показ программируется просто. Можешь сама посмотреть.

— Подожди, не спеши. Посмотрим подпрограмму в строках 2000–2050. Она сначала считывает фамилию и, если она совпадает с символом «#», кончает свою работу. Все ясно.

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

— Это не проходит и при записи на бумагу. А вот если можно было бы слова, написанные на бумаге, передвигать то влево, то вправо, то вверх, то вниз — вот бы облегчилась жизнь ученика!

— Я не точно выразился. Передвигать данные на диске нельзя технически, а средствами программирования это сделать можно: переписываем файл в другое место и во время переписки добавляем данные о новом ученике. Переписывать же на диске можно, потому что на нем очень легко старую запись стереть и на том же месте записать что-то новое, и так хоть двести раз подряд. Между прочим, Алгоритмыч как-то сказал, что файлы можно организовать и так, что удастся вставлять добавки, не переписывая весь файл, но это уже заметно сложнее…

— И чтобы это понять, нужно кончить физмат? Не так ли?

КАК ДОПОЛНИТЬ СПИСОК
— Да, именно так он и сказал! Но вернемся к программе. Вставляем новые данные в файл таким образом. Сначала считываем файл до того места, где в список будем заносить нового ученика. И не только считываем, но и переписываем в новый файл с описанием «DK1:RABOT». Потом в этот рабочий файл записываем нового ученика при помощи уже разобранной подпрограммы в строках 1000–1130. И, наконец, считываем остаток старого файла снова с записью в рабочий файл. Когда все сделано, данные из рабочего файла переписываем обратно в старый файл и уничтожаем рабочий файл, как ненужный.

— Списываем, записываем, приписываем, переписываем, подписываем, надписываем, выписываем. Как-нибудь по-человечески это изложить нельзя?

— Не знаю. Думаю, что нельзя. Можно только нарисовать схему.



— Сейчас стало понятнее.

— Почти так же вычеркиваем ученика из списка. Только на этот раз данные об этом ученике со старого файла списываем, а в рабочий файл не записываем. И их там не будет. Потом сама посмотри, как это в программе делается. Обязательно посмотри, так как это очень важная программа.

— А что тут такого важного? Обыкновенная программа, и совсем не такая интересная! Ну, записывает на диск. Ну и что?

— А потом же данные можно считать! И с ними сделать все что хочешь! Ты, конечно, спросишь: что можно сделать со списком учеников класса? Правильно. Ничего грандиозного ты с файлом учеников не сделаешь. Но, научившись работать с файлом учеников, ты сможешь на диске создавать файлы с любой информацией на свете и работать с ними.

— Какой бы файл еще создать?… Ученики уже есть… Может быть, учителей?

— Ты, Тоня, лучше думай о том, что нужно сделать, а не о том, что можно было бы сделать. А чтобы это придумать, надо знать и понимать, что с файлами на диске вообще можно делать и, главное, как.



— Но ты же сам говорил, что с файлом учеников ничего особенного сделать нельзя.

— Запомни великую истину, чтобы потом не расстраиваться. Ничего особенного компьютер для тебя не сделает! Но если он сделает вместо тебя что-нибудь не особенное, то у тебя останется больше времени сделать что-то особенное.

— Ну хорошо, и что же мы смогли бы сделать простое?

ДЛЯ ЧЕГО ГОДЕН ТАКОЙ СПИСОК?
— Во-первых, выпечатать списки учеников. Они бывают нужны. Например, едем на экскурсию, надо брать с собой список. Кто-то ведь должен будет его написать. Пусть печатает машина! И для спортивных соревнований, врачебных осмотров, экранов успеваемости — всюду бывают нужны списки учеников.

— Да… На многих экранах успеваемости приходилось в жизни побывать. Когда я была пионеркой, у нас проводились различные соревнования между звеньями. Можно было бы выпечатать списки звеньев, но мы на диске не запоминали номер звена.

— Но никакого запрета не было. Пожалуйста, запоминай. Необходимо, чтобы программа обеспечила ввод номера звена — ввод значения переменной Z или же Z¤. Изменятся подпрограммы: в них появится новая переменная. Кое-что придется изменить и в основной программе.

— Как добавить в программу ввод номера звена, я как-нибудь и сама догадалась бы и могла бы добавить ввод даже двадцати переменных. Я только не знаю, какие нужны.

— Это зависит от твоих целей. От того, что тебе с учениками надо делать. Можешь записать адреса, сведения о родителях. Все равно такие данные школа требует.

— Адреса… Адреса, к слову сказать, имеют составные части. Город, улица, номер дома и квартиры…

— Еще почтовый индекс.

— Да, я тоже его вспомнила. По-видимому, пользователь должен эти составные части вводить по отдельности.

ВВОД ХАРАКТЕРИСТИК УЧЕНИКОВ
— Я тоже так думаю. Посложнее было бы, если бы ты захотела вводить сведения, состоящие из неопределенного количества строк, например характеристику ученика. Тогда можно было бы поступить так. Сначала узнать у пользователя, сколько строк он собирается вводить. А потом написать цикл по строкам. Например, такой:

1500 PRINT «КОЛИЧЕСТВО СТРОК В ХАРАКТЕРИСТИКЕ» \ INPUT 2

1510 PRINT #F, N2

1520 FOR 1 = 1 TO N2

1530 PRINT «ВВЕДИТЕ»;l;«СТРОКУ» \ INPUT R¤

1540 PRINT #F,R¤

1550 NEXT I

1560 RETURN

Так можно было бы дополнить подпрограмму, начинающуюся в строке 1000. Возможен и другой вариант. Ты требуешь, чтобы в конце характеристики пользователь ввел что-нибудь такое, чего в характеристике заведомо не будет, например комбинацию символов «//» или «###» и тому подобное. В этом случае дополнение к подпрограмме могло бы иметь вид:

1500 PRINT «ВВОДИТЕ ХАРАКТЕРИСТИКУ»

1510 PRINT «КОНЕЦ ВВОДА //»

1520 INPUT R¤

1530 PRINT #F,R¤

1540 IF R¤<>«//» THEN 1520

1550 RETURN

Вот так и программируют ввод заранее неизвестного количества строк. Ты заметила, что в первом варианте количество строк я записал на диск?

— Заметила, заметила. Заметила и то, что ты косые черты записал на диск.

— Это для того, чтобы при считывании с диска понять, где кончается характеристика одного ученика и начинается фамилия другого ученика. Ведь на диск записываем только значения переменных, а смысл этих переменных там никак не отражается. Давай, изобразим содержание файла схематически:

Сведения о первом ученике Сведения о втором ученике
Фамиллия Имя Отчество Дата рождения Первая строка характеристики Вторая строка характеристики .. "top" >//
Как видишь, в конце характеристики я написал «//», а в конце файла, если помнишь, ставился символ «#». Выбор символов — дело вкуса, лишь бы не было путаницы.

— При считывании?



Файл состоит из единиц записи


— Так точно! Что ты на диске записала, то и надо будет считывать. Работая с файлом, нужно хорошо знать его структуру. Из чего он состоит, из каких единиц записи. Например, файл со сведениями об учениках FUCH6A состоит из фамилии первого ученика, его имени… и так далее. Все четыре строки символов, ничего не означающие для машины, но для нас имеющие смысл фамилии, имени, отчества и даты рождения, эти четыре строки, вместе взятые, и образуют единицу записи файла. Фактически работа ведется именно с этими единицами записи. Подпрограмма в строках 1000–1130 такую единицу записывает на диск, подпрограмма в строках 2000–2050 ее считывает. Если захочешь составить программу для печати, например, списка учеников, все равно нужно будет запрограммировать считывание целых единиц записи, хотя дату рождения и не собираешься в программе использовать. То, что ты будешь в программе использовать только фамилии и имена, ничего не означает. Изволь считывать всю единицу записи целиком.

ДЕНЬ РОЖДЕНИЯ ДРУГА ЗАБЫТЬ НЕЛЬЗЯ!
Еще мне хочется показать программу, которая проверяет, сколько дней осталось до дня рождения кого-нибудь из одноклассников. Конечно, она использует файл с данными.

10 REM ПРОГРАММА ОПРЕДЕЛЯЕТ БЛИЖАЙШИЙ ДЕНЬ РОЖДЕНИЯ

20 PRINT "СЕГОДНЯШНЕЕ ЧИСЛО ДД-ММ-ГГ" \ INPUT D1¤

30 N=5 \ REM СКОЛЬКО ДНЕЙ ДО ДНЯ РОЖДЕНИЯ

40 PRINT "НОМЕР ДИСКА С ФАЙЛОМ СПИСКА"

50 INPUT D¤

60 PRINT "ВВЕДИТЕ КЛАСС, НАПРИМЕР: 6А"

65 PRINT "БУКВА LATINSKAJA!!!" \ INPUT К¤

70 OPEN "DK"+D¤+":"+"FUCH"+K¤ FOR INPUT AS FILE 1

80 S¤=D¤ \ GOSUB 2000 \ REM ОПРЕДЕЛЯЕТ КОЛ. ДНЕЙ

90 D1=D \ REM И СОХРАНЯЕТ

100 Z=0 \ REM ПОКАЗАТЕЛЬ, НАЙДЕН ЛИ ДЕНЬ РОЖДЕНИЯ

110 G0SUB 1000 \ REM СЧИТЫВАЕТ ЕДИНИЦУ ЗАПИСИ

120 IF U¤<>"#" THEN 160

130 IF Z<>0 THEN 150

140 PRINT " В БЛИЖАЙШЕЕ ВРЕМЯ ДНЕЙ РОЖДЕНИЯ НЕТ"

15 °CLOSE \ STOP

160 S¤=SEG¤(D¤, 1,5)+SEG¤(D1¤x, 6, 8)

170 GOSUB 2000

175 IF D-D1<0 THEN 110

180 IF D-D1>=N THEN 110

190 Z=1 \ REM СИГНАЛ, ЧТО ДЕНЬ РОЖДЕНИЯ НАЙДЕН

200 PRINT l¤;" РОДИЛСЯ";SEG¤(D¤,1,5)

210 GO ТО 110

220 STOP

1000 REM СЧИТЫВАЕТ СВЕДЕНИЯ О ШКОЛЬНИКЕ

1010 INPUT #1,U¤

1020 IF U¤<>“#“ THEN 1040

1030 RETURN

1040 INPUT #1,I¤,O¤,D¤

1050 RETURN

2000 REM ОПРЕДЕЛЯЕТ КОЛИЧЕСТВО ДНЕЙ С НАЧАЛА ВЕКА

2010 DATA 0,31,59,90,120,151,181,212,243,273,304,334

2020 DIM А(12)

2030 RESTORE

2040 FOR I=1 ТО 12 \ READ A(I) \ NEXT I

2050 DEF FND(I)=VAL(SEG¤(S¤,3*I-2,3*I-1))

2060 G=FND(3)

2070 D=G*365+INT(G/4)+A(FND(2))+FND(1)

2080 IF INT(G/4)<>G/4 THEN 2110

2090 IF FND(2)>2 THEN 2110

2100 D=D-1

2110 RETURN

Все операторы этой программы тебе хорошо известны, и ты можешь ее самостоятельно изучить. Единственно, может быть, не поймешь подпрограмму в строках 2000–2110, где рассчитывается, сколько дней прошло с 1 января 1900 года.

— С 1 января 1900 года! Кому нужна такая старина?

— Наш теперешний календарь довольно путаный. Месяцы длиной то 30, то 31 день, плюс еще этот февраль и високосные годы.

— Но тут же ничего нельзя сделать — сам когда-то так выразился.

— Что-нибудь уж можно было бы, но ведь не сделают. Поэтому я должен иметь подпрограмму, рассчитывающую, сколько дней прошло с 1 января 1900 года до сегодняшнего дня и сколько до дня рождения одноклассника, и нахожу разность. Получится, сколько дней осталось. Почему именно с 1 января 1900 года? Думаю, что эта дата совсем не обязательна, но так уж было в той программе, которую мне дали для образца. Понять, как же именно рассчитывается количество прошедших дней, можно, если знать, что каждый четвертый год високосный и числа, которые считываются оператором READ в массив А, выражают количество дней, прошедших с начала года до первого числа соответствующего месяца. Вот и все об этой подпрограмме. А вообще говоря, мы можем эту программу, которая считывает сведения с файла, объединить с той, которая печатает поздравление, и автоматически его напечатать, если день рождения уже близок. Правда, в этом случае единица записи файла должна быть другой и содержать сведения о поздравляемом, нужные для печати — «взрослый» или «ученик», «уважаемый» или «дорогой» и т. д.

— Давай пофантазируем, что машина выпечатывает поздравления не здесь, в машинном зале, а подключается к персональному компьютеру в квартире поздравляемого и печатает там. И даже не печатает, а записывает на диск, что Петя Бейсиков или кто-то другой поздравил. А у того счастливчика имеется программа, которая проверяет, кто поздравил, и посылает ответные поздравления компьютеру, скажем, Пети Бейсикова. Это будет прекрасная жизнь! Никого не надо будет самому поздравлять. Всю дружбу возьмут на себя компьютеры.

— Не хочешь, не делай такие программы поздравлений. Кто тебя заставляет? А представь себе, что на диске хранятся не фамилии, а список работ, которые нужно сделать. И сроки выполнения тоже хранятся там. Тогда машина может печатать не поздравление, а напоминание, что должно быть сделано через столько-то дней. И получится программа контроля выполнения работ. Таких программ уже очень много. Например, я в газете читал о такой программе как о чуде современной техники, и притом чрезвычайно полезном чуде.

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

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

— Неужели?!

— Конечно. Надо только знать, что первый день века был понедельником. Итак, если остаток от деления количества прошедших дней века на семь будет единицей, то сегодня понедельник, если двойкой, то вторник…



— Великолепно! А государственные праздники?

— Их придется разместить в список. Ну, в массив занесешь количество дней с начала года до праздника. Конечно, придется подумать.

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

— Неужели! После стольких разговоров?! Сделаем так. Я до следующего раза обдумаю, где еще нужны файлы, и подготовлю задачи по программированию, оставшиеся в наследство от Алгоритмыча.

— Задачи? Может не надо?

— Нет, надо. Надо хотя бы подумать о том, как их решить.

21. НЕБОЛЬШАЯ ЭКСКУРСИЯ ПО УЛИЦЕ СУВОРОВА

— Тоня, отправимся на экскурсию по улице Суворова.

— Чего это вдруг? А программирование…

— Нет, нет. Никуда ехать не надо. Представим себе, что идем по этой улице, смотрим направо и налево и обсуждаем, где можно использовать ЭВМ и где при этом пригодились бы файлы.

— Это другое дело. Начнем с привокзальной площади.

— На привокзальной площади, каждому ясно, находится вокзал. И там имеется много возможностей использования компьютеров — с файлами и без них. Например, ты хочешь отправиться во Владивосток, но не знаешь, каким поездом, с какого перрона, сколько платить за билет, сколько времени ехать, нужна ли пересадка, и тому подобное. Но, к счастью, в помещениях вокзала ты замечаешь дисплей, на экране которого надпись: ВВЕДИТЕ, В КАКОЙ ГОРОД ХОТИТЕ ЕХАТЬ. Ты сразу хватаешься за клавиатуру и мигом узнаешь все, что нужно. Можешь ли ты после всех этих занятий рассказать, как сделана такая программа информации?




— Там должен быть массив с названиями всех железнодорожных остановок…

— Правильно. И еще?

— Еще массив с… Нет. Несколько массивов. Много массивов. С названиями и номерами поездов, например Рига-Москва 32, с номерами перронов, с ценами на билеты, с временами отправления и всем остальным. Пользователь вводит название города; программа проверяет, есть ли такой город в массиве. Если есть, то из всех массивов выбирает нужную информацию.

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

— Файл с местами… Не понимаю.

— Я это представляю так. Единица ввода такого файла охватывает один вагон, состоит из номера вагона, типа (например, нуль — общий вагон, единица — плацкартный и т. д.), еще чего-то и в самом конце содержит числа, описывающие места (нуль, если место свободное, единица, если занято). Таких чисел должно быть столько же, сколько мест. Например, в купейном вагоне 36 мест. Такая программа была бы не очень простой. Пришлось бы подумать о том, как программировать поиск свободного места; может быть, было бы хорошо где-то отметить, что в вагоне уже нет свободных мест. Еще можно было бы в единице записи указать номер первого свободного места, чтобы не искать по всему вагону.

— Искать — означает сравнивать эти числа с нулем, если нуль — то свободно, ты сказал…

— Ну да. Ты что, не понимаешь?

— Ничего, ничего. Я только громко размышляю.

— Рядом с вокзалом — почта. Здесь можно предложить информационную программу для облегчения подписки на журналы и газеты. Человек приходит на почту, подходит к дисплею, и ему показывают, на какие журналы по садоводству или программированию он может подписаться и сколько это будет стоить.

— Ты что-то не то говоришь. Как ты сможешь определить, о чем журнал? Показ названий ничего не даст, ведь не всегда можно по названию определить, о чем журнал. Скажем, «Огонек». Если кто-то его не знает, то может подумать, что это журнал для пожарников.

— На названия нечего полагаться. Надо на диск записать сведения о журнале, предусматривая в единице записи файла хранение такой информации: название, цена одного номера, количество номеров в год, о чем этот журнал. Скажем, строка символов МО-ОП-МУ-ДЕ-КР могла бы означать — молодежный, общественно-политический, со статьями о музыке, детективами, кроссвордами. Так можно было бы коротко охарактеризовать журнал «Смена». Такие строки мы бы записывали на диск и считывали бы с него, но при показе на экране нужно было бы их расшифровать, чтобы было понятно. Самым трудным при составлении такой программы было бы достаточно полно описать содержание журналов этими строками символов.

— Ладно. Переходим улицу. Там магазины. Гастрономия, напитки, хозтовары, дальше — ткани.

— С точки зрения программирования все магазины почти одинаковы. В файле хранятся сведения о наличии товаров. Получили товар — отмечают в файле. Продали — опять отмечают. Так всегда можно знать, какие товары имеются в магазине, на сколько дней их хватит.

— Ух, и идеализируешь ты сейчас. Так уж там и хотят знать, на сколько дней хватит товара.

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

— Идем дальше. Мастерская оптики, фотоателье…

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

— Теперь гостиница, клуб железнодорожников.

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

— Дальше ничего интересного нет. Магазины, магазины, магазины… А ты их всех отправляешь в один мешок — мешок информации и учета.

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

— Там дальше еще виден кинотеатр, но ясно, что ты не усмотришь никакой разницы между ним и вокзалом. Так что смело можешь объявить: «Уважаемые гости Риги, наша экскурсия закончена. До свидания!»

22. ЧТО ЕЩЕ МОЖНО СДЕЛАТЬ

— Сейчас покажу тебе обещанные задачи. Имеются и простые, и посложнее. Алгоритмыч говорил, что даже начинающий программист должен учиться определять сложность будущей программы — то, сколько времени он будет с нею возиться.

1. Игра с числами. Машина «задумывает» одно число от 1 до 1000. Игрок должен это число угадать максимум за десять попыток. Каждый раз, получив число, программа сообщает, оно больше или меньше «задуманного».

Придумать алгоритм игры.

2. Та же игра, но только сейчас число задумывает игрок, а программа угадывает.

3. Те же игры, что и в предыдущих задачах, но сейчас можно «мухлевать» — один раз за всю игру дать неправильный ответ. Придумать алгоритм игры за угадывающего и задумывающего. Могут быть два варианта игры — когда игрок обязательно один раз за игру «мухлюет» и когда может «мухлевать», а может и не «мухлевать».

4. Спортлото. Составить программы для любителей этой игры. Одну, которая выпечатывает 6 из 45 и 5 из 36 случайных чисел. Вторую, которая на диске собирала бы информацию о всех розыгрышах — какие числа оказались счастливыми, искала бы закономерности в их появлении и потом прогнозировала выигрышные числа следующего розыгрыша.

5. Запрограммировать такую игру: первый игрок называет число в пределах от 1 до 10, второй прибавляет к нему число в пределах от 1 до 10 и сообщает сумму. И так далее. Кто первый из игроков назовет 100, тот победитель. Программа может играть за первого и за второго игрока. Придумать алгоритм, обеспечивающий победу, и запрограммировать его. Составить еще одну программу, которая на победный алгоритм переходила бы не сразу, чтобы противник не догадался, каков алгоритм. А если программа «видит», что противник уже этот алгоритм знает, то, конечно, переходит на победный алгоритм по возможности раньше.

6. Болгарская народная задача. Один крестьянин имеет 25 буйволиц. Первая из них в день дает 1 литр молока, вторая —2 литра, и так далее до двадцать пятой. Крестьянин должен справедливо разделить буйволиц между своими пятью сыновьями, так, чтобы каждый получил одинаковое количество буйволиц и получал одинаковое количество молока в день.

7. Составить программу, которая число от 1 до 10 000, введенное цифрами, выводила бы на русском, английском, немецком языках. Например, вводим «25», программа выводит «двадцать пять». И наоборот — вводим «двадцать пять», выводит «25».

8. Составить программу перевода чисел от 1 до 1000, записанных арабскими цифрами, в числа, записанные римскими цифрами, и наоборот.

9. В машину вводятся три числа. Программа должна определить, могут ли эти числа быть длинами сторон треугольника. Будет ли этот треугольник равносторонним или равнобедренным? Прямоугольным, тупоугольным или остроугольным? Какова его площадь? Найти высоты треугольника. Можно ли из этих высот составить новый треугольник? Если можно, то будет ли этот треугольник равносторонним или равнобедренным? (Квадратный корень вычисляется функцией SQR(X).)

10. Игра «Три дракона». Программа выводит два целых случайных числа в пределах от 1 до 100. Играющий должен ввести третье число. Если все три числа могут быть длинами сторон треугольника, то играющий получает 3 очка, если не годятся, то теряет 33. Если треугольник окажется равнобедренным, то добавляется еще три очка, а если равносторонним, то —33. Если треугольник прямоугольный, то играющему присуждается победа с титулом «троекратный гроссмейстер». Для обычной победы надо собрать 33*3+3 очка. Игра осложняется тем, что могут появиться три дракона. Для того чтобы определить, появится ли какой-нибудь из драконов, выбирается случайное число 1, 2 или 3. Это делается три раза сразу после ввода играющим своего числа. Если в первый раз выпадает 3, то появляется первый дракон. Из основных трех чисел он выбирает то, которое делится на 3 (если такое есть), и уменьшает его на одну треть. Если во второй раз выпадает 3, то появляется второй дракон и увеличивает число, которое делится на три (если такое есть), на одну треть. Если же в третий раз выпадет 3, то третий дракон меньшее число умножает на три.

Если периметр треугольника оказывается равным 33, то выбирается случайное число 1, 2 или 3. Дракон с этим номером проваливается в тартарары — больше появиться не может.

11. Быки и коровы. Программа выбирает четыре случайных числа от 1 до 9 и составляет из них строку символов. Играющий должен ее отгадать, вводя свои предположения. После каждого ввода программа сообщает, сколько цифр угадано точно — сколько «быков», и сколько цифр названы правильно, но помещены в неправильных местах — сколько «коров». Например, программой выбрано число 6834, тогда игра может проходить, например, так:

Догадки Ответы программы
играющего 3333 1 бык
3366 2 коровы
6633 2 быка
7633 1 бык, 1 корова
6833 3 быка
6843 2 быка, 2 коровы
6834 Угадано за 7 ходов
12. Соревнуются два игрока. Первый отворачивается, а второй вводит в машину какое-нибудь слово. Программа гасит экран, перепутывает в слове буквы случайным образом и выводит полученное слово на экран. Например, введено слово КОНКАТЕНАЦИЯ, выводится КАТОКНАЯИЦЕН. Первый игрок должен угадать первоначальное слово и ввести его. Потом игроки меняются местами. Программа находит время, затраченное каждым игроком на обдумывание, и количество ошибок.

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

И — Т--И--Т. Первый игрок угадывает

буквы по одной, и программа определяет, годятся ли они в каком-то месте или нет. Если годятся, то соответствующая черточка заменяется правильной буквой. Фиксируется количество попыток.

14. «Искусственный интеллект». Программа выводит на экран предложение поговорить. Если в ответ вводится предложение, оканчивающееся восклицательным знаком, программа выводит: «Пожалуйста, поспокойнее!» Если в конце предложения вопросительный знак, выводится «Нужно подумать». В других случаях программа с одинаковой вероятностью отвечает: «Да, я об этом слышала» или «Ну и что?» После каждого ответа следует просьба «Поговорим еще, мне скучно».

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

16. Статистическое моделирование. Автомашины одинаковой длины останавливаются на обочине улицы длиной М в случайных местах. Сколько автомашин в среднем вместит такая стоянка, если одна автомашина Занимает К метров? Составить программу для моделирования такой ситуации на ЭВМ: на отрезок [0;1] падают отрезки меньшей длины: К/М. Всякий раз, когда какой-нибудь из них падает на ранее упавший, процесс повторяется. Процесс прекращается, если не осталось сплошного свободного места длиной более К/М. В конце подсчитывается количество маленьких отрезков, вошедших в отрезок [0;1]. Моделирование повторяют 1000 (или более) раз и подсчитывают среднюю вместимость отрезка [0; 1].

17. Составить программу для хранения на диске результатов игр футбольного или хоккейного чемпионата СССР или мира. Программа по требованию должна выпечатывать текущее состояние турнира.

18. На языке эсперанто все глаголы в настоящем времени оканчиваются на — as, в прошедшем на — is. Других слов с такими окончаниями нет. Составить программу, которая текст на языке эсперанто преобразовала бы из прошедшего в настоящее время. Учесть, что после слова может быть не только пробел, но и знаки препинания. Нужно ли знать язык эсперанто для решения этой задачи?

19. Разработать новый язык программирования БОРЯ (Бейсика отображение на русский язык). В этом языке слова в операторах пишутся не на английском, а на русском языке. Например, вместо GO ТО пишется ИДИ НА; вместо RETURN пишется ВОЗВРАТ, и так далее. Составить программу, которая переводила бы программы на Боре в программы на Бейсике. Программа на Боре записана в файле на диске — каждая строка в виде строки символов. И наоборот, на диске записана программа на Бейсике — считать ее, перевести в программу на Боре и записать в файл на диске.

20. Составить 20 программ для обучения и повторения материала уроков текущей четверти. Можно сделать и так, чтобы обучение проходило в виде какой-то игры — подобно игре «Три дракона» (см. задачу 10).


— 20 программ! Ничего не скажешь, остроумно! Больше нельзя было придумать?

— Почему бы и нет! Неужели ты бы не составила?

— Кто его знает… А вообще пора кончать.

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



— Знаешь что! Жизнь прекрасна еще и потому, что человек может программировать!

И так как эту истину первой открыла не она, то ни Петя, ни плескающиеся в лужах воробьи не возражали.

ПАМЯТКА ПРОГРАММИРУЮЩЕМУ НА БЕЙСИКЕ

Слова и символы, включенные в квадратные скобки [], не обязательны;

в угловые скобки <> — поясняют, что в этом месте писать при составлении программы.

НС — произвольный номер строки

ОП — произвольное обозначение переменной или элемента массива

АВ — произвольное арифметическое выражение


ОПЕРАТОРЫ

<ОП>=<АВ> — оператор присвоения

INPUT [#<номер файла>,] <ОП> [,<ОП>…]— оператор ввода

PRINT [#<номер файла>,] <АВ> [,<АВ>…]— оператор вывода

DATA <список значений> — оператор хранения данных

READ <ОП> [,<ОП>…] — чтение данных из хранилища

RESTORE — переход на чтение данных с начала хранилища

IF <условие> THEN <НС> — оператор ветвления (условного перехода)

GO ТО <НС> — оператор безусловного перехода

ON<AB> GO ТО <НС> [,<НС>…] — оператор вычисляемого перехода

GOSUB <НС> — переход на подпрограмму

RETURN — возврат из подпрограммы

FOR <ОП>=<АВ> ТО <АВ> STEP <АВ> — начало цикла

NEXT <ОП> — конец цикла

DIM <описание массива> [,<описание массива>…] — определение массива

DEF FN <буква> [¤] (<аргументы>)=<выражение на Бейсике> — определение функции программиста

OPEN <описание файла> FOR INPUT AS FILE <номер файла> — открытие файла для ввода

OPEN <описание файла> FOR INPUT AS FILE <номер файла> — открытие файла для вывода

CLOSE [<номер файла> [,<номер файла>…]] — закрытие файлов

KILL <описание файла> — стирание файла

REM <текст> — примечание

STOP — логический конец программы

END — физический конец программы


ФУНКЦИИ

ABS(X) — абсолютное значение

INT(<AB>) — целая часть

SGN(<AB>) — знак числа (значения 1,0 или —1)

SQR(<AB>) — квадратный корень

LOG(<AB>) — натуральный логарифм

LOG10(<AB>) — десятичный логарифм

ЕХР(<АВ>) — экспонента

SIN(<AB>) — синус

COS(<AB>) — косинус

ATN(<AB>) — арктангенс

RND — случайное число

PI — число 3.14159

ТАВ(<АВ>) — позиция начала печати

VAL(X¤) — преобразование символьной строки в число

STR¤(<AB>) — преобразование числа в символьную строку

LEN(Х¤) — длина символьной строки

POS(X¤,Y¤,N) — начиная с какого символа строка Y¤ входит в строку X¤; проверка начинается с символа с номером N

SЕG¤(Х¤,М,) — выделение подстроки из строки Х¤ начиная с позиции М и кончая позицией N

СLК¤ — текущее время дня

DАТ¤ — текущая дата


ДИРЕКТИВЫ

NEW<названиe программы> — объявление новой программы

OLD <описание файла> — вызов старой программы в память

SAVE <описание файла> — сохранение программы на диске

LIST[NH] <первый номер группы строк> — <последний номер группы строк> — показ текста программы на экране

RUN[NH] — запуск программы

RESEQ — перенумерация программы

BYE — окончание работы

Редактор В. Парамонова

Художественный редактор И. Егере

Технический редактор И. Васильева

Корректор М. Устинова

Оформление обложки Э.Грикиса

Фото на обложке Ю. Калныня

ИБ № 2854

Сдано в набор 29.05.87 Подписано в печать 29.07.87 Формат 60X84/16. Бумага офсетная № 1. Журнально-рубленная гарнитура. Печать офсетная. 15 физ. печ. л.; 13,95 усл. печ. л.; 42,55 усл. кр. — отт.; 11,09 уч. — изд. л. Тираж 30 000 экз. Заказ № 103391. Цена 60 коп. Издательство «Зинатне», 226530 ГСП Рига, ул. Тургенева, 19. Отпечатано в Рижской Образцовой типографии Государственного комитета Латвийской ССР по делам издательств, полиграфии и книжной торговли, 226004 Рига, Виенибас гатве, 11.

Набор издания подготовлен автором на ЭВМ с использованием диалоговой издательской системы ДИС в Отраслевом вычислительном центре коллективного пользования Госкомиздата ЛатвССР, 226018 Рига, ул. Пушкина, 12. Программисты — А. Овчаренко, Г. Захарычев


Мартузан Б. Я. Как Петя Бейсиков Тоню Соображалкину программировать учил: О программировании вообще и о языке Бейсик в частности. — Рига: Зинатне, 1987.—238 с., ил. 60 к.

Свою книгу о программировании автор адресует учащимся среднего и старшего школьного возраста. И это не случайно. Бруно Мартузан — заведующий лабораторией Вычислительного центра Латвийского государственного университета им. П. Стучки, где он работает свыше четверти века, — много внимания уделяет школьной информатике, занимается ею не только теоретически, но и практически. Несмотря на то что автор впервые выступает в научно-популярном жанре, его книга, вышедшая в свет в 1986 году на латышском языке, на республиканском конкурсе научно-популярной литературы была удостоена диплома первой степени. Проголосовали за нее и читатели: книга, выпущенная тридцатитысячным тиражом, быстро исчезла с книжных прилавков.

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


Оглавление

  • О ЧЕМ ГОВОРИЛИ ТОНЯ И ПЕТЯ, ПРОЧИТАВ ВСЕ ПОСЛЕДУЮЩЕЕ
  • 1. КАК ВСЕ НАЧАЛОСЬ
  • 2. ПЕРВОЕ ЗНАКОМСТВО
  • 3. ТОНЯ УЗНАЕТ, ЧТО ТАКОЕ АЛГОРИТМ
  • 4. ЕЩЁ ОДИН АЛГОРИТМ
  • 5. ЯЗЫКИ, ЯЗЫКИ, ЯЗЫКИ…
  • 6. НАЧИНАЕТСЯ РАБОТА
  • 7. ПЕРВАЯ ПРОГРАММА ТОНИ
  • 8. НЕБОЛЬШАЯ ПОЛЬЗА ОТ ПРОГРАММИРОВАНИЯ
  • 9. ВЕТОК МНОГО-МНОГО, НО НЕ ДЕРЕВО
  • 10. ТОНЯ УЖЕ ЗНАЕТ О ПРОГРАММИРОВАНИИ ВСЕ
  • 11. ДЕЛАЙ КАК Я, ДЕЛАЙ ЛУЧШЕ МЕНЯ!
  • 12. НЕБОЛЬШОЙ ЭКСКУРС В БУХГАЛТЕРСКОЕ ДЕЛО
  • 13. КОМПЬЮТЕР ИЛИ УЧИТЕЛЬ!
  • 14. ГЛАВНОЕ — ЭТО УЧЕТ
  • 15. ВЫЧИСЛИТЕЛЬНАЯ МАШИНА НЕ ТОЛЬКО ВЫЧИСЛЯЕТ
  • 16. РАБОТА СО СЛОВАМИ
  • 17. МАШИНА ОСВАИВАЕТ РУССКИЙ ЯЗЫК
  • 18. ЕЩЁ О ТОМ, КАК КОМПЬЮТЕР УЧИТ ДЕТЕИ
  • 19. ТОНЯ УЗНАЕТ О ФАЙЛАХ
  • 20. ТОНЯ ПРОДОЛЖАЕТ ОСВАИВАТЬ ФАЙЛОЛОГИЮ
  • 21. НЕБОЛЬШАЯ ЭКСКУРСИЯ ПО УЛИЦЕ СУВОРОВА
  • 22. ЧТО ЕЩЕ МОЖНО СДЕЛАТЬ
  • ПАМЯТКА ПРОГРАММИРУЮЩЕМУ НА БЕЙСИКЕ