Постановка задачи
Разработать программу для тестирования знаний в разных областях. Пользователь должен ответить на несколько вопросов, которые случайным образом выбираются из общей базы вопросов. После того как пользователь ответил на все вопросы, программа должна высчитать и выдать результат прохождения теста — процент правильных ответов. Также необходимо дать возможность пользователю подключать внешние файлы, содержащие вопросы и варианты ответов к ним. Для того чтобы пользователь не смог прочитать правильные ответы, следует зашифровать файл с вопросами и ответами.
Структура базы вопросов и ответов
Перед тем как разработать сам тест, разберем содержимое файла, РІ котором Р±СѓРґСѓС‚ храниться РІРѕРїСЂРѕСЃС‹ Рё варианты ответов Рє РЅРёРј. Рто будет ini-файл следующей структуры:
[num]
num=количество вопросов в базе
[Q]
0=Первый вопрос
1=Второй вопрос
[Рђ]
0=0твет к первому вопросу
1=0твет ко второму вопросу
[W1]
0=Неправильный вариант к первому вопросу
1= Неправильный вариант ко второму вопросу
[W2]
0=Неправильный вариант к первому вопросу
1= Неправильный вариант ко второму вопросу
[W3]
0=Неправильный вариант к первому вопросу
1=Неправильный вариант ко второму вопросу
Р’ этом ini-файле шесть разделов: num, Q, A, W1, W2 Рё W3. Как РІС‹ понимаете, если кто-то заглянет РІ этот файл, то уже через несколько РјРёРЅСѓС‚ РѕРЅ будет знать правильные ответы РЅР° РІСЃРµ РІРѕРїСЂРѕСЃС‹. Рђ если РѕРЅ этот файл подкорректирует, то Рё РІРѕРІСЃРµ будет получать только правильные варианты ответов. Для того чтобы этого РЅРµ случилось, РјС‹ будем шифровать нашу базу РІРѕРїСЂРѕСЃРѕРІ. Рто можно сделать СЃ помощью программы Блокнот-шифровальщик, рассмотренной РІ главе 7. Для шифрования выберем небольшое смещение, например, 101. После того как РІС‹ создали РІСЃРµ РІРѕРїСЂРѕСЃС‹ Рё варианты ответов Рє РЅРёРј, РЅРµ забудьте указать количество РІРѕРїСЂРѕСЃРѕРІ РІ разделе num. После этого зашифруйте базу, используя смещение 101.
⊚ Пример зашифрованной базы РІРѕРїСЂРѕСЃРѕРІ/ответов можно найти РЅР° прилагаемом Рє РєРЅРёРіРµ компакт-РґРёСЃРєРµ РІ файле Chapter_13\comp.ini.
Разработка формы
Создайте новый проект Delphi. Присвойте свойству Caption формы значение Tester, а свойству BorderStyle — bsNone. У верхнего края формы разместите компонент Label категории Standard, присвоив его свойству Caption значение Первый вопрос:.
Ниже разместите компонент Memo категории Standard, с помощью которого мы будем отображать текущий вопрос. Присвойте свойству Memo1.Readonly значение True, чтобы пользователь не мог изменить текст вопроса.
Под вопросом будут расположены варианты ответов. Разместите под компонентом Memo1 компонент RadioGroup (группа переключателей) категории Standard и присвойте его свойству Caption значение Варианты ответов:. Разместите на компоненте RadioGroup1 четыре компонента RadioButton (переключатели) категории Standard. Очистите для каждого из них свойство Caption, а свойству Name присвойте значения an1, an2, an3 и an4 соответственно.
В любом месте формы разместите компонент Label, который изначально будет невидимым. Он будет служить для отображения результатов и в последствии будет растянут на всю форму. Установите для него свойства согласно табл. 13.1.
Таблица 13.1. Свойства компонента Label, отображающего результат теста
Свойство | Значение | Пояснение |
Alignment | taCenter | Выравнивание текста — по центру |
Color | clBlack | Цвет фона — черный |
Font.Color | clRed | Цвет текста — красный |
Font.Name | Arial | Название шрифта |
Font.Size | 26 | Размер шрифта |
Font.Style | [fsBold] | Начертание шрифта — полужирное |
Visible | False | При запуске программы метка невидима |
Осуществлять переход к следующему вопросу мы будем с помощью панелей. Разместите под вариантами ответов пять компонентов Panel категории Standard. Для каждой из них присвойте свойству Caption значение Следующий вопрос>>>>>, свойству Color — значение clMaroon, а свойству Font.Color — значение clWhite. Присвойте им имена (свойство Name) p1, р2, p3, р4 и р5. Для того чтобы убрать выпуклость и привести панель к виду стильной кнопки, изменим значение свойства BevelInner на bvRaised, а свойства BevelOuter — на bvLowered. Для всех панелей, кроме p1, присвойте свойству Visible значение False (изначально будет видна только первая панель).
Поскольку в программе будет предусмотрена возможность динамической загрузки базы вопросов/ответов, нам понадобится диалоговое окно открытия файла. Для этого разместим на форме компонент OpenDialog категории Dialogs и присвоим ему имя Open1 (свойство Name). Кроме того, определите в свойстве Filter следующий фильтр: ini-файлы|*.ini|Все файлы|*.*.
Теперь разработаем меню программы. Для этого разместите на форме компонент MainMenu категории Standard и создайте меню в соответствии с рис. 13.1.
⇖ Разработка меню рассматривается РІ главе 6, "Программа просмотра СЂРёСЃСѓРЅРєРѕРІ".
Рис. 13.1. Меню для программы-теста
Полученная форма должна примерно соответствовать рис. 13.2.
Рис. 13.2. Форма программы-теста
Разработка программного кода
Для начала, объявим все глобальные переменные:
var
В Form1: TForm1;
 i, a, n, balls, vopr: integer; {различные счетчики и переменные для подсчета баллов}
 dir, dir2, ss, zz, yes: string; {путь к файлу с вопросами, к программе и расшифрованной базе}
 win: TIniFile; //переменная для работы с ini-файлами
 mass: array[1..100] of integer; {содержит номера уже заданных вопросы, чтобы они не повторялись}
 f1, f2: file of char; //переменные для работы с файлами
 сор: char; //для работы с каждым символом отдельно
