AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TicTacToe - Frage zum Programmablauf

Ein Thema von ShadowDeath · begonnen am 11. Apr 2017 · letzter Beitrag vom 12. Apr 2017
Antwort Antwort
Seite 1 von 3  1 23      
ShadowDeath

Registriert seit: 11. Apr 2017
10 Beiträge
 
#1

TicTacToe - Frage zum Programmablauf

  Alt 11. Apr 2017, 19:18
Hallo Leute,
ich hoffe ihr könnt mir helfen, denn ich habe versucht ein TicTacToe zu programmieren doch irgendwie funktioniert es nicht ganz so wie es soll. Um genau zu sein scheint die Gewinner Abfrage nicht zu funktionieren, doch ich finde den Fehler einfach nicht. Hoffentlich kann mir jemand von euch helfen PS: Ich habe das game unten als Zip angehangen.



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)
    SpeedButton1: TSpeedButton;
    SpeedButton2: TSpeedButton;
    SpeedButton4: TSpeedButton;
    SpeedButton5: TSpeedButton;
    SpeedButton3: TSpeedButton;
    SpeedButton6: TSpeedButton;
    SpeedButton7: TSpeedButton;
    SpeedButton8: TSpeedButton;
    SpeedButton9: TSpeedButton;
    SpeedButton10: TSpeedButton;
    procedure SpeedButton1Click(Sender: TObject);
    procedure SpeedButton10Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);

  private
    { Private-Deklarationen }
    Spielfeld: array[0..2, 0..2] 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.SpeedButton1Click(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 := Index mod 3;
     Y := Index div 3;
   end;
  end;

  // Wurde der Button gefunden?
  if ( X > 2 ) or ( Y > 2 ) 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();

  // 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.SpeedButton10Click(Sender: TObject);
var
  X, Y: Byte;
begin
   // Spiel intern und optisch löschen
   for X := 0 to 2 do
   begin
     for Y := 0 to 2 do
     begin
       Spielfeld[ X, Y ] := 0;
       TSpeedButton( Self.Controls[Y * 3 + 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 := 0 to 2 do
  begin
    Result := Spielfeld[ X, 0 ];
    if ( Result <> Spielfeld[ X, 1 ] ) or ( Result <> Spielfeld[ X, 2 ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;

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

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

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

  // Gibt es noch ein freies Feld? (Das Spiel geht dann noch weiter)
  Result := 0;
  for X := 0 to 2 do
  begin
    for Y := 0 to 2 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.
Angehängte Dateien
Dateityp: zip Project1.zip (2,71 MB, 16x aufgerufen)

Geändert von ShadowDeath (12. Apr 2017 um 09:13 Uhr) Grund: falsche Tags
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.270 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Finde den Fehler einfach nicht

  Alt 11. Apr 2017, 21:10
Hallo,
F5, Strg+F5, F7 und F8 schon probiert?
Heiko
  Mit Zitat antworten Zitat
a.def
(Gast)

n/a Beiträge
 
#3

AW: Finde den Fehler einfach nicht

  Alt 11. Apr 2017, 21:23
Zitat:
Um genau zu sein scheint die Gewinner Abfrage nicht zu funktionieren, doch ich finde den Fehler einfach nicht.
Hier muss man präzisieren was denn überhaupt gewünscht ist. Denn "funktioniert nicht" kann alles bedeuten.

P.S.:
Code:
Code-Tags sind cool
aber
Delphi-Quellcode:
Delphi-Tags sind
cool-er
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.139 Beiträge
 
Delphi 12 Athens
 
#4

AW: Finde den Fehler einfach nicht

  Alt 11. Apr 2017, 22:40
PS: [DELPHI]fdfd[/DELPHI]


Zitat:
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 := Index mod 3;
     Y := Index div 3;
   end;
  end;
Du versuchst also auch einer "zufälligen" Reihenfolge "Aller" Controls auf der Form zu bestimmen welcher Knopf es ist?
Ich wäre da nicht sicher, dass X und Y immer richtig sind.
Aber das würde dir auch der Debugger sagen, wenn man ihn verwendet, auf einen Knopf drückt und dann schaut was danach wirklich in X und Y steht.

PS: Alle VCL-Komponenten haben ein "Tag" property, das der Entwickler frei verwenden kann.
z.B. könnte man bei den Knöpfen 11, 12, 13, 21, ... 33 eintragen und dann

Delphi-Quellcode:
X := (Sender as TSpeedButton).Tag mod 10;
Y := (Sender as TSpeedButton).Tag div 10;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#5

AW: Finde den Fehler einfach nicht

  Alt 11. Apr 2017, 23:05
Hallo,

bisher kann ich den Fehler auch nicht finden.

Aber:
Delphi-Quellcode:
  // Gibt es diagonal einen Gewinner? (Von Links-Oben nach Rechts-Unten)
  for Y := 0 to 2 do
  begin
    Result := Spielfeld[ 0, 0 ];
    if ( Result <> Spielfeld[ 1, 1 ] ) or ( Result <> Spielfeld[ 2, 2 ] ) then Result := 0;
    If Result <> 0 then Exit;
  end;
Die For-Schleife erscheint mir hier überflüssig, es gibt nur eine entsprechende Diagonale, da Y in der Schleife nicht genutzt wird, dürfte das dreifache Durchlaufen der Schleife überflüssig sein.
Gilt analog auch für die andere Diagonale.

Zitat:
Um genau zu sein scheint die Gewinner Abfrage nicht zu funktionieren, doch ich finde den Fehler einfach nicht.
Könntest Du das bitte präzisieren?

Funktioniert das grundsätzlich nicht oder nur ab und an oder nur bei bestimmten Konstellationen?

Der Vorschlag von himitsu ist meiner Meinung nach sehr sinnvoll. Über die "Liste" der Controls kann man zwar abfragen, ob man eine passende Komponenten gefunden hat, aber die Reichenfolge ist nicht zwingend aufsteigend nach Namen, sondern wohl von der Erstellungsreihenfolge in der IDE abhängig. Speedbutton1 muss also nicht unbedingt Self.Controls[0] sein. Allerdings müsste das auffallen, weil dann die Caption nicht korrekt gesetzt wird.

Bei himitsus Ansatz müsste meiner Meinung nach aber Spielfeld: array[0..2, 0..2] of Byte; in Spielfeld: array[1..3, 1..3] of Byte; geändert werden und die For-Schleifen entsprechend von 1 bis 3 gehen. Ebenso müsste dann
Delphi-Quellcode:
// Wurde der Button gefunden?
  if ( X > 2 ) or ( Y > 2 ) then exit;
geändert werden in
Delphi-Quellcode:
// Wurde der Button gefunden?
  if ( X > 3 ) or ( Y > 3 ) then exit;
Wobei diese Abfrage eigentlich überflüssig sein dürfte, da ja nur den SpeedButtons 1 bis 9 die Ereignisroutine zugewiesen wurde. Sollte die Bedingung also erfüllt sein, ist noch irgendwas anderes nicht in Ordnung.
  Mit Zitat antworten Zitat
Daniel
(Co-Admin)

Registriert seit: 30. Mai 2002
Ort: Hamburg
13.919 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 08:08
Moin und willkommen in der DP.
Ich habe mal den Titel Deines Themas angepasst, damit dieser für Dritte aussagekräftiger ist.
Daniel R. Wolf
mit Grüßen aus Hamburg
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.540 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 08:12
Dann hättest Du aber auch gleich die Code- durch Delphi-Tags ersetzen können
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
ShadowDeath

Registriert seit: 11. Apr 2017
10 Beiträge
 
#8

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 09:27
Also, erstmal danke für die zahlreichen Antworten. Ich habe erst einmal die falschen Tags korrigiert, damit es übersichtlicher ist. Zum Punkt, was den nun nicht funktioniert: Er erkennt nie den Gewinner, egal welche Gewinn Konstellation ich teste (sei es diagonal, vertikal oder horizontal). Gewünscht ist, dass er eine Message mit dem Gewinner ausgibt.

Delphi-Quellcode:
 // Sieger ermitteln
  Gewinner := ErmittelGewinner();

  // 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;
Und bezüglich der Tags von VCL-Komponenten: Ich war mir bewusst, dass es diese Eigenschaft für VCL Komponente gibt. Doch leider habe ich mich vorher nie damit auseinander gesetzt, deswegen nahm ich die 'unsaubere' Methoden anhand der Erstellungsreihenfolge (1-9 gehören zum Spielfeld, 10 ist der Neustart Button). Also dürfte es da keine Probleme geben (außer die Unsauberkeit des Codes).
Ich werde versuchen weitgehend alles Überflüssige zu entfernen (For-Schleifen) bzw. zu optimieren (Tags). Dennoch bin ich überzeugt, dass der Fehler woanders liegt. Ich würde mich sehr freuen, wenn ich noch ein paar Lösungsansätze finden würdet bzw. mit mir teilen würdet.
  Mit Zitat antworten Zitat
a.def
(Gast)

n/a Beiträge
 
#9

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 09:58
Delphi-Quellcode:
case Gewinner of
    0: Exit;
Das ist überflüssig, da nach dem Case ja eh kein Code mehr kommt.
  Mit Zitat antworten Zitat
Whookie

Registriert seit: 3. Mai 2006
Ort: Graz
441 Beiträge
 
Delphi 10.3 Rio
 
#10

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 10:11
1. Die Lösung steht doch vermutlich schon in #4
2. Verwende den Debugger und schau dir deine Variablen an
3. Wozu soll die angehängte .exe im Zipfile gut sein? Wenn du möchtest das sich das jemand hier ansieht dann häng das Projekt an, so das man es compilen kann (.exe erstellen kann hier sogut wie jeder )
Whookie

Software isn't released ... it is allowed to escape!
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:07 Uhr.
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