![]() |
Sammelbilder [lineares Feld]
Hi Delphi-Praxis Community,
folgende Problemstellung habe ich: Eine Schokoladenfirma möchte den Umsatz ihrer Schokolade ankurbeln. Die Werbeabteilung kommt auf die (nicht gerade originelle) Idee, mit Sammelbildern neue Käufer zu gewinnen. Jeder Schokoladentafel soll ein Sammelbild beigepackt werden. Mehrere verschiedene Bilder bilden eine Serie, und die Käufer sollen (mindestens) so viele Tafeln kaufen, bis sie die Serie komplett haben. Dann interessiert, wie viele Schokoladentafeln im Mittel gekauft werden müssen, bis eine Serie vollständig ist. Voraussetzung ist dabei, dass die verschiedenen Bilder in gleicher Anzahl beigelegt und die Tafeln in die Versandkartons gut gemischt und verpackt werden. Verwenden Sie einen Array, der so viele Elemente hat wie es Bilder gibt. Vereinbaren Sie außerdem Variable für die Anzahl der noch in der Serie fehlenden Bilder und der schon gesammelten Bilder. Die Anzahl der Bilder in der Serie könnte als Konstante vereinbart werden. Oookay :D Also nehmen wir mal an, es gibt 10 Bilder zu sammeln, dann wären die Variablen folgendermaßen:
Delphi-Quellcode:
Ich habe jetzt mehrere Ideen, die mir im Kopf herumgeistern, aber irgendwie bringe ich sie nicht zusammen in einen richtigen Code. Könnt ihr mir vielleicht helfen ? Meine Idee ist eben, dass z.B. wenn man das 3. Bild zieht, die Variable um 1 addiert wird, also
procedure TForm1.Button1Click(Sender: TObject);
var fehlend, schongekauft : integer; Bilder : array [1..10] of integer;
Delphi-Quellcode:
In der Schleife wird das dann überprüft und dann wird alles weitere berechnet:
Bilder[3] := Bilder [3] + 1
Delphi-Quellcode:
Also wie gesagt, ich weiß nicht genau, wie ich da rangehen soll. Vielleicht könnt ihr mir ja mal ein paar Tips geben. Das wäre echt suuper ! IF Bilder [5] = 0 THEN fehlend := fehlend - 1; Hier ist schonmal ein klitzekleiner Anfang :
Delphi-Quellcode:
Mit freundlichen Grüßen
begin
randomize; schon := 0; fehlend := 10; me2u |
Re: Sammelbilder [lineares Feld]
Hi me2u!
Laß uns das Problem mal systematisch angehen. Als erstes brauchen wir die Variablen mit denen wir arbeiten wollen. Die gebe ich der Einfachheit mal vor:
Delphi-Quellcode:
So, jetzt gehts richtig los.
const
BILDER_GESAMT=10; //logisch oder? var Bilder : array[0..BILDER_GESAMT-1] of Cardinal; //dadurch das wir hier die Konstante nutzen, brauchen wir bei einer Änderung der Bilderzahl nicht immer die Dimension des Arrays anpassen Schokoladen : Cardinal; //die Anzahl der Schokoladen, die wir kaufen BilderKomplett : Boolean; //wird true sein, wenn wir alle Bilder gesammelt haben BildIndex : Cardinal; //eine Zählvariable um durch das Array zu laufen Am Anfang haben wir 0 Schokoladen gekauft (worüber sich der Geldbeutel freut :) ). Also müssen wir Schokoladen auf 0 setzen (deine Aufgabe ist es ab jetzt, dir den Code zu dem auszudenken, was ich sage :) ) Auch haben wir am Anfang noch kein einziges Bild gesammelt. Also sollten wir alle Felder im Array auf 0 setzen. Als nächstes kommt die Einkaufsschleife :) ... eine Schleife, in der wir solange Schokoladen kaufen bis wir alle Bilder gefunden haben. Wir hören erst auf mit dem Schokolade kaufen, wenn wir alle BilderKomplett ;) haben. Der Inhalt der Schleife beschreibt einen Einkauf. Was passiert dabei? Die Anzahl der Schokoladen erhöht sich um 1. (Was sonst?) Wir bekommen auch ein neues Bild in unsere Sammlung. (Hinweis:
Delphi-Quellcode:
liefert bei obiger Deklaration immer einen gültigen Index aus dem Array) Also muss der Wert des entsprechenden Feldes im Array um eins erhöht werden.
Random(BILDER_GESAMT)
Und da wir nun hoffen, endlich alle Bilder gefunden zu haben, kontrollieren wir, ob wir von jedem Bild mindestens eins haben. Wenn das so ist können wir sagen das wir alle BilderKomplett haben. Damit sollte auch unsere Einkaufsschleife beendet sein. In der Variable "Schokoladen" wissen wir nun, wieviele Schokoladen wir kaufen mussten, um alle Bilder zu bekommen. Das Ganze kann man jetzt in eine Funktion packen und diese N-mal aufrufen und damit den Mittelwert (lt. Aufgabenstellung) errechnen. So, ich hoffe, das hat dir ein wenig geholfen. Falls du Lust hast, können wir am Ende deiner Untersuchungen unsere Quellcodes mal vergleichen. :) |
Re: Sammelbilder [lineares Feld]
Zitat:
|
Re: Sammelbilder [lineares Feld]
Hi,
ich tippe mal, dass es um diese Zahl geht. Zitat:
|
Re: Sammelbilder [lineares Feld]
Jelly meinte wohl nicht die Fragestellung des Lehrers(?) sondern was die Frage von me2u ist.
|
Re: Sammelbilder [lineares Feld]
Hiho,
vielen vielen Dank für die Anleitung @chaosben. Momentan bin ich noch in der Schule. Allerdings werde ich gegen Abend gleich mal das austesten, was du vorgeschlagen hast. Ich melde mich wieder, sobald ich nicht mehr weiter weiß. Bis später ;) [edit] Ou man, was hab ich da nur zusammengemurkst :D
Delphi-Quellcode:
Hilfe :D Momentan gibt er noch eine Fehlermeldung des Debuggers aus. Ich weiß zwar, was man machen muss, kann es aber irgendwie nicht in Code umsetzen.
procedure TForm1.Button1Click(Sender: TObject);
const bilder_gesamt = 10; //Anzahl aller Bilder var Bilder : array [0..(bilder_gesamt-1)] of boolean; Tafeln : integer; //Anzahl der Tafeln Schokolade, die gekauft werden fehlend : integer; //Anzahl der Bilder, die man noch nicht gesammelt hat i : integer; //Zählvariable begin //Zufallsgenerator initialisieren randomize; //Startwerte setzen Tafeln := 0; fehlend := 10; for i := 1 to bilder_gesamt do Bilder[i] := false; //Verarbeitung: "Einkauf" Schleife for i := 1 to 100 do begin Tafeln := Tafeln + 1; IF Bilder[random(bilder_gesamt)] = false THEN begin Bilder[random(bilder_gesamt)] := true; fehlend := fehlend - 1; end ELSE exit; end; //Ausgabe lblAusgabe.Caption := 'Man muss ' + IntToStr(Tafeln) + ' Tafeln kaufen.'; end; end. Man setzt immer array[random(10)] auf true und guckst jedes Mal ob alle 10 Elemente true sind, also ob man alle Bilder gesammelt hat. Wenn das der Fall ist kann man abbrechen. Aber was ich da mache, ist Schwachsinn oder ? [/edit] mfg me2u |
Re: Sammelbilder [lineares Feld]
Sorry für den Doppelpost !
|
Re: Sammelbilder [lineares Feld]
Ein paar Dinge ;)
1. Doppelposts sind erst ab 24 h erlaubt (lieber editieren. Die Antworter werden es dir danken) 2. Benutzte statt einer for-schleife eine while-schleife. Weil es kann ja sein, dass man mit 100 Tafeln immer noch nicht alle gefunden hat 3. Du machst einen größeren Fehler bei der Zuweisung:
Delphi-Quellcode:
Und zwar erstellst du einmal beim überprüfen und einmal beim setzen eine Zufallszahl, welche unterschiedlich sein können.
if x[Random(..)] = false then
x[Random(..)] := true; Also =>
Delphi-Quellcode:
4. Wenn du das Bild schon besitzt beendet er die Prozedur ;) Was nicht im Sinne der Aufgabe ist.
a := Random(..)
if x[a] = false then x[a] := true; Mein Tipp wäre also: Durchlaufe die Schleife solange bis du keine fehlenden Bilder mehr hast. (fehlende Bilder ist eine Variable) In jeden druchlauf überprüfst du ob du das Bild schon hast. Wenn es ein neues Bild ist, setze ein weniger fehlendes Bild und setze das Bild auf wahr. |
Re: Sammelbilder [lineares Feld]
So, da du dir schon soviel Mühe gegeben hast, poste ich mal meinen Code. Vielleicht inspiriert er dich noch ein bißchen.
Delphi-Quellcode:
Deine Idee mit dem Array of Boolean ist auch schön ... imho schöner als meine Zählerei. :)
procedure TForm1.btn_Button1Click(Sender: TObject);
const BILDER_GESAMT=10; var Bilder : array[0..BILDER_GESAMT-1] of Cardinal; Schokoladen : Cardinal; BilderKomplett : Boolean; BildIndex : Cardinal; begin Schokoladen:=0; for BildIndex:=Low(Bilder) to High(Bilder) do Bilder[BildIndex]:=0; Randomize; BilderKomplett:=false; while not BilderKomplett do begin Inc(Schokoladen); Inc(Bilder[Random(BILDER_GESAMT)]); BilderKomplett:=true; for BildIndex:=Low(Bilder) to High(Bilder) do BilderKomplett:=BilderKomplett and (Bilder[BildIndex]>0); end; btn_Button1.Caption:=IntToStr(Schokoladen); end; |
Re: Sammelbilder [lineares Feld]
Zitat:
Delphi-Quellcode:
Du brauchst hier natürlich "BilderKomplett" nicht mehr.
{VAR}
Fehlend, rnd : Cardinal; {ANSTELLE DER WHILE-SCHLEIFE} Fehlend := Length(Bilder); while Fehlend > 0 do begin Inc(Schokoladen); rnd := Random(BILDER_GESAMT); Inc(Bilder[rnd]); if Bilder[rnd] = 1 then Dec(Fehlend); end; |
Re: Sammelbilder [lineares Feld]
Ja Fabian, ist klar. Die Optimierungen kann man natürlich noch viel weiter treiben. Ich habs nur nicht gemacht, damit es me2u auch versteht. Aber du hast natürlich recht.
|
Re: Sammelbilder [lineares Feld]
Hi, ich habe mittlerweile folgenden Code: Ich habe übrigens das mit dem boolean geändert, kam irgendwie gerade so, als ich an anderer Stelle das mit + 1 eingebaut habe und dafür natürlich integer oder cardinal benötige.
Delphi-Quellcode:
Jetzt muss man ja theoretisch aus den ganzen Werten, die man rausbekommt einen Mittelwert berechnen. Dafür muss man aber die ganze Prozedur öfters ausführen lassen. Wie kann man so etwas machen? Meine Idee wäre jetzt alles oben bei private reinzuschreiben und unten bei "procedure TForm1.Button1Click(Sender: TObject);" dann alles öfter hinzuschreiben. Ist aber sehr unsauber :D
procedure TForm1.Button1Click(Sender: TObject);
const bilder_gesamt = 10; //Anzahl aller Bilder var Bilder : array [0..(bilder_gesamt-1)] of integer; Tafeln : integer; //Anzahl der Tafeln Schokolade, die gekauft werden fehlend : integer; //Anzahl der Bilder, die man noch nicht gesammelt hat i : integer; //Zählvariable begin //Zufallsgenerator initialisieren randomize; //Startwerte setzen Tafeln := 0; fehlend := bilder_gesamt; //Zuerst müssen alle Bilder den Wert 0 haben for i := 0 to (bilder_gesamt - 1) do Bilder[i]:=0; //Verarbeitung: "Einkauf" Schleife while fehlend > 0 do begin Tafeln := Tafeln + 1; i := Random(bilder_gesamt); //Bild wird als gekauft "markiert" Bilder[i] := Bilder[i] + 1; //Wenn man das Bild hat, wird fehlend verringert IF Bilder[i] = 1 THEN fehlend := fehlend - 1; end; //Ausgabe lblAusgabe.Caption := 'Man muss ' + IntToStr(Tafeln) + ' Tafeln kaufen bis man alle Bilder gesammelt hat.'; end; Und natürlich bräuchte man eine neue Variable, sagen wir mal "Mittelwert". Man muss ja dann immer das Ergebnis bei Tafeln irgendwie zwischenspeichern und am Ende dann rechnen Mittelwert = (Ergebnis1 + Ergebnis2 + Ergebnis3 + ...) / Anzahl Durchläufe Wie realisiert man so etwas am besten ohne diese Ergebnis1 bis x ? Mit freundlichen Grüßen me2u P.S. Ihr seid echt das geilste Delphi Forum, das ich kenne ! Ohne euch hätte ich das wahrscheinlich nicht gepackt. Aber jetzt ist mir ganz klar, was da oben beim Einkaufen der Schokolade passiert :D |
Re: Sammelbilder [lineares Feld]
Zitat:
Delphi-Quellcode:
Zum Schluss nur noch dein Ergebnis durch die Anzahl der Durchläufe teilen:
Ergebnis := Ergebnis + Tafeln ;
Delphi-Quellcode:
var
Ergebnis, i : integer ; begin Ergebnis := 0 ; for i := 1 to AnzahlDurchlaeufe do begin // dein Code Ergebnis := Ergebnis + Tafeln ; end ; TafelnMittelwert := Ergebnis / AnzahlDurchlaeufe ; // Ausgabe end ; |
Re: Sammelbilder [lineares Feld]
Du kannst ja für die From eine eigene Prozedur schreiben wie "Bilder sammeln" o.ä. und das dann mehrmals ausführen.
Delphi-Quellcode:
Nun könntest du das über mehrere Wege berechnen:
procedure BilderSammeln;
begin // Deine ButtonClick-Prozedur end; procedure Button1Click(Sender : Tobject); begin BilderSammeln; end; 1. Du erstellst ein globales, privates array of Cardinal (o.ä.) und lässt dass dann Füllen und später berechnen 2. Du nimmst nur eine globale Variable, und hast eine bestimmte Anzahl von Durchläufen (z.B.) 10 und schreibst alle Werte rein, und berechnest dass dann... 3. Du nimmst die 1. oder 2. Variante, aber dann lokal. Dann muss deine BilderSammeln ein Rückgabewert bekommen ;) Ich hätte es so gemacht:
Delphi-Quellcode:
procedure Button1Click(Sender : TObject);
const Durchlaeufe= 10; var Gesamt : Cardinal; i : Cardinal; begin for i := 0 to Durchlaeufe- 1 do begin Gesamt := Gesamt + BilderSammeln; // Alternativ: inc(Gesamt, BilderSammeln); end; Showmessage('Man benötigt bei ' + IntToStr(Durchlaeufe) + ' Durchläufe(n) ' + IntToStr(Round(Gesamt / Durchlaeufe)) + ' Tafeln Schokolade durchschnittlich'); end; |
Re: Sammelbilder [lineares Feld]
Sorry, dass ich nochmal nerve, aber ich habe Probleme bei dem Mittelwert berechnen. Irgendwie bin ich ganz durcheinander ^^ Bin mir auch nicht sicher, was ich da mit den ganzen neuen Variablen (x und durchlaeufe) überhaupt gemacht hab bzw. machen wollte.
Hier mein Code:
Delphi-Quellcode:
Irgendwelche Vorschläge, wieso das eine Endlosschleife gibt, wären sehr hilfreich. Achja, und mache ich da nicht auch Sachen, die sinnlos sind? Also, was könnte man optimieren ?
procedure TForm1.btnBerechnenClick(Sender: TObject);
var Bilder : array of integer; bilder_gesamt: integer; //Anzahl aller Bilder Tafeln : integer; //Anzahl der Tafeln Schokolade, die gekauft werden fehlend : integer; //Anzahl der Bilder, die man noch nicht gesammelt hat durchlaeufe : integer; //Zählvariable Mittelwert : real; Ergebnis : integer; //Summe aller Tafeln AnzahlDurchlaeufe : integer;//gewünschte Anzahl der Durchläufe i, x : integer; //Zählvariablen begin //Zufallsgenerator initialisieren randomize; //Startwerte setzen bilder_gesamt := StrToInt(edtGesamtbilder.Text); //dynamischer Array SetLength(Bilder, bilder_gesamt); AnzahlDurchlaeufe := StrToInt(edtDurchlaeufe.Text); Ergebnis := 0; //Verarbeitung: "Einkauf" Schleife for durchlaeufe := 1 to AnzahlDurchlaeufe do begin while fehlend > 0 do begin Tafeln := 0; fehlend := bilder_gesamt; //Zuerst müssen alle Bilder den Wert 0 haben for i := 0 to (bilder_gesamt - 1) do begin Bilder[i]:=0; end; Tafeln := Tafeln + 1; x := Random(bilder_gesamt); //Bild wird als gekauft "markiert" Bilder[x] := Bilder[x] + 1; //Wenn man das Bild hat, wird fehlend verringert IF Bilder[x] = 1 THEN begin fehlend := fehlend - 1; end; end; //Man addiert alle Tafeln Ergebnis := Ergebnis + Tafeln; end; Mittelwert := Ergebnis/AnzahlDurchlaeufe; //Ausgabe lblAusgabe.Caption := 'Man muss rund ' + FloatToStr(Mittelwert) + ' Tafeln kaufen bis man alle Bilder gesammelt hat.'; end; end. mfg me2u |
Re: Sammelbilder [lineares Feld]
In einem solchen Fall startet man das Programm und läßt es erstmal loslaufen. Dann wechselt man in die IDE und setzt in der Prozedur, die gerade läuft, einen Breakpoint. Wenn der Debugger dann dort anhält, kann man per F7/F8 durch den Code steppen und sich überlegen, ob das was das Programm tut, sinnvoll ist.
Dein Problem ist folgendes: Jedesmal wenn du in den Laden gehst, um eine neue Schokolade zu kaufen, wirfst du alle schon gesammelten Bilder in den Papierkorb. Auf diese Weise machst du den Schokoladenhersteller reich und du wirst niemals alle Bilder gesammelt haben. :) |
Re: Sammelbilder [lineares Feld]
Zitat:
|
Re: Sammelbilder [lineares Feld]
Guten Abend,
ich habe mittlerweile ein funktionstüchtiges Programm für das Problem fertiggestellt. Es ist eigentlich garnicht so schwer :D Und Jelly, du hattest Recht. Ich hatte das mit dem fehlend und noch irgendwas anderes in der falschen Schleife drin und es wurde immer wieder neu gesetzt und konnte somit nie eine andere Bedingung erfüllen. Hier nochmal der fertige Code:
Delphi-Quellcode:
Ahh, ein tolles Gefühl, wenn's endlich läuft ! Vielen Dank nochmal an alle, die hier gepostet haben. Ohne euch hätte ich das bestimmt nicht hingekriegt. Ihr seid einfach die besten!
procedure TForm1.btnBerechnenClick(Sender: TObject);
var Bilder : array of integer; bilder_gesamt: integer; //Anzahl aller Bilder Tafeln : integer; //Anzahl der Tafeln Schokolade, die gekauft werden fehlend : integer; //Anzahl der Bilder, die man noch nicht gesammelt hat durchlaeufe : integer; //Zählvariable Mittelwert : real; Ergebnis : integer; //Summe aller Tafeln AnzahlDurchlaeufe : integer;//gewünschte Anzahl der Durchläufe i, x : integer; //Zählvariablen begin //Zufallsgenerator initialisieren randomize; //Eingabe: Variablen holen bilder_gesamt := StrToInt(edtGesamtbilder.Text); AnzahlDurchlaeufe := StrToInt(edtDurchlaeufe.Text); Ergebnis := 0; //dynamischer Array SetLength(Bilder, bilder_gesamt); //Verarbeitung: "Einkauf" Schleife for durchlaeufe := 1 to AnzahlDurchlaeufe do begin fehlend := bilder_gesamt; Tafeln := 0; //Zuerst müssen alle Bilder den Wert 0 haben for i := 0 to (bilder_gesamt - 1) do begin Bilder[i]:=0; end; while fehlend > 0 do begin Tafeln := Tafeln + 1; x := Random(bilder_gesamt); //Bild wird als gekauft "markiert" Bilder[x] := Bilder[x] + 1; //Wenn man das Bild hat, wird fehlend verringert IF Bilder[x] = 1 THEN fehlend := fehlend - 1; end; //Man addiert alle Tafeln Ergebnis := Ergebnis + Tafeln; end; Mittelwert := Ergebnis/AnzahlDurchlaeufe; //Ausgabe lblAusgabe.Caption := 'Man muss rund ' + FloatToStr(Mittelwert) + ' Tafeln kaufen bis man alle Bilder gesammelt hat.'; end; end. Mit freundlichen Grüßen me2u |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 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