AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Problem mit Schleifen/Array/??? - Brettspiel Mastermind
Thema durchsuchen
Ansicht
Themen-Optionen

Problem mit Schleifen/Array/??? - Brettspiel Mastermind

Ein Thema von ka8578 · begonnen am 15. Okt 2020 · letzter Beitrag vom 19. Okt 2020
Antwort Antwort
ka8578

Registriert seit: 15. Okt 2020
1 Beiträge
 
Delphi 10.3 Rio
 
#1

Problem mit Schleifen/Array/??? - Brettspiel Mastermind

  Alt 15. Okt 2020, 18:27
Hallo liebes Forum,

ich bin neu hier, (fachfremd) in Informatik unterrichtender Lehrer und bastele gerade an einem Projekt für meinen Wahlpflichtkurs im Jahrgang 10. Ich möchte das Brettspiel "Mastermind" als Smartphone-App umsetzen und stecke nun seit zwei Tagen fest. Leider weiß ich nicht mal, welche die passende Überschrift für mein Problem ist (siehe Titel). Sorry, hier jedenfalls die Infos ...

Ziel d. Spiels:
Das Programm generiert fünf Zufallsfarben, der Spieler muss sie mit möglichst wenigen Versuchen erraten. Er erhält nach jedem Versuch eine Rückmeldung, wie viele richtige Farben er hatte etc. Einen Screenshot des (noch im Rohbau befindlichen) Layouts habe ich angehängt.


Mein Problem:
Ich nutze zur Darstellung 60 TRectangles (12 Reihen mit je 5 Stück), welche dann mit einer Farbe befüllt werden. Ich wollte es vermeiden, 60 Zeilen Code nach dem Schema
Delphi-Quellcode:
Form1.Rec1_1.Fill.Color := TAlphaColorRec.Blue;
Form1.Rec1_2.Fill.Color := ...
...
Form1.Rec12_5.Fill.Color := ... ;
zu schreiben. Ich habe mir gedacht, dass das auch einfacher und effektiver gehen muss und es mit einer for-Schleife (und Arrays) nach folgendem (erstmal vereinfachten) Schema probiert:
Delphi-Quellcode:
...
// Array-Deklaration:
  rechteckenamen: array[1..5] of String;
  rechtecke: array[1..5] of TRectangle;
...
// Befüllen des 1. Arrays (Namen d. Rectangle zunächst als string):
  for I := 1 to 5 do
    rechteckenamen[I] := 'Form1.Rec1_'+inttostr(I) ;

// zum Testen die Namen auf nem Label anzeigen (ja, es klappt!)
  Form1.LbTest.Text := string(rechteckenamen[1])+#13#10 +
    string(rechteckenamen[2])+#13#10 +
    string(rechteckenamen[3])+#13#10 +
    string(rechteckenamen[4])+#13#10 +
    string(rechteckenamen[5])+#13#10 ;

// Befüllen d. 2. Arrays (Umwandlung von string nach TRectangle)
  for J := 1 to 5 do
    rechtecke[J] := TRectangle(rechteckenamen[J]) ;

// wieder Testen (ja, es klappt)
  Form1.LbTest2.Text := string(rechtecke[1])+#13#10 +
    string(rechtecke[2])+#13#10 +
    string(rechtecke[3])+#13#10 +
    string(rechtecke[4])+#13#10 +
    string(rechtecke[5])+#13#10 ;
Soweit funktioniert alles. Sobald ich aber versuche, die im 2. Array gespeicherten und korrekt benannten Rechtecke mit einer Farbe zu versehen (und z.B. die folgende Code-Zeile hinzufüge) ...
  rechtecke[1].Fill.Color := TAlphaColorRec.Blue; ... dann bekomme ich von RAD Studio zwar keine Fehler angezeigt, aber beim Ausführen des Programms (und Klick auf den entsprechenden Button) eine Fehlermeldung "Zugriffsverletzung bei Adresse ... in Modul ..." (siehe Anhang) angezeigt.

Ich bin hier irgendwie mit meinem Latein (bzw. meinen bescheidenen Programmierkenntnissen) am Ende und wäre daher sehr dankbar über ein paar Tipps ...
  • ... wo oben mein Fehler liegt,
  • ... bzw. ob ich komplett auf dem Holzweg bin und mein Vorhaben so wie beschrieben gar nicht realisierbar ist,
  • ... oder es sowieso ganz anders viel besser/einfacher ginge.
Ich hoffe, ich habe nichts Wichtiges vergessen.
Vielen Dank schonmal und viele Grüße

Christoph

