Schrift
[thread]11212[/thread]

Zufalls-LOTTO-Zahlen

Leser: 1


<< >> 10 Einträge, 1 Seite
pax77
 2008-01-29 19:55
#105331 #105331
User since
2008-01-29
3 Artikel
BenutzerIn
[default_avatar]
Hallo, bin sei ein paar Monaten dabei Perl zu programmieren. Anbei ein kleines Prgramm um Zufallszahlen für LOTTO zu generieren. Würde mich freuen wenn jemand etwas zum Stil schreiben könnte und/oder ob sowas taugt z.B. als Beispielcode für Bewerbungen ...
Danke!
pax77

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!C:/Perl/bin/perl.exe 
# 
# v0.96 makemeritch.pl by pax77 
# 
# Erzeugt zufällige Lotto-Zahlen 
# 12 Felder mit jeweils maximal $n Überschneidungen 
# 

use strict; 

my $n = 2; # Anzahl der erlaubten Überschneidungen (2 ist Minimalwert) 
my $DEBUG = 1; # Debug-Level 0, 1 
my $try = 0; 
my @sum; 
NOTE: while (@sum < 12) { # 12 Zahlenreihen werden erzeugt 
        my @lotto; 
        # push(@lotto, 7, 13); # Wenn es Lieblingszahlen gibt (Sollten nicht mehr als $n-2 sein ...) 
        LOTTO: while (@lotto < 6) { # Mit jeweils 6 Zahlen 
                my $zahl = &GetNum(); # Zufallszahl zwischen 1 und 49 
                foreach (@lotto) { 
                                next LOTTO if $_ == $zahl; # Jede Zahl nur ein mal 
                } 
                push(@lotto, $zahl); 
        } 
        # Wenn zu viele Zahlen doppelt mit einer alten Zahlenreihe -> redo 
        $try++, redo NOTE if &CheckDouble(\@lotto); 
        push(@sum, \@lotto); 
        print "($try)\t" if $DEBUG; 
        foreach (sort {$a <=> $b} @lotto) { # Sortierte und formatierte Ausgabe 
                print " " if $_ < 10; 
                print $_." "; 
        } 
        print "\n"; 
} 

sub CheckDouble { 
        my ($check) = @_; 
        my $suc; 
        MAIN: foreach (@sum) { # Jede bereits erzeugte Zahlenreihe 
                my $g = 0; 
                foreach (@$_) { # Jede Zahl der jeweiligen Zahlenreihe 
                        my $temp = $_; 
                        foreach (@$check) { # Vergleiche mit den neuen Zahlen 
                                $g++ if $_ == $temp; 
                                $suc = 1, last MAIN if $g == $n; # Wenn zu viele gleich -> return TRUE 
                        } 
                } 
        } 
        return $suc; 
} 

sub GetNum { 
        return int(rand 49) + 1; 
}
pktm
 2008-01-29 20:40
#105332 #105332
User since
2003-08-07
2921 Artikel
BenutzerIn
[Homepage]
user image
Also.. ich nehme mal an, das liegt an den fehlenden code-Tags, aber die Einrückung finde ich echt grässlich. Das kann doch kein normaler Mensch lesen wollen.

Ansonsten:
#!C:/Perl/bin/perl.exe => #!/Perl/bin/perl

use strict; => use strict; + use warnings;

Grüß, pktm
http://www.intergastro-service.de (mein erstes CMS :) )
pax77
 2008-01-29 20:45
#105333 #105333
User since
2008-01-29
3 Artikel
BenutzerIn
[default_avatar]
Ah, so gefällt es mit auch besser - thx

(1. Beitrag geändert)
lichtkind
 2008-01-29 21:03
#105335 #105335
User since
2004-03-22
5697 Artikel
ModeratorIn + EditorIn
[Homepage]
user image
ust strict ist schonmal gut aber mit use warnigs wäre es noch besser :)

die sub könnte man auch GetRandNum nennen

und ausserdem haben wir hier im forum perl button mit der code besser aussieht.

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#!C:/Perl/bin/perl.exe
#
# v0.96 makemeritch.pl by pax77
#
# Erzeugt zufällige Lotto-Zahlen
# 12 Felder mit jeweils maximal $n Überschneidungen
#

use strict;
use warnings;

my $n = 2; # Anzahl der erlaubten Überschneidungen (2 ist Minimalwert)
my $DEBUG = 1; # Debug-Level 0, 1
my $try = 0;
my @sum;