Добавим в раздел uses ссылку на модуль IniFiles, который потребуется для работы с классом TIniFile. Мы также разработаем четыре собственные процедуры. Объявим их как закрытые члены класса формы:
type
TForm1 = class(TForm)
 …
private
В {В Private declarations }
 procedure start; //начало теста
 procedure question_select ; //выбор вопроса
 procedure vars(var variant: integer); {сортировка и определение правильного варианта ответа}
 procedureverno() ; {проверка: правильно ли ответил пользователь}
public
В { Public declarations }
end;
Теперь создадим сами процедуры в разделе implementation. Процедура Start:
procedure TForm1.start();
begin
 Randomize; //Включаем генератор случайных чисел
 for i:=1 to n do mass[i] := 0; //n – количеству вопросов
 {$I-} //отключаем контроль ошибок ввода/вывода.
 //делаем все элементы видимыми для пользователя
В Memo1.Visible:= True;
В RadioGroup1.Visible:= True;
В Label1.Visible:= True;
В an1.Visible:= True;
В an2.Visible:= True;
В an3.Visible:= True;
В an4.Visible:= True;
В p1.Visible:= True;
В p2.Visible:= False;
В p3.Visible:= False;
В p4.Visible:= False;
В p5.Visible:= False;
В balls:= 0;
 Label2.Visible:= False; //прячем результаты
 Label1.Caption:= 'Первый вопрос:';
 dir2:= 'C:\base.bsd'; //путь к расшифрованной базе
 //копируем зашифрованную базу на диск С:
