| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Games::Sudoku::PatternSolver::Patterns; |
|
2
|
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
54
|
use strict; |
|
|
4
|
|
|
|
|
12
|
|
|
|
4
|
|
|
|
|
160
|
|
|
4
|
4
|
|
|
4
|
|
23
|
use warnings; |
|
|
4
|
|
|
|
|
11
|
|
|
|
4
|
|
|
|
|
539
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
require 5.06.0; |
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our @ISA = qw( Exporter ); |
|
9
|
|
|
|
|
|
|
our @EXPORT_OK = qw( init_patterns init_fields build_groups print_grid_from_vector get_intersections field_coordinates ); |
|
10
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
|
11
|
|
|
|
|
|
|
'all' => \@EXPORT_OK, |
|
12
|
|
|
|
|
|
|
); |
|
13
|
|
|
|
|
|
|
|
|
14
|
4
|
|
|
4
|
|
522
|
use Bit::Vector; |
|
|
4
|
|
|
|
|
1354
|
|
|
|
4
|
|
|
|
|
277
|
|
|
15
|
4
|
|
|
4
|
|
38
|
use Time::HiRes; |
|
|
4
|
|
|
|
|
7
|
|
|
|
4
|
|
|
|
|
34
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
my $VERBOSE = 0; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $file_name = 'patterns_9x9.bin'; |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
##################################### |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
my (%pos_to_offset, %offset_to_pos); |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
{ |
|
26
|
|
|
|
|
|
|
my (%pattern_vectors_by_field, @all_patterns); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub init_patterns { |
|
29
|
|
|
|
|
|
|
# load from file or ask whether to create the patterns file |
|
30
|
|
|
|
|
|
|
|
|
31
|
5
|
100
|
|
5
|
0
|
27
|
return (\%pattern_vectors_by_field, \@all_patterns) if %pattern_vectors_by_field; |
|
32
|
|
|
|
|
|
|
|
|
33
|
4
|
|
|
|
|
10
|
my $module_path = __FILE__; |
|
34
|
4
|
|
|
|
|
92
|
$module_path =~ s|[^/]*$||; |
|
35
|
|
|
|
|
|
|
|
|
36
|
4
|
|
|
|
|
11
|
my $existing_file; |
|
37
|
4
|
50
|
|
|
|
213
|
if (-f './' . $file_name) { |
|
|
|
50
|
|
|
|
|
|
|
38
|
0
|
|
|
|
|
0
|
$existing_file = './' . $file_name; |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
} elsif (-f $module_path . $file_name) { |
|
41
|
4
|
|
|
|
|
17
|
$existing_file = $module_path . $file_name; |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
4
|
50
|
|
|
|
12
|
if ($existing_file) { |
|
45
|
4
|
|
|
|
|
31
|
$file_name = $existing_file; |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
} else { |
|
48
|
0
|
|
|
|
|
0
|
print "No pattern file '$file_name' exists in '$module_path' or in the current directory.\n"; |
|
49
|
|
|
|
|
|
|
|
|
50
|
0
|
0
|
|
|
|
0
|
if (-w $module_path) { |
|
51
|
0
|
|
|
|
|
0
|
$file_name = $module_path . 'symbol_patterns.bin'; |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
} else { |
|
54
|
0
|
0
|
|
|
|
0
|
my $elevated = ($^O =~ /Win/i ? 'administrator' : 'sudo'); |
|
55
|
|
|
|
|
|
|
|
|
56
|
0
|
|
|
|
|
0
|
print "Pls. consider to exit now and restart the program as $elevated, to have the file created in '$module_path' once and for all.\n"; |
|
57
|
0
|
|
|
|
|
0
|
print "Or proceed to have it created in the current directory.\n"; |
|
58
|
0
|
|
|
|
|
0
|
$file_name = './' . 'symbol_patterns.bin'; |
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
0
|
|
|
|
|
0
|
print "\nCreating the patterns should take < 1 minute and takes 0.5MB space.\nProceed? [Yn]:"; |
|
62
|
0
|
|
|
|
|
0
|
my $answer = ; |
|
63
|
0
|
0
|
|
|
|
0
|
exit 0 unless $answer =~ /Y/; |
|
64
|
|
|
|
|
|
|
|
|
65
|
0
|
|
|
|
|
0
|
my $t1 = Time::HiRes::time(); |
|
66
|
0
|
|
|
|
|
0
|
my $fields = init_fields(); |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# prevent an annoying and false OOM message, happening on windows when Ctrl-C is signalled while executing a nested loop |
|
69
|
0
|
|
|
|
|
0
|
my $old_handler = $SIG{'INT'}; |
|
70
|
|
|
|
|
|
|
$SIG{'INT'} = sub { |
|
71
|
0
|
|
|
0
|
|
0
|
print "Exit on user request.\n"; |
|
72
|
0
|
|
|
|
|
0
|
CORE::exit(0); |
|
73
|
0
|
|
|
|
|
0
|
}; |
|
74
|
|
|
|
|
|
|
|
|
75
|
0
|
0
|
|
|
|
0
|
open my $Pattern_Handle, '>', $file_name or die $!; |
|
76
|
0
|
|
|
|
|
0
|
binmode $Pattern_Handle; |
|
77
|
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
0
|
my $written_count = 0; |
|
79
|
0
|
|
|
|
|
0
|
create_patterns($Pattern_Handle, 0, 0, Bit::Vector->new(81), Bit::Vector->new(81), \$written_count, $fields); |
|
80
|
0
|
|
|
|
|
0
|
close $Pattern_Handle; |
|
81
|
|
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
0
|
$SIG{'INT'} = $old_handler; |
|
83
|
0
|
|
|
|
|
0
|
printf("Creating and storing %d patterns took %.2f secs.\n", $written_count, Time::HiRes::time() - $t1); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
|
|
86
|
4
|
|
|
|
|
59
|
my $file_size = -s $file_name; |
|
87
|
4
|
50
|
33
|
|
|
59
|
unless ($file_size and ! ($file_size % 46656)) { |
|
88
|
0
|
|
|
|
|
0
|
die "$file_name seems corrupted."; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
4
|
|
|
|
|
15
|
my $bytes_per_pattern = $file_size / 46656; |
|
92
|
|
|
|
|
|
|
|
|
93
|
4
|
50
|
|
|
|
192
|
open my $Bin_File, '<', $file_name or die "Could not open the patterns binary at '$file_name':\n" . $!; |
|
94
|
4
|
|
|
|
|
16
|
binmode $Bin_File; |
|
95
|
4
|
|
|
|
|
10
|
my $load_count = 0; |
|
96
|
4
|
|
|
|
|
8
|
my $buffer = ''; |
|
97
|
4
|
|
|
|
|
11
|
my $bytes = 0; |
|
98
|
|
|
|
|
|
|
|
|
99
|
4
|
|
|
|
|
57
|
while ($bytes = sysread $Bin_File, $buffer, $bytes_per_pattern) { |
|
100
|
186624
|
50
|
|
|
|
405644
|
$bytes == $bytes_per_pattern or die "Unexpected number of $bytes bytes read (expected $bytes_per_pattern) after $load_count Patterns loaded.\n"; |
|
101
|
186624
|
|
|
|
|
620449
|
my $vector = Bit::Vector->new(81); |
|
102
|
186624
|
|
|
|
|
498362
|
$vector->Block_Store($buffer); |
|
103
|
|
|
|
|
|
|
|
|
104
|
186624
|
|
|
|
|
515066
|
my @fields = $vector->Index_List_Read(); |
|
105
|
186624
|
|
|
|
|
330240
|
foreach my $field_index (@fields) { |
|
106
|
1679616
|
|
|
|
|
2313400
|
push @{$pattern_vectors_by_field{$field_index}}, $vector; |
|
|
1679616
|
|
|
|
|
3751492
|
|
|
107
|
|
|
|
|
|
|
} |
|
108
|
186624
|
|
|
|
|
324690
|
push @all_patterns, $vector; |
|
109
|
186624
|
|
|
|
|
1480443
|
$load_count++; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
4
|
|
|
|
|
96
|
close $Bin_File; |
|
112
|
|
|
|
|
|
|
|
|
113
|
4
|
50
|
|
|
|
74
|
unless ($load_count == 46656) { |
|
114
|
0
|
|
|
|
|
0
|
die "Expected to load 46656 pattern vectors from '$file_name' (got $load_count instead).\n"; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
4
|
50
|
|
|
|
46
|
print("$load_count patterns loaded from $file_name\n") if $VERBOSE; |
|
118
|
|
|
|
|
|
|
|
|
119
|
4
|
|
|
|
|
54
|
return (\%pattern_vectors_by_field, \@all_patterns) |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
} |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# a recursive function that creates all possible distribution patterns and writes them to a binary file |
|
124
|
|
|
|
|
|
|
sub create_patterns { |
|
125
|
0
|
|
|
0
|
0
|
0
|
my ($file_hdl, $start_index, $positioned_count, $positioned_vector, $coverage_vector, $written_count, $fields) = @_; |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# once we end up with an empty first row, we're finished |
|
128
|
0
|
0
|
0
|
|
|
0
|
return 0 if ($positioned_count == 0 && $start_index > 8); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# the return value signals to the former/upper call whether proceeding with the recursion or to return |
|
131
|
0
|
|
|
|
|
0
|
my $return_value = 1; |
|
132
|
|
|
|
|
|
|
# find the next unobstructed cell, starting with the given index |
|
133
|
0
|
|
|
|
|
0
|
for (my $current_index = $start_index; $current_index <= 80; $current_index++) { |
|
134
|
0
|
0
|
|
|
|
0
|
next if $coverage_vector->bit_test($current_index); |
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
# a free cell was found - put it on the grid |
|
137
|
0
|
|
|
|
|
0
|
$positioned_vector->Bit_On($current_index); |
|
138
|
0
|
|
|
|
|
0
|
$positioned_count++; |
|
139
|
|
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
0
|
if ($positioned_count == 9) { |
|
141
|
|
|
|
|
|
|
# with 9 occupied cells the pattern is complete |
|
142
|
0
|
|
|
|
|
0
|
save_pattern($file_hdl, $positioned_vector); |
|
143
|
0
|
|
|
|
|
0
|
$$written_count++; |
|
144
|
0
|
0
|
0
|
|
|
0
|
if ($VERBOSE && ! ($$written_count % 1000)) { |
|
145
|
0
|
|
|
|
|
0
|
print $$written_count, ": "; |
|
146
|
0
|
|
|
|
|
0
|
print_grid_from_vector($positioned_vector); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
} else { |
|
150
|
0
|
|
|
|
|
0
|
my $combined_vector = Bit::Vector->new(81); |
|
151
|
0
|
|
|
|
|
0
|
$combined_vector->Or($coverage_vector, $fields->[$current_index]{covers}); |
|
152
|
|
|
|
|
|
|
|
|
153
|
0
|
0
|
|
|
|
0
|
$return_value = create_patterns($file_hdl, $current_index+1, $positioned_count, $positioned_vector, $combined_vector, $written_count, $fields) |
|
154
|
|
|
|
|
|
|
or last; |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
0
|
|
|
|
|
0
|
$positioned_vector->Bit_Off($current_index); |
|
158
|
0
|
|
|
|
|
0
|
$positioned_count--; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
0
|
return $return_value |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub print_grid_from_vector { |
|
165
|
0
|
|
|
0
|
0
|
0
|
my ($vector, $symbol) = @_; |
|
166
|
0
|
0
|
|
|
|
0
|
$symbol = 'X' unless defined($symbol); |
|
167
|
|
|
|
|
|
|
|
|
168
|
0
|
|
|
|
|
0
|
my $bits = $vector->to_Bin(); |
|
169
|
0
|
|
|
|
|
0
|
$bits =~ s/0/ /g; |
|
170
|
0
|
|
|
|
|
0
|
$bits =~ s/1/$symbol/g; |
|
171
|
0
|
|
|
|
|
0
|
my @bits = reverse split //, $bits; |
|
172
|
|
|
|
|
|
|
|
|
173
|
0
|
|
|
|
|
0
|
print "\n-----------------\n"; |
|
174
|
0
|
|
|
|
|
0
|
while (my @row = splice @bits, 0, 9) { |
|
175
|
0
|
|
|
|
|
0
|
print "@row\n"; |
|
176
|
|
|
|
|
|
|
} |
|
177
|
0
|
|
|
|
|
0
|
print "-----------------\n"; |
|
178
|
|
|
|
|
|
|
} |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
sub save_pattern { |
|
181
|
0
|
|
|
0
|
0
|
0
|
my ($Out_File, $vector) = @_; |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# default string length for 81 bits is 12 bytes on Windows (3 words), 16 bytes on linux (2 words) |
|
184
|
|
|
|
|
|
|
# we unify by cutting to the minimum |
|
185
|
0
|
|
|
|
|
0
|
my $buffer = substr($vector->Block_Read(), 0, 11); |
|
186
|
0
|
|
|
|
|
0
|
my $written = syswrite($Out_File, $buffer); |
|
187
|
0
|
0
|
|
|
|
0
|
unless ($written == 11) { |
|
188
|
0
|
|
|
|
|
0
|
die "Unexpected number of $written bytes written (expected 11)\n"; |
|
189
|
|
|
|
|
|
|
} |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub init_fields { |
|
193
|
|
|
|
|
|
|
# return arrayref with 81 field hashes, field->{covers} has Bit::Vector with constraint coverage field indexes set (row, column and block in one) |
|
194
|
|
|
|
|
|
|
|
|
195
|
4
|
|
|
4
|
0
|
11
|
my $offset = 0; |
|
196
|
|
|
|
|
|
|
|
|
197
|
4
|
50
|
|
|
|
22
|
unless (%pos_to_offset) { |
|
198
|
4
|
|
|
|
|
18
|
foreach my $row ('A' .. 'I') { |
|
199
|
36
|
|
|
|
|
98
|
foreach my $column ('1' .. '9') { |
|
200
|
324
|
|
|
|
|
851
|
$pos_to_offset{$row . $column} = $offset++; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
} |
|
203
|
4
|
|
|
|
|
292
|
%offset_to_pos = reverse %pos_to_offset; |
|
204
|
|
|
|
|
|
|
} |
|
205
|
|
|
|
|
|
|
|
|
206
|
4
|
|
|
|
|
174
|
my %block_ranges = ( |
|
207
|
|
|
|
|
|
|
A => ['A' .. 'C'], |
|
208
|
|
|
|
|
|
|
B => ['A' .. 'C'], |
|
209
|
|
|
|
|
|
|
C => ['A' .. 'C'], |
|
210
|
|
|
|
|
|
|
D => ['D' .. 'F'], |
|
211
|
|
|
|
|
|
|
E => ['D' .. 'F'], |
|
212
|
|
|
|
|
|
|
F => ['D' .. 'F'], |
|
213
|
|
|
|
|
|
|
G => ['G' .. 'I'], |
|
214
|
|
|
|
|
|
|
H => ['G' .. 'I'], |
|
215
|
|
|
|
|
|
|
I => ['G' .. 'I'], |
|
216
|
|
|
|
|
|
|
1 => ['1' .. '3'], |
|
217
|
|
|
|
|
|
|
2 => ['1' .. '3'], |
|
218
|
|
|
|
|
|
|
3 => ['1' .. '3'], |
|
219
|
|
|
|
|
|
|
4 => ['4' .. '6'], |
|
220
|
|
|
|
|
|
|
5 => ['4' .. '6'], |
|
221
|
|
|
|
|
|
|
6 => ['4' .. '6'], |
|
222
|
|
|
|
|
|
|
7 => ['7' .. '9'], |
|
223
|
|
|
|
|
|
|
8 => ['7' .. '9'], |
|
224
|
|
|
|
|
|
|
9 => ['7' .. '9'], |
|
225
|
|
|
|
|
|
|
); |
|
226
|
|
|
|
|
|
|
|
|
227
|
4
|
|
|
|
|
12
|
my @fields = (); |
|
228
|
4
|
|
|
|
|
9
|
$offset = 0; |
|
229
|
4
|
|
|
|
|
15
|
foreach my $row ('A' .. 'I') { |
|
230
|
36
|
|
|
|
|
103
|
foreach my $column ('1' .. '9') { |
|
231
|
324
|
|
|
|
|
926
|
push @fields, new_sudo_field($row, $column, \%pos_to_offset, \%block_ranges); |
|
232
|
324
|
|
|
|
|
976
|
$offset++; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
return \@fields |
|
237
|
4
|
|
|
|
|
107
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub field_coordinates { |
|
240
|
0
|
|
|
0
|
0
|
0
|
return $offset_to_pos{$_[0]} |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
{ |
|
244
|
|
|
|
|
|
|
# used in logic mode only |
|
245
|
|
|
|
|
|
|
my @groups; |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# returns an array of 27 arrays, each with the 9 indexes for any region (row, column or box) |
|
248
|
|
|
|
|
|
|
sub build_groups { |
|
249
|
4
|
|
|
4
|
|
10682
|
use integer; |
|
|
4
|
|
|
|
|
71
|
|
|
|
4
|
|
|
|
|
32
|
|
|
250
|
|
|
|
|
|
|
|
|
251
|
4
|
50
|
|
4
|
0
|
29
|
return \@groups if @groups; |
|
252
|
|
|
|
|
|
|
|
|
253
|
4
|
|
|
|
|
114
|
foreach my $i (0..80) { |
|
254
|
324
|
|
|
|
|
537
|
my $ri = ($i / 9); |
|
255
|
324
|
|
|
|
|
546
|
push @{$groups[$ri]}, $i; |
|
|
324
|
|
|
|
|
648
|
|
|
256
|
324
|
|
|
|
|
607
|
my $ci = $i % 9 + 9; |
|
257
|
324
|
|
|
|
|
479
|
push @{$groups[$ci]}, $i; |
|
|
324
|
|
|
|
|
729
|
|
|
258
|
324
|
|
|
|
|
612
|
my $bi = 3 * ($i / 27) + ($i % 9 / 3) + 18; |
|
259
|
324
|
|
|
|
|
505
|
push @{$groups[$bi]}, $i; |
|
|
324
|
|
|
|
|
732
|
|
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
return \@groups |
|
263
|
4
|
|
|
|
|
24
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
my @intersections; |
|
266
|
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# returns an array of 54 arrays, each with 3 defining vectors of size 81: |
|
268
|
|
|
|
|
|
|
# [ |
|
269
|
|
|
|
|
|
|
# [intersection of a box with a row or column], |
|
270
|
|
|
|
|
|
|
# [excluded subset of same box], |
|
271
|
|
|
|
|
|
|
# [excluded subset of the row or column] |
|
272
|
|
|
|
|
|
|
# ] |
|
273
|
|
|
|
|
|
|
sub get_intersections { |
|
274
|
4
|
|
|
4
|
|
806
|
use integer; |
|
|
4
|
|
|
|
|
10
|
|
|
|
4
|
|
|
|
|
19
|
|
|
275
|
|
|
|
|
|
|
|
|
276
|
4
|
50
|
|
4
|
0
|
37
|
return \@intersections if @intersections; |
|
277
|
|
|
|
|
|
|
|
|
278
|
4
|
50
|
|
|
|
29
|
@groups or build_groups(); |
|
279
|
|
|
|
|
|
|
|
|
280
|
4
|
|
|
|
|
19
|
foreach my $i (0..8) { |
|
281
|
|
|
|
|
|
|
# 1 box |
|
282
|
36
|
|
|
|
|
140
|
my $box_vector = Bit::Vector->new(81); |
|
283
|
36
|
|
|
|
|
72
|
$box_vector->Index_List_Store(@{$groups[$i + 18]}); |
|
|
36
|
|
|
|
|
144
|
|
|
284
|
|
|
|
|
|
|
# 3 intersecting rows |
|
285
|
36
|
|
|
|
|
74
|
my $row_index = ($i / 3) * 3; |
|
286
|
36
|
|
|
|
|
124
|
my @rows = @groups[$row_index, $row_index + 1, $row_index + 2]; |
|
287
|
|
|
|
|
|
|
# 3 intersecting columns |
|
288
|
36
|
|
|
|
|
82
|
my $column_index = ($i * 3 % 9) + 9; |
|
289
|
36
|
|
|
|
|
88
|
my @columns = @groups[$column_index, $column_index + 1, $column_index + 2]; |
|
290
|
|
|
|
|
|
|
|
|
291
|
36
|
|
|
|
|
85
|
foreach my $line (@rows, @columns) { |
|
292
|
216
|
|
|
|
|
592
|
my $line_vector = Bit::Vector->new(81); |
|
293
|
216
|
|
|
|
|
722
|
$line_vector->Index_List_Store(@$line); |
|
294
|
|
|
|
|
|
|
|
|
295
|
216
|
|
|
|
|
3697
|
my $intersection_vector = Bit::Vector->new(81); |
|
296
|
216
|
|
|
|
|
710
|
$intersection_vector->Intersection($box_vector, $line_vector); |
|
297
|
216
|
|
|
|
|
639
|
my $negation_vector_1 = Bit::Vector->new(81); |
|
298
|
216
|
|
|
|
|
668
|
$negation_vector_1->Difference($box_vector, $intersection_vector); |
|
299
|
216
|
|
|
|
|
676
|
my $negation_vector_2 = Bit::Vector->new(81); |
|
300
|
216
|
|
|
|
|
655
|
$negation_vector_2->Difference($line_vector, $intersection_vector); |
|
301
|
|
|
|
|
|
|
|
|
302
|
216
|
|
|
|
|
1151
|
push @intersections, [$intersection_vector, $negation_vector_1, $negation_vector_2]; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
|
|
|
|
|
|
} |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
return \@intersections |
|
307
|
4
|
|
|
|
|
24
|
} |
|
308
|
|
|
|
|
|
|
} |
|
309
|
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
##################################################### |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
sub new_sudo_field { |
|
313
|
324
|
|
|
324
|
0
|
997
|
my ($row, $col, $position_to_offset, $block_ranges) = @_; |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
return { |
|
316
|
324
|
|
|
|
|
1146
|
offset => $position_to_offset->{$row . $col}, |
|
317
|
|
|
|
|
|
|
covers => _get_covered_cells_vector($row, $col, $position_to_offset, $block_ranges), |
|
318
|
|
|
|
|
|
|
candidates => {}, |
|
319
|
|
|
|
|
|
|
value => undef, |
|
320
|
|
|
|
|
|
|
} |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
sub _get_covered_cells_vector { |
|
324
|
324
|
|
|
324
|
|
705
|
my ($row, $col, $position_to_offset, $block_ranges) = @_; |
|
325
|
|
|
|
|
|
|
|
|
326
|
324
|
|
|
|
|
655
|
my %conflicts = (); |
|
327
|
324
|
|
|
|
|
1017
|
foreach my $ri ('A' .. 'I') { |
|
328
|
2916
|
|
|
|
|
8126
|
$conflicts{$ri . $col} = $position_to_offset->{$ri . $col}; |
|
329
|
|
|
|
|
|
|
} |
|
330
|
324
|
|
|
|
|
787
|
foreach my $ci ('1' .. '9') { |
|
331
|
2916
|
|
|
|
|
11284
|
$conflicts{$row . $ci} = $position_to_offset->{$row . $ci}; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
324
|
|
|
|
|
566
|
foreach my $ri (@{$block_ranges->{$row}}) { |
|
|
324
|
|
|
|
|
787
|
|
|
334
|
972
|
|
|
|
|
1554
|
foreach my $ci (@{$block_ranges->{$col}}) { |
|
|
972
|
|
|
|
|
2021
|
|
|
335
|
2916
|
|
|
|
|
7939
|
$conflicts{$ri . $ci} = $position_to_offset->{$ri . $ci}; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
} |
|
338
|
|
|
|
|
|
|
|
|
339
|
324
|
|
|
|
|
1739
|
my $covered_fields_vector = Bit::Vector->new(81); |
|
340
|
324
|
|
|
|
|
1690
|
$covered_fields_vector->Index_List_Store(sort {$a <=> $b} values %conflicts); |
|
|
22241
|
|
|
|
|
36344
|
|
|
341
|
|
|
|
|
|
|
|
|
342
|
324
|
|
|
|
|
3708
|
return $covered_fields_vector |
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
1 |
|
346
|
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
__END__ |