Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi TicTacToe - Frage zum Programmablauf (https://www.delphipraxis.net/192359-tictactoe-frage-zum-programmablauf.html)

ShadowDeath 12. Apr 2017 15:27

AW: TicTacToe - Frage zum Programmablauf
 
Erstmal danke nahpets, dass du dir die Zeit genommen hast mir das zu erklären. Die Gewinn-Abfrage funktioniert jetzt auch. :) Leider ist ein neues Problem aufgetreten: Der Neustart Button hat den Geist aufgegeben. Beim Klicken sagt er, dass eine Zugriffsverletzung vorliegt? Ich habe aus der 3 eine 10 gemacht, da wir ja weiter oben mit 10 Teilen (Beim Kommentar 'Spiel intern und optisch löschen'). & Sorry für die dämlichen Fragereien, aber ich arbeite noch nicht solange mit Delphi :x

Aktueller Code:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Buttons;

type
  TForm1 = class(TForm)
    btnX1Y3: TSpeedButton;
    btnX2Y3: TSpeedButton;
    btnX1Y2: TSpeedButton;
    btnX2Y2: TSpeedButton;
    btnX3Y3: TSpeedButton;
    btnX3Y2: TSpeedButton;
    btnX1Y1: TSpeedButton;
    btnX2Y1: TSpeedButton;
    btnX3Y1: TSpeedButton;
    btnNeuesSpiel: TSpeedButton;
    procedure btnX1Y3Click(Sender: TObject);
    procedure btnNeuesSpielClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);

  private
    { Private-Deklarationen }
    Spielfeld: array[1..3, 1..3] of Byte;
    Spieler, Starter, Gewinner: Byte;
    function ErmittelGewinner() : Byte;

  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// FELD 1 bis Feld 9
procedure TForm1.btnX1Y3Click(Sender: TObject);
var
  X, Y: Byte;
  Index: Byte;
begin
  // Ist der Sender überhaupt ein Speedbutton?
  If not (Sender is TSpeedButton) then Exit;

  // Ist das Spiel schon vorbei?
  If Gewinner <> 0 then
    begin
      ShowMessage( 'Das Spiel ist bereits vorbei. Bitte starte ein neues Spiel.' );
      Exit;
    end;

  // Welcher Button wurde gedrückt?
  X := 90;
  Y := 90;
  for Index := 0 to Self.ControlCount - 1 do
  begin
   If Sender = Self.Controls[ Index ] then
   begin
     X := (Sender as TSpeedButton).Tag mod 10;
     Y := (Sender as TSpeedButton).Tag div 10;
   end;
  end;

  // Wurde der Button gefunden?
  if ( X > 3 ) or ( Y > 3 ) then exit;

  // Ist das gewünschte Feld noch frei?
  If Spielfeld[ X, Y ] <> 0 then
  begin
    ShowMessage( 'Das Feld ist schon besetzt. Bitte wähle ein anderes aus.' );
    Exit;
  end;

  // Zug optisch ausführen
  case Spieler of
    1: TSpeedButton( Sender ).Caption := 'X';
    2: TSpeedButton( Sender ).Caption := 'O';
    else
    begin
      ShowMessage( 'Unerwarteter Fehler!' );
      Exit;
    end;
  end;

  // Zug intern ausführen
  Spielfeld[ X, Y ] := Spieler;

  // Spieler wechseln
  Spieler := Spieler mod 2 + 1;

  // Sieger ermitteln
  Gewinner := ErmittelGewinner();
  //ShowMessage( Format( 'Spieler %d hat gewonnen.', [ Gewinner ] ) );

  // Entsprechend des Siegers eine Meldung ausgeben
  case Gewinner of
    0: Exit;
    1,2: ShowMessage( Format( 'Spieler %d hat gewonnen.', [ Gewinner ] ) );
    3: ShowMessage( 'Das Spiel endet unentschieden.' );
  end;
end;

