Delphi-PRAXiS
Seite 3 von 7     123 45     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Zufallszahl ziehen ohne wiederholung (https://www.delphipraxis.net/128822-zufallszahl-ziehen-ohne-wiederholung.html)

himitsu 7. Feb 2009 08:06

Re: Zufallszahl ziehen ohne wiederholung
 
Zitat:

Zitat von blink182
hab auch mal eben noch was getestet, ist wahrscheinlich nicht so gut wie der oben gepostete code, da es nach 40 klicks eine endlosschleife gibt, aber das kannst du ja noch beheben ;)

die Endlosschleife wär ja noch nichtmal das Schlimmste

Delphi-Quellcode:
for i:=0 to length(zufall) do
hier eine Exception (wenn du mal die Bereichsprüfung anschaltes)

Delphi-Quellcode:
a:=random(39);
die 40 (Index 39) gibt's nicht, da 0..38

Delphi-Quellcode:
zufall: array of integer;
OK, kein Fehler, aber der Index is die Zahl-1, da braucht man nicht unbedingt ein Array of Integer ... Array of Boolean hätt's auch getan,
denn die zugehörige Zahl kann man sich ja aus dem Index errechnen.
PS: bei Array[1..40] of Boolean wär der Index direkt die Zahl
Delphi-Quellcode:
If MeinZahlenArray[gezogeneZahl] Then {zahl wurde gezogen}

oder gleich ein Set of 1..40 :angel:
Delphi-Quellcode:
Var gezogeneZahlen: Set of 1..40;
  Zufallszahl: Integer;

gezogeneZahlen := []; // init

If gezogeneZahlen <> [1..40] Then Begin
  Repeat
    Zufallszahl := Random(40) + 1;
  Until not (Zufallszahl in gezogeneZahlen);
  Include(gezogeneZahlen, Zufallszahl);
End Else Raise Exception.Create('Es gibt keine Zahlen mehr.');
MessageBox(0, PChar(Format('Die Zahl %d wurde soeben gezogen.',
  [Zufallszahl])), 'test', MB_OK);
Delphi-Quellcode:
Var gezogeneZahlen: Set of 1..40;
  Zufallszahl, i: Integer;

gezogeneZahlen := [];
For i := 1 to 15 do Begin
  Repeat
    Zufallszahl := Random(40) + 1;
  Until not (Zufallszahl in gezogeneZahlen);
  Include(gezogeneZahlen, Zufallszahl);
  MessageBox(0, PChar(Format('Die %d. Zahl ist eine %d.',
    [i, Zufallszahl])), 'test', MB_OK);
End;

globetrotter77 7. Feb 2009 09:13

Re: Zufallszahl ziehen ohne wiederholung
 
Wenn's nicht mehr als 255 Fragen sein sollen, könnte man auch eine Lösung mit einem String basteln.
Das sieht dann so aus:
Stelle 1 = #1
Stelle 2 = #2
etc.
Nach jedem Ziehen wird das gezogene Zeichen aus dem String gelöscht.

beispielsweise so:
Delphi-Quellcode:
const gesamt=40;
      anzahl=15;
var liste: string;

procedure TForm1.FormCreate(Sender: TObject);
var i:integer;
begin
  Randomize;
  liste:='';
  for i:=1 to gesamt do
    liste:=liste+chr(i);
end;

procedure TForm1.Button1Click(Sender: TObject);
var p,z:integer;
begin
  if length(liste)<=gesamt-anzahl then
  begin
    showmessage('Fertig!');
    exit;
  end;
  p:=Random(length(liste))+1;
  z:=ord(liste[p]);
  delete(liste,p,1);
  frage(z);
end;

procedure TForm1.frage(z: integer);
begin
  ListBox1.Items.Add(IntToStr(z)); // hier sollte natürlich die eigentliche Frage
                                   // mit der Nr. z bearbeitet werden
end;
Zitat:

hatte bisschen Langeweile und hab das ganze mal zu Übungszwecken (und zur Verwirrung) absichtlich bisschen komplexer gelöst *g*
ein sehr hübscher Ansatz! ... *grins*

himitsu 7. Feb 2009 09:24

Re: Zufallszahl ziehen ohne wiederholung
 
@globetrotter77: mit WideString/UnicodeString ginge das bis 65536

und mit einem "eigenem" Delete ginge das noch viel weiter, wobei man da auch direkt die Fragen/Antworten direkt in das array packen kann,
oder da zusätzlich noch einen Benutzt-Boolean in das Array of Record und man braucht garnicht löschen.

walli18 7. Feb 2009 09:41

Re: Zufallszahl ziehen ohne wiederholung
 
@ Globetrotter!
deine Antwort fand ich bis jetzt am besten, da sie für mich einigermaßen verständlich war!
ich weiß nur nicht, wo ich den teil mit
Delphi-Quellcode:
const gesamt=40;
      anzahl=15;
[b]hinpacken soll bei der deklaration!? Public, Private??

globetrotter77 7. Feb 2009 09:43

Re: Zufallszahl ziehen ohne wiederholung
 
Zitat:

Zitat von himitsu
@globetrotter77: mit WideString/UnicodeString ginge das bis 65536