NOTE: while (@sum < 12) { # 12 Zahlenreihen werden erzeugt
    my @lotto;
    # push(@lotto, 7, 13); # Wenn es Lieblingszahlen gibt (Sollten nicht mehr als $n-2 sein ...)
    LOTTO: while (@lotto < 6) { # Mit jeweils 6 Zahlen
        my $zahl = &GetNum(); # Zufallszahl zwischen 1 und 49
        foreach (@lotto) {
            next LOTTO if $_ == $zahl; # Jede Zahl nur ein mal
        }
        push(@lotto, $zahl);
    }
    # Wenn zu viele Zahlen doppelt mit einer alten Zahlenreihe -> redo

    $try++, redo NOTE if &CheckDouble(\@lotto);
    push(@sum, \@lotto);
    print "($try)\t" if $DEBUG;
    printf "%2d ", $_ for sort {$a <=> $b} @lotto; # Sortierte und formatierte Ausgabe
    print "\n";
}

sub CheckDouble {
    my ($check) = @_;
    my $suc;
    MAIN: foreach (@sum) { # Jede bereits erzeugte Zahlenreihe
        my $g = 0;
        foreach (@$_) { # Jede Zahl der jeweiligen Zahlenreihe
            my $temp = $_;
            foreach (@$check) { # Vergleiche mit den neuen Zahlen
                $g++ if $_ == $temp;
                $suc = 1, last MAIN if $g == $n; # Wenn zu viele gleich -> return TRUE
            }
        }
    }
    return $suc;
}

sub RandNum { int(rand 49) + 1 }


ich hoffe du hast gesehen wie man printf benutzt :)
Wiki:Tutorien in der Wiki, mein zeug:
kephra, baumhaus, garten, gezwitscher

Es beginnt immer mit einer Entscheidung.
Ronnie
 2008-01-29 21:26
#105337 #105337
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Hallo pax77 und willkommen im Forum. Perl ist eine sehr ausdrucksreiche Sprache, die es wirklich lohnt zu lernen. Es gibt viele Module die dir das Leben erleichtern können, z.B. CPAN:List::Util das z.B. eine shuffle-Funktion bereitstellt um den Inhalt eines Arrays zu mischen. Auf use warnings; wurde ja schon hingewiesen. Hier im Wiki findest du auch viele nützliche Infos und wir beantworten auch gerne Fragen. Dein aktueller Programmier-Stil ist sehr C-orientiert. Perl unterstützt eine Vielzahl von Programmierweisen und jeder hier hat eine eigene Vorstellung davon, welche Arbeistweise er oder sie bevorzugt. Ein kleines Beispiel, wie so ein Programm aussehen kann, wenn man schon ein wenig dabei ist:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/perl

use strict;
use warnings;

#use Data::Dumper;
use List::Util qw/shuffle/;

my $cnt = shift @ARGV || 12;    # wir wollen 12 Ziehungen
my @fav = (7, 13);              # und die Zahlen 7 und 13 müssen drin sein

print join( ', ',               # fasse das zusammen zur Ausgabe
    sort { $a <=> $b } (        # numerisch sortiert 
        pick_numbers(6 - @fav, @fav)    # gezogene Nummern
    ) ) . "\n" for 1..$cnt;     # für $cnt Ziehungen

sub pick_numbers {              
    my $n           = shift || 6;       # ziehe $n Zahlen oder 6
    my @numbers     = shuffle (1..49);  # erstelle eine gemischte Liste der Zahlen 1..49
    return @_, @numbers[0..--$n];       # und gib diese zusammen mit evtl. Favoriten zurück
}

Perl ist spannend und für unglaublich viele Aufgaben einsetzbar - nicht für alles - aber eben für sehr vieles. Und es ist eine Sprache die sich aktuell weiter entwickelt, ob als Perl 5.10 oder Perl 6.

Gruß,
Ronnie
Taulmarill
 2008-01-30 11:20
#105356 #105356
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
Beim erstellen der Liste 1..49 sollte beachtet werden, dass hier die Zahlen aus @fav herausgefiltert werden, da diese sonst doppelt vorkommen können.
Außerdem benutze ich lieber ein pseudozufälliges splice um Elemente aus einer Liste zu picken. Bei Lottozahlen ist das eigentlich egal, aber bei großen Listen kann das Mischen der gesamten Liste schon mal länger dauern.

Damit sieht &pick_numbers bei mir jetzt so aus:
Code (perl): (dl )
1
2
3
4
5
sub pick_numbers {
    my $n       = shift || 6;
    my @numbers = grep{ my $i = $_; not grep{ $i == $_ } @_ } 1..49;
    return @_, map{ splice @numbers, rand(@numbers), 1 } 1..$n;
}
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
pax77
 2008-01-30 18:42
