Delphi-PRAXiS
Seite 1 von 14  1 2311     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Minesweeper (https://www.delphipraxis.net/184385-minesweeper.html)

saii 21. Mär 2015 16:25

Minesweeper
 
Hallo, liebe DPler,

Ich programmiere für die Schule Minesweeper in Delphi6 und bräuchte mal eure Hilfe.

Ich nutze ein zweidimensionales Array, in dem ich die Minen zufällig verteile
und in meiner Form1 sind 225 Panels quadratisch angeordnet.
Bisher kann man mit Rechtsklick Panels markieren ("F" als Flagge und "?") und
mit Linksklick wird die Zahl der umliegenden Minen kontrolliert und aufgeschrieben.
Falls man auf eine Mine linksklickt, ist das Spiel verloren.

Nun möchte ich, und dabei brauche ich eure Hilfe, dass wenn keine mit Minen besetzten Felder anliegen, dass passiert, was im Original auch passiert. Ihr wisst hoffentlich, was ich meine :)
Mein Problem dabei ist, dass ich kein Plan hab, wie ich das umsetzen kann.

Anbei mein QuellCode und ein Screenshot meiner Form1.
Hinweis: Das StringGrid ist temporär. Ich nutze es um zu wissen ob sich mein Programm verzählt.
Außerdem sind bisher nur 3 Panels eingebunden ([0,0], [0,1], [1,1])

Ich wäre euch echt unglaublich dankbar, wenn ihr mir da weiterhelfen würdet :-D


