Thema: Delphi Minesweeper

Einzelnen Beitrag anzeigen

Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#73

AW: Minesweeper

  Alt 26. Mär 2015, 02:37
Simpler Maussucht Käse:
Weil das ja so simple ist würde ich ggf. vorschlagen, daß du das kurz in der Play ergänzt.

Delphi-Quellcode:
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.
  Mit Zitat antworten Zitat