File Coverage

blib/lib/Ticketmaster.pm
Criterion Covered Total %
statement 9 79 11.3
branch 0 24 0.0
condition 0 12 0.0
subroutine 3 11 27.2
pod 4 5 80.0
total 16 131 12.2


line stmt bran cond sub pod time code
1             package Ticketmaster;
2              
3 1     1   38079 use 5.008008;
  1         3  
  1         29  
4 1     1   5 use strict;
  1         2  
  1         88  
5 1     1   5 use warnings;
  1         5  
  1         686  
6              
7              
8             our $VERSION = '1.02';
9              
10             sub new {
11 0     0 0   my $class = shift;
12 0   0       my $type = ref($class) || $class;
13 0           my $self = bless {}, $type;
14              
15 0           $self->{'coins'} = [];
16 0 0         $self->reload({ @_ }) if @_;
17 0           $self;
18             }
19              
20             sub reload {
21 0     0 1   my $self = shift;
22 0           $self->{'store'} = { @_ };
23              
24 0           $self->{'min_coin'} = shift @{ [ sort {$a <=> $b} keys %{$self->{'store'}} ] };
  0            
  0            
  0            
25             }
26              
27             sub change {
28 0     0 1   my $self = shift;
29 0           my $change = shift;
30              
31 0 0         return [] if $change <= 0;
32 0           $self->{'change'} = $change;
33 0           $self->_calculate;
34              
35 0           $self->{'coins'};
36             }
37              
38             sub _calculate {
39 0     0     my $self = shift;
40 0           my $limit = shift;
41              
42 0           my $store = $self->{'store'};
43 0           my $coin = $self->_max_coin($limit);
44              
45 0 0         if ($coin) {
46 0           push (@{$self->{'coins'}}, $coin);
  0            
47 0 0         return if $self->{'change'} == 0;
48 0           $self->_calculate($coin);
49             }else{
50             # give up if no way to make change
51 0           my $pop_coin = $self->_withdrawal;
52 0 0         return unless $pop_coin;
53 0           $self->_calculate($pop_coin - 1);
54             }
55             }
56              
57             sub _withdrawal {
58 0     0     my $self = shift;
59 0           my $store = $self->{'store'};
60 0           my $coins = $self->{'coins'};
61              
62 0           my $coin = pop @$coins;
63 0           $self->{'change'} += $coin;
64 0           $store->{$coin} += 1;
65 0 0 0       return if scalar @$coins == 0 && $coin == $self->{'min_coin'};
66 0           return $coin;
67             }
68              
69             sub balance {
70 0     0 1   my $self = shift;
71            
72 0           my %balance;
73 0           foreach (sort keys %{$self->{'store'}}) {
  0            
74 0 0         if ($self->{'store'}->{$_} != 0) {
75 0           $balance{$_} = $self->{'store'}->{$_};
76             }
77             }
78 0           \%balance;
79             }
80              
81             sub _max_coin {
82 0     0     my $self = shift;
83 0           my $limit = shift;
84 0           my $store = $self->{'store'};
85              
86 0           foreach my $coin (sort {$b <=> $a} keys %$store) {
  0            
87             # child coins shouldn't be bigger than his parent
88 0 0 0       next if $limit && $coin > $limit;
89 0 0         next unless $coin <= $self->{'change'};
90 0 0         next unless $store->{$coin} > 0;
91 0           $store->{$coin} -= 1;
92 0           $self->{'change'} -= $coin;
93 0 0 0       my @available_coins = grep { $_ if $_ < $coin && $store->{$_} > 0 } keys %$store;
  0            
94 0           $self->{'available_coins'} = \@available_coins;
95 0           return $coin;
96             }
97 0           return;
98             }
99              
100             sub add_coins {
101 0     0 1   my $self = shift;
102 0           my $coins = { @_ };
103 0           my $store = $self->{'store'};
104              
105 0           my %new_store;
106 0           foreach my $pair ($coins, $store) {
107 0           while (my ($key, $value) = each %$pair) {
108 0 0         if (exists $new_store{$key}) {
109 0           $new_store{$key} += $value;
110             }else{
111 0           $new_store{$key} = $value;
112             }
113             }
114             }
115 0           $self->reload(%new_store);
116             }
117              
118              
119             1;
120