Problem z losowaniem niepowtarzających się liczb.

0

Witam wszystkich jako że to mój pierwszy post na forum. Mam problem z wylowaniem losowych liczb do totka. O ile procedura wypelnij losuje inne liczby za kazdym uruchomieniem o tyle lotto losuje wszystkie liczby z przedzialu 1-49 i program sie zawiesza. Wydanje mi sie ze randomize jest uzyty poprawnie. Nie mam pojecia dlaczego sie tak dzieje. Dzieki za podpowiedz

program lotto ;

uses crt;

CONST PROBY = 1000;
      ZAKRES = 49;
      ILOSC = 6;

var i,j,k,l,pom,pom1,licznik:integer; 
    A:array[1..ZAKRES] of integer; // GLOWNE LOSOWANIE
    A2:array[1..ZAKRES] of integer;  // LOSOWANIE JEDNEGO KUPONU
    wynik:array[1..ILOSC] of integer; // ZLICZAM ILOSC WYSTĄPIEN

procedure wypelnij;
begin
  
  for i:=1 to ZAKRES do 
    A[i]:=0;
  for i:=1 to ILOSC do 
  begin
    pom:=random(49)+1;
    while A[pom]=pom do
      pom:=random(49)+1;
    A[pom]:=pom;
  end;
  for i:=1 to ZAKRES do
    writeln(A[i]);
end;

procedure lotto1;
begin

  for i:=1 to ZAKRES do 
    A2[i]:=0;
    
  for i:=1 to ZAKRES do 
    wynik[i]:=0;
  licznik:=0;
  
 for i:=1 to PROBY do 
  begin
    for j:=1 to ILOSC do
      begin
	pom1:=random(49)+1;
	while A2[pom1]=pom1 do  // CHCE ABY LICZBY SIE NIE POWTARZALY
	  pom1:=random(49)+1;
	A2[pom1]:=pom1;
	writeln('pom1=',pom1);
      
	if A[pom1]=pom1 then 
	  licznik:=licznik+1;  // SPRAWDZAM CZY WYSTAPILA 3,4 ITD
	  writeln(licznik);
      end;
      
    if licznik <> 0 then 
    wynik[licznik]:=wynik[licznik]+1; // ZWIEKSZAM ILOSC WYTAPIEN
    licznik:=0;
    for k:=1 to ZAKRES do 
      A2[i]:=0;
      
  end;
  
end;

begin
randomize;
clrscr;
wypelnij;
lotto1;

end.




0

Podejrzewam, że to while musi być błędne i tworzysz niekończącą się pętle. Poniżej prosty przykład losowania 6 z 49 liczb bez powtarzania. Wprawdzie żywcem skopiowany z mojego starego programu w VCL, pisanego jeszcze w Delphi 3, ale powinieneś zrozumieć ideę. A Randomize użyłeś dobrze. Czyli raz na początku programu przed losowaniem czegokolwiek przez funkcję Random.

//...
procedure Sort_Shell(var a : array of Byte);
var
  Bis, I, J, K : LongInt;
  H : Word;
begin
  Bis := High(A);
  K := Bis shr 1;
  while K > 0 do
  begin
    for I := 0 to Bis - K do
    begin
      J := I;
      while (J >= 0) and (A[J] > A[J + K]) do
      begin
        H := A[J];
        A[J] := A[J + K];
        A[J + K] := H;
        if J > K then
          Dec(J, K)
        else
          J := 0;
      end;
    end;
    K := K shr 1;
  end;
end;

procedure TMainForm.Losuj_Duzy_Lotek;
const
  IleLiczb = 6;
  IloscKul = 49;
var
  Losuj : Boolean;
  I, J, Liczba : Byte;
  WynikiLosowania : string;
  Wyniki : array[1..IleLiczb] of Byte;
begin
  for I := 1 to IleLiczb do
  begin
    Losuj := False;
    while not Losuj do
    begin
      Losuj := True;
      Liczba := Random(IloscKul) + 1;
      if I > 1 then
        for J := 1 to I - 1 do
          if Wyniki[J] = Liczba then
            Losuj := False;
    end;
    Wyniki[I] := Liczba;
  end;
  Sort_Shell(Wyniki);
  for I := 1 to IleLiczb do
  begin
    if I = 1 then
    begin
      WynikiLosowania := IntToStr(Wyniki[I]);
    end
    else
    begin
      WynikiLosowania := WynikiLosowania + #32 + IntToStr(Wyniki[I]);
    end;
  end;
  TempSL.Add(WynikiLosowania);
end;
//...

A temat przenosze do działu Newbie, ponieważ dotyczy podstaw. Zmieniłem też temat, bo Twój problem w przedstawionym kodzie na pewno nie dotyczy procedury Randomize;. Ciężko mieć z nią problem, jeżeli wywoła się ją tylko raz przed późniejszym losowaniem Random.

0
const TableSize= 49;
var Tb:array[1..TableSize]of Byte;

procedure LotoNext;
var I,P:Integer;
var X:Byte;
begin
  for I:=TableSize downto 2 do
  begin
    P:=1+Random(I);
    X:=Tb[P];
    Tb[P]:=Tb[I];
    Tb[I]:=X;
  end;
end;

procedure LotoFirst;
var I:Integer;
begin
  for I:=1 to TableSize do Tb[I]:=I;
  LotoNext;
end;
0
_13th_Dragon napisał(a):
const TableSize= 49;
var Tb:array[1..TableSize]of Byte;

procedure LotoNext;
var I,P:Integer;
var X:Byte;
begin
  for I:=TableSize downto 2 do
  begin
    P:=1+Random(I);
    X:=Tb[P];
    Tb[P]:=Tb[I];
    Tb[I]:=X;
  end;
end;

procedure LotoFirst;
var I:Integer;
begin
  for I:=1 to TableSize do Tb[I]:=I;
  LotoNext;
end;

Dragon, algorytm ładny, ale nie do końca :) Ten algorytm porządkuje całą tablicę losowo, a tu chodzi o wylosowanie 6 liczb. Pętlę można przerwać po 6 przebiegach, więc wystarczy:

for I := TableSize downto TableSize - 5 do
0

No bez przesady :) Gdybyś Ty o tym pomyślał to dodałbyś prostą strukturę (np rekord) do zwracania 6 wylosowanych liczb. Poza tym po drobnej modyfikacji algorytm będzie zwracał wylosowane liczby na pierwszych sześciu miejscach.

0

Nic nie czaisz. Twój algorytm jest maksymalnie zwięzły, dodawanie struktur zwracających wyniki losowania niepotrzebnie go gmatwa. Ja po prostu pokazałem Ci że może być jeszcze lepszy nie zaburzając tej zwięzłości - i tyle.

1 użytkowników online, w tym zalogowanych: 0, gości: 1