zufällige Zahlenreihe ohne doppelte zahlen

Für Fragen von Einsteigern und Programmieranfängern...
L4Z4RUSN00B
Beiträge: 9
Registriert: Mo 17. Aug 2015, 13:07
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von L4Z4RUSN00B »

Hallo liebe Community,
in Informatik sollen wir zur Zeit mittels Lazarus ein Programm entwickeln, mit dem wir eine Reihe von zufällig gewählter Zahlen anzeigen. Bei dieser Zahlenreihe sollen jedoch keine Zahlen doppelt vorkommen. Einen Quelltext habe ich zwar schon, aber ich würde das Programm gerne mit einer Schleife laufen lassen, sodass man auch einige Parameter verändern kann, da die Zahlenreihe im Moment noch statisch ist, d.h. ich mache eine Reihe von 10 Zahlen, müsste jedoch den gesamten Quelltext ändern, um 11 Zahlen o.ä. zu haben.

so sieht mein Quelltext im Moment aus. Hat einer von euch eine Lösung wie man das geschickter angehen kann?

Code: Alles auswählen

unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
 
type
 
  { TSortier }
 
  TSortier = class(TForm)
    BTgen: TButton;
    BTsort: TButton;
    BTspei: TButton;
    BTauf: TButton;
    LAzahl: TLabel;
    procedure BTaufClick(Sender: TObject);
    procedure BTgenClick(Sender: TObject);
    procedure BTsortClick(Sender: TObject);
    procedure BTspeiClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
 
var
  Sortier: TSortier;
  arr: array of integer;
  i,j,k: integer;
implementation
 
{$R *.lfm}
 
{ TSortier }
{------------------------zufällige Zahlenreihe ohne doppelte Zahlen------------}
procedure TSortier.BTgenClick(Sender: TObject);
begin
  LAzahl.caption:='';
  setlength(arr,10);
  arr[0]:=random(100);
  repeat
    arr[1]:=random(100);
  until arr[1]<>arr[0];
  repeat
    arr[2]:=random(100);
  until (arr[2]<>arr[1]) and (arr[2]<>arr[0]);
  repeat
    arr[3]:=random(100);
  until (arr[3]<>arr[2]) and (arr[3]<>arr[1]) and (arr[3]<>arr[0]);
  repeat
    arr[4]:=random(100);
  until (arr[4]<>arr[3]) and (arr[4]<>arr[2]) and (arr[4]<>arr[1]) and (arr[4]<>arr[0]);
  repeat
    arr[5]:=random(100);
  until (arr[5]<>arr[4]) and (arr[5]<>arr[3]) and (arr[5]<>arr[2]) and (arr[5]<>arr[1]) and (arr[5]<>arr[0]);
  repeat
    arr[6]:=random(100);
  until (arr[6]<>arr[5]) and (arr[6]<>arr[4]) and (arr[6]<>arr[3]) and (arr[6]<>arr[2]) and (arr[6]<>arr[1]) and (arr[6]<>arr[0]);
  repeat
    arr[7]:=random(100);
  until (arr[7]<>arr[6]) and (arr[7]<>arr[5]) and (arr[7]<>arr[4]) and (arr[7]<>arr[3]) and (arr[7]<>arr[2]) and (arr[7]<>arr[1]) and (arr[7]<>arr[0]);
  repeat
    arr[8]:=random(100);
  until (arr[8]<>arr[7]) and (arr[8]<>arr[6]) and (arr[8]<>arr[5]) and (arr[8]<>arr[4]) and (arr[8]<>arr[3]) and (arr[8]<>arr[2]) and (arr[8]<>arr[1]) and (arr[8]<>arr[0]);
  repeat
    arr[9]:=random(100);
  until (arr[9]<>arr[8]) and (arr[9]<>arr[7]) and (arr[9]<>arr[6]) and (arr[9]<>arr[5]) and (arr[9]<>arr[4]) and (arr[9]<>arr[3]) and (arr[9]<>arr[2]) and (arr[9]<>arr[1]) and (arr[9]<>arr[0]);
  LAzahl.caption:=inttostr(arr[0])+' '+inttostr(arr[1])+' '+inttostr(arr[2])+' '+inttostr(arr[3])+' '+inttostr(arr[4])+' '+inttostr(arr[5])+' '+inttostr(arr[6])+' '+inttostr(arr[7])+' '+inttostr(arr[8])+' '+inttostr(arr[9]);
end;
 
"Ich weiß, dass ich nichts weiß!" - Sokrates

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von Michl »

Wie der Ablauf aussehen könnte:
1. einer Variablen eine Zahl per Zufall zuweisen
2. per Schleife alle Zahlen des Arrays mit den Zufallszahlen durchgehen und mit der Variable vergleichen
-> wird in dem Array die Zufallszahl gefunden -> zurück zu Punkt 1
-> wurde die Zufallszahl noch nicht gefunden -> die Variable dem Array zuweisen (ich würde, der Einfachheit halber, bei jeder Zuweisung einer Zufallszahl das Array dynamisch in der Größe anpassen)