Form1
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    P_0_0: TPanel;
    P_0_1: TPanel;
    P_0_2: TPanel;
    P_0_3: TPanel;
    P_0_4: TPanel;
    P_0_5: TPanel;
    P_0_6: TPanel;
    P_0_7: TPanel;
    P_0_8: TPanel;
    P_0_9: TPanel;
    P_0_10: TPanel;
    P_0_11: TPanel;
    P_0_12: TPanel;
    P_0_13: TPanel;
    P_0_14: TPanel;
    P_1_0: TPanel;
    P_1_1: TPanel;
    P_1_2: TPanel;
    P_1_3: TPanel;
    P_1_4: TPanel;
    P_1_5: TPanel;
    P_1_6: TPanel;
    P_1_7: TPanel;
    P_1_8: TPanel;
    P_1_9: TPanel;
    P_1_10: TPanel;
    P_1_11: TPanel;
    P_1_12: TPanel;
    P_1_13: TPanel;
    P_1_14: TPanel;
    P_2_0: TPanel;
    P_2_1: TPanel;
    P_2_2: TPanel;
    P_2_3: TPanel;
    P_2_4: TPanel;
    P_2_5: TPanel;
    P_2_6: TPanel;
    P_2_7: TPanel;
    P_2_8: TPanel;
    P_2_9: TPanel;
    P_2_13: TPanel;
    P_2_14: TPanel;
    P_2_10: TPanel;
    P_2_11: TPanel;
    P_3_0: TPanel;
    P_3_1: TPanel;
    P_3_2: TPanel;
    P_3_3: TPanel;
    P_2_12: TPanel;
    P_3_4: TPanel;
    P_3_5: TPanel;
    P_3_6: TPanel;
    P_3_7: TPanel;
    P_3_8: TPanel;
    P_3_9: TPanel;
    P_3_10: TPanel;
    P_3_11: TPanel;
    P_3_12: TPanel;
    P_3_13: TPanel;
    P_3_14: TPanel;
    P_4_0: TPanel;
    P_4_1: TPanel;
    P_4_2: TPanel;
    P_4_3: TPanel;
    P_4_4: TPanel;
    P_4_5: TPanel;
    P_4_6: TPanel;
    P_4_7: TPanel;
    P_4_8: TPanel;
    P_4_9: TPanel;
    P_4_10: TPanel;
    P_4_11: TPanel;
    P_4_12: TPanel;
    P_4_13: TPanel;
    P_4_14: TPanel;
    P_5_0: TPanel;
    P_5_1: TPanel;
    P_5_2: TPanel;
    P_5_3: TPanel;
    P_5_4: TPanel;
    P_5_5: TPanel;
    P_5_6: TPanel;
    P_5_7: TPanel;
    P_5_8: TPanel;
    P_5_9: TPanel;
    P_5_10: TPanel;
    P_5_11: TPanel;
    P_5_12: TPanel;
    P_5_13: TPanel;
    P_5_14: TPanel;
    P_6_0: TPanel;
    P_6_1: TPanel;
    P_6_2: TPanel;
    P_6_3: TPanel;
    P_6_4: TPanel;
    P_6_5: TPanel;
    P_6_6: TPanel;
    P_6_7: TPanel;
    P_6_8: TPanel;
    P_6_9: TPanel;
    P_6_10: TPanel;
    P_6_11: TPanel;
    P_7_0: TPanel;
    P_6_12: TPanel;
    P_6_13: TPanel;
    P_6_14: TPanel;
    P_7_1: TPanel;
    P_7_2: TPanel;
    P_7_3: TPanel;
    P_7_4: TPanel;
    P_7_5: TPanel;
    P_7_6: TPanel;
    P_7_7: TPanel;
    P_7_8: TPanel;
    P_7_9: TPanel;
    P_7_10: TPanel;
    P_7_11: TPanel;
    P_7_12: TPanel;
    P_7_13: TPanel;
    P_7_14: TPanel;
    P_8_0: TPanel;
    P_8_1: TPanel;
    P_8_2: TPanel;
    P_8_3: TPanel;
    P_8_4: TPanel;
    P_8_5: TPanel;
    P_8_6: TPanel;
    P_8_7: TPanel;
    P_8_8: TPanel;
    P_8_9: TPanel;
    P_8_10: TPanel;
    P_8_11: TPanel;
    P_8_12: TPanel;
    P_8_13: TPanel;
    P_8_14: TPanel;
    P_9_0: TPanel;
    P_9_1: TPanel;
    P_9_2: TPanel;
    P_9_3: TPanel;
    P_9_4: TPanel;
    P_9_5: TPanel;
    P_9_6: TPanel;
    P_9_7: TPanel;
    P_9_8: TPanel;
    P_9_9: TPanel;
    P_9_10: TPanel;
    P_9_11: TPanel;
    P_9_12: TPanel;
    P_9_13: TPanel;
    P_9_14: TPanel;
    P_10_0: TPanel;
    P_10_1: TPanel;
    P_10_2: TPanel;
    P_10_3: TPanel;
    P_10_4: TPanel;
    P_10_5: TPanel;
    P_10_6: TPanel;
    P_10_7: TPanel;
    P_10_8: TPanel;
    P_10_9: TPanel;
    P_10_10: TPanel;
    P_10_11: TPanel;
    P_10_12: TPanel;
    P_10_13: TPanel;
    P_10_14: TPanel;
    P_11_0: TPanel;
    P_11_1: TPanel;
    P_11_2: TPanel;
    P_11_3: TPanel;
    P_11_4: TPanel;
    P_11_5: TPanel;
    P_11_6: TPanel;
    P_11_7: TPanel;
    P_11_8: TPanel;
    P_11_9: TPanel;
    P_11_10: TPanel;
    P_11_11: TPanel;
    P_11_12: TPanel;
    P_11_13: TPanel;
    P_11_14: TPanel;
    P_12_0: TPanel;
    P_12_1: TPanel;
    P_12_2: TPanel;
    P_12_3: TPanel;
    P_12_4: TPanel;
    P_12_5: TPanel;
    P_12_6: TPanel;
    P_12_7: TPanel;
    P_12_8: TPanel;
    P_12_9: TPanel;
    P_12_10: TPanel;
    P_12_11: TPanel;
    P_12_12: TPanel;
    P_12_13: TPanel;
    P_12_14: TPanel;
    P_13_0: TPanel;
    P_13_1: TPanel;
    P_14_0: TPanel;
    P_14_1: TPanel;
    P_13_2: TPanel;
    P_14_2: TPanel;
    P_13_3: TPanel;
    P_14_3: TPanel;
    P_13_4: TPanel;
    P_14_4: TPanel;
    P_13_5: TPanel;
    P_14_5: TPanel;
    P_13_6: TPanel;
    P_14_6: TPanel;
    P_13_7: TPanel;
    P_14_7: TPanel;
    P_13_8: TPanel;
    P_14_8: TPanel;
    P_13_9: TPanel;
    P_14_9: TPanel;
    P_13_10: TPanel;
    P_14_10: TPanel;
    P_13_11: TPanel;
    P_14_11: TPanel;
    P_13_12: TPanel;
    P_14_12: TPanel;
    P_13_13: TPanel;
    P_14_13: TPanel;
    P_13_14: TPanel;
    P_14_14: TPanel;
    StringGrid1: TStringGrid;
    procedure CannonFire(var A,B,m:integer);
    procedure P_0_0MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure P_0_1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure P_1_1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  mf: array[0..14, 0..14] of boolean;                    //mf = Minenfeld
  A,B,m:integer;

