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