Das Ganze in Code zu fassen, solltest du schaffen.

Viel Erfolg!

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Warf
Beiträge: 1908
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von Warf »

Eine andere Lösung wären Sets (Mengen)

Code: Alles auswählen

var MySet: Set of Integer;
...
repeat
  RndVal := random(100);
until not (RndVal in MySet);
// Zahl gefunden jetzt noch dem Set Hinzufügen
MySet += [RndVal];
 
//Löschen einer zahl aus dem Set (falls ein wert aus dem Array überschrieben wird):
MySet -= [Wert]

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von corpsman »

Oder du fängst mit einer Sortierten Liste an (erzeugt durch eine Schleife) und tauscht dann beliebig lange immer 2 Indizes
--
Just try it

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von Michl »

Warf hat geschrieben:Eine andere Lösung wären Sets (Mengen)
Zu beachten wäre dabei, daß sie eine Beschränkung von maximal 256 Elementen haben:

Code: Alles auswählen

var
  MySet: set of 0..255;  //das compiliert
  MySet: set of 0..256;  //das compiliert nicht
  MySet: set of Byte;    //das compiliert
  MySet: set of Integer; //das compiliert nicht   

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

L4Z4RUSN00B
Beiträge: 9
Registriert: Mo 17. Aug 2015, 13:07
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von L4Z4RUSN00B »

Vielen Dank schon mal für diese Lösungsansätze. Ich werde mich dann mal dahinter klemmen und rumprobieren.
"Ich weiß, dass ich nichts weiß!" - Sokrates

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von Mathias »

Eine kleine Demo zum Problem:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
const
  max = 4;
var
  ZZahl: array[0..max - 1] of integer;
 
  function Test(z, l: integer): boolean;
  var
    i: integer;
  begin
    Result := False;
    for i := 0 to l - 1 do begin
      if ZZahl[i] = z then begin
        Result := True;
      end;
    end;
  end;
 
var
  i: integer;
begin
  Memo1.Clear;
  for i := 0 to Length(ZZahl) - 1 do begin
 
    repeat
      ZZahl[i] := Random(max);
    until not Test(ZZahl[i], i);
 
    Memo1.Lines.Add(IntToStr(ZZahl[i]));
  end;
end;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

L4Z4RUSN00B
Beiträge: 9
Registriert: Mo 17. Aug 2015, 13:07
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von L4Z4RUSN00B »

@Warf : Ich habe das mit den Sets ausprobiert und es hat geklappt, bis jetzt habe ich schon einige Male neue Zahlenreihen generiert und noch keine doppelten Zahlen vorgefunden.
@Michl : An Schleifen hatte ich ja auch schon gedacht, nur irgendwie habe ich mich immer in den Schleifen verirrt, bzw. waren die Schleifen immer fehlerhaft. Kannst du mir vielleicht mal ein Beispiel für eine solche Schleife oder Prozedur geben die ich dann ausprobiere?

hier meine aktuelle Lösung und vielen Dank nochmal an alle die mir geantwortet haben:

Code: Alles auswählen

procedure TSortier.BTgenClick(Sender: TObject);
var
  myset : set of 0..100;
begin
  LAzahl.caption:='';
  setlength(arr,10);
  FOR i:=0 TO 9 DO
    begin
      repeat
        arr[i]:=random(100);
      until not (arr[i] in myset);
      myset+= [arr[i]];
      LAzahl.caption:=LAzahl.caption+' '+inttostr(arr[i]);
    END;
end;
"Ich weiß, dass ich nichts weiß!" - Sokrates

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von Michl »

Na ist doch gut! Wenn es funktioniert und du verstehst, warum es funktioniert, dann ist doch alles in Butter!

Generell unterschied sich mein gedachter Ansatz nicht von dem von Mathias:

Code: Alles auswählen

procedure TSortier.BTgenClick(Sender: TObject);
var
  i, Zahl: Integer;
 
  function ZahlInArray: Boolean;
  var
    iTest: Integer;
  begin
    Result := false;
    for iTest in arr do
      if iTest = Zahl then Result := true;
  end;
 
begin
  LAzahl.caption:='';
  SetLength(arr, 0);
  for i := 0 to 9 do begin
    repeat
      Zahl := Random(100);
    until not ZahlInArray;
    SetLength(arr, i + 1);
    arr[i] := Zahl;
    LAzahl.caption:=LAzahl.caption+' '+inttostr(arr[i]);
  end;
end

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von theo »

Übersichtlich wäre auch das (nur als Anregung, es gibt auch mit Listen noch schnellere und andere Varianten)

Code: Alles auswählen

var
  List: TList;
  Zahl: cardinal;
