unit MinesweeperUnit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls;
const
cGridCount = 9;
cMinesCount = 10;
cFlagSign = '
?';
cMineSign = '
X';
type
TMinesweeperPanel =
class(TPanel)
private
function GetMine: boolean;
public
X, Y: integer;
FlankingMinesCount: integer;
property Mine: boolean
read GetMine;
end;
TMinesweeperForm =
class(TForm)
procedure FormCreate(Sender: TObject);
procedure PanelsMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
private
FPanels:
array[0..cGridCount - 1, 0..cGridCount - 1]
of TMinesweeperPanel;
function InPanelGrid(X, Y: integer): boolean;
function GetFlankingMinesCount(X, Y: integer): integer;
procedure NewGame;
procedure ShowMines;
procedure CreatePanels;
procedure Play(X, Y: integer);
end;
var
MinesweeperForm: TMinesweeperForm;
implementation
{$R *.dfm}
{ TMinesweeperPanel }
function TMinesweeperPanel.GetMine: boolean;
begin
Result := FlankingMinesCount < 0;
// *** -1 als Kennzeichnung für Mine ***
end;
{ TMinesweeperForm }
procedure TMinesweeperForm.CreatePanels;
var
I, X, Y: integer;
begin
I := 0;
for X := 0
to cGridCount - 1
do
for Y := 0
to cGridCount - 1
do
begin
Inc(I);
FPanels[X, Y] := TMinesweeperPanel.Create(Self);
FPanels[X, Y].Parent := Self;
FPanels[X, Y].
Name := '
Panel' + IntToStr(I);
FPanels[X, Y].Width := 30;
FPanels[X, Y].Height := 30;
FPanels[X, Y].Caption := '
';
FPanels[X, Y].Left := 20 + (X * 30);
FPanels[X, Y].Top := 20 + (Y * 30);
FPanels[X, Y].BorderStyle := bsSingle;
FPanels[X, Y].OnMouseUp := PanelsMouseUp;
FPanels[X, Y].X := X;
FPanels[X, Y].Y := Y;
end;
end;
function TMinesweeperForm.InPanelGrid(X, Y: integer): boolean;
begin
Result := (X >= 0)
and (X <= cGridCount - 1)
and (Y >= 0)
and (Y <= cGridCount - 1);
end;
function TMinesweeperForm.GetFlankingMinesCount(X, Y: integer): integer;
begin
Result := 0;
if InPanelGrid(X + 1, Y)
and FPanels[X + 1, Y].Mine
then
Inc(Result);
if InPanelGrid(X + 1, Y + 1)
and FPanels[X + 1, Y + 1].Mine
then
Inc(Result);
if InPanelGrid(X, Y + 1)
and FPanels[X, Y + 1].Mine
then
Inc(Result);
if InPanelGrid(X - 1, Y + 1)
and FPanels[X - 1, Y + 1].Mine
then
Inc(Result);
if InPanelGrid(X - 1, Y)
and FPanels[X - 1, Y].Mine
then
Inc(Result);
if InPanelGrid(X - 1, Y - 1)
and FPanels[X - 1, Y - 1].Mine
then
Inc(Result);
if InPanelGrid(X, Y - 1)
and FPanels[X, Y - 1].Mine
then
Inc(Result);
if InPanelGrid(X + 1, Y - 1)
and FPanels[X + 1, Y - 1].Mine
then
Inc(Result);
end;
procedure TMinesweeperForm.NewGame;
var
I, X, Y: integer;
begin
ClientWidth := cGridCount * 30 + 40;
ClientHeight := ClientWidth;
for X := 0
to cGridCount - 1
do
for Y := 0
to cGridCount - 1
do
begin
FPanels[X, Y].Caption := '
';
FPanels[X, Y].Color := clBtnFace;
FPanels[X, Y].Enabled := true;
FPanels[X, Y].FlankingMinesCount := 0;
end;
for I := 1
to cMinesCount
do
begin
X := Random(cGridCount);
Y := Random(cGridCount);
// FPanels[X, Y].Caption := cMineSign;
FPanels[X, Y].FlankingMinesCount := -1;
end;
for X := 0
to cGridCount - 1
do
for Y := 0
to cGridCount - 1
do
if not FPanels[X, Y].Mine
then
FPanels[X, Y].FlankingMinesCount := GetFlankingMinesCount(X, Y);
end;
procedure TMinesweeperForm.FormCreate(Sender: TObject);
begin
Randomize;
CreatePanels;
NewGame;
end;
procedure TMinesweeperForm.Play(X, Y: integer);
var
I, J: integer;
begin
if InPanelGrid(X, Y)
and FPanels[X, Y].Enabled
then
begin
if FPanels[X, Y].FlankingMinesCount > 0
then
FPanels[X, Y].Caption := IntToStr(FPanels[X, Y].FlankingMinesCount)
else
FPanels[X, Y].Caption := '
';
FPanels[X, Y].Color := clWindow;
FPanels[X, Y].Enabled := false;
(*
Mit der linken Maustaste freigelegte Felder, die keine Mine enthalten, enthüllen die Anzahl der Minen,
die sich in den benachbarten acht Feldern befinden.
Ein aufgedecktes Feld, das an allen Seiten von Minen umgeben ist, wird eine 8 zeigen.
Durch die Zahlen der aufgedeckten Felder ist es meist möglich, den Aufenthaltsort der Minen herauszufinden.
Wenn man einen Doppelklick mit der linken Maustaste auf ein aufgedecktes Feld macht,
in dessen Nachbarschaft bereits alle Minen markiert sind oder darauf mit der linken
und der rechten Maustaste gleichzeitig klickt, werden die restlichen Felder mit einem Mal aufgedeckt.
Eine Sonderrolle spielen Felder, die keine Minen in ihrer Nachbarschaft aufweisen:
Solche zeigen zum einen nicht etwa eine 0, sondern sie werden farblich anders dargestellt.
Zum anderen werden alle noch verdeckten Felder in ihrer Nachbarschaft automatisch aufgedeckt.
Ist ein so neu aufdecktes Feld ebenfalls ein Null-Feld, so wird dieser Prozess rekursiv weitergeführt.
*)
for I := -1
to 1
do
for J := -1
to 1
do
if ((I <> 0)
or (J <> 0))
and InPanelGrid(X + I, Y + J)
then
if ..
and ..
and ..
and ..
and ..
then Play(X + I, Y + J);
end;
end;
procedure TMinesweeperForm.ShowMines;
// GameOver;
var
X, Y: integer;
begin
for X := 0
to cGridCount - 1
do
for Y := 0
to cGridCount - 1
do
if FPanels[X, Y].Mine
then
FPanels[X, Y].Caption := cMineSign;
Application.ProcessMessages;
end;
procedure TMinesweeperForm.PanelsMouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
Panel: TMinesweeperPanel;
begin
Panel := TMinesweeperPanel(Sender);
if Panel.Mine
then
begin
Panel.Color := clHighlight;
ShowMines;
Showmessage('
Du hast leider verloren.');
NewGame;
end
else
if Button = mbLeft
then
Play(Panel.X, Panel.Y)
else
if Button = mbRight
then
begin
if Panel.Caption = cFlagSign
then
Panel.Caption := '
'
else
Panel.Caption := cFlagSign;
end;
end;
end.