Программирование на языке Pascal

           

Активная область ввода / вывода


Процедура Window(x1,y1,x2,y2: byte) создаст на экране окно с координатами левого верхнего угла в точке (x1,y1) и координатами правого нижнего угла в точке (x2,y2). Теперь активная область экрана будет ограничена этим окном. Текущие координаты курсора будут отсчитываться не от левого верхнего угла экрана, а от левого верхнего угла этого окна.



Цвета


Процедура TextBackground(color: byte) установит цвет фона.

Процедура TextColor(color: byte) установит цвет выводимого текста.

Замечание: Вместо номера цвета возможно использовать соответствующую константу (см. табл. 14.1).

Таблица 14.1. Стандартные цвета языка Pascal

Стандартная константаНомерЦветСтандартная константаНомерЦвет
black0Черныйdarkgray8Темно-серый
blue1Синийlightblue9Ярко-синий
green2Зеленыйlightgreen10Ярко-зеленый
cyan3Голубойlightcyan11Ярко-голубой
red4Красныйlightred12Розовый
magenta5Фиолетовыйlightmagenta13Ярко-фиолетовый
brown6Коричневыйyellow14Желтый
lightgray7Светло-серыйwhite15Белый

Помимо этого, можно использовать константу blink = 128 (мерцание).



Меню


Меню предоставляет пользователю возможность выбора из нескольких предложенных программой вариантов. Самое простое меню в программе на языке Pascal - это пронумерованный список возможных действий с запросом у пользователя номера выбранного варианта. При обработке этого номера также необходим контроль правильности ввода.

Способы создания более сложных и красивых форм меню мы здесь рассматривать не будем, поскольку современные интерфейсно-ориентированные языки (например, Delphi) предоставляют для этого гораздо более мощные средства. Курсы по этим языкам мы и порекомендуем всем желающим.



Очистка


Процедура ClrScr очистит весь экран (или активное окно); курсор будет помещен в верхний левый его угол.

Процедура ClrEol очистит текущую строку, начиная с текущей позиции курсора и до правого края экрана (окна).

Процедура DelLine удалит строку, в которой находится курсор.

Процедура InsLine очистит текущую строку целиком. Курсор останется на прежней позиции.



Позиционирование


Процедура GotoXY(x,y: byte) переместит курсор в заданную позицию в пределах текущего окна (экрана).

Функция WhereX: byte вычислит положение курсора в текущем окне (или на экране): его горизонтальную составляющую. Напомним, что координата X отсчитывается от левого края экрана (окна).

Функция WhereY: byte вычислит положение курсора в текущем окне (или на экране): его вертикальную составляющую. Напомним, что координата Y отсчитывается от верхнего края экрана (окна).





Пример использования текстовой графики


Задача 1. Написать простейший скрин-сейвер (screen-saver) - программу, предохраняющую монитор от пережигания. Его основными чертами должны стать:

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



Пример пользовательского интерфейса


В качестве примера мы приведем программу, реализующую широко известную игру "Быки и коровы". Эта программа отслеживает все варианты некорректного ввода (первая цифра вводимого числа - не ноль; все цифры различны; вводится именно цифра, а не любой другой символ), а также нажатие клавиш ESCAPE и BACK SPACE.

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

Мы приводим программу в полном, работающем виде, поскольку лишь 10% ее текста не относятся к обеспечению интерфейса:

program bull_and_cow; uses crt; const cifr: set of '0'..'9' = ['0'..'9']; yes: set of char = ['Y','y','Д','д','L','l']; cifr10: set of 0..9 = [0..9]; type cifr_char = '0'..'9'; vector = array[1..10] of 0..9;

var zagadano,popytka: vector; i,j,jj,n: 1..10; flag: boolean; c: cifr_char; c1: char; set_of_popyt,set_of_zagad: set of 0..9; num_of_popyt,cow,bull,err: integer;

procedure error_(st: string; x,y: integer); begin textcolor(lightred); write(' Ошибка: ',st); gotoxy(wherex+x,wherey+y); textcolor(white); flag:= false; end;

function check(cc: char):integer; begin case cc of chr(27) : begin {Escape} check:= 1; textcolor(lightgreen); clreol; write('До свидания? Y/N'); if readkey in yes then begin clrscr; halt end else begin gotoxy(wherex-16,wherey); clreol; end; textcolor(white); end; chr(8) : begin {BackSpace} check:= 2; if j>1 then dec(j); if popytka[j]= zagadano[j] then dec(bull) else if popytka[j] in set_of_zagad then dec(cow); set_of_popyt:= set_of_popyt-[popytka[j]]; gotoxy(wherex-1,wherey); clreol; end; chr(13) : if (j<>n) {Enter} then begin writeln('Недостаточно цифр! Введите число заново.'); gotoxy(1,wherey-1); check:= 3; end; '0'..'9' : begin write(cc); check:= 0; end; else begin write(cc); check:= 4; end; end; {end-of-case} end;


