Программирование с C++ Builder

           

Текст программы



Полный текст программы "Сапер" приведен ниже: в листингах 10.11 и 10.12 — заголовочный файл и модуль главной формы; в листинге 10.13 — модуль формы О программе.

 Листинг 10.11. Заголовочный файл главной формы (saper_.h)
#ifndef saper_H fdefine saper_H

#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>


#include <Forms.hpp>
#include <ExtCtrls.hpp>
 # include <Menus.hpp>
class TForml : public TForm { published:
TMainMenu *MainMenul;
// команды главного меню TMenuItem *N1;


// Новая игра TMenuItem *N2; // команда "?"
// команды меню "?" TMenuItem *N3;
// Справка TMenuItem *N4; // О программе
void __fasteall
FormMouseDown(TObject *Sender, TMouseButton Button,
TShiftState Shift, int X, int Y);
void __fastcall FormPaint(TObject *Sender);
void _fastcall FormCreate(TObject *Sender);
// выбор,команды в меню
void  fastcall NIClick(TObject  *Sender);  
// Новая игра
void __fastcall N3Click(TObject  *Sender);  
// Справка
void __fastoall N4Click(TObject  *Sender);  
// О программе
private:
void  fastcall ShowPole(int status); // отображает поле
// отображает содержимое клетки
void __fastcall Kletka (int row, int col, int status);
void __fastcall Mina (int x, int y);  // рисует мину
void __fastcall Flag( int x, int y);  // рисует флаг
public:
__fastcall TForml(TComponent* Owner); };
extern PACKAGE TForml *Forml; tendif

Листинг 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); }

Листинг 10.13. Модуль формы О программе (saper2_.cpp)
#include <vcl.h>
#pragma hdrstop
#include "saper_2.h"
#pragma package(smart_init)
#pragma resource "*.dfm" TAboutForm *AboutForm;
__fastcall TAboutForm::TAboutForm(TComponent* Owner)
: TForm(Owner) { }
// Выбор URL-адреса
void __fastcall TAboutForm: :Label5Click(TObject *Sender)
{
/*  В функцию ShellExvte надо передать указатель на
null terminated строку (char*). Свойство Caption — это AnsiString.
Преобразование Ansi-строки в указатель
на nt-строку выполняет метод c_str()
*/
//, открыть файл, имя которого находится в поле
Labels ShellExecute
(AboutForm->Handle,"open",Label5->Caption.c_str(),
NULL,NULL,SW_RESTORE); }
// щелчок на кнопке QK
void __fastcall TAboutForm::ButtonlClick(TObject *Sender)
{
ModalResult = mrOk; }


Содержание раздела