| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# PODNAME: Game::Lottery |
|
2
|
|
|
|
|
|
|
# ABSTRACT: Generate and Check Big Draw Lottery Tickets |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=pod |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
=head1 NAME |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
Game::Lottery |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
=head1 VERSION |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
version 1.04 |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Pick and check numbers for popular Lottery Draw Games using a Cryptographically Secure randomizer. |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
General Draw Games and Big Draw Games are supported, but ticket valuation functions are only available for PowerBall and MegaMillions. |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
Use the bundled lottery-big-draw.pl script to pick your numbers: |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
lottery-big-draw.pl -h |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
To use in your code: |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
use Game::Lottery; |
|
29
|
|
|
|
|
|
|
my $lottery = Game::Lottery->new( game => 'PowerBall'); |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DRAW GAMES |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
Lottery Draw games have a pool of balls. Players bet on as many numbers as the number of balls that will be drawn. |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 BIG DRAW LOTTERY GAMES |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
Have a pool of balls (white) players must match, and a second pool (red) from which (usually) a single ball is drawn, many of the prizes require matching the red ball. |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
The odds of winning the big prize in the two main games in the United States: PowerBall and MegaMillions, are about 300 Million to 1. When the prize isn't won, the jackpot increases. The JackPots frequently get quite large. When the JackPots get large enough, the expected value of a ticket exceeds the cost. The smaller prizes in both US games return less than 20% of the ticket value. |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
There are several options to increase bet sizes, both major games have a multiplier ball option; these are not currently supported. |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
California has a different payout on non-jackpot prizes. For California and any other jurisdictions not using the standard payout table, the expected value generated by this software does not apply. |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
|
46
|
|
|
|
|
|
|
|
|
47
|
6
|
|
|
6
|
|
1564651
|
use 5.038; |
|
|
6
|
|
|
|
|
25
|
|
|
48
|
6
|
|
|
6
|
|
3216
|
use experimental qw/class/; |
|
|
6
|
|
|
|
|
25986
|
|
|
|
6
|
|
|
|
|
37
|
|
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
class Game::Lottery; |
|
51
|
|
|
|
|
|
|
our $VERSION="1.04"; |
|
52
|
6
|
|
|
6
|
|
4557
|
use Math::Random::Secure; |
|
|
6
|
|
|
|
|
1257983
|
|
|
|
6
|
|
|
|
|
403
|
|
|
53
|
6
|
|
|
6
|
|
5323
|
use Path::Tiny; |
|
|
6
|
|
|
|
|
92001
|
|
|
|
6
|
|
|
|
|
604
|
|
|
54
|
|
|
|
|
|
|
# use Data::Dumper; |
|
55
|
|
|
|
|
|
|
# use Data::Printer; |
|
56
|
6
|
|
|
6
|
|
3977
|
use English; |
|
|
6
|
|
|
|
|
19171
|
|
|
|
6
|
|
|
|
|
40
|
|
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
field $game : param; |
|
59
|
|
|
|
|
|
|
field $wb; # White Balls |
|
60
|
|
|
|
|
|
|
field $rb; # Red Balls |
|
61
|
|
|
|
|
|
|
field $wbd; # White Balls to Draw |
|
62
|
|
|
|
|
|
|
field $rbd; # Red Balls to Draw |
|
63
|
|
|
|
|
|
|
field %coll; # collision prevention |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
ADJUST { |
|
66
|
|
|
|
|
|
|
if ( $game =~ /^power/i ) { |
|
67
|
|
|
|
|
|
|
$game = 'PowerBall'; |
|
68
|
|
|
|
|
|
|
$wb = 69; |
|
69
|
|
|
|
|
|
|
$wbd = 5; |
|
70
|
|
|
|
|
|
|
$rb = 26; |
|
71
|
|
|
|
|
|
|
$rbd = 1; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
elsif ( $game =~ /^mega/i ) { |
|
74
|
|
|
|
|
|
|
$game = 'MegaMillions'; |
|
75
|
|
|
|
|
|
|
$wb = 70; |
|
76
|
|
|
|
|
|
|
$wbd = 5; |
|
77
|
|
|
|
|
|
|
$rb = 25; |
|
78
|
|
|
|
|
|
|
$rbd = 1; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
elsif ( $game =~ /^draw/i ) { |
|
81
|
|
|
|
|
|
|
$game = 'Draw'; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
elsif ( $game =~ /^custom/i ) { |
|
84
|
|
|
|
|
|
|
$game = 'CustomBigDraw'; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
else { |
|
87
|
|
|
|
|
|
|
die "Unknown GAME $game.\n"; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
5040
|
|
|
5040
|
|
1027089
|
sub _PickBall ($BallLastNum) { |
|
|
5040
|
|
|
|
|
8799
|
|
|
|
5040
|
|
|
|
|
8210
|
|
|
92
|
|
|
|
|
|
|
# rand starts at 0 -- offset the pick. |
|
93
|
5040
|
|
|
|
|
11383
|
my $pick = 1 + int Math::Random::Secure::rand($BallLastNum); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
12
|
|
|
12
|
|
3793
|
sub _DrawBalls ( $BallLastNum, $BallsDrawn ) { |
|
|
12
|
|
|
|
|
28
|
|
|
|
12
|
|
|
|
|
43
|
|
|
|
12
|
|
|
|
|
20
|
|
|
97
|
12
|
100
|
66
|
|
|
74
|
unless( $BallLastNum and $BallsDrawn ) { |
|
98
|
1
|
|
|
|
|
6
|
die "Balls are not defined. If this is a BigDraw did you use CustomBigDrawSetup?\n"; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
11
|
|
|
|
|
26
|
my %balls = (); |
|
101
|
11
|
|
|
|
|
39
|
until ( scalar( keys %balls ) == $BallsDrawn ) { |
|
102
|
40
|
|
|
|
|
94
|
my $newball = sprintf( "%02d", _PickBall($BallLastNum) ); |
|
103
|
40
|
|
|
|
|
56298
|
$balls{$newball} = $newball; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
11
|
|
|
|
|
96
|
return [ sort { $a <=> $b } ( keys(%balls) ) ]; |
|
|
52
|
|
|
|
|
147
|
|
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head1 METHODS |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head2 new |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Required parameter: game |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Games currently supported are PowerBall, MegaMillions, Draw (1 ball pool) and CustomBigDraw(custom 2 ball pools). Game names may be abbreviated as mega, power, draw and custom. |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
my $game = Game::Lottery->new( game => 'PowerBall'); |
|
117
|
|
|
|
|
|
|
my $game = Game::Lottery->new( game => 'power'); |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head2 Game |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
Returns the Game. |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
say $game->Game(); |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=cut |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
method _NoCollision ( $balls1, $balls2=[] ) { |
|
128
|
|
|
|
|
|
|
my $key = join '', ($balls1->@*, $balls2->@*); |
|
129
|
|
|
|
|
|
|
if ( defined $coll{$key }) { return 0 } |
|
130
|
|
|
|
|
|
|
$coll{$key } = 1 ; |
|
131
|
|
|
|
|
|
|
return 1; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
method Game { |
|
135
|
|
|
|
|
|
|
return $game; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
=head2 BasicDraw |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
Returns an Array Reference of balls picked. Applicable to a large number of Draw games. |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
my $drawn = $game->BasicDraw( $BallLastNum, $BallsDrawn ); |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
=cut |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
method BasicDraw ( $BallLastNum, $BallsDrawn ) { |
|
147
|
|
|
|
|
|
|
my $balls = undef; |
|
148
|
|
|
|
|
|
|
until (defined $balls) { |
|
149
|
|
|
|
|
|
|
$balls = _DrawBalls( $BallLastNum, $BallsDrawn ); |
|
150
|
|
|
|
|
|
|
$balls = undef unless $self->_NoCollision( $balls ); |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
$balls; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=head2 BigDraw |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Draws White and Red Balls for Big Draw Games. |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
Returns a Hash Reference. |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
my $drawn = $game->BigDraw(); |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
{ |
|
164
|
|
|
|
|
|
|
game => $game, |
|
165
|
|
|
|
|
|
|
whiteballs => ArrayRef, |
|
166
|
|
|
|
|
|
|
redballs => ArrayRef |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
=head2 CustomBigDrawSetup |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
For CustomBigDraw games, the pool ranges and number of balls to draw must be set before using the BigDraw method. For the directly supported Big Draw Games this is done at new. The game name is set to CustomBigDraw |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
$game->CustomBigDrawSetup( |
|
174
|
|
|
|
|
|
|
game => 'Some other big draw game', # optionally set a custom game name. |
|
175
|
|
|
|
|
|
|
white => 99, |
|
176
|
|
|
|
|
|
|
whitecount => 1, |
|
177
|
|
|
|
|
|
|
red => 20, |
|
178
|
|
|
|
|
|
|
redcount => 5 |
|
179
|
|
|
|
|
|
|
); |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=cut |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
method CustomBigDrawSetup (%balls) { |
|
184
|
|
|
|
|
|
|
$wb = $balls{'white'}; |
|
185
|
|
|
|
|
|
|
$wbd = $balls{'whitecount'}; |
|
186
|
|
|
|
|
|
|
$rb = $balls{'red'}; |
|
187
|
|
|
|
|
|
|
$rbd = $balls{'redcount'} || 1; |
|
188
|
|
|
|
|
|
|
$game = $balls{'game'} if $balls{'game'}; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
method BigDraw { |
|
192
|
|
|
|
|
|
|
while (1) { |
|
193
|
|
|
|
|
|
|
my $draw = { |
|
194
|
|
|
|
|
|
|
'game' => $game, |
|
195
|
|
|
|
|
|
|
'whiteballs' => _DrawBalls( $wb, $wbd ), |
|
196
|
|
|
|
|
|
|
'redballs' => _DrawBalls( $rb, $rbd ) |
|
197
|
|
|
|
|
|
|
}; |
|
198
|
|
|
|
|
|
|
if ( $self->_NoCollision( $draw->{whiteballs}, $draw->{redballs} ) ) { |
|
199
|
|
|
|
|
|
|
return $draw; |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
|
|
204
|
8
|
|
|
8
|
|
12
|
sub _round_val ($val) { sprintf( "%.2f", $val ) } |
|
|
8
|
|
|
|
|
11
|
|
|
|
8
|
|
|
|
|
9
|
|
|
|
8
|
|
|
|
|
118
|
|
|
205
|
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
# Calculate the |
|
207
|
|
|
|
|
|
|
sub _BaseMMVal { |
|
208
|
3
|
|
|
3
|
|
8
|
my $val = 2 * ( 1 / 37 ); # Red |
|
209
|
3
|
|
|
|
|
4
|
$val += 4 * ( 1 / 89 ); # Red + 1 White |
|
210
|
3
|
|
|
|
|
3
|
$val += 10 * ( 1 / 693 ); # Red + 2 White |
|
211
|
3
|
|
|
|
|
4
|
$val += 10 * ( 1 / 606 ); # 3 White |
|
212
|
3
|
|
|
|
|
5
|
$val += 200 * ( 1 / 14547 ); # Red + 3 White |
|
213
|
3
|
|
|
|
|
4
|
$val += 500 * ( 1 / 38792 ); # 4 White |
|
214
|
3
|
|
|
|
|
5
|
$val += 10000 * ( 1 / 931001 ); # Red + 4 White |
|
215
|
3
|
|
|
|
|
4
|
$val += 10**6 * ( 1 / 12607306 ); # 5 White |
|
216
|
3
|
|
|
|
|
34
|
return $val; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub _BasePBVal { |
|
220
|
3
|
|
|
3
|
|
4
|
my $val = 4 * ( 1 / 38.32 ); # Red |
|
221
|
3
|
|
|
|
|
7
|
$val += 4 * ( 1 / 91.98 ); # Red + 1 White |
|
222
|
3
|
|
|
|
|
2
|
$val += 7 * ( 1 / 701.33 ); # Red + 2 White |
|
223
|
3
|
|
|
|
|
5
|
$val += 7 * ( 1 / 579.76 ); # 3 White |
|
224
|
3
|
|
|
|
|
3
|
$val += 100 * ( 1 / 1494.11 ); # Red + 3 White |
|
225
|
3
|
|
|
|
|
4
|
$val += 100 * ( 1 / 36525.17 ); # 4 White |
|
226
|
3
|
|
|
|
|
4
|
$val += 50000 * ( 1 / 913129.18 ); # Red + 4 White |
|
227
|
3
|
|
|
|
|
5
|
$val += 10**6 * ( 1 / 11688053.52 ); # 5 White |
|
228
|
3
|
|
|
|
|
9
|
return $val; |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
=head2 TicketValue |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Returns the expected value of a ticket given a JackPot. The Cash Value should be used, not the advertised annuity value. The value passed may be either in dollars or millions of dollars. If no value (or 0) is based the result will be the return of all other prizes than the jackpot. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
my $TicketValue = $game->TicketValue( 600 ); |
|
236
|
|
|
|
|
|
|
my $BaseTicketValue = $game->TicketValue( 0 ); |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=head2 TicketJackPotValue |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
Returns just value of the JackPot divided by the number of possible combinations. |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
my $JackPot = $game->TicketJackPotValue( 600 ); |
|
243
|
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=cut |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
method TicketValue ( $jackpot = 0 ) { |
|
247
|
|
|
|
|
|
|
# allows jackpot in millions or in dollars. |
|
248
|
|
|
|
|
|
|
$jackpot = $jackpot * 10**6 if $jackpot < 10**6; |
|
249
|
|
|
|
|
|
|
if ( 'PowerBall' eq $game ) { |
|
250
|
|
|
|
|
|
|
return _round_val( _BasePBVal() + $jackpot / 292201338 ); |
|
251
|
|
|
|
|
|
|
} |
|
252
|
|
|
|
|
|
|
elsif ( 'MegaMillions' eq $game ) { |
|
253
|
|
|
|
|
|
|
return _round_val( _BaseMMVal() + $jackpot / 302575350 ); |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
else { |
|
256
|
|
|
|
|
|
|
die "Payout data not available for ${game}!"; |
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
} |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
method TicketJackPotValue ($jackpot) { |
|
261
|
|
|
|
|
|
|
# allows jackpot in millions or in dollars. |
|
262
|
|
|
|
|
|
|
$jackpot = $jackpot * 10**6 if $jackpot < 10**6; |
|
263
|
|
|
|
|
|
|
if ( 'PowerBall' eq $game ) { |
|
264
|
|
|
|
|
|
|
return _round_val( $jackpot / 292201338 ); |
|
265
|
|
|
|
|
|
|
} |
|
266
|
|
|
|
|
|
|
elsif ( 'MegaMillions' eq $game ) { |
|
267
|
|
|
|
|
|
|
return _round_val( $jackpot / 302575350 ); |
|
268
|
|
|
|
|
|
|
} |
|
269
|
|
|
|
|
|
|
else { |
|
270
|
|
|
|
|
|
|
die "Payout data not available for ${game}!"; |
|
271
|
|
|
|
|
|
|
} |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head2 SavePicks |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
Save an arrayref of picks from BasicDraw or BigDraw to a file. |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
$game->SavePicks( $file, $picks ); |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head2 ReadPicks |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Read saved picks from a file, returns an array. |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
my @picks = $game->ReadPicks( $file ); |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=cut |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
method SavePicks ( $file, $picks ) { |
|
289
|
|
|
|
|
|
|
open( my $out, '>', $file ) || die "unable to open output $file, $?"; |
|
290
|
|
|
|
|
|
|
for my $pick ( $picks->@* ) { |
|
291
|
|
|
|
|
|
|
print $out do { join ' ', $pick->{whiteballs}->@* }; |
|
292
|
|
|
|
|
|
|
print $out ' '; |
|
293
|
|
|
|
|
|
|
for my $red ( $pick->{redballs}->@* ) { |
|
294
|
|
|
|
|
|
|
print $out "[${red}]"; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
print $out "\n"; |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
method ReadPicks ($file) { |
|
301
|
|
|
|
|
|
|
my @picks = (); |
|
302
|
|
|
|
|
|
|
for my $line ( path($file)->lines() ) { |
|
303
|
|
|
|
|
|
|
next if $line =~ /^#/; # skip comment lines |
|
304
|
|
|
|
|
|
|
next unless $line =~ /\d/; # skip lines missing data |
|
305
|
|
|
|
|
|
|
my $pick = {}; |
|
306
|
|
|
|
|
|
|
chomp $line; |
|
307
|
|
|
|
|
|
|
( $pick->{memo}, $line ) = split /::\s+|::/, $line if ( $line =~ /::/ ); |
|
308
|
|
|
|
|
|
|
$pick->{balls} = [ split /\s+/, $line ]; |
|
309
|
|
|
|
|
|
|
push @picks, $pick; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
@picks; |
|
312
|
|
|
|
|
|
|
} |
|
313
|
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head1 Checking Tickets |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 CheckPicks |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
say join "\n", $game->CheckPicks( $winnersfile, $ticketsfile ); |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=head2 The Saved Tickets File Format |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
This library pads single digit numbers with a leading 0. It uses [] to differentiate red balls. The balls are checked as strings so 01 and 1 are not matching numbers just as 02 and [02] are not. The entries are simply the numbers on a line, separated by spaces, with the red balls in [brackets]. |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
A file generated by SavePicks looks like this: |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
05 40 50 57 60 [15] |
|
327
|
|
|
|
|
|
|
02 33 36 44 68 [19] |
|
328
|
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
The format allows for a memo at the beginning of a line, separated from the data by a double colon ::. When included in a winners file, the memo is included in the output. Usually the memo is the date of the draw, but it can be any string. Lines beginning with # are considered comments and not read. |
|
330
|
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Winners files need to be created by hand. |
|
332
|
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# example winners file |
|
334
|
|
|
|
|
|
|
2023-09-16:: 22 30 37 44 45 [18] |
|
335
|
|
|
|
|
|
|
# the memo is just a string, it doesn't have to be the date |
|
336
|
|
|
|
|
|
|
Wednesday 2023-10-11::22 24 40 52 64 [10] |
|
337
|
|
|
|
|
|
|
# the memo isn't required but is helpful when you have |
|
338
|
|
|
|
|
|
|
# multiple lines in your winners file. |
|
339
|
|
|
|
|
|
|
16 34 46 57 59 [23] |
|
340
|
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
=cut |
|
342
|
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
method CheckPicks ( $winnersfile, $ticketsfile ) { |
|
344
|
|
|
|
|
|
|
local $LIST_SEPARATOR = " "; |
|
345
|
|
|
|
|
|
|
my @winners = $self->ReadPicks($winnersfile); |
|
346
|
|
|
|
|
|
|
my @tickets = $self->ReadPicks($ticketsfile); |
|
347
|
|
|
|
|
|
|
my @result = (); |
|
348
|
|
|
|
|
|
|
for my $drawing (@winners) { |
|
349
|
|
|
|
|
|
|
my $ctr = 1; |
|
350
|
|
|
|
|
|
|
my $linehead = '* '; |
|
351
|
|
|
|
|
|
|
my %winballs = map { $_ => $_ } ( $drawing->{balls}->@* ); |
|
352
|
|
|
|
|
|
|
if ( defined $drawing->{memo} ) { |
|
353
|
|
|
|
|
|
|
$linehead .= $drawing->{memo} . ' * '; |
|
354
|
|
|
|
|
|
|
} |
|
355
|
|
|
|
|
|
|
$linehead .= "@{ $drawing->{balls} }"; |
|
356
|
|
|
|
|
|
|
push @result, $linehead; |
|
357
|
|
|
|
|
|
|
for my $ticket (@tickets) { |
|
358
|
|
|
|
|
|
|
my @matched = (); |
|
359
|
|
|
|
|
|
|
my @checkballs = $ticket->{balls}->@*; |
|
360
|
|
|
|
|
|
|
for my $ball (@checkballs) { |
|
361
|
|
|
|
|
|
|
push @matched, ($ball) if defined $winballs{$ball}; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
my $out = " ${\ $ctr++ } -- @checkballs "; |
|
364
|
|
|
|
|
|
|
if (@matched) { |
|
365
|
|
|
|
|
|
|
$out .= "matched (${\ scalar(@matched) }): @matched"; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
push @result, $out; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
return @result; |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
1; |
|
374
|
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=pod |
|
376
|
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
You can allow the Lottery to pick numbers for you, which will save you from having to put numbers you picked onto the slips for the lottery machines. If you search the web and the mobile app stores, you'll find plenty of sites and apps that do similar things to this module. |
|
380
|
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 AUTHOR |
|
382
|
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
John Karr L |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=head2 CONTRIBUTORS |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 BUGS |
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Please report any bugs or feature requests through the web interface at L. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes. |
|
390
|
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head1 TODO |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
The most interesting thing todo would be to use an API to get winning ticket data. There are several providers that require registering for a key. The author would prefer to use a keyless api, preferably provided by the major games or one of the state lotteries. The major games do not provide such an API. |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
Copyright 2023 John Karr. |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify |
|
400
|
|
|
|
|
|
|
it under the terms of the GNU General Public License as published by |
|
401
|
|
|
|
|
|
|
the Free Software Foundation, either version 3 of the License, or |
|
402
|
|
|
|
|
|
|
(at your option) any later version. |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful, |
|
405
|
|
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
406
|
|
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
407
|
|
|
|
|
|
|
GNU General Public License for more details. |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License |
|
410
|
|
|
|
|
|
|
along with this program. If not, see L. |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=cut |