Вот ее правила. Игровое поле разделено на клетки, за каждой из которых скрыта картинка. Картинки — парные, т. е. на игровом поле есть две клетки, в которых находятся одинаковые картинки. В начале игры все клетки "закрыты". Щелчок левой кнопкой мыши "открывает" клетку, в клетке появляется картинка. Теперь надо найти клетку, в которой находится такая же картинка, как и в открытой клетке. Щелчок к другой клетке открывает вторую картинку (рис. 1.61). Если картинки в открытых клетках одинаковые, то эти клетки "исчезают". Если разные — то клетки остаются открытыми. Очередной щелчок закрывает открытые клетки и открывает следующую. Следует обратить внимание, что две открытые клетки закрываются даже в том случае, если от крытая картинка такая же, как и одна из двух открытых. Игра заканчивается, когда игрок откроет ("найдет") все пары картинок.

Рис. 1.61. Игровое поле программы Парные картинки

Разработайте программу, реализующую игру "Парные картинки". Картинки должны загружаться из файла.

В приведенной реализации игры все картинки квадратные и на ходятся в одном файле (рис. 1.62). Это позволило сделать про грамму "интеллектуальной" — размер игрового поля (количество клеток по горизонтали и вертикали) определяется количеством картинок в файле: зная высоту и ширину картинки в файле, программа вычисляет размер картинок, их количество и уста навливает соответствующий размер игрового поля.

Вид формы программы "Парные картинки" приведен на рис. 1.63.

Рис. 1.62. Все картинки находятся в одном файле

Рис. 1.63. Форма программы Парные картинки

unit dblpic_;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, jpeg, ExtCtrls, Menus;
type
TForml = class (TForm)
Timerl: TTimer;
MainMenul: TMainMenu;
HI; TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormPaint(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button:
TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure TimerlTimer(Sender: TObject);
procedure NIClick(Sender: TObject);
private
I Private declarations }
public
I Public declarations }
end;
// объявление нового типа col_row
col_row = record
col: integer;
row: integer;
end;
const

MAX_SIZE = 32; // максимальное кол-во парных картинок
МАХ_Н =8; // максимальный размер поля — 8x8
M.AXJJ = 8;
var
Forml: TForml;
Pole: array [1..MAX_H,1..MftXJW] of integer;
{ Pole[i,j] < 100 — код картинки, клетка закрыта;
Pole[i,j) > 100 и < 200 - клетка открыта,
игрок видит картинку;
Pole[i,j) > 200 — игрок нашел пару для этой картинки )
Pictures: TBitmap; // картинки, загруженные из файла
n : integer; .// кол-во открытых пар картинок
count: integer; // кол-во открытых в данный момент клеток
openl: col_row; // координаты 1-й открытой клетки
open2: col_row; // координаты 2-й открытой клетки
W: integer; // кол-во клеток по горизонтали
Н: integer; // кол-во клеток по вертикали
// произведение VI и Н должно быть кратно двум
WK: integer; // ширина клетки
НК: integer; // высота клетки
implementation
(SR *.dfm}
// рисует клетку поля
procedure Kletka(col,row: integer);
var
x,y: integer; // левый верхний угол клетки (координаты)
src, dst : Trect; // источник и получатель битового образа
begin
// преобразуем координаты клетки
// в координаты на поверхности формы
х : = (col-l)*WK;
у := (row-l)*HK;
if Pole[col,row] > 200 then
// для этой клетки найдена пара
// клетку надо убрать с поля
begin
// установить цвет границы, закраски и текста
Forml.Canvas.Brush.Color := clBtnFace;
Forml.Canvas.Pen.Color := clBtnFace;
Forml.Canvas.Font.Color : = clBtnFace;
end;
if (Pole[col,row] > 100) and (Pole[col,row] < 200)
then
// клетка открыта — вывести картинку
begin •
// Pole[col,row] = номер картинки + 100,
// где 100 — признак того, что клетка открыта
// определим положение картинки в Pictures
src := Bounds((Pole[col,row]-100 -1)*WK,0,WK,HK);
// координаты картинки (клетки) на форме
dst := Bounds(х,у,HK-2,WK-2) ;
// вывести картинку в клетку
Forml.Canvas.CopyRect(dst,Pictures.Canvas,src) ;
// установить цвет границы и цифры
Forml.Canvas.Pen.Color := clBlack;
Forml.Canvas.Font.Color := clBlack;
Forml.Canvas.Brush.Style := bsClear;
end;
if (Pole[col,row] > 0) and (Pole[col,row] < 100) then
// клетка закрыта, рисуем только контур
begin
Forml.Canvas.Brush.Color := clBtnFace;
Forml.Canvas.Pen.Color := clBlack;
Forml.Canvas.Font.Color := clBtnFace;
end;
// отрисовать клетку
Forml.Canvas.Rectangle(x,у,x+WK-2,y+HK-2);
//Forml. Canvas. TextOut (x+15,y+15, IntToStr (Pole [col, row])),
Forml.Canvas.Brush.Color := clBtnFace;
end;
// отрисовывает поле
procedure ShowPole;
var
row,col: integer;
begin
for row: =1 to H do
for col:=l to W do
Kletka(row,col);
end;
// новая игра
Procedure NewGame;
var
k: integer; // кол-во парных, картинок
r: integer; // случайное число
buf: array[l..MAX_SIZE] of integer;
// в buf[i] записываем, сколько чисел i
// записали в массив Pole
i,j: integer; // индексы массивов
begin
Randomize;
k := Trunc(H*W/2);
for i:=l to k do
buf[i] := 0;
// запишем в массив Pole случайные числа
// от 1 до 2
// каждое число должно быть записано два раза
for i: =1 to H do
for j:=1 to W do
begin
repeat
r := random (k) + 1;
until buf[r] < 2;
Pole[i,j] := r; // код картинки
inc(buf [г] ) ;
end;
// здесь поле сгенерировано
n:=0;
ShowPole;
end;
// создание формы
procedure TForml.FormCreate(Sender: TObject);
var
np: integer; // кол-во парных картинок
begin
Pictures := TBitmap.Create;
// загрузить картинки из файла
Pictures.LoadFromFile('pictures.bmp');

