aboutsummaryrefslogtreecommitdiff
path: root/challenge-086
diff options
context:
space:
mode:
authorAbigail <abigail@abigail.be>2020-11-11 19:02:41 +0100
committerAbigail <abigail@abigail.be>2020-11-11 19:13:01 +0100
commite0679ea4a927d6ca49cb7b6605290ac3d3dcefb7 (patch)
treef80b0594072988c6600670525ab99bad5e623581 /challenge-086
parentfa9d7d5527b5ceee775c3ee7e50163781faa7039 (diff)
downloadperlweeklychallenge-club-e0679ea4a927d6ca49cb7b6605290ac3d3dcefb7.tar.gz
perlweeklychallenge-club-e0679ea4a927d6ca49cb7b6605290ac3d3dcefb7.tar.bz2
perlweeklychallenge-club-e0679ea4a927d6ca49cb7b6605290ac3d3dcefb7.zip
Use a bit field to keep track of possibilities.
Diffstat (limited to 'challenge-086')
-rw-r--r--challenge-086/abigail/perl/ch-2.pl43
1 files changed, 28 insertions, 15 deletions
diff --git a/challenge-086/abigail/perl/ch-2.pl b/challenge-086/abigail/perl/ch-2.pl
index 2fb2e79a50..4b5c3146f7 100644
--- a/challenge-086/abigail/perl/ch-2.pl
+++ b/challenge-086/abigail/perl/ch-2.pl
@@ -70,6 +70,14 @@ die "Too many different clues!" if $clue_count > $SIZE;
die "Not enough different clues" if $clue_count < $SIZE - 1;
#
+# Can't have a size which exceeds the number of bits in an integer.
+# Typically, bit size will be 32, 64 or 128.
+# This isn't much of a restriction, as a typical 32x32 sudoku will take
+# a very, very long time to calculate.
+#
+die "Sudoku is too big\n" if $SIZE > length sprintf "%b", ~0;
+
+#
# We may have to come with a missing clue name. This could be
# a number, or a letter.
# - If there are numbers, but 1 is missing, use 1.
@@ -170,16 +178,17 @@ foreach my $x (@INDICES) {
# Not solved. Out of the elements, record the numbers
# which cannot be seen from this square.
#
- my %set = map {$_ => 1} @ELEMENTS;
+ my $set = (1 << ($clue_count)) - 1;
foreach my $can_see (sees ($x, $y)) {
- delete $set {$sudoku [$$can_see [0]] [$$can_see [1]]};
+ $set &= ~(1 << ($sudoku [$$can_see [0]] [$$can_see [1]] - 1));
}
- $$unsolved {$x, $y} = [keys %set];
+ $$unsolved {$x, $y} = $set;
}
}
+
no warnings 'recursion';
sub solve ($solved, $unsolved) {
#
@@ -188,16 +197,23 @@ sub solve ($solved, $unsolved) {
return $solved unless keys %$unsolved;
#
- # Find the (a) square which the least possibilities
+ # Find the (a) square which the least possibilities; this
+ # means finding the set with the least amount of bits set.
#
- my ($key) = sort {@{$$unsolved {$a}} <=> @{$$unsolved {$b}} ||
- $a cmp $b} keys %$unsolved;
+ my ($key) = map {$$_ [0]}
+ sort {$$a [1] <=> $$b [1]}
+ map {[$_, sprintf ("%b", $$unsolved {$_}) =~ y/1/1/]}
+ keys %$unsolved;
my ($x, $y) = split $; => $key;
+ my $possibilities = $$unsolved {$key};
#
- # Try each possibility
+ # Guess each possibility for this key.
#
- foreach my $guess (@{$$unsolved {$key}}) {
+ foreach my $guess (@ELEMENTS) {
+ my $mask = 1 << ($guess - 1);
+ next unless $possibilities & $mask;
+
#
# Create new solved and unsolved structures
#
@@ -207,10 +223,7 @@ sub solve ($solved, $unsolved) {
#
# Copy unsolved
#
- my $new_unsolved;
- foreach my $key (keys %$unsolved) {
- $$new_unsolved {$key} = [@{$$unsolved {$key}}];
- }
+ my $new_unsolved = {%$unsolved};
#
# Delete our guess
@@ -223,9 +236,9 @@ sub solve ($solved, $unsolved) {
#
foreach my $can_see (sees ($x, $y)) {
my ($x, $y) = @$can_see;
- $$new_unsolved {$x, $y} = [grep {$_ != $guess}
- @{$$new_unsolved {$x, $y}}]
- if $$new_unsolved {$x, $y};
+ if ($$new_unsolved {$x, $y}) {
+ $$new_unsolved {$x, $y} &= ~ $mask;
+ }
}
#