В CopyFile(PChar(ss), PChar(dir2), True);
 //связываем переменную f1 с зашифрованным ini-файлом
В AssignFile(f1, ss);
 //связываем переменную f2 с файлом C:\base.bsd
В AssignFile(f2, dir2);
 Reset(f1); //открываем первый файл на чтение
 Rewrite(f2); //второй – на запись
В while not Eof(fl) do
 begin //пока не достигнут конец первого файла
  Read(f1, cop); //считываем один символ из файла
  сор:= Chr(Ord(cop) xor 101); //расшифровываем символ
 Write(f2, сор); //записываем расшифрованный символ в файл
В end;
 CloseFile(f1) ; //закрываем первый файл
 CloseFile(f2); //закрываем второй файл
 {$I+} //включаем контроль ошибок ввода/вывода
 Win := TIniFile.Create(dir2) ; //работаем с ini-файлом
 //считываем количество вопросов в базе
В ss:= Win.ReadString('num', 'num', ss);
 //преобразовываем строку в число и записываем значение в n
В n := StrToInt(ss);
В vopr:=Random(4) + 1;
//случайное число от 1 до 4
 vars(vopr) ; {передаем число процедуре vars, которая сортирует варианты ответов}
end;
Рта процедура начинает РёРіСЂСѓ. Сначала делаем РІСЃРµ элементы видимыми Рё прячем метку, отображающую результат прохождения теста. Затем открываем файл, содержащий РІРѕРїСЂРѕСЃС‹, Рё считываем РёР· него РїРѕ РѕРґРЅРѕРјСѓ символу. Каждый байт расшифровывается РѕСЃРѕР±Рѕ Рё записывается РІ отдельный файл. Далее РјС‹ работаем СЃ расшифрованным файлом как СЃ обычным ini-файлом. Первое, что РјС‹ считываем, — это общее количество РІРѕРїСЂРѕСЃРѕРІ РІ базе.
Теперь очередь процедуры question_select:
procedure TForm1.question_seleСЃt();
label ran ; //метка ran для быстрого перехода
begin
В Randomize;
ran:
 a:=Random(n); //выбираем случайный вопрос из базы
 //проверяем: не задавали ли мы этот вопрос ранее
В for i : =1 to n do
В if mass[i] = a then goto ran;
В for i : =1 to n do
В if mass[i] = 0 then begin
  mass[i] := а; {записываем номер вопроса, чтобы не задавать его больше }
В В Break ;
В end;
 //сбрасываем флажки со всех вариантов ответов
В an1.Checked:= False;
В an2.Checked:= False;
В an3.Checked:= False;
В an4.Checked:= False;
end;
Рта процедура случайным образом выбирает РІРѕРїСЂРѕСЃ. Затем выполняется проверка: РЅРµ задавался ли этот РІРѕРїСЂРѕСЃ ранее. Если РјС‹ нашли РІРѕРїСЂРѕСЃ, который еще РЅРµ был задан, то задаем его Рё помечаем как уже заданный, чтобы РЅРµ задавать его больше РІ текущей сессии.
Процедура verno:
procedure TForm1.verno();
begin
В if an1.Checked then
В В if yes = an1.Caption then balls:= balls + 1;
В if an2.Checked then
В if yes = an2.Caption then balls:= balls + 1;
В if an3.Checked then
В if yes = an3.Caption then balls:= balls + 1;
В if an4.Checked then
В if yes = an4.Caption then balls:= balls + 1;
end;
Здесь мы сравниваем правильный ответ с вариантом, который дал пользователь, и в случае правильного ответа пополняем счетчик правильных ответов.
Процедура vars:
procedure TForm1.vars(var variant: integer);
begin
 //вызываем процедуру выбора случайного вопроса question_select();
В case variant of
В 1:
В В begin
  Win:= TIniFile.Create(dir2); //открываем ini-файл
   //считываем вопрос
В В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
  //считываем правильный вариант ответа
