unit uSystProg;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, sSkinManager, ExtCtrls, StdCtrls, Clipbrd, Buttons,
  XPMan, ShellApi, DBCtrls, Grids, DBGrids, DB, ADODB, RxRichEd, PNGButton,
  Menus, rxDBRichEd, RXDBCtrl, sButton, sBitBtn, mmsystem;

const
  Lett: string = 'ABCDE';
  sItogTest = 'Итоговый тест';

type
  TForm1 = class(TForm)
    sSkinManager1: TsSkinManager;
    lblCaption: TLabel;
    XPManifest1: TXPManifest;
    pnlTest: TPanel;
    lstVopr: TListBox;
    btnTestEnd: TsBitBtn;
    rgOtv: TRadioGroup;
    grpVopr: TGroupBox;
    grpTextVopr: TGroupBox;
    pnlResults: TPanel;
    dsUsers: TDataSource;
    dbgrd1: TDBGrid;
    dbmmoRes1: TDBMemo;
    ADOConnection: TADOConnection;
    tblUsers: TADOTable;
    dsResults: TDataSource;
    tblResults: TADOTable;
    dbgrd2: TDBGrid;
    pnlReg: TPanel;
    bvl1: TBevel;
    lbl1: TLabel;
    btnOk: TsBitBtn;
    btnCancel: TsBitBtn;
    lbl2: TLabel;
    lbl3: TLabel;
    cbbName: TComboBox;
    edtPass: TEdit;
    lblWrongPass: TLabel;
    shp1: TShape;
    dlgFont1: TFontDialog;
    lblFont: TLabel;
    btnWelcome: TPNGButton;
    Shape1: TShape;
    img1: TImage;
    img2: TImage;
    img3: TImage;
    img4: TImage;
    btnRazdel1: TPNGButton;
    btnRazdel2: TPNGButton;
    btnRazdel3: TPNGButton;
    btnResults: TPNGButton;
    btnGame: TPNGButton;
    btnFiles: TPNGButton;
    btnHelp: TPNGButton;
    btnAbout: TPNGButton;
    dlgSave1: TSaveDialog;
    edtVopr: TRxDBRichEdit;
    dsLection: TDataSource;
    tblLection: TADOTable;
    dsLabWork: TDataSource;
    tblLabWork: TADOTable;
    dsTest: TDataSource;
    tblTest: TADOTable;
    dsFile: TDataSource;
    tblFile: TADOTable;
    tblShell: TADOTable;
    dsShell: TDataSource;
    edtText: TRxDBRichEdit;
    rxdbgrdMenu: TDBGrid;
    btnOpen: TsBitBtn;
    btnTestItog: TsBitBtn;
    btnLectFile: TsBitBtn;
    sgCW: TStringGrid;
    tblCW: TADOTable;
    dsCW: TDataSource;
    tmr1: TTimer;
    mmCW: TMemo;
    btnChekCW: TsBitBtn;
    procedure btnRazdel1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure edtTextMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormResize(Sender: TObject);
    procedure lstVoprClick(Sender: TObject);
    procedure rgOtvClick(Sender: TObject);
    procedure btnTestEndClick(Sender: TObject);
    procedure btnWelcomeClick(Sender: TObject);
    procedure btnResultsClick(Sender: TObject);
    procedure btnOkClick(Sender: TObject);
    procedure cbbNameChange(Sender: TObject);
    procedure btnCancelClick(Sender: TObject);
    procedure lblFontClick(Sender: TObject);
    procedure lblFontMouseEnter(Sender: TObject);
    procedure lblFontMouseLeave(Sender: TObject);
    procedure lblFontMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure btnOpenClick(Sender: TObject);
    procedure btnTestItogClick(Sender: TObject);
    procedure btnLectFileClick(Sender: TObject);
    procedure tblLectionAfterScroll(DataSet: TDataSet);
    procedure btnGameClick(Sender: TObject);
    procedure sgCWKeyPress(Sender: TObject; var Key: Char);
    procedure sgCWDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure tmr1Timer(Sender: TObject);
    procedure btnChekCWClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure SetAttr;
    function Shifr(S: string): string;
  end;

