Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Freien Platz ermitteln (https://www.delphipraxis.net/165382-freien-platz-ermitteln.html)

VkPenguin 27. Dez 2011 16:53

Freien Platz ermitteln
 
Hallo zusammen, ich hab malwieder ein Problem.
Details die keine Rolle spielen lasse ich der einfachheit halber mal Weg, aber im Prinzip habe ich folgendes Problem: Mein Programm soll "Zähler" Kreise der Größe "Groesse" Zeichnen. Diese werden voher festgelegt. Die Y-Achsenposition ist immer gleich. Nun möchte nicht, dass er Kreise übereinanderzeichnet, also reicht KreisXPos:=Random(Bildschirmbreite) nicht. Ich hab schon ein bisschen im Internet gesucht und mir aus dem was ich gefunden hab eine Lösung zusammengebaut, die aber Leider nicht funktioniert.... aber warum? Hab es schon mit debuggen probiert, bin aber nicht dahintergekommen. Hier der entscheidende Codeausschnitt:

Delphi-Quellcode:
Var Frei: Array[1..2000] Of Integer; //Tatsächlich Freie Positionen (Wer hat schon mehr als 2000 Pixel als Auflösung? Ist nicht ideal, aber verfeinerungen kann man ja später noch einfügen.)
Var Belegung: Array [1..2000] of Boolean; // Positionen, die in irgendeiner Form von einem Kreis benutzt werden, nicht unbedingt als Ursprung

Procedure XpositionenFestlegen;
Var I,k,J,M:Integer;
Platz:Boolean;
Begin
Zähler:=Random(15); //Anzahl der Kreise

for I := 1 to Zähler do
 Begin
 Platz:=True;
 K:=0;
 Kreisanzahl:=Kreisanzahl+1;
 Groesse:=15;
 
 for J:=1 To Bildschirmbreite Do
 Begin
  if Belegung[J]=False then
  Begin
   Platz:=True;
   for M:=J-Trunc(Groesse/2) To Trunc(J+Groesse/2) DO //Groesse/2 Da der Radius zur einen und zur anderen Seite gemessen werden soll
   Begin
    If Belegung[M]=True Then Platz:=False //Wenn eine benötigten Flächen belegt ist, ist der Platz insgesamt nicht frei
   End;
   if (Platz=True) then
   Begin
    K:=K+1;
    Frei[K]:=J;  
   End;
  End;
 End;
 X:=Frei[Random(K)];
 K:=0;
 KreisPosX:=X;
 For J:=KreisPosX-Trunc(Groesse/2) To (KreisPosX+Trunc(Groesse/2) Do //Fläche, die der neue Kreis einnimmt.
    Begin
    Belegung[J]:=True;
    End;
 End;
End;
(Unwichtiges, was ohne zusammenhang nur verwirren würde habe ich zum besseren Verständnis rausgeschnitten)
Meine Frage also: Kann mir jemand einen Tipp geben, was falsch ist oder wie ich das ganze besser machen könnte? Nur bitte keine Perfekte Lösung Posten, die werde ich als Anfänger wohl eh nicht verstehen - dann bringt es mir nichts, auch wenn es lieb gemeint ist. Danke euch :-)

Sir Rufo 27. Dez 2011 23:49

AW: Freien Platz ermitteln
 
1. Abfrage von Bool-Werten
Falsch ist
Delphi-Quellcode:
var IsValid : Boolen;
...
if IsValid = True then
...
if IsValid = False then
Richtig ist:
Delphi-Quellcode:
var IsValid : Boolen;
...
if IsValid then
...
if not IsValid then
2. Integer-Division
So nicht
Delphi-Quellcode:
var IntValue : integer;
...
IntValue := Trunc( IntValue / 2 );
sondern so
Delphi-Quellcode:
var IntValue : integer;
...
IntValue := IntValue div 2;
3. Flächen Operationen (TRect)
Delphi/Windows bringt von Haus aus schon Routinen mit um mit Flächen zu arbeiten.
z.B. Delphi-Referenz durchsuchenIntersectRect

Merk dir also zu jedem Kreis (in einem Array) die Fläche, die dieser Kreis belegt und prüfe diese Liste der Flächen

VkPenguin 28. Dez 2011 00:55

AW: Freien Platz ermitteln
 
Hi, danke für deine Antwort! Nur verstehe ich nicht ganz, warum.. Also ich meine, was ist denn der Unterschied zwischen den beiden Varianten? Werde es dann aber ab jetzt so handhaben. Und zu dem dritten: Auch das werd ich mir mal anschaun und dann später (heute nichtmehr :) ) im Programm ändern, ist sicherlich die geschicktere Variante.. Aber ich verstehe dennoch nicht, warum es so, wie ich es gemacht habe, nicht auch geht...?

himitsu 28. Dez 2011 01:19

AW: Freien Platz ermitteln
 
Delphi-Quellcode:
var B: Boolean;

