#!/usr/bin/perl
use warnings;
use strict;
use DBI;

#### configure for your game here
my $min = 3;
my @letters = map { $_ eq 'q' ? 'qu' : $_ } map lc, split '', 'abcdefghijklmnop';
my $muddled = 0;
my $common  = 0;
my $safe    = 0 ;
####

my(%found, %all, %limits);
my $file = '/Users/pudge/Downloads/words.sql';
my $dbh = DBI->connect("dbi:SQLite:dbname=$file"); 

my %seen;
for my $l (@letters) {
	next if $seen{$l}++;
	my $st = "SELECT * FROM ${l}_words";
	my @arr = $dbh->selectall_arrayref($st);
	for my $a (@arr) {
		for my $w (@$a) {
			next if $common && !$w->[2];
			next if $safe   &&  $w->[3];
			my $word = $l . $w->[0];
			$all{$word} = 1;
			limit($word);
			if ($w->[1]){
				$all{$word . 's'} = 1;
				$limits{$word . 's'} = 1;
			}
		}
	}
}
printf "\nFetched %d words from dictionary.
Finding all $min+ words that match:\n\n", scalar keys(%all);

# sure there is a good algorithm for this ... but this was easier
my %matrix = (
	1  => [2,5,6],
	2  => [1,3,5,6,7],
	3  => [2,4,6,7,8],
	4  => [3,7,8],
	5  => [1,2,6,9,10],
	6  => [1,2,3,5,7,9,10,11],
	7  => [2,3,4,6,8,10,11,12],
	8  => [3,4,7,11,12],
	9  => [5,6,10,13,14],
	10 => [5,6,7,9,11,13,14,15],
	11 => [6,7,8,10,12,14,15,16],
	12 => [7,8,11,15,16],
	13 => [9,10,14],
	14 => [9,10,11,13,15],
	15 => [10,11,12,14,16],
	16 => [11,12,15]
);

# use same algo for muddled, just make every letter adjacent to every other
if ($muddled) {
	%matrix = ();
	my @foo = 1 .. scalar(@letters);
	$matrix{$_} = \@foo for @foo;
}

getnext($letters[$_-1], $_) for (1..16);
print "  * $_\n" for sort keys %found;
printf "\nDone.  %d words found.\n\n", scalar keys(%found);



sub getnext {
	my($pword, $num, %used) = @_;
	$used{$num} = 1;

	for my $n (@{ $matrix{$num} }) {
		next if $used{$n};
		my $nword = $pword;
		$nword .= $letters[$n-1];
		next unless length($nword) < $min || $limits{$nword};
		$found{$nword} = 1 if length($nword) >= $min && $all{$nword};
		getnext($nword, $n, %used);
	}
}

sub limit {
	my($word) = @_;
	for my $i (reverse($min .. length($word))) {
		my $w = substr($word, 0, $i);
		last if $limits{$w};
		$limits{$w} = 1;
	}
}

__END__