Delphi. Учимся на примерах

Парижский Сергей Михайлович

Глава 9

Игра "Угадывание чисел"

 

 

Постановка задачи

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

 

Разработка формы

Создайте новый проект Delphi и присвойте свойству Caption (заголовок) формы значение Игра. Угадывание чисел. Вверху формы будут расположены элементы управления для настройки диапазона угадываемых чисел. Разместим на форме три компонента Label (метки) категории Standard и два компонента Edit (поле ввода) той же категории. Изменим их свойства согласно табл. 9.1.

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

Компонент Свойство Значение Пояснение
Label1 Caption Диапазон чисел: Надпись метки
Font.Style [fsBold] Начертание шрифта — полужирное
Left 8 Отступ слева
Top 16 Отступ сверху
Label2 Caption от Надпись метки
Font.Style [fsBold] Начертание шрифта — полужирное
Left 104 Отступ слева
Top 16 Отступ сверху
Label3 Caption до Надпись метки
Font.Style [fsBold] Начертание шрифта — полужирное
Left 216 Отступ слева
Top 16 Отступ сверху
Edit1 Name start Новое имя поля, предназначенного для ввода начального числа диапазона
Text 1 Содержимое поля
Left 128 Отступ слева
Top 8 Отступ сверху
Width 57 РЁРёСЂРёРЅР°
Edit2 Name finish Новое имя поля, предназначенного для ввода конечного числа диапазона
Text 1000 Содержимое поля
Left 256 Отступ слева
Top 8 Отступ сверху
Width 57 РЁРёСЂРёРЅР°

Разместите на форме под этими компонентами еще один компонент Label, назовите его pl1 (свойство Name), а свойству Caption присвойте значение Первый игрок:. Справа от метки pl1 разместите компонент Edit, свойству Name которого присвойте значение ch1, а свойству Text — значение 0. Справа от поля ch1 разместите еще один компонент Label. Присвойте ему имя znak1 и очистите свойство Caption.

Под компонентами pl1, ch1 и znak1 разместите аналогичные компоненты для второго игрока, присвоив им имена рl2, ch2 и znak2 соответственно. Свойству рl2.Caption присвойте значение Второй игрок:, свойству ch2.Text — значение 0, а свойство znak2.Caption очистите. Поскольку по умолчанию игру будет начинать первый игрок, мы должны заблокировать ввод для второго игрока. Для этого измените значение свойства Enabled для компонентов ch2 и р12 на False.

Разместите на форме справа от компонентов znak1 и znak2 еще один компонент Label и измените его свойства согласно табл. 9.2.

Таблица 9.2. Свойства нового компонента Label

Свойство Значение Пояснение
Name X Новое имя компонента
Caption X Надпись метки
Font.Color clRed Цвет шрифта — красный
Font.Name Courier New Название шрифта
Font.Size 36 Размер шрифта
Font.Style [fsBold] Начертание шрифта — полужирное
Height 54 Высота метки

Ниже всех компонентов разместите компонент Checkbox (флажок) категории Standard. Присвойте его свойству Name значение comp, a свойству Caption — значение Играть против компьютера (проследите также, чтобы свойство Checked было равно False).

Ниже разместите две кнопки (компонент Button категории Standard), присвоив их свойству Caption значения Принять вариант и Новая игра. Полученная форма должна соответствовать рис. 9.1.

Рис. 9.1. Форма для игры "Угадывание чисел"

 

Разработка программного кода

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

var

В Form1: TForm1;

В num, j, i, kolvo, big, small: integer;

 maximum, minimum: array [1..100] of integer; {массивы максимальных и минимальных чисел}

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

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

Объявим эти процедуры как закрытые члены класса формы:

type

В TForm1 = class(TForm)

 …

private

В { Private declarations }

В procedure min();

В procedure max();

public

В { Public declarations }

end;

После этого создадим сами процедуры в разделе implementation:

//процедура нахождения наименьшего числа

procedure TForm1.min ();

begin

В for i:=1 to kolvo do begin

В В for j:=1 to kolvo do begin

   {Если число меньше наименьшего, то оно становится наименьшим}

В В  if minimum[j] > small then small:= minimum[j];

В В end;

В  end;

end;

//процедура нахождения наибольшего числа

procedure TForm1.max();

var temp: integer;

begin

В temp:= StrToInt(finish.Text) ;

В for i:=1 to kolvo do begin

В В for j:=1 to kolvo do begin

В В  if temp > maximum[j] then

    if maximum[j] > 0 then temp:= maximum[j]; {если число больше наибольшего…}

В  end;

В end;

В if ( (temp<>0) and (temp<>StrTolnt(finish.Text) ) ) then

  {… и если число входит в допустимый диапазон, то оно становится наибольшим}