В В В an1.Caption:= Win.ReadString('A', IntToStr(a), an1.Caption);
  //считываем три неверных варианта к данному вопросу
В В В an2.Caption:= Win.ReadString('W1', IntToStr(a), an2.Caption);
В В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
  Win.Free; //освобождаем ini-файл
  //помечаем первый вариант как правильный
В В yes:= an1.Caption;
В end;
В 2:
В В begin
В В Win:= TIniFile.Create(dir2);
В В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В an2.Caption:= Win.Readstring('A', IntToStr(a), an2.Caption);
В В В an1.Caption:= Win.Readstring('W1', IntToStr(a), an1.Caption);
В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
В В В Win.Free;
В В yes: = an2.Caption;
В end;
В 3:
В В begin
В В Win:= TIniFile.Create(dir2);
В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В В an3.Caption:= Win.ReadString('A', IntToStr(a), an3.Caption);
В В an2.Caption:= Win.ReadString('W1', IntToStr(a), an2.Caption);
В В an1.Caption:= Win.ReadString('W2', IntToStr(a), an1.Caption);
В В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
В В Win.Free;
В В yes:= an3.Caption;
В end;
В 4:
В В begin
В В Win:= TIniFile.Create(dir2);
В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В an4.Caption:= Win.ReadString('A', IntToStr(a), an4.Caption);
В В В an2.Caption:= Win.ReadString('Wl', IntToStr(a), an2.Caption);
В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В В an1.Caption:= Win.ReadString('W3', IntToStr(a), an1.Caption);
В В Win.Free;
В В yes:= an4.Caption;
В end;
В end;
end;
Здесь мы вначале запускаем процедуру выбора вопроса. Потом проверяем: какой вариант ответа является правильным. Затем считываем вопрос и варианты ответов к нему. Сортируем и отображаем все это на форме.
Обработчик события создания главной формы будет выглядеть следующим образом:
procedure TForm1.FormCreate(Sender: TObject);
begin
В Randomize;
 //получаем каталог, в котором находится наша программа
В dir:= GetCurrentDir;
 ss:= dir + '\comp.ini'; //путь к базе вопросов
В zz:= ss;
 start(); //начинаем тест
end;
Теперь создадим обработчик события главной формы OnDestroy (возникает при выходе из программы):
procedure TForm1.FormDestroy(Sender: TObject);
begin
 DeleteFile('c:\base.bsd'); //удаляем расшифрованную базу
end;
Теперь обрабатываем команды меню. Обработчик события OnClick для пункта РРіСЂР°→Заново:
procedure TForm1.N1Click(Sender: TObject);
begin
В Randomize;
В ss:= zz;
 start(); //начало теста
end;
Поскольку у нас весь основной код вынесен в процедуры, теперь достаточно только вызвать процедуру начала игры.
Обработчик события OnClick для пункта меню РРіСЂР°→Загрузить базу:
procedure TForm1.N2Click(Sender: TObject);
begin
В Randomize;
 //начинаем обзор с текущего каталога
В Open1.InitialDir:= GetCurrentDir;
 if not Open1.Execute then ShowMessage('Вы не выбрали файл!')
В else begin
 ss:= Open1.FileName; //открываем выбранный файл
 zz:= ss; //запоминаем путь к базе
 start (); //начинаем тест
В end;
end;
Здесь мы предлагаем пользователю выбрать через диалоговое окно обзора ini– или любой другой файл, в котором содержатся зашифрованные вопросы и варианты ответов. Когда пользователь выбрал файл, мы запускаем процедуру start и, тем самым, начинаем тест.
Обработчик события OnClick для пункта меню РРіСЂР°→Выход:
procedure TForm1.N4Click(Sender: TObject);
begin
 Halt; //выход из программы
