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
a.def
(Gast)

n/a Beiträge
 
#1

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 12:12
Zitat:
Um das zu prüfen, solltest Du zuerst mal mit dem Debugger schauen, was genau passiert.
Seine IDE hat keinen Debugger
  Mit Zitat antworten Zitat
Whookie

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

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 12:31
Nimm einfach die Tag-Eigenschaft und schreib da die Koordinaten rein so wie das in #4 steht!
Die Erstellreihenfolge hat genau NICHTS mit deiner Anordnung der Buttons zu tun...
Whookie

Software isn't released ... it is allowed to escape!
  Mit Zitat antworten Zitat
SProske

Registriert seit: 16. Feb 2015
Ort: Halle/S.
116 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#3

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 12:43
Sofern ich mich nicht ganz falsch erinnere, hat die Starter durchaus einen Debugger, nur wurden einem Variableninhalte nicht beim Mouseover angezeigt, sondern diese mussten zu den überwachten Ausdrücken hinzugefügt werden. Haltepunkte setzen, durchsteppen etc. funktionierte aber ganz normal.
Sebastian
  Mit Zitat antworten Zitat
madas

Registriert seit: 9. Aug 2007
207 Beiträge
 
#4

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 12:58
Schnellschuss ins Blaue:

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TPlayer = (pX = -1, pNobody = 0, pO = 1);

  TForm1 = class(TForm)
    Button11: TButton;
    Button12: TButton;
    Button13: TButton;
    Button21: TButton;
    Button22: TButton;
    Button23: TButton;
    Button31: TButton;
    Button32: TButton;
    Button33: TButton;
    ButtonNewGame: TButton;
    LabelCurrentPlayer: TLabel;

    procedure ButtonClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ButtonNewGameClick(Sender: TObject);
  private
    fCurrentPlayer, fLastWinner: TPlayer;
    dFrom13To31, dFrom11To33, FMoves: Integer;
    fZeilen, fSpalten: array[1..3] of Integer;

    procedure NewGame;
    procedure NextPlayer;
    procedure ResetPlayground;
    procedure UpdateStatus;

    function IsGameOver: Boolean;
    procedure DisablePlayground;
  public
  end;

var
  Form1: TForm1;

implementation

uses TypInfo;

{$R *.dfm}

procedure TForm1.ButtonClick(Sender: TObject);
var
  btn: TButton;
  x, y: Integer;
begin
  if (Assigned(Sender)) and (Sender is TButton) then
  begin
    Inc(FMoves);

    btn := TButton(Sender);

    case fCurrentPlayer of
      pX: btn.Caption := 'X';
      pO: btn.Caption := 'O';
    end;

    btn.Enabled := false;

    x := btn.Tag mod 10;
    y := btn.Tag div 10;

    Inc(fSpalten[x], Ord(fCurrentPlayer));
    Inc(fZeilen[y], Ord(fCurrentPlayer));

    if (x = y) then
    begin
      Inc(dFrom11To33, Ord(fCurrentPlayer));
      if (x = 2) then
        Inc(dFrom13To31, Ord(fCurrentPlayer));
    end else
    begin
      if (Abs(x - y) = 2) then
        Inc(dFrom13To31, Ord(fCurrentPlayer));
    end;

    // Gewinner ermitteln
    if (IsGameOver) then
    begin
      DisablePlayground;
      case fLastWinner of
        pX: ShowMessage('Winner is X');
        pO: ShowMessage('Winner is O');
        pNobody: ShowMessage('draw');
      end;
      Exit;
    end;

    NextPlayer;
  end;
end;

function TForm1.IsGameOver: Boolean;
var
  i: Integer;