#105366 #105366
User since
2008-01-29
3 Artikel
BenutzerIn
[default_avatar]
Vielen Dank für die Antworten!
@Ronnie: Das ist ja mal richtig schöner Code. Aber sehe ich das richtig, dass 'meine' Funktion &CheckDouble() darin nicht realisiert ist? Könnte also sein das zweimal die gleichen Zahlen getippt werden (wenn auch in etwa so wahrscheinlich wie ein Lotto-Gewinn ...).

@lichtkind: printf hatte ich auch erst, meinte aber in meinem Kamel-Buch gelesen zu haben das man das vermeiden soll wenns nicht sein muss oder war das sprintf?; wahrscheinlich egal wenn man nicht auf 50 verschiedenen Plattformen unterwegs ist. Das man for-Schleifen auch hinten anhängen kann ist mir neu, danke!

Dieses besagte Kamel-Buch ist auch die einzige Bezugsquelle die ich momentan habe, da ich an dem Platz wo ich (meistens) programmiere leider kein Internet zur Verfügung habe und so schon das eine oder andere Rad neu erfinden musste ...

Grüße,
pax77
Ronnie
 2008-01-30 19:31
#105367 #105367
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Hallo pax77,

die Anmerkungen von Taulmarill, bezüglich der Favoriten in meiner Lösungs sind wichtig. Ansonsten hast du recht, auf check_double habe ich verzichtet, könnte man aber auch Recht schön mit der Hilfe von CPAN:List::MoreUtils machen:

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use List::Util qw/sum min/;
use List::MoreUtils qw/pairwise/;

sub distance {
    my ($i, $j) = @_;
    no warnings;
    my $distance = sum pairwise { $a != $b } @$i, @$j;
    return $distance;
}

sub distance_to_any {
    my ($i, $l) = @_;
    return min ( map distance( $i, $_ ), @$l  );
}

print distance ([1, 2, 3, 4], [1, 8, 5, 7]) . "\n";
print distance_to_any ( [1, 2, 3, 4], [ [1, 8, 5, 7], [1, 2, 3, 9] ] )

Wie taulmarill aufgezeigt hat, geht es auch gut ohne zusätzliche Module, mit Bordmitteln.

Gruß,
Ronnie
topeg
 2008-01-31 00:31
#105369 #105369
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Mit der richtigen Wahl des Algorithmus wird das ganze auch ohne zusätzliche Module sehr klein:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl

use strict;
use warnings;

my @faf=(1,22);

my @z=(1..49);
for my $pos (sort{$b<=>$a}@faf)
{ splice(@z,($pos-1),1); }

for my $cnt (1..12)
{
 my @lotto=@z;
 splice(@lotto,int(rand($#lotto)+0.5),1) while(@lotto > (6-@faf) );
 @lotto=sort{$a<=>$b}(@faf,@lotto);
 printf("Ziehung: %2d -> %s\n", $cnt, join(',',@lotto));
}
Taulmarill
 2008-01-31 15:07
#105401 #105401
User since
2004-02-19
1750 Artikel
BenutzerIn

user image
@topeg: deine art Pseudozufallszahlen zu erzeugen, erzeugt keine gleichmäßige Verteilung. Bei folgendem Script:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my @num = 0..9;
my %res;

for ( 1 .. 1_000_000 ) {
    $res{ $num[ rand @num ] }++;
}
print "Test 1:\n";
print "$_ => $res{$_}\n" for @num;

print "\n";
%res = ();

for ( 1 .. 1_000_000 ) {
    $res{ int( rand($#num) + 0.5 ) }++;
}
print "Test 2:\n";
print "$_ => $res{$_}\n" for @num;

bekomme ich folgendes Ergebnis:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Test 1:
0 => 99890
1 => 99720
2 => 100091
3 => 99762
4 => 100083
5 => 99604
6 => 99967
7 => 100189
8 => 99925
9 => 100769

Test 2:
0 => 55212
1 => 110670
2 => 111032
3 => 111548
4 => 110812
5 => 111082
6 => 111016
7 => 111557
8 => 111592
9 => 55479
$_=unpack"B*",~pack"H*",$_ and y&1|0& |#&&print"$_\n"for@.=qw BFA2F7C39139F45F78
0A28104594444504400 0A2F107D54447DE7800 0A2110453444450500 73CF1045138445F4800 0
F3EF2044E3D17DE 8A08A0451412411 F3CF207DF41C79E 820A20451412414 83E93C4513D17D2B
<< >> 10 Einträge, 1 Seite



View all threads created 2008-01-29 19:55.