implementation
{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);              //Verteilung der Minen
var    i: integer;
begin
randomize;
        for i:=0 to 50 do
        begin
                A:=random(15);
                B:=random(15);
                mf[A,B]:=true;
                StringGrid1.Cells[A,B]:='M';
        end;
end;

procedure TForm1.CannonFire(var A,B,m:integer);             //Procedure für Linksklick
var z:integer;
begin
if mf[A,B]=false then                                      //Falls keine Mine...
 begin
  m:=0;
  if (A+1>=0) and (A+1<=14) and (B>=0) and (B<=14) then      if mf[A+1,B]=true then    m:=m+1;
  if (A+1>=0) and (A+1<=14) and (B+1>=0) and (B+1<=14) then  if mf[A+1,B+1]=true then   m:=m+1;
  if (A>=0) and (A<=14) and (B+1>=0) and (B+1<=14) then         if mf[A,B+1]=true then   m:=m+1;
  if (A-1>=0) and (A-1<=14) and (B+1>=0) and (B+1<=14) then  if mf[A-1,B+1]=true then   m:=m+1;
  if (A-1>=0) and (A-1<=14) and (B>=0) and (B<=14) then         if mf[A-1,B]=true then   m:=m+1;
  if (A-1>=0) and (A-1<=14) and (B-1>=0) and (B-1<=14) then  if mf[A-1,B-1]=true then   m:=m+1;
  if (A>=0) and (A<=14) and (B-1>=0) and (B-1<=14) then         if mf[A,B-1]=true then   m:=m+1;
  if (A+1>=0) and (A+1<=14) and (B-1>=0) and (B-1<=14) then  if mf[A+1,B-1]=true then   m:=m+1;

  if m=0 then
  begin                                                    //Hier soll der beschriebene Fall programmiert werden
   repeat

   until z=1;
  end;
 end;
 if mf[A,B]=true then                                       //Falls Mine getroffen wurde..
  begin
   ShowMessage('Du hast Verloren!');
   close;
  end;
end;


//---------------------------------------------------------------Folgend: Einbindung Panels

procedure TForm1.P_0_0MouseDown(Sender: TObject; Button: TMouseButton;   //Panel_0_0
        Shift: TShiftState; X, Y: Integer);
var    s:string;
        c:char;