PS.: Ich habe diesen Post nach bestem Wissen und Gewissen erstellt. Auch die hier im Forum zu findenden Beiträge zum Brettspiel Mastermind haben mir bei meinem Problem leider nicht weitergeholfen.
Miniaturansicht angehängter Grafiken
screenshot-mastermind.png   screenshot-mastermind-fehler.png  
  Mit Zitat antworten Zitat
TurboMagic

Registriert seit: 28. Feb 2016
Ort: Nordost Baden-Württemberg
2.812 Beiträge
 
Delphi 12 Athens
 
#2

AW: Problem mit Schleifen/Array/??? - Brettspiel Mastermind

  Alt 15. Okt 2020, 21:00
Hallo,

ich hoffe doch, dass dir bewußt ist, dass ein TRectangle ein Objekt ist?
Die Objektinstanz muss man erst erzeugen, bevor man diese Verwenden kann.

So wie du es machst, greifst du auf Speicher zu, der deinem jeweiligen Rectangle
gar nicht gehört. Du schreibst also irgendwo in den Speicher weil die TRectangle
Variablen ohne weitere Initialisierung einfach eine zufällige Speicheradresse enthalten.

So und wie lösen wir das nun?

Hier mal etwas Code der 60 Rectangles erzeugt und in eine Liste packt:
Die Liste ist mittels Generics umgesetzt, falls das konzeptionell aber über
euren Unterricht hinausgeht kann man das auch ein wenig mehr "OldSchool" umsetzen.

Delphi-Quellcode:
unit BoardForm;

interface

uses
  [..] // was alles für eine FMX Form usw. nötig ist
  System.Generics.Collections;

type
  TBoardForm = class(TForm)
  private
    FRectangleList : TObjectList<TRectangle>;

    procedure CreateRectangle(x,y, Width, Height : Single; Color: TAlphaColor);
  public
    procedure CreateRectangles;
  end;

implementation

procedure TBoardForm.CreateRectangle(x,y, Width, Height : Single; Color: TAlphaColor);
var
  Rectangle: TRectangle;
begin
  Rectangle := TRectangle.Create(self); // Owner ist die eigene Form
  Rectangle.Position.X := x;
  Rectangle.Position.Y := y;
  Rectangle.Width := Width;
  Rectangle.Height := Height;
  Rectangle.Fill.Color := Color;

  FRectangleList.Add(Rectangle);
end;

procedure TBoardForm.CreateRectangles;
var
  i : Integer;
begin
  // Liste erzeugen inkl. OwnsObjects auf true, damit die hinzugefügten
  // Rectangles beim späteren Freigeben der Liste auch freigegeben werden.
  // Bei Desktopprogramm und ab Delphi 10.4 auch bei Smartphone App sonst
  // sog. Speicherleck.
  FRectangleList := TObjectList<TRectangle>.Create(true);

  // 60 Rectangles mal irgendwie erzeugen, X/Y Platzierung kannst du selber gerade ziehen
  for i := 1 to 60 do
    CreateRectangle(i*3, i*3, 5, 5, TAlphaColor.claBlue);

  // Ändern der Farbe eines bestimmten Rectangles (des 6.):
  FRectangleList[5].Fill.Color := TAlphaColor.claRed;
end;
Und falls Generics zu heftig für euch ist:
Statt TObjectList<TRectangle> eine normale TObjctList; aus System.Contnrs benutzen
und beim Lesezugriff typecasten: TRectangle(FRectangleList[5]).Fill.Color := TAlphaColor.claRed;

Grüße
TurboMagic
  Mit Zitat antworten Zitat
bcvs

Registriert seit: 16. Jun 2011
668 Beiträge
 
Delphi 12 Athens
 
#3

AW: Problem mit Schleifen/Array/??? - Brettspiel Mastermind

  Alt 16. Okt 2020, 07:13
Oder, wenn du die Rectangles nicht zur Laufzeit, sondern im Objekt-Inspector erzeugt, dieser Ansatz, den du schon versucht hast:

Statt:
Delphi-Quellcode:
// Befüllen des 1. Arrays (Namen d. Rectangle zunächst als string):
  for I := 1 to 5 do
    rechteckenamen[I] := 'Form1.Rec1_'+inttostr(I) ;
so:
Delphi-Quellcode:
For i:=1 to 5 do
  rechtecke[i]:=FindComponent('Rec1_'+inttostr(I));
Damit speicherst du die Objektinstanzen der automatisch erzeugten Rectangles im deinem rechtecke - Array und kannst später darüber darauf zugreifen. Dein Array Rechteckenamen brauchst du nicht.

Aber unbedingt das 'Form1' weglassen. Das gehört nicht zum Namen der Komponente, sondern ist der Name des Forms, auf dem die Komponente liegt.

