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 6 7 85.7
total 167 171 97.6


line stmt bran cond sub pod time code
1             package Game::Cribbage::Score;
2              
3 11     11   56 use strict;
  11         16  
  11         389  
4 11     11   40 use warnings;
  11         11  
  11         531  
5              
6 11     11   43 use Object::Proto::Sugar -types;
  11         14  
  11         68  
7              
8 11     11   13994 use ntheory qw/forcomb vecsum/;
  11         114376  
  11         58  
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   247 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 54 my ($self, $params) = @_;
46 33         79 my $starter = $self->cards->[-1];
47 33         34 my @cards = sort { $b->value <=> $a->value } @{$self->cards};
  196         264  
  33         103  
48 33         94 $self->calculate_fifteen(@cards);
49 33         75 $self->calculate_of_a_kind(@cards);
50 33         88 $self->calculate_run(@cards);
51 33         95 $self->calculate_flush(@cards);
52 33 100       102 $self->calculate_nob($starter, @cards) if $self->with_starter;
53 33         68 $self->calculate_total();
54 33         105 return $self;
55             }
56              
57             sub calculate_nob {
58 17     17 1 30 my ($self, $starter, @cards) = @_;
59              
60 17 100       46 return if ($starter->symbol eq 'J');
61              
62 16         69 for (@cards) {
63 60 100 66     142 if ($_->symbol eq 'J' && $starter->suit eq $_->suit) {
64 5         18 push @{$self->nobs}, $_;
  5         12  
65 5         12 last;
66             }
67             }
68             };
69              
70             sub calculate_run {
71 33     33 1 52 my ($self, @cards) = @_;
72              
73 33         48 my @values = map { $_->run_value } @cards;
  149         195  
74            
75 33         38 my %map;
76 33         56 foreach my $n (1 .. @values) {
77             forcomb {
78 767     767   787 my $first = $values[$_[0]];
79 767         648 my $match = 1;
80 767 100       1155 return if scalar @_ < 3;
81 352         521 for (my $i = 1; $i < scalar(@_); $i++) {
82 839         730 $first = $first - 1;
83 839 100       1091 if ($first != $values[$_[$i]]) {
84 777         1009 $match = 0;
85             }
86             }
87 352 100       638 if ($match) {
88 22 100       46 if (scalar(@_) == 3) {
    100          
89 15         17 push @{$map{three}}, [@cards[@_]];
  15         92  
90             } elsif (scalar(@_) == 4) {
91 6         6 push @{$map{four}}, [@cards[@_]];
  6         57  
92             } else {
93 1         1 push @{$map{five}}, [@cards[@_]];
  1         5  
94             }
95             }
96 149         444 } @values, $n;
97             }
98            
99 33 100       141 if ($map{five}) {
    100          
    100          
100 1         4 $self->run($map{five});
101             } elsif ($map{four}) {
102 4         23 $self->run($map{four});
103             } elsif ($map{three}) {
104 4         24 $self->run($map{three});
105             }
106             }
107              
108             sub calculate_flush {
109 33     33 1 68 my ($self, @cards) = @_;
110 33         41 my %map;
111 33         49 push @{$map{$_->suit}}, $_ for (@cards);
  149         306  
112 33         66 for (keys %map) {
113 92         95 my $c = scalar @{$map{$_}};
  92         94  
114 92 100       199 if ($c == 4) {
    100          
115 2         4 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 1 51 my ($self, @cards) = @_;
125 33         41 my @values = map { $_->value } @cards;
  149         204  
126 33         74 foreach my $n (1 .. @values) {
127             forcomb {
128 767 100   767   3380 push @{$self->fifteen}, [@cards[@_]] if vecsum(@values[@_]) == 15;
  67         151  
129 149         540 } @values, $n
130             }
131             }
132              
133             sub calculate_of_a_kind {
134 33     33 1 115 my ($self, @cards) = @_;
135 33         43 my %map = ();
136 33         49 push @{$map{$_->symbol}}, $_ for (@cards);
  149         265  
137 33         101 for (keys %map) {
138 117         109 my $c = scalar @{$map{$_}};
  117         125  
139 117 100       187 next if ($c == 1);
140 23 100       63 if ($c == 2) {
    100          
    50          
141 16         21 push @{$self->pair}, $map{$_};
  16         68  
142             } elsif ($c == 3) {
143 5         9 push @{$self->three_of_a_kind}, $map{$_};
  5         26  
144             } elsif ($c == 4) {
145 2         2 push @{$self->four_of_a_kind}, $map{$_};
  2         8  
146             }
147             }
148             }
149              
150             sub calculate_total {
151 33     33 1 42 my ($self) = @_;
152 33         51 my $scored = $self->scored;
153 33         37 my $score = 0;
154 33         36 for (keys %{$scored}) {
  33         75  
155 264 100       223 if (scalar @{$self->$_}) {
  264         500  
156 64 100       83 if ($_ eq 'run') {
157 9 50       26 $score += scalar @{$self->$_} * scalar @{$self->$_->[0]}
  9         15  
  9         19  
158             if $self->$_->[0];
159             } else {
160 55         85 $score += $scored->{$_} * scalar @{$self->$_};
  55         94  
161             }
162             }
163             }
164 33         74 $self->total_score($score);
165             }
166              
167             1;
168              
169             __END__