Find The Wordiest Combination Lock I have a combination padlock which has letters instead of numbers. It looks like this: http://pictures.picpedia.com/2012/09/Word_Combination_Padlock.jpg There are 5 reels, each of which has 10 different letters on it.

Most people like to use a word for their combination rather than an arbitrary string of letters. (Less secure, of course, but easier to remember.) So when manufacturing the lock, it would be good to build it to have a combination of letters which can be used to create as many 5-letter English words as possible. 

Your task, should you choose to accept it, is to find an assignment of letters to reels which will allow as many words as possible to be created. For example, your solution might be

ABCDEFGHIJ DEFGHIJKLM ZYXWVUTSR ABCDEFGHIJ ABCDEFGHIJ

(If you weren't feeling too imaginative, that is).

For consistency, please use the word list at http://www.cs.duke.edu/~ola/ap/linuxwords

Any 5-letter word in that list is OK, including proper names. Ignore Sino- and L'vov and any other words in the list which contain a non a-z character.

The winning program is the one which produces the largest set of words. In the event that multiple programs find the same result, the first one to be posted wins. The program should run in under 5 minutes. 

Edit: since activity has died down, and no better solutions have come out, I declare Peter Taylor the winner! Thanks everyone for your inventive solutions.
1275 words by simple greedy hill-climbing

Code is C#. Solution produced is

Score 1275 from ^[bcdfgmpstw][aehiloprtu][aeilnorstu][acdeklnrst][adehklrsty]$


I'm using that output format because it's really easy to test:

grep -iE "^[bcdfgmpstw][aehiloprtu][aeilnorstu][acdeklnrst][adehklrsty]$" linuxwords.txt | wc




namespace Sandbox {
    class Launcher {
        public static void Main(string[] args)
        {
            string[] lines = _Read5s();
            int[][] asMasks = lines.Select(line =&gt; line.ToCharArray().Select(ch =&gt; 1 &lt;&lt; (ch - 'a')).ToArray()).ToArray();
            Console.WriteLine(string.Format("{0} words found", lines.Length));

            // Don't even bother starting with a good mapping.
            int[] combos = _AllCombinations().ToArray();
            int[] best = new int[]{0x3ff, 0x3ff, 0x3ff, 0x3ff, 0x3ff};
            int bestSc = 0;
            while (true)
            {
                Console.WriteLine(string.Format("Score {0} from {1}", bestSc, _DialsToString(best)));

                int[] prevBest = best;
                int prevBestSc = bestSc;

                // Greedy hill-climbing approach
                for (int off = 0; off &lt; 5; off++)
                {
                    int[] dials = (int[])prevBest.Clone();

                    dials[off] = (1 &lt;&lt; 26) - 1;
                    int[][] filtered = asMasks.Where(mask =&gt; _Permitted(dials, mask)).ToArray();
                    int sc;
                    dials[off] = _TopTen(filtered, off, out sc);
                    if (sc &gt; bestSc)
                    {
                        best = (int[])dials.Clone();
                        bestSc = sc;
                    }
                }

                if (bestSc == prevBestSc) break;
            }

            Console.WriteLine("Done");
            Console.ReadKey();
        }

        private static int _TopTen(int[][] masks, int off, out int sc)
        {
            IDictionary&lt;int, int&gt; scores = new Dictionary&lt;int, int&gt;();
            for (int k = 0; k &lt; 26; k++) scores[1 &lt;&lt; k] = 0;

            foreach (int[] mask in masks) scores[mask[off]]++;

            int rv = 0;
            sc = 0;
            foreach (KeyValuePair&lt;int, int&gt; kvp in scores.OrderByDescending(kvp =&gt; kvp.Value).Take(10))
            {
                rv |= kvp.Key;
                sc += kvp.Value;
            }
            return rv;
        }

        private static string _DialsToString(int[] dials)
        {
            StringBuilder sb = new StringBuilder("^");
            foreach (int dial in dials)
            {
                sb.Append('[');
                for (int i = 0; i &lt; 26; i++)
                {
                    if ((dial &amp; (1 &lt;&lt; i)) != 0) sb.Append((char)('a' + i));
                }
                sb.Append(']');
            }
            sb.Append('$');
            return sb.ToString();
        }

        private static IEnumerable&lt;int&gt; _AllCombinations()
        {
            // \binom{26}{10}
            int set = (1 &lt;&lt; 10) - 1;
            int limit = (1 &lt;&lt; 26);
            while (set &lt; limit)
            {
                yield return set;

                // Gosper's hack:
                int c = set &amp; -set;
                int r = set + c;
                set = (((r ^ set) &gt;&gt; 2) / c) | r;
            }
        }

        private static bool _Permitted(int[] dials, int[] mask)
        {
            for (int i = 0; i &lt; dials.Length; i++)
            {
                if ((dials[i] &amp; mask[i]) == 0) return false;
            }
            return true;
        }

        private static string[] _Read5s()
        {
            System.Text.RegularExpressions.Regex word5 = new System.Text.RegularExpressions.Regex("^[a-z][a-z][a-z][a-z][a-z]$", System.Text.RegularExpressions.RegexOptions.Compiled);
            return File.ReadAllLines(@"d:\tmp\linuxwords.txt").Select(line =&gt; line.ToLowerInvariant()).Where(line =&gt; word5.IsMatch(line)).ToArray();
        }
    }
}