File Coverage

blib/lib/App/Games/Keno.pm
Criterion Covered Total %
statement 57 106 53.7
branch 26 48 54.1
condition 10 18 55.5
subroutine 10 13 76.9
pod 0 5 0.0
total 103 190 54.2


line stmt bran cond sub pod time code
1             use Moose;
2 1     1   879 use Types::Standard qw(Int ArrayRef HashRef Bool);
  1         402373  
  1         6  
3 1     1   7338 use Carp qw(croak carp);
  1         65957  
  1         12  
4 1     1   1082 use List::Compare qw (get_intersection);
  1         3  
  1         56  
5 1     1   798 use List::Util qw(any uniq);
  1         20340  
  1         45  
6 1     1   8 use Scalar::Util qw(looks_like_number);
  1         3  
  1         69  
7 1     1   6  
  1         3  
  1         1156  
8             # ABSTRACT: Plays Keno
9              
10             =head1 NAME
11            
12             App::Games::Keno
13            
14             =head1 SYNOPSIS
15            
16             This package plays a game of Keno. The number range is 1 to 80 and the payout amounts are for 1 to 10 spots.
17            
18             Sample code to play 1000 draws with 5 spots. The spots are chosen for you.
19              
20             use App::Games::Keno;
21              
22             my $first_game = App::Games::Keno->new( num_spots => 5, draws => 1000 );
23             $first_game->PlayKeno;
24             say "You won \$"
25             . $first_game->winnings . " on "
26             . $first_game->draws
27             . " draws.";
28              
29             This is how you choose your own spots.
30              
31             my $second_game = App::Games::Keno->new(
32             spots => [ 45, 33, 12, 20, 75 ],
33             draws => 1000
34             );
35             $second_game->PlayKeno;
36             say "You won \$"
37             . $second_game->winnings . " on "
38             . $second_game->draws
39             . " draws.";
40              
41             Several verbosity levels exist, use theme like this:
42              
43             my $third_game = App::Games::Keno->new(
44             spots => [ 45, 33, 12, 20, 75 ],
45             draws => 1000,
46             verbose => 1
47             );
48            
49             Verbose level 0 is the default and prints nothing.
50             Verbose level 1 prints the amount won on winning draws.
51             Verbose level 2 prints evrything from verbose level 1 and the
52             numbers drawn on each draw and the numbers that matched.
53              
54             =cut
55              
56             my $self = shift;
57              
58 17     17 0 19474 croak "Didn't get the number of draws you want"
59             if ( !defined $self->draws );
60 17 100       430 croak "Spots or Number of spots (not both)"
61             if ( defined $self->spots && defined $self->num_spots );
62 16 100 100     338 croak "Need spots or number of spots"
63             if ( !defined $self->spots && !defined $self->num_spots );
64 15 100 100     330  
65             if ( !defined $self->verbose ) { $self->verbose(0); }
66             if ( $self->verbose < 0 || $self->verbose > 2 ) {
67 14 50       290 warn "'" . $self->verbose . "' is not a valid verbose level, using '0'";
  0         0  
68 14 100 100     287 $self->verbose(0);
69 2         43 }
70 2         64  
71             if ( defined $self->spots ) {
72             if ( any { !looks_like_number($_) } @{ $self->spots } ) {
73 14 100 33     292 croak "One of the spots you chose doesn't look like a number.";
    50          
74 13 100   30   65 }
  30         63  
  13         260  
75 1         186 if ( any { $_ < 1 || $_ > 80 } @{ $self->spots } ) {
76             croak "You chose a spot that is out of the 1 to 80 range";
77 12 100   28   78 }
  28 100       75  
  12         269  
78 3         314 if ( scalar @{ $self->spots } != uniq @{ $self->spots } ) {
79             croak "You appear to have chosen two or more of the same spots";
80 9 100       32 }
  9         193  
  9         175  
81 1         90 if ( scalar @{ $self->spots } < 1 ) {
82             croak "You must choose at least one spot";
83 8 100       15 }
  8         175  
84 1         95 if ( my $too_many_spots = scalar @{ $self->spots } > 10 ) {
85             croak "Too many spots. You must choose between 1 and 10 spots";
86 7 100       13 }
  7         137  
87 1         92 $self->num_spots( scalar @{ $self->spots } );
88             }
89 6         10 elsif ( $self->num_spots >= 1 && $self->num_spots <= 10 ) {
  6         117  
90             $self->spots( get_random_set( $self->num_spots ) );
91             }
92 1         26 else {
93             croak "You must ask for between 1 and 10 spots.";
94             }
95 0         0  
96             if ( !defined $self->verbose ) {
97             $self->verbose(0);
98 7 50       147 }
99 0         0  
100             return;
101             }
102 7         20  
103             has 'draws' => (
104             is => 'rw',
105             isa => Int,
106             );
107              
108             has 'winnings' => (
109             is => 'rw',
110             isa => Int,
111             default => 0
112             );
113              
114             has 'num_won_draws' => (
115             is => 'rw',
116             isa => Int,
117             default => 0
118             );
119              
120             has 'num_spots' => (
121             is => 'rw',
122             isa => Int,
123             );
124              
125             has 'spots' => (
126             is => 'rw',
127             isa => ArrayRef,
128             );
129              
130             has 'verbose' => (
131             is => 'rw',
132             isa => Int,
133             default => 0
134             );
135              
136             has 'payout_table' => (
137             is => 'ro',
138             isa => HashRef,
139             default => sub {
140             return {
141             '1' => {
142             '1' => 2
143             },
144             '2' => {
145             '2' => 11
146             },
147             '3' => {
148             '2' => 2,
149             '3' => 27
150             },
151             '4' => {
152             '2' => 1,
153             '3' => 5,
154             '4' => 75
155             },
156             '5' => {
157             '3' => 2,
158             '4' => 18,
159             '5' => 420
160             },
161             '6' => {
162             '3' => 1,
163             '4' => 8,
164             '5' => 50,
165             '6' => 1100,
166             },
167             '7' => {
168             '3' => 1,
169             '4' => 3,
170             '5' => 17,
171             '6' => 100,
172             '7' => 4500
173             },
174             '8' => {
175             '4' => 2,
176             '5' => 12,
177             '6' => 50,
178             '7' => 750,
179             '8' => 10_000
180             },
181             '9' => {
182             '4' => 1,
183             '5' => 6,
184             '6' => 25,
185             '7' => 150,
186             '8' => 3000,
187             '9' => 30_000,
188             },
189             '10' => {
190             '0' => 5,
191             '5' => 2,
192             '6' => 15,
193             '7' => 40,
194             '8' => 450,
195             '9' => 4250,
196             '10' => 100_000
197             }
198             };
199             }
200             );
201              
202             my $self = shift;
203             my $num_won_draws = 0;
204             if ( $self->verbose > 0 ) {
205 0     0 0 0 print "You are playing "
206 0         0 . $self->draws
207 0 0       0 . " draws with "
208             . scalar @{ $self->spots }
209             . " spots: "
210             . join( " ", sort { $a <=> $b } @{ $self->spots } )
211 0         0 . "\n\n";
212             }
213 0         0 for ( 1 .. $self->draws ) {
  0         0  
  0         0  
214             my $drawnNumbers = get_random_set(20);
215             my $list_compare = List::Compare->new( $self->spots, $drawnNumbers );
216 0         0 my @matchedNumbers = $list_compare->get_intersection;
217 0         0 my $matches = scalar @matchedNumbers;
218 0         0 my $this_payout = $self->get_payout($matches);
219 0         0 if ( $matches > 6 && $matches == $self->num_spots ) {
220 0         0 print
221 0         0 "You matched all $matches spots and won \$$this_payout on draw $_\n";
222 0 0 0     0 }
223 0         0 if ( $this_payout > 0 ) {
224             $num_won_draws++;
225             }
226 0 0       0 my $winningsIn = $self->winnings;
227 0         0 my $winningsOut = $winningsIn + $this_payout;
228             $self->winnings($winningsOut);
229 0         0  
230 0         0 if ( $self->verbose > 1 ) {
231 0         0 print "** Draw $_: ";
232             print join( " ", sort { $a <=> $b } @{$drawnNumbers} );
233 0 0       0 if ( $matches > 0 ) {
234 0         0 print "\nYou matched $matches numbers: ("
235 0         0 . join( " ", sort { $a <=> $b } @matchedNumbers ) . ") ";
  0         0  
  0         0  
236 0 0       0  
237             }
238 0         0 else {
  0         0  
239             print "\nYou matched no numbers.";
240             }
241             if ( $this_payout == 0 ) {
242 0         0 print " There is no payout for that. You LOSE!!";
243             }
244 0 0       0 print "\n";
245 0         0 }
246              
247 0         0 if ( $self->verbose > 0 && $this_payout > 0 ) {
248             print
249             "You matched $matches numbers and won \$$this_payout on draw $_\n";
250 0 0 0     0 }
251 0         0 }
252             if ( $self->verbose > 0 ) {
253             print "\nYou won "
254             . commify($num_won_draws) . " of "
255 0 0       0 . commify( $self->draws )
256 0         0 . " draws.\n";
257             }
258             return;
259             }
260              
261 0         0 my $count = shift;
262             my @random_set;
263             my %seen;
264              
265 1     1 0 10 for ( 1 .. $count ) {
266 1         2 my $candidate = 1 + int rand(80);
267             redo if $seen{$candidate}++;
268             push @random_set, $candidate;
269 1         5 }
270 5         11  
271 5 50       27 return \@random_set;
272 5         11 }
273              
274             my $self = shift;
275 1         28 my $match = shift;
276             my $spot = $self->num_spots;
277              
278             if ( exists( $self->payout_table->{$spot}{$match} ) ) {
279 0     0 0   return $self->payout_table->{$spot}{$match};
280 0           }
281 0           else {
282             return 0;
283 0 0         }
284 0           }
285              
286             my $text = reverse $_[0];
287 0           $text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
288             return scalar reverse $text;
289             }
290              
291             1;
292 0     0 0