end;
Теперь обработаем щелчок мышью на панели p1:
procedure TForm1.p1Click(Sender: TObject);
begin
 Label1.Caption:= 'Второй вопрос:';
 verno(); //принимаем вариант ответа
 p1.Visible:= False; //убираем первую панель
 р2.Visible:=True; //активизируем вторую панель
 vopr:= Random(4) +1; //выбираем случайный вариант ответа
 vars(vopr); //задаем вопрос
end;
Здесь мы вначале изменяем заголовок на "Второй вопрос:", после чего принимаем вариант ответа, выбранный пользователем, вызывая процедуру verno.
Затем готовим форму ко второму вопросу: прячем первую панель и выводим вторую. Вызываем процедуру vars, которая выбирает вопрос и отображает его вместе с вариантами ответа.
Обработаем щелчок мышью на второй панели:
procedure TForm1.p2Click(Sender: TObject);
begin
 Label1.Caption:= 'Третий вопрос:';
В verno();
В p2.Visible:= False;
В p3.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr);
end;
Здесь происходит то же самое, что и для панели p1, только надпись метки принимает значение "Третий вопрос", мы прячем вторую "кнопку" и активизируем третью для следующего вопроса.
Аналогичные обработчики события OnClick создаем для третьей и четвертой панелей:
procedure TForm1.p3Click(Sender: TObject);
begin
 Label1.Caption := 'Четвертый вопрос:';
В verno();
В СЂ3.Visible:= False;
В p4.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr) ;
end;
procedure TForm1.p4Click(Sender: TObject);
begin
 Label1.Caption:= 'Пятый вопрос:';
В verno();
В p4.Visible:= False;
В p5.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr);
end;
Для пятой (последней) панели обработчик события OnClick будет выглядеть несколько иначе:
procedure TForm1.p5Click(Sender: TObject);
begin
 //проверяем правильность ответа на последний вопрос
В verno () ;
 //узнаем, сколько баллов набрал пользователь
В ss := IntToStr(balls) ;
 //делаем почти все компоненты невидимыми
В Memo1 . Visible:= False;
В СЂ5.Visible:= False;
В RadioGroup1.Visible:= False;
В Label1.Visible:= False;
В an1.Visible:= False;
В an2.Visible:= False;
В an3.Visible:= False;
В an4.Visible:= False;
 Label2.Visible:=True; //показываем метку с результатом
 Label2.Align := alClient; //растягиваем ее на всю форму
 //Отображаем процент правильных ответов
 Label2.Caption:= 'Правильных ответов' + IntToStr(balls*(100 div 5))+'%';
end;
После проверки правильности ответа на последний вопрос, мы прячем почти все компоненты на форме, оставляя видимой только метку Label2 для вывода результата и меню, чтобы можно было продолжить работу с программой. С помощью метки мы отображаем процент правильных ответов пользователя по формуле: "количество правильных ответов * (100 / количество заданных вопросов)". Пример отображения результата теста представлен на рис. 13.3.
Рис. 13.3. Отображение результата теста
Единственное, что осталось сделать, — реализовать имитацию нажатия кнопки при щелчке на панели мышью. Для того чтобы "оживить" панель, для нее следует создать обработчики двух событий: OnMouseDown и OnMouseUp. Первое событие возникает при щелчке мышью, а второе — при отпускании кнопки мыши. Для панели pi эти обработчики будут выглядеть следующим образом:
procedure TForm1.p1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p1.BevelInner:= bvLowered;
В p1.BevelOuter:= bvRaised;
end;
procedure TForm1.p1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p1 . BevelInner:=bvRaised;
В p1.BevelOuter:=bvLowered;
end;
Для всех остальных панелей обработчики этих событий будут выглядеть аналогичным образом за исключением того, что имя p1 потребуется изменить на имя р2, p3, р4 или р5.
Программа тестирования в действии показана на рис. 13.4.
Рис. 13.4. Программа тестирования в действии
Полный исходный код модуля
Полный код модуля программы-теста представлен в листинге 13.1.
Листинг 13.1. Модуль программы-теста
unit Unit1;
interface
uses
В Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, IniFiles, jpeg, Menus;
type TForm1 = class(TForm)
В Memo1: TMemo;
В RadioGroup1: TRadioGroup;
В p1: TPanel;
В p2: TPanel;
В p3: TPanel;
В p4: TPanel;
В p5: TPanel;
В an1: TRadioButton;
В an2: TRadioButton;
В an3: TRadioButton;
В an4: TRadioButton;
В Label1: TLabel;
В Label2: TLabel;
В MainMenu1:В TMainMenu;
В N1: TMenuItem;
В N2: TMenuItem;
В N3: TMenuItem;
В N4: TMenuItem;
В Open1: TOpenDialog;
В procedure FormCreate(Sender: TObject);
В procedure p1Click(Sender: TObject);
В procedure p2Click(Sender: TObject);
В procedure p3Click(Sender: TObject);
В procedure p4Click(Sender: TObject);
В procedure p5Click(Sender: TObject);
В procedure Image1Click(Sender: TObject);
В procedure p1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p3MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p3MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p4MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p5MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure p5MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
В procedure N1Click(Sender: TObject);
В procedure N2Click(Sender: TObject);
В procedure N4Click(Sender: TObject);
В procedure FormDestroy(Sender: TObject);
private
В {В Private declarations }
 procedure start; //начало теста
 procedure question_select; //выбор вопроса
 procedure vars(var variant: integer); {сортировка и определение правильного варианта ответа}
 procedureverno(); {проверка: правильно ли ответил пользователь}