begin
  Randomize;
  List := TList.Create;
  repeat
    Zahl := Random(5);
    if List.IndexOf(Pointer(Zahl)) < 0 then
    begin
      List.Add(Pointer(Zahl));
      ShowMessage(IntToStr(Zahl));
    end;
  until List.Count = 5;
  List.Free;
end

hausi
Beiträge: 132
Registriert: Mi 23. Sep 2009, 08:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von hausi »

Für mein Lottoprogramm habe ich das so gelöst:

vor jeder neuen Zahl habe ich randomize gemacht
Dann mit random eine neue Zahl erzeugt.
Die erste Zahl muss ich nicht vergleichen.
Bei der zweiten Zahl habe ich eine Schleife gemacht und mache solange eine neue Zahl, bis diese nicht gleich der ersten ist.
Bei der dritten Zahl habe ich ebenfalls eine Schleife gemacht und mittels if Abfrage mit der ersten und zweiten Zahl verglichen. Ist die dritte Zahl ungleich der ersten und zweiten, merkt sich das System auch diese Zahl und verlässt die Schleife.
usw usw

Ist zwar viel Schreibarbeit, aber auf diese Weise habe ich keine Zahl doppelt. Zudem kann man ja die Befehlszeilen kopieren und dann ergänzen.

Hausi

gocher
Beiträge: 298
Registriert: Di 23. Nov 2010, 23:41
OS, Lazarus, FPC: Ubuntu/Win, Lazarus trunk, FPC trunk
CPU-Target: 32Bit/64Bit
Wohnort: Geldern
Kontaktdaten:

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von gocher »

ungefähr so

Code: Alles auswählen

type 
  TIntArray: Array of Integer;
function inArray(a: TIntArray; o: Integer): boolean;
var i: Integer;
begin
  result := false;
  for i:=0 to length(a)-1 do
    if a[i]=o then
    begin
      result := true;
      break;
    end;
end;
 
var
  a: TIntArray;
  i, o: Integer;
begin
  i := 0;
  randomize;
  repeat
    setlength(a, i+1);
    o := random(100);
    if not inArray(a, o) then
    begin
      a[i] := o;
      inc(i);
    end;
  until (i=10);

...
MfG Gocher
akt. Projekt: Webserver(HTTPS HTTP/2) mit integrierten CMS in Free Pascal - www.gocher.me

L4Z4RUSN00B
Beiträge: 9
Registriert: Mo 17. Aug 2015, 13:07
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von L4Z4RUSN00B »

@hausi: So hatte ich das vorher auch und hat auch funktioniert, nur ich fand das umständlich jedes Mal den Quelltext zu ändern um die Länge des Arrays zu wechseln. Deshalb hätte ich lieber ne Schleife gehabt so wie es jetzt der Fall ist.
"Ich weiß, dass ich nichts weiß!" - Sokrates

hausi
Beiträge: 132
Registriert: Mi 23. Sep 2009, 08:44
OS, Lazarus, FPC: Winux (L 0.9.xy FPC 2.2.z)
CPU-Target: xxBit

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von hausi »

Ja ist eine gute Idee das so zu machen, vor allem wenn man so viele Zahlen hat. Vielleicht könnte man noch randomize einbauen.

Da ich nicht so ein guter Programmierer bin, programmiere ich ab und zu umständlich, komme aber ans Ziel und ich kann meinen Code lesen und ändern.

Nun ist mir bei diesem Beispiel klar, dass die Zahl in a abgelegt wird. Wie fülle ich nun die Zahlen ab indem ich a(1) für Variable 1 nehme?

Hausi

Benutzeravatar
corpsman
Lazarusforum e. V.
Beiträge: 1496
Registriert: Sa 28. Feb 2009, 08:54
OS, Lazarus, FPC: Linux Mint Mate, Lazarus GIT Head, FPC 3.0
CPU-Target: 64Bit
Wohnort: Stuttgart
Kontaktdaten:

Re: zufällige Zahlenreihe ohne doppelte zahlen

Beitrag von corpsman »

Hier eine Beispielimplementierung meines obigen Vorschlages, ganz ohne gefährliche repeat until schleifen.

Code: Alles auswählen

 
var
  a:Array of integer;
  i1,i2,t,i:integer;
Begin 
  randomize; // Zufallszahlen initialisieren ( typisch in Form create)
  setlength(a, 100); // Ein Array mit 100 Zahlen
  for i := 0 to high(a) do a[i] := i+1; // Initialisieren sortiert mit den Zahlen 1 .. 100
  // Mischen
  for i := 0 to high(a) div 2 do begin
    i1 := random(length(a));
    i2 := random(length(a))
    if i1 <> i2 then begin
      t := a[i1];
      a[i1] := a[i2];
      a[i2] := t;
    end;
  end;
  // Ab hier sind die Zahlen Gemischt
 
--
Just try it

Antworten