Przeliczenie Liczb Lotto 6z49 na numer kombinacji.

Pawlik67

Funkcja NUMER_KOMBINACJI podaje, którym z kolei układem są liczby które mamy zadeklarowane w tabeli 'Liczba[]'.
Np. układ liczb:
1,2,3,4,5,6 to numer kombinacji 1,
1,2,3,4,5,7 to numer kombinacji 2,
.... itd ....
zaś 44,45,46,47,48,49 to ostatni numer kombinacji czyli 13 983 816.

//Funkcja SILNIA zwraca silnię n-tej liczby

function SILNIA(n: Byte): LongWord;
begin
   SILNIA := 1
   if n < 2 then
      SILNIA := 1
      else
      SILNIA := SILNIA(n - 1) * n;
end { koniec funkcji SILNIA }

//Funkcja KOMBINACJE oblicza ilość kombinacji bez powtórek.
// Lba  - Długość ciągu, ilość wylosowanych liczb; tu 6.
// elem - Ilość elmentów; tu 49.

function KOMBINACJE(Lba, Elem: Byte): LongWord;
begin
   KOMBINACJE := Trunc(Round(SILNIA(Elem) / (SILNIA(Lba) * SILNIA(Elem - Lba))));
end; { koniec funkcji KOMBINACJE }

// Funkcja NUMER_KOMBINACJI zwraca numer kombinacji odpowiadający
// kolejnym liczbom.
// Liczby zawarte są w tabeli ( Liczba : Array[1..6] Of Byte; ).
// ka - ilość liczb, tu podstaw 6.
// en - ilość elementów, tu podstaw 49.

function NUMER_KOMBINACJI(ka, en: Byte): LongWord;
var
   xx: Integer;
   Pozycja: Integer;
begin
   Pozycja := KOMBINACJE(ka, en);
   for xx := ka downto 1 do
      if (en - Liczba[xx]) > (ka - xx) then
         Pozycja := Pozycja - KOMBINACJE((ka + 1) - xx, en - Liczba[xx]);
   NUMER_KOMBINACJI := Pozycja;
end; { koniec funkcji NUMER_KOMBINACJI }

Oczywiście funkcja jest przystosowana do obliczania numeru kombinacji dla innych układów np 5z42.... Należy jednak pamiętać, że numer kombinacji możemy tu obliczyć tylko dla układów bez powtórek czyli każda z 6-ciu liczb w tabeli 'Liczba[]' musi być inna i muszą one być posortowane od najmniejszej do największej.

Mam nadzieję, że z zamianą Numeru Kombinacji na układ 6-ciu liczb z 49 nie będzie większych problemów. Jeśli sprawi to kłopot, proszę o e-milka.

Wierzę, że opisana funkcja przyda się grającym w Lotto :-)

6 komentarzy

hehehe co za pomysł :)

Mam pytanko ;)

Moje pytanie dotyczy funkcji SILNIA, która ma bodaj liczyć (jak sama nazwa
wskazuje) silnia liczby. Tylko, że ta funkcja ma wiele do życzenia, gdyż silnia
liczby 13 wynosi 6,E+09 (6 227 020 800), a wyniki jaki otrzymamy korzystając z w/w funkcji wyniesie 2,E+09 (1 932 053 504). Chyba można się domyśleć, jakie wyniki uzyskamy wprowadzając większą liczbę np. 35 - otrzymamy wynik zerowy, dlatego, że typ funkcji SILNIA jest LongWord (0..4 294 967 295). Jedynie funkcja ta poprawnie obliczy nam do liczby 12. :)

A co do funkcji NUMER_KOMBINACJI pozostawię już bez komentarza. :)

tomko29, u mnie wszystko ok. Staram się zawsze testować to co chcę opublikować :)
Pozdrawiam

Idea jest całkiem ok tylko jak już napisał tomko29 delphi nie jest w stanie policzyć silni dla liczby większej niż 12... ale jest rozwiązanie tego i to całkiem proste... Otóż w Excelu można wyliczyć silnię dla liczby (max 99) i jak stworzymy tablicę 294 możliwych wartości to zobaczymy pewną zależność pomiędzy komórkami tej tablicy, co nasunie pomysł realizacji tego w delphi i to bez przeliczania ogromnych wartości... Podpowiem tylko, że tabela ma wymiary 49x6. Jeżeli znajdę chwilę wolnego czasu zamieszczę gotowe rozwiązanie...

Przypadkiem mi się tu weszło to sobie przypomniałem że coś podobnego kiedyś robiłem. Znalazłem to w swoich archiwach.

unit PermutationEngine;

interface uses
SysUtils;