public
В { Public declarations }
end;
var
В Form1: TForm1;
 i, a, n, balls, vopr: integer; {различные счетчики и переменные для подсчета баллов}
 dir, dir2, ss, zz, yes: string; {путь к файлу с вопросами, к программе и расшифрованной базе}
 win: TIniFile; //переменная для работы с ini-файлами
 mass: array[1..100] of integer; {содержит номера уже заданных вопросы, чтобы они не повторялись}
 f1, f2: file of char; //переменные для работы с файлами
 сор: char; //для работы с каждым символом отдельно
implementation
{$R *.dfm}
procedure TForm1.vars(var variant: integer);
begin
 //вызываем процедуру выбора случайного вопроса question_select();
В case variant of
В 1:
В В begin
  Win:= TIniFile.Create(dir2); //открываем ini-файл
   //считываем вопрос
В В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
  //считываем правильный вариант ответа
В В В an1.Caption:= Win.ReadString('A', IntToStr(a), an1.Caption);
  //считываем три неверных варианта к данному вопросу
В В В an2.Caption:= Win.ReadString('W1', IntToStr(a), an2.Caption);
В В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
  Win.Free; //освобождаем ini-файл
  //помечаем первый вариант как правильный
В В yes:= an1.Caption;
В end;
В 2:
В В begin
В В Win:= TIniFile.Create(dir2);
В В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В an2.Caption:= Win.Readstring('A', IntToStr(a), an2.Caption);
В В В an1.Caption:= Win.Readstring('W1', IntToStr(a), an1.Caption);
В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
В В В Win.Free;
В В yes: = an2.Caption;
В end;
В 3:
В В begin
В В Win:= TIniFile.Create(dir2);
В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В В an3.Caption:= Win.ReadString('A', IntToStr(a), an3.Caption);
В В an2.Caption:= Win.ReadString('W1', IntToStr(a), an2.Caption);
В В an1.Caption:= Win.ReadString('W2', IntToStr(a), an1.Caption);
В В В an4.Caption:= Win.ReadString('W3', IntToStr(a), an4.Caption);
В В Win.Free;
В В yes:= an3.Caption;
В end;
В 4:
В В begin
В В Win:= TIniFile.Create(dir2);
В В Memo1.Text:= Win.ReadString('Q', IntToStr(a), Memo1.Text);
В В an4.Caption:= Win.ReadString('A', IntToStr(a), an4.Caption);
В В В an2.Caption:= Win.ReadString('Wl', IntToStr(a), an2.Caption);
В В an3.Caption:= Win.ReadString('W2', IntToStr(a), an3.Caption);
В В В an1.Caption:= Win.ReadString('W3', IntToStr(a), an1.Caption);
В В Win.Free;
В В yes:= an4.Caption;
В end;
В end;
end;
procedure TForm1.start();
begin
 Randomize; //Включаем генератор случайных чисел
 for i:=1 to n do mass[i] := 0; //n – количеству вопросов
 {$I-} //отключаем контроль ошибок ввода/вывода.
 //делаем все элементы видимыми для пользователя
