|
__author__ = 'David Ruffner' |
|
|
|
import pandas as pd |
|
import re |
|
import collections |
|
|
|
# Load up the standard scrabble words |
|
# For faster performace copy the file locally. |
|
#words = pd.read_csv('https://raw.githubusercontent.com/jmlewis/valett/master/scrabble/sowpods.txt', header=None) |
|
words = pd.read_csv('sowpods.txt', header=None) |
|
words = words.iloc[:,0] |
|
|
|
|
|
def match(word, pattern): |
|
""" |
|
Test if word matches python regex pattern. |
|
""" |
|
|
|
if isinstance(word, basestring): |
|
if pattern.match(word): |
|
return True |
|
else: |
|
return False |
|
else: |
|
return False |
|
|
|
|
|
def getNonZeroSplits(pattern, word): |
|
""" |
|
Get none empty splits from a regex pattern applied to a word. |
|
""" |
|
|
|
splits = pattern.split(word) |
|
return [x for x in splits if x] |
|
|
|
|
|
def split(word, startPattern, endPattern): |
|
""" |
|
Find leftover fragment after removing characters found by startPattern and endPattern. |
|
""" |
|
|
|
end = getNonZeroSplits(startPattern,word)[0] |
|
middle = getNonZeroSplits(endPattern, end)[-1] |
|
return middle |
|
|
|
|
|
def inMyLetters(word, myLetters): |
|
""" |
|
Use counters (essentially multisets) to test whether the letters in word |
|
can be created from and arrangement of myLetters. |
|
""" |
|
|
|
c1 = collections.Counter(word) |
|
c2 = collections.Counter(myLetters) |
|
if len(c1 - c2) == 0: # If len is 0 then c2 contains all the letters in c1 |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
def findWord(myLetters, startsWith, endsWith, gapLength): |
|
""" |
|
Finds a scrabble word that satisfies the conditions and can be |
|
made from myLetters. |
|
""" |
|
|
|
# Handle empty arguments |
|
if startsWith is not None: |
|
startPattern = '^{}'.format(startsWith) |
|
else: |
|
startPattern = '^' |
|
|
|
if endsWith is not None: |
|
endPattern = '{}$'.format(endsWith) |
|
else: |
|
endPattern = '$' |
|
|
|
if gapLength is not None: |
|
midPattern = '.{{{0},{0}}}'.format(gapLength) |
|
else: |
|
midPattern = '.+'.format(startPattern, endPattern) |
|
|
|
pattern = re.compile('{0}{1}{2}'.format(startPattern, midPattern, endPattern)) |
|
|
|
# Find all words that match patterns |
|
matches = words.apply(match, convert_dtype=False, args=(pattern,)) |
|
# Find fragments of those words not in patterns |
|
fragments = words[matches].apply(split, args=(re.compile(startPattern), |
|
re.compile(endPattern))) |
|
# See which of these words are in the myLetters |
|
possibleWords = words.loc[fragments[fragments.apply(inMyLetters, args=(myLetters,))].index] |
|
|
|
return possibleWords.values |
|
|
|
|
|
if __name__ == '__main__': |
|
import argparse |
|
|
|
parser = argparse.ArgumentParser() |
|
parser.add_argument('-m', '--myLetters', help='String of your scrabble letters') |
|
parser.add_argument('-s', '--startsWith', help='Starting letters') |
|
parser.add_argument('-e', '--endsWith', help='Ending letters') |
|
parser.add_argument('-g', '--gapLength', type=int, help='Number of letters in gap') |
|
args = parser.parse_args() |
|
|
|
words = findWord(args.myLetters, args.startsWith, args.endsWith, args.gapLength) |
|
for word in words: |
|
print word |