def getPlay(self, left, right, length=None, wordplays=None, gui=None): charades = [] possible_lefts = [] # consist of word-certainty pairs possible_rights = [] # consist of just words (more convenient this way) # Check if any possible code keywords exist in either part. if wordplays is not None: for typ in ['initial', 'final']: try: for pos, word in enumerate(left): word = wordnet.stemmer.stem(word) if word in wordplays[typ].keywords: if len(left[:pos]) > 0: possible_lefts.append((wordplays[typ].getPlay(left[:pos]),1.0)) if len(left[pos+1:]) > 0: possible_lefts.append((wordplays[typ].getPlay(left[pos+1:]),1.0)) except KeyError: pass try: for pos, word in enumerate(right): word = wordnet.stemmer.stem(word) if word in wordplays[typ].keywords: if len(right[:pos]) > 0: possible_rights.append(wordplays[typ].getPlay(right[:pos])) if len(right[pos+1:]) > 0: possible_rights.append(wordplays[typ].getPlay(right[pos+1:])) except KeyError: pass # Add any abbreviations to the mix if len(left) == 1: possible_lefts.extend([(a, 1.0) for a in wordnet.getAbbreviations(left[0])]) if len(right) == 1: possible_rights.extend(wordnet.getAbbreviations(right[0])) left, right = ('_'.join(left), '_'.join(right)) # Try synonyms too if wordnet.exists(left): possible_lefts.extend([(s, -1.0) for s in wordnet.getSynonyms(left) if len(s.split('_'))==1]) for possible_left, lsim in possible_lefts: for possible_right, rsim in [(pr, wordnet.calcSimilarity(pr, right))\ for pr in self.getPossibleRights(possible_left, length) if wordnet.exists(pr)] +\ [(pr, 1.0) for pr in possible_rights if wordnet.exists(possible_left + pr)]: if gui and gui.halt(): return charades if rsim > 0: if lsim < 0: # Wait till now to compute this, as earlier we weren't sure if it'd get used. lsim = wordnet.calcSimilarity(possible_left, left) charades.append((possible_left+possible_right, rsim * lsim)) return charades
def check(self, clue, token_sets, **kwargs): finals = [] tokens = [token for token_set in token_sets.values() for token in token_set] for combo in self.getCombinations(tokens): soln = self.getPlay(combo) if wordnet.exists(soln) and clue.checkSolution(soln): finals.append(WordplaySolution(soln, self.__typ__, combo, self.calcCertainty(len(combo),len(tokens)))) logger.debug('Final solutions found: %s' % finals) return finals
def test_non_existence(self): for word in ['spellling', 'ish', 'veary', 'impoortent']: self.assertFalse(wordnet.exists(word), '\'%s\' should not be in wordlist!' % word)
def test_existence(self): for word in ['cryptic', 'crosswords', 'are', 'neat']: self.assertTrue(wordnet.exists(word), '\'%s\' is not in wordlist!' % word)
def parseClue(self, clue, length=None, typ=None, known_letters=None, brute_force=False, **kwargs): """ This is the core method that handles input clues, interprets them, then passes them off to other modules to dissect. It then re-assimilates all solutions, sorts them, then returns them to the user. """ logger.info('Parsing clue: %s' % clue) # Convert to Clue object if it is not already. if not isinstance(clue, Clue): clue = Clue(clue, length, typ, known_letters) logger.debug('Converted clue to Clue object: %s' % clue) # Loop through all possible definitions. solutions = [] raw_solns = set() # for bruteforcing later raw_definitions = [] # for bruteforcing later for defpos in filter(lambda x: x!=0, range(-DEFINITION_MAX_LEN, DEFINITION_MAX_LEN+1)): # Generate a list of possible solutions for chosen definition. # Defpos signifies how many words in the definition. # A negative value indicates to take words from end of string. definition = '_'.join(clue.tokens[0 if defpos > 0 else defpos : defpos if defpos > 0 else None]) if not wordnet.exists(definition): continue raw_definitions.append([defpos,definition]) # Generate possible wordplay interpretations. (Convert to a tree structure with keywords at nodes.) wpTokens = clue.tokens[0 if defpos < 0 else defpos:defpos if defpos < 0 else None] interpretations = self.interpret(clue, wpTokens) # Consider each interpretation. for kwpos, typs in interpretations.items(): for typ, subplay in typs.items(): if self.gui_thread: if self.gui_thread.halt(): return solutions self.gui_thread.updateStatus(typ=typ) for soln in self.wordplays[typ].check(clue, subplay, wordplays=self.wordplays, gui=self.gui_thread, **kwargs): if self.gui_thread and self.gui_thread.halt(): return solutions certainty = wordnet.calcSimilarity(soln.solution, definition) * soln.certainty if certainty > 0: solutions.append( Solution(clue, soln.solution, defpos, [(kwpos + (defpos if defpos > 0 else 0)) if kwpos >= 0 else -1, typ, ' '.join(soln.applied_to)], certainty ) ) raw_solns.add(soln.solution) # Sort solutions by certainty score. solutions = sorted(solutions, key=lambda s: s.certainty, reverse=True) # Consider brute-forcing solutions. if brute_force: if known_letters is None: raise BruteForceWithoutKnownLettersException if self.gui_thread: if self.gui_thread.halt(): return solutions self.gui_thread.updateStatus(typ='brute-forcing') # Get a brute-forced list of solutions. brute_solns = set(wordnet.getWordsWithPattern(clue.regex)) - raw_solns brute_forced_solutions = [] for soln in brute_solns: if self.gui_thread and self.gui_thread.halt(): return solutions soln_certainty = max([(0,None)]+[(wordnet.calcSimilarity(soln, d[1]), d[0]) for d in raw_definitions], key=lambda x:x[0]) brute_forced_solutions.append( Solution(clue, soln, soln_certainty[1] if soln_certainty[0] > 0 else None, [-1, 'brute-forced', '---'], soln_certainty[0] ) ) solutions.extend(sorted(brute_forced_solutions, key=lambda s: s.certainty, reverse=True)) if solutions: logger.info('%i solution(s) found. Best solution is \'%s\' (certainty: %f)' % (len(solutions), solutions[0].solution, solutions[0].certainty)) else: logger.info('Unsuccessful in resolving clue.') return solutions