File Coverage

blib/lib/Game/Cribbage/Play.pm
Criterion Covered Total %
statement 105 106 99.0
branch 26 28 92.8
condition 7 9 77.7
subroutine 15 15 100.0
pod 8 8 100.0
total 161 166 96.9


line stmt bran cond sub pod time code
1             package Game::Cribbage::Play;
2              
3 10     10   82056 use strict;
  10         43  
  10         400  
4 10     10   37 use warnings;
  10         16  
  10         498  
5              
6 10     10   512 use Object::Proto::Sugar -types;
  10         12086  
  10         60  
7 10     10   12180 use Game::Cribbage::Play::Card;
  10         83  
  10         369  
8 10     10   3790 use Game::Cribbage::Play::Score;
  10         107  
  10         400  
9 10     10   390 use Game::Cribbage::Error;
  10         21  
  10         254  
10 10     10   442 use ntheory qw/forcomb vecsum/;
  10         11049  
  10         45  
11              
12             has [qw/id next_to_play/] => (
13             is => 'rw',
14             );
15              
16             has total => (
17             is => 'rw',
18             isa => Int,
19             default => 0,
20             );
21              
22             has [qw/cards scored/] => (
23             is => 'rw',
24             isa => ArrayRef,
25             default => []
26             );
27              
28             sub test_card {
29 15     15 1 85 my ($self, $player, $card) = @_;
30              
31 15         19 my $total = $self->calculate_total([@{$self->cards}, $card], 0);
  15         42  
32            
33 15 100       32 if ($total > 31) {
34 1         3 return Game::Cribbage::Error->new(
35             message => 'Total count would be greater than 31 if ' . $card->stringify . ' was to be played',
36             go => 1
37             );
38             }
39              
40 14         70 my $score = Game::Cribbage::Play::Score->new(
41             player => $player,
42             card => $card
43             );
44              
45 14         31 $self->calculate_pair($score, $card);
46              
47 14         38 $self->calculate_run($score, $card);
48              
49 14         13 $total = $self->calculate_total([@{$self->cards}, $card], 0);
  14         43  
50              
51 14         32 $self->calculate_hits($score, $total);
52              
53 14         28 return $score->score;
54             }
55              
56             sub card {
57 53     53 1 156 my ($self, $player, $card) = @_;
58              
59 53         60 my $total = $self->calculate_total([@{$self->cards}, $card], 0);
  53         169  
60              
61 53 50       123 if ($total > 31) {
62 0         0 return Game::Cribbage::Error->new(
63             message => 'Total count would be greater than 31 if ' . $card->stringify . ' was to be played',
64             go => 1
65             );
66             }
67              
68 53         263 my $score = Game::Cribbage::Play::Score->new(
69             player => $player,
70             card => $card
71             );
72              
73 53         117 $self->calculate_pair($score, $card);
74              
75 53         114 $self->calculate_run($score, $card);
76              
77 53         53 push @{$self->cards}, Game::Cribbage::Play::Card->new(
  53         239  
78             player => $player,
79             card => $card
80             );
81              
82 53         105 $total = $self->calculate_total($self->cards, 1);
83              
84 53         116 $self->calculate_hits($score, $total);
85              
86 53 100       94 if ($score->score) {
87 16         17 push @{$self->scored}, $score;
  16         28  
88             }
89 53         133 return $score;
90             }
91              
92             sub force_card {
93 4     4 1 18 my ($self, $player, $card) = @_;
94              
95 4         5 for (@{$self->cards}) {
  4         11  
96 1 50       10 if ($_->card->match($card)) {
97 1         4 return 0;
98             }
99             }
100            
101 3         7 return $self->card($player, $card);
102             }
103              
104              
105             sub end_play {
106 8     8 1 591 my ($self) = @_;
107              
108 8 100       27 return unless $self->cards->[0];
109              
110 7         57 my $score = Game::Cribbage::Play::Score->new(
111             player => $self->cards->[-1]->player,
112             card => $self->cards->[-1],
113             go => 1
114             );
115              
116 7         29 push @{$self->scored}, $score;
  7         21  
117              
118 7         16 return $score;
119             }
120              
121             sub calculate_pair {
122 67     67 1 98 my ($self, $score, $card) = @_;
123              
124 67 100 100     231 if ($self->cards->[-1] && $self->cards->[-1]->symbol eq $card->symbol) {
125 9 100 66     24 if ($self->cards->[-2] && $self->cards->[-2]->symbol eq $card->symbol) {
126 4 100 66     27 if ($self->cards->[-3] && $self->cards->[-3]->symbol eq $card->symbol) {
127 1         3 $score->pair(3);
128             } else {
129 3         4 $score->pair(2);
130             }
131             } else {
132 5         15 $score->pair(1);
133             }
134             }
135              
136 67         127 return 1;
137             }
138              
139             sub calculate_run {
140 67     67 1 77 my ($self, $score, $card) = @_;
141 67         71 my @cards = map { $_->card } @{$self->cards};
  47         82  
  67         122  
142 67         120 my @values = map { $_->run_value } (@cards, $card);
  114         166  
143 67         91 my $length = scalar @values - 1;
144 67         72 my $set = 5;
145 67         87 for my $n (qw/6 5 4 3 2/) {
146 334         329 my $match = $set--;
147 334 100       455 next unless $n <= $length;
148 17         72 my @new = sort { $a <=> $b } @values[$length - $n .. $length];
  55         85  
149 17         55 my $first = $new[0];
150 17         76 for (my $i = 1; $i <= $n; $i++) {
151 23         29 $first = $first + 1;
152 23 100       40 if ($first != $new[$i]) {
153 14         16 $match = 0;
154 14         24 $i = $n + 1;
155             }
156             }
157 17 100       41 if ($match) {
158 3         6 $score->run($match);
159 3         7 last;
160             }
161             }
162              
163 67         111 return 1;
164             }
165              
166             sub calculate_total {
167 137     137 1 1316 my ($self, $cards, $set) = @_;
168              
169 137         174 my $total = 0;
170 137         155 for (@{ $cards }) {
  137         175  
171 236         354 $total += $_->value;
172             }
173 137 100       221 if ($set) {
174 54         93 $self->total($total);
175             }
176              
177 137         185 return $total;
178             }
179              
180             sub calculate_hits {
181 67     67 1 101 my ($self, $score, $total) = @_;
182 67 100       141 if ($total == 15) {
    100          
183 4         9 $score->fifteen(1);
184             } elsif ($total == 31) {
185 1         4 $score->pegged(1);
186 1         2 $score->go(1);
187             }
188              
189 67         73 return 1;
190             }
191              
192             1;
193              
194             __END__