![]() |
TicTacToe - Frage zum Programmablauf
Liste der Anhänge anzeigen (Anzahl: 1)
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. |
AW: Finde den Fehler einfach nicht
Hallo,
F5, Strg+F5, F7 und F8 schon probiert? |
AW: Finde den Fehler einfach nicht
Zitat:
P.S.:
Code:
aber
Code-Tags sind cool
Delphi-Quellcode:
8-)
Delphi-Tags sind
cool-er |
AW: Finde den Fehler einfach nicht
PS: [DELPHI]fdfd[/DELPHI]
Zitat:
Ich wäre da nicht sicher, dass X und Y immer richtig sind. :stupid: 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; |
AW: Finde den Fehler einfach nicht
Hallo,
bisher kann ich den Fehler auch nicht finden. Aber:
Delphi-Quellcode:
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.
// 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; Gilt analog auch für die andere Diagonale. Zitat:
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
Delphi-Quellcode:
in
Spielfeld: array[0..2, 0..2] of Byte;
Delphi-Quellcode:
geändert werden und die For-Schleifen entsprechend von 1 bis 3 gehen. Ebenso müsste dann
Spielfeld: array[1..3, 1..3] of Byte;
Delphi-Quellcode:
geändert werden in
// Wurde der Button gefunden?
if ( X > 2 ) or ( Y > 2 ) then exit;
Delphi-Quellcode:
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.
// Wurde der Button gefunden?
if ( X > 3 ) or ( Y > 3 ) then exit; |
AW: TicTacToe - Frage zum Programmablauf
Moin und willkommen in der DP. :hi:
Ich habe mal den Titel Deines Themas angepasst, damit dieser für Dritte aussagekräftiger ist. |
AW: TicTacToe - Frage zum Programmablauf
Dann hättest Du aber auch gleich die Code- durch Delphi-Tags ersetzen können :mrgreen:
|
AW: TicTacToe - Frage zum Programmablauf
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:
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).
// 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; 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. :) |
AW: TicTacToe - Frage zum Programmablauf
Delphi-Quellcode:
Das ist überflüssig, da nach dem Case ja eh kein Code mehr kommt.
case Gewinner of
0: Exit; |
AW: TicTacToe - Frage zum Programmablauf
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 ;) ) |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:33 Uhr. |
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