begin clrscr; textcolor(lightmagenta); writeln(' Поиграем в "Быков и коров"?'); textcolor(yellow); writeln(' (бык - это цифра, стоящая на своем месте; а корова - просто верная)'); textcolor(green); writeln(' Итак... Я загадываю число из разных цифр. Вам отгадывать! '); writeln(' (Выход из программы - <ESC> )'); textcolor(cyan); write('Введите количество цифр в угадываемом числе: '); {$I-}; flag:= false; repeat textcolor(white); c1:= readkey; clreol; err:= check(c1); if err= 4 then error_('введена не цифра!',-27,0); if err = 0 then case c1 of '0' : begin writeln; error_('в числе должна быть хотя бы одна цифра!',-3,-1) end; '1' : begin c1:= readkey; flag:= true; case c1 of '0' : begin n:=10; writeln(c1) end; #13 : n:= 1; else begin writeln(c1); error_('в числе может быть не более 10 разных цифр!',-7,-1); end; end;{case} end; else begin val(c1,n,err); flag:= true; end; end; if n>10 then until flag; writeln;
{-- Zagadyvanie chisla --------------------} randomize; zagadano[1]:= random(9)+1; set_of_zagad:=[zagadano[1]]; for i:=2 to n do repeat zagadano[i]:= random(10); if not (zagadano[i] in set_of_zagad) then begin set_of_zagad:= set_of_zagad+[zagadano[i]]; flag:= true; end else flag:=false; until flag;
{--- Game --------------------------} textcolor(lightmagenta); write('Начинаем! '); textcolor(cyan); clreol; writeln('Вводите Ваши числа:'); textcolor(white); num_of_popyt:= 0; flag:= true; repeat {Ввод очередного числа} cow:= 0; bull:= 0; set_of_popyt:= []; j:=1; while j<=n do {Ввод по цифрам} repeat c:= readkey; err:= check(c); clreol; if err = 4 then error_('Введена не цифра! Измените последний символ.',-54,0); if err = 0 then if (c='0')and(j=1) then error_('Первой цифрой не может быть ноль! Повторите ввод.',-59,0) else begin val(c,popytka[j],err); if popytka[j] in set_of_popyt then error_('Одинаковых цифр быть не должно! Измените последнюю цифру.',-67,0) else begin set_of_popyt:= set_of_popyt+[popytka[j]]; flag:= true; if popytka[j]=zagadano[j] then inc(bull) else if popytka[j] in set_of_zagad then inc(cow); inc(j) end; end; until flag;
clreol; readln; textcolor(yellow); gotoxy(n+1,wherey-1); writeln(' Быков - ',bull,'; коров - ',cow); inc(num_of_popyt); textcolor(white); until bull = n; textcolor(green); if bull= n then writeln('Поздравляю! Вы выиграли за ',num_of_popyt,' шагов!'); readln; clrscr end.

Процедуры модуля Crt


В предыдущей лекции мы уже упоминали, что модуль Crt, входящий в состав стандартных библиотек языка Pascal, содержит средства для работы с экраном в текстовом режиме.

Для того чтобы сделать работоспособными все описанные ниже процедуры и функции, ваша программа должна подключить стандартный модуль Crt:

uses crt;



program scrsav; uses crt; var


program scrsav; uses crt; var n,i,x,y,c,t,z: word; err: integer;
begin n:=10; if paramcount>0 then if paramstr(1)='?' then begin writeln('scrsav [density: byte] (=10 by default)'); halt end else begin val(paramstr(1),n,err); if (err<>0)or(n<=0) then n:=10; end; randomize; {активизация генератора случайных чисел} while not keypressed do begin y:= random(24)+1; {генерация случайного числа от 1 до 25} x:= random(79)+1; {генерация случайного числа от 1 до 80} z:= random(220)+33; {генерация случайного символа}
c:= random(14)+1; {генерация случайного цвета от 1 до 15} gotoxy(x,y); textcolor(c); delay(n); write(chr(z)); for i:= 1 to 10 do begin y:= random(24)+1; {генерация случайного числа от 1 до 25} x:= random(79)+1; {генерация случайного числа от 1 до 80} gotoxy(x,y); textcolor(black); delay(n); write(' '); end; end.
Замечание: Параметр, регулирующий густоту и скорость изменения символов на экране, можно задавать как аргумент из командной строки во время вызова программы (см. лекцию 13).