begin
  Result := False;
  for i := 1 to 3 do
  begin
    Result := Result or (Abs(fSpalten[i]) = 3) or (Abs(fZeilen[i]) = 3);
  end;
  Result := Result or (Abs(dFrom13To31) = 3) or (Abs(dFrom11To33) = 3);
  if (Result) then
  begin
    fLastWinner := fCurrentPlayer
  end else
  if (FMoves = 9) then
  begin
    Result := True;
    fLastWinner := pNobody;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  fCurrentPlayer := pX;
  fLastWinner := pNobody;
  NewGame;
end;

procedure TForm1.NewGame;
begin
  ResetPlayground;
  NextPlayer;
end;

procedure TForm1.DisablePlayground;
var
  i: Integer;
begin
  for i := 0 to Self.ControlCount - 1 do
  begin
    if (Self.Controls[i] is TButton) and
       (TButton(Self.Controls[i]).Tag > 0) then
    begin
      TButton(Self.Controls[i]).Enabled := false;
    end;
  end;
end;

procedure TForm1.ResetPlayground;
var
  i: Integer;
begin
  FMoves := 0;
  for i := 0 to Self.ControlCount - 1 do
  begin
    if (Self.Controls[i] is TButton) and
       (TButton(Self.Controls[i]).Tag > 0) then
    begin
      TButton(Self.Controls[i]).Caption := EmptyStr;
      TButton(Self.Controls[i]).Enabled := true;
    end;
  end;

  for i := Low(fSpalten) to High(fSpalten) do
    fSpalten[i] := 0;
  for i := Low(fZeilen) to High(fZeilen) do
    fZeilen[i] := 0;
  dFrom13To31 := 0;
  dFrom11To33 := 0;
end;

procedure TForm1.NextPlayer;
begin
  if (fLastWinner = pNobody) then
  begin
    fCurrentPlayer := TPlayer(Ord(fCurrentPlayer) * -1)
  end else
  begin
    fCurrentPlayer := TPlayer(Ord(fLastWinner) * -1);
    fLastWinner := pNobody;
  end;
  UpdateStatus;
end;

procedure TForm1.UpdateStatus;
begin
  case fCurrentPlayer of
    pX: LabelCurrentPlayer.Caption := 'current player: X';
    pO: LabelCurrentPlayer.Caption := 'current player: O';
  end;
end;

procedure TForm1.ButtonNewGameClick(Sender: TObject);
begin
  NewGame;
end;

end.
Delphi-Quellcode:
object Form1: TForm1
  Left = 414
  Top = 203
  BorderStyle = bsToolWindow
  Caption = 'TicTacToe'
  ClientHeight = 264
  ClientWidth = 201
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object LabelCurrentPlayer: TLabel
    Left = 8
    Top = 8
    Width = 67
    Height = 13
    Caption = 'current player:'
  end
  object Button11: TButton
    Tag = 11
    Left = 8
    Top = 32
    Width = 57
    Height = 57
    TabOrder = 0
    OnClick = ButtonClick
  end
  object Button12: TButton
    Tag = 12
    Left = 72
    Top = 32
    Width = 57
    Height = 57
    TabOrder = 1
    OnClick = ButtonClick
  end
  object Button13: TButton
    Tag = 13
    Left = 136
    Top = 32
    Width = 57
    Height = 57
    TabOrder = 2
    OnClick = ButtonClick
  end
  object Button21: TButton
    Tag = 21
    Left = 8
    Top = 96
    Width = 57
    Height = 57
    TabOrder = 3
    OnClick = ButtonClick
  end
  object Button22: TButton
    Tag = 22
    Left = 72
    Top = 96
    Width = 57
    Height = 57
    TabOrder = 4
    OnClick = ButtonClick
  end
  object Button23: TButton
    Tag = 23
    Left = 136
    Top = 96
    Width = 57
    Height = 57
    TabOrder = 5
    OnClick = ButtonClick
  end
  object Button31: TButton
    Tag = 31
    Left = 8
    Top = 160
    Width = 57
    Height = 57
    TabOrder = 6
    OnClick = ButtonClick
  end
  object Button32: TButton
    Tag = 32
    Left = 72
    Top = 160
    Width = 57
    Height = 57
    TabOrder = 7
    OnClick = ButtonClick
  end
  object Button33: TButton
    Tag = 33
    Left = 136
    Top = 160
    Width = 57
    Height = 57
    TabOrder = 8
    OnClick = ButtonClick
  end
  object ButtonNewGame: TButton
    Left = 8
    Top = 224
    Width = 185
    Height = 25
    Caption = 'neues Spiel'
    TabOrder = 9
    OnClick = ButtonNewGameClick
  end
