aeinprst: 346 aeilprst: 344 adeiprst: 332 aeimprst: 328 #### use Algorithm::Combinatorics qw(:all); my $iter = combinations_with_repetition(\@{['a'..'z']}, 8); #### #! /usr/bin/perl use threads; use threads::shared; use Thread::Semaphore; use integer; my $CORES = 8; my $TOTAL :shared = 0; my $TDONE :shared = 0; my $tresh = 0; my (%P, %N, @W, @N, %RES); sub wfilt { tr/a-z//cd; length() <= 8; } sub wval { my $x = 1; $x *= $P{$_} for split //; $x } @P{'a'..'z'} = grep {(1x$_)!~/^(11+)\1+$/} 2..101; open(WORDS, "words") or die; @W = grep wfilt, ; $N{&wval}++ for @W; @N = keys %N; my $SEM = Thread::Semaphore->new($CORES); my @T = map threads->new(\&worker, $_), 'a'..'z'; report ((map {$_->join()} @T), 0); sub x2 { map { my $t = $_; map {$t.$_} @_ } @_ } sub worker { my ($pivot) = @_; # aaaPzzzz my (%A, %Z, @A, @Z, $a, $z); $A{&wval} //= $_ for grep s/.$/$pivot/, x2(x2('a'..$pivot)); $Z{&wval} //= $_ for x2(x2($pivot..'z')); @A = keys %A; @Z = keys %Z; report (-int(@A)*int(@Z)); for $a (@A) { $SEM->down(); my @R; for $z (@Z) { my ($v, $n) = ($a*$z, 0); $v % $_ or $n += $N{$_} for @N; # 99.99% push @R, ($A{$a}.$Z{$z} => $n) if ($n > $tresh); } report (@R, int(@Z)); $SEM->up(); } return (%RES); } sub report { if ((my $n = pop) < 0) { lock($TOTAL); $TOTAL -= $n; } else { lock($TDONE); $TDONE += $n; } return unless @_; %RES = (%RES, @_); my @top = sort { $RES{$b} <=> $RES{$a} } keys %RES; delete @RES{splice(@top, 20)} if @top > 20; print "$_: $RES{$_}\n" for @top; $tresh = $RES{pop @top}; no integer; printf "! progress %d/%d (% 3.1f%%)\n@{['-'x40]}\n", $TDONE, $TOTAL, 100.0*$TDONE/$TOTAL; }