Zitat:
Delphi-Quellcode:
// Befüllen d. 2. Arrays (Umwandlung von string nach TRectangle)
  for J := 1 to 5 do
    rechtecke[J] := TRectangle(rechteckenamen[J]) ;

// wieder Testen (ja, es klappt)
  Form1.LbTest2.Text := string(rechtecke[1])+#13#10 +
    string(rechtecke[2])+#13#10 +
    string(rechtecke[3])+#13#10 +
    string(rechtecke[4])+#13#10 +
    string(rechtecke[5])+#13#10 ;
Auch hier bitte das Form1. weglassen oder durch Self ersetzen. Form1 ist die Instanzvariable des Forms. Die kann aber auch ganz anders heißen. In deinem Fall mag das gehen, aber wenn du mal eine zweite Instanz eines Forms erzeugst, greifst du sonst immer auf die erste Instanz zu oder gar ins Leere.

Abgesehen davon kann die Umwandlung von String zu TRectangle nicht funktionieren. Du speicherst hier einen String in deinem Rechtecke-Array, aber das ist nur der Name des Rectangles, nicht das Rectangle selbst.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Problem mit Schleifen/Array/??? - Brettspiel Mastermind

  Alt 16. Okt 2020, 08:38
Was mich jetzt am Meisten überrascht, erschreckender Weise, ist,
dass der Compiler hier wirklich keinen Fehler oder zumindestens eine Warnung wirft.


Zitat:
Delphi-Quellcode:
// Befüllen d. 2. Arrays (Umwandlung von string nach TRectangle)
  for J := 1 to 5 do
    rechtecke[J] := TRectangle(rechteckenamen[J]) ;

// wieder Testen (ja, es klappt)
  Form1.LbTest2.Text := string(rechtecke[1])+#13#10 +
    string(rechtecke[2])+#13#10 +
    string(rechtecke[3])+#13#10 +
    string(rechtecke[4])+#13#10 +
    string(rechtecke[5])+#13#10 ;
Klar, aber da du nun den Mist geaut hast, hast du es auch verdient, dass es knallt.
Man konvertiert keine "inkompatiblen" Typen ineinander.

TRectangle ist ein TObject und kein string.


FindComponent ist eine Methde, die ein Objekt dort findet, wo es über den Owner drin ist.
Delphi-Quellcode:
R := TRectangle.Create(TheOwner);
R.Name := 'abc';

...

R := TheOwner.FindComponent('abc');
Was man über den FormDesigner draufgelegt hat, das hat als Owner die Form.
Drum geht dort Self.FindCompoent() und in Methoden der eigenen Form, da kann man den Owner auch weglassen, daher einfach nur noch FindComponent().


Zitat:
string(rechteckenamen[5])
rechteckenamen ist schon ein String, also nutzlos zu casten.


Wenn du von Casts keine Ahnung hast, dann lasst es bitte sein.
Und lerne bitte zuerst wie man es richtig macht,
denn sonst machst du, so wie hier, nur das Speichermanagement kaputt und freust dich über das "schöne" Ergebnis, ein knallendes Feuerwerk.


Zitat:
Form1.Rec1_1.Fill.Color :=
Wenn dein Code in eine TForm1.Methode liegt, dann lass' unbedingt auch den Zugriff auf die globale Variable weg.
Falls du unbedingt etwas benötigst, dann verwende an diesen Stellen das Self.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu (16. Okt 2020 um 08:52 Uhr)
  Mit Zitat antworten Zitat
DasWolf

Registriert seit: 7. Jun 2016
75 Beiträge
 
Delphi 10.1 Berlin Professional
 
#5

AW: Problem mit Schleifen/Array/??? - Brettspiel Mastermind

  Alt 19. Okt 2020, 08:36
Zitat:
string(rechteckenamen[5])
rechteckenamen ist schon ein String, also nutzlos zu casten.


Wenn du von Casts keine Ahnung hast, dann lasst es bitte sein.
Und lerne bitte zuerst wie man es richtig macht,
denn sonst machst du, so wie hier, nur das Speichermanagement kaputt und freust dich über das "schöne" Ergebnis, ein knallendes Feuerwerk.
Wenn man einem Lehrer etwas beibringen will, in diesem Falle sehr oberlehrerhaft, dann bitte richtig. Ansonsten wird es den Schülern falsch mitgegeben.

rechteckenamen ist kein String, sondern ein Array. rechteckenamen[5] ist ein String.
Wenn er keine Ahnung von Casts hat, dann soll er es lernen, aber nicht sein lassen.
Was sind das denn für Empfehlungen hier?!
  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 05:06 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