| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/local/bin/perl -w |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
package Games::Sudoku::OO::Set; |
|
4
|
|
|
|
|
|
|
|
|
5
|
2
|
|
|
2
|
|
10
|
use strict; |
|
|
2
|
|
|
|
|
4
|
|
|
|
2
|
|
|
|
|
2656
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
sub new { |
|
8
|
291
|
|
|
291
|
0
|
384
|
my $proto = shift; |
|
9
|
291
|
|
33
|
|
|
914
|
my $class = ref($proto) || $proto; |
|
10
|
291
|
|
|
|
|
911
|
my %args = (cells=>undef, possibles=>undef, @_); |
|
11
|
291
|
|
|
|
|
499
|
my $self = {}; |
|
12
|
291
|
100
|
|
|
|
699
|
if (defined $args{possibles}){ |
|
13
|
194
|
|
|
|
|
247
|
%{$self->{POSSIBLES}} = %{$args{possibles}}; |
|
|
194
|
|
|
|
|
1243
|
|
|
|
194
|
|
|
|
|
824
|
|
|
14
|
194
|
|
|
|
|
541
|
%{$self->{UNSOLVED_VALUES}} = %{$args{possibles}}; |
|
|
194
|
|
|
|
|
1322
|
|
|
|
194
|
|
|
|
|
642
|
|
|
15
|
|
|
|
|
|
|
}else { |
|
16
|
97
|
|
|
|
|
263
|
$self->{POSSIBLES} = {}; |
|
17
|
97
|
|
|
|
|
197
|
$self->{UNSOLVED_VALUES} = {}; |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
291
|
|
|
|
|
478
|
@{$self->{QUEUED_SOLVED_CELLS}}= (); |
|
|
291
|
|
|
|
|
725
|
|
|
21
|
291
|
|
|
|
|
530
|
$self->{SOLVED_CELLS} = {}; |
|
22
|
291
|
|
|
|
|
496
|
$self->{UNSOLVED_CELLS} = {}; |
|
23
|
|
|
|
|
|
|
|
|
24
|
291
|
|
|
|
|
565
|
foreach my $cell (@{$args{cells}}){ |
|
|
291
|
|
|
|
|
851
|
|
|
25
|
0
|
|
|
|
|
0
|
$self->addCell($cell); |
|
26
|
|
|
|
|
|
|
} |
|
27
|
291
|
|
|
|
|
946
|
bless ($self, $class); |
|
28
|
291
|
|
|
|
|
1036
|
return $self; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
sub addCell { |
|
32
|
2955
|
|
|
2955
|
0
|
4072
|
my $self = shift; |
|
33
|
2955
|
|
|
|
|
5094
|
my $cell = shift; |
|
34
|
2955
|
|
|
|
|
13080
|
$self->setBackReference($cell); |
|
35
|
2955
|
|
|
|
|
3695
|
push @{$self->{CELLS}}, $cell; |
|
|
2955
|
|
|
|
|
7147
|
|
|
36
|
2955
|
50
|
|
|
|
9998
|
if (defined $cell->getValue()){ |
|
37
|
0
|
|
|
|
|
0
|
$self->{SOLVED_CELLS}{$cell} = $cell; |
|
38
|
0
|
|
|
|
|
0
|
delete $self->{UNSOLVED_VALUES}{$cell->getValue()}; |
|
39
|
|
|
|
|
|
|
}else { |
|
40
|
2955
|
|
|
|
|
14484
|
$self->{UNSOLVED_CELLS}{$cell} = $cell; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub solve { |
|
45
|
1695
|
|
|
1695
|
0
|
2681
|
my $self = shift; |
|
46
|
1695
|
|
|
|
|
3699
|
$self->propagateSolved(); |
|
47
|
1695
|
|
|
|
|
4775
|
$self->findHasToBeCells(); |
|
48
|
1695
|
|
|
|
|
4825
|
return keys %{$self->{UNSOLVED_CELLS}}; |
|
|
1695
|
|
|
|
|
6852
|
|
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
sub notifySolved{ |
|
52
|
2955
|
|
|
2955
|
0
|
4116
|
my $self = shift; |
|
53
|
2955
|
|
|
|
|
4130
|
my $cell = shift; |
|
54
|
|
|
|
|
|
|
#print STDERR "notified that ". $cell->toStr ." was solved\n"; |
|
55
|
2955
|
|
|
|
|
11892
|
$self->{SOLVED_CELLS}{$cell} = 1; |
|
56
|
2955
|
|
|
|
|
7985
|
delete $self->{UNSOLVED_CELLS}{$cell}; |
|
57
|
2955
|
|
|
|
|
11471
|
delete $self->{UNSOLVED_VALUES}{$cell->getValue()}; |
|
58
|
2955
|
|
|
|
|
4285
|
push @{$self->{QUEUED_SOLVED_CELLS}}, $cell; |
|
|
2955
|
|
|
|
|
11304
|
|
|
59
|
|
|
|
|
|
|
} |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
sub propagateSolved { |
|
62
|
1695
|
|
|
1695
|
0
|
2387
|
my $self = shift; |
|
63
|
1695
|
|
|
|
|
2014
|
my @queue = @{$self->{QUEUED_SOLVED_CELLS}}; |
|
|
1695
|
|
|
|
|
5407
|
|
|
64
|
1695
|
100
|
|
|
|
5305
|
return unless (@queue); |
|
65
|
|
|
|
|
|
|
|
|
66
|
1088
|
|
|
|
|
1518
|
@{$self->{QUEUED_SOLVED_CELLS}} = (); |
|
|
1088
|
|
|
|
|
2842
|
|
|
67
|
|
|
|
|
|
|
|
|
68
|
1088
|
|
|
|
|
2246
|
foreach my $solved_cell (@queue){ |
|
69
|
|
|
|
|
|
|
#print "propagating :" . $solved_cell->toStr ."\n"; |
|
70
|
2951
|
|
|
|
|
3648
|
while( my (undef, $test_cell) = each (%{$self->{UNSOLVED_CELLS}})){ |
|
|
12587
|
|
|
|
|
48839
|
|
|
71
|
9636
|
|
|
|
|
35021
|
$test_cell->notPossible($solved_cell->getValue()); |
|
72
|
|
|
|
|
|
|
} |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
|
|
75
|
1088
|
|
|
|
|
2974
|
$self->checkConsistency(); |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub findHasToBeCells { |
|
79
|
1695
|
|
|
1695
|
0
|
2616
|
my $self = shift; |
|
80
|
1695
|
|
|
|
|
2475
|
my @unsolved_values = keys (%{$self->{UNSOLVED_VALUES}}); |
|
|
1695
|
|
|
|
|
19491
|
|
|
81
|
1695
|
|
|
|
|
4082
|
foreach my $value (@unsolved_values){ |
|
82
|
3091
|
|
|
|
|
4863
|
my @couldBe = (); |
|
83
|
3091
|
|
|
|
|
4132
|
foreach my $cell (values %{$self->{UNSOLVED_CELLS}}){ |
|
|
3091
|
|
|
|
|
10736
|
|
|
84
|
17052
|
100
|
|
|
|
51186
|
if ($cell->couldBe($value)){ |
|
85
|
10716
|
|
|
|
|
23071
|
push @couldBe, $cell; |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
} |
|
88
|
3091
|
100
|
|
|
|
11642
|
if (@couldBe == 1){ |
|
|
|
100
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
#print $couldBe[0]->toStr(). " has to be $value\n"; |
|
90
|
212
|
|
|
|
|
792
|
$couldBe[0]->setValue($value); |
|
91
|
|
|
|
|
|
|
}elsif(@couldBe){ |
|
92
|
2686
|
|
|
|
|
3496
|
my $saved_row; |
|
93
|
2686
|
|
|
|
|
3743
|
my $rows_equal=1; |
|
94
|
2686
|
|
|
|
|
6689
|
my $saved_column ; |
|
95
|
2686
|
|
|
|
|
3414
|
my $columns_equal=1; |
|
96
|
2686
|
|
|
|
|
2814
|
my $saved_square; |
|
97
|
2686
|
|
|
|
|
3465
|
my $squares_equal = 1; |
|
98
|
2686
|
|
|
|
|
4122
|
foreach my $cell (@couldBe){ |
|
99
|
|
|
|
|
|
|
#print $cell->toStr . "could be $value\n"; |
|
100
|
|
|
|
|
|
|
|
|
101
|
10504
|
|
|
|
|
35387
|
my $row = $cell->getRow(); |
|
102
|
10504
|
100
|
100
|
|
|
65984
|
if (defined $saved_row && ($saved_row != $row)){ |
|
103
|
|
|
|
|
|
|
# print $cell->toStr() . "not in the same row\n"; |
|
104
|
1896
|
|
|
|
|
2727
|
$rows_equal = 0; |
|
105
|
|
|
|
|
|
|
} |
|
106
|
10504
|
|
|
|
|
14054
|
$saved_row = $row; |
|
107
|
|
|
|
|
|
|
|
|
108
|
10504
|
|
|
|
|
27737
|
my $column = $cell->getColumn(); |
|
109
|
10504
|
100
|
100
|
|
|
58597
|
if (defined $saved_column && ($saved_column != $column)){ |
|
110
|
|
|
|
|
|
|
# print $cell->toStr() . "not in the same column\n"; |
|
111
|
6968
|
|
|
|
|
10082
|
$columns_equal = 0; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
10504
|
|
|
|
|
13600
|
$saved_column = $column; |
|
114
|
|
|
|
|
|
|
|
|
115
|
10504
|
|
|
|
|
36281
|
my $square = $cell->getSquare(); |
|
116
|
10504
|
100
|
100
|
|
|
54660
|
if (defined $saved_square && ($saved_square != $square)){ |
|
117
|
|
|
|
|
|
|
#print $cell->toStr() . "not in the same square\n"; |
|
118
|
3805
|
|
|
|
|
5198
|
$squares_equal = 0; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
10504
|
|
|
|
|
22516
|
$saved_square = $square; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
2686
|
100
|
100
|
|
|
10439
|
if ($squares_equal && $saved_square != $self){ |
|
123
|
|
|
|
|
|
|
#print "rest of square can't be $value\n"; |
|
124
|
244
|
|
|
|
|
611
|
$saved_square->setCantBeCells($value,@couldBe); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
2686
|
100
|
66
|
|
|
7267
|
if ($columns_equal && $saved_column != $self){ |
|
127
|
|
|
|
|
|
|
#print "rest of column can't be $value\n"; |
|
128
|
308
|
|
|
|
|
785
|
$saved_column->setCantBeCells($value,@couldBe); |
|
129
|
|
|
|
|
|
|
} |
|
130
|
2686
|
100
|
100
|
|
|
21605
|
if ($rows_equal && $saved_row != $self){ |
|
131
|
|
|
|
|
|
|
#print "rest of row can't be $value\n"; |
|
132
|
219
|
|
|
|
|
559
|
$saved_row->setCantBeCells($value,@couldBe); |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
} |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub setCantBeCells { |
|
139
|
771
|
|
|
771
|
0
|
1059
|
my $self = shift; |
|
140
|
771
|
|
|
|
|
1054
|
my $value = shift; |
|
141
|
771
|
|
|
|
|
1542
|
my @has_to_be = @_; |
|
142
|
771
|
|
|
|
|
906
|
foreach my $cell (values %{$self->{UNSOLVED_CELLS}}){ |
|
|
771
|
|
|
|
|
5336
|
|
|
143
|
3837
|
|
|
|
|
7509
|
my $duplicate = 0; |
|
144
|
|
|
|
|
|
|
#print "checking if " . $cell->toStr() . "is a has to be\n"; |
|
145
|
3837
|
|
|
|
|
6284
|
foreach my $has_to_be (@has_to_be){ |
|
146
|
8502
|
100
|
|
|
|
22416
|
if ($cell == $has_to_be){ |
|
147
|
1673
|
|
|
|
|
3345
|
$duplicate++; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
} |
|
150
|
3837
|
100
|
|
|
|
11067
|
unless ($duplicate){ |
|
151
|
|
|
|
|
|
|
#print $cell->toStr . "can't be $value\n"; |
|
152
|
2164
|
|
|
|
|
7201
|
$cell->notPossible($value); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
} |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub checkConsistency { |
|
158
|
1088
|
|
|
1088
|
0
|
1636
|
my $self = shift; |
|
159
|
1088
|
|
|
|
|
1307
|
my %seen_values; |
|
160
|
1088
|
|
|
|
|
1249
|
foreach my $cell (@{$self->{CELLS}}){ |
|
|
1088
|
|
|
|
|
6256
|
|
|
161
|
11850
|
100
|
|
|
|
30097
|
if(defined $cell->getValue()){ |
|
162
|
8581
|
100
|
|
|
|
26938
|
if($seen_values{$cell->getValue()}){ |
|
163
|
219
|
|
|
|
|
583
|
print "INCONSISTENT!!!". $cell->toStr(). "\n"; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
8581
|
|
|
|
|
32692
|
$seen_values{$cell->getValue()}++; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
} |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
1; |