File Coverage

blib/lib/Game/Cribbage/Hands.pm
Criterion Covered Total %
statement 161 168 95.8
branch 52 64 81.2
condition 6 11 54.5
subroutine 27 29 93.1
pod 22 23 95.6
total 268 295 90.8


line stmt bran cond sub pod time code
1             package Game::Cribbage::Hands;
2              
3 8     8   58 use strict;
  8         10  
  8         1872  
4 8     8   29 use warnings;
  8         1535  
  8         1986  
5              
6 8     8   42 use Object::Proto::Sugar -types;
  8         7  
  8         47  
7 8     8   8278 use Game::Cribbage::Player::Hand;
  8         83  
  8         352  
8 8     8   3303 use Game::Cribbage::Play;
  8         86  
  8         333  
9 8     8   37 use Game::Cribbage::Error;
  8         9  
  8         276  
10              
11             has id => (
12             is => 'rw',
13             isa => Int
14             );
15              
16             has number => (
17             is => 'ro',
18             isa => Int
19             );
20              
21             has crib_player => (
22             is => 'rw',
23             isa => Str
24             );
25              
26             has crib_complete => (
27             is => 'rw',
28             isa => Bool
29             );
30              
31             has [qw/starter play player1 player2 player3 player4/] => (
32             is => 'rw',
33             isa => Object
34             );
35              
36             has cannot_play => (
37             is => 'rw',
38             isa => HashRef,
39             default => {}
40             );
41              
42             has play_history => (
43             is => 'rw',
44             isa => ArrayRef,
45             default => []
46             );
47              
48              
49             sub BUILD {
50 41     41 0 71 my ($self, $options) = @_;
51 41 100       162 $self->crib_player('player1') if !$self->crib_player;
52 41         104 return $self;
53             }
54              
55             sub init {
56 41     41 1 59 my ($self, $game) = @_;
57 41         45 for (@{$game->players}) {
  41         82  
58 82         139 my $player = $_->player;
59 82         345 $self->$player(Game::Cribbage::Player::Hand->new(
60             player => $player
61             ));
62             }
63 41         123 $self->new_play();
64 41         76 $self;
65             }
66              
67             sub add_starter_card {
68 31     31 1 40 my ($self, $player, $card) = @_;
69 31         54 $self->starter($card);
70            
71 31         32 my $scored = 0;
72 31 100       100 if ($card->symbol =~ m/^J$/) {
73 1         5 $scored = Game::Cribbage::Play::Score->new(
74             player => $player,
75             card => $card,
76             flipped => 1
77             );
78 1         1 push @{$self->play->scored}, $scored;
  1         3  
79             }
80              
81 31         56 for (qw/player1 player2 player3 player4/) {
82 124 100       214 if ($self->$_) {
83 62         116 $self->$_->starter($card);
84             }
85             }
86              
87 31         48 return $scored;
88             }
89              
90             sub find_player_card {
91 3     3 1 8 my ($self, $card) = @_;
92 3         3 my $player;
93 3         4 for my $p (qw/player1 player2 player3 player4/) {
94 12 100       23 if ($self->$p) {
95 6         7 for (@{$self->$p->cards}) {
  6         11  
96 15 100       21 if ($_->match($card)) {
97 3         4 $card = $_;
98 3         3 $player = $p;
99 3         4 last;
100             }
101             }
102             }
103             }
104 3         8 return ($card, $player);
105             }
106              
107             sub force_play_card {
108 2     2 1 6 my ($self, $card) = @_;
109 2         4 my $player;
110 2         3 ($card, $player) = $self->find_player_card($card);
111 2         5 $card->used(1);
112 2         9 my $scored = $self->play->force_card($player, $card);
113 2         5 $self->set_next_to_play();
114 2         4 return ($scored, $player);
115             }
116              
117             sub play_card {
118 29     29 1 39 my ($self, $player, $card_index) = @_;
119 29 50       83 my $hand = ref $player ? $player->player : $player;
120 29 100       93 if ($self->play->next_to_play ne $hand) {
121 5         51 return Game::Cribbage::Error->new( message => 'It is not the turn of ' . $hand );
122             }
123 24 50       96 my $card = ref $card_index ? $card_index : $self->$hand->get($card_index);
124 24 50 33     107 if (!$card || $card->used) {
125 0         0 die 'CARD HAS ALREADY BEEN PLAYED IN THIS ROUND';
126             }
127              
128 24         51 my $total = $self->play->total;
129 24 100       55 if ($card->value + $total > 31) {
130 2         12 return Game::Cribbage::Error->new( over => 1, message => 'Playing this card will make the score greater than 31');
131             }
132 22         46 $card->used(1);
133 22         79 my $scored = $self->play->card($player, $card);
134 22         51 $self->set_next_to_play();
135 22         39 return $scored;
136             }
137              
138             sub cannot_play_a_card {
139 11     11 1 15 my ($self, $player) = @_;
140            
141 11 100       33 my $hand = ref $player ? $player->player : $player;
142 11 100       46 if ($self->play->next_to_play ne $hand) {
143 1         11 return Game::Cribbage::Error->new( message => 'It is not the turn of ' . $hand );
144             }
145              
146 10         22 my $current_total = $self->play->total;
147              
148 10         11 my @can_be_played;
149 10         15 for (@{$self->$hand->cards}) {
  10         80  
150 40 100       68 next if $_->used;
151 23 100       35 if ( ($current_total + $_->value) < 31 ) {
152 10         14 push @can_be_played, $_;
153             }
154             }
155              
156 10 100       22 return \@can_be_played if scalar @can_be_played;
157              
158 7         15 $self->set_next_to_play();
159              
160 7         19 $self->cannot_play->{$hand} = 1;
161              
162 7         19 return 1;
163             }
164              
165             sub set_next_to_play {
166 31     31 1 37 my ($self) = @_;
167 31         80 my $next = $self->parse_next_to_play($self->play->next_to_play);
168 31         69 $self->play->next_to_play($next);
169             }
170              
171             sub parse_next_to_play {
172 35     35 1 60 my ($self, $player_string) = @_;
173 35         129 $player_string =~ m/player(\d)/;
174 35         72 my $index = $1;
175 35         39 $index++;
176 35         44 my $next = 'player' . $index;
177 35 100       84 if ($self->$next) {
178 22         42 return $next;
179             } else {
180 13         28 return 'player1';
181             }
182             }
183              
184             sub set_player_hand_id {
185 3     3 1 5 my ($self, $player, $id) = @_;
186 3 50       7 my $hand = ref $player ? $player->player : $player;
187 3         13 $self->$hand->id($id);
188 3         4 return $id;
189             }
190              
191             sub get_player_hand_id {
192 2     2 1 4 my ($self, $player) = @_;
193 2 50       6 my $hand = ref $player ? $player->player : $player;
194 2         10 return $self->$hand->id;
195             }
196              
197             sub get_crib_player_hand_id {
198 2     2 1 3 my ($self) = @_;
199 2         5 my $hand = $self->crib_player;
200 2         11 return $self->$hand->id;
201             }
202              
203             sub get_card {
204 8     8 1 9 my ($self, $player, $card_index) = @_;
205 8 50       21 my $hand = ref $player ? $player->player : $player;
206 8         22 my $card = $self->$hand->get($card_index);
207 8         24 return $card;
208             }
209              
210             sub play_score {
211 13     13 1 22 my ($self) = @_;
212 13   100     75 return $self->play->total || 0;
213             }
214              
215             sub last_play_score {
216 3     3 1 11 my ($self) = @_;
217 3         8 my $prev = $self->play_history->[-2];
218 3 100       14 return $prev ? $prev->total : 'This is the first play';
219             }
220              
221             sub new_play {
222 45     45 1 60 my ($self) = @_;
223 45         114 my $next_to_play = $self->crib_player;
224 45 100       96 if ($self->play) {
225 4 50       39 $next_to_play = $self->parse_next_to_play(ref $self->play->cards->[-1]->player ? $self->play->cards->[-1]->player->player : $self->play->cards->[-1]->player);
226             }
227 45         232 $self->play(Game::Cribbage::Play->new(
228             next_to_play => $next_to_play
229             ));
230 45         48 push @{$self->play_history}, $self->play;
  45         105  
231             }
232              
233             sub next_play {
234 7     7 1 9 my ($self, $game) = @_;
235              
236             # first check whether any players can play on the current 'play'
237             # if they can they must use those cards first.
238 7         18 my $current_total = $self->play->total;
239              
240 7         9 my $available_cards = 0;
241 7         12 for my $hand (qw/player1 player2 player3 player4/) {
242 22 100       52 if ($self->$hand) {
243 12         14 my @can_be_played;
244 12         11 for (@{$self->$hand->cards}) {
  12         28  
245 48 100       103 next if $_->used;
246 21         21 $available_cards = 1;
247 21 100       35 if ( $current_total + $_->value < 31 ) {
248 6         6 push @can_be_played, $_;
249             }
250             }
251 12 100       38 if (scalar @can_be_played) {
252 2         10 return Game::Cribbage::Error->new(
253             message => 'Cards can be played',
254             player => $hand,
255             cards => \@can_be_played
256             );
257             }
258             }
259             }
260              
261 5         18 $self->cannot_play({});
262             # now we know cards can't be played confirm we have cards left to Play another 'play'.
263 5 100       10 if (!$available_cards) {
264 1         3 $game->end_hands();
265 1         2 return undef;
266             }
267            
268 4         6 my $scored;
269 4 50 66     26 if (!$self->play->scored->[-1] || !$self->play->scored->[-1]->go) {
270 4         14 $scored = $self->play->end_play();
271             }
272              
273 4         12 $self->new_play();
274              
275 4         9 return $scored;
276             }
277              
278             sub end_play {
279 2     2 1 4 my ($self) = @_;
280              
281 2         2 my $scored;
282              
283 2 50 33     36 if (!$self->play->scored->[-1] || !$self->play->scored->[-1]->go) {
284 2         8 $scored = $self->play->end_play();
285             }
286              
287 2         6 $self->play(undef);
288              
289 2         4 return $scored;
290             }
291              
292             sub score_hands {
293 3     3 1 6 my ($self) = @_;
294 3         4 my %scored;
295 3         7 for (qw/player1 player2 player3 player4/) {
296 12 100       43 $scored{$_} = $self->$_->calculate_score()
297             if ($self->$_);
298             }
299 3         9 return \%scored;
300             }
301              
302             sub card_exists {
303 0     0 1 0 my ($self, $player, $card) = @_;
304 0 0       0 $player = ref $player ? $player->player : $player;
305 0         0 return $self->$player->card_exists($card);
306             }
307              
308             sub set_crib_complete {
309 2     2 1 4 my ($self) = @_;
310 2         6 $self->crib_complete(1);
311             }
312              
313             sub best_run_play {
314 2     2 1 4 my ($self, $player) = @_;
315 2 50       6 $player = ref $player ? $player->player : $player;
316 2         23 return $self->$player->best_run_play($self->play);
317             }
318              
319             sub next_to_play_id {
320 0     0 1   my ($self, $game) = @_;
321 0           my $hand = $self->play->next_to_play;
322 0           return $hand;
323             }
324              
325             1;
326              
327             __END__