und mit einem "eigenem" Delete ginge das noch viel weiter, wobei man da auch direkt die Fragen/Antworten direkt in das array packen kann,
oder da zusätzlich noch einen Benutzt-Boolean in das Array of Record und man braucht garnicht löschen.

Für den Anfang dürften die 255 bzw. 65535 (!) aber ausreichen!
Das mit dem Benutzt-Kennzeichen funktioniert aber nicht ganz so gut, weil du dann zumindest theoretisch in eine Endlosschleife kommen könntest.

Die Fragen würde ich von außen über eine INI beisteuern.
z.B.
Zitat:

[Frage3]
Frage:=Wann war die russische Oktoberrevolution?
A=1919
B=1920
C=1917
D=1918
Lösung=3
Dann lässt sich das Ganze ganz einfach einheitlich mit Radiobuttons o.ä. darstellen.

globetrotter77 7. Feb 2009 09:47

Re: Zufallszahl ziehen ohne wiederholung
 
Zitat:

Zitat von walli18
@ Globetrotter!
deine Antwort fand ich bis jetzt am besten, da sie für mich einigermaßen verständlich war!
ich weiß nur nicht, wo ich den teil mit
Delphi-Quellcode:
const gesamt=40;
      anzahl=15;
[b]hinpacken soll bei der deklaration!? Public, Private??

Du kannst sie sowohl im Public als auch im Private-Bereich unterbringen.
Da es sich aber um ganz einfache Definitionen handelt, die nicht unbedingt was mit der Klasse zu tun haben, geht es ebenso im implementation-Bereich, wobei du nur darauf achten musst, dass die Definition OBERHALB derjenigen Funktionen und Prozeduren steht, die darauf zugreifen!

z.B. so:
Delphi-Quellcode:
var
  Form1: TForm1;

implementation

{$R *.DFM}

const gesamt=40;
      anzahl=15;

var liste: string;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Randomize;
  ButtonNeuClick(Sender);
end;

walli18 7. Feb 2009 10:03

Re: Zufallszahl ziehen ohne wiederholung
 
Danke Globetrotter, mit deiner Variante hab ichs hinbekommen!!!

globetrotter77 7. Feb 2009 10:12

Re: Zufallszahl ziehen ohne wiederholung
 
Zitat:

Zitat von walli18
Danke Globetrotter, mit deiner Variante hab ichs hinbekommen!!!

Gern geschehen!
Versuch aber auf jeden Fall, genau zu verstehen, wieso das so funktioniert!
Sonst stehst du da nächste Mal wieder da wie der Ochs vor dem Berg! :?

juergen 7. Feb 2009 10:41

Re: Zufallszahl ziehen ohne wiederholung
 
Hallo zusammen,

auch wenn es schon Lösungen gibt, so möchte ich für die genannte Anforderung auf die Umsetzung in Form eines boolschen Array hinweisen.
Für einen Lottogenerator hatte ich es mal wie nachfolgend zu sehen umgesetzt.

Delphi-Quellcode:
procedure TForm1.Btn1Click(Sender: TObject);
var lAb_Anzahl_Werte_Depot: Array[1..49] of Boolean;
     i, Zufallszahl: Integer;
begin
  for i:= 1 to 49 do lAb_Anzahl_Werte_Depot[i]:=false;
  for i:=1 to 6 do begin
   repeat
    Zufallszahl:=random(49)+1
   until lAb_Anzahl_Werte_Depot[Zufallszahl] = false;
   lAb_Anzahl_Werte_Depot[Zufallszahl]:=true;
  end;
  Edit1.Text:='';
  for i:=1 to 49 do
   if lAb_Anzahl_Werte_Depot[i] then Edit1.Text:= Edit1.Text + ' ' + Inttostr(i) + ' ';
end;
Hiermit hat man die 2 Eigenschaften welche benötigt werden (Anzahl von Werten und den boolschen Wert ob schon "gezogen" oder nicht).

himitsu 7. Feb 2009 11:43

Re: Zufallszahl ziehen ohne wiederholung
 
Zitat:

Zitat von globetrotter77
Für den Anfang dürften die 255 bzw. 65535 (!) aber ausreichen!

65536, denn in Delphi-Strings kann man auch die #0 benutzen

Zitat:

Zitat von globetrotter77
Das mit dem Benutzt-Kennzeichen funktioniert aber nicht ganz so gut, weil du dann zumindest theoretisch in eine Endlosschleife kommen könntest.

das kommt darau an, wie du die Abfrage gestaltest.
Delphi-Quellcode:
i := -1;
for i2 := 1 to 40
  if not meinArray[i2].istSchonBenutzt then begin
    i := i2;
    break;
  end;
if i <> -1 then begin
  meinArray[i].isSchonBenutzt := true;
  ShowMessage('Zahl ', i, ' wurde gezogen.');
end else nichts_mehr_frei;
oder besser noch 'nen knuffiges While-Do-Schleifchen
Delphi-Quellcode:
i := 1;
while (i <= 40) and meinArray[i].istSchonBenutzt do Inc(i);
if i <= 40 then begin
  meinArray[i].isSchonBenutzt := true;
  ShowMessage('Zahl ', i, ' wurde gezogen und die Frage is "', meinArray[i].dieFrage, '".');
end else nichts_mehr_frei;


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:40 Uhr.
Seite 3 von 7     123 45     Letzte »    

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