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 0 8 0.0
total 153 166 92.1


line stmt bran cond sub pod time code
1             package Game::Cribbage::Play;
2              
3 10     10   85699 use strict;
  10         33  
  10         315  
4 10     10   33 use warnings;
  10         17  
  10         452  
5              
6 10     10   526 use Object::Proto::Sugar -types;
  10         12590  
  10         61  
7 10     10   11631 use Game::Cribbage::Play::Card;
  10         88  
  10         382  
8 10     10   3617 use Game::Cribbage::Play::Score;
  10         108  
  10         404  
9 10     10   411 use Game::Cribbage::Error;
  10         23  
  10         299  
10 10     10   488 use ntheory qw/forcomb vecsum/;
  10         11242  
  10         47  
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 0 54 my ($self, $player, $card) = @_;
30              
31 15         31 my $total = $self->calculate_total([@{$self->cards}, $card], 0);
  15         64  
32            
33 15 100       32 if ($total > 31) {
34 1         4 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         73 my $score = Game::Cribbage::Play::Score->new(
41             player => $player,
42             card => $card
43             );
44              
45 14         29 $self->calculate_pair($score, $card);
46              
47 14         25 $self->calculate_run($score, $card);
48              
49 14         16 $total = $self->calculate_total([@{$self->cards}, $card], 0);
  14         45  
50              
51 14         33 $self->calculate_hits($score, $total);
52              
53 14         25 return $score->score;
54             }
55              
56             sub card {
57 53     53 0 164 my ($self, $player, $card) = @_;
58              
59 53         65 my $total = $self->calculate_total([@{$self->cards}, $card], 0);
  53         164  
60              
61 53 50       139 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         262 my $score = Game::Cribbage::Play::Score->new(
69             player => $player,
70             card => $card
71             );
72              
73 53         115 $self->calculate_pair($score, $card);
74              
75 53         103 $self->calculate_run($score, $card);
76              
77 53         54 push @{$self->cards}, Game::Cribbage::Play::Card->new(
  53         220  
78             player => $player,
79             card => $card
80             );
81              
82 53         114 $total = $self->calculate_total($self->cards, 1);
83              
84 53         96 $self->calculate_hits($score, $total);
85              
86 53 100       104 if ($score->score) {
87 16         18 push @{$self->scored}, $score;
  16         27  
88             }
89 53         126 return $score;
90             }
91              
92             sub force_card {
93 4     4 0 18 my ($self, $player, $card) = @_;
94              
95 4         5 for (@{$self->cards}) {
  4         15  
96 1 50       4 if ($_->card->match($card)) {
97 1         4 return 0;
98             }
99             }
100            
101 3         8 return $self->card($player, $card);
102             }
103              
104              
105             sub end_play {
106 8     8 0 798 my ($self) = @_;
107              
108 8 100       29 return unless $self->cards->[0];
109              
110 7         58 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         15 push @{$self->scored}, $score;
  7         14  
117              
118 7         17 return $score;
119             }
120              
121             sub calculate_pair {
122 67     67 0 111 my ($self, $score, $card) = @_;
123              
124 67 100 100     201 if ($self->cards->[-1] && $self->cards->[-1]->symbol eq $card->symbol) {
125 9 100 66     23 if ($self->cards->[-2] && $self->cards->[-2]->symbol eq $card->symbol) {
126 4 100 66     12 if ($self->cards->[-3] && $self->cards->[-3]->symbol eq $card->symbol) {
127 1         3 $score->pair(3);
128             } else {
129 3         6 $score->pair(2);
130             }
131             } else {
132 5         9 $score->pair(1);
133             }
134             }
135              
136 67         94 return 1;
137             }
138              
139             sub calculate_run {
140 67     67 0 85 my ($self, $score, $card) = @_;
141 67         72 my @cards = map { $_->card } @{$self->cards};
  47         98  
  67         122  
142 67         94 my @values = map { $_->run_value } (@cards, $card);
  114         163  
143 67         96 my $length = scalar @values - 1;
144 67         71 my $set = 5;
145 67         96 for my $n (qw/6 5 4 3 2/) {
146 334         298 my $match = $set--;
147 334 100       441 next unless $n <= $length;
148 17         129 my @new = sort { $a <=> $b } @values[$length - $n .. $length];
  55         87  
149 17         23 my $first = $new[0];
150 17         31 for (my $i = 1; $i <= $n; $i++) {
151 23         26 $first = $first + 1;
152 23 100       56 if ($first != $new[$i]) {
153 14         16 $match = 0;
154 14         22 $i = $n + 1;
155             }
156             }
157 17 100       32 if ($match) {
158 3         5 $score->run($match);
159 3         7 last;
160             }
161             }
162              
163 67         95 return 1;
164             }
165              
166             sub calculate_total {
167 137     137 0 1742 my ($self, $cards, $set) = @_;
168              
169 137         140 my $total = 0;
170 137         131 for (@{ $cards }) {
  137         186  
171 236         339 $total += $_->value;
172             }
173 137 100       211 if ($set) {
174 54         91 $self->total($total);
175             }
176              
177 137         173 return $total;
178             }
179              
180             sub calculate_hits {
181 67     67 0 84 my ($self, $score, $total) = @_;
182 67 100       155 if ($total == 15) {
    100          
183 4         7 $score->fifteen(1);
184             } elsif ($total == 31) {
185 1         3 $score->pegged(1);
186 1         3 $score->go(1);
187             }
188              
189 67         72 return 1;
190             }
191              
192             1;