B := Boolean(3);

if B = True then
  ShowMessage('True')
else if B = False then
  ShowMessage('False')
else
  ShowMessage('hmm?');

if B then
  ShowMessage('2: True')
else if not B then
  ShowMessage('2: False')
else
  ShowMessage('2: hmm?');

VkPenguin 29. Dez 2011 15:22

AW: Freien Platz ermitteln
 
Habe die Schreibweisen wie ihr es vorgeschlagen habt gleich überall im Programm geändert, macht einfach mehr Sinn.

@Sir Rufo:
Zitat:

Zitat von Sir Rufo (Beitrag 1143397)
Delphi/Windows bringt von Haus aus schon Routinen mit um mit Flächen zu arbeiten.
z.B. Delphi-Referenz durchsuchenIntersectRect

Merk dir also zu jedem Kreis (in einem Array) die Fläche, die dieser Kreis belegt und prüfe diese Liste der Flächen

war glaub ich ein wirklich guter Tipp. Allerdings konnte ich keine entsprechende Funktion für Kreise finden. Ich könnte zwar für jeden Kreis noch ein temporäres Rechteck erstellen, um damit zu rechnen, aber das ist keine sehr elegante Lösung.

Aber im Prinzip müsste es doch so in der Richtung gehen:
*Pseudo-Code*
Delphi-Quellcode:
For I:=1 To AnzahlDerKreise Do
Begin
Überprüfe überschneidung Kreis(I) und NeuerKreis
If KeineÜberschneidung Then Kreis kann gezeichnet werden
End;
Allerdings wäre das ja auch nicht ganz das gelbe vom Ei, denn dann würde das Programm ja solange immer wieder an zufälligen Positionen versuchen, einen Kreis zu zeichnen, bis es irgendwann passt. Besser wäre ja, wenn es ermitteln würde, wo ein Kreis hinpasst und dann eine zufällige Position davon aussuchen würde oder nicht? Das war ja das Ziel von
Delphi-Quellcode:
 X:=Frei[Random(K)]; //Frei ist das Array mit freien Plätzen
Ich weiß allerdings nicht, wie ich das hiermit umsetzen soll. Meint ihr, es ist der richtige Weg, wenn ich in der Richtung weitermache?

himitsu 29. Dez 2011 15:30

AW: Freien Platz ermitteln
 
Wann berühren sich Kreise?

wenn der Abstand = 0 ist
oder
der Abstand der Mittelpunkte der Summe der Radien entspricht


Delphi-Quellcode:
if Abstand_der_Kreismittelpunkte >= Radius_des_einen_Kreises + Radius_des_andern_Kreises then
  passt;

// oder
if Abstand_der_Kreismittelpunkte - Radius_des_einen_Kreises - Radius_des_andern_Kreises >= 0 then // Abstand größer-gleich 0
  passt;

PS: Ein Array mit freien Plätzen, wo du nur einen Platz prüfen mußt, das geht nur, wenn
- alle Kreise gleich groß
- alle Kreise genau auf solchen Plätzen liegen, also in einem definierten Raster

Sir Rufo 29. Dez 2011 20:55

AW: Freien Platz ermitteln
 
Die Kreise liegen doch alle auf einer Achse, somit ist es egal, ob du die Kreisfläche oder vereinfacht das umschließende Quadrat des Kreises prüfst ;)

VkPenguin 30. Dez 2011 19:14

AW: Freien Platz ermitteln
 
Nabend zusammen,
hab mich jetzt nocheinmal eingehend damit beschäftigt und das ganze durch den Debugger laufen lassen. Dabei sind mir zwei Sachen aufgefallen:

1. Der Fehler. Ich weiß garnicht, wie ich so blöd sein kann :P Der Tipp mit "div 2" statt "/2" war ja gut, da ich aber ohnehin den Radius und nicht den Durchmesser als "Größe" festgelegt hatte, war das totaler Blödsinn.. Es funktioniert also jetzt, danke für eure Tipps! :)
2. (Und das ist wirklich seltsam) Für die Procedur habe ich eine lokale Variable deklariert, die AM ANFANG der Procedur, also schon vor dem ersten Zugriff einen gigantischen Wert (etwa: 2012404120) hat. Das kann doch garnicht sein ?! Wenn ich am Anfang "Variable:=0;" eingebe, funktioniert alles.

himitsu 30. Dez 2011 19:18

AW: Freien Platz ermitteln
 
2. Wenn du eine Variable nicht initialisierst, dann brauchst du dich nicht wundern, wenn dort ein "zufälliger" Wert drin steht.

Lokale Variablen werden nunmal nicht automatisch intialisiert. :stupid:

VkPenguin 30. Dez 2011 19:31

AW: Freien Platz ermitteln
 
Okay, aber was soll das denn? Ich muss also jede lokale Variable erst initialisieren? Wieder was gelernt :P


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:29 Uhr.
Seite 1 von 2  1 2   

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