// NEUES SPIEL
procedure TForm1.btnNeuesSpielClick(Sender: TObject);
var
  X, Y: Byte;
begin
   // Spiel intern und optisch löschen
   for X := 1 to 3 do
   begin
     for Y := 1 to 3 do
     begin
       Spielfeld[ X, Y ] := 0;
       TSpeedButton( Self.Controls[Y * 10 + X ] ).Caption := '';
     end;
   end;

   // Entscheiden, wer die nächste Runde beginnen darf
   case Gewinner of
     1,2: Starter := Gewinner mod 2 + 1; // Der Verlierer startet
     0,3: Starter := Starter mod 2 + 1; // Spieler 2 aus der vorherigen Runde ist nun Spieler 1
   end;

   // Vorbereitungen abschließen
   Spieler := Starter;
   Gewinner := 0;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Spieler := 1;
  Starter := 1;
end;

function TForm1.ErmittelGewinner() : Byte;
var
  X, Y: Byte;
begin
  // Gewinner ermitteln

  // Gibt es einen Gewinner auf der Y-Achse?
  for X := 1 to 3 do
  begin
    Result := Spielfeld[ X, 1 ];
    if ( Result <> Spielfeld[ X, 2 ] ) or ( Result <> Spielfeld[ X, 3 ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;

  // Gibt es einen Gewinner auf der X-Achse?
  for Y := 1 to 3 do
  begin
    Result := Spielfeld[ 1, Y ];
    if ( Result <> Spielfeld[ 2, Y ] ) or ( Result <> Spielfeld[ 3, Y ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;

  // Gibt es diagonal einen Gewinner? (Von Links-Oben nach Rechts-Unten)
  for Y := 1 to 3 do
  begin
    Result := Spielfeld[ 1, 1 ];
    if ( Result <> Spielfeld[ 2, 2 ] ) or ( Result <> Spielfeld[ 3, 3 ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;

  // Gibt es diagonal einen Gewinner? (Von Rechts-Oben nach Links-Unten)
  for Y := 1 to 3 do
  begin
    Result := Spielfeld[ 3, 1 ];
    if ( Result <> Spielfeld[ 2, 2 ] ) or ( Result <> Spielfeld[ 1, 3 ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;

  // Gibt es noch ein freies Feld? (Das Spiel geht dann noch weiter)
  for X := 1 to 3 do
  begin
    for Y := 1 to 3 do
    begin
      if Spielfeld[ X, Y ] = 0 then Exit;
    end;
  end;

  // Es gab bisher keinen Gewinner. Freie Felder gibt es auch nicht mehr.
  // Das Spiel endet also unentschieden.
  Result := 3;

end;

end.

DeddyH 12. Apr 2017 15:30

AW: TicTacToe - Frage zum Programmablauf
 
Zitat:

Delphi-Quellcode:
TSpeedButton( Self.Controls[Y * 10 + X ] ).Caption := '';

Das wären bei X=3 und Y=3 ja 34 Controls (Index beginnt bei 0), und alle müssen Speedbuttons sein. Das erscheint mir ein wenig viel.

ShadowDeath 12. Apr 2017 15:33

AW: TicTacToe - Frage zum Programmablauf
 
Zitat:

Zitat von DeddyH (Beitrag 1367372)
Zitat:

Delphi-Quellcode:
TSpeedButton( Self.Controls[Y * 10 + X ] ).Caption := '';

Das wären bei X=3 und Y=3 ja 34 Controls (Index beginnt bei 0), und alle müssen Speedbuttons sein. Das erscheint mir ein wenig viel.

Also wäre 2 der passende Multiplikator?

EDIT: Habe es grade mit 2 getestet. Leider lässt er 12,13 & 23 so wie sie sind & cleart dafür den Neustart-Speedbutton.
EDIT 2: ich habe vom Produkt nochmal 1 abgezogen, damit der neustart Button bleibt. Jetzt werden nur noch 13 & 23 nicht gecleart. :x

nahpets 12. Apr 2017 15:39

AW: TicTacToe - Frage zum Programmablauf
 
Dashier ist jetzt so nicht mehr richtig:
Delphi-Quellcode:
// Welcher Button wurde gedrückt?
  X := 90;
  Y := 90;
  for Index := 0 to Self.ControlCount - 1 do
  begin
   If Sender = Self.Controls[ Index ] then
   begin
     X := (Sender as TSpeedButton).Tag mod 10;
     Y := (Sender as TSpeedButton).Tag div 10;
   end;
  end;
Dashier sollte ausreichen:
Delphi-Quellcode:
  X := (Sender as TSpeedButton).Tag mod 10;
  Y := (Sender as TSpeedButton).Tag div 10;
Wir wollen ja, weil es nicht funktioniert, vom Durchlaufen von Self.Controls weg. Die Nutzung der Eigenschaft Tag dient ja genau der Abschaffung dieser fehleranfälligen Vorgehensweise.

Wir brauchen durch die Änderung auf die Tag-Nutzung nicht mehr abfragen, welcher Button gedrückt wurde. Der Button teilt uns dies durch den Inhalt von Tag selbst mit.

Der Button mit Tag = 11 sagt dadurch letztlich: "Ich bin der Butten von unten links."
Der Button mit Tag = 33 sagt uns: "Ich bin der Button von oben rechts."

Mit Tag mod 10 bzw. Tag div 10 wird der zweistellige Wert von Tag auf X und Y "verteilt", also in die jeweiligen Koordinaten umgerechnet.

ShadowDeath 12. Apr 2017 15:42

AW: TicTacToe - Frage zum Programmablauf
 
Ist erledigt. Trotzdem wird weiterhin 13 & 23 nicht gecleart.

nahpets 12. Apr 2017 15:49

AW: TicTacToe - Frage zum Programmablauf
 
Dieses ist so nicht korrekt, die "geographische" Lage der Buttons hat sich durch die Nutzung von Tag und die geänderten Namen nicht verändert.
Delphi-Quellcode:
 for X := 1 to 3 do
   begin
     for Y := 1 to 3 do
     begin
       Spielfeld[ X, Y ] := 0;
       TSpeedButton( Self.Controls[Y * 10 + X ] ).Caption := '';
     end;
   end;
Hier würd' ich es mal so versuchen:
Delphi-Quellcode:
  for X := 1 to 3 do for Y := 1 to 3 do Spielfeld[X,Y] := 0;
  for X := 0 to Self.Controls.Count - 1 do
    begin
      if Self.Controls[X] is TSpeedButton then
        begin
          if TSpeedButton(Self.Controls[X]).Tag <> 0 then TSpeedButton(Self.Controls[X]).Caption := '';
        end;
    end;
(Ist jetzt nur ungetestet hingedaddelt. Schreibfehler (wie immer) nicht ausgeschlossen.)

HolgerX 12. Apr 2017 15:54

AW: TicTacToe - Frage zum Programmablauf
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hmm..


Hab mir deinen Source genommen..
- Den Startbutton aber als TBitBtn
- Den Speedbuttons einen Tag von 0-9 verpasst
- Entsprechende Stellen umgestellt oder bereinigt

Und siehe da dein Basis-Code läuft.

ShadowDeath 12. Apr 2017 16:01

AW: TicTacToe - Frage zum Programmablauf
 
@nahpets: Danke, jetzt geht es :) & nochmals danke für die guten Erklärungen.
@Holger: Danke auch an dich. Ich werde mir den Code gleich anschauen :)
@ALLE: Danke für eure hilfreichen Antworten und Lösungsansätze.

PS: Ich habe noch ein Problem, um das ihr euch kümmern könnt, zudem ich nachher einen Thread erstellen werde ^^ (Geht um ein anderes Spiel)


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:16 Uhr.
Seite 3 von 3     123   

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