This may get me a
very clever, -10, but I've tweaked the program to run rather quickly (
-n 22 runs in a few seconds) by using a known general solution as the basis of my regex. Technically, it still generates a regular expression and matches it against the who-doesn't-attack-whom string, so
-n 3 returns no match.
#!/usr/bin/perl
use strict;
use warnings 'all';
use Getopt::Long;
Getopt::Long::Configure ("bundling");
GetOptions ('p|print' => \my $print,
'P|Print' => \my $Print,
'n|number=i' => \(my $nr_of_queens = 8)
);
my @rows = 1 .. $nr_of_queens;
my @cols = ('a' .. 'z') [0 .. $nr_of_queens - 1];
sub a2i {ord ($_ [0]) - ord ('a') + 1}
sub i2a {chr ($_ [0] + ord ('a') - 1)}
# Given a square, return all non-attacked squares on columns to
# the *left* of the given square. (a1 is the lower left corner).
sub free {
my ($C, $R) = $_ [0] =~ /(\D)(\d+)/;
$C = a2i $C;
map {join "" => i2a ($_ -> [0]), $_ -> [1]}
grep {$_ -> [0] != $C &&
$_ -> [1] != $R &&
abs ($_ -> [0] - $C) != abs ($_ -> [1] - $R)}
map {my $c = a2i $_; map {[$c, $_]} @rows} @cols [0 .. $C - 1]
}
my ($str, $re) = ('', '');
my $solrow = 0;
foreach my $c (@cols) {
$str .= ";," . (join "," => map {"$c$_"} @rows) . ",\n";
$solrow += 2;
$solrow = 1 if $solrow > $nr_of_queens;
$re .= ".*\n" unless $c eq 'a';
$re .= ";.*,($c$solrow),";
next if $c eq 'a';
$re .= sprintf "(?:.*\n){%d}\\%d:", $solrow, a2i($c);
for my $i (1..a2i($c)-1) {
$re .= ".*,\\$i,";
}
$re .= sprintf "(?:.*\n){%d}", $nr_of_queens - $solrow;
map {$str .= "$_:," . join (",," => free ($_)) . ",\n"} map {"$c$_
+"} @rows;
}
if ($print || $Print) {
print "'$str' =~ \n/^$re/\n";
exit if $Print;
}
if (my @a = $str =~ /^$re/) {
print "[@a]\n";
}
__END__