HK := Pictures.Height-1; // высота картинки
WK := HK; // ширина картинки
np:= Round(Pictures.Width / WK);
if np <= 15
then H := 4
else H :=5;
W := Round(np*2/H);
// установить размеры поля
Forml.ClientHeight := H * HK;
Forml.ClientWidth := W * WK;
Forml.Timerl.Enabled := False;
Forml.Timerl.Interval := 200;
n := 0;
NewGame;
end;
// прорисовка клеток на поле
procedure TForml.FormPaint(Sender: TObject);
begin
ShowPole;
end;
// щелчок в клетке
procedure TForml.FormMouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
col_: integer; // номер клетки по горизонтали
row_: integer; // номер клетки по вертикали
begin
col_ := Trunc(X/WK) + 1;
row__ := Trunc(Y/HK) + 1;
if Pole[col_,row_] > 200 then
// щелчок в месте одной из двух
// уже найденных парных картинок
exit;
// открытых клеток нет
if count = 0 then
begin
count : = 1;
openl.col := col_;
openl. row : = row__;
// клетка помечается как открытая
Pole[openl.col,openl.row] := Pole[openl.col,openl.row] + 100;
Kletka(openl.col,openl.row);
exit;
end;
// открыта одна клетка, надо открыть вторую
if count = 1 then begin
open2.col := col_;
open2.row := row_;
// если открыта одна клетка и щелчок сделан
// в этой клетке, то ничего не происходит
if (openl.col = open2.col) and (openl.row = open2.row)
then exit
else begin
count := 2; // теперь открыты две клетки
Pole[open2.col,open2.row] :=
Pole[open2.col,open2.row] + 100;
Kletka(open2.col,open2.row); // отрисуем вторую клетку
// проверим, открытые картинки одинаковые?
if Pole[openl.col,openl.row] = Pole[open2.col,open2.row] then
// открыты две одинаковые картинки
begin
n := n+1;
Forml.Timerl.Enabled := True; // запустить таймер
// процедура обработки события OnTimer
// "сотрет" две одинаковые картинки
end;
end;
exit;
end;
if count = 2 then
begin
// открыты 2 клетки с разными картинками
// закроем их и откроем новую, в которой
// сделан щелчок
// закрыть открытые клетки
Pole[openl.col,openl.row] := Pole[openl.col,openl.row] — 100;
Pole[open2.col,open2.row] := Pole[open2.col,open2.row] —
100;
Kletka(openl.col,openl.row);
Kletka(open2.col,open2.row);
// запись в openl номера текущей клетки
openl.col := col_;
openl.row := row_;
count := 1; // счетчик открытых клеток
// открыть текущую клетку
Pole[openl.col,openl.row] := Pole[openl.col,openl.row] + 100;
Kletka(openl.col,openl.row) ;
end;
end;
// обработка события таймера
procedure TForml.TimerlTimer(Sender: TObject);
begin
// в массиве Pole клетки помечаются как совпавшие
Pole[openl.col,openl.row] := Pole[openl.col,openl.row] + 100;
Pole[open2.col,open2.row] := Pole[open2.col,open2.row] + 100;
count := 0;
// отрисовать клетки
Kletka(open2.col,open2.row) ;
Kletka(openl.col,openl.row);
// остановка таймера
Forml.Timerl.Enabled := False;
if n = Trunc(W*H/2)
then // открыты все пары
begin
Forml.Canvas.Font.Name := 'Times New Roman';
Forml.Canvas.Font.Size := 36;
Forml.Canvas.Font.Color := clBlack;
Forml.Canvas.TextOut(70,160,'Game Over!') ;
Forml.Canvas.Font.Size := 10;
Forml.Canvas.TextOut(120,210,'(с) КультинП.Н., 2003');
end;
end;
// выбор в меню команды Новая игра
procedure TForml.NIClick(Sender: TObject);
begin
Canvas.Rectangle(0,O,ClientWidth,ClientHeight);
NewGame;
end;
end.