begin
  s := P_0_0.Caption;                                                   //Rechtsklick
  if s <> '' then c := s[1]
  else
    c := ' ';
  if (Button = mbRight) then
    case c of
      ' ': c := 'F';
      'F': c := '?';
      else c := ' ';
    end;
  P_0_0.Caption := c;

  if (Button = mbLeft) then                                            //Linksklick
  begin
  A:=0;
  B:=0;
  CannonFire(A,B,m);
  P_0_0.Caption:=IntToStr(m);
  P_0_0.Enabled:=false;
  end;

end;

procedure TForm1.P_0_1MouseDown(Sender: TObject; Button: TMouseButton;   //Panel_0_1
  Shift: TShiftState; X, Y: Integer);
var    s:string;
        c:char;
begin
  s := P_0_1.Caption;
  if s <> '' then c := s[1]
  else
    c := ' ';
  if (Button = mbRight) then
    case c of
      ' ': c := 'F';
      'F': c := '?';
      else c := ' ';
    end;
  P_0_1.Caption := c;

  if (Button = mbLeft) then
  begin
  A:=1;
  B:=0;
  CannonFire(A,B,m);
  P_0_1.Caption:=IntToStr(m);
  P_0_1.Enabled:=false;
  end;
end;

procedure TForm1.P_1_1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var    s:string;
        c:char;
begin
  s := P_1_1.Caption;
  if s <> '' then c := s[1]
  else
    c := ' ';
  if (Button = mbRight) then
    case c of
      ' ': c := 'F';
      'F': c := '?';
      else c := ' ';
    end;
  P_1_1.Caption := c;

  if (Button = mbLeft) then
  begin
  A:=1;
  B:=1;
  CannonFire(A,B,m);
  P_1_1.Caption:=IntToStr(m);
  P_1_1.Enabled:=false;
  end;
end;


end.

Sir Rufo 21. Mär 2015 16:34

AW: Minesweeper
 
Kleine Grundregel:

Was ich nicht erklären kann, habe ich nicht verstanden, kann ich auch nicht programmieren, egal wie fit ich in der Programmiersprache bin.

Also, ergründe, was da genau passieren soll. Nimm dazu ein Blatt und Stift und male die Situation auf und spiele das auf dem Blatt durch. Das machst du so lange bis du das verstanden hast. Dann leite daraus eine allgemeine Vorgehensweise ab.

Wenn du uns also das erklären kannst, dann helfen wir dir gerne bei der Umsetzung in Delphi weiter :)

saii 21. Mär 2015 16:38

AW: Minesweeper
 
Alles klar, Ich probiers mal aus :)

saii 21. Mär 2015 18:23

AW: Minesweeper
 
Kleine Zwischenfrage:

Kann ich irgendwie über Variablen ein Panel anwählen?
Ich möchte in einer Prozedur die Caption von mehreren Panels ändern.
In der Prozedur arbeite ich mit einem Array und ich möchte im Prinzip
Koordinaten des Arrays mit einem Panel verknüpfen.

Ansonsten komme ich vorwärts. Nur da brauch ich grad wirklich Hilfe.

Sir Rufo 21. Mär 2015 18:34

AW: Minesweeper
 
Jede Komponente auf der Form (die mit dem OI dort hin gekommen ist) hat eine Variable, die eine Referenz auf die Komponente beinhaltet.

Du suchst aber wohl eher ein Panel-Array. Dann erstelle dir so ein Panel-Array und trage die Panels dort ein, schon kannst du die über das Array ansprechen.

So ganz nebenbei hätte ich das eher mit einem DrawGrid gemacht (oder mit einer PaintBox und alles selber gezeichnet), aber niemals mit so einem Komponenten-Haufen. Aber jeder wie er mag :)

saii 21. Mär 2015 19:03

AW: Minesweeper
 
Ich hab das DrawGrid noch nie genutzt.
Das läuft auch Koordinaten und hat das OnMouseDown-Ereignis?

Und dann statt Panels und dem Array einfach nur ein DrawGrid?

Popov 21. Mär 2015 19:12

