File Coverage

blib/lib/Games/Puzzles/SendMoreMoney.pm
Criterion Covered Total %
statement 61 72 84.7
branch 11 24 45.8
condition 1 3 33.3
subroutine 11 11 100.0
pod 0 6 0.0
total 84 116 72.4


line stmt bran cond sub pod time code
1             ###########################################
2             # Games::Puzzles::SendMoreMoney
3             # 2005, Mike Schilli
4             ###########################################
5              
6             ###########################################
7             package Games::Puzzles::SendMoreMoney;
8             ###########################################
9              
10 1     1   20394 use strict;
  1         1  
  1         34  
11 1     1   4 use warnings;
  1         2  
  1         25  
12 1     1   714 use Algorithm::FastPermute;
  1         766  
  1         56  
13 1     1   1262 use Log::Log4perl qw(:easy);
  1         52570  
  1         6  
14              
15             our $VERSION = "0.03";
16             our $STOP_SOLVER = 0;
17              
18             ###########################################
19             sub new {
20             ###########################################
21 1     1 0 28 my($class, %options) = @_;
22              
23 1         11 my $self = {
24             puzzle => undef,
25             permutator => undef,
26             search_space => undef,
27             validator => undef,
28             reporter => undef,
29             values => undef,
30             %options,
31             };
32              
33 1 50       6 LOGDIE "Mandatory parameter puzzle missing"
34             unless defined $self->{puzzle};
35              
36 1         16 ($self->{left}, $self->{right}) = split /\s*=\s*/, $self->{puzzle};
37              
38 1 50       5 LOGDIE "Puzzle not an equation: '$self->{puzzle}'"
39             unless defined $self->{right};
40              
41 1         4 bless $self, $class;
42              
43 1         11 $self->{chars} = [$self->chars_extract($self->{puzzle})];
44            
45 1         5 return $self;
46             }
47              
48             ###########################################
49             sub tryout {
50             ###########################################
51 1     1 0 3 my($self, $try) = @_;
52              
53 1 50       7 unless($self->{seen}->{join "", values %$try}++) {
54 1 50       6 if($self->is_valid($try)) {
55 1 50       4 if($self->evaluate($try)) {
56 1 50       7 $self->{reporter}->($try) if defined $self->{reporter};
57 1         4 push @{$self->{results}}, $try;
  1         2  
58 1         3 return 1;
59             }
60             }
61             }
62              
63 0         0 return 0;
64             }
65              
66             ###########################################
67             sub solve {
68             ###########################################
69 1     1 0 8 my($self) = @_;
70              
71 1         2 my %try;
72 1         4 $self->{results} = ();
73              
74 1         3 $self->{seen} = {};
75 1         3 $self->{results} = [];
76              
77 1 50       6 if($self->{permutator}) {
78 0         0 while(my $perm = $self->{permutator}->next()) {
79 0         0 DEBUG "Permutation: @$perm";
80 0         0 @try{@{$self->{chars}}} = @$perm;
  0         0  
81 0         0 $self->tryout(\%try);
82 0 0       0 last if $STOP_SOLVER;
83             }
84             } else {
85 1         2 my @array = @{$self->{values}};
  1         4  
86 1         3 eval {
87             permute {
88 1     1   12 DEBUG "Permutation: @array";
89 1         18 @try{@{$self->{chars}}} = @array;
  1         5  
90 1         4 $self->tryout(\%try);
91 1 50       12 die "STOP_SOLVER_SET" if $STOP_SOLVER;
92 1         14 } @array;
93             };
94 1 50 33     17 if($@ and $@ !~ /STOP_SOLVER_SET/) {
95 0         0 die "Error is '$@'";
96             }
97             }
98              
99 1         4 return $self->{results};
100             }
101              
102             ###########################################
103             sub is_valid {
104             ###########################################
105 1     1 0 2 my($self, $try) = @_;
106              
107 1 50       4 if(defined $self->{validator}) {
108 0         0 return $self->{validator}->($try);
109             }
110              
111 1         4 return 1;
112             }
113              
114             ###########################################
115             sub evaluate {
116             ###########################################
117 1     1 0 2 my($self, $try) = @_;
118              
119 1         11 (my $left_tmp = $self->{left}) =~ s/([a-zA-Z])/$try->{$1}/g;
120 1         6 (my $right_tmp = $self->{right}) =~ s/([a-zA-Z])/$try->{$1}/g;
121            
122             # Remove pseudo-octal values
123 1         2 $left_tmp =~ s/\b0+([1-9])/$1/g;
124 1         3 $right_tmp =~ s/\b0+([1-9])/$1/g;
125              
126 1 50       98 if(eval $left_tmp == eval $right_tmp) {
127 1         6 INFO "$left_tmp == $right_tmp";
128 1         12 return 1;
129             }
130              
131 0         0 DEBUG "$left_tmp != $right_tmp";
132 0         0 return 0;
133             }
134              
135             ###########################################
136             sub chars_extract {
137             ###########################################
138 1     1 0 4 my($self, $string) = @_;
139              
140 1         2 my %chars = ();
141              
142 1         7 while($string =~ /([a-zA-Z])/g) {
143 2         11 $chars{$1}++;
144             }
145              
146 1         6 return keys %chars;
147             }
148              
149             1;
150              
151             __END__