type
TBalls=array of Byte;
TPermutationEngine=class
protected
FCount,FFrom:Byte;
FIndex:Int64;
procedure SetIndex(AIndex:Int64);
public
class function CountFrom(ACount,AFrom:Byte):Int64;
constructor Create(ACount,AFrom:Byte);
function IndexOf(const ABalls:TBalls):Int64;
procedure Reset;
function PermutationCount:Int64;
function Next:Boolean;
function Prev:Boolean;
function AsString:String;
procedure GetBalls(var Balls:TBalls);
property Index:Int64 read FIndex write SetIndex;
end;

implementation

class function TPermutationEngine.CountFrom(ACount,AFrom:Byte):Int64;
var I:Byte;
begin
Result:=1;
if ACount>0 then
begin
for I:=0 to ACount-1 do Result:=(Result)*Byte(AFrom-I);
for I:=ACount downto 2 do Result:=(Result)div(I);
end;
end;

procedure TPermutationEngine.SetIndex(AIndex:Int64);
begin
if (AIndex<0)or(AIndex>=PermutationCount) then raise Exception.Create('TPermutationEngine: Index out of range');
FIndex:=AIndex;
end;

constructor TPermutationEngine.Create(ACount,AFrom:Byte);
begin
inherited Create;
if ACount>AFrom then raise Exception.Create('TPermutationEngine: Count>From');
if ACount<1 then raise Exception.Create('TPermutationEngine: Count<1');
if AFrom>254 then raise Exception.Create('TPermutationEngine: From>254');
FCount:=ACount;
FFrom:=AFrom;
Reset;
end;

function TPermutationEngine.IndexOf(const ABalls:TBalls):Int64;
var Ball,I,K:Byte;
begin
Result:=0;
Ball:=0;
for K:=0 to FCount-1 do
begin
for I:=Ball+1 to ABalls[K]-1 do
begin
Inc(Result,CountFrom(FCount-K-1,FFrom-I));
end;
Ball:=ABalls[K];
end;
end;

procedure TPermutationEngine.Reset;
begin
FIndex:=0;
end;

function TPermutationEngine.PermutationCount:Int64;
begin
Result:=CountFrom(FCount,FFrom);
end;

function TPermutationEngine.Next:Boolean;
var Max:Int64;
begin
Inc(FIndex);
Max:=PermutationCount;
Result:=(FIndex<Max);
if not Result then FIndex:=0;
end;

function TPermutationEngine.Prev:Boolean;
begin
Dec(FIndex);
Result:=(FIndex>=0);
if not Result then FIndex:=PermutationCount-1;
end;

function TPermutationEngine.AsString:String;
var I:Byte;
var Balls:TBalls;
begin
GetBalls(Balls);
SetLength(Result,0);
for I:=0 to FCount-1 do
begin
if I>0 then Result:=Result+',';
Result:=Result+IntToStr(Balls[I]);
end;
SetLength(Balls,0);
end;

procedure TPermutationEngine.GetBalls(var Balls:TBalls);
var AMin,AMax,ACur:TBalls;
var NIndex:Int64;
var I,K,D:Byte;

function CheckResult(const Test:TBalls):Boolean;
begin
NIndex:=IndexOf(Test);
Result:=(FIndex=NIndex);
if Result then Move(Test[0],Balls[0],FCount);
end;

begin
SetLength(Balls,FCount);
SetLength(AMin,FCount);
SetLength(AMax,FCount);
SetLength(ACur,FCount);
try
for I:=0 to FCount-1 do
begin
AMin[I]:=I+1;
AMax[I]:=FFrom-FCount+I+1;
end;
if CheckResult(AMin) then Exit;
if CheckResult(AMax) then Exit;
while true do
begin
for I:=0 to FCount-1 do
begin
D:=AMax[I]-AMin[I];
if D>0 then
begin
if D>1 then
begin
ACur[I]:=(AMax[I]+AMin[I])shr(1);
for K:=I+1 to FCount-1 do ACur[K]:=ACur[K-1]+1;
end
else
begin
if AMax[I+1]=AMax[I]+1 then
begin
ACur[I]:=AMin[I];
for K:=I+1 to FCount-1 do ACur[K]:=FFrom-FCount+K+1;
end
else
begin
ACur[I]:=AMax[I];
for K:=I+1 to FCount-1 do ACur[K]:=ACur[K-1]+1;
end;
end;
if CheckResult(ACur) then Exit;
if NIndex<FIndex then
begin
Move(ACur[0],AMin[0],FCount);
end
else
begin
Move(ACur[0],AMax[0],FCount);
end;
Break;
end
else
begin
ACur[I]:=AMax[I];
end;
end;
end;
finally
SetLength(AMin,0);
SetLength(AMax,0);
SetLength(ACur,0);
end;
end;

end.

dziwny kod, można to zrobić zupełnie łatwiej i prościej, chodzby używjając random i odkładając sobie liczby które się wylosowały do tablicy. potem przy losowaniu następnej liczby sprawdzić w tablicy czy już taka jest, jak jest to wylosować inną. po co tak utrudniać sobie życie.