Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Lottery Numbers

by OverlordQ (Hermit)
on May 03, 2004 at 00:59 UTC ( [id://349890] : sourcecode . print w/replies, xml ) Need Help??
Category: Fun Stuff
Author/Contact Info OverlordQ - PM Node: 236515
Description: Takes the results of past lottery drawings and feeds it into a weighted random number generator to guess future results. Horribly inefficient I suspect.
#!/usr/bin/perl -w

use strict;
use List::Util qw(shuffle);

## CSV file has following format:
## Game Name, Month, Day, Year, Num1, Num2, Num3, Num4, Num5, Mega Bal
+l, Megaplier
## The Megaplier is ignored
open(FILE,"megamillion.csv") or die "Cannot open csv: $!\n";
my @csv = <FILE>;
close(FILE);

## Initialize the temporary hashes
my %hash;
my %bonus;

## Inefficient loop to get number counts
foreach my $line (@csv) {
        my ($game,$month,$day,$year,$one,$two,$three,$four,$five,$bonu
+s) = split(/,/,$line);
        $hash{$one}++;
        $hash{$two}++;
        $hash{$three}++;
        $hash{$four}++;
        $hash{$five}++;
        $bonus{$bonus}++;
}

## Initialize the weighted arrays
my @draw;
my @mega;

## Loop and push the numbers into the arrays, and shuffle
foreach my $key (sort keys %hash) {
    for(my $count = 0; $count < $hash{$key}; $count++) {
        push(@draw,$key);
    }
}
@draw = shuffle(@draw);

foreach my $key (sort keys %bonus) {
    for(my $count = 0; $count< $hash{$key}; $count++) {
        push(@mega,$key);
    }
}
@mega = shuffle(@mega);

sub draw_regular {
    $draw[ rand(@draw) ];
}

sub draw_mega {
    $mega[ rand(@mega) ];
}

## Keep track of number's we've picked
my @picked;

## Loop and draw 5 numbers, pick another incase we draw the same numbe
+r twice.
for(my $i=0;$i<=4;$i++) {
    my $number = draw_regular();
    foreach my $pick (@picked) {
                while($number == $pick) {
            $number = draw_regular();
        }
    }
    push(@picked,$number);
}

## Output the Numbers we drew.

print "Draw: " . join(',', sort(@picked)) . "\n";
print "Bonus: " . draw_mega();
Replies are listed 'Best First'.
Re: Lottery Numbers
by jdporter (Chancellor) on May 03, 2004 at 01:36 UTC

    At least your intuition is accurate, wrt the inefficiency of the code. Not that it's all that bad, and for a script like this, who cares if it runs in 3 seconds or 6?

    Here's some suggestions:

    • Look at all the places you use sort. Most, if not all, are unnecessary.
    • Your reading and parsing of the file could be much more concise, with a payoff in efficiency. To wit:
      while (<FILE>) { # line at a time my( $game,$month,$day,$year,$one,$two,$three,$four,$five,$bonus) = s +plit; for ( $one,$two,$three,$four,$five ) { $hash{$_}++; } $bonus{$bonus}++; # bonus }
    • Your inner "pushing" loops could be replaced with:
      push @draw, ($key) x $hash{$key};
      Let perl do the grunt work.
      I might even combine the two "pushing" loops into something like the following-
      foreach my $key ( keys %hash ) { push @draw, ($key) x $hash{$key}; push @mega, ($key) x $hash{$key} if exists $bonus{$key}; }
      since, I'm assuming, a number can only appear in the 'bonus' column if it also appears at least once in one of the other columns.
    • Your duplicate-detecting loop has a bug. You want to pick a new number if the current number is the same as any in your @picked array. I assume. Right?
      If so, then you could use grep to do set membership tests on the array.
      Even better would be to use a hash. You're doing many repeated set membership tests on it, and a hash is much better at this than an array. If you care about the order in which numbers are picked (and I assume you do), you could use Tie::IxHash to get an order-preserving hash.
      Or in a case like this you could just use an auxiliary "seen" hash.
      Here's a solution using grep:
      my $number; do { $number = draw_regular(); } while ( grep { $_ == $number } @picked ); push @picked, $number;
      Here's a solution using an aux hash:
      my $number; do { $number = draw_regular(); } while ( exists $seen{$number} ); $seen{$number}++; push @picked, $number;

      Thanks for the help. The only think you were off on was the bonus. The bonus is an entire diffrent set of numbers not related to the others.
        There is one simple thing that you can fix the source file, just delete everything before 10/15/2013.
Re: Lottery Numbers
by TomDLux (Vicar) on May 04, 2004 at 00:22 UTC

    You may improve your coding, but the coded won't improve your winnings.

    Probabilities are odd, because you're dealing with infinite sequences, and our brains are wired to deal with shorter-term problems ( like our next meal, sex tonight, and the growling noise from the closet ).

    Probability says that if you flip a fair coin often enough, and it never balances on the edge, sooner or later you'll have a long string of heads ( or tails ). Once you've had a dozen heads, some people think tails is more likely, because it has to get back to 50-50. That's the trick about infinite sequences. Sooner or later it will get back to balance, but it can take forever to get there. In the meantime, the odds are still 50% heads, 50% tails. Of course, there IS the possibility that a dozen heads indicates an unfair coin.

    If you're dealing with one of those lotteries that uses ping-pong balls, there's always the possibility of some accidental inconsistency that makes some numbers fractionally more likely than others. Otherwise, the fact that a number has appeared frequently makes it neither more likely nore less likely to appear in the next draw.

    --
    TTTATCGGTCGTTATATAGATGTTTGCA