AABAABAA
AABAABAA
BBABBABB
AABAABAA
AABAABAA
BBABBABB
AABAABAA
AABAABAA
####
use strict;
use warnings;
#
# Two types of operation:
#
# - Pick a symbol:
# '' =~ /<[A-C]*([A-C])[A-C]*>/
#
# - Constraint check:
# '' =~ /<(?:[A-C]*,)*\x\y\z?(?:,[A-C]*)*>/
#
sub allowed {
my ($syms) = @_;
my @combos;
for my $y (@$syms) {
for my $x (@$syms) {
next if $x eq $y;
push @combos, "$y$x";
push @combos, "$y$y$x";
}
}
return @combos;
}
{
my $solve = shift || "count_solutions"; # first_solution, all_solutions, count_solutions
my $grid_size = shift || 8;
my $num_symbols = shift || 6;
my @syms = ('A'..'Z')[0..$num_symbols-1];
my $syms_list = join('', reverse(@syms));
my $syms_class = "[" . $syms[0] . "-" . $syms[-1] . "]";
my $pick_str = "<$syms_list>";
my $pick_pat = "<$syms_class*($syms_class)$syms_class*>";
my $constr_str = "<" . join(',',allowed(\@syms)) . ">";
my $constr_pat_gen = sub { "<(?:$syms_class*,)*\\$_[0]\\$_[1]\\$_[2]?(?:,$syms_class*)*>" };
my $str = '';
my $pat = '';
for my $y (0..$grid_size-1) {
for my $x (0..$grid_size-1) {
$str .= $pick_str;
$pat .= $pick_pat;
my $z = $y * $grid_size + $x + 1;
if ($x >= 2) {
$str .= $constr_str;
$pat .= $constr_pat_gen->($z, $z-1, $z-2);
}
if ($y >= 2) {
$str .= $constr_str;
$pat .= $constr_pat_gen->($z, $z-1*$grid_size, $z-2*$grid_size);
}
}
}
#print("$str\n");
#print("$pat\n");
if ($solve eq "first_solution") {
my (@sol) = $str =~ /^$pat\z/
or die("No solution");
for my $y (0..$grid_size-1) {
for my $x (0..$grid_size-1) {
print($sol[$y * $grid_size + $x]);
}
print("\n");
}
}
elsif ($solve eq "all_solutions") {
use re 'eval';
local our $count = 0;
$str =~ /^$pat\z(?{
++$count;
for my $y (0..$grid_size-1) {
for my $x (0..$grid_size-1) {
no strict 'refs';
print(${ $y * $grid_size + $x + 1 });
}
print("\n");
}
print("\n");
})(?!)/;
print("$count solutions\n");
}
elsif ($solve eq "count_solutions") {
use re 'eval';
local our $count = 0;
$str =~ /^$pat\z(?{ ++$count; print "$count\n" if $count % 10000 == 0; })(?!)/;
print("$count solutions\n");
}
else {
die("Bad value for \$solve\n");
}
}
## ##
F
FF