File Coverage

lib/Games/Nonogram/Block.pm
Criterion Covered Total %
statement 69 75 92.0
branch 33 42 78.5
condition 7 9 77.7
subroutine 15 15 100.0
pod 12 12 100.0
total 136 153 88.8


line stmt bran cond sub pod time code
1             package Games::Nonogram::Block;
2            
3 5     5   23 use strict;
  5         10  
  5         150  
4 5     5   24 use warnings;
  5         7  
  5         119  
5 5     5   23 use base qw( Games::Nonogram::Base );
  5         7  
  5         5962  
6            
7             sub new {
8 19     19 1 68 my ($class, %options) = @_;
9            
10 19         190 my $self = bless {
11             id => $options{id},
12             length => $options{length},
13             line_size => $options{line_size},
14             left => 0,
15             right => 0,
16             forbidden => {},
17             }, $class;
18             }
19            
20 3     3 1 11 sub id { shift->{id} }
21            
22             sub clear {
23 34     34 1 41 my $self = shift;
24            
25 34         78 $self->{left} = $self->{right} = 0;
26 34         82 $self->{forbidden} = {};
27             }
28            
29             sub length {
30 634     634 1 792 my ($self, $value) = @_;
31            
32 634 50       1562 if ( defined $value ) {
33 0         0 $self->die_if_overflowed( $value );
34 0         0 $self->{length} = $value;
35             }
36 634         2369 $self->{length};
37             }
38            
39             sub left {
40 1036     1036 1 1392 my ($self, $value) = @_;
41            
42 1036 100       1990 if ( defined $value ) {
43 60         192 $self->die_if_overflowed( $value );
44 60         89 $self->{left} = $value;
45             }
46 1036         15536 $self->{left};
47             }
48            
49             sub right {
50 782     782 1 960 my ($self, $value) = @_;
51            
52 782 100       4234 if ( defined $value ) {
53 65         189 $self->die_if_overflowed( $value );
54 65         103 $self->{right} = $value;
55             }
56 782         3698 $self->{right};
57             }
58            
59             sub die_if_overflowed {
60 125     125 1 135 my ($self, $value) = @_;
61            
62 125 50       186 if ( $self->is_overflowed( $value ) ) {
63 0         0 my ( $package, $file, $line, $subr ) = caller(1);
64            
65 0         0 die <<"__MESSAGE__";
66             Block $$self{id} is broken. ($subr overflow: $value)
67             Unless you're trying to solve by brute force,
68             there may be something wrong in the puzzle data.
69             LEFT: $$self{left}
70             RIGHT: $$self{right}
71             LENGTH: $$self{length}
72             __MESSAGE__
73             }
74             }
75            
76             sub is_overflowed {
77 125     125 1 147 my ($self, $value) = @_;
78            
79 125 50 33     541 return 1 if $value > $self->{line_size} || $value < 1;
80            
81 125 100       341 my $left = $self->{left} or return;
82 91 100       244 my $right = $self->{right} or return;
83            
84 57 50       219 return 1 if $left > $right;
85             }
86            
87             sub cant_have {
88 105     105 1 121 my $self = shift;
89            
90 105 50       170 if ( @_ == 1 ) {
    0          
91 105         100 my $id = shift;
92 105         221 $self->{forbidden}->{$id} = 1;
93             }
94             elsif ( @_ ) {
95 0         0 $self->{forbidden}->{$_} = 1 for ( $self->range( @_ ) );
96             }
97            
98 105 100       373 if ( $self->length > 1 ) {
99 15 100       25 my @forbiddens = sort { $a <=> $b }
  334         708  
100 57 50       366 grep { $_ > $self->left && $_ < $self->right }
101 57         70 keys %{ $self->{forbidden} || {} };
102 57         127 push @forbiddens, $self->right + 1;
103            
104 57         105 my $prev = $self->left - 1;
105 57         88 foreach my $pos ( @forbiddens ) {
106 74 100       440 if ( $prev + 1 == $pos ) {
107 10         12 $prev = $pos;
108 10         14 next;
109             }
110 64 100       132 if ( ( $pos - 1 ) - ( $prev + 1 ) + 1 < $self->length ) {
111 3         14 $self->log(
112             'block ', $self->id, ': ',
113             ( $prev + 1 ), "-", ( $pos - 1 ),
114             " cannot have ", $self->length
115             );
116 3         23 $self->{forbidden}->{$_} = 1 for ( $prev + 1 .. $pos - 1 );
117             }
118 64         141 $prev = $pos;
119             }
120            
121 57         135 while( $self->{forbidden}->{ $self->left } ) {
122 5         13 $self->left( $self->left + 1 );
123             }
124 57         135 while( $self->{forbidden}->{ $self->right } ) {
125 11         25 $self->right( $self->right - 1 );
126             }
127             }
128             }
129            
130             sub might_have {
131 500     500 1 6253 my ($self, $id) = @_;
132            
133 500 100       2094 return 0 if $self->{forbidden}->{$id};
134            
135 278 100 100     443 ( $self->left > $id or $self->right < $id ) ? 0 : 1;
136             }
137            
138             sub must_have {
139 206     206 1 240 my ($self, $id) = @_;
140            
141 206 100       655 return 0 if $self->{forbidden}->{$id};
142            
143 145         248 my $offset = $self->length - 1;
144            
145 145 100 100     590 ( $self->left + $offset < $id
146             or
147             $self->right - $offset > $id ) ? 0 : 1;
148             }
149            
150             sub try {
151 86     86 1 103 my ($self, $from, $length) = @_;
152            
153 86 50       234 if ( $length > $self->length ) {
    100          
154 0         0 $self->cant_have( from => $from - 1, length => $length + 2 );
155             }
156             elsif ( $length == $self->length ) {
157 4         11 $self->cant_have( $from - 1 );
158 4         10 $self->cant_have( $from + $length );
159             }
160             }
161            
162             1;
163            
164             __END__