В Memo1.Visible:= True;
В RadioGroup1.Visible:= True;
В Label1.Visible:= True;
В an1.Visible:= True;
В an2.Visible:= True;
В an3.Visible:= True;
В an4.Visible:= True;
В p1.Visible:= True;
В p2.Visible:= False;
В p3.Visible:= False;
В p4.Visible:= False;
В p5.Visible:= False;
В balls:= 0;
 Label2.Visible:= False; //прячем результаты
 Label1.Caption:= 'Первый вопрос:';
 dir2:= 'C:\base.bsd'; //путь к расшифрованной базе
 //копируем зашифрованную базу на диск С:
В CopyFile(PChar(ss), PChar(dir2), True);
 //связываем переменную f1 с зашифрованным ini-файлом
В AssignFile(f1, ss);
 //связываем переменную f2 с файлом C:\base.bsd
В AssignFile(f2, dir2);
 Reset(f1); //открываем первый файл на чтение
 Rewrite(f2); //второй – на запись
В while not Eof(fl) do
 begin //пока не достигнут конец первого файла
  Read(f1, cop); //считываем один символ из файла
  сор:= Chr(Ord(cop) xor 101); //расшифровываем символ
 Write(f2, сор); //записываем расшифрованный символ в файл
В end;
 CloseFile(f1); //закрываем первый файл
 CloseFile(f2); //закрываем второй файл
 {$I+} //включаем контроль ошибок ввода/вывода
 Win:= TIniFile.Create(dir2); //работаем с ini-файлом
 //считываем количество вопросов в базе
В ss:= Win.ReadString('num', 'num', ss);
 //преобразовываем строку в число и записываем значение в n
В n:= StrToInt(ss);
В vopr:=Random(4) + 1;
//случайное число от 1 до 4
 vars(vopr); {передаем число процедуре vars, которая сортирует варианты ответов}
end;
procedure TForm1.question_seleСЃt();
label ran; //метка ran для быстрого перехода
begin
В Randomize;
ran:
 a:=Random(n); //выбираем случайный вопрос из базы
 //проверяем: не задавали ли мы этот вопрос ранее
В for i:=1 to n do
В if mass[i] = a then goto ran;
В for i:=1 to n do
В if mass[i] = 0 then begin
  mass[i]:= а; {записываем номер вопроса, чтобы не задавать его больше }
В В Break;
В end;
 //сбрасываем флажки со всех вариантов ответов
В an1.Checked:= False;
В an2.Checked:= False;
В an3.Checked:= False;
В an4.Checked:= False;
end;
procedure TForm1.verno();
begin
В if an1.Checked then
В В if yes = an1.Caption then balls:= balls + 1;
В if an2.Checked then
В if yes = an2.Caption then balls:= balls + 1;
В if an3.Checked then
В if yes = an3.Caption then balls:= balls + 1;
В if an4.Checked then
В if yes = an4.Caption then balls:= balls + 1;
end;
procedure TForm1.N2Click(Sender: TObject);
begin
В Randomize;
 //начинаем обзор с текущего каталога
В Open1.InitialDir:= GetCurrentDir;
 if not Open1.Execute then ShowMessage('Вы не выбрали файл!')
В else begin
 ss:= Open1.FileName; //открываем выбранный файл
 zz:= ss; //запоминаем путь к базе
 start(); //начинаем тест