В  big := temp;

end;

Рассмотрим процедуру, которая будет выполняться при создании формы:

procedure TForm1.FormCreate(Sender: TObject);

begin

 Randomize; //включаем генератор случайных чисел

 //загадываем случайное число из заданного диапазона

 num:= Random(StrToInt(finish.Text) – StrToInt(start.Text)) + StrToInt(start.Text);

 kolvo:= 0; //обнуляем количество попыток

 big:= StrToInt(finish.Text); //самое большое число

 small:= StrToInt(start.Text); //самое маленькое число

end;

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

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

procedure TForm1.Button2Click(Sender: TObject);

begin

 //увеличиваем количество попыток на единицу

В kolvo:= kolvo + 1;

 if not comp.Checked then //если идет игра с человеком

В begin

  if pl1.Enabled then begin //если ход первого игрока

  //если вариант больше загаданного числа, ставим знак >

В В if StrToInt(ch1.Text) > num then znak1.Caption:= '>';

  //если вариант меньше загаданного числа, ставим знак <

В В if StrToInt(ch1.Text) < num then znak1.Caption:= '<';

  if StrToInt(ch1.Text) = num then //если число угадано

В В begin

   znak1.Caption:= '='; //изменим знак на "="

   //вместо знака "X" показываем загаданное число

В  В С….Caption:= IntToStr(num);

   //выводим сообщение о победе первого игрока

   ShowMessage('Победил первый игрок!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки')

В  end;

  //передаем ход второму игроку

В  pl1.Enabled:= False;

В  ch1.Enabled:= False;

В  ch2.Enabled:= True;

В  pl2.Enabled:= True;

  Exit; //прерываем выполнение процедуры

В end;

 if pl2.Enabled then begin //если ход второго игрока

  {сравниваем загаданное число с вариантом второго игрока и ставим соответствующий знак}

В  if StrToInt(ch2.Text) > num then znak2.Caption:= '>';

В  if StrToInt(ch2.Text) < num then znak2.Caption := '<';

В В  if StrToInt(ch2.Text) = num then begin

В В В  znak2.Caption := '=';

В В В  x.Caption:= IntToStr(num);

    ShowMessage('Победил второй игрок!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки')

В В  end;

В  end;

  //передаем ход первому игроку

В В СЂl2.Enabled:= False;

В В ch2.Enabled:= False;

В В ch1.Enabled:= True;

В В pl1.Enabled:= True;

В  Exit;

В end;

 if comp.Checked then begin //если игра против компьютера

  {проверяем вариант первого игрока и ставим соответствующий знак}

В  if StrToInt(ch1.Text) > num then znak1.Caption:= '>';

В  if StrToInt(ch1.Text) < num then znak1.Caption:= '<';

В  if StrToInt(ch1.Text) = num then begin

В В  znak1.Caption:= '=';

В В  x.Caption:= IntToStr(num);

   ShowMessage('Вы победили!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки');

В В  Exit;

В  end;

  //если вариант первого игрока больше загаданного числа

В  if znak1.Caption = '>' then begin

   maximum[kolvo]:= StrToInt(ch1.Text); {добавляем в массив наибольших чисел вариант первого игрока}

В В  max();

   //ищем наибольшее число

В  end;

  //если вариант первого игрока меньше загаданного числа

В  if znak1.Caption = '<' then begin

   minimum[kolvo]:= StrToInt(ch1.Text); {добавляем число в массив наименьших чисел, выданных первым игроком}

   min(); //ищем наименьшее число

В В  end;

   //после всех расчетов, компьютер выдает свой вариант

   ch2.Text:= IntToStr(Random(big– small)+ small);

В  end;

  //проверяем вариант компьютера и ставим соответствующий знак

В  if StrToInt(ch2.Text) > num then znak2.Caption:= '>';

В  if StrToInt(ch2.Text) < num then znak2.Caption:= '<';

В  if StrToInt(ch2.Text) = num then begin znak2.Caption:= '=' ;