end

Geändert von madas (12. Apr 2017 um 14:28 Uhr)
  Mit Zitat antworten Zitat
ShadowDeath

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

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 13:11
Hab mal die Ausgabe als Screen hochgeladen. Da ist deutlich ersichtlich, dass die Positionen nicht stimmen (wie bereits von euch gesagt). Ich möchte aber nicht einfach copy & pasten, also wäre es super, wenn jemand die Zeit/Lust hätte mir das mit den Tags so zu erklären, dass ich es verstehe & selbst einbauen kann.
Angehängte Grafiken
Dateityp: png TicTacToe.png (36,6 KB, 11x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.660 Beiträge
 
Delphi 12 Athens
 
#6

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 13:46
Wenn Du Dein Spielfeld als Array[0..2, 0..2] of TSpeedButton deklarierst und entsprechend befüllst, kannst Du doch direkt auf den jeweiligen SpeedButton zugreifen und dort in dessen Tag-Eigenschaft schreiben bzw. daraus lesen. Das ist zwar das genaue Gegenteil von Trennung von Logik und Darstellung, macht die Sache aber viel einfacher IMO.
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
nahpets
(Gast)

n/a Beiträge
 
#7

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 14:17
Hab mal die Ausgabe als Screen hochgeladen. Da ist deutlich ersichtlich, dass die Positionen nicht stimmen (wie bereits von euch gesagt). Ich möchte aber nicht einfach copy & pasten, also wäre es super, wenn jemand die Zeit/Lust hätte mir das mit den Tags so zu erklären, dass ich es verstehe & selbst einbauen kann.
Bitte gib' zuerst den Speedbuttons aussagefähige Namen:

Beispiel:

Der Speedbutton unten links bekommt den Namen btnX1Y1.
Der unten in der Mitte btnX2Y1 und unten rechts der btnX3Y1.

Als Tag gibst Du jeweils die beiden Ziffern aus dem Namen ein, also unten links Tag = 11, unten in der Mitte Tag = 21 und unten rechts Tag = 31.

Analog dann auch die übrigen Speedbuttons.

Den Speedbutton 10 benennst Du z. B. btnNeuesSpiel.

Danach übernimmst Du den Vorschlag von himitsu aus Post #4.

Wenn ich jetzt nicht zusehr um die Ecke gedacht habe, könnte es dann schon funktionieren.

Die Eigenschaft Tag ist eigentlich nichts weiter als ein Integer, der grundsätzlich erstmal für nix benötigt wird.
Die Eigenschaft lässt sich aber gut für die Zuordnung von nummerischen Werten, die im Programmablauf benötigt werden, "missbrauchen". Anstatt abzufragen: "Wurde SpeedbuttonX gedrückt" (oder gar den gedrückten Button erst in einer Liste (Self.Controls) zu suchen), kann man hier halt den nummerischen Wert abfragen. Und wenn man den beim Programmdesign so wählt, dass er sich in die Programmlogik einfügt, kann man sich damit sehr viel Arbeit ersparen.
  Mit Zitat antworten Zitat
ShadowDeath

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

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 15:27
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

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.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.660 Beiträge
 
Delphi 12 Athens
 
#9

AW: TicTacToe - Frage zum Programmablauf

  Alt 12. Apr 2017, 15:30
Zitat:
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.
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
Antwort Antwort


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 06:57 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