File Coverage

blib/lib/Game/Cribbage/Score.pm
Criterion Covered Total %
statement 105 105 100.0
branch 40 42 95.2
condition 2 3 66.6
subroutine 14 14 100.0
pod 0 7 0.0
total 161 171 94.1


line stmt bran cond sub pod time code
1             package Game::Cribbage::Score;
2              
3 11     11   75 use strict;
  11         16  
  11         369  
4 11     11   36 use warnings;
  11         11  
  11         552  
5              
6 11     11   45 use Object::Proto::Sugar -types;
  11         12  
  11         106  
7              
8 11     11   13704 use ntheory qw/forcomb vecsum/;
  11         111605  
  11         56  
9              
10             has total_score => (
11             is => 'rw',
12             isa => Int
13             );
14              
15             has scored => (
16             is => 'ro',
17             builder => 1
18             );
19              
20             sub _build_scored {
21             return {
22 33     33   238 fifteen => 2,
23             pair => 2,
24             three_of_a_kind => 6,
25             four_of_a_kind => 12,
26             run => [3, 4, 5],
27             four_flush => 4,
28             five_flush => 5,
29             nobs => 1
30             }
31             }
32              
33             has [qw/fifteen pair three_of_a_kind four_of_a_kind run four_flush five_flush nobs cards/] => (
34             is => 'rw',
35             isa => ArrayRef,
36             default => []
37             );
38              
39             has with_starter => (
40             is => 'ro',
41             isa => Bool
42             );
43              
44             sub BUILD {
45 33     33 0 51 my ($self, $params) = @_;
46 33         67 my $starter = $self->cards->[-1];
47 33         34 my @cards = sort { $b->value <=> $a->value } @{$self->cards};
  196         281  
  33         87  
48 33         91 $self->calculate_fifteen(@cards);
49 33         71 $self->calculate_of_a_kind(@cards);
50 33         77 $self->calculate_run(@cards);
51 33         94 $self->calculate_flush(@cards);
52 33 100       95 $self->calculate_nob($starter, @cards) if $self->with_starter;
53 33         66 $self->calculate_total();
54 33         104 return $self;
55             }
56              
57             sub calculate_nob {
58 17     17 0 33 my ($self, $starter, @cards) = @_;
59              
60 17 100       101 return if ($starter->symbol eq 'J');
61              
62 16         28 for (@cards) {
63 60 100 66     159 if ($_->symbol eq 'J' && $starter->suit eq $_->suit) {
64 5         14 push @{$self->nobs}, $_;
  5         11  
65 5         12 last;
66             }
67             }
68             };
69              
70             sub calculate_run {
71 33     33 0 46 my ($self, @cards) = @_;
72              
73 33         48 my @values = map { $_->run_value } @cards;
  149         199  
74            
75 33         35 my %map;
76 33         53 foreach my $n (1 .. @values) {
77             forcomb {
78 767     767   745 my $first = $values[$_[0]];
79 767         676 my $match = 1;
80 767 100       1179 return if scalar @_ < 3;
81 352         461 for (my $i = 1; $i < scalar(@_); $i++) {
82 839         716 $first = $first - 1;
83 839 100       1054 if ($first != $values[$_[$i]]) {
84 777         908 $match = 0;
85             }
86             }
87 352 100       593 if ($match) {
88 22 100       41 if (scalar(@_) == 3) {
    100          
89 15         31 push @{$map{three}}, [@cards[@_]];
  15         81  
90             } elsif (scalar(@_) == 4) {
91 6         9 push @{$map{four}}, [@cards[@_]];
  6         52  
92             } else {
93 1         1 push @{$map{five}}, [@cards[@_]];
  1         6  
94             }
95             }
96 149         434 } @values, $n;
97             }
98            
99 33 100       125 if ($map{five}) {
    100          
    100          
100 1         6 $self->run($map{five});
101             } elsif ($map{four}) {
102 4         21 $self->run($map{four});
103             } elsif ($map{three}) {
104 4         15 $self->run($map{three});
105             }
106             }
107              
108             sub calculate_flush {
109 33     33 0 54 my ($self, @cards) = @_;
110 33         34 my %map;
111 33         41 push @{$map{$_->suit}}, $_ for (@cards);
  149         299  
112 33         65 for (keys %map) {
113 92         87 my $c = scalar @{$map{$_}};
  92         96  
114 92 100       196 if ($c == 4) {
    100          
115 2         3 push @{$self->four_flush}, $map{$_};
  2         6  
116             } elsif ($c == 5) {
117 1         2 push @{$self->five_flush}, $map{$_};
  1         4  
118             }
119             }
120              
121             }
122              
123             sub calculate_fifteen {
124 33     33 0 64 my ($self, @cards) = @_;
125 33         45 my @values = map { $_->value } @cards;
  149         198  
126 33         69 foreach my $n (1 .. @values) {
127             forcomb {
128 767 100   767   1453 push @{$self->fifteen}, [@cards[@_]] if vecsum(@values[@_]) == 15;
  67         136  
129 149         565 } @values, $n
130             }
131             }
132              
133             sub calculate_of_a_kind {
134 33     33 0 49 my ($self, @cards) = @_;
135 33         58 my %map = ();
136 33         116 push @{$map{$_->symbol}}, $_ for (@cards);
  149         274  
137 33         65 for (keys %map) {
138 117         95 my $c = scalar @{$map{$_}};
  117         126  
139 117 100       191 next if ($c == 1);
140 23 100       50 if ($c == 2) {
    100          
    50          
141 16         17 push @{$self->pair}, $map{$_};
  16         41  
142             } elsif ($c == 3) {
143 5         9 push @{$self->three_of_a_kind}, $map{$_};
  5         16  
144             } elsif ($c == 4) {
145 2         3 push @{$self->four_of_a_kind}, $map{$_};
  2         7  
146             }
147             }
148             }
149              
150             sub calculate_total {
151 33     33 0 43 my ($self) = @_;
152 33         50 my $scored = $self->scored;
153 33         37 my $score = 0;
154 33         37 for (keys %{$scored}) {
  33         72  
155 264 100       266 if (scalar @{$self->$_}) {
  264         484  
156 64 100       122 if ($_ eq 'run') {
157 9 50       25 $score += scalar @{$self->$_} * scalar @{$self->$_->[0]}
  9         17  
  9         21  
158             if $self->$_->[0];
159             } else {
160 55         67 $score += $scored->{$_} * scalar @{$self->$_};
  55         101  
161             }
162             }
163             }
164 33         71 $self->total_score($score);
165             }
166              
167             1;