В  x.Caption:= IntToStr(num);

  ShowMessage('Вы проиграли!' + #13#10 + 'В этот раз победил компьютер!' + #13#10 + ' Число угадано за ' + IntToStr(kolvo) + ' попытки');

В end;

end;

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

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

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

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

Для того чтобы можно было переключаться между режимами игры "с человеком" и "против компьютера", создадим обработчик события OnClick для флажка comp:

procedure TForm1.compClick(Sender: TObject);

begin

 if comp.Checked then begin //если флажок установлен

  //блокируем ввод от второго игрока

В В ch2.Enabled:= False;

В В СЂl2.Enabled:= False;

  //включаем ввод от первого игрока

В В ch1.Enabled:= True;

В В pl1.Enabled:= True;

В end

В else begin

  //если игра идет с человеком, то

  //включаем ввод для второго игрока

В  ch2.Enabled:= True;

В В СЂl2.Enabled:= True;

В end;

end;

Осталось только обработать нажатие кнопки Новая игра:

procedure TForm1.Button1Click(Sender: TObject);

begin

В if ((StrToInt(finish.Text) > StrToInt(start.Text)) and (StrToInt(start.Text) > 0) and (StrToInt(finish.Text) < 60000))

 then {проверяем, не выходит ли заданное пользователем число за допустимые пределы}

  {загадаем случайное число в заданном диапазоне}

  num:= Random(StrToInt(finish.Text) – StrToInt(start.Text)) + StrToInt(start.Text)

 else ShowMessage('Неверный диапазон!');

 //обнуляем все, и придаем программе начальный вид

В znak1.Caption:= '';

В znak2.Caption:= '';

В ch1.Enabled:= True;

В ch2.Enabled:= False;

В pl1.Enabled:= True;

В pl2.Enabled:= False;

В x.Caption:= 'X';

В ch1.Text:= '0';

В ch2.Text:= '0';

 //очистим массивы наибольших и наименьших чисел

В for i:= 1 to kolvo+1 do begin

В  minimum[i]:= 0;

В  maximum[i]:= 0;

  big:= StrToInt(finish.Text); //наибольшее число

  small:= StrToInt(start.Text); //наименьшее число

В end;

 kolvo:= 0; //количество использованных попыток

end;

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

Компилируем и запускаем программу на выполнение. Игра в действии показана на рис. 9.2.

Рис. 9.2. Игра "Угадывание чисел" в действии

 

Полный исходный код модуля

Полный исходный код программного модуля игры "Угадывание чисел" представлен в листинге 9. 1.

Листинг 9.1. Программный модуль игры "Угадывание чисел"

unit Unit1;

interface

uses

В Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;

type TForm1 = class(TForm)

В Button1: TButton;

В Label1: TLabel;

В Label2: TLabel;

В start : TEdit;

В finish: TEdit;

В Label3: TLabel;

В pl1: TLabel;

В ch1: TEdit;

В pl2: TLabel;

В ch2: TEdit;

В comp: TCheckBox;

В Button2: TButton;

В x: TLabel;

В znak1: TLabel;

В znak2: TLabel;

В procedure FormCreate(Sender: TObject);

В procedure compClick(Sender: TObject);

В procedure Button1Click(Sender: TObject);

В procedure Button2Click(Sender: TObject);

private

В { Private declarations }

В procedure min();

В procedure max();

public

В { Public declarations }

end;

var

В Form1: TForm1;

В num, j, i, kolvo, big, small: integer;

 maximum, minimum: array [1..100] of integer; {массивы максимальных и минимальных чисел}

implementation

{$R *.dfm}

//процедура нахождения наименьшего числа

procedure TForm1.min();

begin

В for i:=1 to kolvo do begin

В В for j:=1 to kolvo do begin

   {Если число меньше наименьшего, то оно становится наименьшим}

В В  if minimum[j] > small then small:= minimum[j];

В В end;

В end;

end;

//процедура нахождения наибольшего числа

procedure TForm1.max();

var temp: integer;

begin

В temp:= StrToInt(finish.Text);

В for i:=1 to kolvo do begin

В В for j:=1 to kolvo do begin

В В  if temp > maximum[j] then

    if maximum[j] > 0 then temp:= maximum[j]; {если число больше наибольшего…}

В  end;

В end;

В if ( (temp<>0) and (temp<>StrTolnt(finish.Text)) ) then

  {… и если число входит в допустимый диапазон, то оно становится наибольшим}

В  big:= temp;

end;

procedure TForm1.compClick(Sender: TObject);

begin

 if comp.Checked then begin //если флажок установлен

  //блокируем ввод от второго игрока

В В ch2.Enabled:= False;

В В СЂl2.Enabled:= False;

  //включаем ввод от первого игрока

В В ch1.Enabled:= True;

В В pl1.Enabled:= True;

В end

В else begin

  //если игра идет с человеком, то

  //включаем ввод для второго игрока

В  ch2.Enabled:= True;

В В СЂl2.Enabled:= True;

В end;

end;

procedure TForm1.Button1Click(Sender: TObject);

begin

В if ((StrToInt(finish.Text) > StrToInt(start.Text)) and (StrToInt(start.Text) > 0) and (StrToInt(finish.Text) < 60000))

 then {проверяем, не выходит ли заданное пользователем число за допустимые пределы}

  {загадаем случайное число в заданном диапазоне}

  num:= Random(StrToInt(finish.Text) – StrToInt(start.Text)) + StrToInt(start.Text)

 else ShowMessage('Неверный диапазон!');

 //обнуляем все, и придаем программе начальный вид

В znak1.Caption:= '';

В znak2.Caption:= '';

В ch1.Enabled:= True;

В ch2.Enabled:= False;

В pl1.Enabled:= True;

В pl2.Enabled:= False;

В x.Caption:= 'X';

В ch1.Text:= '0';

В ch2.Text:= '0';

 //очистим массивы наибольших и наименьших чисел

В for i:= 1 to kolvo+1 do begin

В  minimum[i]:= 0;

В  maximum[i]:= 0;

  big:= StrToInt(finish.Text); //наибольшее число

  small:= StrToInt(start.Text); //наименьшее число

В end;

 kolvo:= 0; //количество использованных попыток

end;

procedure TForm1.Button2Click(Sender: TObject);

begin

 //увеличиваем количество попыток на единицу

В kolvo:= kolvo + 1;

 if not comp.Checked then //если идет игра с человеком

В begin

  if pl1.Enabled then begin //если ход первого игрока

  //если вариант больше загаданного числа, ставим знак >

В В if StrToInt(ch1.Text) > num then znak1.Caption:= '>';

  //если вариант меньше загаданного числа, ставим знак <

В В if StrToInt(ch1.Text) < num then znak1.Caption:= '<';

  if StrToInt(ch1.Text) = num then //если число угадано

В В begin

   znak1.Caption:= '='; //изменим знак на "="

   //вместо знака "X" показываем загаданное число

В  В С….Caption:= IntToStr(num);

   //выводим сообщение о победе первого игрока

   ShowMessage('Победил первый игрок!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки')

В  end;

  //передаем ход второму игроку

В  pl1.Enabled:= False;

В  ch1.Enabled:= False;

В  ch2.Enabled:= True;

В  pl2.Enabled:= True;

  Exit; //прерываем выполнение процедуры

В end;

 if pl2.Enabled then begin //если ход второго игрока

  {сравниваем загаданное число с вариантом второго игрока и ставим соответствующий знак}

В  if StrToInt(ch2.Text) > num then znak2.Caption:= '>';

В  if StrToInt(ch2.Text) < num then znak2.Caption := '<';

В В  if StrToInt(ch2.Text) = num then begin

В В В  znak2.Caption := '=';

В В В  x.Caption:= IntToStr(num);

    ShowMessage('Победил второй игрок!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки')

В В  end;

В  end;

  //передаем ход первому игроку

В В СЂl2.Enabled:= False;

В В ch2.Enabled:= False;

В В ch1.Enabled:= True;

В В pl1.Enabled:= True;

В  Exit;

В end;

 if comp.Checked then begin //если игра против компьютера

  {проверяем вариант первого игрока и ставим соответствующий знак}

В  if StrToInt(ch1.Text) > num then znak1.Caption:= '>';

В  if StrToInt(ch1.Text) < num then znak1.Caption:= '<';

В  if StrToInt(ch1.Text) = num then begin

В В  znak1.Caption:= '=';

В В  x.Caption:= IntToStr(num);

   ShowMessage('Вы победили!' + #13#10 + 'Число угадано за ' + IntToStr(kolvo) + ' попытки');

В В  Exit;

В  end;

  //если вариант первого игрока больше загаданного числа

В  if znak1.Caption = '>' then begin

   maximum[kolvo]:= StrToInt(ch1.Text); {добавляем в массив наибольших чисел вариант первого игрока}

В В  max();

   //ищем наибольшее число

В  end;

  //если вариант первого игрока меньше загаданного числа

В  if znak1.Caption = '<' then begin

   minimum[kolvo]:= StrToInt(ch1.Text); {добавляем число в массив наименьших чисел, выданных первым игроком}

   min();//ищем наименьшее число

В В  end;

   //после всех расчетов, компьютер выдает свой вариант

   ch2.Text:= IntToStr(Random(big– small)+ small);

В  end;

  //проверяем вариант компьютера и ставим соответствующий знак

В  if StrToInt(ch2.Text) > num then znak2.Caption:= '>';

В  if StrToInt(ch2.Text) < num then znak2.Caption:= '<';

В  if StrToInt(ch2.Text) = num then begin znak2.Caption:= '=' ;

В  x.Caption:= IntToStr(num);

  ShowMessage('Вы проиграли!' + #13#10 + 'В этот раз победил компьютер!' + #13#10 + ' Число угадано за ' + IntToStr(kolvo) + ' попытки');

В end;

end;

end.

⊚ Р’СЃРµ файлы проекта Рё исполняемый файл рассмотренной программы находятся РЅР° прилагаемом Рє РєРЅРёРіРµ компакт-РґРёСЃРєРµ РІ папке Chapter09.