var
  Form1: TForm1;
  slVopr, slOtv: TStringList;

implementation

{$R *.dfm}

procedure TForm1.edtTextMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  edtText.Perform(WM_MOUSEACTIVATE, 0, 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
  // Выравнивание элементов управления
  edtText.Left := 10;
  edtText.Top := 138;
  rxdbgrdMenu.Left := edtText.Left;
  rxdbgrdMenu.Top := edtText.Top;
  pnlTest.Left := edtText.Left;
  pnlTest.Top := edtText.Top;
  pnlResults.Left := edtText.Left;
  pnlResults.Top := edtText.Top;
  sgCW.DoubleBuffered := True;
  sgCW.Top := edtText.Top;
  sgCW.Height := 305;
  sgCW.RowCount := tblCW.RecordCount;
  mmCW.Top := sgCW.Top + sgCW.Height;
  mmCW.Height := 121;
  btnChekCW.Top := edtText.Top + 1;
  btnChekCW.Left := edtText.Left + 1;
  // Дублирование "нажатых" изображений кнопок их стандартными изображениями
  for i := 0 to ComponentCount - 1 do
    if Components[i] is TPNGButton then
    begin
      TPNGButton(Components[i]).CaptionDefault := '';
      TPNGButton(Components[i]).PicturePress := TPNGButton(Components[i]).PictureDefault;
    end;
  // Открытие таблиц базы данных
  tblUsers.Open;
  tblResults.Open;
  tblLection.Open;
  tblLabWork.Open;
  tblFile.Open;
  tblShell.Open;
  tblCW.Open;
  // Создание списков строк
  slVopr := TStringList.Create;
  slOtv := TStringList.Create;
  // Вывод приветственного текста
  btnWelcomeClick(btnWelcome);
end;

// Вывод дополнительных текстов оболочки
// Приветствие, справка, об авторах
procedure TForm1.btnWelcomeClick(Sender: TObject);
begin
  if pnlTest.Visible and rgOtv.Enabled then
    Exit;
  PlaySound(PAnsiChar('Windows XP - пуск.wav'), 0, SND_ASYNC);
  btnTestItog.Visible := False;
  btnLectFile.Visible := False;
  sgCW.Visible := False;
  mmCW.Visible := False;
  btnChekCW.Visible := False;
  // Выбор источника данных
  edtText.DataSource := dsShell;
  tblShell.Open;
  // Выбор записи соответственно свойству "Tag" нажатой кнопки
  tblShell.RecNo := TPNGButton(Sender).Tag;
  // Вывести заголовок
  lblCaption.Caption := tblShell.FieldByName('Caption').AsString;
  // Показать элемент отображающий текст
  edtText.Visible := True;
  edtText.BringToFront;
end;

// Отображение меню с темами, соответственно нажатой кнопке раздела

procedure TForm1.btnRazdel1Click(Sender: TObject);
var
  i, h: Integer;
begin
  if pnlTest.Visible and rgOtv.Enabled then
    Exit;
  PlaySound(PAnsiChar('Windows XP - печать завершена.wav'), 0, SND_ASYNC);
  lblCaption.Caption := TPNGButton(Sender).Hint;
  btnTestItog.Visible := False;
  btnLectFile.Visible := False;
  sgCW.Visible := False;
  mmCW.Visible := False;
  btnChekCW.Visible := False;
  case TPNGButton(Sender).Tag of
    1: begin
        rxdbgrdMenu.DataSource := dsLection;
        btnLectFile.Visible := True;
      end;
    2: rxdbgrdMenu.DataSource := dsLabWork;
    3: begin
        rxdbgrdMenu.DataSource := dsLection;
        btnTestItog.Visible := True;
      end;
    4: begin
        rxdbgrdMenu.DataSource := dsFile;
      end;
  end;
  rxdbgrdMenu.Visible := True;
  rxdbgrdMenu.DataSource.DataSet.First;
  btnOpen.Visible := True;
  btnOpen.Tag := TPNGButton(Sender).Tag;
  edtText.Visible := False;
  pnlResults.Visible := False;
  pnlTest.Visible := False;
end;

// Выравнивание размеров элементов после изменения размеров формы

procedure TForm1.FormResize(Sender: TObject);
begin
  rxdbgrdMenu.Columns.Items[1].Width :=
    rxdbgrdMenu.Width - rxdbgrdMenu.Columns.Items[0].Width - 24;
  btnFiles.Left := (ClientWidth div 2) - (btnFiles.Width div 2);
  pnlReg.Left := (ClientWidth div 2) - (pnlReg.Width div 2);
  pnlReg.Top := (ClientHeight div 2) - (pnlReg.Height div 2);
end;

// Выбор пользователем номера вопроса
procedure TForm1.lstVoprClick(Sender: TObject);
begin
  // Поиск вопроса и отображение его текста
  tblTest.Locate('id', slVopr.Strings[lstVopr.ItemIndex], []);
  SetAttr;
  // Установка флага если ответ на вопрос уже дан
  rgOtv.ItemIndex := StrToInt(slOtv.Strings[lstVopr.ItemIndex]);
end;

procedure TForm1.rgOtvClick(Sender: TObject);
begin
  if not rgOtv.Enabled then
    Exit;
  // Запомнить даный пользователем ответ
  slOtv.Strings[lstVopr.ItemIndex] := IntToStr(rgOtv.ItemIndex);
  lstVopr.Items.Strings[lstVopr.ItemIndex] := IntToStr(lstVopr.ItemIndex + 1)
    + '.    ' + Lett[rgOtv.ItemIndex + 1]
end;

// Завершение тестирования, проверка и вывод результатов
procedure TForm1.btnTestEndClick(Sender: TObject);
var
  i, n: Integer;
  s: string;
  slRes: TStringList;
begin
  if Application.MessageBox(PChar('Завершить тестирование?'),
    PChar('Подтверждение'), MB_YESNO) = IDYES then
  begin
    rgOtv.Enabled := False;
    btnTestEnd.Enabled := False;
    n := 0;
    slRes := TStringList.Create;
    for i := 0 to lstVopr.Items.Count - 1 do
    begin
      tblTest.Locate('id', slVopr.Strings[lstVopr.ItemIndex], []);
      edtVopr.SelectAll;
      S := Trim(edtVopr.SelText);
      slRes.Append(IntToStr(i + 1) + '. ' + S);

      if slOtv.Strings[i] <> '-1' then
      begin
        if Lett[StrToInt(slOtv.Strings[i]) + 1] = tblTest.FieldByName('Otv').AsString then
        begin
          lstVopr.Items.Strings[i] := lstVopr.Items.Strings[i] + '   +';
          slRes.Append(Lett[StrToInt(slOtv.Strings[i]) + 1] + ' + ВЕРНО'#13'***');
          Inc(n)
        end else
        begin
          lstVopr.Items.Strings[i] := lstVopr.Items.Strings[i] + '   -';
          slRes.Append(Lett[StrToInt(slOtv.Strings[i]) + 1] + ' - НЕВЕРНО'#13'***');
        end;
      end else
      begin
        lstVopr.Items.Strings[i] := lstVopr.Items.Strings[i] + '   -';
        slRes.Append('? - НЕВЕРНО'#13'***');
      end;
    end;
    i := 0;
    repeat
      s := slRes.Strings[i];
      while Pos(#13#13#9, s) <> 0 do
        Delete(s, Pos(#13#13#9, s), 1);
      slRes.Strings[i] := s;
      Inc(i);
    until i > slRes.Count - 1;
//    ShowMessage(slRes.Text);
    PlaySound(PAnsiChar('tada.wav'), 0, SND_ASYNC);
    ShowMessage('Верных ответов: ' + IntToStr(n));
    // Если тест Итоговый
    if Pos(sItogTest, lblCaption.Caption) <> 0 then
    begin
      slRes.Insert(0, 'Верных ответов: ' + IntToStr(n) + #13);
      // то сохранить результаты базе данных
      tblResults.Append;
      tblResults.FieldByName('idUser').AsInteger := tblUsers.FieldByName('id').AsInteger;
      tblResults.FieldByName('TestData').AsDateTime := Now;
      tblResults.FieldByName('Res').AsString := slRes.Text;
      tblResults.Post;
    end;
    slRes.Free;
  end;
end;

procedure TForm1.btnResultsClick(Sender: TObject);
begin
  PlaySound(PAnsiChar('chimes.wav'), 0, SND_ASYNC);
  lblCaption.Caption := 'Результаты итоговых тестов';
  pnlResults.Visible := True;
  pnlResults.BringToFront;
end;

// Процедура регистрации / авторизации пользователя
procedure TForm1.btnOkClick(Sender: TObject);
var
  i: Integer;
begin
  // Попытка найти пользователя в базе данных и проверить правильность его пароля
  for i := 1 to tblUsers.RecordCount do
  begin
    tblUsers.RecNo := i;
    if AnsiUpperCase(tblUsers.FieldByName('Name').AsString) = AnsiUpperCase(cbbName.Text) then
      if tblUsers.FieldByName('PWord').AsString = edtPass.Text then
      begin
        lblCaption.Caption := sItogTest + ' (' + cbbName.Text + ')';
        lblWrongPass.Visible := False;
        pnlReg.Visible := False;
        pnlTest.Visible := True;
        Exit;
      end else
      begin
        lblWrongPass.Visible := True;
        edtPass.SetFocus;
        Exit;
      end;
  end;
  // Если пользователь не найден
  if Application.MessageBox(PChar('Зарегистрировать Вас под именем ' + cbbName.Text + '?'),
    PChar('Подтверждение'), MB_YESNO) = IDYES then
  begin
    tblUsers.Edit;
    tblUsers.FieldByName('Name').AsString := cbbName.Text;
    tblUsers.FieldByName('PWord').AsString := edtPass.Text;
    tblUsers.Post;
    lblCaption.Caption := sItogTest + ' (' + cbbName.Text + ')';
    lblWrongPass.Visible := False;
    pnlReg.Visible := False;
    pnlTest.Visible := True;
  end;
end;

// Событие резактирования имени пользователя

procedure TForm1.cbbNameChange(Sender: TObject);
begin
  // Управление доступностью кнопки подтверждения ввода пароля
  btnOk.Enabled := Trim(cbbName.Text) <> ''
end;

// Отмена авторизации

procedure TForm1.btnCancelClick(Sender: TObject);
begin
  pnlReg.Visible := False;
end;

// Выбор пользователем гарнитуры и размера шрифта

procedure TForm1.lblFontClick(Sender: TObject);
begin
  if dlgFont1.Execute then
  begin
    SetAttr
  end;
end;

procedure TForm1.lblFontMouseEnter(Sender: TObject);
begin
  lblFont.Font.Color := clBlue;
end;

procedure TForm1.lblFontMouseLeave(Sender: TObject);
begin
  lblFont.Font.Color := clGray;
end;

procedure TForm1.lblFontMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  lblFont.Font.Color := clGreen;
end;

// Установка атрибутов отображаемого текста

procedure TForm1.SetAttr;
begin
  edtText.SelectAll;
  edtText.SelAttributes.Name := dlgFont1.Font.Name;
  edtText.SelAttributes.Size := dlgFont1.Font.Size;
  edtText.SelStart := 0;
  edtText.SelLength := 0;
  edtVopr.SelectAll;
  edtVopr.SelAttributes.Name := dlgFont1.Font.Name;
  edtVopr.SelAttributes.Size := dlgFont1.Font.Size;
  edtVopr.SelStart := 0;
  edtVopr.SelLength := 0;
end;

// Простая процедура шифрования текстовой строки

function TForm1.Shifr(S: string): string;
var
  i: Integer;
begin
  Result := '';
  for i := 1 to Length(S) do
    Result := Result + chr(ord(S[i]) - 1);
end;

// Открытие учебного материала одного из типов...
procedure TForm1.btnOpenClick(Sender: TObject);
var
  S: string;
  VoprCnt, i, k: Integer;
begin
  PlaySound(PAnsiChar('chimes.wav'), 0, SND_ASYNC);

  case TBitBtn(Sender).Tag of
    1: begin // Лекции
        edtText.DataSource := dsLection;
      end;
    2: begin // Лаб. раб.
        edtText.DataSource := dsLabWork;
      end;
    3, 5: begin // Тесты
        lblCaption.Caption := 'Тестирование: ' + tblLection.FieldByName('Caption').AsString; ;
        slVopr.Clear;
        slOtv.Clear;
        lstVopr.Items.Clear;
        tblTest.Close;
        tblTest.Filter := '';
        tblTest.Filtered := False;
        if TBitBtn(Sender).Tag = 5 then
          VoprCnt := 40
        else
        begin
          // Фильтрация вопросов с помощью ссылочной целостности
          VoprCnt := 20;
          tblTest.Filter := 'rLectNum=' + tblLection.FieldByName('Num').AsString;
          tblTest.Filtered := True;
        end;
        tblTest.Open;
        if tblTest.RecordCount < VoprCnt then
          VoprCnt := tblTest.RecordCount;
        Screen.Cursor := crHourGlass;
        // Загрузка идентификаторов вопросов в списки
        for i := 1 to VoprCnt do
        begin
          tblTest.RecNo := i;
          slVopr.Append(tblTest.FieldByName('id').AsString);
          slOtv.Append('-1');
        end;
        // Оставить только vn штук
        Randomize;
        while slVopr.Count > VoprCnt do
        begin
          k := Random(slVopr.Count);
          slVopr.Delete(k);
          slOtv.Delete(k);
        end;
        // Перемешать
        for i := 1 to 1000 do
        begin
          k := Random(slVopr.Count);
          s := slVopr.Strings[k];
          slVopr.Strings[k] := slVopr.Strings[0];
          slVopr.Strings[0] := s;
          s := slOtv.Strings[k];
          slOtv.Strings[k] := slOtv.Strings[0];
          slOtv.Strings[0] := s;
        end;
        Screen.Cursor := crDefault;
        // Вывести список номеров вопросов
        for i := 0 to slVopr.Count - 1 do
          lstVopr.Items.Append(IntToStr(i + 1) + '.    ?');
        rgOtv.Enabled := True;
        btnTestEnd.Enabled := True;
        lstVopr.ItemIndex := 0;
        lstVoprClick(Sender);
        if VoprCnt = 20 then
          pnlTest.Visible := True;
        Exit;
      end;
    4: begin
        // Распаковка и открытие прикреплённых файлов
        dlgSave1.FileName := tblFile.FieldByName('FileName').AsString;
        if dlgSave1.Execute then
        begin
          TBlobField(tblFile.FieldByName('File')).SaveToFile(dlgSave1.FileName);
          ShellExecute(Handle, 'open', pansichar(dlgSave1.FileName), nil, nil, SW_SHOWNORMAL);
          Exit;
        end else Exit;
      end;
  end;
  rxdbgrdMenu.Visible := False;
  btnOpen.Visible := False;
  edtText.Visible := True;
  lblCaption.Caption := rxdbgrdMenu.DataSource.DataSet.FieldByName('Caption').AsString;
  edtText.BringToFront;
end;

// Выбрано итоговое тестирование
procedure TForm1.btnTestItogClick(Sender: TObject);
begin
  // Предварительная загрузка вопросов
  btnOpenClick(btnTestItog);
  // Инициализация диалога авторизации
  cbbName.Items.Clear;
  tblUsers.First;
  while not tblUsers.Eof do
  begin
    cbbName.Items.Append(tblUsers.FieldByName('Name').AsString);
    tblUsers.Next;
  end;
  edtPass.Text := '';
  lblWrongPass.Visible := False;
  // Вывод диалога авторизации перед тестированием
  pnlReg.Visible := True;
  pnlReg.BringToFront;
end;

function GetTempDir: string;
var
  Buffer: array[0..1023] of Char;
begin
  SetString(Result, Buffer, GetTempPath(Sizeof(Buffer) - 1, Buffer));
end;

procedure TForm1.btnLectFileClick(Sender: TObject);
var
  S: string;
begin
  S := GetTempDir + '\SysProg\Present';
  ForceDirectories(S);
  S := S + '\Present' + tblLection.FieldByName('Num').AsString + '.pps';
  TBlobField(tblLection.FieldByName('File')).SaveToFile(S);
  ShellExecute(Handle, 'open', pansichar(S), nil, nil, SW_SHOWNORMAL);
  PlaySound(PAnsiChar('chimes.wav'), 0, SND_ASYNC);
end;

procedure TForm1.tblLectionAfterScroll(DataSet: TDataSet);
begin
  btnLectFile.Enabled := TBlobField(tblLection.FieldByName('File')).BlobSize > 0
end;

procedure TForm1.btnGameClick(Sender: TObject);
begin
  PlaySound(PAnsiChar('chimes.wav'), 0, SND_ASYNC);
  lblCaption.Caption := 'Кроссворд';
  sgCW.Visible := True;
  sgCW.BringToFront;
  mmCW.Visible := True;
  mmCW.BringToFront;
  btnChekCW.Visible := True;
  btnChekCW.BringToFront;
end;

procedure TForm1.sgCWKeyPress(Sender: TObject; var Key: Char);
begin
  Key := AnsiUpperCase(string(Key))[1];
  tblCW.RecNo := sgCW.Row + 1;
  if Trim(tblCW.FieldByName('C' + IntToStr(sgCW.Col + 1)).AsString) = '' then
  begin
    Key := #0;
  end else
    sgCW.Cells[sgCW.Col, sgCW.Row] := Key;

end;

procedure TForm1.sgCWDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
  S: string;
begin
  tblCW.RecNo := ARow + 1;
  S := Trim(tblCW.FieldByName('C' + IntToStr(ACol + 1)).AsString);
  if S = '' then
  begin
    sgCW.Canvas.Brush.Color := $00F5F3F4;
    sgCW.Canvas.Pen.Color := sgCW.Canvas.Brush.Color;
    sgCW.Canvas.Rectangle(Rect.Left, Rect.Top, Rect.Right + 1, Rect.Bottom + 1);
  end else
  begin
    sgCW.Canvas.Brush.Color := clWhite;
    sgCW.Canvas.Pen.Color := clBlack;
    sgCW.Canvas.Rectangle(Rect.Left - 1, Rect.Top - 1, Rect.Right + 1, Rect.Bottom + 1);
    if Length(S) > 1 then
    begin
      Delete(S, 1, 1);
      sgCW.Canvas.Font.Size := 8;
      sgCW.Canvas.Brush.Style := bsClear;
      sgCW.Canvas.TextOut(Rect.Left + 1, Rect.Top - 1, S);
      S := sgCW.Cells[aCol, aRow];
      sgCW.Canvas.Font.Size := 10;
      sgCW.Canvas.Font.Style := [fsbold];
      sgCW.Canvas.TextOut(Rect.Left + ((Rect.Right - Rect.Left) div 2) -
        (sgCW.Canvas.TextWidth(S) div 2), Rect.Bottom - sgCW.Canvas.TextHeight(S), S);
      sgCW.Canvas.Font.Style := [];
      sgCW.Canvas.Brush.Style := bsSolid;
      Exit;
    end;
    S := sgCW.Cells[aCol, aRow];
    sgCW.Canvas.Font.Size := 14;
    sgCW.Canvas.TextOut(Rect.Left + ((Rect.Right - Rect.Left) div 2) -
      (sgCW.Canvas.TextWidth(S) div 2), Rect.Top + 1, S);
  end;
end;

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  if sgCW.Visible then
  begin
    sgCW.Canvas.Lock;
    sgCW.Invalidate;
    sgCW.Canvas.Unlock;
  end;
end;

procedure TForm1.btnChekCWClick(Sender: TObject);
var
  S: string;
  i, j: Integer;
begin
  for j := 1 to tblCW.RecordCount do
  begin
    tblCW.RecNo := j;
    for i := 1 to 38 do
    begin
      S := Trim(tblCW.FieldByName('C' + IntToStr(i)).AsString);
      if S <> '' then
      if AnsiUpperCase(string(S[1])) <> sgCW.Cells[i - 1, j - 1] then
      begin
        sgCW.Col := i - 1;
        sgCW.Row := j - 1;
        ShowMessage('Есть ошибка!');
        sgCW.SetFocus;
        Exit;
      end;
    end;
  end;
  PlaySound(PAnsiChar('tada.wav'), 0, SND_ASYNC);
  ShowMessage('Поздравляем! Вы разгадали весь кроссворд!');
end;

end.

