Since it's slow like hell (but I've some ideas to speed it up)
Speeding it up turned out to be easier than I thought it was.
Below is reworked program that is dramatically faster that
the original. But first a table comparing running times of
three versions, the original, pure regex solution from the
parent node, the faster (still pure regex) solution presented
below, and the non-pure variant presented last year. The
latter is still the faster solution though.
Timings (values in wall clock seconds):
N Original Faster Non-pure
4 0.035 0.034 0.035
5 0.045 0.036 0.036
6 0.769 0.041 0.038
7 4.833 0.042 0.038
8 0.082 0.049
9 0.072 0.044
10 0.113 0.056
11 3.504 0.051
12 0.096
13 0.071
14 0.577
15 0.467
16 3.864
17 2.289
18 19.630
19 1.324
20 117.227
Before giving the program, some sample output:
$ ./queens -p -n 4
';,a1,a2,a3,a4,
;,b1,b2,b3,b4,
b1:,a3,a4,
b2:,a4,
b3:,a1,
b4:,a1,a2,
;,c1,c2,c3,c4,
c1:,a2,a4,b3,b4,
c2:,a1,a3,b4,
c3:,a2,a4,b1,
c4:,a1,a3,b1,b2,
;,d1,d2,d3,d4,
d1:,a2,a3,b2,b4,c3,c4,
d2:,a1,a3,a4,b1,b3,c4,
d3:,a1,a2,a4,b2,b4,c1,
d4:,a2,a3,b1,b3,c1,c2,
' =~
/^;.*,(\w+),.*
;.*,(\w+),.*
[^;]*\2:.*,\1[^;]*
;.*,(\w+),.*
[^;]*\3:.*,\1.*,\2[^;]*
;.*,(\w+),.*
[^;]*\4:.*,\1.*,\2.*,\3[^;]*
/
[a3 b1 c4 d2]
$ ./queens -n 8
[a8 b4 c1 d3 e6 f2 g7 h5]
And here's the program:
#!/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) = ("", "");
foreach my $c (@cols) {
$str .= ";," . (join "," => map {"$c$_"} @rows) . ",\n";
$re .= ";.*,(\\w+),.*\n";
next if $c eq 'a';
map {$str .= "$_:," . join ("," => free ($_)) . ",\n"} map {"$c$_"
+} @rows;
my $C = a2i $c;
$re .= "[^;]*\\$C:" . join ("" => map {".*,\\$_"} 1 .. $C - 1) . "
+[^;]*\n";
}
if ($print || $Print) {
print "'$str' =~ \n/^$re/\n";
exit if $Print;
}
if (my @a = $str =~ /^$re/) {
print "[@a]\n";
}
__END__
Abigail
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
Outside of code tags, you may need to use entities for some characters:
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.