program scrsav; uses crt; var


program scrsav; uses crt; var n,i,x,y,c,t,z: word; err: integer;
begin n:=10; if paramcount>0 then if paramstr(1)='?' then begin writeln('scrsav [density: byte] (=10 by default)'); halt end else begin val(paramstr(1),n,err); if (err<>0)or(n<=0) then n:=10; end; randomize; {активизация генератора случайных чисел} while not keypressed do begin y:= random(24)+1; {генерация случайного числа от 1 до 25} x:= random(79)+1; {генерация случайного числа от 1 до 80} z:= random(220)+33; {генерация случайного символа}
c:= random(14)+1; {генерация случайного цвета от 1 до 15} gotoxy(x,y); textcolor(c); delay(n); write(chr(z)); for i:= 1 to 10 do begin y:= random(24)+1; {генерация случайного числа от 1 до 25} x:= random(79)+1; {генерация случайного числа от 1 до 80} gotoxy(x,y); textcolor(black); delay(n); write(' '); end; end.
Замечание: Параметр, регулирующий густоту и скорость изменения символов на экране, можно задавать как аргумент из командной строки во время вызова программы (см. лекцию 13).

Создание дружественного интерфейса


Напомним, что пользовательский интерфейс - это обеспечение взаимодействия программы и человека1).

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



Текстовый режим


В текстовом режиме единицей вывода информации служит символ. На экране каждый символ занимает одно знакоместо - прямоугольный участок размером 8х8 пикселей (зерен экрана). Во весь экран помещается 80х25 знакомест.

Курсор (мигающий прямоугольник) помечает то место на экране, куда по умолчанию будет осуществлен вывод очередного символа, - текущую позицию. Для определения текущей позиции курсора предназначена сетка координат, мысленно накладываемая на экран. Левое верхнее знакоместо имеет координаты (1,1), правое верхнее - (1,80), левое нижнее - (25,1) и правое нижнее - соответственно (25,80).

Рассмотренные в лекции 6 процедуры write() и writeln() работают именно с текстовым экраном: они выводят информацию посимвольно, начиная с текущей позиции курсора.

Если при выводе информации в текстовый файл любой символ записывается туда в виде своего изображения, то при выводе на экран существуют четыре исключения из этого правила:

Вместо изображения символа #7 компьютер издаст звуковой сигнал.Вместо изображения символа #8 курсор на экране будет передвинут на одну позицию влево.Вместо изображения символа #10 курсор на экране будет передвинут на одну строку вниз.Вместо изображения символа #13 курсор на экране будет передвинут на начало текущей строки.

Остальные символы выводятся на экран в "правильном" виде.



Ввод информации


Язык Pascal относится к процедурно-ориентированным языкам, поэтому последовательность ввода информации жестко задается самой программой2). Эта жесткость накладывает на программиста дополнительные обязательства при оформлении интерфейса.

Пользователь может вводить информацию двумя способами: свободным вводом или выбором из предоставленных возможностей.

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



Вывод информации


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

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

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

Адекватными выполняемой задаче

Это означает, что терминология сообщений должна соответствовать той области, к которой относится задача.

Учитывающими контингент пользователей, на которых рассчитана программа

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

Логично сгруппированными

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

Информативными

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


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

Защита


При свободном вводе пользователь, вообще говоря, может вводить что угодно (а то и вовсе что попало) и совсем не обязательно информацию в ожидаемом программой формате. А в языке Pascal, как мы уже знаем, недопустимы несоответствия типов данных. Например, если не отключен контроль ввода/вывода (см. лекцию 6), то попытка ввести букву "О", когда ожидается цифра "0", приведет к аварийной остановке программы. Еще сложнее бывает разобраться с форматами дат, вещественных чисел (часто вместо десятичной точки пользователи ставят привычную русскому человеку запятую) и т.п.

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

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



Заставка


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

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

название программы;пояснение (краткую или подробную информацию о решаемой задаче);информацию об авторе(-ах) программы;номер версии программы;и т.п.

Заставка может состоять как из отдельного экрана, который исчезает после нажатия произвольной клавиши (его сменяет рабочая область программы), так и лишь из одной строки, которая остается на экране до конца работы программы (или пока ее не вытеснит объемный вывод). Например:

Сортировка линейного массива (до 10 000 элементов) методом пирамиды. Нахождение кратчайшего пути в связном графе. Зодиак. Определение знака гороскопа по дате рождения. Поиграем в крестики-нолики на доске 5х5!



Звук


Процедура Sound(hz: word) включит звуковой сигнал с частотой hz герц.

Процедура NoSound выключит звуковой сигнал.