AW: Minesweeper
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nur ein kleiner Tipp: das mit den Panels ist keine tolle Idee, denn es macht dich sehr unflexibel. Sowas (das Feld) zeichnet man entweder auf der Form, PaintBox oder Image. Die Zelle ermittelt man durch die Berechnung (Breite des Feldes geteilt durch breite Zelle, gleich Zelle). Hört sich zuerst kompliziert an, ist aber hundert mal einfacher als es mit Panelen zu machen.

Ich hab im Anhang ein kleines Beispiel. Das "Spiel" habe ich mal gemacht als einer Schiffe versenken programmieren wollte und auch Panele nehmen wollte.

Guck dir mal in der Funktion FeldKoordinate wie das Feld aus einer Image berechnet wird (und natürlich auch das OnMouseUp Ereignis von Image) und in DrawMatrix wie man ein Feld zeichnet.

Mavarik 21. Mär 2015 23:35

AW: Minesweeper
 
Und selbst wenn Du Panel's nehmen willst...

Aber dann bitte nicht Zusammengeklickt sondern dynamisch erzeugen...

Delphi-Quellcode:
Procedure TForm1.InitFeld;
var
  X,Y      : Integer;
begin
  for X := 0 to XMAX do
   for Y := 0 to YMAX do
     begin
       MeinCoolesPanelArray[X,Y] := TPanel.Create(Self);
       MeinCoolesPanelArray[X,Y].Parent := self;
       MeinCoolesPanelArray[X,Y].Left := StartX + X*XSize;
       MeinCoolesPanelArray[X,Y].Top := StartY + Y*YSize;
       MeinCoolesPanelArray[X,Y].Width := XSize-XRand;      
       MeinCoolesPanelArray[X,Y].Height:= YSize-YRand;
       MeinCollesPanelArray[X,Y].OnClick := PanelClick;
       ....
     end;
end;
Mavarik

saii 22. Mär 2015 14:09

AW: Minesweeper
 
Macht es Sinn über Self.Compenents auf die Panels zuzugreifen?


(A und B sind global als integer definiert)
Delphi-Quellcode:
var  s:String;    
    Panel:TPanel;
begin
  A:=0;
  B:=0;

  Panel:=TPanel(Self.Components['P_'+IntToStr(A)+'_'+IntToStr(B)]);

  s:=Panel.Caption;
  //...
  end;
Leider krieg ich so in der "Panel:=TPanel.."-Zeile die Meldung "[Fehler] Unit1.pas(334): Inkompatible Typen: 'Integer' und 'String'"

Popov 22. Mär 2015 14:17

AW: Minesweeper
 
Wenn es funktioniert, dann funktioniert es eben. Du kannst dir auch FindComponent an genauer angucken.

Das einzige Problem was ich an deinem Code sehe ist, du solltest vorher prüfen ob die Komponente auch wirklich exisiert, bevor du auf sie zugreifst. Ansonsten gibt es eine böse Fehlermeldung.


//Edit:

Ich sehe gerade den Fehler. Components erwartet einen Index (Zahl), keinen Text. Also z. B. Self.Components[5].

Die Kunst ist nun herauszufinden welchen Index das Panel 'P_'+IntToStr(A)+'_'+IntToStr(B) hat.

//Edit 2:

Eine Möglichkeit der Suche, vorausgesetzt du nimmst nicht FindComponent, wäre:

Delphi-Quellcode:
var
  i: Integer;
  Gesucht: String;
begin
  Gesucht := 'P_'+IntToStr(1)+'_'+IntToStr(5);
  for i := 0 to Self.ComponentCount - 1 do
  begin
    if Self.Components[i].Name = Gesucht then
    begin
      ShowMessage('Die Gesuchte Komponente hat den Index: ' + IntToStr(i));
      Break;
    end;
  end;
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:09 Uhr.
Seite 1 von 14  1 2311     Letzte »    

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz