с графикой, использование рекурсии, доступ
Листинг 10.12.
Модуль главной формы (saperXcpp),
/* Игра "Сапер". Демонстрирует работу с графикой, использование рекурсии, доступ к файлу справочной информации. */ #include <vcl.h>
#include <stdlib.h>
// для доступа к ГСЧ #include <time.h>
#linclude <stdio.h>
#pragma hdrstop #include "saper_.h" #include "saper_2.cpp" #pragma package(smart_init) #pragma resource "*.dfm" TForml *Forml; // главное окно fastcall TForml::TForml(TComponent* Owner) : TForm(Owner) { } fdefine MR 10 // кол-во клеток- по вертикали fdefine MC 10 // кол-во клеток по горизонтали idefine MM 10 // кол-во мин int Pole[MR+2][МС+2]; // минное поле // 0..8 — количество мин в соседних клетках // 9 — в клетке мина // 100..109 — клетка открыта // 200..209 — в клетку поставлен флаг int nMin; // кол-во, найденных мин int nFlag; // кол-во поставленных флагов int status =0; //0 — начало игры; 1 — игра; 2 — результат // смещение игрового поля относительно левого верхнего угла // поверхности формы tdefine LEFT 0 // по X Idefine ТОР 1 // по Y ttdefine W 40 // ширина клетки поля #define H 40 // высота клетки поля void __fastcall NewGameO; // новая игра — "разбрасывает" мины void __fastcall Open(int row, int col);
/* открывает текущую и соседние пустые клетки */ // нажатие кнопки мыши на игровом поле void __fastcall TForml: :FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int x, int y) {
if ( status == 2) return; if ( status == 0) status = 1; x -= LEFT; у -= TOP; if (x >
0 && у >
0) { // преобразуем координаты мыши // в индексы клетки поля int row = y/H + 1; int col = x/W + 1; if (Button = mbLeft) { if ( Pole[row][col] == 9) { Pole[row][col] +=100; status =2; // игра закончена ShowPole(status);
} else if ( Pole[row][col] < 9) { Open(row,col);
ShowPole(status);
} } else if (Button == mbRight) { nFlag++; if ( Pole[row][col] = 9) nMin++; Pole[row][col] += 200; // поставили флаг if (nMin == NM && nFlag == MM) { status = 2; // игра закончена ShowPole(status);
} else Kletka(row, col, status);
} } } // Функция обработки события OnCreate обычно используется // для инициализации глобальных переменных void__fastcall TForml::FormCreate(TObject *Sender) { // В неотображаемые эл-ты массива, которые соответствуют // клеткам по границе игрового поля, запишем число -3. // Это значение используется функцией Open для завершения // рекурсивного процесса открытия соседних пустых клеток. for ( int row=0; row <= MR+1; row++) for ( int col=0; col <= MC+1; col++) Pole[row][col] = -3; NewGameO; // "разбросать" мины Forml->
ClientWidth = W*MC; Forml->
ClientHeight = H*MR+TOP+1; } // Вывод поля как результат обработки события Paint // позволяет проводить любые манипуляции с формой // во время работы программы void fastcall TForml::FormPaint(TObject *Sender) { ShowPoletstatus);
} // Показывает поле void fastcall TForml::ShowPole( int status) { for ( int row = 1; row <= MR; row++) for ( int col = 1; col <= MC; col++) Kletka(row, col, status);
) // рисует на экране клетку void fastcall TForml::Kletka(int row, int col, int status) { int x = LEFT + (col-D* W; int у = TOP + (row-1)* H; if (status ==0) // начало игры { // клетка — серый квадрат Canvas->
Brush->
Color = clLtGray; Canvas->
Rectangle(x-l,y-l,x+W,y+H);
return; } // во время (status = 1) и в конце (status = 2) игр if ( Pole[row][col] < 100) { // клетка не открыта Canvas->
Brush->
Color = clLtGray; // не открытые — серые Canvas->
Rectangle(x-l,y-l,x+W,y+H);
if (status == 2 SS Pole[row][col] = 9} Mina( x, y);
// игра закончена, показать мину return; } // клетка открыта Canvas->
Brush->
Color = clWhite; // открытые - белые Canvas->
Rectangle(x-1,y-1,x+W,у+Н);
if ( Pole[row][col] == 100) // клетка открыта, но она пустая return; . if ( Pole[row][col] >
= 101 && Pole[row][col] <= 108) { Canvas->
Font->
Size = 14; Canvas->
Font->
Color = clBlue; Canvas->
TextOutA(x+3,y+2,IntToStr(Pole[row][col] -100));
return; } if ( Pole[row][col] >
= 200) Flag(x, y) ; if (Pole[row][col] == 109) // на этой мине подорвались! { Canvas->
Brush->
Color = clRed; Canvas->
Rectangle(x,y,x+W,y+H);
} if (( Pole[row][col] % 10 == 9) && (status == 2)) Mina( x, y);
} // рекурсивная функция открывает текущую и все соседние // клетки, в которых нет мин void fastcall Open(int row, int col) { if (Pole[row][col] = 0) { Pole[row][col] = 100; // открываем клетки слева, справа, снизу и сверху Open(row,col-l);
Open(row-l,col);
Open(row,col+1);
Open(row+1,col);
// открываем примыкающие диагонально Open(row-l,col-l);
Open(row-l,col+l) ; Open(row+1,col-1);
Open(row+1,col+1);
} else // -3 — это граница игрового поля if (Pole[row][col] < 100 && Pole[row][col] != -3} Pole[row][col] += 100; } // новая игра — генерирует новое поле void __£astcall NewGame() { // Очистим эл-ты массива, соответствующие отображаемым // клеткам, а в неотображаемые (по границе игрового поля) // запишем число -3. Уникальное значение клеток границы // используется функцией Open для завершения рекурсивного // процесса открытия соседних пустых клеток. int row,col; for (row=0; row <= MR+1; row++) for (col=0; col <= MC+1; col++) Pole[row][col] = -3; for (row=l; row <= MR; row++) for (col=l; col <= MC; col++) Pole[row][col] = 0; // расставим мины time_t t; // используется ГСЧ srand((unsigned) time(&t));
// инициализация ГСЧ int n = 0; // кол-во мин do { row = randO % MR +1; col = rand() % MC +1; if ( Pole[row][col] != 9) { Pole[row][col] = 9; n++; } } while ( n < 10);
// вычисление кол-ва мин в соседних клетках int k; for ( row = 1; row <= MR; row++) for ( col = 1; col <= MC; col++) if ( Pole[row][col] != 9) { k =0; if ( Pole[row-l][col-1] == 9} k++; if ( Pole[row-1][col] == 9) k++; if ( Pole[row-1][col+1] == 9) k++; if ( Pole[row][col-1] == 9) k++; if ( Pole[row][col+1] == 9) k++; if ( Pole[row+1][col-1] == 9) k++; if ( Pole[row+1][col] == 9) k++; if ( Pole[row+1][col+1] == 9) k++; Pole[row][col] = k; } status =0; // начало игры nMin =0; // нет обнаруженных мин nFlag =0; // нет флагов } // рисует мину void __fastcall TForml::Mina(int x, int y) { Canvas->
Brush->
Color = clGreen; Canvas->
Pen->
Color = clBlack; Canvas->
Rectangle(x+16,y+26,x+24,y+30) ; // корпус Canvas->
Rectangle(x+8,y+30,x+32,y+34) ; Canvas->
Pie(x+6,y+28,x+34,y+44,x+34,y+36,x+6,y+36);
// полоса на корпусе Canvas->
MoveTo(x+12,y+32);
Canvas->
LineTo(x+28,y+32);
// основание Canvas->
MoveTo(x+8,y+36);
Canvas->
LineTo(x+32,y+36);
// вертикальный "ус" Canvas->
MoveTo(x+20,y+22);
Canvas->
LineTo(x+20,y+26);
// боковые "усы" Canvas->
MoveTo(x+8, y+30);
Canvas-XLineTo(x+6,y+28);
Canvas->
MoveTo(x+32,y+30);
Canvas->
LineTo(x+34,y+28);
} // рисует флаг void __fastoall TForml::Flag( int x, int y) { TPoint p[4]; // координаты флажка и нижней точки древка // точки флажка р[0].х=х+4; р[0].у=у+4; р[1].х=х+30; р[1].у=у+12; р[2].х=х+4; р[2].у=у+20; // установим цвет кисти и карандаша Canvas->
Brush->
Color = clRed; Canvas->
Pen->
Color = clRed; // чтобы контур флажка бил красный Canvas->
Polygon(p, 2);
// флажок // древко Canvas->
Pen->
Color = clBlack; Canvas->
MoveTo(p[0].x, p[0] .у);
Canvas->
LineTo(x+4,y+36) ; TPoint m[5]; // буква М m[0].x=x+8; m[0].y=y+14; m[l].x=x+8; m[l].y=y+8; m[2].x=x+10; m[2].y=y+10; m[3].x=x+12; m[3].y=y+8; m[4].x=x+12; m[4].y=y+14; Canvas->
Pen->
Color = clWhite; Canvas->
Polyline(m,4);
Canvas->
Pen->
Color = clBlack; } // команда главного меню Новая игра
void__fastcall TForml::NlCllck(TObject *Sender) { NewGame();
ShowPole(status);
} // выбор в меню "?" команды О программе void__fastcall TForml::N4Click(TObject *Sender) { AboutForm-ХГор = Forml->
Top + Forml->
Height/2 - AboutForm->
Height/2; AboutForm->
Left = Forml->
Left + Forml->
Width/2 - AboutForm->
Width/2; AboutForm->
ShowModal();
} // выбор в меню "?" команды Справка void __fastcall TForml::N3Click(TObject *Sender) { WinHelp(Forml->
Handle,"saper.hip",HELP_CONTEXT,1);
}
Содержание раздела