В end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
В Randomize;
 //получаем каталог, в котором находится наша программа
В dir:= GetCurrentDir;
 ss:= dir + '\comp.ini'; //путь к базе вопросов
В zz:= ss;
 start(); //начинаем тест
end;
procedure TForm1.p1Click(Sender: TObject);
begin
 Label1.Caption:= 'Второй вопрос:';
 verno(); //принимаем вариант ответа
 p1.Visible:= False; //убираем первую панель
 р2.Visible:=True; //активизируем вторую панель
 vopr:= Random(4) +1; //выбираем случайный вариант ответа
 vars(vopr); //задаем вопрос
end;
procedure TForm1.p2Click(Sender: TObject);
begin
 Label1.Caption:= 'Третий вопрос:';
В verno();
В p2.Visible:= False;
В p3.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr);
end;
procedure TForm1.p3Click(Sender: TObject);
begin
 Label1.Caption:= 'Четвертый вопрос:';
В verno();
В СЂ3.Visible:= False;
В p4.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr);
end;
procedure TForm1.p4Click(Sender: TObject);
begin
 Label1.Caption:= 'Пятый вопрос:';
В verno();
В p4.Visible:= False;
В p5.Visible:= True;
В vopr:= Random(4) + 1;
В vars(vopr);
end;
procedure TForm1.p5Click(Sender: TObject);
begin
 //проверяем правильность ответа на последний вопрос
В verno() ;
 //узнаем, сколько баллов набрал пользователь
В ss:= IntToStr(balls);
 //делаем почти все компоненты невидимыми
В Memo1.Visible:= False;
В СЂ5.Visible:= False;
В RadioGroup1.Visible:= False;
В Label1.Visible:= False;
В an1.Visible:= False;
В an2.Visible:= False;
В an3.Visible:= False;
В an4.Visible:= False;
 Label2.Visible:=True;//показываем метку с результатом
 Label2.Align:= alClient;//растягиваем ее на всю форму
 //Отображаем процент правильных ответов
 Label2.Caption:= 'Правильных ответов' + IntToStr(balls*(100 div 5))+'%';
end;
procedure TForm1.N4Click(Sender: TObject);
begin
 Halt; //выход из программы
end;
procedure TForm1.p1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p1.BevelInner:= bvLowered;
В p1.BevelOuter:= bvRaised;
end;
procedure TForm1.p1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p1.BevelInner:=bvRaised;
В p1.BevelOuter:=bvLowered;
end;
procedure TForm1.p2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p2.BevelInner:= bvLowered;
В p2.BevelOuter:= bvRaised;
end;
procedure TForm1.p2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p2.BevelInner:=bvRaised;
В p2.BevelOuter:=bvLowered;
end;
procedure TForm1.p3MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p3.BevelInner:= bvLowered;
В p3.BevelOuter:= bvRaised;
end;
procedure TForm1.p3MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p3.BevelInner:=bvRaised;
В p3.BevelOuter:=bvLowered;
end;
procedure TForm1.p4MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p4.BevelInner:= bvLowered;
В p4.BevelOuter:= bvRaised;
end;
procedure TForm1.p4MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p4.BevelInner:=bvRaised;
В p4.BevelOuter:=bvLowered;
end;
procedure TForm1.p5MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p5.BevelInner:= bvLowered;
В p5.BevelOuter:= bvRaised;
end;
procedure TForm1.p5MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
В p5.BevelInner:=bvRaised;
В p5.BevelOuter:=bvLowered;
end;
procedure TForm1.N1Click(Sender: TObject);
begin
В Randomize;
В ss:= zz;
 start(); //начало теста
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
 DeleteFile('c:\base.bsd'); //удаляем расшифрованную базу
end
end.
⊚ Р’СЃРµ файлы проекта Рё исполняемый файл рассмотренной программы находятся РЅР° прилагаемом Рє РєРЅРёРіРµ компакт-РґРёСЃРєРµ РІ папке Chapter_13.